chore(test runner): process-wide cache of required test files (#11230)

This is a preparation to TestRunner api, where we should be
able to run tests multiple times in the same runner process.
This commit is contained in:
Dmitry Gozman 2022-01-06 15:38:10 -08:00 committed by GitHub
parent 16dafba153
commit 19460d50e4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 12 additions and 16 deletions

View file

@ -29,6 +29,11 @@ import { BuiltInReporter, builtInReporters } from './runner';
import { isRegExp } from 'playwright-core/lib/utils/utils'; import { isRegExp } from 'playwright-core/lib/utils/utils';
import { tsConfigLoader, TsConfigLoaderResult } from './third_party/tsconfig-loader'; import { tsConfigLoader, TsConfigLoaderResult } from './third_party/tsconfig-loader';
// To allow multiple loaders in the same process without clearing require cache,
// we make these maps global.
const cachedFileSuites = new Map<string, Suite>();
const cachedTSConfigs = new Map<string, TsConfigLoaderResult>();
export class Loader { export class Loader {
private _defaultConfig: Config; private _defaultConfig: Config;
private _configOverrides: Config; private _configOverrides: Config;
@ -36,9 +41,7 @@ export class Loader {
private _config: Config = {}; private _config: Config = {};
private _configFile: string | undefined; private _configFile: string | undefined;
private _projects: ProjectImpl[] = []; private _projects: ProjectImpl[] = [];
private _fileSuites = new Map<string, Suite>();
private _lastModuleInfo: { rootFolder: string, isModule: boolean } | null = null; private _lastModuleInfo: { rootFolder: string, isModule: boolean } | null = null;
private _tsConfigCache = new Map<string, TsConfigLoaderResult>();
constructor(defaultConfig: Config, configOverrides: Config) { constructor(defaultConfig: Config, configOverrides: Config) {
this._defaultConfig = defaultConfig; this._defaultConfig = defaultConfig;
@ -113,15 +116,15 @@ export class Loader {
} }
async loadTestFile(file: string) { async loadTestFile(file: string) {
if (this._fileSuites.has(file)) if (cachedFileSuites.has(file))
return this._fileSuites.get(file)!; return cachedFileSuites.get(file)!;
try { try {
const suite = new Suite(path.relative(this._fullConfig.rootDir, file) || path.basename(file)); const suite = new Suite(path.relative(this._fullConfig.rootDir, file) || path.basename(file));
suite._requireFile = file; suite._requireFile = file;
suite.location = { file, line: 0, column: 0 }; suite.location = { file, line: 0, column: 0 };
setCurrentlyLoadingFileSuite(suite); setCurrentlyLoadingFileSuite(suite);
await this._requireOrImport(file); await this._requireOrImport(file);
this._fileSuites.set(file, suite); cachedFileSuites.set(file, suite);
return suite; return suite;
} finally { } finally {
setCurrentlyLoadingFileSuite(undefined); setCurrentlyLoadingFileSuite(undefined);
@ -154,10 +157,6 @@ export class Loader {
return this._projects; return this._projects;
} }
fileSuites() {
return this._fileSuites;
}
serialize(): SerializedLoaderData { serialize(): SerializedLoaderData {
return { return {
defaultConfig: this._defaultConfig, defaultConfig: this._defaultConfig,
@ -197,13 +196,13 @@ export class Loader {
private async _requireOrImport(file: string) { private async _requireOrImport(file: string) {
// Respect tsconfig paths. // Respect tsconfig paths.
const cwd = path.dirname(file); const cwd = path.dirname(file);
let tsconfig = this._tsConfigCache.get(cwd); let tsconfig = cachedTSConfigs.get(cwd);
if (!tsconfig) { if (!tsconfig) {
tsconfig = tsConfigLoader({ tsconfig = tsConfigLoader({
getEnv: (name: string) => process.env[name], getEnv: (name: string) => process.env[name],
cwd cwd
}); });
this._tsConfigCache.set(cwd, tsconfig); cachedTSConfigs.set(cwd, tsconfig);
} }
const revertBabelRequire = installTransform(tsconfig); const revertBabelRequire = installTransform(tsconfig);

View file

@ -227,12 +227,9 @@ export class Runner {
if (config.globalSetup && !list) if (config.globalSetup && !list)
globalSetupResult = await (await this._loader.loadGlobalHook(config.globalSetup, 'globalSetup'))(this._loader.fullConfig()); globalSetupResult = await (await this._loader.loadGlobalHook(config.globalSetup, 'globalSetup'))(this._loader.fullConfig());
try { try {
for (const file of allTestFiles)
await this._loader.loadTestFile(file);
const preprocessRoot = new Suite(''); const preprocessRoot = new Suite('');
for (const fileSuite of this._loader.fileSuites().values()) for (const file of allTestFiles)
preprocessRoot._addSuite(fileSuite); preprocessRoot._addSuite(await this._loader.loadTestFile(file));
if (config.forbidOnly) { if (config.forbidOnly) {
const onlyTestsAndSuites = preprocessRoot._getOnlyItems(); const onlyTestsAndSuites = preprocessRoot._getOnlyItems();
if (onlyTestsAndSuites.length > 0) { if (onlyTestsAndSuites.length > 0) {