import { describe, expect, it } from 'vitest'; import { decodeSduiScreenWire } from '@proulr/sdui-contract'; import { compileBdcBlock, compileBdcToWire } from './compile-bdc-to-wire'; import type { BdcElement } from './jsx-runtime'; function screen(props: Record, children: BdcElement[]): BdcElement { return { type: 'screen', props, children }; } describe('BDC compile → contract decode integration', () => { it('round-trips a full BDC tree including header slots and derived labels', () => { const slot: BdcElement = { type: 'chip_row', props: { id: 'slot' }, children: [], }; const wire = compileBdcToWire( screen( { id: 'demo.home', title: 'Demo', data: { city: 'sp' }, header: { title: 'Home', headerSearch: true, brandMode: true, slotBlocks: [{ type: 'ignored' }], }, headerSlot: [slot, { type: 'chip', props: {}, children: [] }], actions: { go: { type: 'navigate', path: '/x' }, }, meta: { bff: 'demo-bff', cache_ttl_ms: 12_000, stale_policy: 'cache_only' }, }, [ { type: 'column', props: { gap: 8, id: 'root' }, children: [ { type: 'button', props: { actionId: 'go', style: { paddingTop: 8, marginBottom: 4 } }, children: [ { type: '_text_node', props: { value: ' Press ' }, children: [] }, { type: 'text', props: { text: 'me' }, children: [] }, ], }, { type: 'text', props: {}, children: [{ type: '_text_node', props: { value: 'Body' }, children: [] }], }, { type: '_fragment', props: {}, children: [], }, { type: 'button', props: { actionId: 'send_message', label: 'Send' }, children: [], }, ], }, ], ), ); expect(wire.schema_version).toBe(1); expect(wire.screen_id).toBe('demo.home'); expect(wire.header).toMatchObject({ title: 'Home', header_search: true, brand_mode: true, }); expect(wire.header?.slot_blocks).toHaveLength(2); expect(wire.blocks[0]?.props).toMatchObject({ gap: 8 }); expect(wire.blocks[0]?.children?.[0]?.props).toMatchObject({ action_id: 'go', label: 'Press me', style: { padding_top: 8, margin_bottom: 4 }, }); expect(wire.blocks[0]?.children?.[1]?.props?.text).toBe('Body'); expect(wire.blocks[0]?.children?.[2]?.props).toMatchObject({ action_id: 'send_message', label: 'Send', }); const decoded = decodeSduiScreenWire(wire); expect(decoded.screenId).toBe('demo.home'); expect(decoded.blocks).toHaveLength(1); expect(decoded.blocks[0]?.type).toBe('column'); expect(decoded.data).toEqual({ city: 'sp' }); expect(decoded.meta.bff).toBe('demo-bff'); }); it('rejects non-screen roots and compiles lone text nodes', () => { expect(() => compileBdcToWire({ type: 'stack', props: {}, children: [] }), ).toThrow(/bdc_root_must_be_screen/); const block = compileBdcBlock({ type: '_text_node', props: { value: 'x' }, children: [], }); expect(block).toEqual({ id: '0', type: 'text', props: { text: 'x' } }); const empty = compileBdcToWire(screen({ id: 'empty' }, [])); expect(empty.data).toEqual({}); expect(empty.actions).toEqual({}); expect(empty.meta).toMatchObject({ cache_ttl_ms: 30_000 }); }); });