Run just the e2e steps you name
GM_STEPS=20, 1-12 or 6,20 takes a subset of the suite, which is seconds instead of two minutes while one step is being written. Steps live off what the earlier ones leave behind, so a subset that skips a prerequisite fails on purpose. The filter had been written as a throwaway script three times; it belongs in the runner. The README stops calling a remote browser the way this suite is meant to be run: with the GPU in use a local run costs ~124 s and about 0.8 of the four cores here, so GM_REMOTE is a convenience, not a requirement.
This commit is contained in:
1 parent
338ff4389f
commit
6ac6b69388
3 files changed
+43
-12
No files matched your search
@@ -541,10 +541,11 @@ npm run lint # ESLint, type-aware; --fix for the fixable half
|
||||
npm run format # Prettier over src, tests and tools
|
||||
npm run check # typecheck + lint + format:check + tests, what CI would run
|
||||
npm run build # writes dist/ and regenerates index.html
|
||||
export GM_REMOTE=user@host # where the browser runs; see below
|
||||
node tools/seed-e2e.mjs && node tools/e2e.mjs # 387 editor checks, screenshots in /tmp/gm-e2e-*.png
|
||||
export GM_REMOTE=user@host # optional: run the browser elsewhere; see below
|
||||
node tools/seed-e2e.mjs && node tools/e2e.mjs # 415 editor checks, screenshots in /tmp/gm-e2e-*.png
|
||||
GM_STEPS=20 node tools/e2e.mjs # or 1-12, or 6,20 – a subset while working on one step
|
||||
node tools/seed-jumprun.mjs && node tools/smoke-jumprun.mjs # 24 checks: the example game, played end to end
|
||||
node tools/seed-tetris.mjs && node tools/smoke-tetris.mjs # 17 checks: the Tetris example, played end to end
|
||||
node tools/seed-tetris.mjs && node tools/smoke-tetris.mjs # 19 checks: the Tetris example, played end to end
|
||||
```
|
||||
|
||||
**A run needs a working GPU.** An idle editor page keeps rendering a picture that never changes, and
|
||||
@@ -555,14 +556,18 @@ full suite takes ~124 s that way. `tools/lib/browser.mjs` therefore always asks
|
||||
machine down. (`--use-angle=gl` and `--use-gl=egl` measure cheaper still, but get no WebGL context at
|
||||
all, so the app never renders.)
|
||||
|
||||
**Run it here by default.** With the GPU in use the full suite costs ~124 s and roughly 0.8 of the
|
||||
four cores of this box (60% renderer, 18% GPU process, load ~1.0), which it carries fine. While one
|
||||
step is being worked on, `GM_STEPS` keeps a run to seconds – take the whole suite before a commit,
|
||||
or when a change touches drawing, the widget toolkit or anything else every step sees.
|
||||
|
||||
**`GM_REMOTE=user@host` moves the browser to another machine** – `tools/lib/browser.mjs` starts it
|
||||
over SSH and forwards its CDP port back to `127.0.0.1`, so the harness itself is unchanged. The
|
||||
checks load the public base URL, so the remote side needs only a browser and internet: no repo, no
|
||||
node. Setup is an SSH key (`GM_REMOTE_KEY`, default `~/.ssh/gm-win.key`). Measured against a Windows
|
||||
desktop with an RTX 4070: **the full suite in ~130 s and 24 smoke checks in 16 s, with this machine idle**
|
||||
(0.4 s of CPU for the whole smoke run, load average 0.04). **That is how the suite is meant to be
|
||||
run here.** A local run works and costs 124 s, but it pins the development box – set `GM_REMOTE` and
|
||||
leave it set; without a reachable host, do not fall back to local, fix the host.
|
||||
desktop with an RTX 4070: **the full suite in ~130 s and 24 smoke checks in 16 s, with this machine
|
||||
idle** (0.4 s of CPU for the whole smoke run, load average 0.04). Worth setting while the box is
|
||||
busy with something else; it is not required, and an unreachable host is no reason to skip a run.
|
||||
|
||||
`tools/remote/gm-browser.ps1` is copied over on every run, and getting the browser to die with the
|
||||
run took three tries, because two obvious leashes do not hold on Windows:
|
||||
@@ -593,10 +598,14 @@ to touch it.
|
||||
|
||||
The e2e run is a list of steps in `tools/e2e/` (hierarchy, inspector, play, assets, drawing,
|
||||
graph, parenting, colliders, containers, text/enabled, menus, textures, frames, overflow, aspect,
|
||||
container tab) that build
|
||||
on each other's scene state
|
||||
and share the CDP driver in `tools/lib/harness.mjs` – `press`, `undo`, `play`, `object(id)`,
|
||||
`world()`, `mutate(js)` and friends, so a check reads like the interaction it exercises.
|
||||
container tab, run-in-editor, pause, nested behaviors, key repeat) that build on each other's
|
||||
scene state and share the CDP driver in `tools/lib/harness.mjs` – `press`, `undo`, `play`,
|
||||
`object(id)`, `world()`, `mutate(js)` and friends, so a check reads like the interaction it
|
||||
exercises.
|
||||
|
||||
`GM_STEPS=20`, `GM_STEPS=1-12` or `GM_STEPS=6,20` runs a subset – seconds instead of minutes
|
||||
while one step is being written. Because a step lives off what the earlier ones left behind, a
|
||||
subset that skips a prerequisite fails on purpose; take `1-N` when in doubt.
|
||||
|
||||
**The example game** (`tools/seed-jumprun.mjs`, project *Jump and Run*) is a complete little
|
||||
platformer built only from assets, containers and graphs: a title screen with a clickable Start
|
||||
|
||||
File renamed without changes.
+23
-1
@@ -6,6 +6,9 @@
|
||||
*
|
||||
* Runs against the fixture project written by tools/seed-e2e.mjs and mutates it heavily; the
|
||||
* steps in tools/e2e/ run in order and build on each other's scene state.
|
||||
*
|
||||
* `GM_STEPS=1-12` or `GM_STEPS=6,20` runs a subset while working on one step. Since later steps
|
||||
* rely on what earlier ones leave behind, a subset that skips a prerequisite fails on purpose.
|
||||
*/
|
||||
import { STEPS } from './e2e/index.mjs';
|
||||
import { runChecks } from './lib/harness.mjs';
|
||||
@@ -13,8 +16,27 @@ import { PROJECTS, cliArgs } from './lib/projects.mjs';
|
||||
|
||||
const { projectId, baseUrl } = cliArgs('e2e.mjs', PROJECTS.fixture);
|
||||
|
||||
function selectSteps(spec) {
|
||||
if (!spec) return STEPS;
|
||||
const wanted = new Set();
|
||||
for (const part of spec.split(',')) {
|
||||
const [from, to] = part.trim().split('-').map(Number);
|
||||
if (!Number.isInteger(from) || from < 1) {
|
||||
console.error(`GM_STEPS: cannot read "${part}" – use 20, 1-12 or 6,20`);
|
||||
process.exit(2);
|
||||
}
|
||||
for (let i = from; i <= (Number.isInteger(to) ? to : from); i++) wanted.add(i);
|
||||
}
|
||||
return STEPS.filter((_, i) => wanted.has(i + 1));
|
||||
}
|
||||
|
||||
const steps = selectSteps(process.env.GM_STEPS);
|
||||
if (steps.length !== STEPS.length) {
|
||||
console.log(`running ${steps.length}/${STEPS.length} steps: ${steps.map((s) => s.name).join(', ')}`);
|
||||
}
|
||||
|
||||
await runChecks({ projectId, baseUrl, port: 9333, shotPrefix: 'gm-e2e' }, async (t) => {
|
||||
await t.navigate();
|
||||
await t.shot('01-loaded');
|
||||
for (const step of STEPS) await step(t);
|
||||
for (const step of steps) await step(t);
|
||||
});
|
||||
Reference in new issue
Block a user