game-harness 1.0.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +4 -0
- package/CHANGELOG.md +18 -2
- package/MIGRATION.md +137 -0
- package/README.md +14 -6
- package/dist/cjs/chromium-launch.js +18 -3
- package/dist/cjs/release-ladder.js +1 -1
- package/dist/esm/chromium-launch.js +17 -3
- package/dist/esm/release-ladder.js +1 -1
- package/dist/types/chromium-launch.d.cts +17 -3
- package/dist/types/chromium-launch.d.ts +17 -3
- package/dist/types/index.d.cts +1 -1
- package/dist/types/index.d.ts +1 -1
- package/dist/types/release-ladder.d.cts +1 -1
- package/dist/types/release-ladder.d.ts +1 -1
- package/docs/architecture.md +2 -2
- package/docs/decisions.md +154 -0
- package/docs/getting-started.md +1 -1
- package/docs/guides/chromium-and-silent-qa.md +9 -0
- package/docs/reference/troubleshooting.md +3 -2
- package/docs/sourcey.config.ts +1 -1
- package/llms.txt +1 -0
- package/maestro/smoke.template.yaml +1 -1
- package/package.json +8 -6
package/AGENTS.md
CHANGED
|
@@ -117,6 +117,10 @@ hardcoded version string into a workflow file.
|
|
|
117
117
|
clean-tarball consumer smoke tests. This is what CI runs; run it before
|
|
118
118
|
every commit.
|
|
119
119
|
- `pnpm test` — unit and contract tests only, for fast iteration.
|
|
120
|
+
- `pnpm test:chromium` — real headed Chromium checks of the launch profile
|
|
121
|
+
(needs `pnpm exec playwright install chromium`, and `xvfb-run -a` on a
|
|
122
|
+
Linux host without a display). CI runs it in its own `chromium` job; it is
|
|
123
|
+
not part of `pnpm verify`, so publishing never depends on a browser.
|
|
120
124
|
- `pnpm --filter game-harness-docs validate` / `pnpm --filter
|
|
121
125
|
game-harness-docs dev` — build or preview the Sourcey docs site in isolation.
|
|
122
126
|
- `pnpm format` — apply Prettier.
|
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,23 @@ All notable changes are recorded here. Releases follow
|
|
|
4
4
|
[Semantic Versioning](https://semver.org/) and are generated from Conventional
|
|
5
5
|
Commits by release-please.
|
|
6
6
|
|
|
7
|
+
## [1.1.0](https://github.com/jbcom/game-harness/compare/game-harness-v1.0.0...game-harness-v1.1.0) (2026-10-07)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
### Features
|
|
11
|
+
|
|
12
|
+
* accept Vitest 5 as a peer alongside Vitest 4 ([5d7a86c](https://github.com/jbcom/game-harness/commit/5d7a86c9e0b393e5e00818f89b03160cdd2c7370))
|
|
13
|
+
* **chromium:** keep background and occluded windows on schedule ([ba72078](https://github.com/jbcom/game-harness/commit/ba72078f8d3af5151d63e331eb84253213ac3a08))
|
|
14
|
+
* converge test-harness into game-harness and keep background windows on schedule ([b5295f9](https://github.com/jbcom/game-harness/commit/b5295f9c6fa421198e171b95358f19459a6f5f99))
|
|
15
|
+
* export VisualBatteryCommand from the package root ([ca6dd88](https://github.com/jbcom/game-harness/commit/ca6dd884935bd91ae811168a88e5a8bbbda0629c))
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
### Bug Fixes
|
|
19
|
+
|
|
20
|
+
* harden release package install ([c74160d](https://github.com/jbcom/game-harness/commit/c74160dc78d43811c94c8249fae40ab9e6bb8632))
|
|
21
|
+
* publish releases from cd workflow ([f6f3b3e](https://github.com/jbcom/game-harness/commit/f6f3b3e5ac1ab8cf3670fb47cb98523f1ce4d1be))
|
|
22
|
+
* publish releases from cd workflow ([c7560ac](https://github.com/jbcom/game-harness/commit/c7560ac921b20ef706f761c14955088bfd07a7f7))
|
|
23
|
+
|
|
7
24
|
## [1.0.0](https://github.com/jbcom/game-harness/compare/game-harness-v0.5.0...game-harness-v1.0.0) (2026-08-24)
|
|
8
25
|
|
|
9
26
|
|
|
@@ -62,8 +79,7 @@ Commits by release-please.
|
|
|
62
79
|
|
|
63
80
|
### Added
|
|
64
81
|
|
|
65
|
-
- Initial standalone public package
|
|
66
|
-
verification harness.
|
|
82
|
+
- Initial standalone public package for browser-game verification.
|
|
67
83
|
- Peer-isolated Playwright and Vitest Browser Mode configuration entry points.
|
|
68
84
|
- Fail-closed silent-QA, production-runtime, visual-regression, Lighthouse, and
|
|
69
85
|
release-ladder primitives.
|
package/MIGRATION.md
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
# Migrating from a scoped `test-harness` package
|
|
2
|
+
|
|
3
|
+
Game Harness grew out of a scoped package published privately as
|
|
4
|
+
`@your-scope/test-harness`. Every capability of that package now lives here, under
|
|
5
|
+
the same export names and subpaths. This guide maps each import, option and
|
|
6
|
+
binary, and lists the few places where Game Harness is stricter. The reasoning
|
|
7
|
+
behind each difference is in [docs/decisions.md](docs/decisions.md).
|
|
8
|
+
|
|
9
|
+
## 1. Swap the dependency
|
|
10
|
+
|
|
11
|
+
```sh
|
|
12
|
+
pnpm remove @your-scope/test-harness
|
|
13
|
+
pnpm add -D game-harness
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Game Harness is on the public npm registry, so a registry mapping for the old
|
|
17
|
+
scope is no longer needed once nothing else uses it. Keep the peers you
|
|
18
|
+
already install: `@playwright/test` for `/playwright` and
|
|
19
|
+
`/production-runtime`, and `vitest` with `@vitest/browser-playwright` for
|
|
20
|
+
`/vitest`. Vitest 4 (from 4.1.10) and Vitest 5 are both supported. Node 22 or
|
|
21
|
+
newer is required.
|
|
22
|
+
|
|
23
|
+
## 2. Rewrite imports
|
|
24
|
+
|
|
25
|
+
Only the package name changes. Every subpath and named export is the same.
|
|
26
|
+
|
|
27
|
+
| Before | After |
|
|
28
|
+
| --------------------------------------------- | --------------------------------- |
|
|
29
|
+
| `@your-scope/test-harness` | `game-harness` |
|
|
30
|
+
| `@your-scope/test-harness/vitest` | `game-harness/vitest` |
|
|
31
|
+
| `@your-scope/test-harness/playwright` | `game-harness/playwright` |
|
|
32
|
+
| `@your-scope/test-harness/silent-qa` | `game-harness/silent-qa` |
|
|
33
|
+
| `@your-scope/test-harness/production-runtime` | `game-harness/production-runtime` |
|
|
34
|
+
| `@your-scope/test-harness/chromium` | `game-harness/chromium` |
|
|
35
|
+
| `@your-scope/test-harness/lighthouse` | `game-harness/lighthouse` |
|
|
36
|
+
| `@your-scope/test-harness/release-ladder` | `game-harness/release-ladder` |
|
|
37
|
+
| `@your-scope/test-harness/visual-battery` | `game-harness/visual-battery` |
|
|
38
|
+
| `@your-scope/test-harness/package.json` | `game-harness/package.json` |
|
|
39
|
+
|
|
40
|
+
A single search and replace of the specifier prefix is enough:
|
|
41
|
+
|
|
42
|
+
```sh
|
|
43
|
+
git grep -lz '@your-scope/test-harness' | xargs -0 perl -pi -e 's#\@your-scope/test-harness#game-harness#g'
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Replace `your-scope` in these commands with the scope your project installed
|
|
47
|
+
the package under.
|
|
48
|
+
|
|
49
|
+
### Export by export
|
|
50
|
+
|
|
51
|
+
| Subpath | Exports (identical names) |
|
|
52
|
+
| --------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
53
|
+
| root | `lighthouseAssertions`, `LighthouseAssertionsOverrides`, `LighthouseCiConfig`, `verifyReleaseLadder`, `ReleaseLadderStep`, `ReleaseLadderResult`, `VerifyReleaseLadderOptions`, `runVisualBattery`, `VisualBatteryError`, `VisualBatteryOptions` |
|
|
54
|
+
| `/vitest` | `defineBrowserTestConfig`, `BrowserTestConfigOptions`, `BrowserInstance` |
|
|
55
|
+
| `/playwright` | `definePlaywrightConfig`, `PlaywrightConfigOptions`, `DeviceTier`, `resolvePlaywrightPort`, `ResolvePlaywrightPortOptions`, `silentTestUrl`, `SilentTestUrlOptions`, `SilentQueryValue`, `openSilentGame`, `OpenSilentGameOptions` |
|
|
56
|
+
| `/silent-qa` | `activateSilentQa`, `isSilentQaRequested`, `isSilentQaActive`, `_resetSilentQaForTests`, `ActivateSilentQaOptions`, `SilentQaMarkerTarget`, `SILENT_QA_QUERY_PARAMETER`, `SILENT_QA_QUERY_VALUE`, `SILENT_QA_MARKER_ATTRIBUTE`, `SILENT_QA_MARKER_VALUE` |
|
|
57
|
+
| `/production-runtime` | `verifyProductionRuntime`, `ProductionRuntimeOptions`, `ProductionRuntimeServerOptions`, `ProductionRuntimeResult`, `ProductionRuntimeIssue`, `ProductionRuntimeVerificationError`, `findAvailableProductionPort`, `AvailableProductionPortOptions`, `readWebGLRenderer`, `requireHardwareWebGL`, `WebGLRendererInfo` |
|
|
58
|
+
| `/chromium` | `createChromiumLaunchProfile`, `ChromiumLaunchProfileOptions`, `ChromiumLaunchProfile`, `ChromiumGpuMode`, `ChromiumEnvironment` |
|
|
59
|
+
| `/lighthouse` | `lighthouseAssertions`, `LighthouseAssertionsOverrides`, `LighthouseCiConfig`, `LighthousePreset` |
|
|
60
|
+
| `/release-ladder` | `verifyReleaseLadder`, `ReleaseLadderStep`, `ReleaseLadderResult`, `VerifyReleaseLadderOptions` |
|
|
61
|
+
| `/visual-battery` | `runVisualBattery`, `VisualBatteryError`, `VisualBatteryOptions` |
|
|
62
|
+
|
|
63
|
+
New in Game Harness: `activateSilentQaAsync` (`/silent-qa`),
|
|
64
|
+
`VisualBatteryCommand` (`/visual-battery` and root) and
|
|
65
|
+
`CHROMIUM_ANTI_THROTTLING_ARGS` (`/chromium`).
|
|
66
|
+
|
|
67
|
+
## 3. Options
|
|
68
|
+
|
|
69
|
+
Every option keeps its name and meaning:
|
|
70
|
+
|
|
71
|
+
| Options type | Options |
|
|
72
|
+
| -------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
73
|
+
| `BrowserTestConfigOptions` | `contextOptions`, `gpuArgs`, `gpuMode`, `headless`, `ui`, `instances`, `optimizeDeps`, `setupFiles`, `name`, `include`, `fileParallelism` |
|
|
74
|
+
| `PlaywrightConfigOptions` | `testDir`, `basePath`, `port`, `webServerCommand`, `gpuMode`, `headless`, `deviceTiers`, `extraProjects`, `journeySpecs`, `ciTimeoutMultiplier`, `overrides` |
|
|
75
|
+
| `SilentTestUrlOptions` | `muteQueryParameter`, `muteQueryValue` |
|
|
76
|
+
| `OpenSilentGameOptions` | `markerSelector`, `markerAttribute`, `markerValue`, `markerTimeout`, `navigationOptions` |
|
|
77
|
+
| `ResolvePlaywrightPortOptions` | `localPort`, `environment` |
|
|
78
|
+
| `ProductionRuntimeOptions` | `url`, `server`, `browserLaunchOptions`, `gpuMode`, `pageOptions`, `silentParameters`, `silentOptions`, `localStorageSentinels`, `assertReady`, `assertSilentState`, `settleTimeMs` |
|
|
79
|
+
| `ProductionRuntimeServerOptions` | `command`, `args`, `cwd`, `env`, `readyUrl`, `startupTimeoutMs`, `shutdownTimeoutMs` |
|
|
80
|
+
| `AvailableProductionPortOptions` | `host` |
|
|
81
|
+
| `ActivateSilentQaOptions` | `search`, `queryParameter`, `markerTarget`, `markerAttribute`, `markerValue` |
|
|
82
|
+
| `VisualBatteryOptions` | `ci`, `cwd`, `testCommand`, `baselinesDir`, `baselineProfile`, `isolatedHarnessFiles`, `log`, `error` |
|
|
83
|
+
| `LighthouseAssertionsOverrides` | `staticDistDir`, `url`, `numberOfRuns`, `assertions` |
|
|
84
|
+
| `ChromiumLaunchProfileOptions` | `gpuMode`, `args`, `env` |
|
|
85
|
+
| `VerifyReleaseLadderOptions` | `log`, `error` |
|
|
86
|
+
|
|
87
|
+
Environment variables are unchanged: `CI`, `MULTIVIEW`, `VISUAL`, `JOURNEY`,
|
|
88
|
+
`PLAYWRIGHT_PORT`, `PW_PORT`, `PW_HEADLESS`, `PW_REUSE_SERVER`,
|
|
89
|
+
`PW_CHROMIUM_CHANNEL` and `VITE_VISUAL_BASELINE_PROFILE`.
|
|
90
|
+
|
|
91
|
+
## 4. Binary
|
|
92
|
+
|
|
93
|
+
| Before | After |
|
|
94
|
+
| ----------------------------- | ----------------------------- |
|
|
95
|
+
| `test-harness-visual-battery` | `game-harness-visual-battery` |
|
|
96
|
+
|
|
97
|
+
The old binary name is still installed as an alias, so scripts keep working,
|
|
98
|
+
but new scripts should use `game-harness-visual-battery`. Arguments are the
|
|
99
|
+
same (`[harness-directory] [--ci]`). Unknown flags or a second directory now
|
|
100
|
+
exit with code 2 instead of being ignored.
|
|
101
|
+
|
|
102
|
+
## 5. Where Game Harness is stricter
|
|
103
|
+
|
|
104
|
+
These are the only changes that can make a previously passing setup fail.
|
|
105
|
+
Each one fails loudly at configuration time with a message naming the
|
|
106
|
+
problem.
|
|
107
|
+
|
|
108
|
+
| Situation | What to do |
|
|
109
|
+
| --------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
110
|
+
| `testCommand` relies on a shell: `'FOO=1 pnpm test:browser'`, `&&`, pipes or quoted arguments | Move the shell logic into a package script and pass its name (`'pnpm test:visual'`), or pass `{ command: 'pnpm', args: ['test:browser'] }`. No shell is ever started. |
|
|
111
|
+
| `PLAYWRIGHT_PORT` or `PW_PORT` set to a non-port value | Fix or unset it. Game Harness throws instead of falling back to the derived port. |
|
|
112
|
+
| `activateSilentQa` given a callback that returns a promise | Use `await activateSilentQaAsync(mute)`. The readiness marker then appears only after the mute has resolved. |
|
|
113
|
+
| `basePath` containing `?`, `#`, `.`/`..` segments or encoded slashes | Pass a plain pathname. Leading, trailing and repeated slashes are normalized for you. |
|
|
114
|
+
| Empty `deviceTiers`, an unknown tier, or `ciTimeoutMultiplier` that is not positive | Pass at least one of `desktop`, `mobile`, `tablet`, `foldable`, `ultrawide`, and a positive multiplier. |
|
|
115
|
+
| Empty Vitest `name`, `instances` or `include` | Omit the option to get the default, or pass a non-empty value. |
|
|
116
|
+
| Lighthouse override with an empty `staticDistDir`, an empty `url` list, or `numberOfRuns < 1` | Omit the override or pass a valid value. |
|
|
117
|
+
| Code that builds a `LighthouseCiConfig` by hand without `ci.collect.staticDistDir` | Add it. The result of `lighthouseAssertions()` always includes it. |
|
|
118
|
+
| `baselinesDir` absolute, or harness or baseline directory outside `cwd` | Use a path relative to, and inside, `cwd`. |
|
|
119
|
+
| A visual-battery run that writes no PNG baselines | It now fails. Make sure the harness actually takes screenshots. |
|
|
120
|
+
|
|
121
|
+
## 6. Behaviour you get for free
|
|
122
|
+
|
|
123
|
+
- Every launch profile adds `--disable-background-timer-throttling`,
|
|
124
|
+
`--disable-renderer-backgrounding` and
|
|
125
|
+
`--disable-backgrounding-occluded-windows`, so background and occluded
|
|
126
|
+
windows keep their timers on schedule when several headed browsers run at
|
|
127
|
+
once. If a custom launch passes its own `args`, they are merged with these,
|
|
128
|
+
and `--mute-audio` is still applied last.
|
|
129
|
+
- Harness files run in a sorted, deterministic order.
|
|
130
|
+
- Visual-battery commands run without a shell, with Windows `.cmd` shims
|
|
131
|
+
resolved for you.
|
|
132
|
+
|
|
133
|
+
## 7. Verify
|
|
134
|
+
|
|
135
|
+
Run the consumer's own full gate (type check, unit tests, browser tests and
|
|
136
|
+
end-to-end tests). A green unit run alone does not prove the browser
|
|
137
|
+
configuration still loads.
|
package/README.md
CHANGED
|
@@ -127,7 +127,7 @@ supported. CI pins the primary gate to the version in `.nvmrc` (currently
|
|
|
127
127
|
24.19.0, the latest Node 24 LTS patch) and additionally runs the full test
|
|
128
128
|
and build suite against Node 22 on Linux to prove the floor of that range,
|
|
129
129
|
alongside macOS and Windows portability on the pinned version. The current
|
|
130
|
-
conformance matrix is Playwright 1.62.1 and Vitest Browser 4.1.10.
|
|
130
|
+
conformance matrix is Playwright 1.62.1 and Vitest Browser 4.1.10 and 5.0.3.
|
|
131
131
|
Package-boundary consumers run with a credential-free home directory and npm
|
|
132
132
|
configuration, install only the peer family needed by each entry point, and
|
|
133
133
|
exercise ESM, CommonJS, the CLI, silent runtime markers, and Chromium launch
|
|
@@ -257,7 +257,14 @@ SwiftShader explicitly; `linux-hardware-vulkan` applies the reviewed
|
|
|
257
257
|
Mesa/ANGLE flags plus `EGL_PLATFORM=surfaceless` for a runner exposing
|
|
258
258
|
`/dev/dri/renderD128`) and always de-duplicates and appends `--mute-audio`
|
|
259
259
|
last, so a caller-supplied arg list can never accidentally drop the silence
|
|
260
|
-
guard.
|
|
260
|
+
guard. Every profile also carries `CHROMIUM_ANTI_THROTTLING_ARGS`
|
|
261
|
+
(`--disable-background-timer-throttling`, `--disable-renderer-backgrounding`,
|
|
262
|
+
`--disable-backgrounding-occluded-windows`), so background and occluded
|
|
263
|
+
windows keep their timers on schedule when several headed browsers run at
|
|
264
|
+
once; Page Visibility still reports `hidden`.
|
|
265
|
+
|
|
266
|
+
Moving from the scoped `test-harness` package this one grew out of? See
|
|
267
|
+
[MIGRATION.md](MIGRATION.md).
|
|
261
268
|
|
|
262
269
|
Every browser launched by `definePlaywrightConfig()` or
|
|
263
270
|
`defineBrowserTestConfig()` receives Chromium's `--mute-audio` argument as a
|
|
@@ -309,8 +316,8 @@ Before publishing, run `pnpm verify` under the pinned release toolchain. The
|
|
|
309
316
|
package verifier uses npm 11.17.0 directly from the package directory, packs a
|
|
310
317
|
tarball, and installs it into credential-free temporary consumers for the
|
|
311
318
|
peer-free root, Playwright/production-runtime, and Vitest Browser boundaries.
|
|
312
|
-
The release
|
|
313
|
-
provenance.
|
|
319
|
+
The tagged-release job in `cd.yml` repeats the full gate before publishing
|
|
320
|
+
with npm provenance through npm trusted publishing (OIDC).
|
|
314
321
|
|
|
315
322
|
## Production runtime verification
|
|
316
323
|
|
|
@@ -556,8 +563,9 @@ See [CONTRIBUTING.md](CONTRIBUTING.md) for contribution and commit guidance.
|
|
|
556
563
|
## Releases and support
|
|
557
564
|
|
|
558
565
|
Conventional commits on `main` are collected into a release pull request by
|
|
559
|
-
release-please. Merging that pull request creates the GitHub release
|
|
560
|
-
|
|
566
|
+
release-please. Merging that pull request creates the GitHub release; its
|
|
567
|
+
published-release event starts `cd.yml`, which verifies and publishes the exact
|
|
568
|
+
tag to npm through OIDC with provenance.
|
|
561
569
|
Changes are recorded in [CHANGELOG.md](CHANGELOG.md).
|
|
562
570
|
|
|
563
571
|
Report defects and feature requests through the repository issue forms. Report
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CHROMIUM_ANTI_THROTTLING_ARGS = void 0;
|
|
3
4
|
exports.createChromiumLaunchProfile = createChromiumLaunchProfile;
|
|
4
5
|
const GPU_ARGS = {
|
|
5
6
|
auto: [],
|
|
@@ -12,13 +13,27 @@ const GPU_ARGS = {
|
|
|
12
13
|
],
|
|
13
14
|
};
|
|
14
15
|
/**
|
|
15
|
-
*
|
|
16
|
-
*
|
|
16
|
+
* Keeps timers and rendering on schedule in pages Chromium considers
|
|
17
|
+
* backgrounded. Several headed windows commonly run at once during a test
|
|
18
|
+
* suite; without these switches a background tab's timers are coalesced to
|
|
19
|
+
* one wake-up per second, and an occluded window or backgrounded renderer is
|
|
20
|
+
* deprioritised, so suites time out for reasons unrelated to the game.
|
|
21
|
+
* Page Visibility still reports `hidden`, so visibility handling stays
|
|
22
|
+
* testable.
|
|
23
|
+
*/
|
|
24
|
+
exports.CHROMIUM_ANTI_THROTTLING_ARGS = Object.freeze([
|
|
25
|
+
'--disable-background-timer-throttling',
|
|
26
|
+
'--disable-renderer-backgrounding',
|
|
27
|
+
'--disable-backgrounding-occluded-windows',
|
|
28
|
+
]);
|
|
29
|
+
/**
|
|
30
|
+
* Builds the shared Chromium renderer, scheduling and silence profile without
|
|
31
|
+
* deciding whether the browser is headed. Callers own that explicit choice.
|
|
17
32
|
*/
|
|
18
33
|
function createChromiumLaunchProfile(options = {}) {
|
|
19
34
|
const gpuMode = options.gpuMode ?? 'auto';
|
|
20
35
|
const args = [
|
|
21
|
-
...new Set([...GPU_ARGS[gpuMode], ...(options.args ?? [])].filter((argument) => argument !== '--mute-audio')),
|
|
36
|
+
...new Set([...GPU_ARGS[gpuMode], ...exports.CHROMIUM_ANTI_THROTTLING_ARGS, ...(options.args ?? [])].filter((argument) => argument !== '--mute-audio')),
|
|
22
37
|
'--mute-audio',
|
|
23
38
|
];
|
|
24
39
|
if (gpuMode === 'linux-hardware-vulkan') {
|
|
@@ -7,7 +7,7 @@ exports.verifyReleaseLadder = verifyReleaseLadder;
|
|
|
7
7
|
* screenshots → native sync, or whatever a given repo's ladder is), run in
|
|
8
8
|
* sequence and stopped at the first failure with a labeled summary.
|
|
9
9
|
*
|
|
10
|
-
* Generalizes the
|
|
10
|
+
* Generalizes the common pattern of many discrete
|
|
11
11
|
* `node scripts/verify-X.mjs` files composed via a shell `&&` chain into a
|
|
12
12
|
* single reusable primitive: each step is a plain function (sync or async),
|
|
13
13
|
* so a repo can inline its logic or delegate to existing scripts via
|
|
@@ -9,13 +9,27 @@ const GPU_ARGS = {
|
|
|
9
9
|
],
|
|
10
10
|
};
|
|
11
11
|
/**
|
|
12
|
-
*
|
|
13
|
-
*
|
|
12
|
+
* Keeps timers and rendering on schedule in pages Chromium considers
|
|
13
|
+
* backgrounded. Several headed windows commonly run at once during a test
|
|
14
|
+
* suite; without these switches a background tab's timers are coalesced to
|
|
15
|
+
* one wake-up per second, and an occluded window or backgrounded renderer is
|
|
16
|
+
* deprioritised, so suites time out for reasons unrelated to the game.
|
|
17
|
+
* Page Visibility still reports `hidden`, so visibility handling stays
|
|
18
|
+
* testable.
|
|
19
|
+
*/
|
|
20
|
+
export const CHROMIUM_ANTI_THROTTLING_ARGS = Object.freeze([
|
|
21
|
+
'--disable-background-timer-throttling',
|
|
22
|
+
'--disable-renderer-backgrounding',
|
|
23
|
+
'--disable-backgrounding-occluded-windows',
|
|
24
|
+
]);
|
|
25
|
+
/**
|
|
26
|
+
* Builds the shared Chromium renderer, scheduling and silence profile without
|
|
27
|
+
* deciding whether the browser is headed. Callers own that explicit choice.
|
|
14
28
|
*/
|
|
15
29
|
export function createChromiumLaunchProfile(options = {}) {
|
|
16
30
|
const gpuMode = options.gpuMode ?? 'auto';
|
|
17
31
|
const args = [
|
|
18
|
-
...new Set([...GPU_ARGS[gpuMode], ...(options.args ?? [])].filter((argument) => argument !== '--mute-audio')),
|
|
32
|
+
...new Set([...GPU_ARGS[gpuMode], ...CHROMIUM_ANTI_THROTTLING_ARGS, ...(options.args ?? [])].filter((argument) => argument !== '--mute-audio')),
|
|
19
33
|
'--mute-audio',
|
|
20
34
|
];
|
|
21
35
|
if (gpuMode === 'linux-hardware-vulkan') {
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* screenshots → native sync, or whatever a given repo's ladder is), run in
|
|
5
5
|
* sequence and stopped at the first failure with a labeled summary.
|
|
6
6
|
*
|
|
7
|
-
* Generalizes the
|
|
7
|
+
* Generalizes the common pattern of many discrete
|
|
8
8
|
* `node scripts/verify-X.mjs` files composed via a shell `&&` chain into a
|
|
9
9
|
* single reusable primitive: each step is a plain function (sync or async),
|
|
10
10
|
* so a repo can inline its logic or delegate to existing scripts via
|
|
@@ -15,13 +15,27 @@ export interface ChromiumLaunchProfileOptions {
|
|
|
15
15
|
env?: Readonly<ChromiumEnvironment>;
|
|
16
16
|
}
|
|
17
17
|
export interface ChromiumLaunchProfile {
|
|
18
|
-
/**
|
|
18
|
+
/**
|
|
19
|
+
* De-duplicated Chromium launch arguments: the `gpuMode` renderer flags, the
|
|
20
|
+
* {@link CHROMIUM_ANTI_THROTTLING_ARGS}, any caller `args`, and always
|
|
21
|
+
* `--mute-audio` last.
|
|
22
|
+
*/
|
|
19
23
|
args: string[];
|
|
20
24
|
/** Present when `env` overrides were supplied or `gpuMode` is `linux-hardware-vulkan` (which also sets `EGL_PLATFORM`); merged on top of `process.env`. */
|
|
21
25
|
env?: ChromiumEnvironment;
|
|
22
26
|
}
|
|
23
27
|
/**
|
|
24
|
-
*
|
|
25
|
-
*
|
|
28
|
+
* Keeps timers and rendering on schedule in pages Chromium considers
|
|
29
|
+
* backgrounded. Several headed windows commonly run at once during a test
|
|
30
|
+
* suite; without these switches a background tab's timers are coalesced to
|
|
31
|
+
* one wake-up per second, and an occluded window or backgrounded renderer is
|
|
32
|
+
* deprioritised, so suites time out for reasons unrelated to the game.
|
|
33
|
+
* Page Visibility still reports `hidden`, so visibility handling stays
|
|
34
|
+
* testable.
|
|
35
|
+
*/
|
|
36
|
+
export declare const CHROMIUM_ANTI_THROTTLING_ARGS: readonly string[];
|
|
37
|
+
/**
|
|
38
|
+
* Builds the shared Chromium renderer, scheduling and silence profile without
|
|
39
|
+
* deciding whether the browser is headed. Callers own that explicit choice.
|
|
26
40
|
*/
|
|
27
41
|
export declare function createChromiumLaunchProfile(options?: ChromiumLaunchProfileOptions): ChromiumLaunchProfile;
|
|
@@ -15,13 +15,27 @@ export interface ChromiumLaunchProfileOptions {
|
|
|
15
15
|
env?: Readonly<ChromiumEnvironment>;
|
|
16
16
|
}
|
|
17
17
|
export interface ChromiumLaunchProfile {
|
|
18
|
-
/**
|
|
18
|
+
/**
|
|
19
|
+
* De-duplicated Chromium launch arguments: the `gpuMode` renderer flags, the
|
|
20
|
+
* {@link CHROMIUM_ANTI_THROTTLING_ARGS}, any caller `args`, and always
|
|
21
|
+
* `--mute-audio` last.
|
|
22
|
+
*/
|
|
19
23
|
args: string[];
|
|
20
24
|
/** Present when `env` overrides were supplied or `gpuMode` is `linux-hardware-vulkan` (which also sets `EGL_PLATFORM`); merged on top of `process.env`. */
|
|
21
25
|
env?: ChromiumEnvironment;
|
|
22
26
|
}
|
|
23
27
|
/**
|
|
24
|
-
*
|
|
25
|
-
*
|
|
28
|
+
* Keeps timers and rendering on schedule in pages Chromium considers
|
|
29
|
+
* backgrounded. Several headed windows commonly run at once during a test
|
|
30
|
+
* suite; without these switches a background tab's timers are coalesced to
|
|
31
|
+
* one wake-up per second, and an occluded window or backgrounded renderer is
|
|
32
|
+
* deprioritised, so suites time out for reasons unrelated to the game.
|
|
33
|
+
* Page Visibility still reports `hidden`, so visibility handling stays
|
|
34
|
+
* testable.
|
|
35
|
+
*/
|
|
36
|
+
export declare const CHROMIUM_ANTI_THROTTLING_ARGS: readonly string[];
|
|
37
|
+
/**
|
|
38
|
+
* Builds the shared Chromium renderer, scheduling and silence profile without
|
|
39
|
+
* deciding whether the browser is headed. Callers own that explicit choice.
|
|
26
40
|
*/
|
|
27
41
|
export declare function createChromiumLaunchProfile(options?: ChromiumLaunchProfileOptions): ChromiumLaunchProfile;
|
package/dist/types/index.d.cts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
export { type LighthouseAssertionsOverrides, type LighthouseCiConfig, lighthouseAssertions, } from './lighthouse.js';
|
|
2
2
|
export { type ReleaseLadderResult, type ReleaseLadderStep, type VerifyReleaseLadderOptions, verifyReleaseLadder, } from './release-ladder.js';
|
|
3
|
-
export { runVisualBattery, VisualBatteryError, type VisualBatteryOptions, } from './visual-battery.js';
|
|
3
|
+
export { runVisualBattery, type VisualBatteryCommand, VisualBatteryError, type VisualBatteryOptions, } from './visual-battery.js';
|
package/dist/types/index.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
export { type LighthouseAssertionsOverrides, type LighthouseCiConfig, lighthouseAssertions, } from './lighthouse.js';
|
|
2
2
|
export { type ReleaseLadderResult, type ReleaseLadderStep, type VerifyReleaseLadderOptions, verifyReleaseLadder, } from './release-ladder.js';
|
|
3
|
-
export { runVisualBattery, VisualBatteryError, type VisualBatteryOptions, } from './visual-battery.js';
|
|
3
|
+
export { runVisualBattery, type VisualBatteryCommand, VisualBatteryError, type VisualBatteryOptions, } from './visual-battery.js';
|
|
@@ -26,7 +26,7 @@ export interface VerifyReleaseLadderOptions {
|
|
|
26
26
|
* screenshots → native sync, or whatever a given repo's ladder is), run in
|
|
27
27
|
* sequence and stopped at the first failure with a labeled summary.
|
|
28
28
|
*
|
|
29
|
-
* Generalizes the
|
|
29
|
+
* Generalizes the common pattern of many discrete
|
|
30
30
|
* `node scripts/verify-X.mjs` files composed via a shell `&&` chain into a
|
|
31
31
|
* single reusable primitive: each step is a plain function (sync or async),
|
|
32
32
|
* so a repo can inline its logic or delegate to existing scripts via
|
|
@@ -26,7 +26,7 @@ export interface VerifyReleaseLadderOptions {
|
|
|
26
26
|
* screenshots → native sync, or whatever a given repo's ladder is), run in
|
|
27
27
|
* sequence and stopped at the first failure with a labeled summary.
|
|
28
28
|
*
|
|
29
|
-
* Generalizes the
|
|
29
|
+
* Generalizes the common pattern of many discrete
|
|
30
30
|
* `node scripts/verify-X.mjs` files composed via a shell `&&` chain into a
|
|
31
31
|
* single reusable primitive: each step is a plain function (sync or async),
|
|
32
32
|
* so a repo can inline its logic or delegate to existing scripts via
|
package/docs/architecture.md
CHANGED
|
@@ -29,8 +29,8 @@ either framework.
|
|
|
29
29
|
2. When a server is configured, its readiness URL must be unreachable first.
|
|
30
30
|
The command is spawned directly with an argument array and must bind with
|
|
31
31
|
strict-port behavior.
|
|
32
|
-
3. A fresh browser launches with the selected renderer profile
|
|
33
|
-
final `--mute-audio` argument.
|
|
32
|
+
3. A fresh browser launches with the selected renderer profile, the
|
|
33
|
+
anti-throttling switches, and exactly one final `--mute-audio` argument.
|
|
34
34
|
4. Local-storage sentinels are installed before application code.
|
|
35
35
|
5. `openSilentGame()` adds the runtime-only mute query and waits for the
|
|
36
36
|
application readiness marker.
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Decisions
|
|
3
|
+
description: Why the package is shaped the way it is, and how a predecessor harness converged into it.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Each entry records a decision, the reason for it, and what it means for a
|
|
7
|
+
consumer. Newest first.
|
|
8
|
+
|
|
9
|
+
## Converging a predecessor `test-harness` package
|
|
10
|
+
|
|
11
|
+
This entry compares the supported migration paths export by export so that
|
|
12
|
+
consumers of an earlier `test-harness` package can move to Game Harness. The step-by-step
|
|
13
|
+
consumer mapping is in [MIGRATION.md](https://github.com/jbcom/game-harness/blob/main/MIGRATION.md).
|
|
14
|
+
|
|
15
|
+
**Decision:** Game Harness is the one canonical harness. Where both packages
|
|
16
|
+
implement the same thing, Game Harness keeps its own public shape; anything the
|
|
17
|
+
predecessor did that Game Harness did not is added here, with tests.
|
|
18
|
+
|
|
19
|
+
### Method
|
|
20
|
+
|
|
21
|
+
1. Diffed every source file of the predecessor's last release against this
|
|
22
|
+
repository's `main`.
|
|
23
|
+
2. Ran the predecessor's own unit suite against Game Harness's source. Every
|
|
24
|
+
behavioural test passed (97 of 107). The ten failures were all in the
|
|
25
|
+
visual battery and mocked `execSync`, an implementation detail Game Harness
|
|
26
|
+
replaced with shell-free `execFileSync`; the behaviour those tests describe
|
|
27
|
+
is covered by Game Harness's own suite. The predecessor's package-contract
|
|
28
|
+
test checks its own package name and is not applicable.
|
|
29
|
+
|
|
30
|
+
### Entry points
|
|
31
|
+
|
|
32
|
+
| Subpath | Predecessor | Game Harness | Notes |
|
|
33
|
+
| --------------------- | ----------- | ------------ | ----------------------------------------------------------- |
|
|
34
|
+
| `.` (root) | yes | yes | Same re-exports: Lighthouse, release ladder, visual battery |
|
|
35
|
+
| `/vitest` | yes | yes | Same function; Game Harness validates its inputs |
|
|
36
|
+
| `/playwright` | yes | yes | Same functions; Game Harness validates and normalizes |
|
|
37
|
+
| `/silent-qa` | yes | yes | Game Harness adds `activateSilentQaAsync` |
|
|
38
|
+
| `/production-runtime` | yes | yes | Same functions; Game Harness validates URLs and durations |
|
|
39
|
+
| `/chromium` | yes | yes | Game Harness adds `CHROMIUM_ANTI_THROTTLING_ARGS` |
|
|
40
|
+
| `/lighthouse` | yes | yes | Same function; result type always carries `staticDistDir` |
|
|
41
|
+
| `/release-ladder` | yes | yes | Identical behaviour |
|
|
42
|
+
| `/visual-battery` | yes | yes | Game Harness adds `VisualBatteryCommand` and path checks |
|
|
43
|
+
| `/package.json` | yes | yes | |
|
|
44
|
+
|
|
45
|
+
Both packages ship ESM and CommonJS builds. Game Harness additionally ships
|
|
46
|
+
separate `.d.cts` declarations for `require` consumers.
|
|
47
|
+
|
|
48
|
+
### Exports
|
|
49
|
+
|
|
50
|
+
Every named export of the predecessor exists in Game Harness under the same
|
|
51
|
+
name and subpath. Game Harness adds three:
|
|
52
|
+
|
|
53
|
+
| Export | Subpath | Why |
|
|
54
|
+
| ------------------------------- | ----------------------- | -------------------------------------------------------------------- |
|
|
55
|
+
| `activateSilentQaAsync` | `/silent-qa` | Publishes the readiness marker only after an async mute resolves |
|
|
56
|
+
| `VisualBatteryCommand` | `/visual-battery`, root | Runs the browser suite without a shell |
|
|
57
|
+
| `CHROMIUM_ANTI_THROTTLING_ARGS` | `/chromium` | The scheduling switches every launch profile now carries (see below) |
|
|
58
|
+
|
|
59
|
+
### Bins
|
|
60
|
+
|
|
61
|
+
| Predecessor | Game Harness |
|
|
62
|
+
| ----------------------------- | ----------------------------------------------------------- |
|
|
63
|
+
| `test-harness-visual-battery` | `game-harness-visual-battery`, and the old name as an alias |
|
|
64
|
+
|
|
65
|
+
Game Harness's CLI also rejects unknown flags and more than one positional
|
|
66
|
+
directory (exit code 2) instead of silently ignoring them.
|
|
67
|
+
|
|
68
|
+
### Peers
|
|
69
|
+
|
|
70
|
+
| Peer | Predecessor | Game Harness |
|
|
71
|
+
| ---------------------------- | ------------- | ------------- |
|
|
72
|
+
| `@playwright/test` | `>=1.62.1 <2` | `>=1.62.1 <2` |
|
|
73
|
+
| `vitest` | `>=4.1.10 <5` | `>=4.1.10 <6` |
|
|
74
|
+
| `@vitest/browser-playwright` | `>=4.1.10 <5` | `>=4.1.10 <6` |
|
|
75
|
+
| Node (`engines`) | `>=24.19.0` | `>=22` |
|
|
76
|
+
|
|
77
|
+
All framework peers stay optional; the root never loads them. CI proves the
|
|
78
|
+
packed tarball against Vitest 4.1.10 and 5.0.3.
|
|
79
|
+
|
|
80
|
+
### Where the shapes differ
|
|
81
|
+
|
|
82
|
+
Game Harness's shape wins in each case. The consumer-facing consequence is
|
|
83
|
+
listed in MIGRATION.md.
|
|
84
|
+
|
|
85
|
+
- **Visual battery `testCommand`.** The predecessor passed a string to a
|
|
86
|
+
shell, so shell syntax (`FOO=1 pnpm …`, `&&`, quoting) worked by accident.
|
|
87
|
+
Game Harness never starts a shell: a string is split on whitespace, or a
|
|
88
|
+
`{ command, args }` object is executed directly. Kept because a shell turns
|
|
89
|
+
a configuration value into a command-injection surface and behaves
|
|
90
|
+
differently on Windows.
|
|
91
|
+
- **Strict input validation.** Game Harness throws a `TypeError` for an
|
|
92
|
+
invalid `PLAYWRIGHT_PORT`/`PW_PORT` (the predecessor silently fell back to
|
|
93
|
+
the derived port), an empty or unknown `deviceTiers` list, a non-positive
|
|
94
|
+
`ciTimeoutMultiplier`, a `basePath` with a query, fragment or traversal, an
|
|
95
|
+
empty Vitest project name, `instances` or `include`, and empty or invalid
|
|
96
|
+
Lighthouse overrides. Kept because a misconfigured gate that silently
|
|
97
|
+
"passes" is not release evidence.
|
|
98
|
+
- **Async mute callbacks.** The predecessor's `activateSilentQa` accepted a
|
|
99
|
+
promise-returning callback and published the readiness marker before the
|
|
100
|
+
mute finished. Game Harness throws and points to `activateSilentQaAsync`.
|
|
101
|
+
- **`LighthouseCiConfig.ci.collect.staticDistDir`** is required in the result
|
|
102
|
+
type. Every preset already sets it, so only code that builds the type by
|
|
103
|
+
hand without it is affected.
|
|
104
|
+
- **Visual battery paths.** Game Harness requires the harness and baseline
|
|
105
|
+
directories to stay inside `cwd`, sorts harness files for a deterministic
|
|
106
|
+
run order, and fails when a run produces no PNG baselines.
|
|
107
|
+
|
|
108
|
+
### Deliberately not carried over
|
|
109
|
+
|
|
110
|
+
- **The predecessor's repository tooling:** its Gitea release workflow,
|
|
111
|
+
release-label script, anonymous-registry environment helper and the test
|
|
112
|
+
that pinned that workflow. Game Harness publishes from GitHub with npm
|
|
113
|
+
trusted publishing and provenance, so none of it applies.
|
|
114
|
+
- **Shell execution for `testCommand`**, for the reason above. A consumer
|
|
115
|
+
that needs environment variables or chained commands puts them in a
|
|
116
|
+
package script and passes that script's name.
|
|
117
|
+
|
|
118
|
+
## Every launch profile disables background throttling
|
|
119
|
+
|
|
120
|
+
**Decision:** `createChromiumLaunchProfile()` always adds
|
|
121
|
+
`--disable-background-timer-throttling`, `--disable-renderer-backgrounding`
|
|
122
|
+
and `--disable-backgrounding-occluded-windows`, exported as
|
|
123
|
+
`CHROMIUM_ANTI_THROTTLING_ARGS`. Every Playwright project, Vitest Browser
|
|
124
|
+
instance and production-runtime launch inherits them.
|
|
125
|
+
|
|
126
|
+
**Why:** a browser suite commonly runs several headed windows at once. A tab
|
|
127
|
+
Chromium considers backgrounded has its timers coalesced to one wake-up per
|
|
128
|
+
second, and an occluded window or backgrounded renderer is deprioritised, so
|
|
129
|
+
suites time out for reasons that have nothing to do with the game.
|
|
130
|
+
|
|
131
|
+
Playwright adds the same switches to its own default arguments today, but the
|
|
132
|
+
profile is the package's contract with every launcher it serves: a custom
|
|
133
|
+
script, a launcher that does not use Playwright, or a caller that passes
|
|
134
|
+
`ignoreDefaultArgs`. Making the switches explicit keeps the guarantee from
|
|
135
|
+
depending on another tool's defaults. They do not change Page Visibility: a
|
|
136
|
+
backgrounded page still reports `hidden`, so a game's pause-on-hide logic
|
|
137
|
+
remains testable.
|
|
138
|
+
|
|
139
|
+
**Evidence:** `pnpm test:chromium` launches headed Chromium over the raw
|
|
140
|
+
DevTools protocol (Playwright's own switches and focus emulation would mask
|
|
141
|
+
the effect), opens a 50 ms timer in one tab and a second tab in front of it,
|
|
142
|
+
and samples the background tab for three seconds. With the profile the timer
|
|
143
|
+
keeps its schedule; a control case without the switches shows the one-second
|
|
144
|
+
throttling, which proves the scenario really backgrounds the tab.
|
|
145
|
+
|
|
146
|
+
## Vitest 4 and 5
|
|
147
|
+
|
|
148
|
+
**Decision:** the `vitest` and `@vitest/browser-playwright` peers accept
|
|
149
|
+
`>=4.1.10 <6`. Development runs on Vitest 5, and the packed-consumer smoke
|
|
150
|
+
runs once against 4.1.10 (the floor) and once against 5.0.3.
|
|
151
|
+
|
|
152
|
+
**Why:** consumers are moving to Vitest 5, and the config fragment
|
|
153
|
+
`defineBrowserTestConfig()` emits is valid for both majors without a code
|
|
154
|
+
change.
|
package/docs/getting-started.md
CHANGED
|
@@ -31,7 +31,7 @@ supported. CI pins the primary gate to the version in `.nvmrc` (currently
|
|
|
31
31
|
24.19.0, the latest Node 24 LTS patch) and additionally runs the full test
|
|
32
32
|
and build suite against Node 22 on Linux to prove the floor of that range,
|
|
33
33
|
alongside macOS and Windows portability on the pinned version. The current
|
|
34
|
-
conformance matrix is Playwright 1.62.1 and Vitest Browser 4.1.10.
|
|
34
|
+
conformance matrix is Playwright 1.62.1 and Vitest Browser 4.1.10 and 5.0.3.
|
|
35
35
|
Package-boundary consumers run with a credential-free home directory and npm
|
|
36
36
|
configuration, install only the peer family needed by each entry point, and
|
|
37
37
|
exercise ESM, CommonJS, the CLI, silent runtime markers, and Chromium launch
|
|
@@ -24,6 +24,15 @@ exposing `/dev/dri/renderD128`) and always de-duplicates and appends
|
|
|
24
24
|
`--mute-audio` last, so a caller-supplied arg list can never accidentally
|
|
25
25
|
drop the silence guard.
|
|
26
26
|
|
|
27
|
+
Every profile also carries `CHROMIUM_ANTI_THROTTLING_ARGS`:
|
|
28
|
+
`--disable-background-timer-throttling`, `--disable-renderer-backgrounding`
|
|
29
|
+
and `--disable-backgrounding-occluded-windows`. When several headed windows
|
|
30
|
+
run at once, Chromium would otherwise coalesce a background tab's timers to
|
|
31
|
+
one wake-up per second and deprioritise occluded windows, and suites time out
|
|
32
|
+
for reasons unrelated to the game. Page Visibility is unaffected: a
|
|
33
|
+
backgrounded page still reports `hidden`, so pause-on-hide logic stays
|
|
34
|
+
testable.
|
|
35
|
+
|
|
27
36
|
Every browser launched by `definePlaywrightConfig()` or
|
|
28
37
|
`defineBrowserTestConfig()` receives Chromium's `--mute-audio` argument as a
|
|
29
38
|
defense-in-depth guard, including projects with custom launch options. The
|
|
@@ -23,8 +23,9 @@ description: Common failure modes and their causes.
|
|
|
23
23
|
## Releases and support
|
|
24
24
|
|
|
25
25
|
Conventional commits on `main` are collected into a release pull request by
|
|
26
|
-
release-please. Merging that pull request creates the GitHub release
|
|
27
|
-
|
|
26
|
+
release-please. Merging that pull request creates the GitHub release; its
|
|
27
|
+
published-release event starts `cd.yml`, which verifies and publishes the exact
|
|
28
|
+
tag to npm through OIDC with provenance.
|
|
28
29
|
Changes are recorded in the [CHANGELOG](https://github.com/jbcom/game-harness/blob/main/CHANGELOG.md).
|
|
29
30
|
|
|
30
31
|
Report defects and feature requests through the
|
package/docs/sourcey.config.ts
CHANGED
package/llms.txt
CHANGED
|
@@ -23,6 +23,7 @@ agent-oriented quick reference before writing code against this package.
|
|
|
23
23
|
- [Visual battery guide](https://jonbogaty.com/game-harness/guides/visual-battery/): Deterministic screenshot baseline orchestration.
|
|
24
24
|
- [Lighthouse presets & release ladder guide](https://jonbogaty.com/game-harness/guides/lighthouse-and-release-ladder/): CI Lighthouse assertions and the release-step orchestrator.
|
|
25
25
|
- [Architecture reference](https://jonbogaty.com/game-harness/reference/architecture/): Module boundaries, runtime evidence flow, build/distribution guarantees.
|
|
26
|
+
- [Decisions reference](https://jonbogaty.com/game-harness/decisions/): Migration and compatibility decisions and their rationale.
|
|
26
27
|
- [Troubleshooting reference](https://jonbogaty.com/game-harness/reference/troubleshooting/): Common failure modes and releases/support.
|
|
27
28
|
|
|
28
29
|
## Optional
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
# render its first screen" flow; add game-specific flows alongside it as
|
|
4
4
|
# separate .maestro/*.yaml files (they're app-specific user journeys, not
|
|
5
5
|
# shareable config — see game-harness's package notes).
|
|
6
|
-
appId: __APP_ID__ # e.g. com.
|
|
6
|
+
appId: __APP_ID__ # e.g. com.example.game — must match capacitor.config.ts's appId
|
|
7
7
|
---
|
|
8
8
|
- launchApp
|
|
9
9
|
- assertVisible:
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "game-harness",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "Release-grade browser QA primitives for TypeScript games: silent Playwright/Vitest sessions, deterministic screenshots, runtime proof, and Lighthouse gates.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
"docs",
|
|
17
17
|
"llms.txt",
|
|
18
18
|
"maestro",
|
|
19
|
+
"MIGRATION.md",
|
|
19
20
|
"LICENSE",
|
|
20
21
|
"README.md"
|
|
21
22
|
],
|
|
@@ -125,8 +126,8 @@
|
|
|
125
126
|
},
|
|
126
127
|
"peerDependencies": {
|
|
127
128
|
"@playwright/test": ">=1.62.1 <2",
|
|
128
|
-
"@vitest/browser-playwright": ">=4.1.10 <
|
|
129
|
-
"vitest": ">=4.1.10 <
|
|
129
|
+
"@vitest/browser-playwright": ">=4.1.10 <6",
|
|
130
|
+
"vitest": ">=4.1.10 <6"
|
|
130
131
|
},
|
|
131
132
|
"peerDependenciesMeta": {
|
|
132
133
|
"@playwright/test": {
|
|
@@ -144,14 +145,14 @@
|
|
|
144
145
|
"@playwright/test": "1.62.1",
|
|
145
146
|
"@types/cross-spawn": "6.0.6",
|
|
146
147
|
"@types/node": "24.13.3",
|
|
147
|
-
"@vitest/browser-playwright": "
|
|
148
|
-
"@vitest/coverage-v8": "
|
|
148
|
+
"@vitest/browser-playwright": "5.0.3",
|
|
149
|
+
"@vitest/coverage-v8": "5.0.3",
|
|
149
150
|
"oxlint": "1.79.0",
|
|
150
151
|
"prettier": "3.9.6",
|
|
151
152
|
"publint": "0.3.24",
|
|
152
153
|
"rimraf": "6.1.3",
|
|
153
154
|
"typescript": "7.0.2",
|
|
154
|
-
"vitest": "
|
|
155
|
+
"vitest": "5.0.3"
|
|
155
156
|
},
|
|
156
157
|
"engines": {
|
|
157
158
|
"node": ">=22"
|
|
@@ -189,6 +190,7 @@
|
|
|
189
190
|
"lint": "oxlint --deny-warnings src tests scripts",
|
|
190
191
|
"package:check": "publint && attw --pack . --profile node16",
|
|
191
192
|
"test": "vitest run",
|
|
193
|
+
"test:chromium": "vitest run --config vitest.chromium.config.ts",
|
|
192
194
|
"test:package": "node scripts/verify-package-boundaries.mjs",
|
|
193
195
|
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
194
196
|
"verify": "pnpm run format:check && pnpm run lint && pnpm run typecheck && pnpm run coverage && pnpm run build && pnpm run package:check && pnpm run test:package"
|