Skip to content

Commit

Permalink
doc, test: update --watch for linux recursive watch
Browse files Browse the repository at this point in the history
  • Loading branch information
avivkeller committed Oct 3, 2024
1 parent 1d5ed72 commit 5e31a82
Show file tree
Hide file tree
Showing 5 changed files with 77 additions and 115 deletions.
4 changes: 0 additions & 4 deletions doc/api/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -2854,10 +2854,6 @@ This flag cannot be combined with
node --watch-path=./src --watch-path=./tests index.js
```

This option is only supported on macOS and Windows.
An `ERR_FEATURE_UNAVAILABLE_ON_PLATFORM` exception will be thrown
when the option is used on a platform that does not support it.

### `--watch-preserve-output`

<!-- YAML
Expand Down
23 changes: 12 additions & 11 deletions doc/api/errors.md
Original file line number Diff line number Diff line change
Expand Up @@ -1252,17 +1252,6 @@ for the JS engine are not set up properly.
A `Promise` that was callbackified via `util.callbackify()` was rejected with a
falsy value.

<a id="ERR_FEATURE_UNAVAILABLE_ON_PLATFORM"></a>

### `ERR_FEATURE_UNAVAILABLE_ON_PLATFORM`

<!-- YAML
added: v14.0.0
-->

Used when a feature that is not available
to the current platform which is running Node.js is used.

<a id="ERR_FS_CP_DIR_TO_NON_DIR"></a>

### `ERR_FS_CP_DIR_TO_NON_DIR`
Expand Down Expand Up @@ -3299,6 +3288,18 @@ An incompatible combination of options was passed to [`crypto.scrypt()`][] or
[`crypto.scryptSync()`][]. New versions of Node.js use the error code
[`ERR_INCOMPATIBLE_OPTION_PAIR`][] instead, which is consistent with other APIs.

<a id="ERR_FEATURE_UNAVAILABLE_ON_PLATFORM"></a>

### `ERR_FEATURE_UNAVAILABLE_ON_PLATFORM`

<!-- YAML
added: v14.0.0
removed: v19.1.0
-->

Used when a feature that is not available
to the current platform which is running Node.js is used.

<a id="ERR_FS_INVALID_SYMLINK_TYPE"></a>

### `ERR_FS_INVALID_SYMLINK_TYPE`
Expand Down
4 changes: 0 additions & 4 deletions lib/internal/errors.js
Original file line number Diff line number Diff line change
Expand Up @@ -1202,10 +1202,6 @@ E('ERR_FALSY_VALUE_REJECTION', function(reason) {
this.reason = reason;
return 'Promise was rejected with falsy value';
}, Error, HideStackFramesError);
E('ERR_FEATURE_UNAVAILABLE_ON_PLATFORM',
'The feature %s is unavailable on the current platform' +
', which is being used to run Node.js',
TypeError);
E('ERR_FS_CP_DIR_TO_NON_DIR',
'Cannot overwrite non-directory with directory', SystemError);
E('ERR_FS_CP_EEXIST', 'Target already exists', SystemError);
Expand Down
114 changes: 54 additions & 60 deletions test/parallel/test-watch-mode-files_watcher.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -93,14 +93,13 @@ describe('watch mode file watcher', () => {
assert.ok(changesCount < 5);
});

it('should ignore files in watched directory if they are not filtered',
{ skip: !supportsRecursiveWatching }, async () => {
watcher.on('changed', common.mustNotCall());
watcher.watchPath(tmpdir.path);
writeFileSync(tmpdir.resolve('file3'), '1');
// Wait for this long to make sure changes are not triggered
await setTimeout(1000);
});
it('should ignore files in watched directory if they are not filtered', async () => {
watcher.on('changed', common.mustNotCall());
watcher.watchPath(tmpdir.path);
writeFileSync(tmpdir.resolve('file3'), '1');
// Wait for this long to make sure changes are not triggered
await setTimeout(1000);
});

it('should allow clearing filters', async () => {
const file = tmpdir.resolve('file4');
Expand All @@ -118,58 +117,53 @@ describe('watch mode file watcher', () => {
assert.strictEqual(changesCount, 1);
});

it('should watch all files in watched path when in "all" mode',
{ skip: !supportsRecursiveWatching }, async () => {
watcher = new FilesWatcher({ debounce: 100, mode: 'all' });
watcher.on('changed', () => changesCount++);

const file = tmpdir.resolve('file5');
watcher.watchPath(tmpdir.path);

const changed = once(watcher, 'changed');
await setTimeout(common.platformTimeout(100)); // avoid throttling
writeFileSync(file, 'changed');
await changed;
assert.strictEqual(changesCount, 1);
});

it('should ruse existing watcher if it exists',
{ skip: !supportsRecursiveWatching }, () => {
assert.deepStrictEqual(watcher.watchedPaths, []);
watcher.watchPath(tmpdir.path);
assert.deepStrictEqual(watcher.watchedPaths, [tmpdir.path]);
watcher.watchPath(tmpdir.path);
assert.deepStrictEqual(watcher.watchedPaths, [tmpdir.path]);
});

it('should ruse existing watcher of a parent directory',
{ skip: !supportsRecursiveWatching }, () => {
assert.deepStrictEqual(watcher.watchedPaths, []);
watcher.watchPath(tmpdir.path);
assert.deepStrictEqual(watcher.watchedPaths, [tmpdir.path]);
watcher.watchPath(tmpdir.resolve('subdirectory'));
assert.deepStrictEqual(watcher.watchedPaths, [tmpdir.path]);
});

it('should remove existing watcher if adding a parent directory watcher',
{ skip: !supportsRecursiveWatching }, () => {
assert.deepStrictEqual(watcher.watchedPaths, []);
const subdirectory = tmpdir.resolve('subdirectory');
mkdirSync(subdirectory);
watcher.watchPath(subdirectory);
assert.deepStrictEqual(watcher.watchedPaths, [subdirectory]);
watcher.watchPath(tmpdir.path);
assert.deepStrictEqual(watcher.watchedPaths, [tmpdir.path]);
});

it('should clear all watchers when calling clear',
{ skip: !supportsRecursiveWatching }, () => {
assert.deepStrictEqual(watcher.watchedPaths, []);
watcher.watchPath(tmpdir.path);
assert.deepStrictEqual(watcher.watchedPaths, [tmpdir.path]);
watcher.clear();
assert.deepStrictEqual(watcher.watchedPaths, []);
});
it('should watch all files in watched path when in "all" mode', async () => {
watcher = new FilesWatcher({ debounce: 100, mode: 'all' });
watcher.on('changed', () => changesCount++);

const file = tmpdir.resolve('file5');
watcher.watchPath(tmpdir.path);

const changed = once(watcher, 'changed');
await setTimeout(common.platformTimeout(100)); // avoid throttling
writeFileSync(file, 'changed');
await changed;
assert.strictEqual(changesCount, 1);
});

it('should ruse existing watcher if it exists', () => {
assert.deepStrictEqual(watcher.watchedPaths, []);
watcher.watchPath(tmpdir.path);
assert.deepStrictEqual(watcher.watchedPaths, [tmpdir.path]);
watcher.watchPath(tmpdir.path);
assert.deepStrictEqual(watcher.watchedPaths, [tmpdir.path]);
});

it('should ruse existing watcher of a parent directory', () => {
assert.deepStrictEqual(watcher.watchedPaths, []);
watcher.watchPath(tmpdir.path);
assert.deepStrictEqual(watcher.watchedPaths, [tmpdir.path]);
watcher.watchPath(tmpdir.resolve('subdirectory'));
assert.deepStrictEqual(watcher.watchedPaths, [tmpdir.path]);
});

it('should remove existing watcher if adding a parent directory watcher', () => {
assert.deepStrictEqual(watcher.watchedPaths, []);
const subdirectory = tmpdir.resolve('subdirectory');
mkdirSync(subdirectory);
watcher.watchPath(subdirectory);
assert.deepStrictEqual(watcher.watchedPaths, [subdirectory]);
watcher.watchPath(tmpdir.path);
assert.deepStrictEqual(watcher.watchedPaths, [tmpdir.path]);
});

it('should clear all watchers when calling clear', () => {
assert.deepStrictEqual(watcher.watchedPaths, []);
watcher.watchPath(tmpdir.path);
assert.deepStrictEqual(watcher.watchedPaths, [tmpdir.path]);
watcher.clear();
assert.deepStrictEqual(watcher.watchedPaths, []);
});

it('should watch files from subprocess IPC events', async () => {
const file = fixtures.path('watch-mode/ipc.js');
Expand Down
47 changes: 11 additions & 36 deletions test/sequential/test-watch-mode.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@ import { createInterface } from 'node:readline';
if (common.isIBMi)
common.skip('IBMi does not support `fs.watch()`');

const supportsRecursive = common.isMacOS || common.isWindows;

function restart(file, content = readFileSync(file)) {
// To avoid flakiness, we save the file repeatedly until test is done
writeFileSync(file, content);
Expand Down Expand Up @@ -259,9 +257,7 @@ describe('watch mode', { concurrency: !process.env.TEST_PARALLEL, timeout: 60_00
]);
});

it('should watch changes to a file with watch-path', {
skip: !supportsRecursive,
}, async () => {
it('should watch changes to a file with watch-path', async () => {
const dir = tmpdir.resolve('subdir1');
mkdirSync(dir);
const file = createTmpFile();
Expand All @@ -280,9 +276,7 @@ describe('watch mode', { concurrency: !process.env.TEST_PARALLEL, timeout: 60_00
assert.strictEqual(stderr, '');
});

it('should watch when running an non-existing file - when specified under --watch-path', {
skip: !supportsRecursive
}, async () => {
it('should watch when running an non-existing file - when specified under --watch-path', async () => {
const dir = tmpdir.resolve('subdir2');
mkdirSync(dir);
const file = path.join(dir, 'non-existing.js');
Expand All @@ -304,9 +298,7 @@ describe('watch mode', { concurrency: !process.env.TEST_PARALLEL, timeout: 60_00
]);
});

it('should watch when running an non-existing file - when specified under --watch-path with equals', {
skip: !supportsRecursive
}, async () => {
it('should watch when running an non-existing file - when specified under --watch-path with equals', async () => {
const dir = tmpdir.resolve('subdir3');
mkdirSync(dir);
const file = path.join(dir, 'non-existing.js');
Expand Down Expand Up @@ -453,34 +445,25 @@ console.log(values.random);
]);
});

// TODO: Remove skip after https://github.com/nodejs/node/pull/45271 lands
it('should not watch when running an missing file', {
skip: !supportsRecursive
}, async () => {
it('should not watch when running an missing file', async () => {
const nonExistingfile = tmpdir.resolve(`${tmpFiles++}.js`);
await failWriteSucceed({ file: nonExistingfile, watchedFile: nonExistingfile });
});

it('should not watch when running an missing mjs file', {
skip: !supportsRecursive
}, async () => {
it('should not watch when running an missing mjs file', async () => {
const nonExistingfile = tmpdir.resolve(`${tmpFiles++}.mjs`);
await failWriteSucceed({ file: nonExistingfile, watchedFile: nonExistingfile });
});

it('should watch changes to previously missing dependency', {
skip: !supportsRecursive
}, async () => {
it('should watch changes to previously missing dependency', async () => {
const dependency = tmpdir.resolve(`${tmpFiles++}.js`);
const relativeDependencyPath = `./${path.basename(dependency)}`;
const dependant = createTmpFile(`console.log(require('${relativeDependencyPath}'))`);

await failWriteSucceed({ file: dependant, watchedFile: dependency });
});

it('should watch changes to previously missing ESM dependency', {
skip: !supportsRecursive
}, async () => {
it('should watch changes to previously missing ESM dependency', async () => {
const relativeDependencyPath = `./${tmpFiles++}.mjs`;
const dependency = tmpdir.resolve(relativeDependencyPath);
const dependant = createTmpFile(`import ${JSON.stringify(relativeDependencyPath)}`, '.mjs');
Expand Down Expand Up @@ -517,9 +500,7 @@ console.log(values.random);
]);
});

it('should run when `--watch-path=./foo --require ./bar.js`', {
skip: !supportsRecursive,
}, async () => {
it('should run when `--watch-path=./foo --require ./bar.js`', async () => {
const projectDir = tmpdir.resolve('project2');
mkdirSync(projectDir);

Expand Down Expand Up @@ -549,9 +530,7 @@ console.log(values.random);
]);
});

it('should run when `--watch-path=./foo --require=./bar.js`', {
skip: !supportsRecursive,
}, async () => {
it('should run when `--watch-path=./foo --require=./bar.js`', async () => {
const projectDir = tmpdir.resolve('project3');
mkdirSync(projectDir);

Expand Down Expand Up @@ -581,9 +560,7 @@ console.log(values.random);
]);
});

it('should run when `--watch-path ./foo --require ./bar.js`', {
skip: !supportsRecursive,
}, async () => {
it('should run when `--watch-path ./foo --require ./bar.js`', async () => {
const projectDir = tmpdir.resolve('project5');
mkdirSync(projectDir);

Expand Down Expand Up @@ -613,9 +590,7 @@ console.log(values.random);
]);
});

it('should run when `--watch-path=./foo --require=./bar.js`', {
skip: !supportsRecursive,
}, async () => {
it('should run when `--watch-path=./foo --require=./bar.js`', async () => {
const projectDir = tmpdir.resolve('project6');
mkdirSync(projectDir);

Expand Down

0 comments on commit 5e31a82

Please sign in to comment.