playwright/test-runner/src/testCollector.ts

140 lines
4.9 KiB
TypeScript
Raw Normal View History

2020-08-18 23:12:31 +02:00
/**
* 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.
*/
import path from 'path';
import { fixturesForCallback } from './fixtures';
2020-08-22 09:05:24 +02:00
import { Configuration, Test, Suite } from './test';
import { fixturesUI } from './fixturesUI';
2020-08-18 23:12:31 +02:00
export class TestCollector {
suite: Suite;
2020-08-18 23:12:31 +02:00
private _matrix: { [key: string]: string; };
private _options: any;
private _grep: RegExp;
private _hasOnly: boolean;
constructor(files: string[], matrix: { [key: string] : string }, options) {
2020-08-20 21:51:05 +02:00
this._matrix = matrix;
2020-08-18 23:12:31 +02:00
this._options = options;
this.suite = new Suite('');
2020-08-18 23:12:31 +02:00
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);
2020-08-18 23:12:31 +02:00
}
hasOnly() {
return this._hasOnly;
}
_addFile(file) {
2020-08-22 09:05:24 +02:00
const suite = new Suite('');
const revertBabelRequire = fixturesUI(suite, file, this._options.timeout);
require(file);
revertBabelRequire();
suite._renumber();
2020-08-18 23:12:31 +02:00
const workerGeneratorConfigurations = new Map();
2020-08-22 09:05:24 +02:00
suite.eachTest((test: Test) => {
2020-08-18 23:12:31 +02:00
// Get all the fixtures that the test needs.
const fixtures = fixturesForCallback(test.fn);
2020-08-18 23:12:31 +02:00
// For generator fixtures, collect all variants of the fixture values
// to build different workers for them.
const generatorConfigurations = [];
for (const name of fixtures) {
2020-08-20 21:51:05 +02:00
const values = this._matrix[name];
if (!values)
2020-08-18 23:12:31 +02:00
continue;
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()) {
2020-08-22 09:05:24 +02:00
const clone = this._cloneSuite(suite, configurationObject, configurationString, tests);
2020-08-18 23:12:31 +02:00
this.suite.addSuite(clone);
clone.title = path.basename(file) + (hash.length ? `::[${hash}]` : '');
}
}
_cloneSuite(suite: Suite, configurationObject: Configuration, configurationString: string, tests: Set<Test>) {
2020-08-18 23:12:31 +02:00
const copy = suite.clone();
copy.only = suite.only;
copy.configuration = configurationObject;
2020-08-22 09:05:24 +02:00
for (const entry of suite._entries) {
if (entry instanceof Suite) {
copy.addSuite(this._cloneSuite(entry, configurationObject, configurationString, tests));
} else {
const test = entry;
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);
}
2020-08-18 23:12:31 +02:00
}
return copy;
}
2020-08-18 23:12:31 +02:00
_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;
}
2020-08-18 23:12:31 +02:00
}
module.exports = { TestCollector };