import { beforeAll, describe, expect, it } from 'vitest'; import { resolveLayout } from '../src/index.js'; import { ensureEngineReady } from './_setup.js'; import { fixture } from './fixtures/demo-300x250.fixture.js'; describe('resolveLayout — integration against demo fixture', () => { beforeAll(async () => { await ensureEngineReady(); }); it('resolves a short headline without overflow or sibling pushes', () => { const out = resolveLayout(fixture, { headline: 'Hi', subheadline: 'Sub', cta: 'Go' }); expect(out).toHaveLength(1); const artboard = out[0]!; expect(artboard.artboard_id).toBe('300x250'); const headline = artboard.layers.find((l) => l.layer_id === 'headline'); expect(headline).toBeDefined(); // A trivial single-word headline should fit at or near max font size and // never trigger overflow. expect(headline!.layout_log?.overflow_triggered).toBe(false); expect(headline!.layout_log?.siblings_pushed).toEqual([]); expect(headline!.computed_font_size).toBeGreaterThanOrEqual(18); expect(headline!.computed_font_size).toBeLessThanOrEqual(28); }); it('shrinks or pushes when headline is too long', () => { const out = resolveLayout(fixture, { headline: 'A really long headline copy that should not fit at the original font size', subheadline: 'Sub copy goes here', cta: 'Shop now' }); const headline = out[0]!.layers.find((l) => l.layer_id === 'headline')!; // Either shrunk or overflowed — both are valid outcomes given the layout. const shrunkOrOverflowed = headline.layout_log!.font_size_reduced || headline.layout_log!.overflow_triggered; expect(shrunkOrOverflowed).toBe(true); expect(headline.character_count).toBeGreaterThan(30); }); it('populates layout_log on every text layer', () => { const out = resolveLayout(fixture, { headline: 'Hi', subheadline: 'Sub', cta: 'Go' }); const textLayers = out[0]!.layers.filter((l) => l.type === 'text'); expect(textLayers.length).toBeGreaterThan(0); for (const l of textLayers) { expect(l.layout_log).toBeDefined(); expect(typeof l.layout_log!.original_height).toBe('number'); expect(typeof l.layout_log!.computed_height).toBe('number'); } }); it('parity baseline: snapshot of the resolved layer geometry', () => { const out = resolveLayout(fixture, { headline: 'Hello world', subheadline: 'Subtitle line', cta: 'Shop now' }); // Snapshot only fields that are stable across dropflow patch releases: // ids, types, computed coords. Heights and font sizes can drift by a // pixel on font shaper updates and are checked structurally elsewhere. const sanitized = out.map((ab) => ({ artboard_id: ab.artboard_id, layers: ab.layers.map((l) => ({ layer_id: l.layer_id, type: l.type, computed_x: l.computed_x, computed_y: l.computed_y, character_count: l.character_count, font_size_reduced: l.layout_log?.font_size_reduced ?? null, overflow_triggered: l.layout_log?.overflow_triggered ?? null })) })); expect(sanitized).toMatchSnapshot(); }); });