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);
});