Skip to content

Commit 686131e

Browse files
committed
add more tests
Signed-off-by: rishichawda <[email protected]>
1 parent 0e3e113 commit 686131e

File tree

2 files changed

+371
-1
lines changed

2 files changed

+371
-1
lines changed

__tests__/edge-cases.ts

Lines changed: 369 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,369 @@
1+
/**
2+
* Test edge case handling
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: empty note block (only marker)', async () => {
15+
const markdown = '> [!note]'
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 still transform into a note (with empty content)
28+
assert.ok(output.includes('class="remark-note remark-note-note"'),
29+
'Empty note should still be transformed')
30+
31+
// Should have the note structure
32+
assert.ok(output.includes('remark-note-header'),
33+
'Empty note should have header')
34+
assert.ok(output.includes('remark-note-content'),
35+
'Empty note should have content container')
36+
})
37+
38+
test('remark-notes: note with only marker and whitespace', async () => {
39+
const markdown = '> [!tip]\n> \n> '
40+
41+
const file = await unified()
42+
.use(remarkParse)
43+
.use(remarkNotes)
44+
.use(remarkRehype, { allowDangerousHtml: true })
45+
.use(rehypeRaw)
46+
.use(rehypeStringify)
47+
.process(markdown)
48+
49+
const output = String(file)
50+
51+
// Should transform with empty/minimal content
52+
assert.ok(output.includes('class="remark-note remark-note-tip"'),
53+
'Note with only whitespace should be transformed')
54+
})
55+
56+
test('remark-notes: special HTML characters in content', async () => {
57+
const markdown = '> [!note]\n> Content with <script>alert("XSS")</script> & special chars < > " \''
58+
59+
const file = await unified()
60+
.use(remarkParse)
61+
.use(remarkNotes)
62+
.use(remarkRehype, { allowDangerousHtml: true })
63+
.use(rehypeRaw)
64+
.use(rehypeStringify)
65+
.process(markdown)
66+
67+
const output = String(file)
68+
69+
// Should escape or properly handle special characters
70+
// The remark/rehype pipeline should handle escaping automatically
71+
assert.ok(output.includes('remark-note-note'),
72+
'Note with special chars should be transformed')
73+
74+
// Verify some form of the content exists (may be escaped)
75+
assert.ok(output.includes('special chars') || output.includes('Content with'),
76+
'Content should be present')
77+
})
78+
79+
test('remark-notes: note with code blocks', async () => {
80+
const markdown = `> [!tip]
81+
> Here's some code:
82+
>
83+
> \`\`\`javascript
84+
> const x = 42;
85+
> console.log(x);
86+
> \`\`\`
87+
>
88+
> End of tip`
89+
90+
const file = await unified()
91+
.use(remarkParse)
92+
.use(remarkNotes)
93+
.use(remarkRehype, { allowDangerousHtml: true })
94+
.use(rehypeRaw)
95+
.use(rehypeStringify)
96+
.process(markdown)
97+
98+
const output = String(file)
99+
100+
// Should transform and preserve code block
101+
assert.ok(output.includes('class="remark-note remark-note-tip"'),
102+
'Note with code block should be transformed')
103+
104+
assert.ok(output.includes('<code>') || output.includes('const x'),
105+
'Code block should be preserved')
106+
})
107+
108+
test('remark-notes: note with inline code and formatting', async () => {
109+
const markdown = '> [!important]\n> Use `const` not `var` and **always** use *strict mode*'
110+
111+
const file = await unified()
112+
.use(remarkParse)
113+
.use(remarkNotes)
114+
.use(remarkRehype, { allowDangerousHtml: true })
115+
.use(rehypeRaw)
116+
.use(rehypeStringify)
117+
.process(markdown)
118+
119+
const output = String(file)
120+
121+
// Should preserve inline code and formatting
122+
assert.ok(output.includes('class="remark-note remark-note-important"'),
123+
'Note with inline formatting should be transformed')
124+
125+
assert.ok(output.includes('<code>') && output.includes('const'),
126+
'Inline code should be preserved')
127+
128+
assert.ok(output.includes('<strong>') || output.includes('<em>'),
129+
'Bold/italic formatting should be preserved')
130+
})
131+
132+
test('remark-notes: note with links and images', async () => {
133+
const markdown = '> [!note]\n> Check [the docs](https://example.com) and ![image](test.png)'
134+
135+
const file = await unified()
136+
.use(remarkParse)
137+
.use(remarkNotes)
138+
.use(remarkRehype, { allowDangerousHtml: true })
139+
.use(rehypeRaw)
140+
.use(rehypeStringify)
141+
.process(markdown)
142+
143+
const output = String(file)
144+
145+
// Should preserve links and images
146+
assert.ok(output.includes('class="remark-note remark-note-note"'),
147+
'Note with links/images should be transformed')
148+
149+
assert.ok(output.includes('<a') && output.includes('href="https://example.com"'),
150+
'Links should be preserved')
151+
152+
assert.ok(output.includes('<img') && output.includes('src="test.png"'),
153+
'Images should be preserved')
154+
})
155+
156+
test('remark-notes: note with lists', async () => {
157+
const markdown = `> [!tip]
158+
> Here are some tips:
159+
>
160+
> - First item
161+
> - Second item
162+
> - Third item`
163+
164+
const file = await unified()
165+
.use(remarkParse)
166+
.use(remarkNotes)
167+
.use(remarkRehype, { allowDangerousHtml: true })
168+
.use(rehypeRaw)
169+
.use(rehypeStringify)
170+
.process(markdown)
171+
172+
const output = String(file)
173+
174+
// Should preserve lists
175+
assert.ok(output.includes('class="remark-note remark-note-tip"'),
176+
'Note with lists should be transformed')
177+
178+
assert.ok(output.includes('<ul>') || output.includes('<li>'),
179+
'List structure should be preserved')
180+
181+
assert.ok(output.includes('First item') && output.includes('Second item'),
182+
'List content should be preserved')
183+
})
184+
185+
test('remark-notes: note with blockquote in content', async () => {
186+
const markdown = `> [!quote]
187+
> As someone once said:
188+
>
189+
> > This is a nested quote
190+
> > on multiple lines
191+
>
192+
> End of note`
193+
194+
const file = await unified()
195+
.use(remarkParse)
196+
.use(remarkNotes)
197+
.use(remarkRehype, { allowDangerousHtml: true })
198+
.use(rehypeRaw)
199+
.use(rehypeStringify)
200+
.process(markdown)
201+
202+
const output = String(file)
203+
204+
// Should handle nested blockquotes
205+
assert.ok(output.includes('class="remark-note remark-note-quote"'),
206+
'Note with nested blockquote should be transformed')
207+
208+
// Nested blockquote should be preserved (may be rendered as blockquote)
209+
assert.ok(output.includes('nested quote') || output.includes('This is a'),
210+
'Nested blockquote content should be preserved')
211+
})
212+
213+
test('remark-notes: very long content (performance test)', async () => {
214+
// Generate a note with ~2000 words
215+
const longText = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. '.repeat(250)
216+
const markdown = `> [!note]\n> ${longText}`
217+
218+
const startTime = performance.now()
219+
220+
const file = await unified()
221+
.use(remarkParse)
222+
.use(remarkNotes)
223+
.use(remarkRehype, { allowDangerousHtml: true })
224+
.use(rehypeRaw)
225+
.use(rehypeStringify)
226+
.process(markdown)
227+
228+
const endTime = performance.now()
229+
const processingTime = endTime - startTime
230+
231+
const output = String(file)
232+
233+
// Should handle large content
234+
assert.ok(output.includes('class="remark-note remark-note-note"'),
235+
'Large note should be transformed')
236+
237+
assert.ok(output.includes('Lorem ipsum'),
238+
'Large content should be preserved')
239+
240+
// Performance check - should process in reasonable time (< 1000ms for ~2000 words)
241+
assert.ok(processingTime < 1000,
242+
`Large note processing should be fast (took ${processingTime.toFixed(2)}ms)`)
243+
})
244+
245+
test('remark-notes: whitespace preservation - tabs and spaces', async () => {
246+
// Using explicit tab character
247+
const markdown = '> [!note]\n> Line with\ttabs\tand multiple spaces'
248+
249+
const file = await unified()
250+
.use(remarkParse)
251+
.use(remarkNotes)
252+
.use(remarkRehype, { allowDangerousHtml: true })
253+
.use(rehypeRaw)
254+
.use(rehypeStringify)
255+
.process(markdown)
256+
257+
const output = String(file)
258+
259+
// Should transform
260+
assert.ok(output.includes('class="remark-note remark-note-note"'),
261+
'Note with mixed whitespace should be transformed')
262+
263+
// Content should exist (exact whitespace might be normalized by HTML)
264+
assert.ok(output.includes('Line with') && output.includes('tabs'),
265+
'Content with whitespace should be preserved')
266+
})
267+
268+
test('remark-notes: multiline content with varying indentation', async () => {
269+
const markdown = `> [!important]
270+
> First line
271+
> Indented line
272+
> Double indented
273+
> Back to normal`
274+
275+
const file = await unified()
276+
.use(remarkParse)
277+
.use(remarkNotes)
278+
.use(remarkRehype, { allowDangerousHtml: true })
279+
.use(rehypeRaw)
280+
.use(rehypeStringify)
281+
.process(markdown)
282+
283+
const output = String(file)
284+
285+
// Should transform with preserved content
286+
assert.ok(output.includes('class="remark-note remark-note-important"'),
287+
'Note with varying indentation should be transformed')
288+
289+
assert.ok(output.includes('First line') && output.includes('Indented line'),
290+
'All content lines should be preserved')
291+
})
292+
293+
test('remark-notes: unicode and emoji content', async () => {
294+
const markdown = '> [!tip]\n> 你好 🎉 Testing unicode: café, naïve, 日本語'
295+
296+
const file = await unified()
297+
.use(remarkParse)
298+
.use(remarkNotes)
299+
.use(remarkRehype, { allowDangerousHtml: true })
300+
.use(rehypeRaw)
301+
.use(rehypeStringify)
302+
.process(markdown)
303+
304+
const output = String(file)
305+
306+
// Should handle unicode and emoji
307+
assert.ok(output.includes('class="remark-note remark-note-tip"'),
308+
'Note with unicode should be transformed')
309+
310+
assert.ok(output.includes('你好') || output.includes('Testing'),
311+
'Unicode content should be preserved')
312+
})
313+
314+
test('remark-notes: note with HTML entities', async () => {
315+
const markdown = '> [!note]\n> Use &lt;div&gt; and &amp; entities &copy; 2024'
316+
317+
const file = await unified()
318+
.use(remarkParse)
319+
.use(remarkNotes)
320+
.use(remarkRehype, { allowDangerousHtml: true })
321+
.use(rehypeRaw)
322+
.use(rehypeStringify)
323+
.process(markdown)
324+
325+
const output = String(file)
326+
327+
// Should transform and handle entities
328+
assert.ok(output.includes('class="remark-note remark-note-note"'),
329+
'Note with HTML entities should be transformed')
330+
331+
// Entities should be preserved or properly decoded
332+
assert.ok(output.includes('div') || output.includes('entities'),
333+
'Content with entities should be present')
334+
})
335+
336+
test('remark-notes: multiple paragraphs in note', async () => {
337+
const markdown = `> [!bonus]
338+
> First paragraph here.
339+
>
340+
> Second paragraph here.
341+
>
342+
> Third paragraph here.`
343+
344+
const file = await unified()
345+
.use(remarkParse)
346+
.use(remarkNotes)
347+
.use(remarkRehype, { allowDangerousHtml: true })
348+
.use(rehypeRaw)
349+
.use(rehypeStringify)
350+
.process(markdown)
351+
352+
const output = String(file)
353+
354+
// Should preserve multiple paragraphs
355+
assert.ok(output.includes('class="remark-note remark-note-bonus"'),
356+
'Note with multiple paragraphs should be transformed')
357+
358+
assert.ok(output.includes('First paragraph') &&
359+
output.includes('Second paragraph') &&
360+
output.includes('Third paragraph'),
361+
'All paragraphs should be preserved')
362+
363+
// Should have paragraph tags
364+
const paragraphCount = (output.match(/<p>/g) || []).length
365+
assert.ok(paragraphCount >= 3,
366+
'Multiple paragraphs should be rendered as separate <p> tags')
367+
})
368+
369+
console.log('\n✅ All edge case tests completed!')

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,8 @@
3737
"test:styles": "node --loader ts-node/esm __tests__/styles.ts",
3838
"test:custom-prefix": "node --loader ts-node/esm __tests__/custom-prefix.ts",
3939
"test:validation": "node --loader ts-node/esm __tests__/validation.ts",
40-
"test:all": "yarn test && yarn test:styles && yarn test:custom-prefix && yarn test:validation",
40+
"test:edge-cases": "node --loader ts-node/esm __tests__/edge-cases.ts",
41+
"test:all": "yarn test && yarn test:styles && yarn test:custom-prefix && yarn test:validation && yarn test:edge-cases",
4142
"generate:fixtures": "node --loader ts-node/esm __tests__/generate-fixtures.ts"
4243
},
4344
"keywords": [

0 commit comments

Comments
 (0)