chore: create tests groups per project (#20463)

This commit is contained in:
Pavel Feldman 2023-01-28 09:30:42 -08:00 committed by GitHub
parent 7cb1b2db39
commit 2b499bd5d6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 56 additions and 57 deletions

View file

@ -74,6 +74,7 @@ export class Runner {
options, options,
reporter, reporter,
plugins: [], plugins: [],
testGroups: [],
}; };
reporter.onConfigure(config); reporter.onConfigure(config);

View file

@ -46,8 +46,8 @@ export type TaskRunnerState = {
reporter: Multiplexer; reporter: Multiplexer;
config: FullConfigInternal; config: FullConfigInternal;
plugins: TestRunnerPlugin[]; plugins: TestRunnerPlugin[];
testGroups: TestGroup[];
rootSuite?: Suite; rootSuite?: Suite;
testGroups?: TestGroup[];
dispatcher?: Dispatcher; dispatcher?: Dispatcher;
}; };
@ -59,7 +59,7 @@ export function createTaskRunner(config: FullConfigInternal, reporter: Multiplex
if (config.globalSetup || config.globalTeardown) if (config.globalSetup || config.globalTeardown)
taskRunner.addTask('global setup', createGlobalSetupTask()); taskRunner.addTask('global setup', createGlobalSetupTask());
taskRunner.addTask('load tests', createLoadTask()); taskRunner.addTask('load tests', createLoadTask());
taskRunner.addTask('shard tests', createTestGroupsTask());
taskRunner.addTask('prepare to run', createRemoveOutputDirsTask()); taskRunner.addTask('prepare to run', createRemoveOutputDirsTask());
taskRunner.addTask('plugin begin', async ({ rootSuite, plugins }) => { taskRunner.addTask('plugin begin', async ({ rootSuite, plugins }) => {
for (const plugin of plugins) for (const plugin of plugins)
@ -158,22 +158,22 @@ export function createRemoveOutputDirsTask(): Task<TaskRunnerState> {
function createLoadTask(): Task<TaskRunnerState> { function createLoadTask(): Task<TaskRunnerState> {
return async (context, errors) => { return async (context, errors) => {
const { config, reporter, options } = context; const { config, reporter, options } = context;
const rootSuite = await loadAllTests(config, reporter, options, errors); context.rootSuite = await loadAllTests(config, reporter, options, errors);
const testGroups = options.listOnly ? [] : createTestGroups(rootSuite.suites, config.workers);
context.rootSuite = rootSuite;
context.testGroups = testGroups;
if (errors.length)
return;
// Fail when no tests. // Fail when no tests.
if (!rootSuite.allTests().length && !context.options.passWithNoTests) if (!context.rootSuite.allTests().length && !context.options.passWithNoTests)
throw new Error(`No tests found`); throw new Error(`No tests found`);
};
if (!context.options.listOnly) { }
if (context.config.shard)
filterForShard(context.config.shard, rootSuite, testGroups); function createTestGroupsTask(): Task<TaskRunnerState> {
context.config._maxConcurrentTestGroups = testGroups.length; return async context => {
} const { config, rootSuite } = context;
for (const projectSuite of rootSuite!.suites)
context.testGroups.push(...createTestGroups(projectSuite, config.workers));
if (context.config.shard)
filterForShard(context.config.shard, rootSuite!, context.testGroups);
context.config._maxConcurrentTestGroups = context.testGroups.length;
}; };
} }

View file

@ -25,7 +25,7 @@ export type TestGroup = {
tests: TestCase[]; tests: TestCase[];
}; };
export function createTestGroups(projectSuites: Suite[], workers: number): TestGroup[] { export function createTestGroups(projectSuite: Suite, workers: number): TestGroup[] {
// This function groups tests that can be run together. // This function groups tests that can be run together.
// Tests cannot be run together when: // Tests cannot be run together when:
// - They belong to different projects - requires different workers. // - They belong to different projects - requires different workers.
@ -62,49 +62,47 @@ export function createTestGroups(projectSuites: Suite[], workers: number): TestG
}; };
}; };
for (const projectSuite of projectSuites) { for (const test of projectSuite.allTests()) {
for (const test of projectSuite.allTests()) { let withWorkerHash = groups.get(test._workerHash);
let withWorkerHash = groups.get(test._workerHash); if (!withWorkerHash) {
if (!withWorkerHash) { withWorkerHash = new Map();
withWorkerHash = new Map(); groups.set(test._workerHash, withWorkerHash);
groups.set(test._workerHash, withWorkerHash); }
} let withRequireFile = withWorkerHash.get(test._requireFile);
let withRequireFile = withWorkerHash.get(test._requireFile); if (!withRequireFile) {
if (!withRequireFile) { withRequireFile = {
withRequireFile = { general: createGroup(test),
general: createGroup(test), parallel: new Map(),
parallel: new Map(), parallelWithHooks: createGroup(test),
parallelWithHooks: createGroup(test), };
}; withWorkerHash.set(test._requireFile, withRequireFile);
withWorkerHash.set(test._requireFile, withRequireFile); }
}
// Note that a parallel suite cannot be inside a serial suite. This is enforced in TestType. // Note that a parallel suite cannot be inside a serial suite. This is enforced in TestType.
let insideParallel = false; let insideParallel = false;
let outerMostSerialSuite: Suite | undefined; let outerMostSerialSuite: Suite | undefined;
let hasAllHooks = false; let hasAllHooks = false;
for (let parent: Suite | undefined = test.parent; parent; parent = parent.parent) { for (let parent: Suite | undefined = test.parent; parent; parent = parent.parent) {
if (parent._parallelMode === 'serial') if (parent._parallelMode === 'serial')
outerMostSerialSuite = parent; outerMostSerialSuite = parent;
insideParallel = insideParallel || parent._parallelMode === 'parallel'; insideParallel = insideParallel || parent._parallelMode === 'parallel';
hasAllHooks = hasAllHooks || parent._hooks.some(hook => hook.type === 'beforeAll' || hook.type === 'afterAll'); hasAllHooks = hasAllHooks || parent._hooks.some(hook => hook.type === 'beforeAll' || hook.type === 'afterAll');
} }
if (insideParallel) { if (insideParallel) {
if (hasAllHooks && !outerMostSerialSuite) { if (hasAllHooks && !outerMostSerialSuite) {
withRequireFile.parallelWithHooks.tests.push(test); withRequireFile.parallelWithHooks.tests.push(test);
} else {
const key = outerMostSerialSuite || test;
let group = withRequireFile.parallel.get(key);
if (!group) {
group = createGroup(test);
withRequireFile.parallel.set(key, group);
}
group.tests.push(test);
}
} else { } else {
withRequireFile.general.tests.push(test); const key = outerMostSerialSuite || test;
let group = withRequireFile.parallel.get(key);
if (!group) {
group = createGroup(test);
withRequireFile.parallel.set(key, group);
}
group.tests.push(test);
} }
} else {
withRequireFile.general.tests.push(test);
} }
} }