Browse Source

Implemented unit and integration tests for the parser.

master
Silberengel 10 months ago
parent
commit
346ee9457b
  1. 99
      tests/integration/markupIntegration.test.ts
  2. 6
      tests/integration/markupTestfile.md
  3. 118
      tests/unit/advancedMarkupParser.test.ts
  4. 88
      tests/unit/basicMarkupParser.test.ts
  5. 3
      tests/unit/example.js
  6. 6
      tests/unit/example.unit-test.js
  7. 2
      vite.config.ts

99
tests/integration/markupIntegration.test.ts

@ -0,0 +1,99 @@ @@ -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 <h1> tags)
expect(output).toContain('This is a test');
expect(output).toContain('============');
expect(output).toContain('### Disclaimer');
// Unordered list
expect(output).toContain('<ul');
expect(output).toContain('but');
// Ordered list
expect(output).toContain('<ol');
expect(output).toContain('first');
// Nested lists
expect(output).toMatch(/<ul[^>]*>.*<ul[^>]*>/s);
// Blockquotes
expect(output).toContain('<blockquote');
expect(output).toContain('This is important information');
// Inline code
expect(output).toContain('<div class="leather min-h-full w-full flex flex-col items-center">');
// Images
expect(output).toMatch(/<img[^>]+src="https:\/\/upload\.wikimedia\.org\/wikipedia\/commons\/f\/f1\/Heart_coraz%C3%B3n\.svg"/);
// Links
expect(output).toMatch(/<a[^>]+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(/<iframe[^>]+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('<h1');
expect(output).toContain('<h2');
expect(output).toContain('Disclaimer');
// Unordered list
expect(output).toContain('<ul');
expect(output).toContain('but');
// Ordered list
expect(output).toContain('<ol');
expect(output).toContain('first');
// Nested lists
expect(output).toMatch(/<ul[^>]*>.*<ul[^>]*>/s);
// Blockquotes
expect(output).toContain('<blockquote');
expect(output).toContain('This is important information');
// Inline code
expect(output).toMatch(/<code[^>]*>.*leather min-h-full w-full flex flex-col items-center.*<\/code>/s);
// Images
expect(output).toMatch(/<img[^>]+src="https:\/\/upload\.wikimedia\.org\/wikipedia\/commons\/f\/f1\/Heart_coraz%C3%B3n\.svg"/);
// Links
expect(output).toMatch(/<a[^>]+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(/<iframe[^>]+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('<hr');
// Footnote references and section
expect(output).toContain('Footnotes');
expect(output).toMatch(/<li id=\"fn-1\">/);
// Table
expect(output).toContain('<table');
// Code blocks
expect(output).toContain('<pre');
});
});

6
src/lib/utils/markup/markupTestfile.md → tests/integration/markupTestfile.md

@ -25,6 +25,12 @@ npub1l5sga6xg72phsz5422ykujprejwud075ggrr3z2hwyrfgr7eylqstegx9z wrote this. That @@ -25,6 +25,12 @@ npub1l5sga6xg72phsz5422ykujprejwud075ggrr3z2hwyrfgr7eylqstegx9z wrote this. That
> 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

118
tests/unit/advancedMarkupParser.test.ts

@ -0,0 +1,118 @@ @@ -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('<strong>bold</strong>');
expect(output).toContain('<em>italic</em>');
expect(output).toContain('<del class="line-through">strikethrough</del>');
});
it('parses blockquotes', async () => {
const input = '> quote';
const output = await parseAdvancedmarkup(input);
expect(output).toContain('<blockquote');
expect(output).toContain('quote');
});
it('parses multi-line blockquotes', async () => {
const input = '> quote\n> quote';
const output = await parseAdvancedmarkup(input);
expect(output).toContain('<blockquote');
expect(output).toContain('quote');
expect(output).toContain('quote');
});
it('parses unordered lists', async () => {
const input = '* a\n* b';
const output = await parseAdvancedmarkup(input);
expect(output).toContain('<ul');
expect(output).toContain('a');
expect(output).toContain('b');
});
it('parses ordered lists', async () => {
const input = '1. one\n2. two';
const output = await parseAdvancedmarkup(input);
expect(output).toContain('<ol');
expect(output).toContain('one');
expect(output).toContain('two');
});
it('parses links and images', async () => {
const input = '[link](https://example.com) ![alt](https://img.com/x.png)';
const output = await parseAdvancedmarkup(input);
expect(output).toContain('<a');
expect(output).toContain('<img');
});
it('parses hashtags', async () => {
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('<table');
expect(output).toContain('Header');
expect(output).toContain('a');
});
it('parses code blocks (with and without language)', async () => {
const input = '```js\nconsole.log(1);\n```\n```\nno lang\n```';
const output = await parseAdvancedmarkup(input);
const textOnly = output.replace(/<[^>]+>/g, '');
expect(output).toContain('<pre');
expect(textOnly).toContain('console.log(1);');
expect(textOnly).toContain('no lang');
});
it('parses horizontal rules', async () => {
const input = '---';
const output = await parseAdvancedmarkup(input);
expect(output).toContain('<hr');
});
it('parses footnotes (references and section)', async () => {
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');
});
});

88
tests/unit/basicMarkupParser.test.ts

@ -0,0 +1,88 @@ @@ -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('<strong>bold</strong>');
expect(output).toContain('<em>italic</em>');
expect(output).toContain('<del class="line-through">strikethrough</del>');
});
it('parses blockquotes', async () => {
const input = '> quote';
const output = await parseBasicmarkup(input);
expect(output).toContain('<blockquote');
expect(output).toContain('quote');
});
it('parses multi-line blockquotes', async () => {
const input = '> quote\n> quote';
const output = await parseBasicmarkup(input);
expect(output).toContain('<blockquote');
expect(output).toContain('quote');
expect(output).toContain('quote');
});
it('parses unordered lists', async () => {
const input = '* a\n* b';
const output = await parseBasicmarkup(input);
expect(output).toContain('<ul');
expect(output).toContain('a');
expect(output).toContain('b');
});
it('parses ordered lists', async () => {
const input = '1. one\n2. two';
const output = await parseBasicmarkup(input);
expect(output).toContain('<ol');
expect(output).toContain('one');
expect(output).toContain('two');
});
it('parses links and images', async () => {
const input = '[link](https://example.com) ![alt](https://img.com/x.png)';
const output = await parseBasicmarkup(input);
expect(output).toContain('<a');
expect(output).toContain('<img');
});
it('parses hashtags', async () => {
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');
});
});

3
tests/unit/example.js

@ -1,3 +0,0 @@ @@ -1,3 +0,0 @@
export function sum(a, b) {
return a + b
}

6
tests/unit/example.unit-test.js

@ -1,6 +0,0 @@ @@ -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)
})

2
vite.config.ts

@ -27,7 +27,7 @@ export default defineConfig({ @@ -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

Loading…
Cancel
Save