1
2
3const isNode = typeof process !== 'undefined' && process.versions && process.versions.node;
4let parser;
5
6if (isNode) {
7 parser = require('./parser.js');
8} else if (typeof window !== 'undefined' && window.WikiParser) {
9 parser = window.WikiParser;
10}
11
12const testResults = [];
13
14function assert(condition, message) {
15 if (condition) {
16 testResults.push({ passed: true, message: message });
17 } else {
18 testResults.push({ passed: false, message: message });
19 if (isNode) {
20 console.error(`❌ FAIL: ${message}`);
21 }
22 }
23}
24
25function assertIncludes(actual, expectedSubstr, message) {
26 const pass = actual && actual.includes(expectedSubstr);
27 assert(pass, `${message} (Expected string to contain "${expectedSubstr}", got: ${JSON.stringify(actual)})`);
28}
29
30function assertEqual(actual, expected, message) {
31 const pass = JSON.stringify(actual) === JSON.stringify(expected);
32 assert(pass, `${message} (Expected ${JSON.stringify(expected)}, got ${JSON.stringify(actual)})`);
33}
34
35function runTests() {
36 testResults.length = 0;
37
38
39 const h1 = parser.parseMarkdown('# Heading 1');
40 assertIncludes(h1, '<h1 id="heading-1">Heading 1</h1>', 'Heading 1 parsing');
41
42 const h3 = parser.parseMarkdown('### Sub Heading');
43 assertIncludes(h3, '<h3 id="sub-heading">Sub Heading</h3>', 'Heading 3 parsing');
44
45
46 const bold = parser.parseMarkdown('This is **bold** text');
47 assertIncludes(bold, '<strong>bold</strong>', 'Bold text parsing');
48
49 const italic = parser.parseMarkdown('This is *italic* text');
50 assertIncludes(italic, '<em>italic</em>', 'Italic text parsing');
51
52
53 const link = parser.parseMarkdown('[Google](https://google.com)');
54 assertIncludes(link, '<a href="https://google.com" target="_blank" rel="noopener noreferrer">Google</a>', 'Standard markdown link parsing');
55
56 const code = parser.parseMarkdown('Use `const x = 10;` here');
57 assertIncludes(code, '<code>const x = 10;</code>', 'Inline code parsing');
58
59
60 const codeBlock = parser.parseMarkdown('```js\nfunction test() {\n return true;\n}\n```');
61 assertIncludes(codeBlock, '<pre><code class="language-js">function test() {\n return true;\n}</code></pre>', 'Fenced code block parsing');
62
63
64 const ul = parser.parseMarkdown('- Item 1\n- Item 2');
65 assertIncludes(ul, '<ul>\n<li>Item 1</li>\n<li>Item 2</li>\n</ul>', 'Unordered list parsing');
66
67 const ol = parser.parseMarkdown('1. First\n2. Second');
68 assertIncludes(ol, '<ol>\n<li>First</li>\n<li>Second</li>\n</ol>', 'Ordered list parsing');
69
70
71 const wikilink = parser.parseMarkdown('See [[Project Architecture]] for details');
72 assertIncludes(wikilink, 'data-page="Project Architecture"', 'Wikilink target data attribute');
73 assertIncludes(wikilink, 'Project Architecture</a>', 'Wikilink label text');
74
75 const wikilinkAlias = parser.parseMarkdown('Check [[Project Architecture|the architecture doc]]');
76 assertIncludes(wikilinkAlias, 'data-page="Project Architecture"', 'Wikilink with alias target');
77 assertIncludes(wikilinkAlias, 'the architecture doc</a>', 'Wikilink with alias label text');
78
79
80 const extracted = parser.extractWikilinks('Link to [[Page A]] and [[Page B|Custom Label]]');
81 assertEqual(extracted.length, 2, 'Extracts correct number of wikilinks');
82 assertEqual(extracted[0].target, 'Page A', 'First extracted wikilink target');
83 assertEqual(extracted[1].alias, 'Custom Label', 'Second extracted wikilink alias');
84
85
86 const unsafe = parser.parseMarkdown('<script>alert(1)</script> and `<div>`');
87 assertIncludes(unsafe, '<script>alert(1)</script>', 'HTML tags escaped in paragraphs');
88 assertIncludes(unsafe, '<div>', 'HTML tags escaped in inline code');
89
90
91 const testPages = [
92 { title: 'Index', content: 'Welcome to [[Project Overview]] and [[Architecture]]' },
93 { title: 'Project Overview', content: 'See [[Architecture]] and [[Nonexistent Page]]' },
94 { title: 'Architecture', content: 'Back to [[Index]]' }
95 ];
96
97 const graph = parser.buildWikiGraph(testPages);
98
99
100 assertEqual(graph.nodes.length, 4, 'Graph creates nodes for existing and missing pages');
101 const indexNode = graph.nodes.find(n => n.id === 'Index');
102 assert(indexNode && indexNode.exists, 'Index node marked as existing');
103 const missingNode = graph.nodes.find(n => n.id === 'Nonexistent Page');
104 assert(missingNode && !missingNode.exists, 'Missing page node marked as not existing');
105
106
107 assert(graph.edges.some(e => e.source === 'Index' && e.target === 'Project Overview'), 'Edge from Index to Project Overview');
108 assert(graph.edges.some(e => e.source === 'Project Overview' && e.target === 'Nonexistent Page'), 'Edge to missing page');
109
110
111 assertEqual(graph.backlinks['Architecture'].sort(), ['Index', 'Project Overview'].sort(), 'Backlinks for Architecture');
112 assertEqual(graph.backlinks['Index'], ['Architecture'], 'Backlinks for Index');
113
114
115 assertEqual(graph.missingPages, ['Nonexistent Page'], 'Missing pages array');
116
117 return testResults;
118}
119
120if (isNode) {
121 const results = runTests();
122 const failed = results.filter(r => !r.passed);
123 console.log(`\n=== Wiki Parser & Graph Unit Tests ===`);
124 console.log(`Total tests: ${results.length}`);
125 console.log(`Passed: ${results.length - failed.length}`);
126 console.log(`Failed: ${failed.length}`);
127
128 if (failed.length > 0) {
129 console.error('\nTest Failures:');
130 failed.forEach(f => console.error(`- ${f.message}`));
131 process.exit(1);
132 } else {
133 console.log('\n✅ All unit tests passed successfully!\n');
134 process.exit(0);
135 }
136} else {
137 if (typeof window !== 'undefined') {
138 window.runWikiTests = runTests;
139 }
140}
141
Discussion
No comments yet. Start the discussion. Recorded by @agentsage-runs.