Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nodejs/node.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorJames M Snell <jasnell@gmail.com>2021-02-02 02:53:36 +0300
committerDanielle Adams <adamzdanielle@gmail.com>2021-02-16 17:16:19 +0300
commit88d3f74c85eaa62b4d721a880cb6bc8ea2237bc3 (patch)
tree11ad4a45a8e1ed6ee6940d545b7aa11ebf902b85 /test
parentb2b64113b19074691084700a6a9a6b1cede93435 (diff)
fs: add fsPromises.watch()
An alternative to `fs.watch()` that returns an `AsyncIterator` ```js const { watch } = require('fs/promises'); (async () => { const ac = new AbortController(); const { signal } = ac; setTimeout(() => ac.abort(), 10000); const watcher = watch('file.txt', { signal }); for await (const { eventType, filename } of watcher) { console.log(eventType, filename); } })() ``` Signed-off-by: James M Snell <jasnell@gmail.com> PR-URL: https://github.com/nodejs/node/pull/37179 Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
Diffstat (limited to 'test')
-rw-r--r--test/parallel/test-bootstrap-modules.js3
-rw-r--r--test/parallel/test-fs-promises-watch.js115
2 files changed, 118 insertions, 0 deletions
diff --git a/test/parallel/test-bootstrap-modules.js b/test/parallel/test-bootstrap-modules.js
index 4d47de41c29..236c95457fe 100644
--- a/test/parallel/test-bootstrap-modules.js
+++ b/test/parallel/test-bootstrap-modules.js
@@ -17,6 +17,7 @@ const expectedModules = new Set([
'Internal Binding credentials',
'Internal Binding fs',
'Internal Binding fs_dir',
+ 'Internal Binding fs_event_wrap',
'Internal Binding messaging',
'Internal Binding module_wrap',
'Internal Binding native_module',
@@ -31,6 +32,7 @@ const expectedModules = new Set([
'Internal Binding types',
'Internal Binding url',
'Internal Binding util',
+ 'Internal Binding uv',
'Internal Binding worker',
'NativeModule buffer',
'NativeModule events',
@@ -51,6 +53,7 @@ const expectedModules = new Set([
'NativeModule internal/fs/utils',
'NativeModule internal/fs/promises',
'NativeModule internal/fs/rimraf',
+ 'NativeModule internal/fs/watchers',
'NativeModule internal/idna',
'NativeModule internal/linkedlist',
'NativeModule internal/modules/run_main',
diff --git a/test/parallel/test-fs-promises-watch.js b/test/parallel/test-fs-promises-watch.js
new file mode 100644
index 00000000000..4603b934c4b
--- /dev/null
+++ b/test/parallel/test-fs-promises-watch.js
@@ -0,0 +1,115 @@
+'use strict';
+const common = require('../common');
+
+if (common.isIBMi)
+ common.skip('IBMi does not support `fs.watch()`');
+
+const { watch } = require('fs/promises');
+const fs = require('fs');
+const assert = require('assert');
+const { join } = require('path');
+const tmpdir = require('../common/tmpdir');
+
+class WatchTestCase {
+ constructor(shouldInclude, dirName, fileName, field) {
+ this.dirName = dirName;
+ this.fileName = fileName;
+ this.field = field;
+ this.shouldSkip = !shouldInclude;
+ }
+ get dirPath() { return join(tmpdir.path, this.dirName); }
+ get filePath() { return join(this.dirPath, this.fileName); }
+}
+
+const kCases = [
+ // Watch on a directory should callback with a filename on supported systems
+ new WatchTestCase(
+ common.isLinux || common.isOSX || common.isWindows || common.isAIX,
+ 'watch1',
+ 'foo',
+ 'filePath'
+ ),
+ // Watch on a file should callback with a filename on supported systems
+ new WatchTestCase(
+ common.isLinux || common.isOSX || common.isWindows,
+ 'watch2',
+ 'bar',
+ 'dirPath'
+ )
+];
+
+tmpdir.refresh();
+
+for (const testCase of kCases) {
+ if (testCase.shouldSkip) continue;
+ fs.mkdirSync(testCase.dirPath);
+ // Long content so it's actually flushed.
+ const content1 = Date.now() + testCase.fileName.toLowerCase().repeat(1e4);
+ fs.writeFileSync(testCase.filePath, content1);
+
+ async function test() {
+ const watcher = watch(testCase[testCase.field]);
+ for await (const { eventType, filename } of watcher) {
+ assert.strictEqual(['rename', 'change'].includes(eventType), true);
+ assert.strictEqual(filename, testCase.fileName);
+ break;
+ }
+
+ // Waiting on it again is a non-op
+ // eslint-disable-next-line no-unused-vars
+ for await (const p of watcher) {
+ assert.fail('should not run');
+ }
+ }
+
+ // Long content so it's actually flushed. toUpperCase so there's real change.
+ const content2 = Date.now() + testCase.fileName.toUpperCase().repeat(1e4);
+ setImmediate(() => {
+ fs.writeFileSync(testCase.filePath, '');
+ fs.writeFileSync(testCase.filePath, content2);
+ });
+
+ test().then(common.mustCall());
+}
+
+assert.rejects(
+ // eslint-disable-next-line no-unused-vars
+ async () => { for await (const _ of watch(1)) {} },
+ { code: 'ERR_INVALID_ARG_TYPE' });
+
+assert.rejects(
+ // eslint-disable-next-line no-unused-vars
+ async () => { for await (const _ of watch(__filename, 1)) {} },
+ { code: 'ERR_INVALID_ARG_TYPE' });
+
+assert.rejects(
+ // eslint-disable-next-line no-unused-vars
+ async () => { for await (const _ of watch('', { persistent: 1 })) {} },
+ { code: 'ERR_INVALID_ARG_TYPE' });
+
+assert.rejects(
+ // eslint-disable-next-line no-unused-vars
+ async () => { for await (const _ of watch('', { recursive: 1 })) {} },
+ { code: 'ERR_INVALID_ARG_TYPE' });
+
+assert.rejects(
+ // eslint-disable-next-line no-unused-vars
+ async () => { for await (const _ of watch('', { encoding: 1 })) {} },
+ { code: 'ERR_INVALID_ARG_VALUE' });
+
+assert.rejects(
+ // eslint-disable-next-line no-unused-vars
+ async () => { for await (const _ of watch('', { signal: 1 })) {} },
+ { code: 'ERR_INVALID_ARG_TYPE' });
+
+(async () => {
+ const ac = new AbortController();
+ const { signal } = ac;
+ setImmediate(() => ac.abort());
+ try {
+ // eslint-disable-next-line no-unused-vars
+ for await (const _ of watch(__filename, { signal })) {}
+ } catch (err) {
+ assert.strictEqual(err.name, 'AbortError');
+ }
+})().then(common.mustCall());