It seems protractor doesn't provide any out of the box solution for starting a server before it runs. Having to run multiple commands before functional tests will run is a bad user experience and bad for automated testing.
Angular-cli has its own solution that is rather complicated, which this plugin claims to duplicate, although it doesn't work for me and may be unmaintained. https://www.npmjs.com/package/protractor-webpack
EDIT: BETTER SOLUTION ACCEPTED BELOW
I came up with a solution using child_process.exec that seems to work well, although I don't like it very much. I'd like to share it in case anyone needs it and to see if anyone can come up with a better solution.
Launch the process in the beforeLaunch hook of protractor:
beforeLaunch: () => {
webpackServerProcess = exec(`webpack-dev-server --port=3003 --open=false`, null, () => {
console.log(`Webpack Server process reports that it exited. Its possible a server was already running on port ${port}`)
});
},
Then above the configuration block we set up the exit handlers to make positively sure that server gets killed when we are done.
let webpackServerProcess; // Set below in beforeLaunch hook
function cleanUpServer(eventType) {
console.log(`Server Cleanup caught ${eventType}, killing server`);
if (webpackServerProcess) {
webpackServerProcess.kill();
console.log(`SERVER KILLED`);
}
}
[`exit`, `SIGINT`, `SIGUSR1`, `SIGUSR2`, `uncaughtException`].forEach((eventType) => {
process.on(eventType, cleanUpServer.bind(null, eventType));
})
The various event listeners are needed to handle cntrl+c events and situations where the process is killed by ID. Strange that node does not provide an event to encompass all of these.
I found a much more reliable way to do it using the webpack-dev-server node api. That way no separate process is spawned and we don't have to clean anything. Also, it blocks protractor until webpack is ready.
Protractor also has
onCleanUp
that will run after all the specs in the file have finished.And you are doing the right thing by keeping a reference to your process so that you can kill it later.
Since you are launching the serverProcess with child_process.exec, and not in a detached state, it should go away if the main process is killed with SIGINT or anything else. So you might not even have to kill it or cleanup.