|
| 1 | +/** |
| 2 | + * Test validation behavior |
| 3 | + */ |
| 4 | + |
| 5 | +import { test } from 'node:test' |
| 6 | +import assert from 'node:assert/strict' |
| 7 | +import { unified } from 'unified' |
| 8 | +import remarkParse from 'remark-parse' |
| 9 | +import remarkRehype from 'remark-rehype' |
| 10 | +import rehypeRaw from 'rehype-raw' |
| 11 | +import rehypeStringify from 'rehype-stringify' |
| 12 | +import remarkNotes from '../index.js' |
| 13 | + |
| 14 | +test('remark-notes: invalid note type is ignored (graceful degradation)', async () => { |
| 15 | + const markdown = '> [!warning]\n> This is an invalid note type' |
| 16 | + |
| 17 | + const file = await unified() |
| 18 | + .use(remarkParse) |
| 19 | + .use(remarkNotes) |
| 20 | + .use(remarkRehype, { allowDangerousHtml: true }) |
| 21 | + .use(rehypeRaw) |
| 22 | + .use(rehypeStringify) |
| 23 | + .process(markdown) |
| 24 | + |
| 25 | + const output = String(file) |
| 26 | + |
| 27 | + // Should remain as a regular blockquote |
| 28 | + assert.ok(output.includes('<blockquote>'), |
| 29 | + 'Invalid note type should remain as blockquote') |
| 30 | + |
| 31 | + // Should NOT be transformed into a note |
| 32 | + assert.ok(!output.includes('class="remark-note'), |
| 33 | + 'Invalid note type should not be transformed into a note') |
| 34 | + |
| 35 | + // Should still contain the original marker |
| 36 | + assert.ok(output.includes('[!warning]'), |
| 37 | + 'Original marker should be preserved for invalid types') |
| 38 | +}) |
| 39 | + |
| 40 | +test('remark-notes: valid note types are transformed', async () => { |
| 41 | + const validTypes = ['note', 'tip', 'important', 'quote', 'bonus'] |
| 42 | + |
| 43 | + for (const type of validTypes) { |
| 44 | + const markdown = `> [!${type}]\n> Test content` |
| 45 | + |
| 46 | + const file = await unified() |
| 47 | + .use(remarkParse) |
| 48 | + .use(remarkNotes) |
| 49 | + .use(remarkRehype, { allowDangerousHtml: true }) |
| 50 | + .use(rehypeRaw) |
| 51 | + .use(rehypeStringify) |
| 52 | + .process(markdown) |
| 53 | + |
| 54 | + const output = String(file) |
| 55 | + |
| 56 | + // Should be transformed into a note |
| 57 | + assert.ok(output.includes(`class="remark-note remark-note-${type}"`), |
| 58 | + `Valid type '${type}' should be transformed into a note`) |
| 59 | + |
| 60 | + // Should NOT remain as blockquote with marker |
| 61 | + assert.ok(!output.includes(`[!${type}]`), |
| 62 | + `Marker should be removed for valid type '${type}'`) |
| 63 | + } |
| 64 | +}) |
| 65 | + |
| 66 | +test('remark-notes: case insensitive note type matching', async () => { |
| 67 | + const variations = ['TIP', 'Tip', 'tIp', 'tiP'] |
| 68 | + |
| 69 | + for (const variant of variations) { |
| 70 | + const markdown = `> [!${variant}]\n> Test content` |
| 71 | + |
| 72 | + const file = await unified() |
| 73 | + .use(remarkParse) |
| 74 | + .use(remarkNotes) |
| 75 | + .use(remarkRehype, { allowDangerousHtml: true }) |
| 76 | + .use(rehypeRaw) |
| 77 | + .use(rehypeStringify) |
| 78 | + .process(markdown) |
| 79 | + |
| 80 | + const output = String(file) |
| 81 | + |
| 82 | + // Should be transformed (case insensitive) |
| 83 | + assert.ok(output.includes('class="remark-note remark-note-tip"'), |
| 84 | + `Case variant '${variant}' should be recognized as valid`) |
| 85 | + } |
| 86 | +}) |
| 87 | + |
| 88 | +test('remark-notes: multiple notes with mixed valid and invalid types', async () => { |
| 89 | + const markdown = ` |
| 90 | +> [!note] |
| 91 | +> Valid note |
| 92 | +
|
| 93 | +> [!warning] |
| 94 | +> Invalid type |
| 95 | +
|
| 96 | +> [!tip] |
| 97 | +> Another valid note |
| 98 | +` |
| 99 | + |
| 100 | + const file = await unified() |
| 101 | + .use(remarkParse) |
| 102 | + .use(remarkNotes) |
| 103 | + .use(remarkRehype, { allowDangerousHtml: true }) |
| 104 | + .use(rehypeRaw) |
| 105 | + .use(rehypeStringify) |
| 106 | + .process(markdown) |
| 107 | + |
| 108 | + const output = String(file) |
| 109 | + |
| 110 | + // Valid notes should be transformed |
| 111 | + assert.ok(output.includes('class="remark-note remark-note-note"'), |
| 112 | + 'First valid note should be transformed') |
| 113 | + assert.ok(output.includes('class="remark-note remark-note-tip"'), |
| 114 | + 'Second valid note should be transformed') |
| 115 | + |
| 116 | + // Invalid note should remain as blockquote |
| 117 | + assert.ok(output.includes('[!warning]'), |
| 118 | + 'Invalid note marker should be preserved') |
| 119 | + |
| 120 | + // Count blockquotes (should have 1 for the invalid type) |
| 121 | + const blockquoteMatches = output.match(/<blockquote>/g) |
| 122 | + assert.ok(blockquoteMatches && blockquoteMatches.length >= 1, |
| 123 | + 'At least one blockquote should remain for invalid type') |
| 124 | +}) |
| 125 | + |
| 126 | +test('remark-notes: typos in note types are not transformed', async () => { |
| 127 | + const typos = ['notte', 'tipp', 'importnt', 'qoute', 'bouns'] |
| 128 | + |
| 129 | + for (const typo of typos) { |
| 130 | + const markdown = `> [!${typo}]\n> Test content` |
| 131 | + |
| 132 | + const file = await unified() |
| 133 | + .use(remarkParse) |
| 134 | + .use(remarkNotes) |
| 135 | + .use(remarkRehype, { allowDangerousHtml: true }) |
| 136 | + .use(rehypeRaw) |
| 137 | + .use(rehypeStringify) |
| 138 | + .process(markdown) |
| 139 | + |
| 140 | + const output = String(file) |
| 141 | + |
| 142 | + // Should remain as blockquote with marker |
| 143 | + assert.ok(output.includes(`[!${typo}]`), |
| 144 | + `Typo '${typo}' should remain as blockquote`) |
| 145 | + |
| 146 | + // Should NOT be transformed |
| 147 | + assert.ok(!output.includes('class="remark-note'), |
| 148 | + `Typo '${typo}' should not be transformed`) |
| 149 | + } |
| 150 | +}) |
| 151 | + |
| 152 | +console.log('All validation tests completed!') |
0 commit comments