// Embed expansion (Phase 16.2, D-17). The Blog Editor stores the placeholder //
; the sinks render // expandEmbeds(sanitizeJournalHtml(html)), so the sanitizer runs first and the // only iframe in the output is the one built from a validated placeholder. import { test } from 'node:test' import assert from 'node:assert/strict' import { readFileSync } from 'node:fs' import { EMBED_PLACEHOLDER, EMBED_PROVIDERS, expandEmbeds } from '../app/utils/embeds.ts' import { sanitizeJournalHtml } from '../app/utils/htmlGate.ts' const ID = 'dQw4w9WgXcQ' const PLACEHOLDER = `
` const IFRAME = '
' + `' + '
' // The sink: sanitize, then expand last. const sink = (html: string) => expandEmbeds(sanitizeJournalHtml(html)) // The payload transform sanitizes, and the sink sanitizes again before expanding. const payloadThenSink = (html: string) => expandEmbeds(sanitizeJournalHtml(sanitizeJournalHtml(html))) const iframeCount = (html: string) => (html.match(/' + `` + PLACEHOLDER + '

After

' for (const run of [sink, payloadThenSink]) { const out = run(stored) assert.equal(out, `

Before

${IFRAME}

After

`) assert.equal(iframeCount(out), 1) assert.doesNotMatch(out, /evil\.test/) } }) test('a placeholder smuggling an iframe or extra attributes expands only its validated parts', () => { const stored = `
` assert.equal(sink(stored), IFRAME) assert.equal(payloadThenSink(stored), IFRAME) }) test('a malformed placeholder stays an empty figure after the sink', () => { assert.equal(sink(`
`), '
') assert.equal(sink(`
`), `
`) assert.equal(iframeCount(sink(`
`)), 0) }) test('the payload-then-sink pipeline gives the same result as the sink', () => { const stored = `

x

${PLACEHOLDER}

y

` assert.equal(payloadThenSink(stored), sink(stored)) assert.equal(sink(stored), `

x

${IFRAME}

y

`) }) test('two placeholders in one body both expand', () => { const other = 'abcdefghijk' const out = sink(`${PLACEHOLDER}

between

`) assert.equal(iframeCount(out), 2) assert.equal(out, `${IFRAME}

between

${IFRAME.replace(ID, other)}`) }) test('the editor corpus embed entries expand after sanitizing', () => { const corpus = JSON.parse( readFileSync(new URL('./fixtures/editor-corpus.json', import.meta.url), 'utf8'), ) as Array<{ name: string; html: string }> const embed = corpus.find((e) => e.name === 'embed-youtube') assert.ok(embed) assert.equal(payloadThenSink(embed.html), IFRAME) const combined = corpus.find((e) => e.name === 'combined') assert.ok(combined) const out = payloadThenSink(combined.html) assert.ok(out.startsWith(IFRAME), out) assert.equal(iframeCount(out), 1) // Entries without a placeholder pass through the expansion unchanged. for (const entry of corpus.filter((e) => !e.html.includes('data-embed'))) { const clean = sanitizeJournalHtml(entry.html) assert.equal(expandEmbeds(clean), clean, entry.name) } })