Concurrently node exits with status 1. This halts Teamcity leading it to believe that the tests failed

送分小仙女□ 提交于 2019-12-06 15:36:51

Finally found a solution to this problem. I wrote a little script that runs the mock webapi and the karma tests as child processes.

test-single-run-single-process.js

const spawn = require('cross-spawn');

/**
 * Running the tests requires a mock webapi which is gladly provided by json-server.
 * Running the tests in teamcity requires that everything is executed from one terminal.
 * Different mock data sets can be easily used if the mockapi is a child process.
 * We do not need to keep the mockWebapi alive between trials.
 * 
 * After all the tests have succeeded we then close the json-server by sending (SIGINT).
 * Finally the process will exit with code 0, which means for TeamCity that all is OK.
 * Now it can proceed with the next build step.
 * So basically we can run the tests both standalone and in one single terminal.
 * Notice that the mockWebapi is a forked process so we can send messages to it.
 * 
 * <!> Failed approach - Closing the mockwebapi
 * Using kill command leaves no option for gracefull shutdown. 
 * SIGINT or SIGTERM signals are not received by the mockWebapi.
 * The server will stay active keeping the 3000 port busy.
 * 
 *     mockWebapi.kill('SIGINT'); 
 */

const fork = require('child_process').fork
const mockWebapi = fork('./tools/mock-webapi/mock-webapi.js')

const karma = spawn(
    `karma start --single-run --browsers ChromeHeadless`,
    [], { stdio: 'inherit' }
);

// 1) Listen to karma exit
karma.on('close', (code, signal) => { 
    console.log('Karma closed. Code:', code, 'Signal:', signal);
    code === 0 && gracefullyCloseMockWebapi(true);
});
karma.on('error', (code, signal) => { 
    console.log('Karma error. Code:', code, 'Signal:', signal);
    gracefullyCloseMockWebapi(false);
});

let gracefullyCloseMockWebapi = (testsCompletedOk) => {
    console.log('Gracefuly close webapi. Tests completed ok:', testsCompletedOk);
    mockWebapi.send({ testsCompletedOk });
};

// 2) Finish the job, pass the exit code from mockWeabpi to the command line
mockWebapi.on('close', (code, signal) => { 
    console.log('Mock webapi closed. Code:', code, 'Signal:', signal);
    process.exit(code);
});

mock-webapi.js

// Some project specific work is done before starting the server

/**
 * <!> Failed approach - concurrently
 * Dispatching the following command will exit with code 1. 
 * The SIGTERM or SIGINT handlers are not called after the tests are done.
 * concurrently --kill-others --success first 
 *     "node ./tools/mock-webapi/mock-webapi.js" "npm run test-single-run"
 *
 *     process.on('SIGINT', (code) => {
 *         server.close(function () {
 *             process.exit(0);
 *         });
 *     });
 *
 * <!> Working approach
 * Spawning a process child and sending it a message to self-close.
 * Double check it with "echo Exit Code is %errorlevel%" after the processes terminated.
 */

function setupJsonServer(mocks, routes) {
    let server = jsonServer.create(),
        port = 3000;

    const router = jsonServer.router(mocks);

    server.use(jsonServer.defaults());
    server.use(jsonServer.rewriter(routes));
    server.use(router);

    server.listen(port, () => {
        console.log(`JSON Server is running at ${port}`)
        console.log('Process id is', process.pid);
    });

    process.on('message', function ({ testsCompletedOk }) {
        console.log('Mockwebapi will terminate. Tests completed ok', testsCompletedOk)
        process.exit(testsCompletedOk === true ? 0 : 1)
    });

}

Additional reading:

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!