@rstest/browser 0.10.6 → 0.11.1
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/dist/browser-container/container-static/js/{854.c59f71483d.js → 328.37af068e21.js} +2712 -2786
- package/dist/browser-container/container-static/js/328.37af068e21.js.LICENSE.txt +1 -0
- package/dist/browser-container/container-static/js/{index.fedc31dff3.js → index.c8fe4ff310.js} +58 -56
- package/dist/browser-container/index.html +1 -1
- package/dist/browser.js +1 -1
- package/dist/hostController.d.ts +17 -1
- package/dist/index.js +443 -365
- package/dist/protocol.d.ts +7 -1
- package/dist/providers/index.d.ts +3 -0
- package/package.json +7 -7
- package/src/client/entry.ts +25 -23
- package/src/client/formatConsole.ts +77 -0
- package/src/client/locator.ts +1 -5
- package/src/hostController.ts +671 -526
- package/src/protocol.ts +9 -5
- package/src/providers/index.ts +3 -0
- package/src/providers/playwright/runtime.ts +11 -6
- package/dist/browser-container/container-static/js/854.c59f71483d.js.LICENSE.txt +0 -1
- package/src/client/fakeTimersStub.ts +0 -91
- /package/dist/{626.js → 33.js} +0 -0
package/dist/protocol.d.ts
CHANGED
|
@@ -65,9 +65,15 @@ export type BrowserHostConfig = {
|
|
|
65
65
|
* Used by browser RPC calls to prevent stale requests from previous reruns.
|
|
66
66
|
*/ runId?: string;
|
|
67
67
|
/**
|
|
68
|
-
* Base URL for runner (iframe) pages.
|
|
68
|
+
* Base URL for runner (iframe) pages. Container origin; used as a fallback
|
|
69
|
+
* when a project has no entry in `projectRunnerUrls`.
|
|
69
70
|
*/ runnerUrl?: string;
|
|
70
71
|
/**
|
|
72
|
+
* Per-project runner origin base URLs, keyed by project name. Each browser
|
|
73
|
+
* project runs on its own dev server, so the container must load each test
|
|
74
|
+
* file's iframe from that project's own origin.
|
|
75
|
+
*/ projectRunnerUrls?: Record<string, string>;
|
|
76
|
+
/**
|
|
71
77
|
* WebSocket port for container RPC.
|
|
72
78
|
*/ wsPort?: number;
|
|
73
79
|
/**
|
|
@@ -41,6 +41,9 @@ import type { BrowserRpcRequest } from '../rpcProtocol.js';
|
|
|
41
41
|
on: {
|
|
42
42
|
(event: 'popup', listener: (page: BrowserProviderPage) => void) : void;
|
|
43
43
|
(event: 'console', listener: (message: BrowserConsoleMessage) => void) : void;
|
|
44
|
+
// Page died: renderer crash or unexpected close. Headless scheduling wires
|
|
45
|
+
// these to fail the file immediately. Listeners take no payload.
|
|
46
|
+
(event: 'crash' | 'close', listener: () => void) : void;
|
|
44
47
|
};
|
|
45
48
|
close: () => Promise<void>;
|
|
46
49
|
[Symbol.asyncDispose]: () => Promise<void>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rstest/browser",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.1",
|
|
4
4
|
"description": "Browser mode support for Rstest testing framework.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"rstest",
|
|
@@ -48,21 +48,21 @@
|
|
|
48
48
|
"ws": "^8.21.0"
|
|
49
49
|
},
|
|
50
50
|
"devDependencies": {
|
|
51
|
-
"@rslib/core": "0.23.
|
|
51
|
+
"@rslib/core": "0.23.2",
|
|
52
52
|
"@types/convert-source-map": "^2.0.3",
|
|
53
53
|
"@types/picomatch": "^4.0.3",
|
|
54
54
|
"@types/ws": "^8.18.1",
|
|
55
55
|
"@vitest/snapshot": "^3.2.6",
|
|
56
56
|
"birpc": "^4.0.0",
|
|
57
|
-
"picomatch": "^4.0.
|
|
58
|
-
"playwright": "^1.61.
|
|
59
|
-
"@rstest/
|
|
57
|
+
"picomatch": "^4.0.5",
|
|
58
|
+
"playwright": "^1.61.1",
|
|
59
|
+
"@rstest/core": "0.11.1",
|
|
60
60
|
"@rstest/tsconfig": "0.0.1",
|
|
61
|
-
"@rstest/
|
|
61
|
+
"@rstest/browser-ui": "0.0.0"
|
|
62
62
|
},
|
|
63
63
|
"peerDependencies": {
|
|
64
64
|
"playwright": "^1.49.1",
|
|
65
|
-
"@rstest/core": "^0.
|
|
65
|
+
"@rstest/core": "^0.11.1"
|
|
66
66
|
},
|
|
67
67
|
"peerDependenciesMeta": {
|
|
68
68
|
"playwright": {
|
package/src/client/entry.ts
CHANGED
|
@@ -32,6 +32,7 @@ import {
|
|
|
32
32
|
createRunnerLifecycleRequest,
|
|
33
33
|
sendRunnerLifecycle,
|
|
34
34
|
} from './dispatchTransport';
|
|
35
|
+
import { formatConsoleArgs } from './formatConsole';
|
|
35
36
|
import { BrowserSnapshotEnvironment } from './snapshot';
|
|
36
37
|
import {
|
|
37
38
|
findNewScriptUrl,
|
|
@@ -109,24 +110,6 @@ const ensureRuntimeEnv = (env: RuntimeConfig['env'] | undefined): void => {
|
|
|
109
110
|
}
|
|
110
111
|
};
|
|
111
112
|
|
|
112
|
-
/**
|
|
113
|
-
* Format an argument for console output.
|
|
114
|
-
*/
|
|
115
|
-
const formatArg = (arg: unknown): string => {
|
|
116
|
-
if (arg === null) return 'null';
|
|
117
|
-
if (arg === undefined) return 'undefined';
|
|
118
|
-
if (typeof arg === 'string') return arg;
|
|
119
|
-
if (typeof arg === 'number' || typeof arg === 'boolean') return String(arg);
|
|
120
|
-
if (arg instanceof Error) {
|
|
121
|
-
return arg.stack || `${arg.name}: ${arg.message}`;
|
|
122
|
-
}
|
|
123
|
-
try {
|
|
124
|
-
return JSON.stringify(arg, null, 2);
|
|
125
|
-
} catch {
|
|
126
|
-
return String(arg);
|
|
127
|
-
}
|
|
128
|
-
};
|
|
129
|
-
|
|
130
113
|
const getFileTaskId = (testPath: string): string => {
|
|
131
114
|
return `file:${testPath}`;
|
|
132
115
|
};
|
|
@@ -161,8 +144,7 @@ const interceptConsole = (
|
|
|
161
144
|
// Call original for browser DevTools
|
|
162
145
|
originalConsole[level](...args);
|
|
163
146
|
|
|
164
|
-
|
|
165
|
-
const content = args.map(formatArg).join(' ');
|
|
147
|
+
const content = formatConsoleArgs(args);
|
|
166
148
|
const currentTask = getCurrentTask();
|
|
167
149
|
|
|
168
150
|
// Send to host
|
|
@@ -284,10 +266,19 @@ const toContextKey = (absolutePath: string, projectRoot: string): string => {
|
|
|
284
266
|
const normalizedAbsolute = normalize(absolutePath);
|
|
285
267
|
const normalizedRoot = normalize(projectRoot);
|
|
286
268
|
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
269
|
+
// Only strip the root at a path boundary: a bare `startsWith` would mangle a
|
|
270
|
+
// sibling like `/repo/pkg-extra/a.test.ts` under root `/repo/pkg`. Must stay
|
|
271
|
+
// in sync with the host `toContextKey` (hostController.ts) so the non-watch
|
|
272
|
+
// import-map keys resolve.
|
|
273
|
+
const withinRoot =
|
|
274
|
+
normalizedAbsolute === normalizedRoot ||
|
|
275
|
+
normalizedAbsolute.startsWith(`${normalizedRoot}/`);
|
|
276
|
+
if (!withinRoot) {
|
|
277
|
+
// Test file outside the project root: keep the absolute path as the key so
|
|
278
|
+
// `toAbsolutePath` round-trips it instead of re-rooting under projectRoot.
|
|
279
|
+
return normalizedAbsolute;
|
|
290
280
|
}
|
|
281
|
+
const relative = normalizedAbsolute.slice(normalizedRoot.length);
|
|
291
282
|
return relative.startsWith('/') ? `.${relative}` : `./${relative}`;
|
|
292
283
|
};
|
|
293
284
|
|
|
@@ -296,6 +287,11 @@ const toContextKey = (absolutePath: string, projectRoot: string): string => {
|
|
|
296
287
|
* e.g., './src/foo.test.ts' -> '/project/src/foo.test.ts'
|
|
297
288
|
*/
|
|
298
289
|
const toAbsolutePath = (key: string, projectRoot: string): string => {
|
|
290
|
+
// An absolute key (test file outside the project root, see `toContextKey`)
|
|
291
|
+
// round-trips as-is; only `./`-prefixed relative keys are re-rooted.
|
|
292
|
+
if (!key.startsWith('.')) {
|
|
293
|
+
return key;
|
|
294
|
+
}
|
|
299
295
|
// key format: ./src/foo.test.ts
|
|
300
296
|
// Ensure no double slashes by removing trailing slash from projectRoot
|
|
301
297
|
const normalizedRoot = normalize(projectRoot).replace(/\/$/, '');
|
|
@@ -482,6 +478,10 @@ const run = async () => {
|
|
|
482
478
|
rootPath: options.rootPath,
|
|
483
479
|
runtimeConfig,
|
|
484
480
|
taskId: 0,
|
|
481
|
+
// The kept-module-cache flush keyed on `buildId` is node worker-pool
|
|
482
|
+
// only (#1373); browser runners never reuse a node worker, so a constant
|
|
483
|
+
// inert id is correct here.
|
|
484
|
+
buildId: 0,
|
|
485
485
|
outputModule: false,
|
|
486
486
|
environment: 'browser',
|
|
487
487
|
testPath,
|
|
@@ -578,6 +578,8 @@ const run = async () => {
|
|
|
578
578
|
rootPath: options.rootPath,
|
|
579
579
|
runtimeConfig,
|
|
580
580
|
taskId: 0,
|
|
581
|
+
// See the `buildId` note above: inert in browser mode.
|
|
582
|
+
buildId: 0,
|
|
581
583
|
outputModule: false,
|
|
582
584
|
environment: 'browser',
|
|
583
585
|
currentTask: taskStack[0],
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/** Stringify a single console argument for terminal forwarding. */
|
|
2
|
+
export const formatArg = (arg: unknown): string => {
|
|
3
|
+
if (arg === null) return 'null';
|
|
4
|
+
if (arg === undefined) return 'undefined';
|
|
5
|
+
if (typeof arg === 'string') return arg;
|
|
6
|
+
if (typeof arg === 'number' || typeof arg === 'boolean') return String(arg);
|
|
7
|
+
// `JSON.stringify(symbol)` is `undefined`, so a symbol must be handled before
|
|
8
|
+
// the JSON path or it would forward as an empty/`undefined` log.
|
|
9
|
+
if (typeof arg === 'symbol') return arg.toString();
|
|
10
|
+
if (arg instanceof Error) {
|
|
11
|
+
return arg.stack || `${arg.name}: ${arg.message}`;
|
|
12
|
+
}
|
|
13
|
+
try {
|
|
14
|
+
return JSON.stringify(arg, null, 2);
|
|
15
|
+
} catch {
|
|
16
|
+
return String(arg);
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
// Format specifiers understood by the browser console. `%c` applies CSS in a
|
|
21
|
+
// real console; forwarded to a terminal there is no styling, so it is consumed
|
|
22
|
+
// and dropped (matching how Node's `util.format` handles it). `%%` is a literal
|
|
23
|
+
// percent sign. Kept aligned with the browser console spec (no Node-only `%j`,
|
|
24
|
+
// since these logs originate in the browser).
|
|
25
|
+
// cspell:ignore sdifo WHATWG
|
|
26
|
+
const HAS_SPECIFIER = /%[sdifoOc%]/;
|
|
27
|
+
const SPECIFIER = /%[sdifoOc%]/g;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Join console arguments the way a console does. When the first argument is a
|
|
31
|
+
* string carrying `printf`-style specifiers, substitute the following arguments
|
|
32
|
+
* into it (consuming `%c` styles without emitting them), then append any
|
|
33
|
+
* leftover arguments. Otherwise fall back to a plain space-join.
|
|
34
|
+
*
|
|
35
|
+
* Without this, `console.info('%cText', 'font-weight:bold')` (e.g. React's
|
|
36
|
+
* DevTools notice) leaks the raw `%c` directive and its CSS argument into the
|
|
37
|
+
* forwarded terminal output.
|
|
38
|
+
*/
|
|
39
|
+
export const formatConsoleArgs = (args: unknown[]): string => {
|
|
40
|
+
const first = args[0];
|
|
41
|
+
if (typeof first !== 'string' || !HAS_SPECIFIER.test(first)) {
|
|
42
|
+
return args.map(formatArg).join(' ');
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
let next = 1;
|
|
46
|
+
const substituted = first.replace(SPECIFIER, (spec) => {
|
|
47
|
+
if (spec === '%%') return '%';
|
|
48
|
+
if (next >= args.length) return spec;
|
|
49
|
+
const arg = args[next++];
|
|
50
|
+
switch (spec) {
|
|
51
|
+
case '%c':
|
|
52
|
+
return ''; // CSS directive: swallow the style argument
|
|
53
|
+
case '%s':
|
|
54
|
+
return formatArg(arg);
|
|
55
|
+
case '%d':
|
|
56
|
+
case '%i': {
|
|
57
|
+
// Match the browser console formatter (WHATWG): parseInt on the value,
|
|
58
|
+
// so unit-suffixed strings like '42px' format as 42 (not NaN).
|
|
59
|
+
// `String()` first keeps Symbol safe — a bare `parseInt(symbol)` throws
|
|
60
|
+
// via ToString, whereas the spec maps a Symbol to NaN.
|
|
61
|
+
const num = Number.parseInt(String(arg), 10);
|
|
62
|
+
return Number.isNaN(num) ? 'NaN' : String(num);
|
|
63
|
+
}
|
|
64
|
+
case '%f': {
|
|
65
|
+
const num = Number.parseFloat(String(arg));
|
|
66
|
+
return Number.isNaN(num) ? 'NaN' : String(num);
|
|
67
|
+
}
|
|
68
|
+
default: // %o, %O
|
|
69
|
+
return formatArg(arg);
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
if (next >= args.length) {
|
|
74
|
+
return substituted;
|
|
75
|
+
}
|
|
76
|
+
return [substituted, ...args.slice(next).map(formatArg)].join(' ');
|
|
77
|
+
};
|
package/src/client/locator.ts
CHANGED
|
@@ -29,11 +29,7 @@ export type LocatorTextOptions = {
|
|
|
29
29
|
};
|
|
30
30
|
|
|
31
31
|
export type LocatorKeyboardModifier =
|
|
32
|
-
| '
|
|
33
|
-
| 'Control'
|
|
34
|
-
| 'ControlOrMeta'
|
|
35
|
-
| 'Meta'
|
|
36
|
-
| 'Shift';
|
|
32
|
+
'Alt' | 'Control' | 'ControlOrMeta' | 'Meta' | 'Shift';
|
|
37
33
|
|
|
38
34
|
export type LocatorMouseButton = 'left' | 'right' | 'middle';
|
|
39
35
|
|