/** * impeccable fixture pins (commit 1 of the design-detector interop). * * gstack never runs impeccable's engine in CI. What the detector wrapper and * the catalog rely on is pinned here from real captures instead: * - the rule registry (61 ids) at the commit the engine-v0.1.3 release shipped * - the `detect --json` output shape over gstack's own planted-slop fixture, * once as a source scan and once over the rendered-DOM dump that * lib/dom-dump-script.ts produces through the browse engine * - the dump script's own contract (IIFE, no single quotes, no `${`) * Re-capture protocol: test/fixtures/impeccable-captures.meta.json. */ import { describe, test, expect } from 'bun:test'; import * as fs from 'fs'; import * as path from 'path'; import { DOM_DUMP_SCRIPT, DOM_DUMP_STYLE_ATTR, DOM_DUMP_NOTE_PREFIX, DOM_DUMP_FILE } from '../lib/dom-dump-script'; const FIXTURES = path.join(import.meta.dir, 'fixtures'); const read = (name: string) => fs.readFileSync(path.join(FIXTURES, name), 'utf-8'); const json = (name: string) => JSON.parse(read(name)); interface RegistryEntry { id: string; name: string; category: string; description: string } interface Finding { antipattern: string; name: string; description: string; severity: string; category: string; file: string; line: number; snippet: string; } const registry = json('impeccable-antipatterns.json') as { _source: Record; rules: RegistryEntry[] }; const sourceSample = json('impeccable-detect-sample.json') as Finding[]; const domSample = json('impeccable-detect-dom-sample.json') as Finding[]; const meta = json('impeccable-captures.meta.json'); const dump = read('review-eval-design-slop.dom.html'); const registryIds = new Set(registry.rules.map(r => r.id)); const categoryOf = new Map(registry.rules.map(r => [r.id, r.category])); describe('impeccable rule registry fixture', () => { test('is the upstream file at a pinned commit', () => { expect(registry._source.path).toBe('crates/live/assets/antipatterns.json'); expect(registry._source.commit).toMatch(/^[0-9a-f]{40}$/); expect(registry._source.engineRelease).toBe('engine-v0.1.3'); expect(meta.registry.commit).toBe(registry._source.commit); }); test('has 61 well-formed entries with unique kebab-case ids', () => { expect(registry.rules.length).toBe(61); expect(meta.registry.entries).toBe(61); for (const r of registry.rules) { expect(r.id).toMatch(/^[a-z0-9]+(-[a-z0-9]+)*$/); expect(r.name.length).toBeGreaterThan(0); expect(r.description.length).toBeGreaterThan(0); expect(['slop', 'quality']).toContain(r.category); } expect(registryIds.size).toBe(61); }); test('splits 32 slop / 29 quality', () => { const slop = registry.rules.filter(r => r.category === 'slop').length; expect(slop).toBe(32); expect(registry.rules.length - slop).toBe(29); }); test('carries the ids the doctrine names', () => { for (const id of ['side-tab', 'overused-font', 'nested-cards', 'kicker-above-heading', 'icon-tile-stack', 'gradient-text', 'ai-color-palette', 'cream-palette', 'dark-glow', 'pulsing-dot', 'em-dash-overuse', 'low-contrast', 'broken-image', 'design-system-font', 'design-system-color', 'design-system-radius', 'design-system-font-size']) { expect(registryIds.has(id)).toBe(true); } }); }); function checkFindings(sample: Finding[], expectedFile: string) { expect(Array.isArray(sample)).toBe(true); expect(sample.length).toBeGreaterThan(0); for (const f of sample) { expect(Object.keys(f).sort()).toEqual(meta.findingFields.slice().sort()); expect(registryIds.has(f.antipattern)).toBe(true); expect(f.category).toBe(categoryOf.get(f.antipattern)); expect(typeof f.severity).toBe('string'); expect(typeof f.line).toBe('number'); expect(typeof f.snippet).toBe('string'); expect(f.file).toBe(expectedFile); expect(f.file.startsWith('/')).toBe(false); } } describe('detect --json source-scan sample', () => { test('is a real capture over the planted-slop fixture, paths normalized', () => { checkFindings(sourceSample, 'test/fixtures/review-eval-design-slop.html'); expect(meta.captures['impeccable-detect-sample.json'].exit).toBe(2); }); test('contains a deterministic slop id and a quality id', () => { const ids = new Set(sourceSample.map(f => f.antipattern)); expect(ids.has('ai-color-palette')).toBe(true); expect(ids.has('low-contrast')).toBe(true); }); }); describe('detect --json DOM-dump sample', () => { test('is a real capture over the committed dump, paths normalized', () => { checkFindings(domSample, 'test/fixtures/review-eval-design-slop.dom.html'); expect(meta.captures['impeccable-detect-dom-sample.json'].exit).toBe(2); expect(meta.captures['impeccable-detect-dom-sample.json'].stderrBytes).toBe(0); }); test('the static engine reads inlined