clone

a browser-first diagram editor with live svg previews, local drafts and encrypted, accountless sharing

main
diagramzip / renderers / edge / test / browser-unit.test.ts
browser-unit.test.ts 4.2K
1import { describe, expect, it } from 'vitest'2import { cacheKey, createBrowserRendererUnit } from '../../shared/browser-unit'3import { NORMALIZER_BUILD } from '../../../shared/svg/index.js'45const descriptor = {6 id: 'mermaid',7 kind: 'render',8 version: 'mermaid@11.17.0',9 build: 'mermaid-test-browser-run-1',10 pipeline: ['mermaid'],11 frame: '/index.html?v=1',12 knownLosses: [],13} as const14const unit = createBrowserRendererUnit(descriptor)15const fetchUnit = unit.fetch!16const context = {17 waitUntil() {},18 passThroughOnException() {},19 props: {},20} as unknown as ExecutionContext2122function env(serviceFetch?: (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>) {23 return {24 ASSETS: {25 fetch: async () => new Response('<!doctype html><title>renderer frame</title>', { headers: { 'Content-Type': 'text/html' } }),26 },27 BROWSER_RENDERER: {28 fetch: serviceFetch ?? (async (input: RequestInfo | URL, init?: RequestInit) => {29 const request = new Request(input, init)30 const body = await request.json() as { engine: string }31 return Response.json({32 svg: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 10"><text x="1" y="8">ok</text></svg>',33 version: 'mermaid@11.17.0',34 build: 'frame-test-1',35 pipeline: [body.engine],36 })37 }),38 },39 }40}4142function renderRequest(source: string): Request {43 return new Request('https://mermaid.render.diagram.zip/v1/svg', {44 method: 'POST',45 headers: { 'Content-Type': 'application/json' },46 body: JSON.stringify({ source }),47 })48}4950describe('browser-backed renderer unit', () => {51 it('names the normalizer build in its cache namespace', async () => {52 const key = await cacheKey({ engine: 'mermaid', source: 'graph TD', format: 'svg', options: {}, metadata: { title: '', description: '' }, presentation: { background: '', padding: 0, frame: false } }, descriptor)53 expect(new URL(key.url).pathname).toContain(`/${NORMALIZER_BUILD}/mermaid/`)54 })5556 it('serves the renderer frame outside the public API namespace', async () => {57 const response = await fetchUnit(58 new Request('https://mermaid.render.diagram.zip/index.html') as Parameters<typeof fetchUnit>[0],59 env() as unknown as Parameters<typeof fetchUnit>[1],60 context,61 )62 expect(response.status).toBe(200)63 expect(await response.text()).toContain('renderer frame')64 })6566 it('renders through the private service while owning public identity headers', async () => {67 const response = await fetchUnit(68 renderRequest(`graph TD; A-->B-${crypto.randomUUID()}`) as Parameters<typeof fetchUnit>[0],69 env() as unknown as Parameters<typeof fetchUnit>[1],70 context,71 )72 expect(response.status).toBe(200)73 expect(response.headers.get('X-Diagram-Renderer')).toBe('browser-run')74 expect(response.headers.get('X-Diagram-Engine-Version')).toBe('mermaid@11.17.0')75 expect(response.headers.get('X-Renderer-Build')).toBe('mermaid-test-browser-run-1')76 expect(await response.text()).toContain('>ok</text>')77 })7879 it('rejects body-selected engines without calling the private service', async () => {80 let called = false81 const response = await fetchUnit(82 new Request('https://mermaid.render.diagram.zip/v1/svg', {83 method: 'POST',84 headers: { 'Content-Type': 'application/json' },85 body: JSON.stringify({ engine: 'tikz', source: 'graph TD' }),86 }) as Parameters<typeof fetchUnit>[0],87 env(async () => { called = true; return Response.json({}) }) as unknown as Parameters<typeof fetchUnit>[1],88 context,89 )90 expect(response.status).toBe(400)91 expect(called).toBe(false)92 })9394 it('normalizes private service failures to a stable gateway error', async () => {95 const response = await fetchUnit(96 renderRequest(`graph TD; failure-${crypto.randomUUID()}`) as Parameters<typeof fetchUnit>[0],97 env(async () => Response.json({ error: { code: 'render_failed', message: 'sensitive detail' } }, { status: 500 })) as unknown as Parameters<typeof fetchUnit>[1],98 context,99 )100 expect(response.status).toBe(502)101 await expect(response.json()).resolves.toEqual({ error: { code: 'render_failed', message: 'The browser renderer could not render the diagram.' } })102 })103})