110 lines
3.8 KiB
TypeScript
110 lines
3.8 KiB
TypeScript
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'])
|
|
})
|
|
})
|