From 346ee9457b52b8b198ebe2d9ca7aadf7534569ca Mon Sep 17 00:00:00 2001 From: Silberengel Date: Mon, 12 May 2025 23:19:28 +0200 Subject: [PATCH] Implemented unit and integration tests for the parser. --- tests/integration/markupIntegration.test.ts | 99 +++++++++++++++ .../integration}/markupTestfile.md | 6 + tests/unit/advancedMarkupParser.test.ts | 118 ++++++++++++++++++ tests/unit/basicMarkupParser.test.ts | 88 +++++++++++++ tests/unit/example.js | 3 - tests/unit/example.unit-test.js | 6 - vite.config.ts | 2 +- 7 files changed, 312 insertions(+), 10 deletions(-) create mode 100644 tests/integration/markupIntegration.test.ts rename {src/lib/utils/markup => tests/integration}/markupTestfile.md (95%) create mode 100644 tests/unit/advancedMarkupParser.test.ts create mode 100644 tests/unit/basicMarkupParser.test.ts delete mode 100644 tests/unit/example.js delete mode 100644 tests/unit/example.unit-test.js diff --git a/tests/integration/markupIntegration.test.ts b/tests/integration/markupIntegration.test.ts new file mode 100644 index 0000000..0bc7443 --- /dev/null +++ b/tests/integration/markupIntegration.test.ts @@ -0,0 +1,99 @@ +import { describe, it, expect } from 'vitest'; +import { parseBasicmarkup } from '../../src/lib/utils/markup/basicMarkupParser'; +import { parseAdvancedmarkup } from '../../src/lib/utils/markup/advancedMarkupParser'; +import { readFileSync } from 'fs'; +import { join } from 'path'; + +const testFilePath = join(__dirname, './markupTestfile.md'); +const md = readFileSync(testFilePath, 'utf-8'); + +describe('Markup Integration Test', () => { + it('parses markupTestfile.md with the basic parser', async () => { + const output = await parseBasicmarkup(md); + // Headers (should be present as text, not

tags) + expect(output).toContain('This is a test'); + expect(output).toContain('============'); + expect(output).toContain('### Disclaimer'); + // Unordered list + expect(output).toContain(']*>.*]*>/s); + // Blockquotes + expect(output).toContain(''); + // Images + expect(output).toMatch(/]+src="https:\/\/upload\.wikimedia\.org\/wikipedia\/commons\/f\/f1\/Heart_coraz%C3%B3n\.svg"/); + // Links + expect(output).toMatch(/]+href="https:\/\/github.com\/nostrability\/nostrability\/issues\/146"/); + // Hashtags + expect(output).toContain('text-primary-600'); + // Nostr identifiers (should be njump.me links) + expect(output).toContain('https://njump.me/npub1l5sga6xg72phsz5422ykujprejwud075ggrr3z2hwyrfgr7eylqstegx9z'); + // Wikilinks + expect(output).toContain('wikilink'); + // YouTube iframe + expect(output).toMatch(/]+youtube/); + // Tracking token removal: should not contain utm_, fbclid, or gclid in any link + expect(output).not.toMatch(/utm_/); + expect(output).not.toMatch(/fbclid/); + expect(output).not.toMatch(/gclid/); + // Horizontal rule (should be present as --- in basic) + expect(output).toContain('---'); + // Footnote references (should be present as [^1] in basic) + expect(output).toContain('[^1]'); + // Table (should be present as | Syntax | Description | in basic) + expect(output).toContain('| Syntax | Description |'); + }); + + it('parses markupTestfile.md with the advanced parser', async () => { + const output = await parseAdvancedmarkup(md); + // Headers + expect(output).toContain(']*>.*]*>/s); + // Blockquotes + expect(output).toContain(']*>.*leather min-h-full w-full flex flex-col items-center.*<\/code>/s); + // Images + expect(output).toMatch(/]+src="https:\/\/upload\.wikimedia\.org\/wikipedia\/commons\/f\/f1\/Heart_coraz%C3%B3n\.svg"/); + // Links + expect(output).toMatch(/]+href="https:\/\/github.com\/nostrability\/nostrability\/issues\/146"/); + // Hashtags + expect(output).toContain('text-primary-600'); + // Nostr identifiers (should be njump.me links) + expect(output).toContain('https://njump.me/npub1l5sga6xg72phsz5422ykujprejwud075ggrr3z2hwyrfgr7eylqstegx9z'); + // Wikilinks + expect(output).toContain('wikilink'); + // YouTube iframe + expect(output).toMatch(/]+youtube/); + // Tracking token removal: should not contain utm_, fbclid, or gclid in any link + expect(output).not.toMatch(/utm_/); + expect(output).not.toMatch(/fbclid/); + expect(output).not.toMatch(/gclid/); + // Horizontal rule + expect(output).toContain('/); + // Table + expect(output).toContain(' important information > with a second[^2] footnote. +This is a youtube link +https://www.youtube.com/watch?v=9aqVxNCpx9s + +And here is a link with tracking tokens: +https://arstechnica.com/science/2019/07/new-data-may-extend-norse-occupancy-in-north-america/?fbclid=IwAR1LOW3BebaMLinfkWFtFpzkLFi48jKNF7P6DV2Ux2r3lnT6Lqj6eiiOZNU + This is an unordered list: * but * not diff --git a/tests/unit/advancedMarkupParser.test.ts b/tests/unit/advancedMarkupParser.test.ts new file mode 100644 index 0000000..6e64327 --- /dev/null +++ b/tests/unit/advancedMarkupParser.test.ts @@ -0,0 +1,118 @@ +import { describe, it, expect } from 'vitest'; +import { parseAdvancedmarkup } from '../../src/lib/utils/markup/advancedMarkupParser'; + +function stripWS(str: string) { + return str.replace(/\s+/g, ' ').trim(); +} + +describe('Advanced Markup Parser', () => { + it('parses headers (ATX and Setext)', async () => { + const input = '# H1\nText\n\nH2\n====\n'; + const output = await parseAdvancedmarkup(input); + expect(stripWS(output)).toContain('H1'); + expect(stripWS(output)).toContain('H2'); + }); + + it('parses bold, italic, and strikethrough', async () => { + const input = '*bold* **bold** _italic_ __italic__ ~strikethrough~ ~~strikethrough~~'; + const output = await parseAdvancedmarkup(input); + expect(output).toContain('bold'); + expect(output).toContain('italic'); + expect(output).toContain('strikethrough'); + }); + + it('parses blockquotes', async () => { + const input = '> quote'; + const output = await parseAdvancedmarkup(input); + expect(output).toContain(' { + const input = '> quote\n> quote'; + const output = await parseAdvancedmarkup(input); + expect(output).toContain(' { + const input = '* a\n* b'; + const output = await parseAdvancedmarkup(input); + expect(output).toContain(' { + const input = '1. one\n2. two'; + const output = await parseAdvancedmarkup(input); + expect(output).toContain(' { + const input = '[link](https://example.com) ![alt](https://img.com/x.png)'; + const output = await parseAdvancedmarkup(input); + expect(output).toContain(' { + const input = '#hashtag'; + const output = await parseAdvancedmarkup(input); + expect(output).toContain('text-primary-600'); + expect(output).toContain('#hashtag'); + }); + + it('parses nostr identifiers', async () => { + const input = 'npub1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq'; + const output = await parseAdvancedmarkup(input); + expect(output).toContain('https://njump.me/npub1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq'); + }); + + it('parses emoji shortcodes', async () => { + const input = 'hello :smile:'; + const output = await parseAdvancedmarkup(input); + expect(output).toMatch(/😄|:smile:/); + }); + + it('parses wikilinks', async () => { + const input = '[[Test Page|display]]'; + const output = await parseAdvancedmarkup(input); + expect(output).toContain('wikilink'); + expect(output).toContain('display'); + }); + + it('parses tables (with and without headers)', async () => { + const input = `| Syntax | Description |\n|--------|-------------|\n| Header | Title |\n| Paragraph | Text |\n\n| a | b |\n| c | d |`; + const output = await parseAdvancedmarkup(input); + expect(output).toContain(' { + const input = '```js\nconsole.log(1);\n```\n```\nno lang\n```'; + const output = await parseAdvancedmarkup(input); + const textOnly = output.replace(/<[^>]+>/g, ''); + expect(output).toContain(' { + const input = '---'; + const output = await parseAdvancedmarkup(input); + expect(output).toContain(' { + const input = 'Here is a footnote[^1].\n\n[^1]: This is the footnote.'; + const output = await parseAdvancedmarkup(input); + expect(output).toContain('Footnotes'); + expect(output).toContain('This is the footnote'); + expect(output).toContain('fn-1'); + }); +}); \ No newline at end of file diff --git a/tests/unit/basicMarkupParser.test.ts b/tests/unit/basicMarkupParser.test.ts new file mode 100644 index 0000000..45e0d46 --- /dev/null +++ b/tests/unit/basicMarkupParser.test.ts @@ -0,0 +1,88 @@ +import { describe, it, expect } from 'vitest'; +import { parseBasicmarkup } from '../../src/lib/utils/markup/basicMarkupParser'; + +// Helper to strip whitespace for easier comparison +function stripWS(str: string) { + return str.replace(/\s+/g, ' ').trim(); +} + +describe('Basic Markup Parser', () => { + it('parses ATX and Setext headers', async () => { + const input = '# H1\nText\n\nH2\n====\n'; + const output = await parseBasicmarkup(input); + expect(stripWS(output)).toContain('H1'); + expect(stripWS(output)).toContain('H2'); + }); + + it('parses bold, italic, and strikethrough', async () => { + const input = '*bold* **bold** _italic_ __italic__ ~strikethrough~ ~~strikethrough~~'; + const output = await parseBasicmarkup(input); + expect(output).toContain('bold'); + expect(output).toContain('italic'); + expect(output).toContain('strikethrough'); + }); + + it('parses blockquotes', async () => { + const input = '> quote'; + const output = await parseBasicmarkup(input); + expect(output).toContain(' { + const input = '> quote\n> quote'; + const output = await parseBasicmarkup(input); + expect(output).toContain(' { + const input = '* a\n* b'; + const output = await parseBasicmarkup(input); + expect(output).toContain(' { + const input = '1. one\n2. two'; + const output = await parseBasicmarkup(input); + expect(output).toContain(' { + const input = '[link](https://example.com) ![alt](https://img.com/x.png)'; + const output = await parseBasicmarkup(input); + expect(output).toContain(' { + const input = '#hashtag'; + const output = await parseBasicmarkup(input); + expect(output).toContain('text-primary-600'); + expect(output).toContain('#hashtag'); + }); + + it('parses nostr identifiers', async () => { + const input = 'npub1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq'; + const output = await parseBasicmarkup(input); + expect(output).toContain('https://njump.me/npub1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq'); + }); + + it('parses emoji shortcodes', async () => { + const input = 'hello :smile:'; + const output = await parseBasicmarkup(input); + expect(output).toMatch(/😄|:smile:/); + }); + + it('parses wikilinks', async () => { + const input = '[[Test Page|display]]'; + const output = await parseBasicmarkup(input); + expect(output).toContain('wikilink'); + expect(output).toContain('display'); + }); +}); \ No newline at end of file diff --git a/tests/unit/example.js b/tests/unit/example.js deleted file mode 100644 index 54a837e..0000000 --- a/tests/unit/example.js +++ /dev/null @@ -1,3 +0,0 @@ -export function sum(a, b) { - return a + b -} \ No newline at end of file diff --git a/tests/unit/example.unit-test.js b/tests/unit/example.unit-test.js deleted file mode 100644 index f0058d7..0000000 --- a/tests/unit/example.unit-test.js +++ /dev/null @@ -1,6 +0,0 @@ -import { expect, test } from 'vitest' -import { sum } from './example.js' - -test('adds 1 + 2 to equal 3', () => { - expect(sum(1, 2)).toBe(3) -}) \ No newline at end of file diff --git a/vite.config.ts b/vite.config.ts index 4dc4254..fc84d3a 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -27,7 +27,7 @@ export default defineConfig({ } }, test: { - include: ['./tests/unit/**/*.unit-test.js'] + include: ['./tests/unit/**/*.test.ts', './tests/integration/**/*.test.ts'] }, define: { // Expose the app version as a global variable