v1.1.0: pooled runtime, 959 tests, production hardening (0 squash)

This commit is contained in:
John Dvorak
2025-08-15 10:00:00 -07:00
commit 92deb689cd
321 changed files with 79170 additions and 0 deletions
+36
View File
@@ -0,0 +1,36 @@
// examples/failing-test.js
// Example of a failing layout assertion and the diagnostic information
// you can extract from the failure.
//
// In V1.0, failures are surfaced through standard Playwright assertions.
// The extracted geometry gives you raw measured values for debugging.
const { test, expect } = require('@playwright/test')
const { imhotep } = require('imhotep-playwright')
test('failing gap assertion shows diagnostics', async ({ page }) => {
await page.goto('https://example.com')
const ui = await imhotep(page)
const leftData = await ui.extract('.left-box')
const rightData = await ui.extract('.right-box')
expect(leftData.length).toBeGreaterThanOrEqual(1)
expect(rightData.length).toBeGreaterThanOrEqual(1)
const left = leftData[0].rect
const right = rightData[0].rect
// Calculate the actual gap between the two boxes
const actualGap = right.x - (left.x + left.width)
console.log('Diagnostic output:')
console.log(` Left box: x=${left.x}, width=${left.width}`)
console.log(` Right box: x=${right.x}, width=${right.width}`)
console.log(` Actual gap: ${actualGap}px`)
console.log(` Required: at least 16px`)
// This assertion will fail if the gap is too small.
// The console output above gives you the exact measured values.
expect(actualGap).toBeGreaterThanOrEqual(16)
})
+39
View File
@@ -0,0 +1,39 @@
// examples/page-test.js
// Simple page layout test using Imhotep extraction and Playwright assertions.
//
// This is the primary working pattern in V1.0: use ui.extract() to get
// element geometry, then assert with Playwright's expect().
const { test, expect } = require('@playwright/test')
const { imhotep } = require('imhotep-playwright')
test('page layout relations', async ({ page }) => {
// Navigate to a page with a known layout
await page.goto('https://example.com')
// Attach Imhotep to the page
const ui = await imhotep(page)
// Extract geometry for the elements we want to verify
const headerData = await ui.extract('header')
const navData = await ui.extract('nav')
const mainData = await ui.extract('main')
// All selectors should resolve to at least one element
expect(headerData.length).toBeGreaterThanOrEqual(1)
expect(navData.length).toBeGreaterThanOrEqual(1)
expect(mainData.length).toBeGreaterThanOrEqual(1)
const header = headerData[0].rect
const nav = navData[0].rect
const main = mainData[0].rect
// Layout law: nav should be below header with at least 8px gap
expect(nav.y).toBeGreaterThanOrEqual(header.y + header.height + 8)
// Layout law: main should be below nav
expect(main.y).toBeGreaterThanOrEqual(nav.y + nav.height)
// Layout law: header should span full width
expect(header.width).toBeGreaterThanOrEqual(320)
})
+51
View File
@@ -0,0 +1,51 @@
// examples/responsive-test.js
// Responsive layout test: verify layout invariants across multiple viewports.
//
// Use ui.applyEnvironment() to resize the viewport, then extract geometry
// and assert layout laws. This replaces writing separate tests per breakpoint.
const { test, expect } = require('@playwright/test')
const { imhotep } = require('imhotep-playwright')
test('responsive sidebar layout', async ({ page }) => {
await page.goto('https://example.com')
const ui = await imhotep(page)
const viewports = [
{ width: 375, height: 667, name: 'mobile' },
{ width: 768, height: 1024, name: 'tablet' },
{ width: 1280, height: 720, name: 'desktop' },
]
for (const vp of viewports) {
// Apply the environment case
await ui.applyEnvironment({
viewport: { width: vp.width, height: vp.height },
})
// Reload so the page lays out at the new size
await page.reload()
await page.waitForLoadState('networkidle')
const sidebarData = await ui.extract('.sidebar')
const contentData = await ui.extract('.content')
expect(sidebarData.length).toBeGreaterThanOrEqual(1)
expect(contentData.length).toBeGreaterThanOrEqual(1)
const sidebar = sidebarData[0].rect
const content = contentData[0].rect
if (vp.name === 'mobile') {
// Mobile: sidebar stacks above content
expect(sidebar.y + sidebar.height).toBeLessThanOrEqual(content.y + 1)
// Mobile: sidebar should be nearly full width
expect(sidebar.width).toBeGreaterThanOrEqual(vp.width * 0.8)
} else {
// Tablet and desktop: sidebar is left of content
expect(sidebar.x + sidebar.width).toBeLessThanOrEqual(content.x + 1)
// Sidebar should have a fixed or minimum width
expect(sidebar.width).toBeGreaterThanOrEqual(200)
}
}
})
+59
View File
@@ -0,0 +1,59 @@
// examples/solver-direct-test.js
// Direct solver usage: evaluate layout assertions against a mock GeometryWorld.
//
// This bypasses the browser and tests the geometry logic engine directly.
// Useful for unit testing layout invariants without a browser overhead.
import { evaluate, registerDefaultClauses } from 'imhotep-solver'
// Register the built-in clause evaluators
registerDefaultClauses()
// Build a minimal GeometryWorld with two boxes
const world = {
boxes: {
boxId: new Uint32Array([1, 2]),
subjectId: new Uint32Array([1, 2]),
frameId: new Uint32Array([0, 0]),
borderLeft: new Float64Array([0, 110]),
borderTop: new Float64Array([0, 0]),
borderRight: new Float64Array([100, 210]),
borderBottom: new Float64Array([50, 50]),
paddingLeft: new Float64Array([0, 0]),
paddingTop: new Float64Array([0, 0]),
paddingRight: new Float64Array([0, 0]),
paddingBottom: new Float64Array([0, 0]),
contentLeft: new Float64Array([0, 110]),
contentTop: new Float64Array([0, 0]),
contentRight: new Float64Array([100, 210]),
contentBottom: new Float64Array([50, 50]),
},
}
// Define a clause: subject 1 should be left of subject 2 with gap 8-16
const clauses = [
{
clauseKind: 'relation.leftOf',
version: 1,
clauseId: 'clause_1',
subjectRef: 1,
referenceRef: 2,
bounds: { minGap: 8, maxGap: 16 },
},
]
// Evaluate the clause
const result = evaluate(world, clauses)
console.log('Solver direct evaluation:')
console.log(` Passed: ${result.clauseResults.every((r) => r.status === 'pass')}`)
for (const clauseResult of result.clauseResults) {
console.log(` Clause ${clauseResult.clauseId}: ${clauseResult.status}`)
if (clauseResult.metrics) {
console.log(` Observed gap: ${clauseResult.metrics.observedGap}px`)
console.log(` Required: ${clauseResult.metrics.minGap}px to ${clauseResult.metrics.maxGap}px`)
}
}
// This will pass because the gap is 10px (110 - 100), which is within 8-16.
+45
View File
@@ -0,0 +1,45 @@
// examples/state-test.js
// State materialization test: verify geometry changes between default, hover,
// and focus-visible states.
//
// Imhotep can materialize CSS pseudo-states without manual interaction
// choreography. This is useful for testing focus rings, hover expansions,
// and active press states.
const { test, expect } = require('@playwright/test')
const { imhotep } = require('imhotep-playwright')
test('button state geometry', async ({ page }) => {
await page.goto('https://example.com')
const ui = await imhotep(page)
// Default state
await ui.materializeState('.button', 'default')
const defaultData = await ui.extract('.button')
const defaultRect = defaultData[0].rect
// Hover state
await ui.materializeState('.button', 'hover')
const hoverData = await ui.extract('.button')
const hoverRect = hoverData[0].rect
// Focus-visible state
await ui.materializeState('.button', 'focus-visible')
const focusData = await ui.extract('.button')
const focusRect = focusData[0].rect
// Hover should not shrink the button
expect(hoverRect.width).toBeGreaterThanOrEqual(defaultRect.width)
// Focus-visible should show an outline (geometry may expand)
expect(focusRect.width).toBeGreaterThanOrEqual(defaultRect.width)
// Active state (pressed)
await ui.materializeState('.button', 'active')
const activeData = await ui.extract('.button')
const activeRect = activeData[0].rect
// Active should not collapse to zero
expect(activeRect.width).toBeGreaterThan(0)
expect(activeRect.height).toBeGreaterThan(0)
})