Audit pass: - Frame rule counts frames since the last move, so every step lasts exactly movesEvery(score) frames, also right after a speed-up - clampTime + MAX_GAP_MS: a hidden tab no longer replays the whole gap - Pong Restart keeps held keys - Fact corrections (mulberry32 output coverage, Haskell IO, uniform) - New fixture cases from a mutation analysis Extensions (all three tracks, shared fixtures, course text): - Turn queue (Exercise 10.6), persisted high score (10.7), replay viewer (10.8), play() end-to-end helper (9.5) - Optional State (4.7) and optional Module 7b, stack-safe IO - Module 12, property-based testing with generators, shrinking, invariants and a model-based oracle - Module 13, Conway's Life with a Click event - JS type checking via jsconfig, JSDoc and types.d.ts - Maintainer tools: scripts/mutate.mjs, scripts/typecheck-js.sh, Playwright end-to-end suite (e2e/, scripts/e2e.sh) Docs: docs/contract.md is the canonical contract; specs and build log under docs/superpowers. Verified: JS 728, Scala 689, F# 691 unit tests; stubs and progression M01-M13 and M07b; 176 end-to-end tests on Chromium and WebKit. Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
55 lines
2.5 KiB
JavaScript
55 lines
2.5 KiB
JavaScript
// Playwright configuration for the end-to-end tests. Run through scripts/e2e.sh, which builds and serves a copy of the
|
|
// repository whose <track>/src holds the solutions and passes its address in E2E_BASE_URL.
|
|
//
|
|
// Browsers: Chromium and WebKit, and Firefox if a build is installed. Nothing is ever downloaded. If the exact build
|
|
// this Playwright version expects is missing but another revision of the same browser is in the Playwright cache
|
|
// (~/.cache/ms-playwright, or PLAYWRIGHT_BROWSERS_PATH), that one is used and named; if there is none, the project is
|
|
// left out with a message.
|
|
import { defineConfig, chromium, webkit, firefox } from '@playwright/test'
|
|
import { existsSync, readdirSync } from 'node:fs'
|
|
import { homedir } from 'node:os'
|
|
import { join } from 'node:path'
|
|
|
|
const cache = process.env.PLAYWRIGHT_BROWSERS_PATH || join(homedir(), '.cache', 'ms-playwright')
|
|
const launchers = {
|
|
chromium: ['chrome-linux64/chrome', 'chrome-linux/chrome'],
|
|
webkit: ['pw_run.sh'],
|
|
firefox: ['firefox/firefox'],
|
|
}
|
|
// Print the notes once, from the main process, not again from every worker.
|
|
const say = (msg) => { if (!process.env.TEST_WORKER_INDEX) console.log(msg) }
|
|
|
|
const browser = (name, type) => {
|
|
if (existsSync(type.executablePath())) return { name, use: { browserName: name } }
|
|
const other = existsSync(cache)
|
|
? readdirSync(cache)
|
|
.filter((d) => new RegExp(`^${name}-\\d+$`).test(d))
|
|
.sort((a, b) => Number(b.split('-')[1]) - Number(a.split('-')[1]))
|
|
.flatMap((d) => launchers[name].map((l) => join(cache, d, l)))
|
|
.find(existsSync)
|
|
: undefined
|
|
if (other) {
|
|
say(`e2e: ${name}: the expected build is not installed; using ${other}`)
|
|
return { name, use: { browserName: name, launchOptions: { executablePath: other } } }
|
|
}
|
|
say(`e2e: ${name}: no build installed, skipping this project (npx playwright install ${name} would download one)`)
|
|
return null
|
|
}
|
|
|
|
export default defineConfig({
|
|
testDir: 'tests',
|
|
fullyParallel: true,
|
|
workers: process.env.E2E_WORKERS ? Number(process.env.E2E_WORKERS) : '50%',
|
|
forbidOnly: true,
|
|
retries: 0,
|
|
timeout: 60_000,
|
|
reporter: [['list'], ['html', { open: 'never', outputFolder: 'playwright-report' }]],
|
|
outputDir: 'test-results',
|
|
use: {
|
|
baseURL: process.env.E2E_BASE_URL ?? 'http://127.0.0.1:8000',
|
|
viewport: { width: 1280, height: 900 },
|
|
trace: 'retain-on-failure',
|
|
},
|
|
projects: [browser('chromium', chromium), browser('webkit', webkit), browser('firefox', firefox)].filter(Boolean),
|
|
})
|