import { describe, expect, it } from 'vitest';
import { analyseDeckLayout, assertDeckLayoutSafe } from '../src/qa/deck-layout.js';
import { validateBrand } from '../src/brands/validate.js';
import { buildBrandSystem } from '../src/brands/engine/index.js';
// The deck lays content on fixed-size 16:9 slides, so the layout guard pins
// down the structural invariants that keep brand copy from clipping. The
// real generated deck must pass; a deck missing any invariant must fail.
const VALID_BRAND = {
name: 'OpenDesign',
tagline: 'The open-source, local-first alternative to Claude Design.',
description:
'OpenDesign is the official open-source, local-first alternative to Claude Design — an agent-native design platform that turns the coding agent into a full design studio, generating on-brand artifacts from a single source of truth.',
colors: [
{ role: 'background', hex: '#ffffff', oklch: '', name: 'White', usage: 'page' },
{ role: 'surface', hex: '#f6f6f6', oklch: '', name: 'Surface', usage: 'cards' },
{ role: 'foreground', hex: '#101010', oklch: '', name: 'Ink', usage: 'text' },
{ role: 'muted', hex: '#7a7a7a', oklch: '', name: 'Muted', usage: 'secondary text' },
{ role: 'border', hex: '#e6e6e6', oklch: '', name: 'Hairline', usage: 'borders' },
{ role: 'accent', hex: '#36ff14', oklch: '', name: 'Voltage', usage: 'CTAs' },
{ role: 'accent-secondary', hex: '#0a7d22', oklch: '', name: 'Pine', usage: 'success' },
],
};
function renderRealDeck(): string {
const brand = validateBrand({ ...VALID_BRAND }, 'https://open-design.ai');
const system = buildBrandSystem(brand);
const deck = system.files['artifacts/deck.html'];
if (!deck) throw new Error('expected a deck artifact in the brand system');
return deck;
}
describe('analyseDeckLayout', () => {
it('passes the real generated brand deck with no issues', () => {
const report = analyseDeckLayout(renderRealDeck());
expect(report.issues).toEqual([]);
expect(report.slideCount).toBeGreaterThanOrEqual(10);
});
it('assertDeckLayoutSafe does not throw on the real generated deck', () => {
expect(() => assertDeckLayoutSafe(renderRealDeck())).not.toThrow();
});
it('flags a document with no slides', () => {
const report = analyseDeckLayout('
not a deck
');
expect(report.issues.map((i) => i.code)).toContain('no-slides');
});
it('flags a frame that is not a size container', () => {
const html = `
hi
`;
const report = analyseDeckLayout(html);
expect(report.issues.map((i) => i.code)).toContain('frame-not-size-container');
});
it('flags a deck missing the shrink-to-fit runtime', () => {
const html = `
hi
`;
const report = analyseDeckLayout(html);
expect(report.issues.map((i) => i.code)).toContain('fit-runtime-missing');
});
it('flags a slide body without a .f-fit layer', () => {
const html = `
unprotected
`;
const report = analyseDeckLayout(html);
expect(report.issues.map((i) => i.code)).toContain('fit-layer-missing');
});
it('flags a headline/lede slot that uses a line-clamp truncation class', () => {
const html = `
A headline that will be cut
`;
const report = analyseDeckLayout(html);
expect(report.issues.map((i) => i.code)).toContain('headline-truncation');
});
it('flags a funnel track that carries its value label inline', () => {
const html = `