chore: prepare to deps (#20513)

This commit is contained in:
Pavel Feldman 2023-01-30 14:34:48 -08:00 committed by GitHub
parent 99353038f0
commit 0dd090aeab
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 52 additions and 54 deletions

View File

@ -40,7 +40,7 @@ export class Dispatcher {
private _queue: TestGroup[] = []; private _queue: TestGroup[] = [];
private _queuedOrRunningHashCount = new Map<string, number>(); private _queuedOrRunningHashCount = new Map<string, number>();
private _finished = new ManualPromise<void>(); private _finished = new ManualPromise<void>();
private _isStopped = false; private _isStopped = true;
private _testById = new Map<string, TestData>(); private _testById = new Map<string, TestData>();
private _config: FullConfigInternal; private _config: FullConfigInternal;
@ -48,15 +48,9 @@ export class Dispatcher {
private _hasWorkerErrors = false; private _hasWorkerErrors = false;
private _failureCount = 0; private _failureCount = 0;
constructor(config: FullConfigInternal, testGroups: TestGroup[], reporter: Reporter) { constructor(config: FullConfigInternal, reporter: Reporter) {
this._config = config; this._config = config;
this._reporter = reporter; this._reporter = reporter;
this._queue = testGroups;
for (const group of testGroups) {
this._queuedOrRunningHashCount.set(group.workerHash, 1 + (this._queuedOrRunningHashCount.get(group.workerHash) || 0));
for (const test of group.tests)
this._testById.set(test.id, { test, resultByWorkerIndex: new Map() });
}
} }
private _processFullySkippedJobs() { private _processFullySkippedJobs() {
@ -167,7 +161,14 @@ export class Dispatcher {
return workersWithSameHash > this._queuedOrRunningHashCount.get(worker.hash())!; return workersWithSameHash > this._queuedOrRunningHashCount.get(worker.hash())!;
} }
async run() { async run(testGroups: TestGroup[]) {
this._queue = testGroups;
for (const group of testGroups) {
this._queuedOrRunningHashCount.set(group.workerHash, 1 + (this._queuedOrRunningHashCount.get(group.workerHash) || 0));
for (const test of group.tests)
this._testById.set(test.id, { test, resultByWorkerIndex: new Map() });
}
this._isStopped = false;
this._workerSlots = []; this._workerSlots = [];
// 1. Allocate workers. // 1. Allocate workers.
for (let i = 0; i < this._config.workers; i++) for (let i = 0; i < this._config.workers; i++)

View File

@ -22,11 +22,11 @@ import type { Multiplexer } from '../reporters/multiplexer';
import { createRootSuite, filterOnly, filterSuite } from '../common/suiteUtils'; import { createRootSuite, filterOnly, filterSuite } from '../common/suiteUtils';
import type { Suite, TestCase } from '../common/test'; import type { Suite, TestCase } from '../common/test';
import { loadTestFilesInProcess } from '../common/testLoader'; import { loadTestFilesInProcess } from '../common/testLoader';
import type { FullConfigInternal } from '../common/types'; import type { FullConfigInternal, FullProjectInternal } from '../common/types';
import { errorWithFile } from '../util'; import { errorWithFile } from '../util';
import type { Matcher, TestFileFilter } from '../util'; import type { Matcher, TestFileFilter } from '../util';
import { createFileMatcher } from '../util'; import { createFileMatcher } from '../util';
import { collectFilesForProjects, filterProjects } from './projectUtils'; import { collectFilesForProject, filterProjects } from './projectUtils';
import { requireOrImport } from '../common/transform'; import { requireOrImport } from '../common/transform';
import { serializeConfig } from '../common/ipc'; import { serializeConfig } from '../common/ipc';
@ -40,10 +40,13 @@ type LoadOptions = {
export async function loadAllTests(config: FullConfigInternal, reporter: Multiplexer, options: LoadOptions, errors: TestError[]): Promise<Suite> { export async function loadAllTests(config: FullConfigInternal, reporter: Multiplexer, options: LoadOptions, errors: TestError[]): Promise<Suite> {
const projects = filterProjects(config.projects, options.projectFilter); const projects = filterProjects(config.projects, options.projectFilter);
const filesByProject = await collectFilesForProjects(projects, options.testFileFilters); const filesByProject = new Map<FullProjectInternal, string[]>();
const allTestFiles = new Set<string>(); const allTestFiles = new Set<string>();
for (const files of filesByProject.values()) for (const project of projects) {
const files = await collectFilesForProject(project, options.testFileFilters);
filesByProject.set(project, files);
files.forEach(file => allTestFiles.add(file)); files.forEach(file => allTestFiles.add(file));
}
// Load all tests. // Load all tests.
const preprocessRoot = await loadTests(config, reporter, allTestFiles, errors); const preprocessRoot = await loadTests(config, reporter, allTestFiles, errors);

View File

@ -50,29 +50,22 @@ export function filterProjects(projects: FullProjectInternal[], projectNames?: s
return result; return result;
} }
export async function collectFilesForProjects(projects: FullProjectInternal[], commandLineFileFilters: TestFileFilter[]): Promise<Map<FullProjectInternal, string[]>> { export async function collectFilesForProject(project: FullProjectInternal, commandLineFileFilters: TestFileFilter[]): Promise<string[]> {
const extensions = ['.js', '.ts', '.mjs', '.tsx', '.jsx']; const extensions = ['.js', '.ts', '.mjs', '.tsx', '.jsx'];
const testFileExtension = (file: string) => extensions.includes(path.extname(file)); const testFileExtension = (file: string) => extensions.includes(path.extname(file));
const filesByProject = new Map<FullProjectInternal, string[]>();
const fileToProjectName = new Map<string, string>();
const commandLineFileMatcher = commandLineFileFilters.length ? createFileMatcherFromFilters(commandLineFileFilters) : () => true; const commandLineFileMatcher = commandLineFileFilters.length ? createFileMatcherFromFilters(commandLineFileFilters) : () => true;
for (const project of projects) { const allFiles = await collectFiles(project.testDir, project._respectGitIgnore);
const allFiles = await collectFiles(project.testDir, project._respectGitIgnore); const testMatch = createFileMatcher(project.testMatch);
const testMatch = createFileMatcher(project.testMatch); const testIgnore = createFileMatcher(project.testIgnore);
const testIgnore = createFileMatcher(project.testIgnore); const testFiles = allFiles.filter(file => {
const testFiles = allFiles.filter(file => { if (!testFileExtension(file))
if (!testFileExtension(file)) return false;
return false; const isTest = !testIgnore(file) && testMatch(file) && commandLineFileMatcher(file);
const isTest = !testIgnore(file) && testMatch(file) && commandLineFileMatcher(file); if (!isTest)
if (!isTest) return false;
return false; return true;
fileToProjectName.set(file, project.name); });
return true; return testFiles;
});
filesByProject.set(project, testFiles);
}
return filesByProject;
} }
async function collectFiles(testDir: string, respectGitIgnore: boolean): Promise<string[]> { async function collectFiles(testDir: string, respectGitIgnore: boolean): Promise<string[]> {

View File

@ -19,12 +19,13 @@ import { monotonicTime } from 'playwright-core/lib/utils';
import type { FullResult } from '../../types/testReporter'; import type { FullResult } from '../../types/testReporter';
import { dockerPlugin } from '../plugins/dockerPlugin'; import { dockerPlugin } from '../plugins/dockerPlugin';
import { webServerPluginsForConfig } from '../plugins/webServerPlugin'; import { webServerPluginsForConfig } from '../plugins/webServerPlugin';
import { collectFilesForProjects, filterProjects } from './projectUtils'; import { collectFilesForProject, filterProjects } from './projectUtils';
import { createReporter } from './reporters'; import { createReporter } from './reporters';
import { createTaskRunner, createTaskRunnerForList } from './tasks'; import { createTaskRunner, createTaskRunnerForList } from './tasks';
import type { TaskRunnerState } from './tasks'; import type { TaskRunnerState } from './tasks';
import type { FullConfigInternal } from '../common/types'; import type { FullConfigInternal } from '../common/types';
import type { Matcher, TestFileFilter } from '../util'; import type { Matcher, TestFileFilter } from '../util';
import { colors } from 'playwright-core/lib/utilsBundle';
export type RunOptions = { export type RunOptions = {
listOnly: boolean; listOnly: boolean;
@ -43,14 +44,13 @@ export class Runner {
async listTestFiles(projectNames: string[] | undefined): Promise<any> { async listTestFiles(projectNames: string[] | undefined): Promise<any> {
const projects = filterProjects(this._config.projects, projectNames); const projects = filterProjects(this._config.projects, projectNames);
const filesByProject = await collectFilesForProjects(projects, []);
const report: any = { const report: any = {
projects: [] projects: []
}; };
for (const [project, files] of filesByProject) { for (const project of projects) {
report.projects.push({ report.projects.push({
...sanitizeConfigForJSON(project, new Set()), ...sanitizeConfigForJSON(project, new Set()),
files files: await collectFilesForProject(project, [])
}); });
} }
return report; return report;
@ -78,6 +78,16 @@ export class Runner {
}; };
reporter.onConfigure(config); reporter.onConfigure(config);
if (!options.listOnly && config._ignoreSnapshots) {
reporter.onStdOut(colors.dim([
'NOTE: running with "ignoreSnapshots" option. All of the following asserts are silently ignored:',
'- expect().toMatchSnapshot()',
'- expect().toHaveScreenshot()',
'',
].join('\n')));
}
const taskStatus = await taskRunner.run(context, deadline); const taskStatus = await taskRunner.run(context, deadline);
let status: FullResult['status'] = 'passed'; let status: FullResult['status'] = 'passed';
if (context.dispatcher?.hasWorkerErrors() || context.rootSuite?.allTests().some(test => !test.ok())) if (context.dispatcher?.hasWorkerErrors() || context.rootSuite?.allTests().some(test => !test.ok()))

View File

@ -17,7 +17,7 @@
import fs from 'fs'; import fs from 'fs';
import path from 'path'; import path from 'path';
import { promisify } from 'util'; import { promisify } from 'util';
import { colors, rimraf } from 'playwright-core/lib/utilsBundle'; import { rimraf } from 'playwright-core/lib/utilsBundle';
import { Dispatcher } from './dispatcher'; import { Dispatcher } from './dispatcher';
import type { TestRunnerPlugin, TestRunnerPluginRegistration } from '../plugins'; import type { TestRunnerPlugin, TestRunnerPluginRegistration } from '../plugins';
import type { Multiplexer } from '../reporters/multiplexer'; import type { Multiplexer } from '../reporters/multiplexer';
@ -72,7 +72,7 @@ export function createTaskRunner(config: FullConfigInternal, reporter: Multiplex
}); });
taskRunner.addTask('setup workers', createSetupWorkersTask()); taskRunner.addTask('setup workers', createSetupWorkersTask());
taskRunner.addTask('test suite', async ({ dispatcher }) => dispatcher!.run()); taskRunner.addTask('test suite', async ({ dispatcher, testGroups }) => dispatcher!.run(testGroups));
return taskRunner; return taskRunner;
} }
@ -87,7 +87,7 @@ export function createTaskRunnerForList(config: FullConfigInternal, reporter: Mu
return taskRunner; return taskRunner;
} }
export function createPluginSetupTask(pluginRegistration: TestRunnerPluginRegistration): Task<TaskRunnerState> { function createPluginSetupTask(pluginRegistration: TestRunnerPluginRegistration): Task<TaskRunnerState> {
return async ({ config, reporter, plugins }) => { return async ({ config, reporter, plugins }) => {
let plugin: TestRunnerPlugin; let plugin: TestRunnerPlugin;
if (typeof pluginRegistration === 'function') if (typeof pluginRegistration === 'function')
@ -100,7 +100,7 @@ export function createPluginSetupTask(pluginRegistration: TestRunnerPluginRegist
}; };
} }
export function createGlobalSetupTask(): Task<TaskRunnerState> { function createGlobalSetupTask(): Task<TaskRunnerState> {
return async ({ config }) => { return async ({ config }) => {
const setupHook = config.globalSetup ? await loadGlobalHook(config, config.globalSetup) : undefined; const setupHook = config.globalSetup ? await loadGlobalHook(config, config.globalSetup) : undefined;
const teardownHook = config.globalTeardown ? await loadGlobalHook(config, config.globalTeardown) : undefined; const teardownHook = config.globalTeardown ? await loadGlobalHook(config, config.globalTeardown) : undefined;
@ -113,19 +113,10 @@ export function createGlobalSetupTask(): Task<TaskRunnerState> {
}; };
} }
export function createSetupWorkersTask(): Task<TaskRunnerState> { function createSetupWorkersTask(): Task<TaskRunnerState> {
return async params => { return async params => {
const { config, testGroups, reporter } = params; const { config, reporter } = params;
if (config._ignoreSnapshots) { const dispatcher = new Dispatcher(config, reporter);
reporter.onStdOut(colors.dim([
'NOTE: running with "ignoreSnapshots" option. All of the following asserts are silently ignored:',
'- expect().toMatchSnapshot()',
'- expect().toHaveScreenshot()',
'',
].join('\n')));
}
const dispatcher = new Dispatcher(config, testGroups!, reporter);
params.dispatcher = dispatcher; params.dispatcher = dispatcher;
return async () => { return async () => {
await dispatcher.stop(); await dispatcher.stop();
@ -133,7 +124,7 @@ export function createSetupWorkersTask(): Task<TaskRunnerState> {
}; };
} }
export function createRemoveOutputDirsTask(): Task<TaskRunnerState> { function createRemoveOutputDirsTask(): Task<TaskRunnerState> {
return async ({ config, options }) => { return async ({ config, options }) => {
const outputDirs = new Set<string>(); const outputDirs = new Set<string>();
for (const p of config.projects) { for (const p of config.projects) {