clone

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

main
diagramzip / renderers / edge / test / goat.test.ts
goat.test.ts 3.2K
1import { createHash } from 'node:crypto'2import { describe, expect, it } from 'vitest'3import { goatAdapter } from '../src/adapters/goat'4import type { RenderRequest } from '../src/runtime/types'56const request = (source: string, options: Record<string, string> = {}): RenderRequest => ({7 engine: 'goat', source, format: 'svg', options,8 metadata: { title: '', description: '' },9 presentation: { background: '', padding: 0, frame: false },10})1112const fixture = ' +--+\n |A |\n +--+'1314describe('GoAT edge-Wasm adapter', () => {15 it('matches the pinned Docker native fixture byte-for-byte', async () => {16 const result = await goatAdapter.render(request(fixture), new AbortController().signal)17 expect(result.body).toContain('<svg')18 expect(result.body).toMatch(/width="48" height="58"/)19 expect(createHash('sha256').update(result.body).digest('hex')).toBe('c12324f3c2d5c3dbe68f3661fd617133121b25f4da6e8d170dce6118907a8330')20 })2122 it('preserves leading whitespace and exact ASCII defaults', async () => {23 const result = await goatAdapter.render(request(' +--+\n |A |\n +--+'), new AbortController().signal)24 expect(result.body).toMatch(/width="48" height="58"/)25 expect(result.body).toContain('color: #000')26 expect(result.body).toContain('color: #FFF')27 })2829 it('uses UTF-8 mode by option presence, including an empty value', async () => {30 const result = await goatAdapter.render(request('┌──┐\n│A │\n└──┘', { utf8: '' }), new AbortController().signal)31 expect(result.body).toContain('<svg')32 expect(result.body).toContain('A')33 })3435 it('retains the light and dark color CSS branches', async () => {36 const result = await goatAdapter.render(request('box', {37 'svg-color-light-scheme': '#123456', 'svg-color-dark-scheme': 'rgb(255, 0, 0)',38 }), new AbortController().signal)39 expect(result.body).toContain('color: #123456')40 expect(result.body).toContain('color: rgb(255, 0, 0)')41 expect(result.body).toContain('prefers-color-scheme: dark')42 })4344 it('rejects unknown, unsafe, malformed, and oversized inputs', async () => {45 const invalidOptions: Record<string, string>[] = [46 { css: 'x' },47 { 'svg-color-light-scheme': 'rgb(0,0,0);fill:url(https://x)' },48 { 'svg-color-light-scheme': 'rgb(0, 0' },49 { 'svg-color-light-scheme': 'var(--x)' },50 ]51 for (const options of invalidOptions) await expect(goatAdapter.render(request('box', options), new AbortController().signal)).rejects.toMatchObject({ status: 400 })52 await expect(goatAdapter.render(request('é'.repeat(140_000)), new AbortController().signal)).rejects.toMatchObject({ status: 413 })53 })5455 it('is stable across sequential and concurrent calls', async () => {56 const signal = new AbortController().signal57 const sequential = await Promise.all([1, 2, 3].map(() => goatAdapter.render(request(fixture), signal)))58 expect(new Set(sequential.map(result => result.body)).size).toBe(1)59 const concurrent = await Promise.all([60 goatAdapter.render(request(' +--+\n |A |\n +--+'), signal),61 goatAdapter.render(request(' +----+\n | B |\n +----+'), signal),62 goatAdapter.render(request(' +-----+\n | C |\n +-----+'), signal),63 ])64 expect(concurrent.every(result => result.body.includes('<svg'))).toBe(true)65 })66})