UNPKG

@qooxdoo/framework

Version:

The JS Framework for Coders

239 lines (215 loc) 6.71 kB
/* ************************************************************************ qooxdoo - the new era of web development http://qooxdoo.org Copyright: 2020 Henner Kollmann License: MIT: https://opensource.org/licenses/MIT See the LICENSE file in the project"s top-level directory for details. ************************************************************************ */ const fs = require("fs"); const path = require("path"); const process = require("process"); /** * Compiles the project, serves it up as a web page (default, can be turned off), * and dispatches the "runTests" event. * * All tests that should be run need to register themselves by the * test command. This is usually done in a `compile.js` file by either * * - adding a listener for the "runTests" event fired on the command * instance in the `load()` method of the class extending {@link * qx.tool.cli.api.CompilerApi} or {@link qx.tool.cli.api.CompilerApi}. * * - or by implementing a `beforeTests()` method in the class * extending {@link qx.tool.cli.api.CompilerApi} * * The event and/or method is called with a {@link qx.event.type.Data} * containing the command instance. * */ qx.Class.define("qx.tool.cli.commands.Test", { extend: qx.tool.cli.commands.Serve, statics: { /** * The name of the file containing the compile config for the testrunner * defaults to "compile-test.json" */ CONFIG_FILENAME: "compile-test.json", YARGS_BUILDER: { "fail-fast": { describe: "Exit on first failing test", default: false, type: "boolean" }, "disable-webserver": { describe: "Disables the start of the webserver", default: false, type: "boolean" } }, getYargsCommand() { return { command: "test", describe: "run test for current project", builder: (() => { let res = Object.assign( {}, qx.tool.cli.commands.Compile.YARGS_BUILDER, qx.tool.cli.commands.Serve.YARGS_BUILDER, qx.tool.cli.commands.Test.YARGS_BUILDER ); delete res.watch; delete res["machine-readable"]; delete res["feedback"]; delete res["show-startpage"]; delete res["rebuild-startpage"]; return res; })() }; } }, events: { /** * Fired to start tests. * * The event data is the command instance: * cmd: {qx.tool.cli.commands.Test} */ runTests: "qx.event.type.Data" }, construct(argv) { super(argv); this.__tests = []; this.addListener("changeExitCode", evt => { let exitCode = evt.getData(); // overwrite error code only in case of errors if (exitCode !== 0 && argv.failFast) { process.exit(Math.min(255, exitCode)); } }); }, properties: { /** * The exit code of all tests. * */ exitCode: { check: "Number", event: "changeExitCode", nullable: false, init: 0 }, /** * Is the webserver instance needed for the test? */ needsServer: { check: "Boolean", nullable: false, init: false } }, members: { /** * @var {Array} */ __tests: null, /** * add a test object and listens for the change of exitCode property * @param {qx.tool.cli.api.Test} test */ addTest(test) { qx.core.Assert.assertInstance(test, qx.tool.cli.api.Test); test.addListenerOnce("changeExitCode", evt => { let exitCode = evt.getData(); // handle result and inform user if (exitCode === 0) { if (test.getName() && !this.argv.quiet) { qx.tool.compiler.Console.info(`Test '${test.getName()}' passed.`); } } else if (test.getName()) { qx.tool.compiler.Console.error( `Test '${test.getName()}' failed with exit code ${exitCode}.` ); } // overwrite error code only in case of errors if (exitCode !== 0) { if (test.getFailFast()) { this.argv.failFast = true; } this.setExitCode(exitCode); } }); this.__tests.push(test); return test; }, /** * @Override */ async process() { this.argv.watch = false; this.argv["machine-readable"] = false; this.argv["feedback"] = false; this.argv["show-startpage"] = false; // check for special test compiler config if ( !this.argv.configFile && fs.existsSync( path.join(process.cwd(), qx.tool.cli.commands.Test.CONFIG_FILENAME) ) ) { this.argv.configFile = qx.tool.cli.commands.Test.CONFIG_FILENAME; } this.addListener("making", () => { if ( !this.hasListener("runTests") && this.__tests.length === 0 && (!this.getCompilerApi() || typeof this.getCompilerApi().beforeTests != "function") ) { qx.tool.compiler.Console.error( `No tests are registered! You need to either register tests, or install a testrunner. See documentation at https://qooxdoo.org/docs/#/development/testing/` ); process.exit(1); } }); this.addListener("afterStart", async () => { qx.tool.compiler.Console.info(`Running unit tests`); if (this.argv.verbose) { console.log(this.argv); } await this.fireDataEventAsync("runTests", this); if ( this.getCompilerApi() && typeof this.getCompilerApi().beforeTests == "function" ) { await this.getCompilerApi().beforeTests(this); } for (let test of this.__tests) { qx.tool.compiler.Console.info(`Running ${test.getName()}`); await test.execute(); } // for bash exitcode is not allowed to be more then 255! // We must exit the process here because serve runs infinite! process.exit(Math.min(255, this.getExitCode())); }); if (this.__needsServer()) { // start server await super.process(); } else { // compile only await qx.tool.cli.commands.Compile.prototype.process.call(this); // since the server is not started, manually fire the event necessary for firing the "runTests" event await this.fireDataEventAsync("afterStart"); } }, __needsServer() { return ( !this.argv.disableWebserver && (this.getNeedsServer() || this.__tests.some(test => test.getNeedsServer())) ); } } });