@rstest/browser 0.11.5 → 0.11.7

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.
Files changed (86) hide show
  1. package/dist/browser-container/container-static/css/index.43daaf6c93.css +1 -0
  2. package/dist/browser-container/container-static/js/260.3739fe815c.js +194 -0
  3. package/dist/browser-container/container-static/js/index.c0f87bfb3e.js +1 -0
  4. package/dist/browser-container/index.html +1 -1
  5. package/dist/browserExecutor.d.ts +7 -5
  6. package/dist/browserRsbuild.d.ts +139 -0
  7. package/dist/browserV8Coverage.d.ts +15 -0
  8. package/dist/client/240~1.js +150 -0
  9. package/dist/{augmentExpect.d.ts → client/client/augmentExpect.d.ts} +1 -1
  10. package/dist/client/{browserRpc.d.ts → client/browserRpc.d.ts} +1 -1
  11. package/dist/client/{dispatchTransport.d.ts → client/dispatchTransport.d.ts} +8 -4
  12. package/dist/client/client/index.d.ts +2 -0
  13. package/dist/client/client/runIdentity.d.ts +12 -0
  14. package/dist/client/client/runner.d.ts +4 -0
  15. package/dist/client/client/snapshot.d.ts +27 -0
  16. package/dist/client/client/sourceMapSupport.d.ts +36 -0
  17. package/dist/{browser.js → client/index.js} +3 -102
  18. package/dist/client/protocol.d.ts +225 -0
  19. package/dist/client/rpcProtocol.d.ts +138 -0
  20. package/dist/client/runner.js +675 -0
  21. package/dist/client/sourceMap/sourceMapLoader.d.ts +25 -0
  22. package/dist/containerRpc.d.ts +60 -0
  23. package/dist/dispatchCapabilities.d.ts +1 -2
  24. package/dist/headedRunRegistry.d.ts +51 -0
  25. package/dist/headedScheduler.d.ts +58 -0
  26. package/dist/headlessScheduler.d.ts +38 -0
  27. package/dist/headlessTransport.d.ts +4 -2
  28. package/dist/hostController.d.ts +12 -47
  29. package/dist/hostPayloads.d.ts +24 -0
  30. package/dist/index.js +2019 -1516
  31. package/dist/protocol.d.ts +48 -8
  32. package/dist/providers/index.d.ts +21 -0
  33. package/dist/providers/playwright/v8Coverage.d.ts +2 -0
  34. package/dist/rpcProtocol.d.ts +1 -2
  35. package/dist/schedulerSeam.d.ts +42 -0
  36. package/dist/sourceMap/sourceMapLoader.d.ts +12 -1
  37. package/dist/watchRerunPlanner.d.ts +20 -4
  38. package/dist/watchRuntime.d.ts +21 -0
  39. package/dist/watchSignals.d.ts +29 -0
  40. package/package.json +12 -12
  41. package/dist/33.js +0 -7
  42. package/dist/browser-container/container-static/css/index.0521ff95b1.css +0 -1
  43. package/dist/browser-container/container-static/js/506.b2f920fa67.js +0 -194
  44. package/dist/browser-container/container-static/js/index.d27fd63f5e.js +0 -1
  45. package/dist/browser.d.ts +0 -2
  46. package/dist/headlessLatestRerunScheduler.d.ts +0 -18
  47. package/src/augmentExpect.ts +0 -62
  48. package/src/browser.ts +0 -3
  49. package/src/browserExecutor.ts +0 -140
  50. package/src/browserRpcRegistry.ts +0 -57
  51. package/src/client/api.ts +0 -213
  52. package/src/client/browserRpc.ts +0 -86
  53. package/src/client/dispatchTransport.ts +0 -240
  54. package/src/client/entry.ts +0 -807
  55. package/src/client/locator.ts +0 -448
  56. package/src/client/snapshot.ts +0 -113
  57. package/src/client/sourceMapSupport.ts +0 -159
  58. package/src/concurrency.ts +0 -65
  59. package/src/configValidation.ts +0 -263
  60. package/src/dispatchCapabilities.ts +0 -182
  61. package/src/dispatchRouter.ts +0 -82
  62. package/src/env.d.ts +0 -54
  63. package/src/headedSerialTaskQueue.ts +0 -23
  64. package/src/headlessLatestRerunScheduler.ts +0 -76
  65. package/src/headlessTransport.ts +0 -28
  66. package/src/hostController.ts +0 -4633
  67. package/src/index.ts +0 -51
  68. package/src/manifest.d.ts +0 -41
  69. package/src/protocol.ts +0 -225
  70. package/src/providers/index.ts +0 -126
  71. package/src/providers/playwright/compileLocator.ts +0 -130
  72. package/src/providers/playwright/dispatchBrowserRpc.ts +0 -372
  73. package/src/providers/playwright/expectUtils.ts +0 -57
  74. package/src/providers/playwright/implementation.ts +0 -35
  75. package/src/providers/playwright/index.ts +0 -1
  76. package/src/providers/playwright/runtime.ts +0 -159
  77. package/src/providers/playwright/textMatcher.ts +0 -10
  78. package/src/rpcProtocol.ts +0 -218
  79. package/src/runSession.ts +0 -110
  80. package/src/sessionRegistry.ts +0 -89
  81. package/src/sourceMap/sourceMapLoader.ts +0 -96
  82. package/src/viewportPresets.ts +0 -69
  83. package/src/watchRerunPlanner.ts +0 -77
  84. /package/dist/{rslib-runtime.js → 612~0.js} +0 -0
  85. /package/dist/client/{api.d.ts → client/api.d.ts} +0 -0
  86. /package/dist/client/{locator.d.ts → client/locator.d.ts} +0 -0
