#!/usr/bin/env node /** * Unit tests for Excalidraw Obsidian format utilities * Run with: node server/excalidraw-obsidian.test.mjs */ import assert from 'assert'; import { parseObsidianExcalidrawMd, parseFlatJson, toObsidianExcalidrawMd, extractFrontMatter, parseExcalidrawAny, isValidExcalidrawScene } from './excalidraw-obsidian.mjs'; let passed = 0; let failed = 0; function test(name, fn) { try { fn(); console.log(`โœ… ${name}`); passed++; } catch (error) { console.error(`โŒ ${name}`); console.error(` ${error.message}`); failed++; } } // Sample data const sampleScene = { elements: [ { id: '1', type: 'rectangle', x: 100, y: 100, width: 200, height: 100 } ], appState: { viewBackgroundColor: '#ffffff' }, files: {} }; const sampleFrontMatter = `--- excalidraw-plugin: parsed tags: [excalidraw] ---`; console.log('๐Ÿงช Running Excalidraw Obsidian Format Tests\n'); // Test: extractFrontMatter test('extractFrontMatter - extracts front matter', () => { const md = `--- excalidraw-plugin: parsed --- Content here`; const result = extractFrontMatter(md); assert.ok(result); assert.ok(result.includes('excalidraw-plugin')); }); test('extractFrontMatter - returns null when no front matter', () => { const md = 'Just some content'; const result = extractFrontMatter(md); assert.strictEqual(result, null); }); // Test: toObsidianExcalidrawMd test('toObsidianExcalidrawMd - creates valid markdown', () => { const md = toObsidianExcalidrawMd(sampleScene); assert.ok(md.includes('---')); assert.ok(md.includes('excalidraw-plugin')); assert.ok(md.includes('```compressed-json')); assert.ok(md.includes('# Excalidraw Data')); }); test('toObsidianExcalidrawMd - preserves existing front matter', () => { const customFrontMatter = `--- excalidraw-plugin: parsed tags: [custom, test] ---`; const md = toObsidianExcalidrawMd(sampleScene, customFrontMatter); assert.ok(md.includes('tags: [custom, test]')); }); // Test: parseObsidianExcalidrawMd round-trip test('parseObsidianExcalidrawMd - round-trip conversion', () => { const md = toObsidianExcalidrawMd(sampleScene); const parsed = parseObsidianExcalidrawMd(md); assert.ok(parsed); assert.ok(Array.isArray(parsed.elements)); assert.strictEqual(parsed.elements.length, 1); assert.strictEqual(parsed.elements[0].type, 'rectangle'); }); // Test: parseFlatJson test('parseFlatJson - parses valid JSON', () => { const json = JSON.stringify(sampleScene); const parsed = parseFlatJson(json); assert.ok(parsed); assert.ok(Array.isArray(parsed.elements)); assert.strictEqual(parsed.elements.length, 1); }); test('parseFlatJson - returns null for invalid JSON', () => { const parsed = parseFlatJson('not valid json'); assert.strictEqual(parsed, null); }); test('parseFlatJson - returns null for JSON without elements', () => { const parsed = parseFlatJson('{"foo": "bar"}'); assert.strictEqual(parsed, null); }); // Test: parseExcalidrawAny test('parseExcalidrawAny - parses Obsidian format', () => { const md = toObsidianExcalidrawMd(sampleScene); const parsed = parseExcalidrawAny(md); assert.ok(parsed); assert.ok(Array.isArray(parsed.elements)); }); test('parseExcalidrawAny - parses flat JSON', () => { const json = JSON.stringify(sampleScene); const parsed = parseExcalidrawAny(json); assert.ok(parsed); assert.ok(Array.isArray(parsed.elements)); }); test('parseExcalidrawAny - returns null for invalid content', () => { const parsed = parseExcalidrawAny('invalid content'); assert.strictEqual(parsed, null); }); // Test: isValidExcalidrawScene test('isValidExcalidrawScene - validates correct structure', () => { assert.strictEqual(isValidExcalidrawScene(sampleScene), true); }); test('isValidExcalidrawScene - rejects invalid structure', () => { assert.strictEqual(isValidExcalidrawScene({}), false); assert.strictEqual(isValidExcalidrawScene({ elements: 'not an array' }), false); assert.strictEqual(isValidExcalidrawScene(null), false); }); // Test: Empty scene handling test('toObsidianExcalidrawMd - handles empty scene', () => { const emptyScene = { elements: [], appState: {}, files: {} }; const md = toObsidianExcalidrawMd(emptyScene); const parsed = parseObsidianExcalidrawMd(md); assert.ok(parsed); assert.ok(Array.isArray(parsed.elements)); assert.strictEqual(parsed.elements.length, 0); }); // Test: Large scene handling test('toObsidianExcalidrawMd - handles large scene', () => { const largeScene = { elements: Array.from({ length: 100 }, (_, i) => ({ id: `${i}`, type: 'rectangle', x: i * 10, y: i * 10, width: 50, height: 50 })), appState: {}, files: {} }; const md = toObsidianExcalidrawMd(largeScene); const parsed = parseObsidianExcalidrawMd(md); assert.ok(parsed); assert.strictEqual(parsed.elements.length, 100); }); // Test: Special characters in scene test('toObsidianExcalidrawMd - handles special characters', () => { const sceneWithSpecialChars = { elements: [ { id: '1', type: 'text', text: 'Hello "World" & ' } ], appState: {}, files: {} }; const md = toObsidianExcalidrawMd(sceneWithSpecialChars); const parsed = parseObsidianExcalidrawMd(md); assert.ok(parsed); assert.strictEqual(parsed.elements[0].text, 'Hello "World" & '); }); // Summary console.log('\nโ”'.repeat(30)); console.log(`โœ… Passed: ${passed}`); console.log(`โŒ Failed: ${failed}`); console.log('โ”'.repeat(30)); process.exit(failed > 0 ? 1 : 0);