diff --git a/test/helpers/watcher-flow.ts b/test/helpers/watcher-flow.ts index 787c0704d..bf17aa8d0 100644 --- a/test/helpers/watcher-flow.ts +++ b/test/helpers/watcher-flow.ts @@ -1,6 +1,7 @@ /** - * The handshake a test of the native watcher makes before it writes what it - * means to hear: changesFlow, and the probe files it writes (isProbe). + * The handshake a watcher test makes, on either of chokidar's backends, before + * it writes what it means to hear: changesFlow, and the probe files it writes + * (isProbe). */ import assert from 'node:assert/strict'; import { writeFileSync } from 'node:fs'; @@ -29,10 +30,12 @@ export const isProbe = (path: string): boolean => basename(path).startsWith(PROB * one is added. So a file written in between isn't reported until a later * change in its directory, when chokidar reads the directory again, and a probe * reported in one directory can come from a stream made before another - * directory's watch. Each attempt writes a new probe in each directory still - * unreported and waits up to a second, since the next probe is that later - * change. The probes stay in the batches, and a test's results leave them out - * (isProbe). + * directory's watch. chokidar's polling backend starts a directory's poll just + * before `onReady` too, and the poll's first stat is what each later one is + * compared with, so a file written before that stat is never reported. Each + * attempt writes a new probe in each directory still unreported and waits up + * to a second, since the next probe is that later change. The probes stay in + * the batches, and a test's results leave them out (isProbe). */ export async function changesFlow(root: string, batches: FsChange[][], dirs: readonly string[]): Promise { const where = dirs.length ? dirs : ['']; diff --git a/test/workspace-watcher.test.ts b/test/workspace-watcher.test.ts index 38fb5a383..1b5e087e9 100644 --- a/test/workspace-watcher.test.ts +++ b/test/workspace-watcher.test.ts @@ -131,8 +131,9 @@ async function waitFor(predicate: () => boolean, message: string, timeoutMs = EV } /** - * A polling watcher, once chokidar's first scan is done. A change made before - * then can be part of the files chokidar starts from (ignoreInitial), and is + * A polling watcher, once chokidar's first scan is done and its poll reports + * changes (changesFlow). A change made before then can be part of the files + * chokidar starts from (ignoreInitial), or of the poll's first stat, and is * then never reported. If the watcher has reported an error and isn't ready * when the wait checks, the wait fails with that error, and a watcher that * doesn't get ready is stopped. @@ -144,6 +145,7 @@ async function readyWithPolling(): Promise<{ watcher: MountWatcher; batches: FsC try { await waitFor(() => ready || failed !== undefined, 'expected the watcher to be ready'); if (!ready) throw failed; + await changesFlow(tmp, collected.batches, []); } catch (error) { await collected.watcher.stop(); throw error; @@ -330,8 +332,10 @@ describe('MountWatcher lifecycle', () => { try { assert.ok(existsSync(nested), 'start() should have created the watched path'); // A file written before chokidar's first scan is done can be part of - // what it starts from (ignoreInitial), and then is never reported. + // what it starts from (ignoreInitial), or of the poll's first stat, just + // after onReady, and then is never reported. await waitFor(() => ready, 'onReady should have fired'); + await changesFlow(nested, batches, []); writeFileSync(join(nested, 'ticket.md'), 'hi'); await changeFor(batches, 'ticket.md'); } finally { @@ -455,6 +459,7 @@ describe('MountWatcher lifecycle', () => { try { await waitFor(() => ready, 'expected initial watcher ready'); + await changesFlow(tmp, batches, []); const file = join(tmp, 'normal.md'); writeFileSync(file, 'v1'); @@ -738,6 +743,7 @@ describe('MountWatcher lifecycle', () => { await (watcher as unknown as { reattach(): Promise }).reattach(); assert.ok(errors.some((e) => e.message === 'close failed'), "the re-attach reported its close's failure"); await waitFor(() => readyCount === 2, 'expected the watcher to attach again'); + await changesFlow(tmp, batches, []); writeFileSync(join(tmp, 'after.md'), 'x'); await changeFor(batches, 'after.md', 'created'); } finally {