From 52b0811c55ac174c25190cb46d7e341c8b465d12 Mon Sep 17 00:00:00 2001 From: Simon Knott Date: Fri, 26 Jul 2024 16:52:12 +0200 Subject: [PATCH] remove the watch mode concept, combine both watchers --- packages/playwright-ct-core/src/devServer.ts | 2 +- packages/playwright/src/fsWatcher.ts | 20 +++----- packages/playwright/src/runner/testServer.ts | 49 +++++++++++--------- 3 files changed, 35 insertions(+), 36 deletions(-) diff --git a/packages/playwright-ct-core/src/devServer.ts b/packages/playwright-ct-core/src/devServer.ts index 2e1e7c76bf..0a825eeaf1 100644 --- a/packages/playwright-ct-core/src/devServer.ts +++ b/packages/playwright-ct-core/src/devServer.ts @@ -61,7 +61,7 @@ export async function runDevServer(config: FullConfigInternal): Promise<() => Pr projectOutputs.add(p.project.outputDir); } - const globalWatcher = new Watcher('deep', async () => { + const globalWatcher = new Watcher(async () => { const registry: ComponentRegistry = new Map(); await populateComponentsFromTests(registry); // compare componentRegistry to registry key sets. diff --git a/packages/playwright/src/fsWatcher.ts b/packages/playwright/src/fsWatcher.ts index a1c09c343d..fd7e616b56 100644 --- a/packages/playwright/src/fsWatcher.ts +++ b/packages/playwright/src/fsWatcher.ts @@ -21,26 +21,24 @@ export type FSEvent = { event: 'add' | 'addDir' | 'change' | 'unlink' | 'unlinkD export class Watcher { private _onChange: (events: FSEvent[]) => void; - private _watchedFiles: string[] = []; + private _watchedPaths: string[] = []; private _ignoredFolders: string[] = []; private _collector: FSEvent[] = []; private _fsWatcher: FSWatcher | undefined; private _throttleTimer: NodeJS.Timeout | undefined; - private _mode: 'flat' | 'deep'; - constructor(mode: 'flat' | 'deep', onChange: (events: FSEvent[]) => void) { - this._mode = mode; + constructor(onChange: (events: FSEvent[]) => void) { this._onChange = onChange; } - update(watchedFiles: string[], ignoredFolders: string[], reportPending: boolean) { - if (JSON.stringify([this._watchedFiles, this._ignoredFolders]) === JSON.stringify(watchedFiles, ignoredFolders)) + update(watchedPaths: string[], ignoredFolders: string[], reportPending: boolean) { + if (JSON.stringify([this._watchedPaths, this._ignoredFolders]) === JSON.stringify(watchedPaths, ignoredFolders)) return; if (reportPending) this._reportEventsIfAny(); - this._watchedFiles = watchedFiles; + this._watchedPaths = watchedPaths; this._ignoredFolders = ignoredFolders; void this._fsWatcher?.close(); this._fsWatcher = undefined; @@ -48,17 +46,13 @@ export class Watcher { clearTimeout(this._throttleTimer); this._throttleTimer = undefined; - if (!this._watchedFiles.length) + if (!this._watchedPaths.length) return; const ignored = [...this._ignoredFolders, '**/node_modules/**']; - this._fsWatcher = chokidar.watch(watchedFiles, { ignoreInitial: true, ignored }).on('all', async (event, file) => { + this._fsWatcher = chokidar.watch(watchedPaths, { ignoreInitial: true, ignored }).on('all', async (event, file) => { if (this._throttleTimer) clearTimeout(this._throttleTimer); - if (this._mode === 'flat' && event !== 'add' && event !== 'change') - return; - if (this._mode === 'deep' && event !== 'add' && event !== 'change' && event !== 'unlink' && event !== 'addDir' && event !== 'unlinkDir') - return; this._collector.push({ event, file }); this._throttleTimer = setTimeout(() => this._reportEventsIfAny(), 250); }); diff --git a/packages/playwright/src/runner/testServer.ts b/packages/playwright/src/runner/testServer.ts index a6cd770af7..e381db886d 100644 --- a/packages/playwright/src/runner/testServer.ts +++ b/packages/playwright/src/runner/testServer.ts @@ -27,7 +27,7 @@ import { TestRun, createTaskRunnerForList, createTaskRunnerForTestServer, create import { open } from 'playwright-core/lib/utilsBundle'; import ListReporter from '../reporters/list'; import { SigIntWatcher } from './sigIntWatcher'; -import { type FSEvent, Watcher } from '../fsWatcher'; +import { Watcher } from '../fsWatcher'; import type { ReportEntry, TestServerInterface, TestServerInterfaceEventEmitters } from '../isomorphic/testServerInterface'; import { Runner } from './runner'; import type { ConfigCLIOverrides } from '../common/ipc'; @@ -64,8 +64,12 @@ class TestServer { class TestServerDispatcher implements TestServerInterface { private _configLocation: ConfigLocation; - private _globalWatcher: Watcher; - private _testWatcher: Watcher; + + private _watcher: Watcher; + private _watchedProjectDirs = new Set(); + private _ignoredProjectOutputs = new Set(); + private _watchedTestDependencies = new Set(); + private _testRun: { run: Promise, stop: ManualPromise } | undefined; readonly transport: Transport; private _queue = Promise.resolve(); @@ -86,17 +90,14 @@ class TestServerDispatcher implements TestServerInterface { gracefullyProcessExitDoNotHang(0); }, }; - this._globalWatcher = new Watcher('deep', events => this._checkForChangedTestFiles(events)); - this._testWatcher = new Watcher('flat', events => this._checkForChangedTestFiles(events)); + this._watcher = new Watcher(events => { + const collector = new Set(); + events.forEach(f => collectAffectedTestFiles(f.file, collector)); + this._dispatchEvent('testFilesChanged', { testFiles: [...collector] }); + }); this._dispatchEvent = (method, params) => this.transport.sendEvent?.(method, params); } - private _checkForChangedTestFiles(events: FSEvent[]) { - const collector = new Set(); - events.forEach(f => collectAffectedTestFiles(f.file, collector)); - this._dispatchEvent('testFilesChanged', { testFiles: [...collector] }); - } - private async _wireReporter(messageSink: (message: any) => void) { return await createReporterForTestServer(this._serializer, messageSink); } @@ -281,24 +282,28 @@ class TestServerDispatcher implements TestServerInterface { await taskRunner.reporter.onEnd({ status }); await taskRunner.reporter.onExit(); - const projectDirs = new Set(); - const projectOutputs = new Set(); + this._watchedProjectDirs = new Set(); + this._ignoredProjectOutputs = new Set(); for (const p of config.projects) { - projectDirs.add(p.project.testDir); - projectOutputs.add(p.project.outputDir); + this._watchedProjectDirs.add(p.project.testDir); + this._ignoredProjectOutputs.add(p.project.outputDir); } const result = await resolveCtDirs(config); if (result) { - projectDirs.add(result.templateDir); - projectOutputs.add(result.outDir); + this._watchedProjectDirs.add(result.templateDir); + this._ignoredProjectOutputs.add(result.outDir); } if (this._watchTestDirs) - this._globalWatcher.update([...projectDirs], [...projectOutputs], false); + this.updateWatcher(false); return { report, status }; } + private updateWatcher(reportPending: boolean) { + this._watcher.update([...this._watchedProjectDirs, ...this._watchedTestDependencies], [...this._ignoredProjectOutputs], reportPending); + } + async runTests(params: Parameters[0]): ReturnType { let result: Awaited> = { status: 'passed' }; this._queue = this._queue.then(async () => { @@ -366,12 +371,12 @@ class TestServerDispatcher implements TestServerInterface { } async watch(params: { fileNames: string[]; }) { - const files = new Set(); + this._watchedTestDependencies = new Set(); for (const fileName of params.fileNames) { - files.add(fileName); - dependenciesForTestFile(fileName).forEach(file => files.add(file)); + this._watchedTestDependencies.add(fileName); + dependenciesForTestFile(fileName).forEach(file => this._watchedTestDependencies.add(file)); } - this._testWatcher.update([...files], [], true); + this.updateWatcher(true); } async findRelatedTestFiles(params: Parameters[0]): ReturnType {