2026-08-09 06:59:23 -07:00
|
|
|
import { describe, test, expect } from 'vitest';
|
|
|
|
|
import { deriveVirtualRows, VIRTUAL_CHILD_PROPS } from './layers-virtual-rows';
|
|
|
|
|
|
|
|
|
|
describe('deriveVirtualRows', () => {
|
|
|
|
|
test('returns one row per item, labelled by the registered field', () => {
|
|
|
|
|
const rows = deriveVirtualRows('Features Grid', {
|
|
|
|
|
features: [{ title: 'Fast' }, { title: 'Secure' }],
|
|
|
|
|
});
|
|
|
|
|
expect(rows).toEqual([
|
|
|
|
|
{ index: 0, label: 'Fast' },
|
|
|
|
|
{ index: 1, label: 'Secure' },
|
|
|
|
|
]);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('falls back to "<Fallback> N" when the label field is missing or blank', () => {
|
|
|
|
|
const rows = deriveVirtualRows('Features Grid', {
|
|
|
|
|
features: [{ title: '' }, { description: 'no title key' }],
|
|
|
|
|
});
|
|
|
|
|
expect(rows).toEqual([
|
|
|
|
|
{ index: 0, label: 'Feature 1' },
|
|
|
|
|
{ index: 1, label: 'Feature 2' },
|
|
|
|
|
]);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('trims and truncates a long label to 40 characters with an ellipsis', () => {
|
|
|
|
|
const long = 'x'.repeat(60);
|
|
|
|
|
const rows = deriveVirtualRows('Features Grid', { features: [{ title: ` ${long} ` }] });
|
|
|
|
|
expect(rows[0].label).toHaveLength(41);
|
|
|
|
|
expect(rows[0].label.endsWith('…')).toBe(true);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('an unregistered component yields no rows', () => {
|
|
|
|
|
expect(deriveVirtualRows('Heading', { text: 'hi' })).toEqual([]);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('a missing or non-array prop yields no rows instead of throwing', () => {
|
|
|
|
|
expect(deriveVirtualRows('Tabs', {})).toEqual([]);
|
|
|
|
|
expect(deriveVirtualRows('Tabs', { tabs: 'not an array' })).toEqual([]);
|
|
|
|
|
expect(deriveVirtualRows('Tabs', { tabs: null })).toEqual([]);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('a non-object item still gets a fallback label', () => {
|
|
|
|
|
expect(deriveVirtualRows('Menu', { links: ['raw string'] })).toEqual([
|
|
|
|
|
{ index: 0, label: 'Link 1' },
|
|
|
|
|
]);
|
|
|
|
|
});
|
|
|
|
|
|
2026-08-09 07:04:54 -07:00
|
|
|
test('Hero, Call to Action and CTA Section derive rows from their shared ctas prop', () => {
|
|
|
|
|
const ctas = [
|
|
|
|
|
{ text: 'Get Started', href: '#', variant: 'primary' },
|
|
|
|
|
{ text: 'Learn More', href: '#learn', variant: 'outline' },
|
|
|
|
|
];
|
|
|
|
|
expect(deriveVirtualRows('Hero', { ctas })).toEqual([
|
|
|
|
|
{ index: 0, label: 'Get Started' },
|
|
|
|
|
{ index: 1, label: 'Learn More' },
|
|
|
|
|
]);
|
|
|
|
|
expect(deriveVirtualRows('Call to Action', { ctas })).toEqual([
|
|
|
|
|
{ index: 0, label: 'Get Started' },
|
|
|
|
|
{ index: 1, label: 'Learn More' },
|
|
|
|
|
]);
|
|
|
|
|
expect(deriveVirtualRows('CTA Section', { ctas })).toEqual([
|
|
|
|
|
{ index: 0, label: 'Get Started' },
|
|
|
|
|
{ index: 1, label: 'Learn More' },
|
|
|
|
|
]);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('a CTA with no text falls back to "Button N"', () => {
|
|
|
|
|
const rows = deriveVirtualRows('Hero', {
|
|
|
|
|
ctas: [{ href: '#' }, { text: '', href: '#empty' }],
|
|
|
|
|
});
|
|
|
|
|
expect(rows).toEqual([
|
|
|
|
|
{ index: 0, label: 'Button 1' },
|
|
|
|
|
{ index: 1, label: 'Button 2' },
|
|
|
|
|
]);
|
|
|
|
|
});
|
|
|
|
|
|
2026-08-09 06:59:23 -07:00
|
|
|
test('every registry entry has a non-empty prop, label and fallback', () => {
|
|
|
|
|
for (const [name, spec] of Object.entries(VIRTUAL_CHILD_PROPS)) {
|
|
|
|
|
expect(spec.prop, `${name}.prop`).toBeTruthy();
|
|
|
|
|
expect(spec.label, `${name}.label`).toBeTruthy();
|
|
|
|
|
expect(spec.fallback, `${name}.fallback`).toBeTruthy();
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
});
|