mirror of
https://github.com/microsoft/playwright.git
synced 2025-06-26 21:40:17 +00:00
144 lines
5.0 KiB
JavaScript
144 lines
5.0 KiB
JavaScript
/**
|
|
* 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(files, 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]);
|
|
}
|
|
|
|
for (const file of files)
|
|
this._addFile(file);
|
|
|
|
this._hasOnly = this._filterOnly(this.suite);
|
|
}
|
|
|
|
hasOnly() {
|
|
return this._hasOnly;
|
|
}
|
|
|
|
_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);
|
|
}
|
|
});
|
|
|
|
// 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.__only = suite.__only;
|
|
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.__only = test.__only;
|
|
testCopy.__ordinal = test.__ordinal;
|
|
testCopy.__configurationObject = configurationObject;
|
|
testCopy.__configurationString = configurationString;
|
|
copy.addTest(testCopy);
|
|
}
|
|
return copy;
|
|
}
|
|
|
|
_filterOnly(suite) {
|
|
const onlySuites = suite.suites.filter(child => this._filterOnly(child) || child.__only);
|
|
const onlyTests = suite.tests.filter(test => test.__only);
|
|
if (onlySuites.length || onlyTests.length) {
|
|
suite.suites = onlySuites;
|
|
suite.tests = onlyTests;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
module.exports = { TestCollector };
|