nightwatch
Version:
Easy to use Node.js based end-to-end testing solution for web applications using the W3C WebDriver API.
193 lines (150 loc) • 5.29 kB
JavaScript
const child_process = require('child_process');
const EventEmitter = require('events');
const boxen = require('boxen');
const {Logger, isObject, symbols} = require('../../utils');
const ProcessListener = require('../../runner/process-listener.js');
let prevIndex = 0;
class ChildProcess extends EventEmitter {
static get defaultStartDelay() {
return 10;
}
static get prevIndex() {
return prevIndex;
}
static set prevIndex(val) {
prevIndex = val;
}
constructor(environment, index, env_output, settings, args) {
super();
this.settings = settings;
this.env_output = env_output || [];
this.mainModule = process.mainModule.filename;
this.index = index;
this.itemKey = this.getChildProcessEnvKey(environment);
this.startDelay = settings.parallel_process_delay || ChildProcess.defaultStartDelay;
this.environment = environment;
this.child = null;
this.globalExitCode = 0;
this.env_label = '';
this.args = args || [];
}
setLabel(label) {
this.env_itemKey = label;
this.env_label = this.settings.disable_colors ? ` ${label} ` : Logger.colors.bgBlack.yellow.bold(` ${label} `);
return this;
}
printLog(msg) {
if (this.settings.output) {
// eslint-disable-next-line no-console
console.info(msg);
}
}
getChildProcessEnvKey(env) {
return `${env}_${this.index + 1}`;
}
/**
* Returns an array of cli arguments to be passed to the child process,
* based on the args passed to the main process
* @returns {Array}
*/
getArgs() {
const args = [];
if (isObject(this.settings.test_workers)) {
const {node_options} = this.settings.test_workers;
if (node_options === 'auto' || node_options === 'inherit' || node_options === true) {
args.push.apply(args, process.execArgv);
} else if (Array.isArray(node_options)) {
args.push.apply(args, node_options);
}
}
args.push(this.mainModule);
args.push.apply(args, this.args);
args.push('--parallel-mode');
return args;
}
writeToStdout(data) {
data = data.toString().trim();
const color_pair = this.availColors[this.index % 4];
let output = '';
if (ChildProcess.prevIndex !== this.index) {
ChildProcess.prevIndex = this.index;
if (this.settings.live_output) {
output += '\n';
}
}
if (this.settings.output && (this.settings.detailed_output || !this.settings.silent)) {
let childProcessLabel;
if (this.settings.disable_colors) {
childProcessLabel = ' ' + this.environment + ' ';
} else {
childProcessLabel = '';
this.env_label = Logger.colors[color_pair[0]][color_pair[1]](` ${this.environment} `);
}
const lines = data.split('\n').map(line => {
return childProcessLabel + ' ' + line + ' ';
});
data = lines.join('\n');
}
output += data;
if (this.settings.live_output) {
process.stdout.write(output + '\n');
} else {
this.env_output.push(output);
}
}
run(colors, type) {
this.availColors = colors;
const cliArgs = this.getArgs();
const env = {};
Object.keys(process.env).forEach(function(key) {
env[key] = process.env[key];
});
return new Promise((resolve, reject) => {
setTimeout(() => {
env.__NIGHTWATCH_PARALLEL_MODE = '1';
env.__NIGHTWATCH_ENV = this.environment;
env.__NIGHTWATCH_ENV_KEY = this.itemKey;
env.__NIGHTWATCH_ENV_LABEL = this.env_itemKey;
env.__NIGHTWATCH_PARALLEL_TYPE = type;
this.child = child_process.spawn(process.execPath, cliArgs, {
cwd: process.cwd(),
encoding: 'utf8',
env,
stdio: [null, null, null, 'ipc']
});
if (typeof this.child.send == 'function') {
this.child.send(JSON.stringify({
type: 'vite',
vite_port: this.settings.vite_port
}));
}
const color_pair = this.availColors[this.index % 4];
this.printLog(' Running: ' + Logger.colors[color_pair[0]][color_pair[1]](` ${this.env_itemKey} `));
this.child.stdout.on('data', data => {
this.writeToStdout(data);
});
this.child.on('message', message => {
this.emit('message', message);
});
this.child.stderr.on('data', data => {
this.writeToStdout(data);
});
this.processListener = new ProcessListener(this.child);
this.child.on('exit', code => {
this.printLog('');
const status = code > 0 ? symbols.fail : symbols.ok;
if (this.settings.disable_output_boxes) {
// eslint-disable-next-line no-console
console.log(`\n${status} ${this.env_label}`, this.env_output.join('\n'), '\n');
} else {
// eslint-disable-next-line no-console
console.log(boxen(this.env_output.join('\n'), {title: `────────────────── ${status} ${this.env_label}`, padding: 1, borderColor: 'cyan'}));
}
code = code || this.processListener.exitCode;
resolve(code);
});
}, this.index * this.startDelay);
});
}
}
module.exports = ChildProcess;