import assert from 'node:assert/strict'; import { test } from 'node:test'; import { escapeHtml, renderEmbedPage, renderOEmbedJson, renderProjectPage, type ProjectCardData } from '../src/cards.ts'; const malicious: ProjectCardData = { actor: 'alice.bsky.social', did: 'did:plc:alice', rkey: '3la1', name: '', description: 'a "quoted" & tagged description', }; test('escapeHtml escapes every special character', () => { assert.equal(escapeHtml(`'), false); assert.equal( html.includes(''), true, ); assert.equal( html.includes(''), true, ); }); test('renderProjectPage redirects humans via meta refresh to the app URL', () => { const html = renderProjectPage(malicious, 'https://nibling.run'); assert.equal( html.includes(''), true, ); }); test('renderEmbedPage HTML-escapes the name and embeds the app in an iframe', () => { const html = renderEmbedPage(malicious, 'https://nibling.run'); assert.equal(html.includes(''), false); assert.equal( html.includes('src="https://nibling.run/alice.bsky.social/3la1/embed"'), true, ); }); test('renderOEmbedJson escapes the embed src and keeps the exact title', () => { const oembed = renderOEmbedJson(malicious, 'https://nibling.run'); assert.equal(oembed.type, 'rich'); assert.equal(oembed.title, ''); // JSON, not HTML: not escaped assert.equal(oembed.html.includes(''), false); assert.equal(oembed.html.includes('src="https://nibling.run/alice.bsky.social/3la1/embed"'), true); }); test('renderProjectPage uses the slug for the app URL when the card has one', () => { const withSlug: ProjectCardData = { ...malicious, slug: 'bouncing-ball' }; const html = renderProjectPage(withSlug, 'https://nibling.run'); assert.equal( html.includes(''), true, ); }); test('renderEmbedPage uses the slug for the iframe src when the card has one', () => { const withSlug: ProjectCardData = { ...malicious, slug: 'bouncing-ball' }; const html = renderEmbedPage(withSlug, 'https://nibling.run'); assert.equal(html.includes('src="https://nibling.run/alice.bsky.social/bouncing-ball/embed"'), true); });