Search code examples
javascriptprotractorwebpack-dev-server

How to start a server before protractor runs and clean up afterwards


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.


Solution

  • 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.

      beforeLaunch: () => {
        return new Promise((resolve, reject) => {
          new WebpackDevServer(webpack(require('./webpack.config.js')()), {
            // Do stuff
          }).listen(APP_PORT, '0.0.0.0', function(err) {
            console.log('webpack dev server error is ', err)
            resolve()
          }).on('error', (error) => {
            console.log('dev server error ', error)
            reject(error)
          })
        })
      },