test: consolidate runner files (#3415)

This commit is contained in:
Pavel Feldman 2020-08-12 13:47:44 -07:00 committed by GitHub
parent 7e07634cc6
commit 962ddc09c4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
22 changed files with 30 additions and 542 deletions

View file

@ -38,7 +38,7 @@ jobs:
# XVFB-RUN merges both STDOUT and STDERR, whereas we need only STDERR
# Wrap `npm run` in a subshell to redirect STDERR to file.
# Enable core dumps in the subshell.
- run: xvfb-run --auto-servernum -- bash -c "ulimit -c unlimited && node test/mocha/index.js --max-workers=1 --timeout=30000 && npm run coverage"
- run: xvfb-run --auto-servernum -- bash -c "ulimit -c unlimited && node test/runner --max-workers=1 --timeout=30000 && npm run coverage"
env:
BROWSER: ${{ matrix.browser }}
DEBUG: "pw:*,-pw:wrapped*,-pw:test*"
@ -69,7 +69,7 @@ jobs:
- uses: microsoft/playwright-github-action@v1
- run: npm ci
- run: npm run build
- run: node test/mocha/index.js --max-workers=1 --timeout=30000
- run: node test/runner --max-workers=1 --timeout=30000
env:
BROWSER: ${{ matrix.browser }}
DEBUG: "pw:*,-pw:wrapped*,-pw:test*"
@ -103,7 +103,7 @@ jobs:
- uses: microsoft/playwright-github-action@v1
- run: npm ci
- run: npm run build
- run: node test/mocha/index.js --max-workers=1 --timeout=30000
- run: node test/runner --max-workers=1 --timeout=30000
shell: bash
env:
BROWSER: ${{ matrix.browser }}
@ -160,7 +160,7 @@ jobs:
# XVFB-RUN merges both STDOUT and STDERR, whereas we need only STDERR
# Wrap `npm run` in a subshell to redirect STDERR to file.
# Enable core dumps in the subshell.
- run: xvfb-run --auto-servernum -- bash -c "ulimit -c unlimited && node test/mocha/index.js --max-workers=1 --timeout=30000"
- run: xvfb-run --auto-servernum -- bash -c "ulimit -c unlimited && node test/runner --max-workers=1 --timeout=30000"
if: ${{ always() }}
env:
BROWSER: ${{ matrix.browser }}
@ -194,7 +194,7 @@ jobs:
# XVFB-RUN merges both STDOUT and STDERR, whereas we need only STDERR
# Wrap `npm run` in a subshell to redirect STDERR to file.
# Enable core dumps in the subshell.
- run: xvfb-run --auto-servernum -- bash -c "ulimit -c unlimited && node test/mocha/index.js --max-workers=1 --timeout=30000"
- run: xvfb-run --auto-servernum -- bash -c "ulimit -c unlimited && node test/runner --max-workers=1 --timeout=30000"
env:
BROWSER: ${{ matrix.browser }}
DEBUG: "pw:*,-pw:wrapped*,-pw:test*"

View file

@ -1,28 +0,0 @@
module.exports = /** @type {import('@jest/types').Config.InitialOptions} */ ({
// all of our tests have a browser and a node process, so the default max workers is too many.
maxWorkers: Math.ceil(require('os').cpus().length / 2),
rootDir: './test',
testEnvironment: './jest',
testMatch: ['**/?(*.)(jest|spec).[jt]s'],
testRunner: 'jest-circus/runner',
testTimeout: 10000,
globalSetup: './jest/setup.js',
globalTeardown: './jest/teardown.js',
transform: {
'^.+\\.ts$': ['babel-jest', {
presets: [
['@babel/preset-env', {
targets: {
node: 'current'
}
}],
['@babel/preset-typescript']
],
}],
},
reporters: [
'default',
'./jest/reporter'
],
slowTestThreshold: 30
});

View file

@ -9,9 +9,9 @@
"node": ">=10.15.0"
},
"scripts": {
"ctest": "cross-env BROWSER=chromium node test/mocha/index.js",
"ftest": "cross-env BROWSER=firefox node test/mocha/index.js",
"wtest": "cross-env BROWSER=webkit node test/mocha/index.js",
"ctest": "cross-env BROWSER=chromium node test/runner",
"ftest": "cross-env BROWSER=firefox node test/runner",
"wtest": "cross-env BROWSER=webkit node test/runner",
"test": "npm run ctest && npm run ftest && npm run wtest",
"eslint": "[ \"$CI\" = true ] && eslint --quiet -f codeframe --ext js,ts ./src || eslint --ext js,ts ./src",
"tsc": "tsc -p .",
@ -30,7 +30,7 @@
"generate-channels": "node utils/generate_channels.js",
"typecheck-tests": "tsc -p ./test/",
"roll-browser": "node utils/roll_browser.js",
"coverage": "node test/jest/checkCoverage.js",
"coverage": "node test/runner/checkCoverage.js",
"check-deps": "node utils/check_deps.js"
},
"author": {

View file

@ -22,8 +22,8 @@ import { TestServer } from '../utils/testserver/';
import { Connection } from '../lib/rpc/client/connection';
import { Transport } from '../lib/rpc/transport';
import { setUnderTest } from '../lib/helper';
import { installCoverageHooks } from './harness/coverage';
import { valueFromEnv } from './harness/utils';
import { installCoverageHooks } from './runner/coverage';
import { valueFromEnv } from './runner/utils';
setUnderTest(); // Note: we must call setUnderTest before requiring Playwright

View file

@ -1,69 +0,0 @@
/**
* Copyright Microsoft Corporation. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
const colors = require('colors/safe');
const failures = [];
module.exports = function Reporter() {
this.onRunStart = (results, options) => {
process.stdout.write('\n');
}
this.onRunComplete = (test, runResults) => {
process.stdout.write('\n');
const ranTests = runResults.numFailedTests + runResults.numPassedTests;
const summary = [`ok - ${colors.green(runResults.numPassedTests)}`];
if (runResults.numFailedTests)
summary.push(`failed - ${colors.red(runResults.numFailedTests)}`);
if (ranTests < runResults.numTotalTests)
summary.push(`skipped - ${colors.yellow(runResults.numTotalTests - ranTests)}`);
const summaryText = `Ran ${ranTests} of ${runResults.numTotalTests} (${summary.join(', ')})`;
process.stdout.write('\n');
process.stdout.write(summaryText);
process.stdout.write('\n');
for (let i = 0; i < failures.length; ++i) {
const [test, testCaseResult] = failures[i];
const path = test.path.replace(/.*test/, 'test');
const name = colors.yellow(path) + ' — ' + colors.bold(colors.yellow(testCaseResult.fullName));
process.stderr.write(`\n${i + 1}) ${colors.red('[FAIL]')} ${name}\n\n`);
process.stderr.write(testCaseResult.failureMessages + '\n');
}
};
this.onTestCaseResult = (test, testCaseResult) => {
const status = testCaseResult.status;
if (status === 'passed')
process.stdout.write(colors.green('\u00B7'));
if (status === 'failed')
process.stdout.write(colors.red('F'));
if (testCaseResult.status === 'failed')
failures.push([test, testCaseResult]);
}
}
process.on('SIGINT', async () => {
for (let i = 0; i < failures.length; ++i) {
const [test, testCaseResult] = failures[i];
const path = test.path.replace(/.*test/, 'test');
const name = colors.yellow(path) + ' — ' + colors.bold(colors.yellow(testCaseResult.fullName));
process.stderr.write(`\n${i + 1}) ${colors.red('[FAIL]')} ${name}\n\n`);
process.stderr.write(testCaseResult.failureMessages + '\n');
}
process.exit(130);
});

View file

@ -1 +0,0 @@
module.exports = require('./playwrightEnvironment').default

View file

@ -1,178 +0,0 @@
/**
* Copyright Microsoft Corporation. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
const { FixturePool, registerFixture, registerWorkerFixture } = require('../harness/fixturePool');
const path = require('path');
const fs = require('fs');
const debug = require('debug');
const util = require('util');
const GoldenUtils = require('../../utils/testrunner/GoldenUtils');
const reportOnly = !!process.env.REPORT_ONLY_PLATFORM;
const { ModuleMocker } = require('jest-mock');
global.testOptions = require('../harness/testOptions');
global.registerFixture = registerFixture;
global.registerWorkerFixture = registerWorkerFixture;
global.testPath = null;
const browserName = process.env.BROWSER || 'chromium';
const goldenPath = path.join(__dirname, '..', 'golden-' + browserName);
const outputPath = path.join(__dirname, '..', 'output-' + browserName);
let currentFixturePool = null;
process.on('SIGINT', async () => {
if (currentFixturePool) {
await currentFixturePool.teardownScope('test');
await currentFixturePool.teardownScope('worker');
}
process.exit(130);
});
class PlaywrightEnvironment {
constructor(config, context) {
this.moduleMocker = new ModuleMocker(global);
this.fixturePool = new FixturePool();
this.global = global;
this.global.testOptions = testOptions;
this.global.testPath = context.testPath;
}
async setup() {
currentFixturePool = this.fixturePool;
}
async teardown() {
currentFixturePool = null;
await this.fixturePool.teardownScope('worker');
}
runScript(script) {
return script.runInThisContext();
}
async handleTestEvent(event, state) {
if (event.name === 'setup') {
this.fixturePool.patchToEnableFixtures(this.global, 'beforeEach');
this.fixturePool.patchToEnableFixtures(this.global, 'afterEach');
const describeSkip = this.global.describe.skip;
this.global.describe.skip = (...args) => {
if (args.length === 1)
return args[0] ? describeSkip : this.global.describe;
return describeSkip(...args);
};
function addSlow(f) {
f.slow = () => {
return (...args) => f(...args, 90000);
};
return f;
}
const itSkip = this.global.it.skip;
addSlow(itSkip);
addSlow(this.global.it);
this.global.it.skip = (...args) => {
if (args.length === 1)
return args[0] ? itSkip : this.global.it;
return itSkip(...args);
};
if (reportOnly) {
this.global.it.fail = condition => {
return addSlow((...inner) => {
inner[1].__fail = !!condition;
return this.global.it(...inner);
});
};
} else {
this.global.it.fail = this.global.it.skip;
}
const testOptions = this.global.testOptions;
function toBeGolden(received, goldenName) {
const {snapshotState} = this;
const updateSnapshot = snapshotState._updateSnapshot;
const expectedPath = path.join(goldenPath, goldenName);
const fileExists = fs.existsSync(expectedPath);
if (updateSnapshot === 'all' || (updateSnapshot === 'new' && !fileExists)) {
fs.writeFileSync(expectedPath, received);
if (fileExists)
snapshotState.updated++;
else
snapshotState.added++;
return {
pass: true
}
};
const {pass, message} = GoldenUtils.compare(received, {
goldenPath,
outputPath,
goldenName
});
if (pass)
snapshotState.matched++;
else
snapshotState.unmatched++;
return {pass, message: () => message};
};
this.global.expect.extend({ toBeGolden });
}
if (event.name === 'test_start') {
const fn = event.test.fn;
this._lastTest = event.test;
event.test.fn = async () => {
if (reportOnly) {
if (fn.__fail)
throw new Error('fail');
return;
}
debug('pw:test')(`start "${testOrSuiteName(event.test)}"`);
try {
await this.fixturePool.resolveParametersAndRun(fn);
} catch(e) {
debug('pw:test')(`error "${testOrSuiteName(event.test)}"`, util.inspect(e));
throw e;
} finally {
await this.fixturePool.teardownScope('test');
debug('pw:test')(`finish "${testOrSuiteName(event.test)}"`);
}
};
}
if (event.name === 'error')
debug('pw:test')(`error "${testOrSuiteName(this._lastTest)}"`, util.inspect(event.error));
if (event.name === 'test_fn_failure') {
await this.fixturePool.teardownScope('worker');
}
}
}
function testOrSuiteName(o) {
if (o.name === 'ROOT_DESCRIBE_BLOCK')
return '';
let name = o.parent ? testOrSuiteName(o.parent) : '';
if (name && o.name)
name += ' ';
return name + o.name;
}
exports.getPlaywrightEnv = () => PlaywrightEnvironment;
exports.default = exports.getPlaywrightEnv();

View file

@ -1,44 +0,0 @@
/**
* Copyright Microsoft Corporation. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
const colors = require('colors/safe');
const fs = require('fs');
const os = require('os');
const failures = [];
module.exports = function Reporter() {
this.onRunComplete = (test, runResults) => {
runResults.platform = process.env.REPORT_ONLY_PLATFORM || os.platform();
runResults.browserName = process.env.BROWSER || 'chromium';
fs.writeFileSync('jest-report.json', JSON.stringify(runResults, undefined, 2));
};
this.onTestCaseResult = (test, testCaseResult) => {
if (testCaseResult.status === 'failed')
failures.push([test, testCaseResult]);
}
}
process.on('SIGINT', async () => {
for (let i = 0; i < failures.length; ++i) {
const [test, testCaseResult] = failures[i];
const path = test.path.replace(/.*test/, 'test');
const name = colors.yellow(path) + ' — ' + colors.bold(colors.yellow(testCaseResult.fullName));
process.stderr.write(`\n${i + 1}) ${colors.red('[FAIL]')} ${name}\n\n`);
process.stderr.write(testCaseResult.failureMessages + '\n');
}
process.exit(130);
});

View file

@ -1,28 +0,0 @@
/**
* Copyright Microsoft Corporation. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
const fs = require('fs');
const path = require('path');
const rm = require('rimraf').sync;
const browserName = process.env.BROWSER || 'chromium';
module.exports = async function setup() {
const OUTPUT_DIR = path.join(__dirname, '..', 'output-' + browserName);
if (fs.existsSync(OUTPUT_DIR))
rm(OUTPUT_DIR);
fs.mkdirSync(OUTPUT_DIR, { recursive: true });
};

View file

@ -1,18 +0,0 @@
/**
* Copyright Microsoft Corporation. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
module.exports = async function teardown() {
};

View file

@ -1,157 +0,0 @@
/**
* Copyright 2017 Google Inc. All rights reserved.
* Modifications copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
const fs = require('fs');
const path = require('path');
const os = require('os');
const pirates = require('pirates');
const babel = require('@babel/core');
const TestRunner = require('../../utils/testrunner');
const { FixturePool, registerFixture, registerWorkerFixture } = require('../harness/fixturePool');
Error.stackTraceLimit = 15;
global.testOptions = require('../harness/testOptions');
global.registerFixture = registerFixture;
global.registerWorkerFixture = registerWorkerFixture;
process.env.JEST_WORKER_ID = 1;
const browserName = process.env.BROWSER || 'chromium';
const goldenPath = path.join(__dirname, '..', 'golden-' + browserName);
const outputPath = path.join(__dirname, '..', 'output-' + browserName);
function getCLIArgument(argName) {
for (let i = 0; i < process.argv.length; ++i) {
// Support `./test.js --foo bar
if (process.argv[i] === argName)
return process.argv[i + 1];
// Support `./test.js --foo=bar
if (argName.startsWith('--') && process.argv[i].startsWith(argName + '='))
return process.argv[i].substring((argName + '=').length);
// Support `./test.js -j4
if (!argName.startsWith('--') && argName.startsWith('-') && process.argv[i].startsWith(argName))
return process.argv[i].substring(argName.length);
}
return null;
}
function collect(browserNames) {
let parallel = 1;
if (process.env.PW_PARALLEL_TESTS)
parallel = parseInt(process.env.PW_PARALLEL_TESTS.trim(), 10);
if (getCLIArgument('-j'))
parallel = parseInt(getCLIArgument('-j'), 10);
require('events').defaultMaxListeners *= parallel;
let timeout = process.env.CI ? 30 * 1000 : 10 * 1000;
if (!isNaN(process.env.TIMEOUT))
timeout = parseInt(process.env.TIMEOUT * 1000, 10);
if (require('inspector').url()) {
console.log('Detected inspector - disabling timeout to be debugger-friendly');
timeout = 0;
}
const testRunner = new TestRunner({
timeout,
totalTimeout: process.env.CI ? 30 * 60 * 1000 * browserNames.length : 0, // 30 minutes per browser on CI
parallel,
breakOnFailure: process.argv.indexOf('--break-on-failure') !== -1,
verbose: process.argv.includes('--verbose'),
summary: !process.argv.includes('--verbose'),
showSlowTests: process.env.CI ? 5 : 0,
showMarkedAsFailingTests: 10,
lineBreak: parseInt(getCLIArgument('--line-break') || 0, 10),
outputPath,
goldenPath
});
for (const [key, value] of Object.entries(testRunner.api()))
global[key] = value;
const collector = testRunner.collector();
collector.addTestModifier('skip', (t, condition) => condition && t.setSkipped(true));
collector.addSuiteModifier('skip', (s, condition) => condition && s.setSkipped(true));
collector.addTestModifier('fail', (t, condition) => condition && t.setExpectation(t.Expectations.Fail));
collector.addSuiteModifier('fail', (s, condition) => condition && s.setExpectation(s.Expectations.Fail));
collector.addTestModifier('slow', t => t.setTimeout(t.timeout() * 3));
collector.addTestAttribute('debug', t => TraceTestEnvironment.enableForTest(t));
testRunner.api().fdescribe = testRunner.api().describe.only;
testRunner.api().xdescribe = testRunner.api().describe.skip(true);
testRunner.api().fit = testRunner.api().it.only;
testRunner.api().xit = testRunner.api().it.skip(true);
testRunner.api().dit = testRunner.api().it.only.debug;
const fixturePool = new FixturePool();
fixturePool.patchToEnableFixtures(global, 'beforeEach');
fixturePool.patchToEnableFixtures(global, 'afterEach');
collector.addTestCallbackWrapper(callback => fixturePool.wrapTestCallback(callback));
describe('', () => {
for (const name of fs.readdirSync('test')) {
const file = path.join(process.cwd(), 'test', name);
if (!name.includes('.spec.'))
continue;
const revert = pirates.addHook((code, filename) => {
const result = babel.transformFileSync(filename, {
presets: [
['@babel/preset-env', {targets: {node: 'current'}}],
'@babel/preset-typescript']
});
return result.code;
}, {
exts: ['.ts']
});
require(file);
revert();
delete require.cache[require.resolve(file)];
}
});
for (const [key, value] of Object.entries(testRunner.api())) {
// expect is used when running tests, while the rest of api is not.
if (key !== 'expect')
delete global[key];
}
return testRunner;
}
module.exports = collect;
if (require.main === module) {
console.log('Testing on Node', process.version);
const browserNames = ['chromium', 'firefox', 'webkit'].filter(name => {
return process.env.BROWSER === name || !process.env.BROWSER;
});
const testRunner = collect(browserNames);
const testNameFilter = getCLIArgument('--filter');
if (testNameFilter && !testRunner.focusMatchingNameTests(new RegExp(testNameFilter, 'i')).length) {
console.log('ERROR: no tests matched given `--filter` regex.');
process.exit(1);
}
const fileNameFilter = getCLIArgument('--file');
if (fileNameFilter && !testRunner.focusMatchingFileName(new RegExp(fileNameFilter, 'i')).length) {
console.log('ERROR: no files matched given `--file` regex.');
process.exit(1);
}
const repeat = parseInt(getCLIArgument('--repeat'), 10);
if (!isNaN(repeat))
testRunner.repeatAll(repeat);
testRunner.run().then(() => { delete global.expect; });
}

View file

@ -15,7 +15,7 @@
*/
const path = require('path');
const fs = require('fs');
const {installCoverageHooks} = require('../harness/coverage');
const {installCoverageHooks} = require('./coverage');
const browserName = process.env.BROWSER || 'chromium';

View file

@ -22,8 +22,9 @@ class DotReporter extends Base {
constructor(runner, options) {
super(runner, options);
runner.on(constants.EVENT_RUN_BEGIN, () => {
process.stdout.write('\n');
process.on('SIGINT', async () => {
Base.list(this.failures);
process.exit(130);
});
runner.on(constants.EVENT_TEST_PENDING, test => {

View file

@ -14,14 +14,14 @@
* limitations under the License.
*/
const { FixturePool, registerFixture, registerWorkerFixture } = require('../harness/fixturePool');
const { FixturePool, registerFixture, registerWorkerFixture } = require('./fixturePool');
const { Test, Suite } = require('mocha');
const pirates = require('pirates');
const babel = require('@babel/core');
const commonSuite = require('mocha/lib/interfaces/common');
Error.stackTraceLimit = 15;
global.testOptions = require('../harness/testOptions');
global.testOptions = require('./testOptions');
global.registerFixture = registerFixture;
global.registerWorkerFixture = registerWorkerFixture;
process.env.JEST_WORKER_ID = 1;

View file

@ -19,7 +19,9 @@ const path = require('path');
const program = require('commander');
const { Runner } = require('./runner');
const Mocha = require('mocha');
const constants = require('mocha/lib/runner').constants;
const { fixturesUI } = require('./fixturesUI');
const colors = require('colors/safe');
class NullReporter {}
@ -35,6 +37,7 @@ program
collectFiles(path.join(process.cwd(), 'test'), command.args, files);
const rootSuite = new Mocha.Suite('', new Mocha.Context(), true);
console.log(`Transpiling ${files.length} test files`);
// Build the test model, suite per file.
for (const file of files) {
const mocha = new Mocha({
@ -47,8 +50,14 @@ program
mocha.suite.title = path.basename(file);
mocha.suite.root = false;
rootSuite.suites.push(mocha.suite);
await new Promise(f => mocha.run(f));
await new Promise(f => {
const runner = mocha.run(f);
runner.on(constants.EVENT_RUN_BEGIN, () => {
process.stdout.write(colors.yellow('\u00B7'));
});
});
}
console.log();
const runner = new Runner(rootSuite, {
maxWorkers: command.maxWorkers,

View file

@ -51,7 +51,7 @@ class Runner extends EventEmitter {
if (suite.hasOnly())
suite.filterOnly();
console.log(`Running ${suite.total()} tests`);
console.log(`Running ${suite.total()} tests using ${this._maxWorkers} workers`);
this._traverse(suite);
}
@ -128,6 +128,7 @@ class Runner extends EventEmitter {
const worker = child_process.fork(path.join(__dirname, 'worker.js'), {
detached: false,
env: process.env,
stdio: 'ignore'
});
worker.on('exit', () => {
this._workers.delete(worker);

View file

@ -24,7 +24,7 @@ const browserName = process.env.BROWSER || 'chromium';
const goldenPath = path.join(__dirname, '..', 'golden-' + browserName);
const outputPath = path.join(__dirname, '..', 'output-' + browserName);
global.expect = require('expect');
global.testOptions = require('../harness/testOptions');
global.testOptions = require('./testOptions');
const constants = Mocha.Runner.constants;