Skip to content

Commit d491c87

Browse files
committed
Add more unittests
1 parent 25283ef commit d491c87

1 file changed

Lines changed: 213 additions & 8 deletions

File tree

test/unit.js

Lines changed: 213 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -30,23 +30,34 @@ test('Single file change', async () => {
3030

3131
return new Promise((resolve, reject) => {
3232
const timeout = setTimeout(() => {
33-
watcher.unwatch(targetPath);
33+
watcher.watchers.forEach((w) => w.close());
34+
watcher.watchers.clear();
35+
watcher.removeAllListeners();
36+
cleanup(targetPath);
3437
reject(new Error('Test timeout'));
3538
}, TEST_TIMEOUT);
3639

3740
watcher.on('change', (fileName) => {
3841
assert.strictEqual(fileName.endsWith('file.ext'), true);
3942
clearTimeout(timeout);
40-
watcher.unwatch(targetPath);
41-
cleanup(targetPath);
43+
watcher.watchers.forEach((w) => w.close());
44+
watcher.watchers.clear();
4245
watcher.removeAllListeners();
46+
cleanup(targetPath);
4347
resolve();
4448
});
4549

4650
setTimeout(() => {
4751
const filePath = path.join(targetPath, 'file.ext');
4852
fs.writeFile(filePath, 'example', 'utf8', (err) => {
49-
if (err) reject(err);
53+
if (err) {
54+
clearTimeout(timeout);
55+
watcher.watchers.forEach((w) => w.close());
56+
watcher.watchers.clear();
57+
watcher.removeAllListeners();
58+
cleanup(targetPath);
59+
reject(err);
60+
}
5061
});
5162
}, WRITE_TIMEOUT);
5263
});
@@ -63,7 +74,10 @@ test('Aggregated change', async () => {
6374

6475
return new Promise((resolve, reject) => {
6576
const timeout = setTimeout(() => {
66-
watcher.unwatch(targetPath);
77+
watcher.watchers.forEach((w) => w.close());
78+
watcher.watchers.clear();
79+
watcher.removeAllListeners();
80+
cleanup(targetPath);
6781
reject(new Error('Test timeout'));
6882
}, TEST_TIMEOUT);
6983

@@ -82,19 +96,210 @@ test('Aggregated change', async () => {
8296
assert.strictEqual(changeCount, 3);
8397
assert.strictEqual(changes.length, 3);
8498
clearTimeout(timeout);
85-
watcher.unwatch(targetPath);
86-
cleanup(targetPath);
99+
watcher.watchers.forEach((w) => w.close());
100+
watcher.watchers.clear();
87101
watcher.removeAllListeners();
102+
cleanup(targetPath);
88103
resolve();
89104
});
90105

91106
setTimeout(() => {
92107
for (const name of files) {
93108
const filePath = path.join(targetPath, name);
94109
fs.writeFile(filePath, 'example', 'utf8', (err) => {
95-
if (err) reject(err);
110+
if (err) {
111+
clearTimeout(timeout);
112+
watcher.watchers.forEach((w) => w.close());
113+
watcher.watchers.clear();
114+
watcher.removeAllListeners();
115+
cleanup(targetPath);
116+
reject(err);
117+
}
96118
});
97119
}
98120
}, WRITE_TIMEOUT);
99121
});
100122
});
123+
124+
test('File deletion detection', async () => {
125+
const targetPath = path.join(dir, 'test/example3');
126+
fs.mkdirSync(targetPath);
127+
const filePath = path.join(targetPath, 'delete-me.txt');
128+
129+
// Create file first
130+
fs.writeFileSync(filePath, 'content');
131+
132+
const watcher = new metawatch.DirectoryWatcher(OPTIONS);
133+
watcher.watch(targetPath);
134+
135+
return new Promise((resolve, reject) => {
136+
const timeout = setTimeout(() => {
137+
watcher.watchers.forEach((w) => w.close());
138+
watcher.watchers.clear();
139+
watcher.removeAllListeners();
140+
cleanup(targetPath);
141+
reject(new Error('Test timeout'));
142+
}, TEST_TIMEOUT);
143+
144+
watcher.on('delete', (fileName) => {
145+
assert.strictEqual(fileName, filePath);
146+
clearTimeout(timeout);
147+
watcher.watchers.forEach((w) => w.close());
148+
watcher.watchers.clear();
149+
watcher.removeAllListeners();
150+
cleanup(targetPath);
151+
resolve();
152+
});
153+
154+
setTimeout(() => {
155+
fs.unlinkSync(filePath);
156+
}, WRITE_TIMEOUT);
157+
});
158+
});
159+
160+
test('Nested directory watching', async () => {
161+
const targetPath = path.join(dir, 'test/example4');
162+
const nestedPath = path.join(targetPath, 'nested');
163+
fs.mkdirSync(targetPath);
164+
fs.mkdirSync(nestedPath);
165+
166+
const watcher = new metawatch.DirectoryWatcher(OPTIONS);
167+
watcher.watch(targetPath);
168+
169+
return new Promise((resolve, reject) => {
170+
const timeout = setTimeout(() => {
171+
// Clean up all watchers
172+
watcher.watchers.forEach((w) => w.close());
173+
watcher.watchers.clear();
174+
watcher.removeAllListeners();
175+
cleanup(targetPath);
176+
reject(new Error('Test timeout'));
177+
}, TEST_TIMEOUT);
178+
179+
watcher.on('change', (fileName) => {
180+
assert.strictEqual(fileName.endsWith('nested-file.txt'), true);
181+
clearTimeout(timeout);
182+
// Clean up all watchers
183+
watcher.watchers.forEach((w) => w.close());
184+
watcher.watchers.clear();
185+
watcher.removeAllListeners();
186+
cleanup(targetPath);
187+
resolve();
188+
});
189+
190+
setTimeout(() => {
191+
const filePath = path.join(nestedPath, 'nested-file.txt');
192+
fs.writeFile(filePath, 'content', 'utf8', (err) => {
193+
if (err) {
194+
clearTimeout(timeout);
195+
watcher.watchers.forEach((w) => w.close());
196+
watcher.watchers.clear();
197+
watcher.removeAllListeners();
198+
cleanup(targetPath);
199+
reject(err);
200+
}
201+
});
202+
}, WRITE_TIMEOUT);
203+
});
204+
});
205+
206+
test('Constructor with default options', () => {
207+
const watcher = new metawatch.DirectoryWatcher();
208+
assert.strictEqual(watcher.timeout, 5000);
209+
assert.strictEqual(watcher.timer, null);
210+
assert.strictEqual(watcher.watchers.size, 0);
211+
assert.strictEqual(watcher.queue.size, 0);
212+
});
213+
214+
test('Constructor with custom timeout', () => {
215+
const customTimeout = 1000;
216+
const watcher = new metawatch.DirectoryWatcher({ timeout: customTimeout });
217+
assert.strictEqual(watcher.timeout, customTimeout);
218+
});
219+
220+
test('Constructor with zero timeout', () => {
221+
const watcher = new metawatch.DirectoryWatcher({ timeout: 0 });
222+
assert.strictEqual(watcher.timeout, 0);
223+
});
224+
225+
test('Unwatch non-existent directory', () => {
226+
const watcher = new metawatch.DirectoryWatcher();
227+
// Should not throw error
228+
watcher.unwatch('/non/existent/path');
229+
assert.strictEqual(watcher.watchers.size, 0);
230+
});
231+
232+
test('Watch same directory twice', async () => {
233+
const targetPath = path.join(dir, 'test/example5');
234+
235+
// Clean up if exists
236+
if (fs.existsSync(targetPath)) {
237+
fs.rmSync(targetPath, { recursive: true, force: true });
238+
}
239+
240+
fs.mkdirSync(targetPath);
241+
242+
const watcher = new metawatch.DirectoryWatcher(OPTIONS);
243+
244+
try {
245+
// Watch first time
246+
watcher.watch(targetPath);
247+
248+
// Wait a bit for the watcher to be created
249+
await new Promise((resolve) => setTimeout(resolve, 50));
250+
251+
const firstWatcher = watcher.watchers.get(targetPath);
252+
assert.ok(firstWatcher);
253+
254+
// Watch second time - should not create new watcher
255+
watcher.watch(targetPath);
256+
const secondWatcher = watcher.watchers.get(targetPath);
257+
assert.strictEqual(firstWatcher, secondWatcher);
258+
} finally {
259+
// Always clean up watchers
260+
watcher.watchers.forEach((w) => w.close());
261+
watcher.watchers.clear();
262+
watcher.removeAllListeners();
263+
cleanup(targetPath);
264+
}
265+
});
266+
267+
test('Immediate timeout (timeout: 0)', async () => {
268+
const targetPath = path.join(dir, 'test/example6');
269+
fs.mkdirSync(targetPath);
270+
271+
const watcher = new metawatch.DirectoryWatcher({ timeout: 0 });
272+
watcher.watch(targetPath);
273+
274+
return new Promise((resolve, reject) => {
275+
const timeout = setTimeout(() => {
276+
watcher.watchers.forEach((w) => w.close());
277+
watcher.watchers.clear();
278+
watcher.removeAllListeners();
279+
cleanup(targetPath);
280+
reject(new Error('Test timeout'));
281+
}, TEST_TIMEOUT);
282+
283+
let eventCount = 0;
284+
285+
watcher.on('change', () => {
286+
eventCount++;
287+
if (eventCount === 2) {
288+
clearTimeout(timeout);
289+
watcher.watchers.forEach((w) => w.close());
290+
watcher.watchers.clear();
291+
watcher.removeAllListeners();
292+
cleanup(targetPath);
293+
resolve();
294+
}
295+
});
296+
297+
// Create two files quickly
298+
setTimeout(() => {
299+
const file1 = path.join(targetPath, 'file1.txt');
300+
const file2 = path.join(targetPath, 'file2.txt');
301+
fs.writeFileSync(file1, 'content1');
302+
fs.writeFileSync(file2, 'content2');
303+
}, WRITE_TIMEOUT);
304+
});
305+
});

0 commit comments

Comments
 (0)