@@ -1,65 +0,0 @@
1
- import {
2
- getNumCpus,
3
- parseWorkers,
4
- resolveWorkerCount,
5
- } from '@rstest/core/internal/browser';
6
- import type { Rstest } from '@rstest/core/internal/browser';
7
-
8
- // Re-export the shared worker primitives so existing consumers (and unit tests
9
- // importing from `../src/concurrency`) keep a stable import surface.
10
- export { getNumCpus, parseWorkers };
11
-
12
- // The browser headless path caps CPU-derived workers at 12 and halves that
13
- // capped base in watch; the shared `resolveWorkerCount` helper owns the
14
- // `maxWorkers` override and workload clamp.
15
- const DEFAULT_MAX_HEADLESS_WORKERS = 12;
16
-
17
- type HeadlessConcurrencyContext = Pick<Rstest, 'command'> & {
18
- normalizedConfig: {
19
- pool: {
20
- maxWorkers?: string | number;
21
- };
22
- };
23
- };
24
-
25
- const resolveHeadlessWorkerCount = ({
26
- command,
27
- maxWorkers,
28
- totalTasks,
29
- numCpus = getNumCpus(),
30
- }: {
31
- command: HeadlessConcurrencyContext['command'];
32
- maxWorkers?: string | number;
33
- totalTasks: number;
34
- numCpus?: number;
35
- }): number => {
36
- const base = Math.max(Math.min(DEFAULT_MAX_HEADLESS_WORKERS, numCpus - 1), 1);
37
- return resolveWorkerCount({
38
- command,
39
- maxWorkers,
40
- totalTasks,
41
- recommended: base,
42
- watchRecommended: Math.max(Math.floor(base / 2), 1),
43
- numCpus,
44
- });
45
- };
46
-
47
- export const resolveDefaultHeadlessWorkers = (
48
- command: HeadlessConcurrencyContext['command'],
49
- numCpus: number = getNumCpus(),
50
- ): number =>
51
- resolveHeadlessWorkerCount({
52
- command,
53
- totalTasks: Number.POSITIVE_INFINITY,
54
- numCpus,
55
- });
56
-
57
- export const getHeadlessConcurrency = (
58
- context: HeadlessConcurrencyContext,
59
- totalTests: number,
60
- ): number =>
61
- resolveHeadlessWorkerCount({
62
- command: context.command,
63
- maxWorkers: context.normalizedConfig.pool.maxWorkers,
64
- totalTasks: totalTests,
65
- });
@@ -1,263 +0,0 @@
1
- import {
2
- browserIgnoredRuntimeConfigKeys,
3
- color,
4
- logger,
5
- type RstestContext,
6
- type RuntimeConfig,
7
- } from '@rstest/core/internal/browser';
8
- import { resolveBrowserViewportPreset } from './viewportPresets';
9
-
10
- type BrowserProjectConfig =
11
- RstestContext['projects'][number]['normalizedConfig'];
12
-
13
- /**
14
- * Per-key warning for a browser-ignored RuntimeConfig field, keyed by the exact
15
- * RuntimeConfig keys the `executorCapabilities` table marks 'ignored-warn' /
16
- * 'stripped'. {@link reportUnsupportedBrowserOptions} iterates the table's
17
- * {@link browserIgnoredRuntimeConfigKeys} and looks each key up here, so the
18
- * warnings are genuinely table-driven.
19
- */
20
- const ignoredKeyWarnings: Partial<
21
- Record<
22
- keyof RuntimeConfig,
23
- {
24
- /** True when the project's value is non-default (worth warning about). */
25
- isNonDefault: (config: BrowserProjectConfig) => boolean;
26
- message: (config: BrowserProjectConfig) => string;
27
- /**
28
- * Warn only on browser-only runs. Global-only config (copied onto every
29
- * project) that a mixed repo may legitimately set for its node projects.
30
- */
31
- browserOnly?: boolean;
32
- }
33
- >
34
- > = {
35
- testEnvironment: {
36
- isNonDefault: (config) => config.testEnvironment.name !== 'node',
37
- message: (config) =>
38
- `Ignoring testEnvironment '${config.testEnvironment.name}' in browser ` +
39
- 'mode: the browser itself is the test environment.',
40
- },
41
- isolate: {
42
- isNonDefault: (config) => config.isolate === false,
43
- message: () =>
44
- 'Ignoring isolate: false in browser mode: each test file still runs in ' +
45
- 'a fresh context.',
46
- browserOnly: true,
47
- },
48
- federation: {
49
- isNonDefault: (config) => config.federation === true,
50
- message: () =>
51
- 'Ignoring federation in browser mode: it only applies to the Node runner.',
52
- browserOnly: true,
53
- },
54
- detectAsyncLeaks: {
55
- isNonDefault: (config) => config.detectAsyncLeaks === true,
56
- message: () =>
57
- 'Ignoring detectAsyncLeaks in browser mode: it relies on node ' +
58
- 'async_hooks.',
59
- },
60
- logHeapUsage: {
61
- isNonDefault: (config) => config.logHeapUsage === true,
62
- message: () => 'Ignoring logHeapUsage in browser mode.',
63
- },
64
- };
65
-
66
- /**
67
- * Browser-ignored keys handled outside the generic warn loop: `coverage` is
68
- * 'stripped' but gets the dedicated provider check in
69
- * {@link reportUnsupportedBrowserOptions} (a v8 hard error on browser-only
70
- * runs, a warning in mixed runs), not a plain "set → warn".
71
- */
72
- const speciallyHandledIgnoredKeys: (keyof RuntimeConfig)[] = ['coverage'];
73
-
74
- /**
75
- * Every browser-ignored RuntimeConfig key this module checks — the union of the
76
- * warn descriptors and the specially-handled keys. Exported for the lockstep
77
- * test that asserts it covers {@link browserIgnoredRuntimeConfigKeys}.
78
- */
79
- export const browserValidatedIgnoredKeys: (keyof RuntimeConfig)[] = [
80
- ...(Object.keys(ignoredKeyWarnings) as (keyof RuntimeConfig)[]),
81
- ...speciallyHandledIgnoredKeys,
82
- ];
83
-
84
- // Anti-#1389 lockstep (runs at module load): fail loudly if the
85
- // `executorCapabilities` table gains an 'ignored-warn' / 'stripped' browser key
86
- // that this validation does not cover, instead of it becoming a silent no-op.
87
- const assertIgnoredKeysCovered = (): void => {
88
- const covered = new Set<string>(browserValidatedIgnoredKeys);
89
- const uncovered = browserIgnoredRuntimeConfigKeys.filter(
90
- (key) => !covered.has(key),
91
- );
92
- if (uncovered.length > 0) {
93
- throw new Error(
94
- 'Browser config validation is out of sync with executorCapabilities: ' +
95
- `no check for ignored RuntimeConfig field(s): ${uncovered.join(', ')}. ` +
96
- 'Add a descriptor to `ignoredKeyWarnings` or `speciallyHandledIgnoredKeys`.',
97
- );
98
- }
99
- };
100
- assertIgnoredKeysCovered();
101
-
102
- const SUPPORTED_PROVIDERS = ['playwright'] as const;
103
-
104
- const isPlainObject = (value: unknown): value is Record<string, unknown> => {
105
- return Object.prototype.toString.call(value) === '[object Object]';
106
- };
107
-
108
- const validateViewport = (viewport: unknown): void => {
109
- if (viewport == null) {
110
- return;
111
- }
112
-
113
- if (typeof viewport === 'string') {
114
- const presetId = viewport.trim();
115
- if (!presetId) {
116
- throw new Error('browser.viewport must be a non-empty preset id.');
117
- }
118
- if (!resolveBrowserViewportPreset(presetId)) {
119
- throw new Error(
120
- `browser.viewport must be a valid preset id. Received: ${viewport}`,
121
- );
122
- }
123
- return;
124
- }
125
-
126
- if (isPlainObject(viewport)) {
127
- const width = (viewport as any).width;
128
- const height = (viewport as any).height;
129
- if (!Number.isFinite(width) || width <= 0) {
130
- throw new Error('browser.viewport.width must be a positive number.');
131
- }
132
- if (!Number.isFinite(height) || height <= 0) {
133
- throw new Error('browser.viewport.height must be a positive number.');
134
- }
135
- return;
136
- }
137
-
138
- throw new Error(
139
- 'browser.viewport must be either a preset id or { width, height }.',
140
- );
141
- };
142
-
143
- /**
144
- * Warn (or hard-error) on node-only config that is silently ignored under
145
- * `browser.enabled`. Prevents the #1389 class of silent no-ops. The per-key
146
- * warnings are driven by the `executorCapabilities` table: the loop iterates
147
- * {@link browserIgnoredRuntimeConfigKeys} and looks each key up in
148
- * {@link ignoredKeyWarnings}; `coverage` (and `pool`, which is not a
149
- * RuntimeConfig field) keep bespoke handling below.
150
- *
151
- * Scoping rules: `coverage` and `isolate` are global-only config copied onto
152
- * every project, so a v8 hard-error / isolate warning is gated to browser-only
153
- * runs — a mixed repo legitimately sets them for its node projects and must not
154
- * get unsilenceable noise on a correct configuration.
155
- */
156
- const reportUnsupportedBrowserOptions = (context: RstestContext): void => {
157
- const browserProjects = context.projects.filter(
158
- (project) => project.normalizedConfig.browser.enabled,
159
- );
160
- if (browserProjects.length === 0) {
161
- return;
162
- }
163
- const isBrowserOnlyRun = browserProjects.length === context.projects.length;
164
-
165
- // `coverage`, `pool` and `isolate` are global-only config (not settable per
166
- // project), read from the root normalized config.
167
- const globalConfig = context.normalizedConfig;
168
-
169
- const { coverage } = globalConfig;
170
- // `list` never collects coverage, so the v8 guard must not block listing.
171
- if (
172
- context.command !== 'list' &&
173
- coverage.enabled &&
174
- coverage.provider === 'v8'
175
- ) {
176
- if (isBrowserOnlyRun) {
177
- throw new Error(
178
- "Coverage provider 'v8' is not supported in browser mode: browser " +
179
- 'projects produce no v8 coverage. Use the default istanbul provider ' +
180
- "(coverage.provider: 'istanbul') for browser coverage.",
181
- );
182
- }
183
- logger.warn(
184
- color.yellow(
185
- "Coverage provider 'v8' produces no coverage for browser project " +
186
- "files; use the 'istanbul' provider to collect browser coverage. " +
187
- 'Node projects will still use v8.',
188
- ),
189
- );
190
- }
191
-
192
- // Node-only options silently ignored under browser.enabled. Collected into a
193
- // Set so each distinct warning is emitted once, not per project.
194
- const warnings = new Set<string>();
195
-
196
- if (globalConfig.pool.type !== 'forks') {
197
- warnings.add(
198
- `Ignoring pool.type '${globalConfig.pool.type}' in browser mode.`,
199
- );
200
- }
201
- if (globalConfig.pool.execArgv && globalConfig.pool.execArgv.length > 0) {
202
- warnings.add('Ignoring pool.execArgv in browser mode.');
203
- }
204
- // Table-driven warnings: for every browser-ignored RuntimeConfig key, warn
205
- // when a browser project sets it to a non-default value. `isolate` (and any
206
- // other global-only key) is copied onto every project, so reading it per
207
- // project matches the old global read; the Set dedupes the repeats.
208
- for (const project of browserProjects) {
209
- const config = project.normalizedConfig;
210
- for (const key of browserIgnoredRuntimeConfigKeys) {
211
- const descriptor = ignoredKeyWarnings[key];
212
- if (!descriptor) {
213
- // Specially handled elsewhere (e.g. `coverage`).
214
- continue;
215
- }
216
- if (descriptor.browserOnly && !isBrowserOnlyRun) {
217
- continue;
218
- }
219
- if (descriptor.isNonDefault(config)) {
220
- warnings.add(descriptor.message(config));
221
- }
222
- }
223
- }
224
-
225
- for (const message of warnings) {
226
- logger.warn(color.yellow(message));
227
- }
228
- };
229
-
230
- export const validateBrowserConfig = (context: RstestContext): void => {
231
- for (const project of context.projects) {
232
- const { browser, output } = project.normalizedConfig;
233
- if (!browser.enabled) {
234
- continue;
235
- }
236
-
237
- if (!browser.provider) {
238
- throw new Error(
239
- 'browser.provider is required when browser.enabled is true.',
240
- );
241
- }
242
-
243
- if (!SUPPORTED_PROVIDERS.includes(browser.provider)) {
244
- throw new Error(
245
- `browser.provider must be one of: ${SUPPORTED_PROVIDERS.join(', ')}.`,
246
- );
247
- }
248
-
249
- validateViewport(browser.viewport);
250
-
251
- if (!isPlainObject(browser.providerOptions)) {
252
- throw new Error('browser.providerOptions must be a plain object.');
253
- }
254
-
255
- if (output?.bundleDependencies === false) {
256
- throw new Error(
257
- 'output.bundleDependencies false is not supported in browser mode.',
258
- );
259
- }
260
- }
261
-
262
- reportUnsupportedBrowserOptions(context);
263
- };
@@ -1,182 +0,0 @@
1
- import type { Reporter } from '@rstest/core/internal/browser';
2
- import { HostDispatchRouter } from './dispatchRouter';
3
- import {
4
- DISPATCH_NAMESPACE_RUNNER,
5
- DISPATCH_NAMESPACE_SNAPSHOT,
6
- } from './protocol';
7
- import type {
8
- BrowserClientMessage,
9
- BrowserDispatchHandler,
10
- BrowserDispatchRequest,
11
- RunnerDispatchMethod,
12
- SnapshotRpcMethod,
13
- SnapshotRpcMethodArgs,
14
- SnapshotRpcRequest,
15
- } from './protocol';
16
-
17
- export type HostDispatchRouterOptions = ConstructorParameters<
18
- typeof HostDispatchRouter
19
- >[0];
20
-
21
- type RunnerPayload<TType extends BrowserClientMessage['type']> =
22
- Extract<BrowserClientMessage, { type: TType }> extends {
23
- payload: infer TPayload;
24
- }
25
- ? TPayload
26
- : never;
27
-
28
- type ReporterHookArg<THook extends keyof Reporter> =
29
- NonNullable<Reporter[THook]> extends (...args: infer TArgs) => unknown
30
- ? TArgs[0]
31
- : never;
32
-
33
- type RunnerDispatchFileReadyPayload = ReporterHookArg<'onTestFileReady'>;
34
- type RunnerDispatchSuiteStartPayload = ReporterHookArg<'onTestSuiteStart'>;
35
- type RunnerDispatchSuiteResultPayload = ReporterHookArg<'onTestSuiteResult'>;
36
- type RunnerDispatchCaseStartPayload = ReporterHookArg<'onTestCaseStart'>;
37
-
38
- type RunnerDispatchCallbacks = {
39
- onTestFileStart: (payload: RunnerPayload<'file-start'>) => Promise<void>;
40
- onTestFileReady: (payload: RunnerDispatchFileReadyPayload) => Promise<void>;
41
- onTestSuiteStart: (payload: RunnerDispatchSuiteStartPayload) => Promise<void>;
42
- onTestSuiteResult: (
43
- payload: RunnerDispatchSuiteResultPayload,
44
- ) => Promise<void>;
45
- onTestCaseStart: (payload: RunnerDispatchCaseStartPayload) => Promise<void>;
46
- onTestCaseResult: (payload: RunnerPayload<'case-result'>) => Promise<void>;
47
- onTestFileComplete: (
48
- payload: RunnerPayload<'file-complete'>,
49
- ) => Promise<void>;
50
- onLog: (payload: RunnerPayload<'log'>) => Promise<void>;
51
- onFatal: (payload: RunnerPayload<'fatal'>) => Promise<void>;
52
- };
53
-
54
- type CreateHostDispatchRouterOptions = {
55
- routerOptions?: HostDispatchRouterOptions;
56
- runnerCallbacks: RunnerDispatchCallbacks;
57
- runSnapshotRpc: (request: SnapshotRpcRequest) => Promise<unknown>;
58
- extensionHandlers?: Map<string, BrowserDispatchHandler>;
59
- onDuplicateNamespace?: (namespace: string) => void;
60
- };
61
-
62
- /**
63
- * Builds a typed {@link SnapshotRpcRequest} from the untrusted wire envelope,
64
- * one builder per method. Keyed by {@link SnapshotRpcMethod}, so adding or
65
- * renaming a method in the union forces a matching entry here — a stale name
66
- * becomes a compile error instead of silently falling through to `null`. The
67
- * `args` casts are the unavoidable trust boundary for inbound wire data.
68
- */
69
- const snapshotRequestBuilders: {
70
- [M in SnapshotRpcMethod]: (
71
- id: string,
72
- args: BrowserDispatchRequest['args'],
73
- ) => Extract<SnapshotRpcRequest, { method: M }>;
74
- } = {
75
- resolveSnapshotPath: (id, args) => ({
76
- id,
77
- method: 'resolveSnapshotPath',
78
- args: args as SnapshotRpcMethodArgs['resolveSnapshotPath'],
79
- }),
80
- readSnapshotFile: (id, args) => ({
81
- id,
82
- method: 'readSnapshotFile',
83
- args: args as SnapshotRpcMethodArgs['readSnapshotFile'],
84
- }),
85
- saveSnapshotFile: (id, args) => ({
86
- id,
87
- method: 'saveSnapshotFile',
88
- args: args as SnapshotRpcMethodArgs['saveSnapshotFile'],
89
- }),
90
- removeSnapshotFile: (id, args) => ({
91
- id,
92
- method: 'removeSnapshotFile',
93
- args: args as SnapshotRpcMethodArgs['removeSnapshotFile'],
94
- }),
95
- };
96
-
97
- const toSnapshotRpcRequest = (
98
- request: BrowserDispatchRequest,
99
- ): SnapshotRpcRequest | null => {
100
- const builder = snapshotRequestBuilders[
101
- request.method as SnapshotRpcMethod
102
- ] as
103
- | ((id: string, args: BrowserDispatchRequest['args']) => SnapshotRpcRequest)
104
- | undefined;
105
- return builder ? builder(request.requestId, request.args) : null;
106
- };
107
-
108
- export const createHostDispatchRouter = ({
109
- routerOptions,
110
- runnerCallbacks,
111
- runSnapshotRpc,
112
- extensionHandlers,
113
- onDuplicateNamespace,
114
- }: CreateHostDispatchRouterOptions): HostDispatchRouter => {
115
- const router = new HostDispatchRouter(routerOptions);
116
-
117
- // Keyed by RunnerDispatchMethod so adding a runner method to that union forces
118
- // a handler entry here (a missing key is a compile error) — the previous
119
- // `switch` with `default: break` silently dropped unhandled methods. The
120
- // `args` casts are checked against each callback's parameter type, so a wrong
121
- // payload type also fails to compile.
122
- const runnerMethodHandlers: {
123
- [M in RunnerDispatchMethod]: (
124
- args: BrowserDispatchRequest['args'],
125
- ) => Promise<void>;
126
- } = {
127
- 'file-start': (args) =>
128
- runnerCallbacks.onTestFileStart(args as RunnerPayload<'file-start'>),
129
- 'file-ready': (args) =>
130
- runnerCallbacks.onTestFileReady(args as RunnerDispatchFileReadyPayload),
131
- 'suite-start': (args) =>
132
- runnerCallbacks.onTestSuiteStart(args as RunnerDispatchSuiteStartPayload),
133
- 'suite-result': (args) =>
134
- runnerCallbacks.onTestSuiteResult(
135
- args as RunnerDispatchSuiteResultPayload,
136
- ),
137
- 'case-start': (args) =>
138
- runnerCallbacks.onTestCaseStart(args as RunnerDispatchCaseStartPayload),
139
- 'case-result': (args) =>
140
- runnerCallbacks.onTestCaseResult(args as RunnerPayload<'case-result'>),
141
- 'file-complete': (args) =>
142
- runnerCallbacks.onTestFileComplete(
143
- args as RunnerPayload<'file-complete'>,
144
- ),
145
- log: (args) => runnerCallbacks.onLog(args as RunnerPayload<'log'>),
146
- fatal: (args) => runnerCallbacks.onFatal(args as RunnerPayload<'fatal'>),
147
- };
148
-
149
- router.register(
150
- DISPATCH_NAMESPACE_RUNNER,
151
- async (request: BrowserDispatchRequest) => {
152
- // `request.method` is untrusted wire data, so the lookup may miss. Unknown
153
- // methods are ignored for forward-compatibility with newer runners,
154
- // matching the previous `default: break`.
155
- await runnerMethodHandlers[request.method as RunnerDispatchMethod]?.(
156
- request.args,
157
- );
158
- },
159
- );
160
-
161
- router.register(
162
- DISPATCH_NAMESPACE_SNAPSHOT,
163
- async (request: BrowserDispatchRequest) => {
164
- const snapshotRequest = toSnapshotRpcRequest(request);
165
- if (!snapshotRequest) {
166
- return undefined;
167
- }
168
- return runSnapshotRpc(snapshotRequest);
169
- },
170
- );
171
-
172
- for (const [namespace, handler] of extensionHandlers ?? []) {
173
- if (router.has(namespace)) {
174
- onDuplicateNamespace?.(namespace);
175
- continue;
176
- }
177
-
178
- router.register(namespace, handler);
179
- }
180
-
181
- return router;
182
- };
@@ -1,82 +0,0 @@
1
- import type {
2
- BrowserDispatchRequest,
3
- BrowserDispatchResponse,
4
- } from './protocol';
5
-
6
- type DispatchHandler = (request: BrowserDispatchRequest) => Promise<unknown>;
7
-
8
- type HostDispatchRouterOptions = {
9
- isRunTokenStale?: (runToken: number) => boolean;
10
- onStale?: (request: BrowserDispatchRequest) => void;
11
- };
12
-
13
- const toErrorMessage = (error: unknown): string => {
14
- return error instanceof Error ? error.message : String(error);
15
- };
16
-
17
- /**
18
- * Host-side routing layer for dispatch envelopes.
19
- * Capabilities are registered by namespace, while routing stays transport-agnostic.
20
- */
21
- export class HostDispatchRouter {
22
- private handlers = new Map<string, DispatchHandler>();
23
- private options: HostDispatchRouterOptions;
24
-
25
- constructor(options?: HostDispatchRouterOptions) {
26
- this.options = options ?? {};
27
- }
28
-
29
- register(namespace: string, handler: DispatchHandler): void {
30
- this.handlers.set(namespace, handler);
31
- }
32
-
33
- unregister(namespace: string): void {
34
- this.handlers.delete(namespace);
35
- }
36
-
37
- has(namespace: string): boolean {
38
- return this.handlers.has(namespace);
39
- }
40
-
41
- async dispatch(
42
- request: BrowserDispatchRequest,
43
- ): Promise<BrowserDispatchResponse> {
44
- const runToken = request.runToken;
45
- if (
46
- typeof runToken === 'number' &&
47
- this.options.isRunTokenStale?.(runToken)
48
- ) {
49
- // Return a stale marker so callers can drop old-run writes safely.
50
- this.options.onStale?.(request);
51
- return {
52
- requestId: request.requestId,
53
- runToken,
54
- stale: true,
55
- };
56
- }
57
-
58
- const handler = this.handlers.get(request.namespace);
59
- if (!handler) {
60
- return {
61
- requestId: request.requestId,
62
- runToken,
63
- error: `No dispatch handler registered for namespace "${request.namespace}"`,
64
- };
65
- }
66
-
67
- try {
68
- const result = await handler(request);
69
- return {
70
- requestId: request.requestId,
71
- runToken,
72
- result,
73
- };
74
- } catch (error) {
75
- return {
76
- requestId: request.requestId,
77
- runToken,
78
- error: toErrorMessage(error),
79
- };
80
- }
81
- }
82
- }
package/src/env.d.ts DELETED
@@ -1,54 +0,0 @@
1
- import { DISPATCH_MESSAGE_TYPE, DISPATCH_RPC_BRIDGE_NAME } from './protocol';
2
- import type {
3
- BrowserClientMessage,
4
- BrowserDispatchRequest,
5
- BrowserHostConfig,
6
- } from './protocol';
7
-
8
- declare module '@rstest/browser-manifest' {
9
- export type ManifestProjectConfig = {
10
- name: string;
11
- environmentName: string;
12
- projectRoot: string;
13
- };
14
-
15
- export type ManifestTestContext = {
16
- getTestKeys: () => string[];
17
- loadTest: (key: string) => Promise<unknown>;
18
- projectRoot: string;
19
- };
20
-
21
- export const projects: ManifestProjectConfig[];
22
-
23
- export const projectSetupLoaders: Record<
24
- string,
25
- Array<() => Promise<unknown>>
26
- >;
27
-
28
- export const projectTestContexts: Record<string, ManifestTestContext>;
29
-
30
- // Backward compatibility exports
31
- export const projectConfig: ManifestProjectConfig | undefined;
32
- export const setupLoaders: Array<() => Promise<unknown>>;
33
- export const getTestKeys: () => string[];
34
- export const loadTest: (key: string) => Promise<unknown>;
35
- }
36
-
37
- declare global {
38
- const RSTEST_VERSION: string;
39
-
40
- interface Window {
41
- __RSTEST_BROWSER_OPTIONS__?: BrowserHostConfig;
42
- // Keyed by the sentinel constants so the declared global name and the
43
- // constant are the same source — renaming a constant moves this key with it,
44
- // and every `window[CONST]` access site stays in lockstep automatically.
45
- [DISPATCH_MESSAGE_TYPE]?: (message: BrowserClientMessage) => void;
46
- [DISPATCH_RPC_BRIDGE_NAME]?: (
47
- request: BrowserDispatchRequest,
48
- ) => Promise<unknown>;
49
- __rstest_container_dispatch__?: (data: unknown) => void;
50
- __rstest_container_on__?: (data: unknown) => void;
51
- __RSTEST_DONE__?: boolean;
52
- __RSTEST_TEST_FILES__?: string[];
53
- }
54
- }
@@ -1,23 +0,0 @@
1
- type HeadedSerialTask = () => Promise<void>;
2
-
3
- type HeadedSerialTaskQueue = {
4
- enqueue: (task: HeadedSerialTask) => Promise<void>;
5
- };
6
-
7
- /**
8
- * Serializes headed browser file execution so only one task runs at a time.
9
- * The queue keeps draining even if an earlier task rejects.
10
- */
11
- export const createHeadedSerialTaskQueue = (): HeadedSerialTaskQueue => {
12
- let queue: Promise<void> = Promise.resolve();
13
-
14
- const enqueue = (task: HeadedSerialTask): Promise<void> => {
15
- const next = queue.then(task);
16
- queue = next.catch(() => {});
17
- return next;
18
- };
19
-
20
- return {
21
- enqueue,
22
- };
23
- };