ObsiViewer/server/excalidraw-obsidian.test.mjs

205 lines
5.5 KiB
JavaScript

#!/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" & <test>' }
],
appState: {},
files: {}
};
const md = toObsidianExcalidrawMd(sceneWithSpecialChars);
const parsed = parseObsidianExcalidrawMd(md);
assert.ok(parsed);
assert.strictEqual(parsed.elements[0].text, 'Hello "World" & <test>');
});
// Summary
console.log('\n━'.repeat(30));
console.log(`✅ Passed: ${passed}`);
console.log(`❌ Failed: ${failed}`);
console.log('━'.repeat(30));
process.exit(failed > 0 ? 1 : 0);