updated design

This commit is contained in:
SinachPat
2026-04-25 22:52:30 +01:00
parent df79ae0bca
commit e836ac6d2b
22 changed files with 3480 additions and 781 deletions
@@ -0,0 +1,80 @@
import { describe, it, expect } from 'vitest';
import { serializeSnapshot, serializeValue } from '../src/serialize.js';
import type { ComponentSnapshot } from '../src/schemas.js';
const snap: ComponentSnapshot = {
id: 'btn-1',
name: 'Button',
filePath: 'src/components/Button.tsx',
props: { variant: 'primary', size: 'md', disabled: false },
styles: { borderRadius: '8px', background: '#0066FF' },
};
describe('serializeSnapshot', () => {
it('includes component name and filePath', () => {
const out = serializeSnapshot(snap);
expect(out).toContain('Component: Button [src/components/Button.tsx]');
});
it('sorts props alphabetically for stable diffs', () => {
const out = serializeSnapshot(snap);
const propLines = out.split('\n').filter(l => l.includes(':') && !l.includes('Component'));
const propNames = propLines
.map(l => l.trim().split(':')[0]!.trim())
.filter(k => ['disabled', 'size', 'variant', 'background', 'borderRadius'].includes(k));
// disabled < size < variant (alphabetical)
const dIdx = propNames.indexOf('disabled');
const sIdx = propNames.indexOf('size');
const vIdx = propNames.indexOf('variant');
expect(dIdx).toBeLessThan(sIdx);
expect(sIdx).toBeLessThan(vIdx);
});
it('sorts styles alphabetically', () => {
const out = serializeSnapshot(snap);
const bgIdx = out.indexOf('background:');
const brIdx = out.indexOf('borderRadius:');
expect(bgIdx).toBeLessThan(brIdx);
});
it('produces identical output for same input (deterministic)', () => {
expect(serializeSnapshot(snap)).toBe(serializeSnapshot(snap));
});
it('handles component without filePath', () => {
const out = serializeSnapshot({ id: 'x', name: 'Foo', props: {} });
expect(out).toBe('Component: Foo');
});
it('handles empty props and styles', () => {
const out = serializeSnapshot({ id: 'x', name: 'Foo', props: {}, styles: {} });
expect(out).not.toContain('Props:');
expect(out).not.toContain('Styles:');
});
it('serializes nested children', () => {
const withChild: ComponentSnapshot = {
...snap,
children: [{ id: 'icon', name: 'Icon', props: { name: 'check' } }],
};
const out = serializeSnapshot(withChild);
expect(out).toContain('Children:');
expect(out).toContain('[0]');
expect(out).toContain('Component: Icon');
});
});
describe('serializeValue', () => {
it('wraps strings in quotes', () => expect(serializeValue('hello')).toBe('"hello"'));
it('renders numbers as-is', () => expect(serializeValue(42)).toBe('42'));
it('renders booleans', () => {
expect(serializeValue(true)).toBe('true');
expect(serializeValue(false)).toBe('false');
});
it('renders null', () => expect(serializeValue(null)).toBe('null'));
it('renders undefined', () => expect(serializeValue(undefined)).toBe('undefined'));
it('renders arrays', () => expect(serializeValue([1, 'a'])).toBe('[1, "a"]'));
it('renders objects with sorted keys', () => {
expect(serializeValue({ z: 1, a: 2 })).toBe('{ a: 2, z: 1 }');
});
});