import { describe, test, expect } from 'vitest'; import { serializeTreeForCraft, __test } from './apply-ai-response'; describe('serializeTreeForCraft', () => { test('flattens nested tree', () => { const tree = { type: { resolvedName: 'Section' }, props: { aiName: 'Hero', node_id: 'ai-hero-1' }, nodes: [ { type: { resolvedName: 'Heading' }, props: { aiName: 'Title', node_id: 'ai-h-1', text: 'Welcome' }, nodes: [], }, ], }; const out = serializeTreeForCraft(tree); expect(out.rootNodeId).toBe('ai-hero-1'); expect((out.nodes['ai-hero-1'] as any).nodes).toEqual(['ai-h-1']); expect((out.nodes['ai-h-1'] as any).parent).toBe('ROOT'); }); test('auto-generates ids when node_id is missing', () => { const tree = { type: { resolvedName: 'Heading' }, props: {}, nodes: [] }; const out = serializeTreeForCraft(tree); expect(typeof out.rootNodeId).toBe('string'); expect(out.nodes[out.rootNodeId]).toBeDefined(); }); test('sets isCanvas true for layout components', () => { const tree = { type: { resolvedName: 'Container' }, props: { node_id: 'c1' }, nodes: [], }; const out = serializeTreeForCraft(tree); expect((out.nodes['ROOT'] as any).isCanvas).toBe(true); }); test('sets isCanvas false for leaf components', () => { const tree = { type: { resolvedName: 'Heading' }, props: { node_id: 'h1' }, nodes: [], }; const out = serializeTreeForCraft(tree); expect((out.nodes['ROOT'] as any).isCanvas).toBe(false); }); test('aliases root node to ROOT key', () => { const tree = { type: { resolvedName: 'Section' }, props: { node_id: 'ai-section-1' }, nodes: [], }; const out = serializeTreeForCraft(tree); expect(out.nodes['ROOT']).toBeDefined(); expect((out.nodes['ROOT'] as any).parent).toBeNull(); }); }); describe('findNodeIdByAiNodeId', () => { const query = { getNodes: () => ({ 'craft-id-1': { data: { props: { node_id: 'ai-hero-1' } } }, 'craft-id-2': { data: { props: { node_id: 'ai-cta-1' } } }, }), }; test('returns craft id for matching node_id prop', () => { expect(__test.findNodeIdByAiNodeId(query, 'ai-hero-1')).toBe('craft-id-1'); }); test('returns craft id for second entry', () => { expect(__test.findNodeIdByAiNodeId(query, 'ai-cta-1')).toBe('craft-id-2'); }); test('falls back to raw id match', () => { const q = { getNodes: () => ({ 'exact-id': { data: { props: {} } }, }), }; expect(__test.findNodeIdByAiNodeId(q, 'exact-id')).toBe('exact-id'); }); test('returns null when not found', () => { expect(__test.findNodeIdByAiNodeId({ getNodes: () => ({}) }, 'missing')).toBe(null); }); });