简体   繁体   中英

How do I make Protractor wait for webpack-dev-server to start?

I'm trying to replicate, for a non-Angular project, what Angular CLI does when you use ng e2e -- not only running Protractor, but starting up the dev server first, and cleanly shutting it down when Protractor is done.

I've got something that's sort of working, but the way I check to see if webpack-dev-server started successfully -- looking for the specific message "webpack: Compiled successfully." going by through stdout -- seems like an ugly hack. And the way I'm passing stdout and stderr along to the node process with pipe isn't producing all of the output I'd expect either.

Here's my protractor.conf.js so far (with a bunch of debugging console statements left in that I'll clean up later):

const { SpecReporter } = require('jasmine-spec-reporter');
const spawn = require('child_process').spawn;
let webpackServerProcess;

exports.config = {
  allScriptsTimeout: 11000,
  specs: [
    './e2e/**/*.e2e-spec.ts'
  ],
  capabilities: {
    'browserName': 'chrome'
  },
  directConnect: true,
  baseUrl: 'http://localhost:4200/',
  framework: 'jasmine',
  jasmineNodeOpts: {
    showColors: true,
    defaultTimeoutInterval: 30000,
    print: function() {}
  },
  beforeLaunch() {
    return new Promise((resolve, reject) => {
      let resolved = false;
      let rejected = false;

      webpackServerProcess = spawn('webpack-dev-server', ['--port=4200']);
      webpackServerProcess.stdout.pipe(process.stdout);
      webpackServerProcess.stderr.pipe(process.stderr);

      webpackServerProcess.stdout.addListener('data', chunk => {
        const msg = chunk.toString();

        if (msg.indexOf('webpack: Compiled successfully.') >= 0) {
          resolved = true;
          resolve();
        }
        else if (!resolved && msg.indexOf('webpack:') >= 0) {
          rejected = true;
          reject(msg);
        }
      });

      function done() {
        if (!resolved && !rejected)
          reject('webpack-dev-server terminated unexpectedly');
      }

      webpackServerProcess.addListener('close', (code, signal) => {
        console.log('*** close: ' + code + ', ' + signal);
        done();
      });

      webpackServerProcess.addListener('exit', (code, signal) => {
        console.log('*** exit: ' + code + ', ' + signal);
        done();
      });

      webpackServerProcess.addListener('disconnect', () => {
        console.log('*** disconnect');
        done();
      });

      webpackServerProcess.addListener('message', msg => console.log('*** message: ' + msg));

      webpackServerProcess.addListener('error', error => console.log('*** error: ' + error));
    });
  },
  onPrepare() {
    console.log('onPrepare()');

    require('ts-node').register({
      project: 'e2e/tsconfig.e2e.json'
    });
    jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } }));
  },
  onCleanUp() {
    console.log('onCleanUp()');

    if (webpackServerProcess && !webpackServerProcess.killed) {
      try {
        process.kill(webpackServerProcess.pid);
      }
      catch (error) {}
    }
  }
};

Any suggestions for improvement would be greatly appreciated. I've found a couple of other threads related to this topic, but nothing that came to a definitive conclusion.

Having not received any other responses yet, I figured I'd post a cleaned-up version of my previous code, with better stderr output handling and other improvements, as the best answer I have so far:

const { SpecReporter } = require('jasmine-spec-reporter');
const spawn = require('child_process').spawn;
let webpackServerProcess;
let stderrBuffer = '';

function sendToStderr(s) {
  // Undo console overstriking so that %-progress output appears on separate lines.
  s = s.replace(/ \x08\x08/g, '\x08');
  s = s.replace(/\x08+/g, '\n');
  stderrBuffer += s;

  let eol = stderrBuffer.lastIndexOf('\n');

  if (eol >= 0) {
    process.stderr.write(stderrBuffer.substring(0, eol + 1));
    stderrBuffer = stderrBuffer.substring(eol + 1);
  }
}

function flushStderr() {
  if (stderrBuffer) {
    process.stderr.write(stderrBuffer + '\n');
    stderrBuffer = '';
  }
}

exports.config = {
  allScriptsTimeout: 11000,
  specs: [
    './e2e/**/*.e2e-spec.ts'
  ],
  capabilities: {
    'browserName': 'chrome'
  },
  directConnect: true,
  baseUrl: 'http://localhost:4200/',
  framework: 'jasmine',
  jasmineNodeOpts: {
    showColors: true,
    defaultTimeoutInterval: 30000,
    print: function() {}
  },
  beforeLaunch() {
    return new Promise((resolve, reject) => {
      let resolved = false;
      let rejected = false;

      webpackServerProcess = spawn('webpack-dev-server', ['--port=4200']);
      webpackServerProcess.stdout.pipe(process.stdout);

      webpackServerProcess.stdout.addListener('data', chunk => {
        const msg = chunk.toString();

        if (msg.indexOf('webpack: Compiled successfully.') >= 0) {
          resolved = true;
          flushStderr();
          resolve();
        }
        else if (!resolved && msg.indexOf('webpack:') >= 0) {
          rejected = true;
          flushStderr();
          reject(msg);
        }
      });

      webpackServerProcess.stderr.addListener('data', chunk => {
        sendToStderr(chunk.toString());
      });

      // This config is meant for small projects. Assume that if a minute goes by with no errors, webpack has finished
      // building and webpack-dev-server is ready to go for e2e.
      setTimeout(() => {
        if (!resolved && !rejected) {
          resolved = true;
          resolve();
        }
      }, 60000);

      function done() {
        if (!resolved && !rejected) {
          flushStderr();
          reject('webpack-dev-server terminated unexpectedly');
        }
      }

      webpackServerProcess.addListener('close', done);
      webpackServerProcess.addListener('exit', done);
      webpackServerProcess.addListener('disconnect', done);
    });
  },
  onPrepare() {
    require('ts-node').register({
      project: 'e2e/tsconfig.e2e.json'
    });
    jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } }));
  },
  onCleanUp() {
    flushStderr();

    if (webpackServerProcess && !webpackServerProcess.killed) {
      try {
        process.kill(webpackServerProcess.pid);
      }
      catch (error) {}
    }
  }
};

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM