170 lines
4.9 KiB
TypeScript
170 lines
4.9 KiB
TypeScript
// Tests fuer startInboxWatcher
|
|
// Bonus 21: Watcher-Edge-Cases
|
|
|
|
import { describe, it, expect, afterEach } from 'vitest';
|
|
import { mkdtempSync, mkdirSync, writeFileSync } from 'node:fs';
|
|
import { tmpdir } from 'node:os';
|
|
import { join } from 'node:path';
|
|
import { startInboxWatcher, type ActiveWatcher } from '../src/watcher.js';
|
|
|
|
const watchers: ActiveWatcher[] = [];
|
|
afterEach(async () => {
|
|
for (const w of watchers) await w.close();
|
|
watchers.length = 0;
|
|
});
|
|
|
|
function setupInbox(): string {
|
|
const dir = mkdtempSync(join(tmpdir(), 'mindomat-watcher-test-'));
|
|
// Inbox-Struktur
|
|
for (const d of ['00_Inbox', '00_Inbox/Verarbeitet', '00_Inbox/Problemfaelle']) {
|
|
mkdirSync(join(dir, d), { recursive: true });
|
|
}
|
|
return dir;
|
|
}
|
|
|
|
describe('startInboxWatcher', () => {
|
|
it('startet und schliesst sauber', async () => {
|
|
const inbox = setupInbox();
|
|
const processed: string[] = [];
|
|
const watcher = await startInboxWatcher(inbox, {
|
|
processNote: async (p) => {
|
|
processed.push(p);
|
|
},
|
|
debounceMs: 50,
|
|
});
|
|
watchers.push(watcher);
|
|
expect(watcher).toBeDefined();
|
|
expect(typeof watcher.close).toBe('function');
|
|
await watcher.close();
|
|
});
|
|
|
|
it('verarbeitet neue .md-Dateien', async () => {
|
|
const inbox = setupInbox();
|
|
const processed: string[] = [];
|
|
const watcher = await startInboxWatcher(inbox, {
|
|
processNote: async (p) => {
|
|
processed.push(p);
|
|
},
|
|
debounceMs: 100,
|
|
});
|
|
watchers.push(watcher);
|
|
|
|
// Warte, bis Watcher bereit ist
|
|
await new Promise((r) => setTimeout(r, 500));
|
|
|
|
// Schreibe neue .md-Datei
|
|
const notePath = join(inbox, '00_Inbox', 'test.md');
|
|
writeFileSync(notePath, '# Test');
|
|
|
|
// Warte auf Debounce + Verarbeitung
|
|
await new Promise((r) => setTimeout(r, 1500));
|
|
|
|
expect(processed.length).toBe(1);
|
|
expect(processed[0]).toContain('test.md');
|
|
});
|
|
|
|
it('ignoriert Nicht-.md-Dateien', async () => {
|
|
const inbox = setupInbox();
|
|
const processed: string[] = [];
|
|
const watcher = await startInboxWatcher(inbox, {
|
|
processNote: async (p) => {
|
|
processed.push(p);
|
|
},
|
|
debounceMs: 100,
|
|
});
|
|
watchers.push(watcher);
|
|
|
|
await new Promise((r) => setTimeout(r, 500));
|
|
|
|
// Schreibe .txt-Datei (sollte ignoriert werden)
|
|
writeFileSync(join(inbox, '00_Inbox', 'test.txt'), 'not markdown');
|
|
await new Promise((r) => setTimeout(r, 800));
|
|
|
|
expect(processed.length).toBe(0);
|
|
});
|
|
|
|
it('ignoriert Verarbeitet/-Unterordner', async () => {
|
|
const inbox = setupInbox();
|
|
const processed: string[] = [];
|
|
const watcher = await startInboxWatcher(inbox, {
|
|
processNote: async (p) => {
|
|
processed.push(p);
|
|
},
|
|
debounceMs: 100,
|
|
});
|
|
watchers.push(watcher);
|
|
|
|
await new Promise((r) => setTimeout(r, 500));
|
|
|
|
// In Verarbeitet/ schreiben (sollte ignoriert werden)
|
|
writeFileSync(join(inbox, '00_Inbox', 'Verarbeitet', 'old.md'), '# alt');
|
|
await new Promise((r) => setTimeout(r, 800));
|
|
|
|
expect(processed.length).toBe(0);
|
|
});
|
|
|
|
it('Debounce: mehrere schnelle Writes -> eine Verarbeitung', async () => {
|
|
const inbox = setupInbox();
|
|
const processed: string[] = [];
|
|
const watcher = await startInboxWatcher(inbox, {
|
|
processNote: async (p) => {
|
|
processed.push(p);
|
|
},
|
|
debounceMs: 500,
|
|
});
|
|
watchers.push(watcher);
|
|
|
|
await new Promise((r) => setTimeout(r, 500));
|
|
|
|
// 3 schnelle Writes
|
|
for (let i = 0; i < 3; i++) {
|
|
writeFileSync(join(inbox, '00_Inbox', `note-${i}.md`), `# Note ${i}`);
|
|
await new Promise((r) => setTimeout(r, 50));
|
|
}
|
|
// Warte auf Debounce
|
|
await new Promise((r) => setTimeout(r, 1500));
|
|
|
|
// Alle 3 Notizen sollten verarbeitet sein
|
|
expect(processed.length).toBeGreaterThanOrEqual(1);
|
|
expect(processed.length).toBeLessThanOrEqual(3);
|
|
});
|
|
|
|
it('Fehler in processNote werden via onError-Callback gemeldet', async () => {
|
|
const inbox = setupInbox();
|
|
const errors: Array<{ err: Error; path: string }> = [];
|
|
const watcher = await startInboxWatcher(inbox, {
|
|
processNote: async () => {
|
|
throw new Error('Test-Fehler');
|
|
},
|
|
onError: (err, path) => {
|
|
errors.push({ err, path });
|
|
},
|
|
debounceMs: 100,
|
|
});
|
|
watchers.push(watcher);
|
|
|
|
await new Promise((r) => setTimeout(r, 500));
|
|
|
|
writeFileSync(join(inbox, '00_Inbox', 'fail.md'), '# fail');
|
|
await new Promise((r) => setTimeout(r, 1500));
|
|
|
|
expect(errors.length).toBeGreaterThanOrEqual(1);
|
|
expect(errors[0].err.message).toBe('Test-Fehler');
|
|
expect(errors[0].path).toContain('fail.md');
|
|
});
|
|
|
|
it('schliesst sauber ohne haengende Prozesse', async () => {
|
|
const inbox = setupInbox();
|
|
const watcher = await startInboxWatcher(inbox, {
|
|
processNote: async () => {},
|
|
debounceMs: 50,
|
|
});
|
|
|
|
// Vor close: Watcher aktiv
|
|
expect(watcher).toBeDefined();
|
|
|
|
// Close sollte schnell gehen und keine Errors werfen
|
|
await expect(watcher.close()).resolves.not.toThrow();
|
|
});
|
|
});
|