1import assert from 'node:assert/strict'2import test from 'node:test'3import { ClientSvgError, sanitizeAndDecorateSvg } from '../src/client-svg.js'45const metadata = { title: 'Client preview', description: 'Rendered locally' }6const presentation = { background: '#f3f3f3', padding: 16, frame: true }78test('sanitizes and decorates a client-rendered SVG', () => {9 const source = `<svg xmlns="http://www.w3.org/2000/svg" width="100" height="50" viewBox="0 0 100 50">10 <script>alert(1)</script>11 <image href="https://example.com/tracker.png" onload="alert(1)" />12 <foreignObject><div xmlns="http://www.w3.org/1999/xhtml"><span>Alice Agent</span><img src="https://example.com/x" /></div></foreignObject>13 <style><![CDATA[@keyframes dashdraw{to{stroke-dashoffset:0}} .edge{animation:dashdraw 2s linear infinite}]]></style>14 <rect x="10" y="10" width="20" height="10" fill="white" stroke="black" />15 </svg>`1617 const rendered = sanitizeAndDecorateSvg(source, metadata, presentation, 'mermaid')18 assert.match(rendered, /<title>Client preview<\/title>/)19 assert.match(rendered, /<desc>Rendered locally<\/desc>/)20 assert.match(rendered, /viewBox="-16 -16 132 82"/)21 assert.match(rendered, /fill="#f3f3f3"/)22 assert.match(rendered, /Alice Agent/)23 assert.match(rendered, /@keyframes dashdraw/)24 assert.match(rendered, /vector-effect="non-scaling-stroke"/)25 assert.match(rendered, /data-dz-schema="1"/)26 assert.match(rendered, /data-dz-engine="mermaid"/)27 assert.match(rendered, /data-dz-appearance="raw"/)28 assert.match(rendered, /width="20" height="10" fill="white" stroke="black"/)29 assert.doesNotMatch(rendered, /<script|<img|https:\/\/example\.com|onload=/)30})3132test('rejects unsafe client-rendered CSS', () => {33 assert.throws(34 () => sanitizeAndDecorateSvg(35 '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 10 10"><style>rect{fill:url(https://example.com/x)}</style></svg>',36 { title: '', description: '' },37 { background: '', padding: 0, frame: false },38 'mermaid',39 ),40 ClientSvgError,41 )42})4344test('removes a full renderer backdrop but preserves internal white shapes', () => {45 const rendered = sanitizeAndDecorateSvg(46 '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 50"><rect width="100%" height="100%" fill="white"/><rect x="10" y="10" width="20" height="10" fill="white" stroke="black"/></svg>',47 { title: '', description: '' },48 { background: '#222222', padding: 0, frame: false },49 'mermaid',50 )51 assert.doesNotMatch(rendered, /width="100%"/)52 assert.match(rendered, /width="20" height="10" fill="white" stroke="black"/)53})