test: split test-fs-watch-ignore-*

Split and simplify the tests into individual files.

Refs: https://github.com/nodejs/node/pull/61433
PR-URL: https://github.com/nodejs/node/pull/61494
Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com>
This commit is contained in:
Luigi Pinca authored and GitHub committed 2026-01-30 19:57:40 +00:00
1 parent 7407164a56
commit e67848a8ae
18 files changed
+690 -701

No files matched your search

+18
View File
@@ -76,14 +76,32 @@ test-domain-throw-error-then-throw-from-uncaught-exception-handler: PASS, FLAKY
test-domain-with-abort-on-uncaught-exception: PASS, FLAKY
# https://github.com/nodejs/node/issues/54346
test-esm-loader-hooks-inspect-wait: PASS, FLAKY
# https://github.com/nodejs/node/issues/61520
test-fs-promises-watch-iterator: SKIP
test-fs-promises-watch-ignore-function: SKIP
test-fs-promises-watch-ignore-glob: SKIP
test-fs-promises-watch-ignore-mixed: SKIP
test-fs-promises-watch-ignore-regexp: SKIP
test-fs-watch-ignore-function: SKIP
test-fs-watch-ignore-glob: SKIP
test-fs-watch-ignore-mixed: SKIP
test-fs-watch-ignore-regexp: SKIP
# https://github.com/nodejs/node/issues/50050
test-tick-processor-arguments: SKIP
[$system==freebsd]
# https://github.com/nodejs/node/issues/54346
test-esm-loader-hooks-inspect-wait: PASS, FLAKY
# https://github.com/nodejs/node/issues/61520
test-fs-promises-watch-iterator: SKIP
test-fs-promises-watch-ignore-function: SKIP
test-fs-promises-watch-ignore-glob: SKIP
test-fs-promises-watch-ignore-mixed: SKIP
test-fs-promises-watch-ignore-regexp: SKIP
test-fs-watch-ignore-function: SKIP
test-fs-watch-ignore-glob: SKIP
test-fs-watch-ignore-mixed: SKIP
test-fs-watch-ignore-regexp: SKIP
[$system==aix]
# https://github.com/nodejs/node/issues/54346
@@ -0,0 +1,46 @@
import * as common from '../common/index.mjs';
import { skipIfNoWatch } from '../common/watch.js';
skipIfNoWatch();
const assert = await import('node:assert');
const path = await import('node:path');
const tmpdir = await import('../common/tmpdir.js');
const { setTimeout } = await import('node:timers/promises');
const { watch } = await import('node:fs/promises');
const { writeFileSync } = await import('node:fs');
tmpdir.refresh();
const testDir = tmpdir.resolve();
const keepFile = 'visible.txt';
const ignoreFile = '.hidden';
const keepFilePath = path.join(testDir, keepFile);
const ignoreFilePath = path.join(testDir, ignoreFile);
async function watchDir() {
const watcher = watch(testDir, {
ignore: (filename) => filename.startsWith('.'),
});
for await (const { filename } of watcher) {
assert.notStrictEqual(filename, ignoreFile);
if (filename === keepFile) {
break;
}
}
}
async function writeFiles() {
if (common.isMacOS) {
// Do the write with a delay to ensure that the OS is ready to notify us.
// See https://github.com/nodejs/node/issues/52601.
await setTimeout(common.platformTimeout(100));
}
writeFileSync(ignoreFilePath, 'ignored');
writeFileSync(keepFilePath, 'content');
}
await Promise.all([watchDir(), writeFiles()]);
@@ -0,0 +1,44 @@
import * as common from '../common/index.mjs';
import { skipIfNoWatch } from '../common/watch.js';
skipIfNoWatch();
const assert = await import('node:assert');
const path = await import('node:path');
const tmpdir = await import('../common/tmpdir.js');
const { setTimeout } = await import('node:timers/promises');
const { watch } = await import('node:fs/promises');
const { writeFileSync } = await import('node:fs');
tmpdir.refresh();
const testDir = tmpdir.resolve();
const keepFile = 'keep.txt';
const ignoreFile = 'ignore.log';
const keepFilePath = path.join(testDir, keepFile);
const ignoreFilePath = path.join(testDir, ignoreFile);
async function watchDir() {
const watcher = watch(testDir, { ignore: '*.log' });
for await (const { filename } of watcher) {
assert.notStrictEqual(filename, ignoreFile);
if (filename === keepFile) {
break;
}
}
}
async function writeFiles() {
if (common.isMacOS) {
// Do the write with a delay to ensure that the OS is ready to notify us.
// See https://github.com/nodejs/node/issues/52601.
await setTimeout(common.platformTimeout(100));
}
writeFileSync(ignoreFilePath, 'ignored');
writeFileSync(keepFilePath, 'content');
}
await Promise.all([watchDir(), writeFiles()]);
@@ -0,0 +1,35 @@
import '../common/index.mjs';
import { skipIfNoWatch } from '../common/watch.js';
skipIfNoWatch();
const assert = await import('node:assert');
const { watch } = await import('node:fs/promises');
await assert.rejects(
async () => {
const watcher = watch('.', { ignore: 123 });
// eslint-disable-next-line no-unused-vars
for await (const _ of watcher) {
// Will throw before yielding
}
},
{
code: 'ERR_INVALID_ARG_TYPE',
name: 'TypeError',
}
);
await assert.rejects(
async () => {
const watcher = watch('.', { ignore: '' });
// eslint-disable-next-line no-unused-vars
for await (const _ of watcher) {
// Will throw before yielding
}
},
{
code: 'ERR_INVALID_ARG_VALUE',
name: 'TypeError',
}
);
@@ -0,0 +1,53 @@
import * as common from '../common/index.mjs';
import { skipIfNoWatch } from '../common/watch.js';
skipIfNoWatch();
const assert = await import('node:assert');
const path = await import('node:path');
const tmpdir = await import('../common/tmpdir.js');
const { setTimeout } = await import('node:timers/promises');
const { watch } = await import('node:fs/promises');
const { writeFileSync } = await import('node:fs');
tmpdir.refresh();
const testDir = tmpdir.resolve();
const keepFile = 'keep.txt';
const ignoreLog = 'debug.log';
const ignoreTmp = 'temp.tmp';
const keepFilePath = path.join(testDir, keepFile);
const ignoreLogPath = path.join(testDir, ignoreLog);
const ignoreTmpPath = path.join(testDir, ignoreTmp);
async function watchDir() {
const watcher = watch(testDir, {
ignore: [
'*.log',
/\.tmp$/,
],
});
for await (const { filename } of watcher) {
assert.notStrictEqual(filename, ignoreLog);
assert.notStrictEqual(filename, ignoreTmp);
if (filename === keepFile) {
break;
}
}
}
async function writeFiles() {
if (common.isMacOS) {
// Do the write with a delay to ensure that the OS is ready to notify us.
// See https://github.com/nodejs/node/issues/52601.
await setTimeout(common.platformTimeout(100));
}
writeFileSync(ignoreLogPath, 'ignored');
writeFileSync(ignoreTmpPath, 'ignored');
writeFileSync(keepFilePath, 'content');
}
await Promise.all([watchDir(), writeFiles()]);
@@ -0,0 +1,44 @@
import * as common from '../common/index.mjs';
import { skipIfNoWatch } from '../common/watch.js';
skipIfNoWatch();
const assert = await import('node:assert');
const path = await import('node:path');
const tmpdir = await import('../common/tmpdir.js');
const { setTimeout } = await import('node:timers/promises');
const { watch } = await import('node:fs/promises');
const { writeFileSync } = await import('node:fs');
tmpdir.refresh();
const testDir = tmpdir.resolve();
const keepFile = 'keep.txt';
const ignoreFile = 'ignore.tmp';
const keepFilePath = path.join(testDir, keepFile);
const ignoreFilePath = path.join(testDir, ignoreFile);
async function watchDir() {
const watcher = watch(testDir, { ignore: /\.tmp$/ });
for await (const { filename } of watcher) {
assert.notStrictEqual(filename, ignoreFile);
if (filename === keepFile) {
break;
}
}
}
async function writeFiles() {
if (common.isMacOS) {
// Do the write with a delay to ensure that the OS is ready to notify us.
// See https://github.com/nodejs/node/issues/52601.
await setTimeout(common.platformTimeout(100));
}
writeFileSync(ignoreFilePath, 'ignored');
writeFileSync(keepFilePath, 'content');
}
await Promise.all([watchDir(), writeFiles()]);
@@ -0,0 +1,44 @@
'use strict';
const common = require('../common');
const { skipIfNoWatch } = require('../common/watch.js');
skipIfNoWatch();
const assert = require('assert');
const path = require('path');
const fs = require('fs');
const tmpdir = require('../common/tmpdir');
tmpdir.refresh();
const testFileName = 'visible.txt';
const testFilePath = path.join(tmpdir.path, testFileName);
const ignoredFileName = '.hidden';
const ignoredFilePath = path.join(tmpdir.path, ignoredFileName);
const watcher = fs.watch(tmpdir.path, {
ignore: (filename) => filename.startsWith('.'),
});
watcher.on('change', common.mustCallAtLeast((event, filename) => {
assert.notStrictEqual(filename, ignoredFileName);
if (filename === testFileName) {
watcher.close();
}
}, 1));
function writeFiles() {
fs.writeFileSync(ignoredFilePath, 'ignored');
fs.writeFileSync(testFilePath, 'content');
}
if (common.isMacOS) {
// Do the write with a delay to ensure that the OS is ready to notify us. See
// https://github.com/nodejs/node/issues/52601.
setTimeout(writeFiles, common.platformTimeout(100));
} else {
writeFiles();
}
@@ -0,0 +1,44 @@
'use strict';
const common = require('../common');
const { skipIfNoWatch } = require('../common/watch.js');
skipIfNoWatch();
const assert = require('assert');
const path = require('path');
const fs = require('fs');
const tmpdir = require('../common/tmpdir');
tmpdir.refresh();
const testFileName = 'file.txt';
const testFilePath = path.join(tmpdir.path, testFileName);
const ignoredFileName = 'file.log';
const ignoredFilePath = path.join(tmpdir.path, ignoredFileName);
const watcher = fs.watch(tmpdir.path, {
ignore: '*.log',
});
watcher.on('change', common.mustCallAtLeast((event, filename) => {
assert.notStrictEqual(filename, ignoredFileName);
if (filename === testFileName) {
watcher.close();
}
}, 1));
function writeFiles() {
fs.writeFileSync(ignoredFilePath, 'ignored');
fs.writeFileSync(testFilePath, 'content');
}
if (common.isMacOS) {
// Do the write with a delay to ensure that the OS is ready to notify us. See
// https://github.com/nodejs/node/issues/52601.
setTimeout(writeFiles, common.platformTimeout(100));
} else {
writeFiles();
}
@@ -0,0 +1,41 @@
'use strict';
require('../common');
const { skipIfNoWatch } = require('../common/watch.js');
skipIfNoWatch();
const assert = require('assert');
const fs = require('fs');
assert.throws(
() => fs.watch('.', { ignore: 123 }),
{
code: 'ERR_INVALID_ARG_TYPE',
name: 'TypeError',
}
);
assert.throws(
() => fs.watch('.', { ignore: '' }),
{
code: 'ERR_INVALID_ARG_VALUE',
name: 'TypeError',
}
);
assert.throws(
() => fs.watch('.', { ignore: [123] }),
{
code: 'ERR_INVALID_ARG_TYPE',
name: 'TypeError',
}
);
assert.throws(
() => fs.watch('.', { ignore: [''] }),
{
code: 'ERR_INVALID_ARG_VALUE',
name: 'TypeError',
}
);
@@ -0,0 +1,56 @@
'use strict';
const common = require('../common');
const { skipIfNoWatch } = require('../common/watch.js');
skipIfNoWatch();
const assert = require('assert');
const path = require('path');
const fs = require('fs');
const tmpdir = require('../common/tmpdir');
tmpdir.refresh();
const testFileName = 'keep.txt';
const testFilePath = path.join(tmpdir.path, testFileName);
const ignoredLogName = 'debug.log';
const ignoredLogPath = path.join(tmpdir.path, ignoredLogName);
const ignoredTmpName = 'temp.tmp';
const ignoredTmpPath = path.join(tmpdir.path, ignoredTmpName);
const ignoredHiddenName = '.secret';
const ignoredHiddenPath = path.join(tmpdir.path, ignoredHiddenName);
const watcher = fs.watch(tmpdir.path, {
ignore: [
'*.log',
/\.tmp$/,
(filename) => filename.startsWith('.'),
],
});
watcher.on('change', common.mustCallAtLeast((event, filename) => {
assert.notStrictEqual(filename, ignoredLogName);
assert.notStrictEqual(filename, ignoredTmpName);
assert.notStrictEqual(filename, ignoredHiddenName);
if (filename === testFileName) {
watcher.close();
}
}, 1));
function writeFiles() {
fs.writeFileSync(ignoredLogPath, 'ignored');
fs.writeFileSync(ignoredTmpPath, 'ignored');
fs.writeFileSync(ignoredHiddenPath, 'ignored');
fs.writeFileSync(testFilePath, 'content');
}
if (common.isMacOS) {
// Do the write with a delay to ensure that the OS is ready to notify us. See
// https://github.com/nodejs/node/issues/52601.
setTimeout(writeFiles, common.platformTimeout(100));
} else {
writeFiles();
}
@@ -1,219 +0,0 @@
'use strict';
const common = require('../common');
if (common.isIBMi)
common.skip('IBMi does not support `fs.watch()`');
if (common.isAIX)
common.skip('folder watch capability is limited in AIX.');
if (common.isSunOS)
common.skip('fs.watch is not reliable on SunOS.');
const assert = require('assert');
const path = require('path');
const fs = require('fs/promises');
const fsSync = require('fs');
const tmpdir = require('../common/tmpdir');
const testDir = tmpdir.path;
tmpdir.refresh();
// Test 1: String glob pattern ignore with Promise API
(async function testGlobIgnore() {
const testsubdir = await fs.mkdtemp(testDir + path.sep);
const keepFile = 'keep.txt';
const ignoreFile = 'ignore.log';
const keepFilePath = path.join(testsubdir, keepFile);
const ignoreFilePath = path.join(testsubdir, ignoreFile);
const watcher = fs.watch(testsubdir, { ignore: '*.log' });
let seenIgnored = false;
let interval;
process.on('exit', () => {
assert.ok(interval === null);
assert.strictEqual(seenIgnored, false);
});
process.nextTick(common.mustCall(() => {
interval = setInterval(() => {
fsSync.writeFileSync(ignoreFilePath, 'ignored');
fsSync.writeFileSync(keepFilePath, 'content-' + Date.now());
}, 100);
}));
for await (const { filename } of watcher) {
if (filename === ignoreFile) {
seenIgnored = true;
}
if (filename === keepFile) {
break;
}
}
clearInterval(interval);
interval = null;
})().then(common.mustCall());
// Test 2: RegExp ignore pattern with Promise API
(async function testRegExpIgnore() {
const testsubdir = await fs.mkdtemp(testDir + path.sep);
const keepFile = 'keep.txt';
const ignoreFile = 'ignore.tmp';
const keepFilePath = path.join(testsubdir, keepFile);
const ignoreFilePath = path.join(testsubdir, ignoreFile);
const watcher = fs.watch(testsubdir, { ignore: /\.tmp$/ });
let seenIgnored = false;
let interval;
process.on('exit', () => {
assert.ok(interval === null);
assert.strictEqual(seenIgnored, false);
});
process.nextTick(common.mustCall(() => {
interval = setInterval(() => {
fsSync.writeFileSync(ignoreFilePath, 'ignored');
fsSync.writeFileSync(keepFilePath, 'content-' + Date.now());
}, 100);
}));
for await (const { filename } of watcher) {
if (filename === ignoreFile) {
seenIgnored = true;
}
if (filename === keepFile) {
break;
}
}
clearInterval(interval);
interval = null;
})().then(common.mustCall());
// Test 3: Function ignore pattern with Promise API
(async function testFunctionIgnore() {
const testsubdir = await fs.mkdtemp(testDir + path.sep);
const keepFile = 'visible.txt';
const ignoreFile = '.hidden';
const keepFilePath = path.join(testsubdir, keepFile);
const ignoreFilePath = path.join(testsubdir, ignoreFile);
const watcher = fs.watch(testsubdir, {
ignore: (filename) => filename.startsWith('.'),
});
let seenIgnored = false;
let interval;
process.on('exit', () => {
assert.ok(interval === null);
assert.strictEqual(seenIgnored, false);
});
process.nextTick(common.mustCall(() => {
interval = setInterval(() => {
fsSync.writeFileSync(ignoreFilePath, 'ignored');
fsSync.writeFileSync(keepFilePath, 'content-' + Date.now());
}, 100);
}));
for await (const { filename } of watcher) {
if (filename === ignoreFile) {
seenIgnored = true;
}
if (filename === keepFile) {
break;
}
}
clearInterval(interval);
interval = null;
})().then(common.mustCall());
// Test 4: Array of mixed patterns with Promise API
(async function testArrayIgnore() {
const testsubdir = await fs.mkdtemp(testDir + path.sep);
const keepFile = 'keep.txt';
const ignoreLog = 'debug.log';
const ignoreTmp = 'temp.tmp';
const keepFilePath = path.join(testsubdir, keepFile);
const ignoreLogPath = path.join(testsubdir, ignoreLog);
const ignoreTmpPath = path.join(testsubdir, ignoreTmp);
const watcher = fs.watch(testsubdir, {
ignore: [
'*.log',
/\.tmp$/,
],
});
let seenLog = false;
let seenTmp = false;
let interval;
process.on('exit', () => {
assert.ok(interval === null);
assert.strictEqual(seenLog, false);
assert.strictEqual(seenTmp, false);
});
process.nextTick(common.mustCall(() => {
interval = setInterval(() => {
fsSync.writeFileSync(ignoreLogPath, 'ignored');
fsSync.writeFileSync(ignoreTmpPath, 'ignored');
fsSync.writeFileSync(keepFilePath, 'content-' + Date.now());
}, 100);
}));
for await (const { filename } of watcher) {
if (filename === ignoreLog) seenLog = true;
if (filename === ignoreTmp) seenTmp = true;
if (filename === keepFile) {
break;
}
}
clearInterval(interval);
interval = null;
})().then(common.mustCall());
// Test 5: Invalid option validation with Promise API
// Note: async generators don't execute until iteration starts,
// so we need to use assert.rejects with iteration
(async function testInvalidIgnore() {
const testsubdir = await fs.mkdtemp(testDir + path.sep);
await assert.rejects(
async () => {
const watcher = fs.watch(testsubdir, { ignore: 123 });
// eslint-disable-next-line no-unused-vars
for await (const _ of watcher) {
// Will throw before yielding
}
},
{
code: 'ERR_INVALID_ARG_TYPE',
name: 'TypeError',
}
);
await assert.rejects(
async () => {
const watcher = fs.watch(testsubdir, { ignore: '' });
// eslint-disable-next-line no-unused-vars
for await (const _ of watcher) {
// Will throw before yielding
}
},
{
code: 'ERR_INVALID_ARG_VALUE',
name: 'TypeError',
}
);
})().then(common.mustCall());
@@ -0,0 +1,56 @@
'use strict';
const common = require('../common');
const { skipIfNoWatch } = require('../common/watch.js');
skipIfNoWatch();
const assert = require('assert');
const path = require('path');
const fs = require('fs');
const tmpdir = require('../common/tmpdir');
tmpdir.refresh();
const nodeModules = path.join(tmpdir.path, 'node_modules');
const srcDir = path.join(tmpdir.path, 'src');
fs.mkdirSync(nodeModules);
fs.mkdirSync(srcDir);
const testFileName = 'app.js';
const testFilePath = path.join(srcDir, testFileName);
const ignoredFileName = 'package.json';
const ignoredFilePath = path.join(nodeModules, ignoredFileName);
const watcher = fs.watch(tmpdir.path, {
recursive: true,
// On Linux, matching the directory skips watching it entirely.
// On macOS, the native watcher still needs to filter file events inside.
ignore: ['**/node_modules/**', '**/node_modules'],
});
watcher.on('change', common.mustCallAtLeast((event, filename) => {
if (!filename) return;
// On recursive watch, filename includes relative path from watched dir
assert(!filename.includes('node_modules'));
if (filename.endsWith(testFileName)) {
watcher.close();
}
}, 1));
function writeFiles() {
fs.writeFileSync(ignoredFilePath, '{}');
fs.writeFileSync(testFilePath, 'console.log("hello-' + Date.now() + '")');
}
if (common.isMacOS) {
// Do the write with a delay to ensure that the OS is ready to notify us. See
// https://github.com/nodejs/node/issues/52601.
setTimeout(writeFiles, common.platformTimeout(100));
} else {
writeFiles();
}
@@ -0,0 +1,51 @@
'use strict';
const common = require('../common');
const { skipIfNoWatch } = require('../common/watch.js');
skipIfNoWatch();
const assert = require('assert');
const path = require('path');
const fs = require('fs');
const tmpdir = require('../common/tmpdir');
tmpdir.refresh();
const subDirectory = path.join(tmpdir.path, 'subdir');
fs.mkdirSync(subDirectory);
const testFileName = 'file.txt';
const testFilePath = path.join(subDirectory, testFileName);
const ignoredFileName = 'file.log';
const ignoredFilePath = path.join(subDirectory, ignoredFileName);
const watcher = fs.watch(tmpdir.path, {
recursive: true,
ignore: '*.log',
});
watcher.on('change', common.mustCallAtLeast((event, filename) => {
if (!filename) return;
// On recursive watch, filename includes relative path from watched dir
assert(!filename.endsWith(ignoredFileName));
if (filename.endsWith(testFileName)) {
watcher.close();
}
}, 1));
function writeFiles() {
fs.writeFileSync(ignoredFilePath, 'ignored');
fs.writeFileSync(testFilePath, 'content');
}
if (common.isMacOS) {
// Do the write with a delay to ensure that the OS is ready to notify us. See
// https://github.com/nodejs/node/issues/52601.
setTimeout(writeFiles, common.platformTimeout(100));
} else {
writeFiles();
}
@@ -0,0 +1,63 @@
'use strict';
const common = require('../common');
const { skipIfNoWatch } = require('../common/watch.js');
skipIfNoWatch();
const assert = require('assert');
const path = require('path');
const fs = require('fs');
const tmpdir = require('../common/tmpdir');
tmpdir.refresh();
const subDirectory = path.join(tmpdir.path, 'deep');
fs.mkdirSync(subDirectory);
const testFileName = 'visible.txt';
const testFilePath = path.join(subDirectory, testFileName);
const ignoredLogName = 'debug.log';
const ignoredLogPath = path.join(subDirectory, ignoredLogName);
const ignoredTmpName = 'temp.tmp';
const ignoredTmpPath = path.join(subDirectory, ignoredTmpName);
const ignoredHiddenName = '.gitignore';
const ignoredHiddenPath = path.join(subDirectory, ignoredHiddenName);
const watcher = fs.watch(tmpdir.path, {
recursive: true,
ignore: [
'*.log',
/\.tmp$/,
(filename) => path.basename(filename).startsWith('.'),
],
});
watcher.on('change', common.mustCallAtLeast((event, filename) => {
if (!filename) return;
// On recursive watch, filename includes relative path from watched dir
assert(!filename.endsWith(ignoredLogName));
assert(!filename.endsWith(ignoredTmpName));
assert(!filename.endsWith(ignoredHiddenName));
if (filename.endsWith(testFileName)) {
watcher.close();
}
}, 1));
function writeFiles() {
fs.writeFileSync(ignoredLogPath, 'ignored');
fs.writeFileSync(ignoredTmpPath, 'ignored');
fs.writeFileSync(ignoredHiddenPath, 'ignored');
fs.writeFileSync(testFilePath, 'content');
}
if (common.isMacOS) {
// Do the write with a delay to ensure that the OS is ready to notify us. See
// https://github.com/nodejs/node/issues/52601.
setTimeout(writeFiles, common.platformTimeout(100));
} else {
writeFiles();
}
@@ -0,0 +1,51 @@
'use strict';
const common = require('../common');
const { skipIfNoWatch } = require('../common/watch.js');
skipIfNoWatch();
const assert = require('assert');
const path = require('path');
const fs = require('fs');
const tmpdir = require('../common/tmpdir');
tmpdir.refresh();
const subDirectory = path.join(tmpdir.path, 'nested');
fs.mkdirSync(subDirectory);
const testFileName = 'keep.txt';
const testFilePath = path.join(subDirectory, testFileName);
const ignoredFileName = 'temp.tmp';
const ignoredFilePath = path.join(subDirectory, ignoredFileName);
const watcher = fs.watch(tmpdir.path, {
recursive: true,
ignore: /\.tmp$/,
});
watcher.on('change', common.mustCallAtLeast((event, filename) => {
if (!filename) return;
// On recursive watch, filename includes relative path from watched dir
assert(!filename.endsWith(ignoredFileName));
if (filename.endsWith(testFileName)) {
watcher.close();
}
}, 1));
function writeFiles() {
fs.writeFileSync(ignoredFilePath, 'ignored');
fs.writeFileSync(testFilePath, 'content');
}
if (common.isMacOS) {
// Do the write with a delay to ensure that the OS is ready to notify us. See
// https://github.com/nodejs/node/issues/52601.
setTimeout(writeFiles, common.platformTimeout(100));
} else {
writeFiles();
}
@@ -1,234 +0,0 @@
'use strict';
const common = require('../common');
if (common.isIBMi)
common.skip('IBMi does not support `fs.watch()`');
if (common.isAIX)
common.skip('folder watch capability is limited in AIX.');
if (common.isSunOS)
common.skip('fs.watch is not reliable on SunOS.');
const assert = require('assert');
const path = require('path');
const fs = require('fs');
const tmpdir = require('../common/tmpdir');
const testDir = tmpdir.path;
tmpdir.refresh();
// Test 1: String glob pattern ignore with recursive watch
{
const rootDirectory = fs.mkdtempSync(testDir + path.sep);
const testDirectory = path.join(rootDirectory, 'test-recursive-glob');
const subDirectory = path.join(testDirectory, 'subdir');
fs.mkdirSync(testDirectory);
fs.mkdirSync(subDirectory);
const testFile = path.join(subDirectory, 'file.txt');
const ignoredFile = path.join(subDirectory, 'file.log');
const watcher = fs.watch(testDirectory, {
recursive: true,
ignore: '*.log',
});
let seenFile = false;
let seenIgnored = false;
let interval;
watcher.on('change', common.mustCallAtLeast((event, filename) => {
// On recursive watch, filename includes relative path from watched dir
if (filename && filename.endsWith('file.txt')) {
seenFile = true;
}
if (filename && filename.endsWith('file.log')) {
seenIgnored = true;
}
if (seenFile) {
clearInterval(interval);
interval = null;
watcher.close();
}
}, 1));
// Use setInterval to handle potential event delays on macOS FSEvents
process.nextTick(common.mustCall(() => {
interval = setInterval(() => {
fs.writeFileSync(ignoredFile, 'ignored');
fs.writeFileSync(testFile, 'content-' + Date.now());
}, 100);
}));
process.on('exit', () => {
assert.strictEqual(interval, null);
assert.strictEqual(seenFile, true);
assert.strictEqual(seenIgnored, false);
});
}
// Test 2: RegExp ignore pattern with recursive watch
{
const rootDirectory = fs.mkdtempSync(testDir + path.sep);
const testDirectory = path.join(rootDirectory, 'test-recursive-regexp');
const subDirectory = path.join(testDirectory, 'nested');
fs.mkdirSync(testDirectory);
fs.mkdirSync(subDirectory);
const testFile = path.join(subDirectory, 'keep.txt');
const ignoredFile = path.join(subDirectory, 'temp.tmp');
const watcher = fs.watch(testDirectory, {
recursive: true,
ignore: /\.tmp$/,
});
let seenFile = false;
let seenIgnored = false;
let interval;
watcher.on('change', common.mustCallAtLeast((event, filename) => {
if (filename && filename.endsWith('keep.txt')) {
seenFile = true;
}
if (filename && filename.endsWith('temp.tmp')) {
seenIgnored = true;
}
if (seenFile) {
clearInterval(interval);
interval = null;
watcher.close();
}
}, 1));
// Use setInterval to handle potential event delays on macOS FSEvents
process.nextTick(common.mustCall(() => {
interval = setInterval(() => {
fs.writeFileSync(ignoredFile, 'ignored');
fs.writeFileSync(testFile, 'content-' + Date.now());
}, 100);
}));
process.on('exit', () => {
assert.strictEqual(interval, null);
assert.strictEqual(seenFile, true);
assert.strictEqual(seenIgnored, false);
});
}
// Test 3: Glob pattern with ** to match paths in subdirectories
{
const rootDirectory = fs.mkdtempSync(testDir + path.sep);
const testDirectory = path.join(rootDirectory, 'test-recursive-globstar');
const nodeModules = path.join(testDirectory, 'node_modules');
const srcDir = path.join(testDirectory, 'src');
fs.mkdirSync(testDirectory);
fs.mkdirSync(nodeModules);
fs.mkdirSync(srcDir);
const testFile = path.join(srcDir, 'app.js');
const ignoredFile = path.join(nodeModules, 'package.json');
const watcher = fs.watch(testDirectory, {
recursive: true,
// On Linux, matching the directory skips watching it entirely.
// On macOS, the native watcher still needs to filter file events inside.
ignore: ['**/node_modules/**', '**/node_modules'],
});
let seenFile = false;
let seenIgnored = false;
let interval;
watcher.on('change', common.mustCallAtLeast((event, filename) => {
if (filename && filename.endsWith('app.js')) {
seenFile = true;
}
if (filename && filename.includes('node_modules')) {
seenIgnored = true;
}
if (seenFile) {
clearInterval(interval);
interval = null;
watcher.close();
}
}, 1));
// Use setInterval to handle potential event delays on macOS FSEvents
process.nextTick(common.mustCall(() => {
interval = setInterval(() => {
fs.writeFileSync(ignoredFile, '{}');
fs.writeFileSync(testFile, 'console.log("hello-' + Date.now() + '")');
}, 100);
}));
process.on('exit', () => {
assert.strictEqual(interval, null);
assert.strictEqual(seenFile, true);
assert.strictEqual(seenIgnored, false);
});
}
// Test 4: Array of mixed patterns with recursive watch
{
const rootDirectory = fs.mkdtempSync(testDir + path.sep);
const testDirectory = path.join(rootDirectory, 'test-recursive-array');
const subDirectory = path.join(testDirectory, 'deep');
fs.mkdirSync(testDirectory);
fs.mkdirSync(subDirectory);
const testFile = path.join(subDirectory, 'visible.txt');
const ignoredLog = path.join(subDirectory, 'debug.log');
const ignoredTmp = path.join(subDirectory, 'temp.tmp');
const ignoredHidden = path.join(subDirectory, '.gitignore');
const watcher = fs.watch(testDirectory, {
recursive: true,
ignore: [
'*.log',
/\.tmp$/,
(filename) => path.basename(filename).startsWith('.'),
],
});
let seenFile = false;
let seenLog = false;
let seenTmp = false;
let seenHidden = false;
let interval;
watcher.on('change', common.mustCallAtLeast((event, filename) => {
if (filename && filename.endsWith('visible.txt')) {
seenFile = true;
}
if (filename && filename.endsWith('debug.log')) seenLog = true;
if (filename && filename.endsWith('temp.tmp')) seenTmp = true;
if (filename && filename.endsWith('.gitignore')) seenHidden = true;
if (seenFile) {
clearInterval(interval);
interval = null;
watcher.close();
}
}, 1));
// Use setInterval to handle potential event delays on macOS FSEvents
process.nextTick(common.mustCall(() => {
interval = setInterval(() => {
fs.writeFileSync(ignoredLog, 'ignored');
fs.writeFileSync(ignoredTmp, 'ignored');
fs.writeFileSync(ignoredHidden, 'ignored');
fs.writeFileSync(testFile, 'content-' + Date.now());
}, 100);
}));
process.on('exit', () => {
assert.strictEqual(interval, null);
assert.strictEqual(seenFile, true);
assert.strictEqual(seenLog, false);
assert.strictEqual(seenTmp, false);
assert.strictEqual(seenHidden, false);
});
}
@@ -0,0 +1,44 @@
'use strict';
const common = require('../common');
const { skipIfNoWatch } = require('../common/watch.js');
skipIfNoWatch();
const assert = require('assert');
const path = require('path');
const fs = require('fs');
const tmpdir = require('../common/tmpdir');
tmpdir.refresh();
const testFileName = 'keep.txt';
const testFilePath = path.join(tmpdir.path, testFileName);
const ignoredFileName = 'ignore.tmp';
const ignoredFilePath = path.join(tmpdir.path, ignoredFileName);
const watcher = fs.watch(tmpdir.path, {
ignore: /\.tmp$/,
});
watcher.on('change', common.mustCallAtLeast((event, filename) => {
assert.notStrictEqual(filename, ignoredFileName);
if (filename === testFileName) {
watcher.close();
}
}, 1));
function writeFiles() {
fs.writeFileSync(ignoredFilePath, 'ignored');
fs.writeFileSync(testFilePath, 'content');
}
if (common.isMacOS) {
// Do the write with a delay to ensure that the OS is ready to notify us. See
// https://github.com/nodejs/node/issues/52601.
setTimeout(writeFiles, common.platformTimeout(100));
} else {
writeFiles();
}
-248
View File
@@ -1,248 +0,0 @@
'use strict';
const common = require('../common');
if (common.isIBMi)
common.skip('IBMi does not support `fs.watch()`');
if (common.isAIX)
common.skip('folder watch capability is limited in AIX.');
if (common.isSunOS)
common.skip('fs.watch is not reliable on SunOS.');
const assert = require('assert');
const path = require('path');
const fs = require('fs');
const tmpdir = require('../common/tmpdir');
const testDir = tmpdir.path;
tmpdir.refresh();
// Test 1: String glob pattern ignore
{
const rootDirectory = fs.mkdtempSync(testDir + path.sep);
const testDirectory = path.join(rootDirectory, 'test-glob');
fs.mkdirSync(testDirectory);
const testFile = path.join(testDirectory, 'file.txt');
const ignoredFile = path.join(testDirectory, 'file.log');
const watcher = fs.watch(testDirectory, {
ignore: '*.log',
});
let seenFile = false;
let seenIgnored = false;
let interval;
watcher.on('change', common.mustCallAtLeast((event, filename) => {
if (filename === 'file.txt') {
seenFile = true;
}
if (filename === 'file.log') {
seenIgnored = true;
}
if (seenFile) {
clearInterval(interval);
interval = null;
watcher.close();
}
}, 1));
process.nextTick(common.mustCall(() => {
interval = setInterval(() => {
fs.writeFileSync(ignoredFile, 'ignored');
fs.writeFileSync(testFile, 'content-' + Date.now());
}, 100);
}));
process.on('exit', () => {
assert.strictEqual(interval, null);
assert.strictEqual(seenFile, true);
assert.strictEqual(seenIgnored, false);
});
}
// Test 2: RegExp ignore pattern
{
const rootDirectory = fs.mkdtempSync(testDir + path.sep);
const testDirectory = path.join(rootDirectory, 'test-regexp');
fs.mkdirSync(testDirectory);
const testFile = path.join(testDirectory, 'keep.txt');
const ignoredFile = path.join(testDirectory, 'ignore.tmp');
const watcher = fs.watch(testDirectory, {
ignore: /\.tmp$/,
});
let seenFile = false;
let seenIgnored = false;
let interval;
watcher.on('change', common.mustCallAtLeast((event, filename) => {
if (filename === 'keep.txt') {
seenFile = true;
}
if (filename === 'ignore.tmp') {
seenIgnored = true;
}
if (seenFile) {
clearInterval(interval);
interval = null;
watcher.close();
}
}, 1));
process.nextTick(common.mustCall(() => {
interval = setInterval(() => {
fs.writeFileSync(ignoredFile, 'ignored');
fs.writeFileSync(testFile, 'content-' + Date.now());
}, 100);
}));
process.on('exit', () => {
assert.strictEqual(interval, null);
assert.strictEqual(seenFile, true);
assert.strictEqual(seenIgnored, false);
});
}
// Test 3: Function ignore pattern
{
const rootDirectory = fs.mkdtempSync(testDir + path.sep);
const testDirectory = path.join(rootDirectory, 'test-function');
fs.mkdirSync(testDirectory);
const testFile = path.join(testDirectory, 'visible.txt');
const ignoredFile = path.join(testDirectory, '.hidden');
const watcher = fs.watch(testDirectory, {
ignore: (filename) => filename.startsWith('.'),
});
let seenFile = false;
let seenIgnored = false;
let interval;
watcher.on('change', common.mustCallAtLeast((event, filename) => {
if (filename === 'visible.txt') {
seenFile = true;
}
if (filename === '.hidden') {
seenIgnored = true;
}
if (seenFile) {
clearInterval(interval);
interval = null;
watcher.close();
}
}, 1));
process.nextTick(common.mustCall(() => {
interval = setInterval(() => {
fs.writeFileSync(ignoredFile, 'ignored');
fs.writeFileSync(testFile, 'content-' + Date.now());
}, 100);
}));
process.on('exit', () => {
assert.strictEqual(interval, null);
assert.strictEqual(seenFile, true);
assert.strictEqual(seenIgnored, false);
});
}
// Test 4: Array of mixed patterns
{
const rootDirectory = fs.mkdtempSync(testDir + path.sep);
const testDirectory = path.join(rootDirectory, 'test-array');
fs.mkdirSync(testDirectory);
const testFile = path.join(testDirectory, 'keep.txt');
const ignoredLog = path.join(testDirectory, 'debug.log');
const ignoredTmp = path.join(testDirectory, 'temp.tmp');
const ignoredHidden = path.join(testDirectory, '.secret');
const watcher = fs.watch(testDirectory, {
ignore: [
'*.log',
/\.tmp$/,
(filename) => filename.startsWith('.'),
],
});
let seenFile = false;
let seenLog = false;
let seenTmp = false;
let seenHidden = false;
let interval;
watcher.on('change', common.mustCallAtLeast((event, filename) => {
if (filename === 'keep.txt') {
seenFile = true;
}
if (filename === 'debug.log') seenLog = true;
if (filename === 'temp.tmp') seenTmp = true;
if (filename === '.secret') seenHidden = true;
if (seenFile) {
clearInterval(interval);
interval = null;
watcher.close();
}
}, 1));
process.nextTick(common.mustCall(() => {
interval = setInterval(() => {
fs.writeFileSync(ignoredLog, 'ignored');
fs.writeFileSync(ignoredTmp, 'ignored');
fs.writeFileSync(ignoredHidden, 'ignored');
fs.writeFileSync(testFile, 'content-' + Date.now());
}, 100);
}));
process.on('exit', () => {
assert.strictEqual(interval, null);
assert.strictEqual(seenFile, true);
assert.strictEqual(seenLog, false);
assert.strictEqual(seenTmp, false);
assert.strictEqual(seenHidden, false);
});
}
// Test 5: Invalid option validation
{
assert.throws(
() => fs.watch('.', { ignore: 123 }),
{
code: 'ERR_INVALID_ARG_TYPE',
name: 'TypeError',
}
);
assert.throws(
() => fs.watch('.', { ignore: '' }),
{
code: 'ERR_INVALID_ARG_VALUE',
name: 'TypeError',
}
);
assert.throws(
() => fs.watch('.', { ignore: [123] }),
{
code: 'ERR_INVALID_ARG_TYPE',
name: 'TypeError',
}
);
assert.throws(
() => fs.watch('.', { ignore: [''] }),
{
code: 'ERR_INVALID_ARG_VALUE',
name: 'TypeError',
}
);
}