91 lines
2.8 KiB
TypeScript
91 lines
2.8 KiB
TypeScript
|
|
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);
|
||
|
|
});
|
||
|
|
});
|