205 lines
		
	
	
		
			5.5 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			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);
 |