game-harness 1.0.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 +140 -0
- package/CHANGELOG.md +69 -0
- package/LICENSE +21 -0
- package/README.md +568 -0
- package/bin/test-harness-visual-battery.mjs +6 -0
- package/dist/cjs/bin/visual-battery.js +43 -0
- package/dist/cjs/browser-config.js +83 -0
- package/dist/cjs/chromium-launch.js +37 -0
- package/dist/cjs/index.js +10 -0
- package/dist/cjs/lighthouse.js +73 -0
- package/dist/cjs/package.json +3 -0
- package/dist/cjs/playwright-config.js +303 -0
- package/dist/cjs/production-runtime.js +315 -0
- package/dist/cjs/release-ladder.js +40 -0
- package/dist/cjs/silent-qa.js +75 -0
- package/dist/cjs/visual-battery.js +247 -0
- package/dist/esm/bin/visual-battery.js +41 -0
- package/dist/esm/browser-config.js +80 -0
- package/dist/esm/chromium-launch.js +34 -0
- package/dist/esm/index.js +3 -0
- package/dist/esm/lighthouse.js +70 -0
- package/dist/esm/playwright-config.js +292 -0
- package/dist/esm/production-runtime.js +304 -0
- package/dist/esm/release-ladder.js +37 -0
- package/dist/esm/silent-qa.js +67 -0
- package/dist/esm/visual-battery.js +239 -0
- package/dist/types/bin/visual-battery.d.cts +2 -0
- package/dist/types/bin/visual-battery.d.ts +2 -0
- package/dist/types/browser-config.d.cts +100 -0
- package/dist/types/browser-config.d.ts +100 -0
- package/dist/types/chromium-launch.d.cts +27 -0
- package/dist/types/chromium-launch.d.ts +27 -0
- package/dist/types/index.d.cts +3 -0
- package/dist/types/index.d.ts +3 -0
- package/dist/types/lighthouse.d.cts +44 -0
- package/dist/types/lighthouse.d.ts +44 -0
- package/dist/types/playwright-config.d.cts +122 -0
- package/dist/types/playwright-config.d.ts +122 -0
- package/dist/types/production-runtime.d.cts +105 -0
- package/dist/types/production-runtime.d.ts +105 -0
- package/dist/types/release-ladder.d.cts +38 -0
- package/dist/types/release-ladder.d.ts +38 -0
- package/dist/types/silent-qa.d.cts +47 -0
- package/dist/types/silent-qa.d.ts +47 -0
- package/dist/types/visual-battery.d.cts +69 -0
- package/dist/types/visual-battery.d.ts +69 -0
- package/docs/404.md +17 -0
- package/docs/agent-guide.md +10 -0
- package/docs/architecture.md +81 -0
- package/docs/assets/game-harness-hero.webp +0 -0
- package/docs/changelog.md +9 -0
- package/docs/contributing.md +21 -0
- package/docs/entry-points.md +41 -0
- package/docs/getting-started.md +42 -0
- package/docs/guides/chromium-and-silent-qa.md +72 -0
- package/docs/guides/lighthouse-and-release-ladder.md +62 -0
- package/docs/guides/playwright.md +58 -0
- package/docs/guides/production-runtime.md +61 -0
- package/docs/guides/visual-battery.md +58 -0
- package/docs/guides/vitest.md +41 -0
- package/docs/introduction.md +29 -0
- package/docs/package.json +13 -0
- package/docs/quick-start.md +47 -0
- package/docs/reference/troubleshooting.md +33 -0
- package/docs/security.md +15 -0
- package/docs/sourcey.config.ts +79 -0
- package/llms.txt +32 -0
- package/maestro/smoke.template.yaml +11 -0
- package/package.json +196 -0
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { type PlaywrightProviderOptions } from '@vitest/browser-playwright';
|
|
2
|
+
import type { TestUserConfig } from 'vitest/node';
|
|
3
|
+
import { type ChromiumGpuMode } from './chromium-launch.js';
|
|
4
|
+
/**
|
|
5
|
+
* A single browser instance entry, as accepted by Vitest Browser Mode's
|
|
6
|
+
* `test.browser.instances` array (one per browser/viewport combination).
|
|
7
|
+
*/
|
|
8
|
+
export interface BrowserInstance {
|
|
9
|
+
browser: 'chromium' | 'firefox' | 'webkit';
|
|
10
|
+
[key: string]: unknown;
|
|
11
|
+
}
|
|
12
|
+
export interface BrowserTestConfigOptions {
|
|
13
|
+
/**
|
|
14
|
+
* Playwright browser-context options. A device scale factor of 1 is the
|
|
15
|
+
* default so headed and headless Chromium produce the same deterministic
|
|
16
|
+
* screenshot dimensions; callers can override it explicitly when a test
|
|
17
|
+
* needs high-DPI rendering.
|
|
18
|
+
*/
|
|
19
|
+
contextOptions?: PlaywrightProviderOptions['contextOptions'];
|
|
20
|
+
/**
|
|
21
|
+
* Extra Chromium launch args merged after the selected renderer profile.
|
|
22
|
+
* Forwarded to the Playwright provider's `launchOptions.args`.
|
|
23
|
+
*/
|
|
24
|
+
gpuArgs?: string[];
|
|
25
|
+
/** Renderer profile. Defaults to `auto`; software rendering is always explicit. */
|
|
26
|
+
gpuMode?: ChromiumGpuMode;
|
|
27
|
+
/**
|
|
28
|
+
* `true` — always headless. `false` (default) — always headed.
|
|
29
|
+
* `'ci-only'` — headed locally, headless when `process.env.CI` is set.
|
|
30
|
+
* CI should normally retain the headed default and supply Xvfb.
|
|
31
|
+
*/
|
|
32
|
+
headless?: boolean | 'ci-only';
|
|
33
|
+
/**
|
|
34
|
+
* Show Vitest's interactive browser UI. Defaults to false so headed runs use
|
|
35
|
+
* a fixed Playwright viewport and deterministic device scale. The Chromium
|
|
36
|
+
* window remains visible whenever `headless` is false.
|
|
37
|
+
*/
|
|
38
|
+
ui?: boolean;
|
|
39
|
+
/** Browser instances for the `browser.instances` array. Defaults to a single chromium instance. */
|
|
40
|
+
instances?: BrowserInstance[];
|
|
41
|
+
/**
|
|
42
|
+
* Extra module specifiers to add to `optimizeDeps.include`. Useful for
|
|
43
|
+
* deep-import paths (e.g. `three/examples/jsm/utils/SkeletonUtils.js`)
|
|
44
|
+
* that Vite's dependency scanner doesn't discover on its own and that
|
|
45
|
+
* would otherwise trigger a mid-run re-bundle (and a duplicate module
|
|
46
|
+
* instance) the first time a browser test imports them. Read this field
|
|
47
|
+
* off the return value (`__optimizeDepsInclude`) and merge it into your
|
|
48
|
+
* `vite.config.ts`'s own `optimizeDeps.include` — Vitest's `test` fragment
|
|
49
|
+
* has no `optimizeDeps` field of its own, that lives at the top-level
|
|
50
|
+
* Vite config.
|
|
51
|
+
*/
|
|
52
|
+
optimizeDeps?: string[];
|
|
53
|
+
/** Passed through verbatim to `test.setupFiles`. */
|
|
54
|
+
setupFiles?: string[];
|
|
55
|
+
/** Project name. Defaults to `'browser'`. */
|
|
56
|
+
name?: string;
|
|
57
|
+
/** Test file glob(s). Defaults to `['tests/browser/**\/*.browser.test.{ts,tsx}']`. */
|
|
58
|
+
include?: string[];
|
|
59
|
+
/**
|
|
60
|
+
* Disable file-level parallelism. A shared Playwright Chromium pool
|
|
61
|
+
* flakes under parallel browser-test load (independent specs racing for
|
|
62
|
+
* the same browser context can time out). Defaults to `true` (serialized)
|
|
63
|
+
* — flip off only once you've
|
|
64
|
+
* verified your suite tolerates concurrent browser contexts.
|
|
65
|
+
*/
|
|
66
|
+
fileParallelism?: boolean;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Builds a `test` fragment for a Vitest Browser Mode project, wired for
|
|
70
|
+
* real-Chromium (or other Playwright-driven browser) test execution.
|
|
71
|
+
*
|
|
72
|
+
* Encodes a reviewed pattern: headed by default both locally and in
|
|
73
|
+
* CI, silent at the Chromium boundary, and native renderer selection unless a
|
|
74
|
+
* consumer explicitly requests software or the proven Linux Vulkan profile.
|
|
75
|
+
*
|
|
76
|
+
* The returned object is meant to be spread into a Vitest `projects[]`
|
|
77
|
+
* entry's `test` field (or merged into a top-level `test` block for
|
|
78
|
+
* single-project setups):
|
|
79
|
+
*
|
|
80
|
+
* ```ts
|
|
81
|
+
* import { defineBrowserTestConfig } from 'game-harness/vitest';
|
|
82
|
+
*
|
|
83
|
+
* export default defineConfig({
|
|
84
|
+
* test: {
|
|
85
|
+
* projects: [
|
|
86
|
+
* { extends: true, test: { name: 'unit', environment: 'node', include: [...] } },
|
|
87
|
+
* { extends: true, test: defineBrowserTestConfig({
|
|
88
|
+
* optimizeDeps: ['three/examples/jsm/utils/SkeletonUtils.js'],
|
|
89
|
+
* }) },
|
|
90
|
+
* ],
|
|
91
|
+
* },
|
|
92
|
+
* });
|
|
93
|
+
* ```
|
|
94
|
+
*
|
|
95
|
+
* NOTE: a headed browser needs a display server. On Linux CI images without
|
|
96
|
+
* one, wrap the test command in `xvfb-run` rather than forcing headless here.
|
|
97
|
+
*/
|
|
98
|
+
export declare function defineBrowserTestConfig(opts?: BrowserTestConfigOptions): TestUserConfig & {
|
|
99
|
+
__optimizeDepsInclude?: string[];
|
|
100
|
+
};
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { type PlaywrightProviderOptions } from '@vitest/browser-playwright';
|
|
2
|
+
import type { TestUserConfig } from 'vitest/node';
|
|
3
|
+
import { type ChromiumGpuMode } from './chromium-launch.js';
|
|
4
|
+
/**
|
|
5
|
+
* A single browser instance entry, as accepted by Vitest Browser Mode's
|
|
6
|
+
* `test.browser.instances` array (one per browser/viewport combination).
|
|
7
|
+
*/
|
|
8
|
+
export interface BrowserInstance {
|
|
9
|
+
browser: 'chromium' | 'firefox' | 'webkit';
|
|
10
|
+
[key: string]: unknown;
|
|
11
|
+
}
|
|
12
|
+
export interface BrowserTestConfigOptions {
|
|
13
|
+
/**
|
|
14
|
+
* Playwright browser-context options. A device scale factor of 1 is the
|
|
15
|
+
* default so headed and headless Chromium produce the same deterministic
|
|
16
|
+
* screenshot dimensions; callers can override it explicitly when a test
|
|
17
|
+
* needs high-DPI rendering.
|
|
18
|
+
*/
|
|
19
|
+
contextOptions?: PlaywrightProviderOptions['contextOptions'];
|
|
20
|
+
/**
|
|
21
|
+
* Extra Chromium launch args merged after the selected renderer profile.
|
|
22
|
+
* Forwarded to the Playwright provider's `launchOptions.args`.
|
|
23
|
+
*/
|
|
24
|
+
gpuArgs?: string[];
|
|
25
|
+
/** Renderer profile. Defaults to `auto`; software rendering is always explicit. */
|
|
26
|
+
gpuMode?: ChromiumGpuMode;
|
|
27
|
+
/**
|
|
28
|
+
* `true` — always headless. `false` (default) — always headed.
|
|
29
|
+
* `'ci-only'` — headed locally, headless when `process.env.CI` is set.
|
|
30
|
+
* CI should normally retain the headed default and supply Xvfb.
|
|
31
|
+
*/
|
|
32
|
+
headless?: boolean | 'ci-only';
|
|
33
|
+
/**
|
|
34
|
+
* Show Vitest's interactive browser UI. Defaults to false so headed runs use
|
|
35
|
+
* a fixed Playwright viewport and deterministic device scale. The Chromium
|
|
36
|
+
* window remains visible whenever `headless` is false.
|
|
37
|
+
*/
|
|
38
|
+
ui?: boolean;
|
|
39
|
+
/** Browser instances for the `browser.instances` array. Defaults to a single chromium instance. */
|
|
40
|
+
instances?: BrowserInstance[];
|
|
41
|
+
/**
|
|
42
|
+
* Extra module specifiers to add to `optimizeDeps.include`. Useful for
|
|
43
|
+
* deep-import paths (e.g. `three/examples/jsm/utils/SkeletonUtils.js`)
|
|
44
|
+
* that Vite's dependency scanner doesn't discover on its own and that
|
|
45
|
+
* would otherwise trigger a mid-run re-bundle (and a duplicate module
|
|
46
|
+
* instance) the first time a browser test imports them. Read this field
|
|
47
|
+
* off the return value (`__optimizeDepsInclude`) and merge it into your
|
|
48
|
+
* `vite.config.ts`'s own `optimizeDeps.include` — Vitest's `test` fragment
|
|
49
|
+
* has no `optimizeDeps` field of its own, that lives at the top-level
|
|
50
|
+
* Vite config.
|
|
51
|
+
*/
|
|
52
|
+
optimizeDeps?: string[];
|
|
53
|
+
/** Passed through verbatim to `test.setupFiles`. */
|
|
54
|
+
setupFiles?: string[];
|
|
55
|
+
/** Project name. Defaults to `'browser'`. */
|
|
56
|
+
name?: string;
|
|
57
|
+
/** Test file glob(s). Defaults to `['tests/browser/**\/*.browser.test.{ts,tsx}']`. */
|
|
58
|
+
include?: string[];
|
|
59
|
+
/**
|
|
60
|
+
* Disable file-level parallelism. A shared Playwright Chromium pool
|
|
61
|
+
* flakes under parallel browser-test load (independent specs racing for
|
|
62
|
+
* the same browser context can time out). Defaults to `true` (serialized)
|
|
63
|
+
* — flip off only once you've
|
|
64
|
+
* verified your suite tolerates concurrent browser contexts.
|
|
65
|
+
*/
|
|
66
|
+
fileParallelism?: boolean;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Builds a `test` fragment for a Vitest Browser Mode project, wired for
|
|
70
|
+
* real-Chromium (or other Playwright-driven browser) test execution.
|
|
71
|
+
*
|
|
72
|
+
* Encodes a reviewed pattern: headed by default both locally and in
|
|
73
|
+
* CI, silent at the Chromium boundary, and native renderer selection unless a
|
|
74
|
+
* consumer explicitly requests software or the proven Linux Vulkan profile.
|
|
75
|
+
*
|
|
76
|
+
* The returned object is meant to be spread into a Vitest `projects[]`
|
|
77
|
+
* entry's `test` field (or merged into a top-level `test` block for
|
|
78
|
+
* single-project setups):
|
|
79
|
+
*
|
|
80
|
+
* ```ts
|
|
81
|
+
* import { defineBrowserTestConfig } from 'game-harness/vitest';
|
|
82
|
+
*
|
|
83
|
+
* export default defineConfig({
|
|
84
|
+
* test: {
|
|
85
|
+
* projects: [
|
|
86
|
+
* { extends: true, test: { name: 'unit', environment: 'node', include: [...] } },
|
|
87
|
+
* { extends: true, test: defineBrowserTestConfig({
|
|
88
|
+
* optimizeDeps: ['three/examples/jsm/utils/SkeletonUtils.js'],
|
|
89
|
+
* }) },
|
|
90
|
+
* ],
|
|
91
|
+
* },
|
|
92
|
+
* });
|
|
93
|
+
* ```
|
|
94
|
+
*
|
|
95
|
+
* NOTE: a headed browser needs a display server. On Linux CI images without
|
|
96
|
+
* one, wrap the test command in `xvfb-run` rather than forcing headless here.
|
|
97
|
+
*/
|
|
98
|
+
export declare function defineBrowserTestConfig(opts?: BrowserTestConfigOptions): TestUserConfig & {
|
|
99
|
+
__optimizeDepsInclude?: string[];
|
|
100
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/** Browser renderer policy for agent-controlled Chromium sessions. */
|
|
2
|
+
export type ChromiumGpuMode = 'auto' | 'software' | 'linux-hardware-vulkan';
|
|
3
|
+
export type ChromiumEnvironment = Record<string, string | undefined>;
|
|
4
|
+
export interface ChromiumLaunchProfileOptions {
|
|
5
|
+
/**
|
|
6
|
+
* `auto` leaves renderer selection to Chromium (Metal on macOS, the native
|
|
7
|
+
* desktop stack elsewhere). `software` opts into SwiftShader explicitly.
|
|
8
|
+
* `linux-hardware-vulkan` is a proven Mesa/ANGLE profile for a
|
|
9
|
+
* Linux runner with `/dev/dri/renderD128` passed through.
|
|
10
|
+
*/
|
|
11
|
+
gpuMode?: ChromiumGpuMode;
|
|
12
|
+
/** Additional Chromium arguments, de-duplicated ahead of `--mute-audio`. */
|
|
13
|
+
args?: readonly string[];
|
|
14
|
+
/** Environment additions. The Linux hardware profile also sets `EGL_PLATFORM=surfaceless`. */
|
|
15
|
+
env?: Readonly<ChromiumEnvironment>;
|
|
16
|
+
}
|
|
17
|
+
export interface ChromiumLaunchProfile {
|
|
18
|
+
/** De-duplicated Chromium launch arguments for the selected `gpuMode`, always ending in `--mute-audio`. */
|
|
19
|
+
args: string[];
|
|
20
|
+
/** Present when `env` overrides were supplied or `gpuMode` is `linux-hardware-vulkan` (which also sets `EGL_PLATFORM`); merged on top of `process.env`. */
|
|
21
|
+
env?: ChromiumEnvironment;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Builds the shared Chromium renderer and silence profile without deciding
|
|
25
|
+
* whether the browser is headed. Callers own that explicit choice.
|
|
26
|
+
*/
|
|
27
|
+
export declare function createChromiumLaunchProfile(options?: ChromiumLaunchProfileOptions): ChromiumLaunchProfile;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/** Browser renderer policy for agent-controlled Chromium sessions. */
|
|
2
|
+
export type ChromiumGpuMode = 'auto' | 'software' | 'linux-hardware-vulkan';
|
|
3
|
+
export type ChromiumEnvironment = Record<string, string | undefined>;
|
|
4
|
+
export interface ChromiumLaunchProfileOptions {
|
|
5
|
+
/**
|
|
6
|
+
* `auto` leaves renderer selection to Chromium (Metal on macOS, the native
|
|
7
|
+
* desktop stack elsewhere). `software` opts into SwiftShader explicitly.
|
|
8
|
+
* `linux-hardware-vulkan` is a proven Mesa/ANGLE profile for a
|
|
9
|
+
* Linux runner with `/dev/dri/renderD128` passed through.
|
|
10
|
+
*/
|
|
11
|
+
gpuMode?: ChromiumGpuMode;
|
|
12
|
+
/** Additional Chromium arguments, de-duplicated ahead of `--mute-audio`. */
|
|
13
|
+
args?: readonly string[];
|
|
14
|
+
/** Environment additions. The Linux hardware profile also sets `EGL_PLATFORM=surfaceless`. */
|
|
15
|
+
env?: Readonly<ChromiumEnvironment>;
|
|
16
|
+
}
|
|
17
|
+
export interface ChromiumLaunchProfile {
|
|
18
|
+
/** De-duplicated Chromium launch arguments for the selected `gpuMode`, always ending in `--mute-audio`. */
|
|
19
|
+
args: string[];
|
|
20
|
+
/** Present when `env` overrides were supplied or `gpuMode` is `linux-hardware-vulkan` (which also sets `EGL_PLATFORM`); merged on top of `process.env`. */
|
|
21
|
+
env?: ChromiumEnvironment;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Builds the shared Chromium renderer and silence profile without deciding
|
|
25
|
+
* whether the browser is headed. Callers own that explicit choice.
|
|
26
|
+
*/
|
|
27
|
+
export declare function createChromiumLaunchProfile(options?: ChromiumLaunchProfileOptions): ChromiumLaunchProfile;
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export { type LighthouseAssertionsOverrides, type LighthouseCiConfig, lighthouseAssertions, } from './lighthouse.js';
|
|
2
|
+
export { type ReleaseLadderResult, type ReleaseLadderStep, type VerifyReleaseLadderOptions, verifyReleaseLadder, } from './release-ladder.js';
|
|
3
|
+
export { runVisualBattery, VisualBatteryError, type VisualBatteryOptions, } from './visual-battery.js';
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export { type LighthouseAssertionsOverrides, type LighthouseCiConfig, lighthouseAssertions, } from './lighthouse.js';
|
|
2
|
+
export { type ReleaseLadderResult, type ReleaseLadderStep, type VerifyReleaseLadderOptions, verifyReleaseLadder, } from './release-ladder.js';
|
|
3
|
+
export { runVisualBattery, VisualBatteryError, type VisualBatteryOptions, } from './visual-battery.js';
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
export interface LighthouseCiConfig {
|
|
2
|
+
ci: {
|
|
3
|
+
collect: {
|
|
4
|
+
staticDistDir: string;
|
|
5
|
+
url: string[];
|
|
6
|
+
numberOfRuns: number;
|
|
7
|
+
settings: {
|
|
8
|
+
preset: string;
|
|
9
|
+
chromeFlags: string;
|
|
10
|
+
};
|
|
11
|
+
};
|
|
12
|
+
assert: {
|
|
13
|
+
preset: string;
|
|
14
|
+
assertions: Record<string, unknown>;
|
|
15
|
+
};
|
|
16
|
+
upload: {
|
|
17
|
+
target: string;
|
|
18
|
+
};
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
export interface LighthouseAssertionsOverrides {
|
|
22
|
+
staticDistDir?: string;
|
|
23
|
+
url?: string[];
|
|
24
|
+
numberOfRuns?: number;
|
|
25
|
+
assertions?: Record<string, unknown>;
|
|
26
|
+
}
|
|
27
|
+
declare const PRESETS: Record<string, LighthouseCiConfig>;
|
|
28
|
+
/**
|
|
29
|
+
* Returns a Lighthouse CI (`lighthouserc.json`) config object for a named
|
|
30
|
+
* preset, with an escape hatch for per-repo overrides merged on top.
|
|
31
|
+
*
|
|
32
|
+
* ```ts
|
|
33
|
+
* // lighthouserc.mjs
|
|
34
|
+
* import { lighthouseAssertions } from 'game-harness';
|
|
35
|
+
* export default lighthouseAssertions('game-default');
|
|
36
|
+
* ```
|
|
37
|
+
*
|
|
38
|
+
* Or, to keep `lighthouserc.json` as static JSON, run this once and paste
|
|
39
|
+
* the output — the factory has no runtime dependency on the consumer's
|
|
40
|
+
* environment beyond the overrides you pass.
|
|
41
|
+
*/
|
|
42
|
+
export type LighthousePreset = keyof typeof PRESETS | (string & {});
|
|
43
|
+
export declare function lighthouseAssertions(preset?: LighthousePreset, overrides?: LighthouseAssertionsOverrides): LighthouseCiConfig;
|
|
44
|
+
export {};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
export interface LighthouseCiConfig {
|
|
2
|
+
ci: {
|
|
3
|
+
collect: {
|
|
4
|
+
staticDistDir: string;
|
|
5
|
+
url: string[];
|
|
6
|
+
numberOfRuns: number;
|
|
7
|
+
settings: {
|
|
8
|
+
preset: string;
|
|
9
|
+
chromeFlags: string;
|
|
10
|
+
};
|
|
11
|
+
};
|
|
12
|
+
assert: {
|
|
13
|
+
preset: string;
|
|
14
|
+
assertions: Record<string, unknown>;
|
|
15
|
+
};
|
|
16
|
+
upload: {
|
|
17
|
+
target: string;
|
|
18
|
+
};
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
export interface LighthouseAssertionsOverrides {
|
|
22
|
+
staticDistDir?: string;
|
|
23
|
+
url?: string[];
|
|
24
|
+
numberOfRuns?: number;
|
|
25
|
+
assertions?: Record<string, unknown>;
|
|
26
|
+
}
|
|
27
|
+
declare const PRESETS: Record<string, LighthouseCiConfig>;
|
|
28
|
+
/**
|
|
29
|
+
* Returns a Lighthouse CI (`lighthouserc.json`) config object for a named
|
|
30
|
+
* preset, with an escape hatch for per-repo overrides merged on top.
|
|
31
|
+
*
|
|
32
|
+
* ```ts
|
|
33
|
+
* // lighthouserc.mjs
|
|
34
|
+
* import { lighthouseAssertions } from 'game-harness';
|
|
35
|
+
* export default lighthouseAssertions('game-default');
|
|
36
|
+
* ```
|
|
37
|
+
*
|
|
38
|
+
* Or, to keep `lighthouserc.json` as static JSON, run this once and paste
|
|
39
|
+
* the output — the factory has no runtime dependency on the consumer's
|
|
40
|
+
* environment beyond the overrides you pass.
|
|
41
|
+
*/
|
|
42
|
+
export type LighthousePreset = keyof typeof PRESETS | (string & {});
|
|
43
|
+
export declare function lighthouseAssertions(preset?: LighthousePreset, overrides?: LighthouseAssertionsOverrides): LighthouseCiConfig;
|
|
44
|
+
export {};
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { type Page, type PlaywrightTestConfig, type Response } from '@playwright/test';
|
|
2
|
+
import { type ChromiumGpuMode } from './chromium-launch.js';
|
|
3
|
+
export { SILENT_QA_MARKER_ATTRIBUTE, SILENT_QA_MARKER_VALUE, SILENT_QA_QUERY_PARAMETER, SILENT_QA_QUERY_VALUE, } from './silent-qa.js';
|
|
4
|
+
export type DeviceTier = 'desktop' | 'mobile' | 'tablet' | 'foldable' | 'ultrawide';
|
|
5
|
+
type Project = NonNullable<PlaywrightTestConfig['projects']>[number];
|
|
6
|
+
export type SilentQueryValue = string | number | boolean;
|
|
7
|
+
export interface SilentTestUrlOptions {
|
|
8
|
+
/** Runtime-only mute query parameter. Defaults to `muted`. */
|
|
9
|
+
muteQueryParameter?: string;
|
|
10
|
+
/** Runtime-only mute query value. Defaults to `1`. */
|
|
11
|
+
muteQueryValue?: string;
|
|
12
|
+
}
|
|
13
|
+
export interface OpenSilentGameOptions extends SilentTestUrlOptions {
|
|
14
|
+
/** DOM selector that owns the mute-ready marker. Defaults to `html`. */
|
|
15
|
+
markerSelector?: string;
|
|
16
|
+
/** Marker attribute set only after runtime audio is muted. */
|
|
17
|
+
markerAttribute?: string;
|
|
18
|
+
/** Required marker value. Defaults to `muted-test`. */
|
|
19
|
+
markerValue?: string;
|
|
20
|
+
/** Maximum time to wait for the application mute marker. Defaults to 5 seconds. */
|
|
21
|
+
markerTimeout?: number;
|
|
22
|
+
/** Options forwarded to `page.goto()`. */
|
|
23
|
+
navigationOptions?: NonNullable<Parameters<Page['goto']>[1]>;
|
|
24
|
+
}
|
|
25
|
+
export interface ResolvePlaywrightPortOptions {
|
|
26
|
+
/** Stable local-development port. Defaults to 4173. */
|
|
27
|
+
localPort?: number;
|
|
28
|
+
/** Injectable environment for deterministic consumers and tests. Defaults to `process.env`. */
|
|
29
|
+
environment?: Readonly<Record<string, string | undefined>>;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Adds a non-persistent mute mode to a relative or absolute URL.
|
|
33
|
+
* Explicit caller parameters replace existing values, and the mute value is
|
|
34
|
+
* applied last so a stale `muted=0` can never make an agent run audible.
|
|
35
|
+
*/
|
|
36
|
+
export declare function silentTestUrl(target?: string, parameters?: Readonly<Record<string, SilentQueryValue>>, options?: SilentTestUrlOptions): string;
|
|
37
|
+
/**
|
|
38
|
+
* Navigates to a game in runtime-only mute mode and fails closed until the
|
|
39
|
+
* application confirms that audio was muted before test interaction begins.
|
|
40
|
+
*/
|
|
41
|
+
export declare function openSilentGame(page: Page, target?: string, parameters?: Readonly<Record<string, SilentQueryValue>>, options?: OpenSilentGameOptions): Promise<Response | null>;
|
|
42
|
+
export interface PlaywrightConfigOptions {
|
|
43
|
+
/** Playwright `testDir`. Defaults to `'./tests'`. */
|
|
44
|
+
testDir?: string;
|
|
45
|
+
/** Base path the dev/preview server serves from. Defaults to `'/'`. */
|
|
46
|
+
basePath?: string;
|
|
47
|
+
/** Port for the local webServer + baseURL. Defaults to 4173, overridable via `PLAYWRIGHT_PORT`/`PW_PORT`. */
|
|
48
|
+
port?: number;
|
|
49
|
+
/**
|
|
50
|
+
* Builds a custom web-server command with the already-resolved local or
|
|
51
|
+
* CI-isolated port. Prefer this over hard-coding a port in
|
|
52
|
+
* `overrides.webServer.command`.
|
|
53
|
+
*/
|
|
54
|
+
webServerCommand?: (port: number) => string;
|
|
55
|
+
/** Renderer profile. Defaults to native Chromium selection (`auto`). */
|
|
56
|
+
gpuMode?: ChromiumGpuMode;
|
|
57
|
+
/**
|
|
58
|
+
* `false` (default) keeps Chromium headed locally and in CI. Use Xvfb on
|
|
59
|
+
* Linux CI. `true` is explicit headless mode; `ci-only` retains the older
|
|
60
|
+
* hosted-runner behavior when a display is genuinely unavailable.
|
|
61
|
+
*/
|
|
62
|
+
headless?: boolean | 'ci-only';
|
|
63
|
+
/**
|
|
64
|
+
* Which device-tier Playwright projects to include. `desktop` is always
|
|
65
|
+
* present as the tier-1 CI gate; passing more tiers here is equivalent to
|
|
66
|
+
* the `MULTIVIEW=1` convention already wired below — you don't
|
|
67
|
+
* need to also request `desktop` explicitly.
|
|
68
|
+
* Defaults to `['desktop']` (single project, matching the fast CI gate),
|
|
69
|
+
* expanding to all requested tiers when `MULTIVIEW=1` or `VISUAL=1` is set.
|
|
70
|
+
*/
|
|
71
|
+
deviceTiers?: DeviceTier[];
|
|
72
|
+
/** Extra Playwright projects appended after the device-tier projects. */
|
|
73
|
+
extraProjects?: Project[];
|
|
74
|
+
/**
|
|
75
|
+
* Spec globs that only run when `JOURNEY=1` is set (or when `VISUAL=1` is
|
|
76
|
+
* set, since visual runs imply the full journey suite). These are
|
|
77
|
+
* "agent review harness" specs — expensive artefact-producing runs, not
|
|
78
|
+
* part of the fast tier-1 functional gate. Excluded from `testIgnore`
|
|
79
|
+
* otherwise.
|
|
80
|
+
*/
|
|
81
|
+
journeySpecs?: string[];
|
|
82
|
+
/**
|
|
83
|
+
* Multiplier applied to the local (non-CI) timeout defaults to derive the
|
|
84
|
+
* CI timeout. CI runners are consistently slower under WebGL/render load;
|
|
85
|
+
* defaults to 4 (45s local → 180s CI action-adjacent test timeout, scaled
|
|
86
|
+
* per-field below).
|
|
87
|
+
*/
|
|
88
|
+
ciTimeoutMultiplier?: number;
|
|
89
|
+
/**
|
|
90
|
+
* Overrides merged last, escape-hatch for anything this factory doesn't
|
|
91
|
+
* expose. `use` and `webServer` are merged one level deep on top of the
|
|
92
|
+
* computed defaults (see `definePlaywrightConfig`'s return); every other
|
|
93
|
+
* field fully replaces.
|
|
94
|
+
*/
|
|
95
|
+
overrides?: Omit<Partial<PlaywrightTestConfig>, 'use' | 'webServer'> & {
|
|
96
|
+
use?: Partial<NonNullable<PlaywrightTestConfig['use']>>;
|
|
97
|
+
webServer?: Partial<Extract<NonNullable<PlaywrightTestConfig['webServer']>, {
|
|
98
|
+
command?: string;
|
|
99
|
+
}>>;
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Resolves one stable Playwright preview port for every config reload in an
|
|
104
|
+
* Actions job. Explicit `PLAYWRIGHT_PORT`/`PW_PORT` values win; local runs use
|
|
105
|
+
* `localPort`; GitHub/Gitea CI hashes repository, run, job, and local port into
|
|
106
|
+
* an isolated port range.
|
|
107
|
+
*/
|
|
108
|
+
export declare function resolvePlaywrightPort(options?: ResolvePlaywrightPortOptions): number;
|
|
109
|
+
/**
|
|
110
|
+
* Builds a full Playwright config, encoding a tiered-device +
|
|
111
|
+
* env-gated-suite convention:
|
|
112
|
+
*
|
|
113
|
+
* - `desktop` project always runs; `MULTIVIEW=1` (or `VISUAL=1`) expands to
|
|
114
|
+
* every requested device tier (mobile/tablet/foldable/ultrawide).
|
|
115
|
+
* - `JOURNEY=1` (or `VISUAL=1`) opts into expensive artefact-producing specs
|
|
116
|
+
* that are excluded from the default tier-1 functional gate so CI stays
|
|
117
|
+
* fast.
|
|
118
|
+
* - `VISUAL=1` additionally adds `visualSpecs` to the test match glob.
|
|
119
|
+
* - CI timeouts scale up from local defaults via `ciTimeoutMultiplier`
|
|
120
|
+
* (CI runners run WebGL/render-heavy tests 2-4x slower than local dev).
|
|
121
|
+
*/
|
|
122
|
+
export declare function definePlaywrightConfig(opts?: PlaywrightConfigOptions): PlaywrightTestConfig;
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { type Page, type PlaywrightTestConfig, type Response } from '@playwright/test';
|
|
2
|
+
import { type ChromiumGpuMode } from './chromium-launch.js';
|
|
3
|
+
export { SILENT_QA_MARKER_ATTRIBUTE, SILENT_QA_MARKER_VALUE, SILENT_QA_QUERY_PARAMETER, SILENT_QA_QUERY_VALUE, } from './silent-qa.js';
|
|
4
|
+
export type DeviceTier = 'desktop' | 'mobile' | 'tablet' | 'foldable' | 'ultrawide';
|
|
5
|
+
type Project = NonNullable<PlaywrightTestConfig['projects']>[number];
|
|
6
|
+
export type SilentQueryValue = string | number | boolean;
|
|
7
|
+
export interface SilentTestUrlOptions {
|
|
8
|
+
/** Runtime-only mute query parameter. Defaults to `muted`. */
|
|
9
|
+
muteQueryParameter?: string;
|
|
10
|
+
/** Runtime-only mute query value. Defaults to `1`. */
|
|
11
|
+
muteQueryValue?: string;
|
|
12
|
+
}
|
|
13
|
+
export interface OpenSilentGameOptions extends SilentTestUrlOptions {
|
|
14
|
+
/** DOM selector that owns the mute-ready marker. Defaults to `html`. */
|
|
15
|
+
markerSelector?: string;
|
|
16
|
+
/** Marker attribute set only after runtime audio is muted. */
|
|
17
|
+
markerAttribute?: string;
|
|
18
|
+
/** Required marker value. Defaults to `muted-test`. */
|
|
19
|
+
markerValue?: string;
|
|
20
|
+
/** Maximum time to wait for the application mute marker. Defaults to 5 seconds. */
|
|
21
|
+
markerTimeout?: number;
|
|
22
|
+
/** Options forwarded to `page.goto()`. */
|
|
23
|
+
navigationOptions?: NonNullable<Parameters<Page['goto']>[1]>;
|
|
24
|
+
}
|
|
25
|
+
export interface ResolvePlaywrightPortOptions {
|
|
26
|
+
/** Stable local-development port. Defaults to 4173. */
|
|
27
|
+
localPort?: number;
|
|
28
|
+
/** Injectable environment for deterministic consumers and tests. Defaults to `process.env`. */
|
|
29
|
+
environment?: Readonly<Record<string, string | undefined>>;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Adds a non-persistent mute mode to a relative or absolute URL.
|
|
33
|
+
* Explicit caller parameters replace existing values, and the mute value is
|
|
34
|
+
* applied last so a stale `muted=0` can never make an agent run audible.
|
|
35
|
+
*/
|
|
36
|
+
export declare function silentTestUrl(target?: string, parameters?: Readonly<Record<string, SilentQueryValue>>, options?: SilentTestUrlOptions): string;
|
|
37
|
+
/**
|
|
38
|
+
* Navigates to a game in runtime-only mute mode and fails closed until the
|
|
39
|
+
* application confirms that audio was muted before test interaction begins.
|
|
40
|
+
*/
|
|
41
|
+
export declare function openSilentGame(page: Page, target?: string, parameters?: Readonly<Record<string, SilentQueryValue>>, options?: OpenSilentGameOptions): Promise<Response | null>;
|
|
42
|
+
export interface PlaywrightConfigOptions {
|
|
43
|
+
/** Playwright `testDir`. Defaults to `'./tests'`. */
|
|
44
|
+
testDir?: string;
|
|
45
|
+
/** Base path the dev/preview server serves from. Defaults to `'/'`. */
|
|
46
|
+
basePath?: string;
|
|
47
|
+
/** Port for the local webServer + baseURL. Defaults to 4173, overridable via `PLAYWRIGHT_PORT`/`PW_PORT`. */
|
|
48
|
+
port?: number;
|
|
49
|
+
/**
|
|
50
|
+
* Builds a custom web-server command with the already-resolved local or
|
|
51
|
+
* CI-isolated port. Prefer this over hard-coding a port in
|
|
52
|
+
* `overrides.webServer.command`.
|
|
53
|
+
*/
|
|
54
|
+
webServerCommand?: (port: number) => string;
|
|
55
|
+
/** Renderer profile. Defaults to native Chromium selection (`auto`). */
|
|
56
|
+
gpuMode?: ChromiumGpuMode;
|
|
57
|
+
/**
|
|
58
|
+
* `false` (default) keeps Chromium headed locally and in CI. Use Xvfb on
|
|
59
|
+
* Linux CI. `true` is explicit headless mode; `ci-only` retains the older
|
|
60
|
+
* hosted-runner behavior when a display is genuinely unavailable.
|
|
61
|
+
*/
|
|
62
|
+
headless?: boolean | 'ci-only';
|
|
63
|
+
/**
|
|
64
|
+
* Which device-tier Playwright projects to include. `desktop` is always
|
|
65
|
+
* present as the tier-1 CI gate; passing more tiers here is equivalent to
|
|
66
|
+
* the `MULTIVIEW=1` convention already wired below — you don't
|
|
67
|
+
* need to also request `desktop` explicitly.
|
|
68
|
+
* Defaults to `['desktop']` (single project, matching the fast CI gate),
|
|
69
|
+
* expanding to all requested tiers when `MULTIVIEW=1` or `VISUAL=1` is set.
|
|
70
|
+
*/
|
|
71
|
+
deviceTiers?: DeviceTier[];
|
|
72
|
+
/** Extra Playwright projects appended after the device-tier projects. */
|
|
73
|
+
extraProjects?: Project[];
|
|
74
|
+
/**
|
|
75
|
+
* Spec globs that only run when `JOURNEY=1` is set (or when `VISUAL=1` is
|
|
76
|
+
* set, since visual runs imply the full journey suite). These are
|
|
77
|
+
* "agent review harness" specs — expensive artefact-producing runs, not
|
|
78
|
+
* part of the fast tier-1 functional gate. Excluded from `testIgnore`
|
|
79
|
+
* otherwise.
|
|
80
|
+
*/
|
|
81
|
+
journeySpecs?: string[];
|
|
82
|
+
/**
|
|
83
|
+
* Multiplier applied to the local (non-CI) timeout defaults to derive the
|
|
84
|
+
* CI timeout. CI runners are consistently slower under WebGL/render load;
|
|
85
|
+
* defaults to 4 (45s local → 180s CI action-adjacent test timeout, scaled
|
|
86
|
+
* per-field below).
|
|
87
|
+
*/
|
|
88
|
+
ciTimeoutMultiplier?: number;
|
|
89
|
+
/**
|
|
90
|
+
* Overrides merged last, escape-hatch for anything this factory doesn't
|
|
91
|
+
* expose. `use` and `webServer` are merged one level deep on top of the
|
|
92
|
+
* computed defaults (see `definePlaywrightConfig`'s return); every other
|
|
93
|
+
* field fully replaces.
|
|
94
|
+
*/
|
|
95
|
+
overrides?: Omit<Partial<PlaywrightTestConfig>, 'use' | 'webServer'> & {
|
|
96
|
+
use?: Partial<NonNullable<PlaywrightTestConfig['use']>>;
|
|
97
|
+
webServer?: Partial<Extract<NonNullable<PlaywrightTestConfig['webServer']>, {
|
|
98
|
+
command?: string;
|
|
99
|
+
}>>;
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Resolves one stable Playwright preview port for every config reload in an
|
|
104
|
+
* Actions job. Explicit `PLAYWRIGHT_PORT`/`PW_PORT` values win; local runs use
|
|
105
|
+
* `localPort`; GitHub/Gitea CI hashes repository, run, job, and local port into
|
|
106
|
+
* an isolated port range.
|
|
107
|
+
*/
|
|
108
|
+
export declare function resolvePlaywrightPort(options?: ResolvePlaywrightPortOptions): number;
|
|
109
|
+
/**
|
|
110
|
+
* Builds a full Playwright config, encoding a tiered-device +
|
|
111
|
+
* env-gated-suite convention:
|
|
112
|
+
*
|
|
113
|
+
* - `desktop` project always runs; `MULTIVIEW=1` (or `VISUAL=1`) expands to
|
|
114
|
+
* every requested device tier (mobile/tablet/foldable/ultrawide).
|
|
115
|
+
* - `JOURNEY=1` (or `VISUAL=1`) opts into expensive artefact-producing specs
|
|
116
|
+
* that are excluded from the default tier-1 functional gate so CI stays
|
|
117
|
+
* fast.
|
|
118
|
+
* - `VISUAL=1` additionally adds `visualSpecs` to the test match glob.
|
|
119
|
+
* - CI timeouts scale up from local defaults via `ciTimeoutMultiplier`
|
|
120
|
+
* (CI runners run WebGL/render-heavy tests 2-4x slower than local dev).
|
|
121
|
+
*/
|
|
122
|
+
export declare function definePlaywrightConfig(opts?: PlaywrightConfigOptions): PlaywrightTestConfig;
|