222 lines
6.8 KiB
TypeScript
222 lines
6.8 KiB
TypeScript
// Tests fuer NotesApi (Vite-Plugin-Logik)
|
|
// Phase 4.3
|
|
|
|
import { describe, it, expect, afterEach } from 'vitest';
|
|
import { mkdtempSync, mkdirSync, writeFileSync, rmSync, readFileSync, existsSync } from 'node:fs';
|
|
import { tmpdir } from 'node:os';
|
|
import { join } from 'node:path';
|
|
import { NotesApi } from '../src/notes-api-server.js';
|
|
|
|
const vaults: string[] = [];
|
|
afterEach(() => {
|
|
for (const v of vaults) rmSync(v, { recursive: true, force: true });
|
|
});
|
|
|
|
function setupVault(files: Record<string, string> = {}): string {
|
|
const vault = mkdtempSync(join(tmpdir(), 'mindomat-notes-api-'));
|
|
for (const d of [
|
|
'00_Inbox',
|
|
'00_Inbox/Verarbeitet',
|
|
'00_Inbox/Problemfaelle',
|
|
'01_Daily',
|
|
'10_Wiki',
|
|
'10_Wiki/Seiten',
|
|
'20_Projekte',
|
|
'90_Templates',
|
|
'99_System',
|
|
'99_System/Skripte',
|
|
'99_System/Logs',
|
|
'99_System/Cache',
|
|
]) {
|
|
mkdirSync(join(vault, d), { recursive: true });
|
|
}
|
|
for (const [rel, content] of Object.entries(files)) {
|
|
const full = join(vault, rel);
|
|
mkdirSync(join(full, '..'), { recursive: true });
|
|
writeFileSync(full, content);
|
|
}
|
|
return vault;
|
|
}
|
|
|
|
describe('NotesApi.listNotes', () => {
|
|
it('leerer Vault: leere Liste', () => {
|
|
const vault = setupVault();
|
|
vaults.push(vault);
|
|
const api = new NotesApi(vault);
|
|
expect(api.listNotes()).toEqual([]);
|
|
});
|
|
|
|
it('Inbox-Notizen werden gelistet', () => {
|
|
const vault = setupVault({
|
|
'00_Inbox/2026-09-05_A.md': '# A',
|
|
'00_Inbox/2026-09-05_B.md': '# B',
|
|
});
|
|
vaults.push(vault);
|
|
const api = new NotesApi(vault);
|
|
const notes = api.listNotes();
|
|
expect(notes).toContain('00_Inbox/2026-09-05_A.md');
|
|
expect(notes).toContain('00_Inbox/2026-09-05_B.md');
|
|
expect(notes.length).toBe(2);
|
|
});
|
|
|
|
it('Verarbeitet/-Problemfaelle werden NICHT gelistet (Pfad-Filter)', () => {
|
|
const vault = setupVault({
|
|
'00_Inbox/2026-09-05_A.md': '# A',
|
|
'00_Inbox/Verarbeitet/2026-09-05_B.md': '# B',
|
|
'00_Inbox/Problemfaelle/2026-09-05_C.md': '# C',
|
|
});
|
|
vaults.push(vault);
|
|
const api = new NotesApi(vault);
|
|
const notes = api.listNotes();
|
|
// B ist in einem Unterordner, der NICHT in der Top-Level-Liste ist
|
|
// Die Implementation listet nur Top-Level-Files in den 4 Verzeichnissen
|
|
expect(notes).toContain('00_Inbox/2026-09-05_A.md');
|
|
expect(notes.length).toBe(1);
|
|
});
|
|
|
|
it('Forward-Slashes in Pfaden (Windows-Kompatibilitaet)', () => {
|
|
const vault = setupVault({
|
|
'10_Wiki/Seiten/Wiki_A.md': '# Wiki',
|
|
});
|
|
vaults.push(vault);
|
|
const api = new NotesApi(vault);
|
|
const notes = api.listNotes();
|
|
expect(notes[0]).toBe('10_Wiki/Seiten/Wiki_A.md');
|
|
expect(notes[0]).not.toContain('\\');
|
|
});
|
|
});
|
|
|
|
describe('NotesApi.getNote', () => {
|
|
it('gibt null zurueck fuer nicht-existente Notiz', () => {
|
|
const vault = setupVault();
|
|
vaults.push(vault);
|
|
const api = new NotesApi(vault);
|
|
expect(api.getNote('00_Inbox/nicht-da.md')).toBeNull();
|
|
});
|
|
|
|
it('liest existierende Notiz mit Frontmatter', () => {
|
|
const vault = setupVault({
|
|
'00_Inbox/2026-09-05_Test.md': `---
|
|
title: Test
|
|
created: 2026-09-05
|
|
tags: [test]
|
|
---
|
|
|
|
# Inhalt`,
|
|
});
|
|
vaults.push(vault);
|
|
const api = new NotesApi(vault);
|
|
const note = api.getNote('00_Inbox/2026-09-05_Test.md');
|
|
expect(note).not.toBeNull();
|
|
expect(note!.content).toContain('# Inhalt');
|
|
expect(note!.frontmatter.title).toBe('Test');
|
|
expect(note!.frontmatter.tags).toEqual(['test']);
|
|
expect(note!.lastModified).toBeTruthy();
|
|
});
|
|
});
|
|
|
|
describe('NotesApi.saveNote', () => {
|
|
it('schreibt neue Notiz und liest sie zurueck', () => {
|
|
const vault = setupVault();
|
|
vaults.push(vault);
|
|
const api = new NotesApi(vault);
|
|
const id = '01_Daily/2026-09-05_New.md';
|
|
const content = `---
|
|
title: Neu
|
|
created: 2026-09-05
|
|
---
|
|
|
|
# Inhalt`;
|
|
const result = api.saveNote(id, content);
|
|
expect(result.id).toBe(id);
|
|
expect(result.frontmatter.title).toBe('Neu');
|
|
expect(existsSync(join(vault, id))).toBe(true);
|
|
});
|
|
|
|
it('ueberschreibt existierende Notiz', () => {
|
|
const vault = setupVault({
|
|
'00_Inbox/2026-09-05_Update.md': '# alt',
|
|
});
|
|
vaults.push(vault);
|
|
const api = new NotesApi(vault);
|
|
const id = '00_Inbox/2026-09-05_Update.md';
|
|
const newContent = '# neu';
|
|
api.saveNote(id, newContent);
|
|
const readBack = readFileSync(join(vault, id), 'utf-8');
|
|
expect(readBack).toBe(newContent);
|
|
});
|
|
|
|
it('erstellt Parent-Verzeichnisse automatisch', () => {
|
|
const vault = setupVault();
|
|
vaults.push(vault);
|
|
const api = new NotesApi(vault);
|
|
const id = '20_Projekte/Sub/New.md';
|
|
api.saveNote(id, '# Inhalt');
|
|
expect(existsSync(join(vault, id))).toBe(true);
|
|
});
|
|
});
|
|
|
|
describe('NotesApi End-to-End', () => {
|
|
it('list -> get -> save -> get roundtrip', () => {
|
|
const vault = setupVault();
|
|
vaults.push(vault);
|
|
const api = new NotesApi(vault);
|
|
|
|
// 1. Liste ist leer
|
|
expect(api.listNotes()).toEqual([]);
|
|
|
|
// 2. Speichere Notiz
|
|
const id = '10_Wiki/Seiten/Wiki_X.md';
|
|
api.saveNote(id, '---\ntitle: Wiki X\n---\n\n# Wiki X');
|
|
|
|
// 3. Liste enthaelt die Notiz
|
|
expect(api.listNotes()).toContain(id);
|
|
|
|
// 4. getNote liefert die Notiz
|
|
const note = api.getNote(id);
|
|
expect(note).not.toBeNull();
|
|
expect(note!.frontmatter.title).toBe('Wiki X');
|
|
|
|
// 5. Update Notiz
|
|
api.saveNote(id, '---\ntitle: Wiki X (updated)\n---\n\n# Updated');
|
|
const updated = api.getNote(id);
|
|
expect(updated!.frontmatter.title).toBe('Wiki X (updated)');
|
|
expect(updated!.content).toContain('# Updated');
|
|
});
|
|
|
|
it('listNotesWithMetadata liefert Notizen mit Titeln, Tags und Ordnern', () => {
|
|
const vault = setupVault({
|
|
'00_Inbox/2026-09-08_Idee.md': '---\ntitle: Coole Idee\ntags: [app, mobile]\n---\n\n# Coole Idee\n\nDas ist der Snippet-Text.',
|
|
});
|
|
vaults.push(vault);
|
|
const api = new NotesApi(vault);
|
|
const items = api.listNotesWithMetadata();
|
|
expect(items.length).toBe(1);
|
|
expect(items[0].title).toBe('Coole Idee');
|
|
expect(items[0].folder).toBe('00_Inbox');
|
|
expect(items[0].tags).toEqual(['app', 'mobile']);
|
|
expect(items[0].snippet).toContain('Das ist der Snippet-Text.');
|
|
});
|
|
|
|
it('captureNote legt Notiz in 00_Inbox mit Frontmatter an', () => {
|
|
const vault = setupVault();
|
|
vaults.push(vault);
|
|
const api = new NotesApi(vault);
|
|
const result = api.captureNote({
|
|
text: 'Meeting mit Anna morgen um 10 Uhr',
|
|
title: 'Meeting Anna',
|
|
tags: ['meeting', 'arbeit'],
|
|
});
|
|
|
|
expect(result.ok).toBe(true);
|
|
expect(result.noteId).toMatch(/^00_Inbox\/\d{4}-\d{2}-\d{2}_Meeting_Anna_\d+\.md$/);
|
|
expect(existsSync(join(vault, result.noteId))).toBe(true);
|
|
|
|
const saved = api.getNote(result.noteId);
|
|
expect(saved).not.toBeNull();
|
|
expect(saved!.frontmatter.title).toBe('Meeting Anna');
|
|
expect(saved!.content).toContain('Meeting mit Anna morgen um 10 Uhr');
|
|
});
|
|
});
|
|
|