1'use strict'; 2const common = require('../common'); 3 4if (common.isIBMi) 5 common.skip('IBMi does not support `fs.watch()`'); 6 7// Tests if `filename` is provided to watcher on supported platforms 8 9const fs = require('fs'); 10const assert = require('assert'); 11const { join } = require('path'); 12 13class WatchTestCase { 14 constructor(shouldInclude, dirName, fileName, field) { 15 this.dirName = dirName; 16 this.fileName = fileName; 17 this.field = field; 18 this.shouldSkip = !shouldInclude; 19 } 20 get dirPath() { return join(tmpdir.path, this.dirName); } 21 get filePath() { return join(this.dirPath, this.fileName); } 22} 23 24const cases = [ 25 // Watch on a directory should callback with a filename on supported systems 26 new WatchTestCase( 27 common.isLinux || common.isOSX || common.isWindows || common.isAIX, 28 'watch1', 29 'foo', 30 'filePath' 31 ), 32 // Watch on a file should callback with a filename on supported systems 33 new WatchTestCase( 34 common.isLinux || common.isOSX || common.isWindows, 35 'watch2', 36 'bar', 37 'dirPath' 38 ), 39]; 40 41const tmpdir = require('../common/tmpdir'); 42tmpdir.refresh(); 43 44for (const testCase of cases) { 45 if (testCase.shouldSkip) continue; 46 fs.mkdirSync(testCase.dirPath); 47 // Long content so it's actually flushed. 48 const content1 = Date.now() + testCase.fileName.toLowerCase().repeat(1e4); 49 fs.writeFileSync(testCase.filePath, content1); 50 51 let interval; 52 const pathToWatch = testCase[testCase.field]; 53 const watcher = fs.watch(pathToWatch); 54 watcher.on('error', (err) => { 55 if (interval) { 56 clearInterval(interval); 57 interval = null; 58 } 59 assert.fail(err); 60 }); 61 watcher.on('close', common.mustCall(() => { 62 watcher.close(); // Closing a closed watcher should be a noop 63 })); 64 watcher.on('change', common.mustCall(function(eventType, argFilename) { 65 if (interval) { 66 clearInterval(interval); 67 interval = null; 68 } 69 if (common.isOSX) 70 assert.strictEqual(['rename', 'change'].includes(eventType), true); 71 else 72 assert.strictEqual(eventType, 'change'); 73 assert.strictEqual(argFilename, testCase.fileName); 74 75 watcher.close(); 76 77 // We document that watchers cannot be used anymore when it's closed, 78 // here we turn the methods into noops instead of throwing 79 watcher.close(); // Closing a closed watcher should be a noop 80 })); 81 82 // Long content so it's actually flushed. toUpperCase so there's real change. 83 const content2 = Date.now() + testCase.fileName.toUpperCase().repeat(1e4); 84 interval = setInterval(() => { 85 fs.writeFileSync(testCase.filePath, ''); 86 fs.writeFileSync(testCase.filePath, content2); 87 }, 100); 88} 89 90[false, 1, {}, [], null, undefined].forEach((input) => { 91 assert.throws( 92 () => fs.watch(input, common.mustNotCall()), 93 { 94 code: 'ERR_INVALID_ARG_TYPE', 95 name: 'TypeError' 96 } 97 ); 98}); 99