Files
ink-note-app/test/embed.test.js
T
2026-10-15 11:57:09 +02:00

77 lines
4.5 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { test } from 'node:test';
import assert from 'node:assert/strict';
import { createRequire } from 'node:module';
import { parseMarkdown, toMarkdown, mdToHtml, htmlToMd } from '../src/lib/markdown.js';
import { headingOf, linkLabel, normHeading, refPage } from '../src/lib/links.js';
import { headingsOf, sectionOf, staticHtml } from '../src/lib/embed.js';
const require = createRequire(import.meta.url);
const { findLinks, rewriteLinks, backlinks, graph } = require('../electron/links.cjs');
test('heading links: label, parts and round trip', () => {
assert.equal(refPage('Plans/Road map#Q3'), 'Plans/Road map');
assert.equal(headingOf('Road map#Q3 goals'), 'Q3 goals');
assert.equal(headingOf('Page#One#Two'), 'Two');
assert.equal(headingOf('Page#^abc123'), '');
assert.equal(headingOf('Page'), '');
assert.equal(linkLabel('Plans/Road map#Q3'), 'Road map › Q3');
assert.equal(linkLabel('#Local'), 'Local');
assert.equal(linkLabel('Page'), 'Page');
assert.equal(normHeading(' Q3 Goals '), 'q3 goals');
const md = 'See [[Road map#Q3]], [[#Here]] and [[Page#Part|the part]].';
const html = mdToHtml(md);
assert.match(html, /data-ref="Road map#Q3">Road map › Q3</);
assert.match(html, /data-ref="#Here">Here</);
assert.match(html, /data-ref="Page#Part">the part</);
assert.equal(htmlToMd(html), md);
});
test('![[embeds]] are blocks; pictures and other files are not', () => {
const md = 'Before\n\n![[Roadmap]]\n\n![[Plans/Roadmap#Q3 goals|Goals]]\n\n![[photo.png]]\n\n![[slides.pdf]]\n\nAfter\n';
const blocks = parseMarkdown(md);
assert.deepEqual(blocks.map((b) => b.type), ['p', 'embed', 'embed', 'image', 'p', 'p']);
assert.equal(blocks[1].ref, 'Roadmap');
assert.equal(blocks[2].ref, 'Plans/Roadmap#Q3 goals');
assert.equal(blocks[2].alias, 'Goals');
assert.equal(blocks[4].html, '![[slides.pdf]]'); // unsupported files stay as text
assert.equal(toMarkdown(blocks), md);
});
const DOC = parseMarkdown('Intro\n\n# Top\n\nunder top\n\n## Alpha\n\n- one\n- [x] two\n\n### Deep\n\nlow\n\n## Beta\n\nbeta text\n');
test('sections: a heading and everything below it, up to the next heading of the same or a higher level', () => {
assert.deepEqual(headingsOf(DOC).map((h) => `${h.level}:${h.text}`), ['1:Top', '2:Alpha', '3:Deep', '2:Beta']);
assert.deepEqual(sectionOf(DOC, 'alpha').map((b) => b.type), ['h2', 'bullet', 'todo', 'h3', 'p']);
assert.equal(sectionOf(DOC, ' ALPHA ').length, 5);
assert.deepEqual(sectionOf(DOC, 'Beta').map((b) => b.type), ['h2', 'p']);
assert.equal(sectionOf(DOC, 'Top').length, 9); // everything after the intro line
assert.equal(sectionOf(DOC, 'Nope'), null);
});
test('embedded content renders read-only, escaped, and with no editor hooks', () => {
const blocks = parseMarkdown('## Part\n\nSome **bold** & <script>x</script>\n\n- [x] done\n\n```js\nlet a = 1 < 2\n```\n\n| a | b |\n|---|---|\n| 1 | 2 |\n\n![pic](p.png)\n\n![[Other]]\n\n> [!warning]\n> careful\n');
const html = staticHtml(blocks, { imageUrl: (s) => `media://x/${s}` });
assert.ok(!html.includes('contenteditable="true"'), 'nothing editable');
assert.ok(!html.includes('class="block'), 'no editor block wrappers');
assert.ok(!html.includes('<script>'), 'escaped');
assert.match(html, /<div class="eb b-h2"><div class="c">Part<\/div><\/div>/);
assert.match(html, /<b>bold<\/b>/);
assert.match(html, /b-todo done/);
assert.match(html, /<div class="ecell">1<\/div>/);
assert.match(html, /src="media:\/\/x\/p\.png"/);
assert.match(html, /emb-nested.*data-ref="Other"/);
assert.match(html, /data-kind="warning"/);
});
test('on disk: embeds count as links, heading parts and aliases survive a rename, files and code are left alone', () => {
const P = (id, body) => ({ id, title: id.split('/').pop(), parent: null, exists: true, body });
const notes = P('Notes', 'See [[Plan#Goals|goals]] and [[#Local]].\n\n![[Plan]]\n\n![[Plan#Q3]]\n![[photo.png]] ![[slides.pdf]]\n```\n![[Plan]]\n```\n');
const before = [P('Plan', '# Goals'), notes];
assert.deepEqual(findLinks(notes.body).map((l) => (l.embed ? '!' : '') + l.ref), ['Plan#Goals', '#Local', '!Plan', '!Plan#Q3']);
const out = rewriteLinks(notes.body, before, [P('Roadmap', ''), notes], (id) => (id === 'Plan' ? 'Roadmap' : null));
assert.equal(out, 'See [[Roadmap#Goals|goals]] and [[#Local]].\n\n![[Roadmap]]\n\n![[Roadmap#Q3]]\n![[photo.png]] ![[slides.pdf]]\n```\n![[Plan]]\n```\n');
assert.deepEqual(backlinks('Plan', before).map((b) => b.id), ['Notes']);
assert.deepEqual(graph(before).edges, [['Notes', 'Plan']]);
assert.deepEqual(graph(before).ghosts, []);
});