openpencil/tests/engine/render/jsx/gaps.test.ts
Danila Poyarkov f047b0bcb4 fix(svg): preserve explicit none paints
- Normalize SVG paint sentinels before creating icon vector nodes
- Keep inline outline artwork transparent instead of falling back to black
- Cover fill and stroke none values through the Design JSX renderer

Co-authored-by: Rob Coenen <753704+rcoenen@users.noreply.github.com>
2026-08-01 15:42:46 +03:00

76 lines
2.7 KiB
TypeScript

import { describe, expect, it } from 'bun:test'
import { renderJSX } from '@open-pencil/core'
import { makeSceneGraph } from '#tests/helpers/scene'
describe('jsx gaps', () => {
it('mask prop sets isMask + maskType', async () => {
const g = makeSceneGraph()
await renderJSX(
g,
`<Frame name="m" w={80} h={80}><Ellipse mask w={40} h={40} /><Rectangle w={80} h={80} bg="#f00" /></Frame>`
)
const ellipse = [...g.nodes.values()].find((n) => n.type === 'ELLIPSE')
expect(ellipse?.isMask).toBe(true)
expect(ellipse?.maskType).toBe('ALPHA')
})
it('svg element renders vector paths', async () => {
const g = makeSceneGraph()
await renderJSX(
g,
`<svg viewBox="0 0 24 24" w={24} h={24}><path d="M12 21s-7-4.5-9.5-9C0.5 8 2 4 6 4c2.5 0 4 1.5 6 3 2-1.5 3.5-3 6-3 4 0 5.5 4 3.5 8-2.5 4.5-9.5 9-9.5 9z"/></svg>`
)
const vector = [...g.nodes.values()].find((n) => n.type === 'VECTOR')
expect(vector).toBeTruthy()
expect(vector?.vectorNetwork).toBeTruthy()
})
it('renders open and closed SVG paths as separate stroked vectors', async () => {
const g = makeSceneGraph()
await renderJSX(
g,
`<svg viewBox="0 0 24 24" size={24}><path d="M2 2 L22 2" stroke="#000" fill="none" /><path d="M2 6 H22 V22 H2 Z" stroke="#000" fill="none" /></svg>`
)
const vectors = [...g.nodes.values()].filter((node) => node.type === 'VECTOR')
expect(vectors).toHaveLength(2)
for (const vector of vectors) {
expect(vector.vectorNetwork?.vertices.length).toBeGreaterThan(0)
expect(vector.strokes.length).toBeGreaterThan(0)
}
})
it('respects none paints on inline SVG paths', async () => {
const g = makeSceneGraph()
await renderJSX(
g,
`<svg viewBox="0 0 24 24" w={24} h={24}>
<path d="M2 2L22 22" fill="none" stroke="#021A3B" stroke-width="2" />
<path d="M2 22L12 2L22 22Z" fill="#FF0000" stroke="none" />
</svg>`
)
const vectors = [...g.nodes.values()].filter((node) => node.type === 'VECTOR')
expect(vectors).toHaveLength(2)
expect(vectors[0].fills).toEqual([])
expect(vectors[0].strokes).toHaveLength(1)
expect(vectors[1].fills).toHaveLength(1)
expect(vectors[1].strokes).toEqual([])
})
it('instance overrides apply child text by name', async () => {
const g = makeSceneGraph()
await renderJSX(
g,
`<Component name="Badge" w={60} h={24}><Text name="label">+0%</Text></Component>
<Instance of="Badge" overrides={{ 'label:text': '+14%' }} />`
)
const inst = [...g.nodes.values()].find((n) => n.type === 'INSTANCE')
const label = [...g.nodes.values()].find(
(n) => n.type === 'TEXT' && inst && n.parentId === inst.id
)
expect(label?.text).toBe('+14%')
})
})