chore: implement clear-cache through plugins (#32471)
Also switches it to task runner.
This commit is contained in:
parent
d4c77ce260
commit
1ba3db6864
|
@ -16,7 +16,6 @@
|
|||
|
||||
const { test: baseTest, expect, devices, defineConfig: originalDefineConfig } = require('playwright/test');
|
||||
const { fixtures } = require('./lib/mount');
|
||||
const { clearCacheCommand } = require('./lib/cliOverrides');
|
||||
const { createPlugin } = require('./lib/vitePlugin');
|
||||
|
||||
const defineConfig = (...configs) => {
|
||||
|
@ -29,9 +28,6 @@ const defineConfig = (...configs) => {
|
|||
babelPlugins: [
|
||||
[require.resolve('./lib/tsxTransform')]
|
||||
],
|
||||
cli: {
|
||||
'clear-cache': clearCacheCommand,
|
||||
},
|
||||
}
|
||||
};
|
||||
};
|
||||
|
|
|
@ -1,28 +0,0 @@
|
|||
|
||||
/**
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* 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 { cacheDir } from 'playwright/lib/transform/compilationCache';
|
||||
import { resolveDirs } from './viteUtils';
|
||||
import type { FullConfigInternal } from 'playwright/lib/common/config';
|
||||
import { removeFolderAndLogToConsole } from 'playwright/lib/runner/testServer';
|
||||
|
||||
export async function clearCacheCommand(config: FullConfigInternal) {
|
||||
const dirs = await resolveDirs(config.configDir, config.config);
|
||||
if (dirs)
|
||||
await removeFolderAndLogToConsole(dirs.outDir);
|
||||
await removeFolderAndLogToConsole(cacheDir);
|
||||
}
|
|
@ -32,6 +32,7 @@ import type { ComponentRegistry } from './viteUtils';
|
|||
import { createConfig, frameworkConfig, hasJSComponents, populateComponentsFromTests, resolveDirs, resolveEndpoint, transformIndexFile } from './viteUtils';
|
||||
import { resolveHook } from 'playwright/lib/transform/transform';
|
||||
import { runDevServer } from './devServer';
|
||||
import { removeDirAndLogToConsole } from 'playwright/lib/util';
|
||||
|
||||
const log = debug('pw:vite');
|
||||
|
||||
|
@ -78,6 +79,13 @@ export function createPlugin(): TestRunnerPlugin {
|
|||
startDevServer: async () => {
|
||||
return await runDevServer(config);
|
||||
},
|
||||
|
||||
clearCache: async () => {
|
||||
const configDir = config.configFile ? path.dirname(config.configFile) : config.rootDir;
|
||||
const dirs = await resolveDirs(configDir, config);
|
||||
if (dirs)
|
||||
await removeDirAndLogToConsole(dirs.outDir);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -24,8 +24,6 @@
|
|||
"./lib/program": "./lib/program.js",
|
||||
"./lib/transform/babelBundle": "./lib/transform/babelBundle.js",
|
||||
"./lib/transform/compilationCache": "./lib/transform/compilationCache.js",
|
||||
"./lib/runner/runner": "./lib/runner/runner.js",
|
||||
"./lib/runner/testServer": "./lib/runner/testServer.js",
|
||||
"./lib/transform/esmLoader": "./lib/transform/esmLoader.js",
|
||||
"./lib/transform/transform": "./lib/transform/transform.js",
|
||||
"./lib/internalsForTest": "./lib/internalsForTest.js",
|
||||
|
|
|
@ -22,6 +22,7 @@ export interface TestRunnerPlugin {
|
|||
setup?(config: FullConfig, configDir: string, reporter: ReporterV2): Promise<void>;
|
||||
populateDependencies?(): Promise<void>;
|
||||
startDevServer?(): Promise<() => Promise<void>>;
|
||||
clearCache?(): Promise<void>;
|
||||
begin?(suite: Suite): Promise<void>;
|
||||
end?(): Promise<void>;
|
||||
teardown?(): Promise<void>;
|
||||
|
|
|
@ -34,7 +34,6 @@ export { program } from 'playwright-core/lib/cli/program';
|
|||
import type { ReporterDescription } from '../types/test';
|
||||
import { prepareErrorStack } from './reporters/base';
|
||||
import * as testServer from './runner/testServer';
|
||||
import { clearCacheAndLogToConsole } from './runner/testServer';
|
||||
import { runWatchModeLoop } from './runner/watchMode';
|
||||
|
||||
function addTestCommand(program: Command) {
|
||||
|
@ -74,10 +73,13 @@ function addClearCacheCommand(program: Command) {
|
|||
command.description('clears build and test caches');
|
||||
command.option('-c, --config <file>', `Configuration file, or a test directory with optional "playwright.config.{m,c}?{js,ts}"`);
|
||||
command.action(async opts => {
|
||||
const configInternal = await loadConfigFromFileRestartIfNeeded(opts.config);
|
||||
if (!configInternal)
|
||||
const config = await loadConfigFromFileRestartIfNeeded(opts.config);
|
||||
if (!config)
|
||||
return;
|
||||
await clearCacheAndLogToConsole(configInternal);
|
||||
const runner = new Runner(config);
|
||||
const { status } = await runner.clearCache();
|
||||
const exitCode = status === 'interrupted' ? 130 : (status === 'passed' ? 0 : 1);
|
||||
gracefullyProcessExitDoNotHang(exitCode);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ import type { FullResult, TestError } from '../../types/testReporter';
|
|||
import { webServerPluginsForConfig } from '../plugins/webServerPlugin';
|
||||
import { collectFilesForProject, filterProjects } from './projectUtils';
|
||||
import { createErrorCollectingReporter, createReporters } from './reporters';
|
||||
import { TestRun, createTaskRunner, createTaskRunnerForDevServer, createTaskRunnerForList, createTaskRunnerForRelatedTestFiles } from './tasks';
|
||||
import { TestRun, createTaskRunner, createTaskRunnerForClearCache, createTaskRunnerForDevServer, createTaskRunnerForList, createTaskRunnerForRelatedTestFiles } from './tasks';
|
||||
import type { FullConfigInternal } from '../common/config';
|
||||
import { affectedTestFiles } from '../transform/compilationCache';
|
||||
import { InternalReporter } from '../reporters/internalReporter';
|
||||
|
@ -131,6 +131,17 @@ export class Runner {
|
|||
await reporter.onExit();
|
||||
return { status };
|
||||
}
|
||||
|
||||
async clearCache() {
|
||||
const reporter = new InternalReporter([createErrorCollectingReporter(true)]);
|
||||
const taskRunner = createTaskRunnerForClearCache(this._config, reporter, 'in-process', true);
|
||||
const testRun = new TestRun(this._config);
|
||||
reporter.onConfigure(this._config.config);
|
||||
const status = await taskRunner.run(testRun, 0);
|
||||
await reporter.onEnd({ status });
|
||||
await reporter.onExit();
|
||||
return { status };
|
||||
}
|
||||
}
|
||||
|
||||
export type LastRunInfo = {
|
||||
|
|
|
@ -26,12 +26,13 @@ import type { Task } from './taskRunner';
|
|||
import { TaskRunner } from './taskRunner';
|
||||
import type { FullConfigInternal, FullProjectInternal } from '../common/config';
|
||||
import { collectProjectsAndTestFiles, createRootSuite, loadFileSuites, loadGlobalHook } from './loadUtils';
|
||||
import type { Matcher } from '../util';
|
||||
import { removeDirAndLogToConsole, type Matcher } from '../util';
|
||||
import { Suite } from '../common/test';
|
||||
import { buildDependentProjects, buildTeardownToSetupsMap, filterProjects } from './projectUtils';
|
||||
import { FailureTracker } from './failureTracker';
|
||||
import { detectChangedTestFiles } from './vcs';
|
||||
import type { InternalReporter } from '../reporters/internalReporter';
|
||||
import { cacheDir } from '../transform/compilationCache';
|
||||
|
||||
const readDirAsync = promisify(fs.readdir);
|
||||
|
||||
|
@ -139,6 +140,22 @@ export function createTaskRunnerForRelatedTestFiles(config: FullConfigInternal,
|
|||
return taskRunner;
|
||||
}
|
||||
|
||||
export function createTaskRunnerForClearCache(config: FullConfigInternal, reporter: InternalReporter, mode: 'in-process' | 'out-of-process', setupPlugins: boolean): TaskRunner<TestRun> {
|
||||
const taskRunner = TaskRunner.create<TestRun>(reporter, config.config.globalTimeout);
|
||||
if (setupPlugins) {
|
||||
for (const plugin of config.plugins)
|
||||
taskRunner.addTask('plugin setup', createPluginSetupTask(plugin));
|
||||
}
|
||||
taskRunner.addTask('clear cache', {
|
||||
setup: async () => {
|
||||
await removeDirAndLogToConsole(cacheDir);
|
||||
for (const plugin of config.plugins)
|
||||
await plugin.instance?.clearCache?.();
|
||||
},
|
||||
});
|
||||
return taskRunner;
|
||||
}
|
||||
|
||||
function createReportBeginTask(): Task<TestRun> {
|
||||
return {
|
||||
setup: async (reporter, { rootSuite }) => {
|
||||
|
|
|
@ -23,7 +23,7 @@ import type * as reporterTypes from '../../types/testReporter';
|
|||
import { affectedTestFiles, collectAffectedTestFiles, dependenciesForTestFile } from '../transform/compilationCache';
|
||||
import type { ConfigLocation, FullConfigInternal } from '../common/config';
|
||||
import { createErrorCollectingReporter, createReporterForTestServer, createReporters } from './reporters';
|
||||
import { TestRun, createTaskRunnerForList, createTaskRunnerForTestServer, createTaskRunnerForWatchSetup, createTaskRunnerForListFiles, createTaskRunnerForDevServer, createTaskRunnerForRelatedTestFiles } from './tasks';
|
||||
import { TestRun, createTaskRunnerForList, createTaskRunnerForTestServer, createTaskRunnerForWatchSetup, createTaskRunnerForListFiles, createTaskRunnerForDevServer, createTaskRunnerForRelatedTestFiles, createTaskRunnerForClearCache } from './tasks';
|
||||
import { open } from 'playwright-core/lib/utilsBundle';
|
||||
import ListReporter from '../reporters/list';
|
||||
import { SigIntWatcher } from './sigIntWatcher';
|
||||
|
@ -35,7 +35,6 @@ import { webServerPluginsForConfig } from '../plugins/webServerPlugin';
|
|||
import type { TraceViewerRedirectOptions, TraceViewerServerOptions } from 'playwright-core/lib/server/trace/viewer/traceViewer';
|
||||
import type { TestRunnerPluginRegistration } from '../plugins';
|
||||
import { serializeError } from '../util';
|
||||
import { cacheDir } from '../transform/compilationCache';
|
||||
import { baseFullConfig } from '../isomorphic/teleReceiver';
|
||||
import { InternalReporter } from '../reporters/internalReporter';
|
||||
import type { ReporterV2 } from '../reporters/reporterV2';
|
||||
|
@ -202,9 +201,17 @@ export class TestServerDispatcher implements TestServerInterface {
|
|||
}
|
||||
|
||||
async clearCache(params: Parameters<TestServerInterface['clearCache']>[0]): ReturnType<TestServerInterface['clearCache']> {
|
||||
const { config } = await this._loadConfig();
|
||||
if (config)
|
||||
await clearCacheAndLogToConsole(config);
|
||||
const reporter = new InternalReporter([]);
|
||||
const config = await this._loadConfigOrReportError(reporter);
|
||||
if (!config)
|
||||
return;
|
||||
|
||||
const taskRunner = createTaskRunnerForClearCache(config, reporter, 'out-of-process', false);
|
||||
const testRun = new TestRun(config);
|
||||
reporter.onConfigure(config.config);
|
||||
const status = await taskRunner.run(testRun, 0);
|
||||
await reporter.onEnd({ status });
|
||||
await reporter.onExit();
|
||||
}
|
||||
|
||||
async listFiles(params: Parameters<TestServerInterface['listFiles']>[0]): ReturnType<TestServerInterface['listFiles']> {
|
||||
|
@ -525,23 +532,3 @@ export async function resolveCtDirs(config: FullConfigInternal) {
|
|||
templateDir
|
||||
};
|
||||
}
|
||||
|
||||
export async function clearCacheAndLogToConsole(config: FullConfigInternal) {
|
||||
const override = (config.config as any)['@playwright/test']?.['cli']?.['clear-cache'];
|
||||
if (override) {
|
||||
await override(config);
|
||||
return;
|
||||
}
|
||||
await removeFolderAndLogToConsole(cacheDir);
|
||||
}
|
||||
|
||||
export async function removeFolderAndLogToConsole(folder: string) {
|
||||
try {
|
||||
if (!fs.existsSync(folder))
|
||||
return;
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(`Removing ${await fs.promises.realpath(folder)}`);
|
||||
await fs.promises.rm(folder, { recursive: true, force: true });
|
||||
} catch {
|
||||
}
|
||||
}
|
||||
|
|
|
@ -348,3 +348,14 @@ function fileExists(resolved: string) {
|
|||
function dirExists(resolved: string) {
|
||||
return fs.statSync(resolved, { throwIfNoEntry: false })?.isDirectory();
|
||||
}
|
||||
|
||||
export async function removeDirAndLogToConsole(dir: string) {
|
||||
try {
|
||||
if (!fs.existsSync(dir))
|
||||
return;
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(`Removing ${await fs.promises.realpath(dir)}`);
|
||||
await fs.promises.rm(dir, { recursive: true, force: true });
|
||||
} catch {
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,9 +15,6 @@
|
|||
*/
|
||||
|
||||
import { test, expect } from './playwright-test-fixtures';
|
||||
import path from 'path';
|
||||
|
||||
export const ctReactCliEntrypoint = path.join(__dirname, '../../packages/playwright-ct-react/cli.js');
|
||||
|
||||
test('should clear cache with type:module', async ({ runCLICommand }) => {
|
||||
const result = await runCLICommand({
|
||||
|
@ -46,6 +43,6 @@ test('should clear cache for ct', async ({ runCLICommand }) => {
|
|||
import { test } from '@playwright/test';
|
||||
test('example', () => {});
|
||||
`,
|
||||
}, 'clear-cache', [], ctReactCliEntrypoint);
|
||||
}, 'clear-cache', []);
|
||||
expect(result.exitCode).toBe(0);
|
||||
});
|
||||
|
|
|
@ -203,9 +203,9 @@ async function runPlaywrightTest(childProcess: CommonFixtures['childProcess'], b
|
|||
};
|
||||
}
|
||||
|
||||
async function runPlaywrightCLI(childProcess: CommonFixtures['childProcess'], args: string[], baseDir: string, env: NodeJS.ProcessEnv, entryPoint?: string): Promise<{ output: string, stdout: string, stderr: string, exitCode: number }> {
|
||||
async function runPlaywrightCLI(childProcess: CommonFixtures['childProcess'], args: string[], baseDir: string, env: NodeJS.ProcessEnv): Promise<{ output: string, stdout: string, stderr: string, exitCode: number }> {
|
||||
const testProcess = childProcess({
|
||||
command: ['node', entryPoint || cliEntrypoint, ...args],
|
||||
command: ['node', cliEntrypoint, ...args],
|
||||
env: cleanEnv(env),
|
||||
cwd: baseDir,
|
||||
});
|
||||
|
@ -249,7 +249,7 @@ type Fixtures = {
|
|||
writeFiles: (files: Files) => Promise<string>;
|
||||
deleteFile: (file: string) => Promise<void>;
|
||||
runInlineTest: (files: Files, params?: Params, env?: NodeJS.ProcessEnv, options?: RunOptions) => Promise<RunResult>;
|
||||
runCLICommand: (files: Files, command: string, args?: string[], entryPoint?: string) => Promise<{ stdout: string, stderr: string, exitCode: number }>;
|
||||
runCLICommand: (files: Files, command: string, args?: string[]) => Promise<{ stdout: string, stderr: string, exitCode: number }>;
|
||||
startCLICommand: (files: Files, command: string, args?: string[], options?: RunOptions) => Promise<TestChildProcess>;
|
||||
runWatchTest: (files: Files, params?: Params, env?: NodeJS.ProcessEnv, options?: RunOptions) => Promise<TestChildProcess>;
|
||||
interactWithTestRunner: (files: Files, params?: Params, env?: NodeJS.ProcessEnv, options?: RunOptions) => Promise<TestChildProcess>;
|
||||
|
@ -285,9 +285,9 @@ export const test = base
|
|||
|
||||
runCLICommand: async ({ childProcess }, use, testInfo: TestInfo) => {
|
||||
const cacheDir = await fs.promises.mkdtemp(path.join(os.tmpdir(), 'playwright-test-cache-'));
|
||||
await use(async (files: Files, command: string, args?: string[], entryPoint?: string) => {
|
||||
await use(async (files: Files, command: string, args?: string[]) => {
|
||||
const baseDir = await writeFiles(testInfo, files, true);
|
||||
return await runPlaywrightCLI(childProcess, [command, ...(args || [])], baseDir, { PWTEST_CACHE_DIR: cacheDir }, entryPoint);
|
||||
return await runPlaywrightCLI(childProcess, [command, ...(args || [])], baseDir, { PWTEST_CACHE_DIR: cacheDir });
|
||||
});
|
||||
await removeFolders([cacheDir]);
|
||||
},
|
||||
|
|
|
@ -193,3 +193,12 @@ test('find related test files', async ({ startTestServer, writeFiles }) => {
|
|||
|
||||
expect((await testServerConnection.runGlobalTeardown({})).status).toBe('passed');
|
||||
});
|
||||
|
||||
test('clear cache', async ({ startTestServer, writeFiles }) => {
|
||||
await writeFiles(ctFiles);
|
||||
const testServerConnection = await startTestServer();
|
||||
await testServerConnection.initialize({ interceptStdio: true });
|
||||
expect((await testServerConnection.runGlobalSetup({})).status).toBe('passed');
|
||||
await testServerConnection.clearCache({});
|
||||
expect((await testServerConnection.runGlobalTeardown({})).status).toBe('passed');
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue