import { test, expect } from '@playwright/test' import { imhotepFixture } from 'imhotep-playwright' import { enumeratedDomain } from 'imhotep-core/property-contracts' import { resolve } from 'node:path' import { fileURLToPath } from 'node:url' const __dirname = fileURLToPath(new URL('.', import.meta.url)) function fixtureUrl(name: string): string { return 'file://' + resolve(__dirname, 'pages', `${name}.html`) } test.describe('E2E: Fixture enumerated property run', () => { test('exhaustively evaluates all size combinations and stops on failure', async ({ page }) => { const handle = imhotepFixture(fixtureUrl('property-enumerated')) const domain = enumeratedDomain([ { size: 'sm', label: 'Small' }, { size: 'md', label: 'Medium' }, { size: 'lg', label: 'Large' }, ]) let evaluatedCases = 0 const result = await handle.exhaustivelyForAllInputs( page, domain, async (scene, ctx) => { evaluatedCases++ const data = await scene.extract('[data-testid="enumerated-button"]') expect(Array.isArray(data)).toBe(true) expect((data as any[]).length).toBe(1) const box = (data as any[])[0].rect as { width: number; height: number } const input = ctx.input as { size: string; label: string } // Assert button width changes with size if (input.size === 'sm') { expect(box.width).toBeGreaterThanOrEqual(60) expect(box.width).toBeLessThan(80) } else if (input.size === 'md') { expect(box.width).toBeGreaterThanOrEqual(80) expect(box.width).toBeLessThan(100) } else if (input.size === 'lg') { expect(box.width).toBeGreaterThanOrEqual(100) } } ) expect(result.passed).toBe(true) expect(result.mode).toBe('enumerated-determinate') expect(result.totalCases).toBe(3) expect(evaluatedCases).toBe(3) expect(result.diagnostics).toHaveLength(0) }) test('failing case stops with diagnostics', async ({ page }) => { const handle = imhotepFixture(fixtureUrl('property-enumerated')) const domain = enumeratedDomain([ { size: 'sm', label: 'A' }, { size: 'md', label: 'B' }, { size: 'lg', label: 'C' }, ]) let evaluatedCases = 0 const result = await handle.exhaustivelyForAllInputs( page, domain, async (scene, ctx) => { evaluatedCases++ const input = ctx.input as { size: string } // Force a failure on the md case if (input.size === 'md') { throw new Error('Intentional failure for testing diagnostics') } const data = await scene.extract('[data-testid="enumerated-button"]') expect((data as any[]).length).toBe(1) } ) expect(result.passed).toBe(false) expect(result.mode).toBe('enumerated-determinate') // Should have stopped at the failing case (md is second) expect(evaluatedCases).toBe(2) expect(result.failingCase).toEqual({ size: 'md', label: 'B' }) expect(result.diagnostics.length).toBeGreaterThan(0) expect((result.diagnostics[0] as any).code).toBe('IMH_ENUMERATED_RUN_ERROR') }) test('deterministic order with no randomness', async ({ page }) => { const handle = imhotepFixture(fixtureUrl('property-enumerated')) const domain = enumeratedDomain([ { size: 'sm' }, { size: 'md' }, { size: 'lg' }, ]) const order1: string[] = [] await handle.exhaustivelyForAllInputs(page, domain, async (_scene, ctx) => { order1.push((ctx.input as { size: string }).size) }) const order2: string[] = [] await handle.exhaustivelyForAllInputs(page, domain, async (_scene, ctx) => { order2.push((ctx.input as { size: string }).size) }) expect(order1).toEqual(['sm', 'md', 'lg']) expect(order2).toEqual(['sm', 'md', 'lg']) }) })