chore: fix oop loading, prepare to watch (#20618)

This commit is contained in:
Pavel Feldman 2023-02-03 09:11:02 -08:00 committed by GitHub
parent adab7a817e
commit ffb719385b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 49 additions and 27 deletions

View File

@ -159,7 +159,7 @@ async function runTests(args: string[], opts: { [key: string]: any }) {
configLoader.ignoreProjectDependencies();
const config = configLoader.fullConfig();
config._internal.testFileFilters = args.map(arg => {
config._internal.cliFileFilters = args.map(arg => {
const match = /^(.*?):(\d+):?(\d+)?$/.exec(arg);
return {
re: forceRegExp(match ? match[1] : arg),
@ -169,9 +169,9 @@ async function runTests(args: string[], opts: { [key: string]: any }) {
});
const grepMatcher = opts.grep ? createTitleMatcher(forceRegExp(opts.grep)) : () => true;
const grepInvertMatcher = opts.grepInvert ? createTitleMatcher(forceRegExp(opts.grepInvert)) : () => false;
config._internal.testTitleMatcher = (title: string) => !grepInvertMatcher(title) && grepMatcher(title);
config._internal.cliTitleMatcher = (title: string) => !grepInvertMatcher(title) && grepMatcher(title);
config._internal.listOnly = !!opts.list;
config._internal.projectFilter = opts.project || undefined;
config._internal.cliProjectFilter = opts.project || undefined;
config._internal.passWithNoTests = !!opts.passWithNoTests;
const runner = new Runner(config);

View File

@ -94,7 +94,12 @@ export function serializeCompilationCache(): any {
};
}
export function initializeCompilationCache(payload: any) {
export function clearCompilationCache() {
sourceMaps.clear();
memoryCache.clear();
}
export function addToCompilationCache(payload: any) {
for (const entry of payload.sourceMaps)
sourceMaps.set(entry[0], entry[1]);
for (const entry of payload.memoryCache)

View File

@ -450,8 +450,8 @@ export const baseFullConfig: FullConfigInternal = {
maxConcurrentTestGroups: 0,
ignoreSnapshots: false,
plugins: [],
testTitleMatcher: () => true,
testFileFilters: [],
cliTitleMatcher: () => true,
cliFileFilters: [],
listOnly: false,
}
};

View File

@ -50,9 +50,9 @@ type ConfigInternal = {
webServers: Exclude<FullConfigPublic['webServer'], null>[];
plugins: TestRunnerPluginRegistration[];
listOnly: boolean;
testFileFilters: TestFileFilter[];
testTitleMatcher: Matcher;
projectFilter?: string[];
cliFileFilters: TestFileFilter[];
cliTitleMatcher: Matcher;
cliProjectFilter?: string[];
passWithNoTests?: boolean;
};

View File

@ -20,6 +20,7 @@ import { ProcessRunner } from '../common/process';
import type { FullConfigInternal } from '../common/types';
import { loadTestFile } from '../common/testLoader';
import type { TestError } from '../../reporter';
import { addToCompilationCache, serializeCompilationCache } from '../common/compilationCache';
export class LoaderMain extends ProcessRunner {
private _serializedConfig: SerializedConfig;
@ -27,6 +28,7 @@ export class LoaderMain extends ProcessRunner {
constructor(serializedConfig: SerializedConfig) {
super();
addToCompilationCache(serializedConfig.compilationCache);
this._serializedConfig = serializedConfig;
}
@ -39,8 +41,12 @@ export class LoaderMain extends ProcessRunner {
async loadTestFile(params: { file: string }) {
const testErrors: TestError[] = [];
const config = await this._config();
const rootSuite = await loadTestFile(params.file, config.rootDir, testErrors);
return { rootSuite: rootSuite._deepSerialize(), testErrors };
const fileSuite = await loadTestFile(params.file, config.rootDir, testErrors);
return { fileSuite: fileSuite._deepSerialize(), testErrors };
}
async serializeCompilationCache() {
return serializeCompilationCache();
}
}

View File

@ -21,15 +21,15 @@ import type { LoaderHost } from './loaderHost';
import { Suite } from '../common/test';
import type { TestCase } from '../common/test';
import type { FullConfigInternal, FullProjectInternal } from '../common/types';
import { createFileMatcherFromFilters, createTitleMatcher, errorWithFile } from '../util';
import { createTitleMatcher, errorWithFile } from '../util';
import type { Matcher, TestFileFilter } from '../util';
import { buildProjectsClosure, collectFilesForProject, filterProjects } from './projectUtils';
import { requireOrImport } from '../common/transform';
import { buildFileSuiteForProject, filterByFocusedLine, filterOnly, filterTestsRemoveEmptySuites } from '../common/suiteUtils';
import { filterForShard } from './testGroups';
export async function loadAllTests(config: FullConfigInternal, errors: TestError[]): Promise<Suite> {
const projects = filterProjects(config.projects, config._internal.projectFilter);
export async function loadAllTests(config: FullConfigInternal, projectsToIgnore: Set<FullProjectInternal>, fileMatcher: Matcher, errors: TestError[]): Promise<Suite> {
const projects = filterProjects(config.projects, config._internal.cliProjectFilter);
let filesToRunByProject = new Map<FullProjectInternal, string[]>();
let topLevelProjects: FullProjectInternal[];
@ -41,14 +41,15 @@ export async function loadAllTests(config: FullConfigInternal, errors: TestError
// First collect all files for the projects in the command line, don't apply any file filters.
const allFilesForProject = new Map<FullProjectInternal, string[]>();
for (const project of projects) {
if (projectsToIgnore.has(project))
continue;
const files = await collectFilesForProject(project, fsCache);
allFilesForProject.set(project, files);
}
// Filter files based on the file filters, eliminate the empty projects.
const commandLineFileMatcher = config._internal.testFileFilters.length ? createFileMatcherFromFilters(config._internal.testFileFilters) : null;
for (const [project, files] of allFilesForProject) {
const filteredFiles = commandLineFileMatcher ? files.filter(commandLineFileMatcher) : files;
const filteredFiles = files.filter(fileMatcher);
if (filteredFiles.length)
filesToRunByProject.set(project, filteredFiles);
}
@ -67,6 +68,9 @@ export async function loadAllTests(config: FullConfigInternal, errors: TestError
topLevelProjects = filteredProjectClosure.filter(p => p._internal.type === 'top-level');
dependencyProjects = filteredProjectClosure.filter(p => p._internal.type === 'dependency');
topLevelProjects = topLevelProjects.filter(p => !projectsToIgnore.has(p));
dependencyProjects = dependencyProjects.filter(p => !projectsToIgnore.has(p));
// (Re-)add all files for dependent projects, disregard filters.
for (const project of dependencyProjects) {
const files = allFilesForProject.get(project) || await collectFilesForProject(project, fsCache);
@ -113,7 +117,7 @@ export async function loadAllTests(config: FullConfigInternal, errors: TestError
// Prepend the projects that are dependencies.
for (const project of dependencyProjects) {
const projectSuite = await createProjectSuite(fileSuits, project, { testFileFilters: [], testTitleMatcher: undefined }, filesToRunByProject.get(project)!);
const projectSuite = await createProjectSuite(fileSuits, project, { cliFileFilters: [], cliTitleMatcher: undefined }, filesToRunByProject.get(project)!);
if (projectSuite)
rootSuite._prependSuite(projectSuite);
}
@ -121,7 +125,7 @@ export async function loadAllTests(config: FullConfigInternal, errors: TestError
return rootSuite;
}
async function createProjectSuite(fileSuits: Suite[], project: FullProjectInternal, options: { testFileFilters: TestFileFilter[], testTitleMatcher?: Matcher }, files: string[]): Promise<Suite | null> {
async function createProjectSuite(fileSuits: Suite[], project: FullProjectInternal, options: { cliFileFilters: TestFileFilter[], cliTitleMatcher?: Matcher }, files: string[]): Promise<Suite | null> {
const fileSuitesMap = new Map<string, Suite>();
for (const fileSuite of fileSuits)
fileSuitesMap.set(fileSuite._requireFile, fileSuite);
@ -140,7 +144,7 @@ async function createProjectSuite(fileSuits: Suite[], project: FullProjectIntern
}
}
// Filter tests to respect line/column filter.
filterByFocusedLine(projectSuite, options.testFileFilters);
filterByFocusedLine(projectSuite, options.cliFileFilters);
const grepMatcher = createTitleMatcher(project.grep);
const grepInvertMatcher = project.grepInvert ? createTitleMatcher(project.grepInvert) : null;
@ -149,7 +153,7 @@ async function createProjectSuite(fileSuits: Suite[], project: FullProjectIntern
const grepTitle = test.titlePath().join(' ');
if (grepInvertMatcher?.(grepTitle))
return false;
return grepMatcher(grepTitle) && (!options.testTitleMatcher || options.testTitleMatcher(grepTitle));
return grepMatcher(grepTitle) && (!options.cliTitleMatcher || options.cliTitleMatcher(grepTitle));
};
if (filterTestsRemoveEmptySuites(projectSuite, titleMatcher))

View File

@ -22,6 +22,7 @@ import { loadTestFile } from '../common/testLoader';
import type { LoadError } from '../common/fixtures';
import type { FullConfigInternal } from '../common/types';
import { PoolBuilder } from '../common/poolBuilder';
import { addToCompilationCache } from '../common/compilationCache';
export abstract class LoaderHost {
protected _config: FullConfigInternal;
@ -56,18 +57,20 @@ export class OutOfProcessLoaderHost extends LoaderHost {
constructor(config: FullConfigInternal) {
super(config);
this._processHost = new ProcessHost(require.resolve('../loaderMain.js'), 'loader');
this._processHost = new ProcessHost(require.resolve('../loader/loaderMain.js'), 'loader');
this._startPromise = this._processHost.startRunner(serializeConfig(config), true, {});
}
async doLoadTestFile(file: string, loadErrors: LoadError[]): Promise<Suite> {
await this._startPromise;
const result = await this._processHost.sendMessage({ method: 'loadTestFile', params: { file } }) as any;
loadErrors.push(...result.loadErrors);
loadErrors.push(...result.testErrors);
return Suite._deepParse(result.fileSuite);
}
override async stop() {
const result = await this._processHost.sendMessage({ method: 'serializeCompilationCache' }) as any;
addToCompilationCache(result);
await this._processHost.stop();
}
}

View File

@ -28,6 +28,8 @@ import { TaskRunner } from './taskRunner';
import type { Suite } from '../common/test';
import type { FullConfigInternal, FullProjectInternal } from '../common/types';
import { loadAllTests, loadGlobalHook } from './loadUtils';
import { createFileMatcherFromFilters } from '../util';
import type { Matcher } from '../util';
const removeFolderAsync = promisify(rimraf);
const readDirAsync = promisify(fs.readdir);
@ -106,7 +108,7 @@ function createRemoveOutputDirsTask(): Task<TaskRunnerState> {
return async ({ config }) => {
const outputDirs = new Set<string>();
for (const p of config.projects) {
if (!config._internal.projectFilter || config._internal.projectFilter.includes(p.name))
if (!config._internal.cliProjectFilter || config._internal.cliProjectFilter.includes(p.name))
outputDirs.add(p.outputDir);
}
@ -124,10 +126,12 @@ function createRemoveOutputDirsTask(): Task<TaskRunnerState> {
};
}
function createLoadTask(): Task<TaskRunnerState> {
function createLoadTask(projectsToIgnore = new Set<FullProjectInternal>(), additionalFileMatcher?: Matcher): Task<TaskRunnerState> {
return async (context, errors) => {
const { config } = context;
context.rootSuite = await loadAllTests(config, errors);
const cliMatcher = config._internal.cliFileFilters.length ? createFileMatcherFromFilters(config._internal.cliFileFilters) : () => true;
const fileMatcher = (value: string) => cliMatcher(value) && (additionalFileMatcher ? additionalFileMatcher(value) : true);
context.rootSuite = await loadAllTests(config, projectsToIgnore, fileMatcher, errors);
// Fail when no tests.
if (!context.rootSuite.allTests().length && !config._internal.passWithNoTests && !config.shard)
throw new Error(`No tests found`);

View File

@ -31,7 +31,7 @@ import { ProcessRunner } from '../common/process';
import { loadTestFile } from '../common/testLoader';
import { buildFileSuiteForProject, filterTestsRemoveEmptySuites } from '../common/suiteUtils';
import { PoolBuilder } from '../common/poolBuilder';
import { initializeCompilationCache } from '../common/compilationCache';
import { addToCompilationCache } from '../common/compilationCache';
const removeFolderAsync = util.promisify(rimraf);
@ -67,7 +67,7 @@ export class WorkerMain extends ProcessRunner {
process.env.TEST_WORKER_INDEX = String(params.workerIndex);
process.env.TEST_PARALLEL_INDEX = String(params.parallelIndex);
setIsWorkerProcess();
initializeCompilationCache(params.config.compilationCache);
addToCompilationCache(params.config.compilationCache);
this._params = params;
this._fixtureRunner = new FixtureRunner();