diff --git a/src/emulation/watchers.ts b/src/emulation/watchers.ts index 861a4987..9577081a 100644 --- a/src/emulation/watchers.ts +++ b/src/emulation/watchers.ts @@ -4,7 +4,7 @@ import type * as fs from 'node:fs'; import { ErrnoError } from '../error.js'; import { isStatsEqual, type Stats } from '../stats.js'; import { normalizePath } from '../utils.js'; -import { dirname, basename } from './path.js'; +import { basename, dirname } from './path.js'; import { statSync } from './sync.js'; /** @@ -171,23 +171,24 @@ export function removeWatcher(path: string, watcher: FSWatcher) { } export function emitChange(eventType: fs.WatchEventType, filename: string) { - let normalizedFilename: string = normalizePath(filename); + filename = normalizePath(filename); // Notify watchers on the specific file - if (watchers.has(normalizedFilename)) { - for (const watcher of watchers.get(normalizedFilename)!) { + if (watchers.has(filename)) { + for (const watcher of watchers.get(filename)!) { watcher.emit('change', eventType, basename(filename)); } } // Notify watchers on parent directories if they are watching recursively - let parent = dirname(normalizedFilename); - while (parent !== normalizedFilename && parent !== '/') { + let parent = filename, + normalizedFilename; + while (parent !== normalizedFilename) { + normalizedFilename = parent; + parent = dirname(parent); if (watchers.has(parent)) { for (const watcher of watchers.get(parent)!) { - watcher.emit('change', eventType, basename(filename)); + watcher.emit('change', eventType, filename.slice(parent.length + (parent == '/' ? 0 : 1))); } } - normalizedFilename = parent; - parent = dirname(parent); } } diff --git a/tests/fs/watch.test.ts b/tests/fs/watch.test.ts index b335d880..43dc6d83 100644 --- a/tests/fs/watch.test.ts +++ b/tests/fs/watch.test.ts @@ -115,6 +115,27 @@ suite('Watch Features', () => { resolve(); })(); + await fs.promises.unlink(tempFile); + await promise; + }); + test('fs.promises.watch should detect file creations recursively', async () => { + const rootDir = '/'; + const subDir = `${testDir}sub-dir`; + const tempFile = `${subDir}/tempFile.txt`; + await fs.promises.mkdir(subDir); + const watcher = fs.promises.watch(rootDir); + + await fs.promises.writeFile(tempFile, 'Temporary content'); + const { promise, resolve } = Promise.withResolvers(); + (async () => { + for await (const event of watcher) { + assert.equal(event.eventType, 'rename'); + assert.equal(event.filename, tempFile.substring(rootDir.length)); + break; + } + resolve(); + })(); + await fs.promises.unlink(tempFile); await promise; });