game-harness 1.1.2 → 1.2.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/CHANGELOG.md +7 -0
- package/dist/cjs/browser-config.js +15 -1
- package/dist/cjs/vitest-major.js +16 -0
- package/dist/esm/browser-config.js +15 -1
- package/dist/esm/vitest-major.js +13 -0
- package/dist/types/browser-config.d.cts +20 -1
- package/dist/types/browser-config.d.ts +20 -1
- package/dist/types/vitest-major.d.cts +7 -0
- package/dist/types/vitest-major.d.ts +7 -0
- package/docs/guides/vitest.md +15 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,13 @@ 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.2.0](https://github.com/jbcom/game-harness/compare/game-harness-v1.1.2...game-harness-v1.2.0) (2026-10-10)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
### Features
|
|
11
|
+
|
|
12
|
+
* **vitest:** pass the browser server's api, custom commands, failure screenshots and isolation through ([29c6d2d](https://github.com/jbcom/game-harness/commit/29c6d2dbaf099b7dcdf8a9cd2b1ffa621e9d9059))
|
|
13
|
+
|
|
7
14
|
## [1.1.2](https://github.com/jbcom/game-harness/compare/game-harness-v1.1.1...game-harness-v1.1.2) (2026-10-07)
|
|
8
15
|
|
|
9
16
|
|
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.defineBrowserTestConfig = defineBrowserTestConfig;
|
|
4
4
|
const browser_playwright_1 = require("@vitest/browser-playwright");
|
|
5
5
|
const chromium_launch_js_1 = require("./chromium-launch.js");
|
|
6
|
+
const vitest_major_js_1 = require("./vitest-major.js");
|
|
6
7
|
function resolveHeadless(headless) {
|
|
7
8
|
if (typeof headless === 'boolean')
|
|
8
9
|
return headless;
|
|
@@ -40,7 +41,7 @@ function resolveHeadless(headless) {
|
|
|
40
41
|
* one, wrap the test command in `xvfb-run` rather than forcing headless here.
|
|
41
42
|
*/
|
|
42
43
|
function defineBrowserTestConfig(opts = {}) {
|
|
43
|
-
const { contextOptions = {}, gpuArgs = [], gpuMode = 'auto', headless = false, ui = false, instances = [{ browser: 'chromium' }], optimizeDeps = [], setupFiles, name = 'browser', include = ['tests/browser/**/*.browser.test.{ts,tsx}'], fileParallelism = false, } = opts;
|
|
44
|
+
const { contextOptions = {}, gpuArgs = [], gpuMode = 'auto', headless = false, ui = false, instances = [{ browser: 'chromium' }], optimizeDeps = [], setupFiles, name = 'browser', include = ['tests/browser/**/*.browser.test.{ts,tsx}'], fileParallelism = false, api, commands, screenshotFailures, isolate, } = opts;
|
|
44
45
|
if (!name.trim())
|
|
45
46
|
throw new TypeError('browser project name must not be empty');
|
|
46
47
|
if (instances.length === 0) {
|
|
@@ -73,6 +74,19 @@ function defineBrowserTestConfig(opts = {}) {
|
|
|
73
74
|
if (setupFiles) {
|
|
74
75
|
test.setupFiles = [...setupFiles];
|
|
75
76
|
}
|
|
77
|
+
if (api) {
|
|
78
|
+
if ((0, vitest_major_js_1.vitestMajor)() >= 5)
|
|
79
|
+
test.api = { ...api };
|
|
80
|
+
// Vitest 4's browser server reads its own `api`; Vitest 5's types no longer carry it.
|
|
81
|
+
else
|
|
82
|
+
test.browser.api = { ...api };
|
|
83
|
+
}
|
|
84
|
+
if (commands)
|
|
85
|
+
test.browser = { ...test.browser, commands: { ...commands } };
|
|
86
|
+
if (screenshotFailures !== undefined)
|
|
87
|
+
test.browser = { ...test.browser, screenshotFailures };
|
|
88
|
+
if (isolate !== undefined)
|
|
89
|
+
test.isolate = isolate;
|
|
76
90
|
if (optimizeDeps.length > 0) {
|
|
77
91
|
// Vitest's `test` fragment has no `optimizeDeps` field (that lives at
|
|
78
92
|
// the top-level Vite config) — surface the caller's list here so a
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.vitestMajor = vitestMajor;
|
|
4
|
+
const node_1 = require("vitest/node");
|
|
5
|
+
/**
|
|
6
|
+
* The major version of the Vitest the consumer installed. The peer range spans
|
|
7
|
+
* Vitest 4 and 5, which disagree about where some browser-mode options live
|
|
8
|
+
* (Vitest 5 moved the browser server's port from `browser.api` to the
|
|
9
|
+
* top-level `api`, and ignores the old one).
|
|
10
|
+
*/
|
|
11
|
+
function vitestMajor() {
|
|
12
|
+
const major = Number.parseInt(node_1.version, 10);
|
|
13
|
+
if (!Number.isFinite(major))
|
|
14
|
+
throw new Error(`unrecognised Vitest version: ${node_1.version}`);
|
|
15
|
+
return major;
|
|
16
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { playwright } from '@vitest/browser-playwright';
|
|
2
2
|
import { createChromiumLaunchProfile } from './chromium-launch.js';
|
|
3
|
+
import { vitestMajor } from './vitest-major.js';
|
|
3
4
|
function resolveHeadless(headless) {
|
|
4
5
|
if (typeof headless === 'boolean')
|
|
5
6
|
return headless;
|
|
@@ -37,7 +38,7 @@ function resolveHeadless(headless) {
|
|
|
37
38
|
* one, wrap the test command in `xvfb-run` rather than forcing headless here.
|
|
38
39
|
*/
|
|
39
40
|
export function defineBrowserTestConfig(opts = {}) {
|
|
40
|
-
const { contextOptions = {}, gpuArgs = [], gpuMode = 'auto', headless = false, ui = false, instances = [{ browser: 'chromium' }], optimizeDeps = [], setupFiles, name = 'browser', include = ['tests/browser/**/*.browser.test.{ts,tsx}'], fileParallelism = false, } = opts;
|
|
41
|
+
const { contextOptions = {}, gpuArgs = [], gpuMode = 'auto', headless = false, ui = false, instances = [{ browser: 'chromium' }], optimizeDeps = [], setupFiles, name = 'browser', include = ['tests/browser/**/*.browser.test.{ts,tsx}'], fileParallelism = false, api, commands, screenshotFailures, isolate, } = opts;
|
|
41
42
|
if (!name.trim())
|
|
42
43
|
throw new TypeError('browser project name must not be empty');
|
|
43
44
|
if (instances.length === 0) {
|
|
@@ -70,6 +71,19 @@ export function defineBrowserTestConfig(opts = {}) {
|
|
|
70
71
|
if (setupFiles) {
|
|
71
72
|
test.setupFiles = [...setupFiles];
|
|
72
73
|
}
|
|
74
|
+
if (api) {
|
|
75
|
+
if (vitestMajor() >= 5)
|
|
76
|
+
test.api = { ...api };
|
|
77
|
+
// Vitest 4's browser server reads its own `api`; Vitest 5's types no longer carry it.
|
|
78
|
+
else
|
|
79
|
+
test.browser.api = { ...api };
|
|
80
|
+
}
|
|
81
|
+
if (commands)
|
|
82
|
+
test.browser = { ...test.browser, commands: { ...commands } };
|
|
83
|
+
if (screenshotFailures !== undefined)
|
|
84
|
+
test.browser = { ...test.browser, screenshotFailures };
|
|
85
|
+
if (isolate !== undefined)
|
|
86
|
+
test.isolate = isolate;
|
|
73
87
|
if (optimizeDeps.length > 0) {
|
|
74
88
|
// Vitest's `test` fragment has no `optimizeDeps` field (that lives at
|
|
75
89
|
// the top-level Vite config) — surface the caller's list here so a
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { version } from 'vitest/node';
|
|
2
|
+
/**
|
|
3
|
+
* The major version of the Vitest the consumer installed. The peer range spans
|
|
4
|
+
* Vitest 4 and 5, which disagree about where some browser-mode options live
|
|
5
|
+
* (Vitest 5 moved the browser server's port from `browser.api` to the
|
|
6
|
+
* top-level `api`, and ignores the old one).
|
|
7
|
+
*/
|
|
8
|
+
export function vitestMajor() {
|
|
9
|
+
const major = Number.parseInt(version, 10);
|
|
10
|
+
if (!Number.isFinite(major))
|
|
11
|
+
throw new Error(`unrecognised Vitest version: ${version}`);
|
|
12
|
+
return major;
|
|
13
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type PlaywrightProviderOptions } from '@vitest/browser-playwright';
|
|
2
|
-
import type { TestUserConfig } from 'vitest/node';
|
|
2
|
+
import type { BrowserConfigOptions, TestUserConfig } from 'vitest/node';
|
|
3
3
|
import { type ChromiumGpuMode } from './chromium-launch.js';
|
|
4
4
|
/**
|
|
5
5
|
* A single browser instance entry, as accepted by Vitest Browser Mode's
|
|
@@ -64,6 +64,25 @@ export interface BrowserTestConfigOptions {
|
|
|
64
64
|
* verified your suite tolerates concurrent browser contexts.
|
|
65
65
|
*/
|
|
66
66
|
fileParallelism?: boolean;
|
|
67
|
+
/**
|
|
68
|
+
* The browser server's address, such as the port a CI slot or a local
|
|
69
|
+
* port allocator assigned (`{ port, strictPort: true }`). Placed where the
|
|
70
|
+
* installed Vitest reads it: the top-level `api` on Vitest 5, `browser.api`
|
|
71
|
+
* on Vitest 4. Omitted, Vitest's default port is used.
|
|
72
|
+
*/
|
|
73
|
+
api?: BrowserApiConfig;
|
|
74
|
+
/** Custom browser commands (`browser.commands`), e.g. a pointer drawn along a path. */
|
|
75
|
+
commands?: NonNullable<BrowserConfigOptions['commands']>;
|
|
76
|
+
/** `browser.screenshotFailures`. Omitted, Vitest's default applies. */
|
|
77
|
+
screenshotFailures?: boolean;
|
|
78
|
+
/** The top-level `isolate` (Vitest 5 retired `browser.isolate` for it). Omitted, Vitest's default applies. */
|
|
79
|
+
isolate?: boolean;
|
|
80
|
+
}
|
|
81
|
+
/** The browser server's address options: the subset Vitest 4's `browser.api` and Vitest 5's `api` share. */
|
|
82
|
+
export interface BrowserApiConfig {
|
|
83
|
+
port?: number;
|
|
84
|
+
strictPort?: boolean;
|
|
85
|
+
host?: string;
|
|
67
86
|
}
|
|
68
87
|
/**
|
|
69
88
|
* Builds a `test` fragment for a Vitest Browser Mode project, wired for
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type PlaywrightProviderOptions } from '@vitest/browser-playwright';
|
|
2
|
-
import type { TestUserConfig } from 'vitest/node';
|
|
2
|
+
import type { BrowserConfigOptions, TestUserConfig } from 'vitest/node';
|
|
3
3
|
import { type ChromiumGpuMode } from './chromium-launch.js';
|
|
4
4
|
/**
|
|
5
5
|
* A single browser instance entry, as accepted by Vitest Browser Mode's
|
|
@@ -64,6 +64,25 @@ export interface BrowserTestConfigOptions {
|
|
|
64
64
|
* verified your suite tolerates concurrent browser contexts.
|
|
65
65
|
*/
|
|
66
66
|
fileParallelism?: boolean;
|
|
67
|
+
/**
|
|
68
|
+
* The browser server's address, such as the port a CI slot or a local
|
|
69
|
+
* port allocator assigned (`{ port, strictPort: true }`). Placed where the
|
|
70
|
+
* installed Vitest reads it: the top-level `api` on Vitest 5, `browser.api`
|
|
71
|
+
* on Vitest 4. Omitted, Vitest's default port is used.
|
|
72
|
+
*/
|
|
73
|
+
api?: BrowserApiConfig;
|
|
74
|
+
/** Custom browser commands (`browser.commands`), e.g. a pointer drawn along a path. */
|
|
75
|
+
commands?: NonNullable<BrowserConfigOptions['commands']>;
|
|
76
|
+
/** `browser.screenshotFailures`. Omitted, Vitest's default applies. */
|
|
77
|
+
screenshotFailures?: boolean;
|
|
78
|
+
/** The top-level `isolate` (Vitest 5 retired `browser.isolate` for it). Omitted, Vitest's default applies. */
|
|
79
|
+
isolate?: boolean;
|
|
80
|
+
}
|
|
81
|
+
/** The browser server's address options: the subset Vitest 4's `browser.api` and Vitest 5's `api` share. */
|
|
82
|
+
export interface BrowserApiConfig {
|
|
83
|
+
port?: number;
|
|
84
|
+
strictPort?: boolean;
|
|
85
|
+
host?: string;
|
|
67
86
|
}
|
|
68
87
|
/**
|
|
69
88
|
* Builds a `test` fragment for a Vitest Browser Mode project, wired for
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The major version of the Vitest the consumer installed. The peer range spans
|
|
3
|
+
* Vitest 4 and 5, which disagree about where some browser-mode options live
|
|
4
|
+
* (Vitest 5 moved the browser server's port from `browser.api` to the
|
|
5
|
+
* top-level `api`, and ignores the old one).
|
|
6
|
+
*/
|
|
7
|
+
export declare function vitestMajor(): number;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The major version of the Vitest the consumer installed. The peer range spans
|
|
3
|
+
* Vitest 4 and 5, which disagree about where some browser-mode options live
|
|
4
|
+
* (Vitest 5 moved the browser server's port from `browser.api` to the
|
|
5
|
+
* top-level `api`, and ignores the old one).
|
|
6
|
+
*/
|
|
7
|
+
export declare function vitestMajor(): number;
|
package/docs/guides/vitest.md
CHANGED
|
@@ -39,3 +39,18 @@ discover on its own) that must also be merged into your top-level
|
|
|
39
39
|
`vite.config.ts`'s `optimizeDeps.include` — read them off the returned
|
|
40
40
|
fragment's `__optimizeDepsInclude` field, since Vitest's `test` block has no
|
|
41
41
|
`optimizeDeps` field of its own.
|
|
42
|
+
|
|
43
|
+
A game whose suite needs more of Vitest's browser options passes them through
|
|
44
|
+
rather than spreading over the fragment:
|
|
45
|
+
|
|
46
|
+
- `api` is the browser server's address, such as the port a CI slot or a
|
|
47
|
+
local port allocator assigned, with `strictPort: true` so a taken port
|
|
48
|
+
fails rather than drifting. It is placed where the installed Vitest reads
|
|
49
|
+
it: the top-level `api` on Vitest 5 (which ignores `browser.api`),
|
|
50
|
+
`browser.api` on Vitest 4.
|
|
51
|
+
- `commands` registers custom browser commands (`browser.commands`), such as
|
|
52
|
+
a pointer drawn along a path that `userEvent` cannot draw.
|
|
53
|
+
- `screenshotFailures` sets `browser.screenshotFailures`.
|
|
54
|
+
- `isolate` sets the top-level `isolate`, which replaced `browser.isolate`.
|
|
55
|
+
|
|
56
|
+
Each is left to Vitest's default when it is not given.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "game-harness",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.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",
|