Files
Imhotep/packages/imhotep-playwright/src/determinism.test.ts
T

86 lines
2.9 KiB
TypeScript
Raw Normal View History

/**
* Playwright determinism proof tests.
*
* Verifies that the public API honours seed and deterministic options,
* and that execution context propagates correctly through the UI handle.
*/
import { describe, it } from 'node:test'
import assert from 'node:assert'
import { createDeterministicContext, createVolatileContext } from 'imhotep-core'
import type { ExecutionContext } from 'imhotep-core'
// We cannot import `imhotep` directly here because it requires a real
// Playwright page. Instead we test the context factory logic in isolation.
// Full integration tests belong in the fixtures e2e suite.
describe('Playwright determinism', () => {
it('createDeterministicContext with same seed produces identical rng', () => {
const ctx1 = createDeterministicContext(99)
const ctx2 = createDeterministicContext(99)
assert.deepStrictEqual(
[ctx1.rng(), ctx1.rng(), ctx1.rng()],
[ctx2.rng(), ctx2.rng(), ctx2.rng()],
)
})
it('createDeterministicContext produces stable ids', () => {
const ctx = createDeterministicContext(7)
assert.strictEqual(ctx.idGenerator(), 'id-1')
assert.strictEqual(ctx.idGenerator(), 'id-2')
assert.strictEqual(ctx.idGenerator(), 'id-3')
})
it('createDeterministicContext clock is stable', () => {
const ctx = createDeterministicContext(7)
assert.strictEqual(ctx.clock(), 0)
assert.strictEqual(ctx.clock(), 0)
})
it('createVolatileContext clock advances', () => {
const ctx = createVolatileContext()
const t1 = ctx.clock()
const t2 = ctx.clock()
assert.ok(t2 >= t1)
})
it('parallel contexts with same seed produce identical sequences', () => {
const ctxA = createDeterministicContext(1)
const ctxB = createDeterministicContext(1)
assert.deepStrictEqual(
[ctxA.rng(), ctxA.rng()],
[ctxB.rng(), ctxB.rng()],
'same seed must yield same rng sequence',
)
})
it('parallel contexts with different seeds do not interfere', () => {
const ctxA = createDeterministicContext(1)
const ctxB = createDeterministicContext(2)
const idsA = [ctxA.idGenerator(), ctxA.idGenerator()]
const idsB = [ctxB.idGenerator(), ctxB.idGenerator()]
assert.deepStrictEqual(idsA, ['id-1', 'id-2'])
assert.deepStrictEqual(idsB, ['id-1', 'id-2'])
assert.notDeepStrictEqual(
[ctxA.rng(), ctxA.rng()],
[ctxB.rng(), ctxB.rng()],
'different seeds must yield different rng sequences',
)
})
it('property runner seeds are stored in replay metadata', () => {
// This is a contract test: replay metadata must carry the seed.
const meta = {
version: 1 as const,
seed: 42,
numRuns: 100,
sceneTarget: { kind: 'fixture' as const, fixtureId: 'test.html' },
inputDomain: { mode: 'generated' as const, arbitrary: 'record' },
timestamp: new Date().toISOString(),
}
assert.strictEqual(meta.seed, 42)
assert.strictEqual(meta.numRuns, 100)
})
})