Nathan Cooper Nathan Cooper - 1 month ago 40
AngularJS Question

How to run e2e tests in teamcity, How to run the server in the background and run e2e

How do a run the servers I need as well as the e2e tests in a teamcity build step(s)?

I have protractor e2e test for my angular 2 application. (I have a funny mix of angular-cli and gulp, but bear with me.)

Here's how I run my tests locally. I need three console windows (w1,w2,w3).

w1) First thing I need to do is start my application:

npm start
-> Which I have defined in package.json as
ng serve -prod


w2) Then start the fake back-end, an express webserver

npm run gulp e2e-server
-> I've defined
"gulp": "gulp"
in my package config, because
gulp
won't be recognised on teamcity.

3w) And then finally I can run my e2e tests

npm run e2e -- e2e/protractor-teamcity.conf.js
I've defined
"pree2e": "webdriver-manager update"
and
"e2e": "protractor"
in my package config

Then...

I need to manually stop the two servers I started.

Something like this hack will work:

npm run gulp e2e-clean && start "MyWindow" cmd /c "start npm start && npm run gulp e2e-server" && ping -n 31 127.0.0.1 >nul && npm run e2e -- e2e/protractor-teamcity.conf.js


But
start
creates console windows that will never stop. I'm not sure what the consequences of this are (I doubt this will run successfully twice). The ping is a sleep hack, which isn't ideal either.

Has anyone found a solution for running a command "in the background" during the test run and then killing it afterwards?

Answer

So, this is a terrible hack. The sort of hack that suggests something is deeply wrong, but ho-hum:

When ng serve runs it will change the console window title to "angular-cli", when gulp runs it which change it to "gulp" (or "select gulp"). I don't expect anything else will be running with these titles. This is enough to write __kill-running-windows to go and kill these windows.

Package.json:

  "scripts": {
    "start": "ng serve -prod",
    "test": "gulp test-teamcity",
    "pree2e": "webdriver-manager update",
    "e2e": "protractor",
    "gulp": "gulp",

    "e2e-teamcity": "gulp _e2e-clean && npm run _e2e-teamcity & npm run _kill-running-windows",
    "_e2e-teamcity": "npm run _e2e-servers && gulp __wait-60 && gulp _e2e-test-teamcity",
    "_e2e-servers": "start gulp _e2e-server && start gulp serve",
    "_kill-running-windows": "taskkill /fi \"Windowtitle eq gulp\" & taskkill /fi \"Windowtitle eq select gulp\" & taskkill /fi \"Windowtitle eq angular-cli\" & taskkill /fi \"Windowtitle eq select angular-cli\""
  },

The code (the interesting parts anyway, I'll leave what eg gulp serve to the readers imagination):

var expressServer = require("gulp-express");
var process = require("child_process");
var shell = require("gulp-shell");

/**
 * Run vanilla e2e tests with teamcity reporter
 * 
 * (Remember to call `e2e-server`, `serve` and edit `config.json` to point at config.e2e.json` first)
 */
gulp.task("_e2e-test-teamcity", function(done) {
    return gulp.src("")
    .pipe(
        shell(["npm run e2e -- e2e/protractor-teamcity.conf.js"])
    )
});

gulp.task("__wait-60", function(done) {
     // HACK: Do 61 pings -> wait 30 seconds
     process.exec("ping 127.0.0.1 -n 61 > nul", function (err, stdout, stderr) {
         done();
     });
});


/**
 * Run mock backend for the e2e, with canned answers to all calls
 * !! Use config.e2e.json in your application in order to point at this !!
 */
gulp.task("_e2e-server", function () {
    expressServer.run(["./e2e/server.js"]);
    gulp.watch(["./e2e/server.js"], expressServer.notify);
});

For some reason, moving more code into gulp seemed to make the builds never finish on teamcity. But here's the e2e I use locally, which is more gulp based:

/**
 * Run vanilla e2e tests
 * Cleans screenshots folder, tarts the application, starts the mock server
 * Leaves command windows running the servers open at the end of the test run
 * 
 * 30 second wait for tests to start
 * 
 * (Remember to edit `config.json` to point at config.e2e.json` first)
 */
gulp.task("e2e", ["_e2e-clean"], function (done) {
    gulp.src("")
    .pipe(
        shell(["start gulp _e2e-server"])
    ).pipe(
        shell(["start gulp serve"])
    );
    runSequence("__wait-30","_e2e-test", done);
});