test: introduce test collector (#3515)

This commit is contained in:
Pavel Feldman 2020-08-18 14:12:31 -07:00 committed by GitHub
parent 510182f0b9
commit 77cab8bed3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 288 additions and 146 deletions

View File

@ -25,14 +25,13 @@ import { Transport } from '../lib/rpc/transport';
import { setUnderTest } from '../lib/helper';
import { installCoverageHooks } from './runner/coverage';
import { valueFromEnv } from './runner/utils';
import { registerFixture, registerWorkerFixture } from './runner/fixtures';
import { registerFixture, registerWorkerFixture, registerWorkerGenerator } from './runner/fixtures';
import './runner/builtin.fixtures';
import {mkdtempAsync, removeFolderAsync} from './utils';
setUnderTest(); // Note: we must call setUnderTest before requiring Playwright
const browserName = process.env.BROWSER || 'chromium';
const platform = os.platform();
declare global {
@ -58,6 +57,8 @@ declare global {
}
}
const browserName = process.env.BROWSER;
(global as any).MAC = platform === 'darwin';
(global as any).LINUX = platform === 'linux';
(global as any).WIN = platform === 'win32';
@ -92,7 +93,6 @@ const getExecutablePath = (browserName) => {
return process.env.FFPATH;
if (browserName === 'webkit' && process.env.WKPATH)
return process.env.WKPATH;
return
}
registerWorkerFixture('defaultBrowserOptions', async({browserName}, test) => {
@ -151,7 +151,7 @@ registerFixture('toImpl', async ({playwright}, test) => {
});
registerWorkerFixture('browserType', async ({playwright, browserName}, test) => {
const browserType = playwright[process.env.BROWSER || 'chromium']
const browserType = playwright[browserName];
const executablePath = getExecutablePath(browserName)
if (executablePath)
browserType._executablePath = executablePath
@ -184,8 +184,10 @@ registerFixture('server', async ({httpService}, test) => {
await test(httpService.server);
});
registerWorkerFixture('browserName', async ({}, test) => {
await test(browserName);
registerWorkerGenerator('browserName', () => {
if (process.env.BROWSER)
return [process.env.BROWSER];
return ['chromium', 'webkit', 'firefox'];
});
registerWorkerFixture('isChromium', async ({browserName}, test) => {
@ -216,5 +218,5 @@ registerWorkerFixture('asset', async ({}, test) => {
});
registerWorkerFixture('golden', async ({browserName}, test) => {
await test(p => path.join(`${browserName}`, p));
await test(p => path.join(browserName, p));
});

View File

@ -19,6 +19,7 @@ const debug = require('debug');
const registrations = new Map();
const registrationsByFile = new Map();
const generatorRegistrations = new Map();
class Fixture {
constructor(pool, name, scope, fn) {
@ -28,10 +29,13 @@ class Fixture {
this.fn = fn;
this.deps = fixtureParameterNames(this.fn);
this.usages = new Set();
this.value = null;
this.generatorValue = this.pool.generators.get(name);
this.value = this.generatorValue || null;
}
async setup() {
if (this.generatorValue)
return;
for (const name of this.deps) {
await this.pool.setupFixture(name);
this.pool.instances.get(name).usages.add(this.name);
@ -55,6 +59,8 @@ class Fixture {
}
async teardown() {
if (this.generatorValue)
return;
if (this._teardown)
return;
this._teardown = true;
@ -76,6 +82,7 @@ class Fixture {
class FixturePool {
constructor() {
this.instances = new Map();
this.generators = new Map();
}
async setupFixture(name) {
@ -120,21 +127,23 @@ class FixturePool {
}
};
}
}
fixtures(callback) {
const result = new Set();
const visit = (callback) => {
for (const name of fixtureParameterNames(callback)) {
if (name in result)
continue;
result.add(name);
const { fn } = registrations.get(name)
visit(fn);
}
};
visit(callback);
return result;
}
function fixturesForCallback(callback) {
const names = new Set();
const visit = (callback) => {
for (const name of fixtureParameterNames(callback)) {
if (name in names)
continue;
names.add(name);
const { fn } = registrations.get(name)
visit(fn);
}
};
visit(callback);
const result = [...names];
result.sort();
return result;
}
function fixtureParameterNames(fn) {
@ -165,6 +174,11 @@ function registerWorkerFixture(name, fn) {
innerRegisterFixture(name, 'worker', fn);
};
function registerWorkerGenerator(name, fn) {
innerRegisterFixture(name, 'worker', () => {});
generatorRegistrations.set(name, fn);
}
function collectRequires(file, result) {
if (result.has(file))
return;
@ -179,12 +193,16 @@ function lookupRegistrations(file, scope) {
const deps = new Set();
collectRequires(file, deps);
const allDeps = [...deps].reverse();
let result = [];
let result = new Map();
for (const dep of allDeps) {
const registrationList = registrationsByFile.get(dep);
if (!registrationList)
continue;
result = result.concat(registrationList.filter(r => r.scope === scope));
for (const r of registrationList) {
if (scope && r.scope !== scope)
continue;
result.set(r.name, r);
}
}
return result;
}
@ -192,7 +210,7 @@ function lookupRegistrations(file, scope) {
function rerunRegistrations(file, scope) {
// When we are running several tests in the same worker, we should re-run registrations before
// each file. That way we erase potential fixture overrides from the previous test runs.
for (const registration of lookupRegistrations(file, scope))
for (const registration of lookupRegistrations(file, scope).values())
registrations.set(registration.name, registration);
}
@ -202,9 +220,9 @@ function computeWorkerHash(file) {
// This collection of fixtures is the fingerprint of the worker setup, a "worker hash".
// Tests with the matching "worker hash" will reuse the same worker.
const hash = crypto.createHash('sha1');
for (const registration of lookupRegistrations(file, 'worker'))
for (const registration of lookupRegistrations(file, 'worker').values())
hash.update(registration.location);
return hash.digest('hex');
}
module.exports = { FixturePool, registerFixture, registerWorkerFixture, computeWorkerHash, rerunRegistrations };
module.exports = { FixturePool, registerFixture, registerWorkerFixture, computeWorkerHash, rerunRegistrations, lookupRegistrations, fixturesForCallback, registerWorkerGenerator, generatorRegistrations };

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
const { FixturePool, registerFixture, registerWorkerFixture, rerunRegistrations } = require('./fixtures');
const { registerFixture, registerWorkerFixture, registerWorkerGenerator } = require('./fixtures');
const { Test, Suite } = require('mocha');
const { installTransform } = require('./transform');
const commonSuite = require('mocha/lib/interfaces/common');
@ -23,8 +23,8 @@ Error.stackTraceLimit = 15;
global.testOptions = require('./testOptions');
global.registerFixture = registerFixture;
global.registerWorkerFixture = registerWorkerFixture;
global.registerWorkerGenerator = registerWorkerGenerator;
const fixturePool = new FixturePool();
let revertBabelRequire;
function specBuilder(modifiers, specCallback) {
@ -57,7 +57,7 @@ function specBuilder(modifiers, specCallback) {
return builder({}, null);
}
function fixturesUI(testRunner, suite) {
function fixturesUI(wrappers, suite) {
const suites = [suite];
suite.on(Suite.constants.EVENT_FILE_PRE_REQUIRE, function(context, file, mocha) {
@ -65,26 +65,18 @@ function fixturesUI(testRunner, suite) {
const it = specBuilder(['skip', 'fail', 'slow', 'only'], (specs, title, fn) => {
const suite = suites[0];
if (suite.isPending())
fn = null;
let wrapper;
const wrapped = fixturePool.wrapTestCallback(fn);
wrapper = wrapped ? (done, ...args) => {
if (!testRunner.shouldRunTest()) {
done();
return;
}
wrapped(...args).then(done).catch(done);
} : undefined;
const wrapper = fn ? wrappers.testWrapper(fn) : undefined;
if (wrapper) {
wrapper.toString = () => fn.toString();
wrapper.__original = fn;
}
const test = new Test(title, wrapper);
test.__fixtures = fixturePool.fixtures(fn);
test.file = file;
suite.addTest(test);
const only = specs.only && specs.only[0];
const only = wrappers.ignoreOnly ? false : specs.only && specs.only[0];
if (specs.slow && specs.slow[0])
test.timeout(90000);
if (only)
@ -102,7 +94,7 @@ function fixturesUI(testRunner, suite) {
file: file,
fn: fn
});
const only = specs.only && specs.only[0];
const only = wrappers.ignoreOnly ? false : specs.only && specs.only[0];
if (only)
suite.markOnly();
if (!only && specs.skip && specs.skip[0])
@ -112,23 +104,9 @@ function fixturesUI(testRunner, suite) {
return suite;
});
context.beforeEach = (fn) => {
if (!testRunner.shouldRunTest(true))
return;
return common.beforeEach(async () => {
return await fixturePool.resolveParametersAndRun(fn);
});
};
context.afterEach = (fn) => {
if (!testRunner.shouldRunTest(true))
return;
return common.afterEach(async () => {
return await fixturePool.resolveParametersAndRun(fn);
});
};
context.beforeEach = fn => wrappers.hookWrapper(common.beforeEach.bind(common), fn);
context.afterEach = fn => wrappers.hookWrapper(common.afterEach.bind(common), fn);
context.run = mocha.options.delay && common.runWithSuite(suite);
context.describe = describe;
context.fdescribe = describe.only(true);
context.xdescribe = describe.skip(true);
@ -141,8 +119,7 @@ function fixturesUI(testRunner, suite) {
suite.on(Suite.constants.EVENT_FILE_POST_REQUIRE, function(context, file, mocha) {
revertBabelRequire();
rerunRegistrations(file, 'test');
});
};
module.exports = { fixturesUI, fixturePool, registerFixture, registerWorkerFixture };
module.exports = { fixturesUI };

View File

@ -18,9 +18,7 @@ const fs = require('fs');
const path = require('path');
const program = require('commander');
const { Runner } = require('./runner');
const { TestRunner, createTestSuite } = require('./testRunner');
class NullReporter {}
const { TestCollector } = require('./testCollector');
program
.version('Version ' + require('../../package.json').version)
@ -38,42 +36,31 @@ program
// Collect files]
const testDir = path.join(process.cwd(), command.args[0]);
const files = collectFiles(testDir, '', command.args.slice(1));
const rootSuite = new createTestSuite();
let total = 0;
// Build the test model, suite per file.
for (const file of files) {
const testRunner = new TestRunner(file, [], {
forbidOnly: command.forbidOnly || undefined,
grep: command.grep,
reporter: NullReporter,
testDir,
timeout: command.timeout,
trialRun: true,
});
total += testRunner.grepTotal();
rootSuite.addSuite(testRunner.suite);
testRunner.suite.title = path.basename(file);
}
const testCollector = new TestCollector({
forbidOnly: command.forbidOnly || undefined,
grep: command.grep,
timeout: command.timeout,
});
for (const file of files)
testCollector.addFile(file);
const rootSuite = testCollector.suite;
const total = rootSuite.total();
if (!total) {
console.error('No tests found.');
console.error('=================');
console.error(' No tests found.');
console.error('=================');
process.exit(1);
}
// Filter tests.
if (rootSuite.hasOnly())
rootSuite.filterOnly();
if (!command.reporter) {
console.log();
total = Math.min(total, rootSuite.total()); // First accounts for grep, second for only.
const workers = Math.min(command.jobs, files.length);
console.log(`Running ${total} test${ total > 1 ? 's' : '' } using ${workers} worker${ workers > 1 ? 's' : ''}`);
}
// Trial run does not need many workers, use one.
const jobs = (command.trialRun || command.debug) ? 1 : command.jobs;
const runner = new Runner(rootSuite, {
const runner = new Runner(rootSuite, total, {
debug: command.debug,
quiet: command.quiet,
grep: command.grep,

View File

@ -27,7 +27,7 @@ const constants = Mocha.Runner.constants;
process.setMaxListeners(0);
class Runner extends EventEmitter {
constructor(suite, options) {
constructor(suite, total, options) {
super();
this._suite = suite;
this._options = options;
@ -45,30 +45,36 @@ class Runner extends EventEmitter {
const reporterFactory = builtinReporters[options.reporter] || DotRunner;
this._reporter = new reporterFactory(this, {});
this._tests = new Map();
this._files = new Map();
let grep;
if (options.grep) {
const match = options.grep.match(/^\/(.*)\/(g|i|)$|.*/);
grep = new RegExp(match[1] || match[0], match[2]);
}
this._testById = new Map();
this._testsByConfiguredFile = new Map();
suite.eachTest(test => {
if (grep && !grep.test(test.fullTitle()))
return;
if (!this._files.has(test.file))
this._files.set(test.file, 0);
const counter = this._files.get(test.file);
this._files.set(test.file, counter + 1);
this._tests.set(`${test.file}::${counter}`, test);
const configuredFile = `${test.file}::[${test.__configurationString}]`;
if (!this._testsByConfiguredFile.has(configuredFile)) {
this._testsByConfiguredFile.set(configuredFile, {
file: test.file,
configuredFile,
ordinals: [],
configurationObject: test.__configurationObject,
configurationString: test.__configurationString
});
}
const { ordinals } = this._testsByConfiguredFile.get(configuredFile);
ordinals.push(test.__ordinal);
this._testById.set(`${test.__ordinal}@${configuredFile}`, test);
});
if (process.stdout.isTTY) {
console.log();
const jobs = Math.min(options.jobs, this._testsByConfiguredFile.size);
console.log(`Running ${total} test${ total > 1 ? 's' : '' } using ${jobs} worker${ jobs > 1 ? 's' : ''}`);
}
}
_filesSortedByWorkerHash() {
const result = [];
for (const [file, count] of this._files.entries())
result.push({ file, hash: computeWorkerHash(file), ordinals: new Array(count).fill(0).map((_, i) => i) });
for (const entry of this._testsByConfiguredFile.values())
result.push({ ...entry, hash: entry.configurationString + '@' + computeWorkerHash(entry.file) });
result.sort((a, b) => a.hash < b.hash ? -1 : (a.hash === b.hash ? 0 : 1));
return result;
}
@ -170,7 +176,7 @@ class Runner extends EventEmitter {
}
_updateTest(serialized) {
const test = this._tests.get(serialized.id);
const test = this._testById.get(serialized.id);
test.duration = serialized.duration;
return test;
}
@ -228,7 +234,7 @@ class OopWorker extends EventEmitter {
run(entry) {
this.hash = entry.hash;
this.process.send({ method: 'run', params: { file: entry.file, ordinals: entry.ordinals, options: this.runner._options } });
this.process.send({ method: 'run', params: { entry, options: this.runner._options } });
}
stop() {
@ -252,7 +258,7 @@ class InProcessWorker extends EventEmitter {
constructor(runner) {
super();
this.runner = runner;
this.fixturePool = require('./fixturesUI').fixturePool;
this.fixturePool = require('./testRunner').fixturePool;
}
async init() {
@ -265,7 +271,7 @@ class InProcessWorker extends EventEmitter {
async run(entry) {
delete require.cache[entry.file];
const { TestRunner } = require('./testRunner');
const testRunner = new TestRunner(entry.file, entry.ordinals, this.runner._options);
const testRunner = new TestRunner(entry, this.runner._options);
for (const event of ['test', 'pending', 'pass', 'fail', 'done'])
testRunner.on(event, this.emit.bind(this, event));
testRunner.run();

View File

@ -0,0 +1,135 @@
/**
* 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 path = require('path');
const Mocha = require('mocha');
const { fixturesForCallback, generatorRegistrations } = require('./fixtures');
const { fixturesUI } = require('./fixturesUI');
global.testOptions = require('./testOptions');
class NullReporter {}
class TestCollector {
constructor(options) {
this._options = options;
this.suite = new Mocha.Suite('', new Mocha.Context(), true);
this._total = 0;
if (options.grep) {
const match = options.grep.match(/^\/(.*)\/(g|i|)$|.*/);
this._grep = new RegExp(match[1] || match[0], match[2]);
}
}
addFile(file) {
const mocha = new Mocha({
forbidOnly: this._options.forbidOnly,
reporter: NullReporter,
timeout: this._options.timeout,
ui: fixturesUI.bind(null, {
testWrapper: (fn) => done => done(),
hookWrapper: (hook, fn) => {},
ignoreOnly: false,
}),
});
mocha.addFile(file);
mocha.loadFiles();
const workerGeneratorConfigurations = new Map();
let ordinal = 0;
mocha.suite.eachTest(test => {
// All tests are identified with their ordinals.
test.__ordinal = ordinal++;
// Get all the fixtures that the test needs.
const fixtures = fixturesForCallback(test.fn.__original);
// For generator fixtures, collect all variants of the fixture values
// to build different workers for them.
const generatorConfigurations = [];
for (const name of fixtures) {
if (!generatorRegistrations.has(name))
continue;
const values = generatorRegistrations.get(name)();
let state = generatorConfigurations.length ? generatorConfigurations.slice() : [[]];
generatorConfigurations.length = 0;
for (const gen of state) {
for (const value of values)
generatorConfigurations.push([...gen, { name, value }]);
}
}
// No generator fixtures for test, include empty set.
if (!generatorConfigurations.length)
generatorConfigurations.push([]);
for (const configurationObject of generatorConfigurations) {
// Serialize configuration as readable string, we will use it as a hash.
const tokens = [];
for (const { name, value } of configurationObject)
tokens.push(`${name}=${value}`);
const configurationString = tokens.join(', ');
// Allocate worker for this configuration, add test into it.
if (!workerGeneratorConfigurations.has(configurationString))
workerGeneratorConfigurations.set(configurationString, { configurationObject, configurationString, tests: new Set() });
workerGeneratorConfigurations.get(configurationString).tests.add(test);
}
});
if (mocha.suite.hasOnly())
mocha.suite.filterOnly();
// Clone the suite as many times as there are worker hashes.
// Only include the tests that requested these generations.
for (const [hash, {configurationObject, configurationString, tests}] of workerGeneratorConfigurations.entries()) {
const clone = this._cloneSuite(mocha.suite, configurationObject, configurationString, tests);
this.suite.addSuite(clone);
clone.title = path.basename(file) + (hash.length ? `::[${hash}]` : '');
}
}
_cloneSuite(suite, configurationObject, configurationString, tests) {
const copy = suite.clone();
copy.__configurationObject = configurationObject;
for (const child of suite.suites)
copy.addSuite(this._cloneSuite(child, configurationObject, configurationString, tests));
for (const test of suite.tests) {
if (!tests.has(test))
continue;
if (this._grep && !this._grep.test(test.fullTitle()))
continue;
const testCopy = test.clone();
testCopy.__ordinal = test.__ordinal;
testCopy.__configurationObject = configurationObject;
testCopy.__configurationString = configurationString;
copy.addTest(testCopy);
}
return copy;
}
}
function grepTotal(mocha, suite) {
let total = 0;
suite.eachTest(test => {
if (mocha.options.grep.test(test.fullTitle()))
total++;
});
return total;
}
module.exports = { TestCollector };

View File

@ -16,9 +16,11 @@
const path = require('path');
const Mocha = require('mocha');
const { FixturePool, rerunRegistrations, fixturesForCallback } = require('./fixtures');
const { fixturesUI } = require('./fixturesUI');
const { EventEmitter } = require('events');
const fixturePool = new FixturePool();
global.expect = require('expect');
global.testOptions = require('./testOptions');
const GoldenUtils = require('./GoldenUtils');
@ -26,27 +28,34 @@ const GoldenUtils = require('./GoldenUtils');
class NullReporter {}
class TestRunner extends EventEmitter {
constructor(file, ordinals, options) {
constructor(entry, options) {
super();
this.mocha = new Mocha({
forbidOnly: options.forbidOnly,
reporter: NullReporter,
timeout: options.timeout,
ui: fixturesUI.bind(null, this),
ui: fixturesUI.bind(null, {
testWrapper: fn => this._testWrapper(fn),
hookWrapper: (hook, fn) => this._hookWrapper(hook, fn),
ignoreOnly: true
}),
});
if (options.grep)
this.mocha.grep(options.grep);
this._currentOrdinal = -1;
this._failedWithError = false;
this._ordinals = new Set(ordinals);
this._remaining = new Set(ordinals);
this._file = entry.file;
this._ordinals = new Set(entry.ordinals);
this._remaining = new Set(entry.ordinals);
this._trialRun = options.trialRun;
this._passes = 0;
this._failures = 0;
this._pending = 0;
this._relativeTestFile = path.relative(options.testDir, file);
this.mocha.addFile(file);
this.mocha.suite.filterOnly();
this._configuredFile = entry.configuredFile;
this._configurationObject = entry.configurationObject;
this._configurationString = entry.configurationString;
this._parsedGeneratorConfiguration = new Map();
for (const {name, value} of this._configurationObject)
this._parsedGeneratorConfiguration.set(name, value);
this._relativeTestFile = path.relative(options.testDir, this._file);
this.mocha.addFile(this._file);
this.mocha.loadFiles();
this.suite = this.mocha.suite;
}
@ -54,6 +63,9 @@ class TestRunner extends EventEmitter {
async run() {
let callback;
const result = new Promise(f => callback = f);
rerunRegistrations(this._file, 'test');
for (const [name, value] of this._parsedGeneratorConfiguration)
fixturePool.generators.set(name, value);
const runner = this.mocha.run(callback);
const constants = Mocha.Runner.constants;
@ -65,7 +77,7 @@ class TestRunner extends EventEmitter {
if (this._ordinals.size && !this._ordinals.has(ordinal))
return;
this._remaining.delete(ordinal);
this.emit('test', { test: serializeTest(test, ordinal) });
this.emit('test', { test: this._serializeTest(test, ordinal) });
});
runner.on(constants.EVENT_TEST_PENDING, test => {
@ -76,7 +88,7 @@ class TestRunner extends EventEmitter {
return;
this._remaining.delete(ordinal);
++this._pending;
this.emit('pending', { test: serializeTest(test, ordinal) });
this.emit('pending', { test: this._serializeTest(test, ordinal) });
});
runner.on(constants.EVENT_TEST_PASS, test => {
@ -87,7 +99,7 @@ class TestRunner extends EventEmitter {
if (this._ordinals.size && !this._ordinals.has(ordinal))
return;
++this._passes;
this.emit('pass', { test: serializeTest(test, ordinal) });
this.emit('pass', { test: this._serializeTest(test, ordinal) });
});
runner.on(constants.EVENT_TEST_FAIL, (test, error) => {
@ -96,7 +108,7 @@ class TestRunner extends EventEmitter {
++this._failures;
this._failedWithError = error;
this.emit('fail', {
test: serializeTest(test, this._currentOrdinal),
test: this._serializeTest(test, this._currentOrdinal),
error: serializeError(error),
});
});
@ -112,7 +124,7 @@ class TestRunner extends EventEmitter {
await result;
}
shouldRunTest(hook) {
_shouldRunTest(hook) {
if (this._trialRun || this._failedWithError)
return false;
if (hook) {
@ -126,15 +138,32 @@ class TestRunner extends EventEmitter {
return true;
}
grepTotal() {
let total = 0;
this.suite.eachTest(test => {
if (this.mocha.options.grep.test(test.fullTitle()))
total++;
});
return total;
_testWrapper(fn) {
const wrapped = fixturePool.wrapTestCallback(fn);
return wrapped ? (done, ...args) => {
if (!this._shouldRunTest()) {
done();
return;
}
wrapped(...args).then(done).catch(done);
} : undefined;
}
_hookWrapper(hook, fn) {
if (!this._shouldRunTest(true))
return;
return hook(async () => {
return await fixturePool.resolveParametersAndRun(fn);
});
}
_serializeTest(test, ordinal) {
return {
id: `${ordinal}@${this._configuredFile}`,
duration: test.duration,
};
}
_serializeStats(stats) {
return {
passes: this._passes,
@ -145,17 +174,6 @@ class TestRunner extends EventEmitter {
}
}
function createTestSuite() {
return new Mocha.Suite('', new Mocha.Context(), true);
}
function serializeTest(test, origin) {
return {
id: `${test.file}::${origin}`,
duration: test.duration,
};
}
function trimCycles(obj) {
const cache = new Set();
return JSON.parse(
@ -190,4 +208,4 @@ function initializeImageMatcher(options) {
global.expect.extend({ toMatchImage });
}
module.exports = { TestRunner, createTestSuite, initializeImageMatcher };
module.exports = { TestRunner, initializeImageMatcher, fixturePool };

View File

@ -14,9 +14,8 @@
* limitations under the License.
*/
const { fixturePool } = require('./fixturesUI');
const { gracefullyCloseAll } = require('../../lib/server/processLauncher');
const { TestRunner, initializeImageMatcher } = require('./testRunner');
const { TestRunner, initializeImageMatcher, fixturePool } = require('./testRunner');
const { initializeWorker } = require('./builtin.fixtures');
const util = require('util');
@ -57,7 +56,7 @@ process.on('message', async message => {
return;
}
if (message.method === 'run') {
const testRunner = new TestRunner(message.params.file, message.params.ordinals, message.params.options);
const testRunner = new TestRunner(message.params.entry, message.params.options);
for (const event of ['test', 'pending', 'pass', 'fail', 'done'])
testRunner.on(event, sendMessageToParent.bind(null, event));
await testRunner.run();