@rstest/browser 0.11.6 → 0.11.8

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 (88) 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/browserRsbuild.d.ts +24 -4
  6. package/dist/browserV8Coverage.d.ts +15 -0
  7. package/dist/client/240~1.js +150 -0
  8. package/dist/{augmentExpect.d.ts → client/client/augmentExpect.d.ts} +1 -1
  9. package/dist/client/{browserRpc.d.ts → client/browserRpc.d.ts} +1 -1
  10. package/dist/client/{dispatchTransport.d.ts → client/dispatchTransport.d.ts} +8 -4
  11. package/dist/client/client/index.d.ts +2 -0
  12. package/dist/client/client/runIdentity.d.ts +12 -0
  13. package/dist/client/client/runner.d.ts +4 -0
  14. package/dist/client/client/snapshot.d.ts +27 -0
  15. package/dist/client/client/sourceMapSupport.d.ts +36 -0
  16. package/dist/{browser.js → client/index.js} +3 -102
  17. package/dist/client/protocol.d.ts +225 -0
  18. package/dist/client/rpcProtocol.d.ts +138 -0
  19. package/dist/client/runner.js +675 -0
  20. package/dist/client/sourceMap/sourceMapLoader.d.ts +25 -0
  21. package/dist/containerRpc.d.ts +27 -19
  22. package/dist/headedRunRegistry.d.ts +51 -0
  23. package/dist/headedScheduler.d.ts +10 -10
  24. package/dist/headlessScheduler.d.ts +5 -4
  25. package/dist/headlessTransport.d.ts +4 -2
  26. package/dist/hostPayloads.d.ts +1 -7
  27. package/dist/index.js +840 -330
  28. package/dist/protocol.d.ts +48 -8
  29. package/dist/providers/index.d.ts +21 -0
  30. package/dist/providers/playwright/v8Coverage.d.ts +2 -0
  31. package/dist/rpcProtocol.d.ts +1 -2
  32. package/dist/schedulerSeam.d.ts +5 -0
  33. package/dist/sourceMap/sourceMapLoader.d.ts +12 -1
  34. package/dist/watchRerunPlanner.d.ts +20 -9
  35. package/dist/watchSignals.d.ts +8 -1
  36. package/package.json +11 -11
  37. package/dist/33.js +0 -7
  38. package/dist/browser-container/container-static/css/index.0521ff95b1.css +0 -1
  39. package/dist/browser-container/container-static/js/683.4f821ce8f1.js +0 -194
  40. package/dist/browser-container/container-static/js/index.568aa7cb35.js +0 -1
  41. package/dist/browser.d.ts +0 -2
  42. package/src/augmentExpect.ts +0 -62
  43. package/src/browser.ts +0 -3
  44. package/src/browserExecutor.ts +0 -222
  45. package/src/browserRpcRegistry.ts +0 -57
  46. package/src/browserRsbuild.ts +0 -1927
  47. package/src/client/api.ts +0 -213
  48. package/src/client/browserRpc.ts +0 -86
  49. package/src/client/dispatchTransport.ts +0 -240
  50. package/src/client/entry.ts +0 -807
  51. package/src/client/locator.ts +0 -448
  52. package/src/client/snapshot.ts +0 -113
  53. package/src/client/sourceMapSupport.ts +0 -159
  54. package/src/concurrency.ts +0 -65
  55. package/src/configValidation.ts +0 -263
  56. package/src/containerRpc.ts +0 -206
  57. package/src/dispatchCapabilities.ts +0 -177
  58. package/src/dispatchRouter.ts +0 -82
  59. package/src/env.d.ts +0 -54
  60. package/src/headedScheduler.ts +0 -664
  61. package/src/headedSerialTaskQueue.ts +0 -23
  62. package/src/headlessScheduler.ts +0 -566
  63. package/src/headlessTransport.ts +0 -28
  64. package/src/hostController.ts +0 -1365
  65. package/src/hostPayloads.ts +0 -62
  66. package/src/index.ts +0 -51
  67. package/src/manifest.d.ts +0 -41
  68. package/src/protocol.ts +0 -225
  69. package/src/providers/index.ts +0 -126
  70. package/src/providers/playwright/compileLocator.ts +0 -130
  71. package/src/providers/playwright/dispatchBrowserRpc.ts +0 -372
  72. package/src/providers/playwright/expectUtils.ts +0 -57
  73. package/src/providers/playwright/implementation.ts +0 -35
  74. package/src/providers/playwright/index.ts +0 -1
  75. package/src/providers/playwright/runtime.ts +0 -159
  76. package/src/providers/playwright/textMatcher.ts +0 -10
  77. package/src/rpcProtocol.ts +0 -218
  78. package/src/runSession.ts +0 -110
  79. package/src/schedulerSeam.ts +0 -49
  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 -88
  84. package/src/watchRuntime.ts +0 -83
  85. package/src/watchSignals.ts +0 -93
  86. /package/dist/{rslib-runtime.js → 612~0.js} +0 -0
  87. /package/dist/client/{api.d.ts → client/api.d.ts} +0 -0
  88. /package/dist/client/{locator.d.ts → client/locator.d.ts} +0 -0
@@ -1,81 +1,5 @@
1
- import { DISPATCH_RESPONSE_TYPE, DISPATCH_RPC_BRIDGE_NAME as protocol_DISPATCH_RPC_BRIDGE_NAME, DISPATCH_RPC_REQUEST_TYPE as protocol_DISPATCH_RPC_REQUEST_TYPE, DISPATCH_MESSAGE_TYPE as protocol_DISPATCH_MESSAGE_TYPE, DISPATCH_NAMESPACE_BROWSER } from "./33.js";
2
- const DEFAULT_RPC_TIMEOUT_MS = 30000;
3
- const getRpcTimeout = ()=>window.__RSTEST_BROWSER_OPTIONS__?.rpcTimeout ?? DEFAULT_RPC_TIMEOUT_MS;
4
- const pendingRequests = new Map();
5
- let requestIdCounter = 0;
6
- let messageListenerInitialized = false;
7
- const createRequestId = (prefix)=>{
8
- if ('function' == typeof globalThis.crypto?.randomUUID) return globalThis.crypto.randomUUID();
9
- requestIdCounter += 1;
10
- return `${prefix}-${Date.now().toString(36)}-${requestIdCounter.toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
11
- };
12
- const isDispatchResponse = (value)=>'object' == typeof value && null !== value && 'requestId' in value && 'string' == typeof value.requestId;
13
- const settlePendingRequest = (response)=>{
14
- const pending = pendingRequests.get(response.requestId);
15
- if (!pending) return;
16
- pendingRequests.delete(response.requestId);
17
- if (response.stale) return void pending.reject(new Error(pending.staleMessage));
18
- if (response.error) return void pending.reject(new Error(response.error));
19
- pending.resolve(response.result);
20
- };
21
- const initMessageListener = ()=>{
22
- if (messageListenerInitialized) return;
23
- messageListenerInitialized = true;
24
- window.addEventListener('message', (event)=>{
25
- if (event.data?.type === DISPATCH_RESPONSE_TYPE) settlePendingRequest(event.data.payload);
26
- });
27
- };
28
- const unwrapDispatchBridgeResult = (requestId, result, staleMessage)=>{
29
- if (!isDispatchResponse(result)) throw new Error('Invalid dispatch bridge response payload.');
30
- if (result.requestId !== requestId) throw new Error(`Mismatched dispatch response id: expected ${requestId}, got ${result.requestId}`);
31
- if (result.stale) throw new Error(staleMessage);
32
- if (result.error) throw new Error(result.error);
33
- return result.result;
34
- };
35
- const dispatchRpc = ({ requestId, request, timeoutMs, timeoutMessage, staleMessage })=>{
36
- if (window.parent === window) {
37
- const dispatchBridge = window[protocol_DISPATCH_RPC_BRIDGE_NAME];
38
- if (!dispatchBridge) throw new Error('Dispatch RPC bridge is not available in top-level runner.');
39
- return new Promise((resolve, reject)=>{
40
- const timeoutId = setTimeout(()=>{
41
- reject(new Error(timeoutMessage));
42
- }, timeoutMs);
43
- const call = Promise.resolve(dispatchBridge(request)).then((result)=>unwrapDispatchBridgeResult(requestId, result, staleMessage));
44
- call.then((result)=>{
45
- clearTimeout(timeoutId);
46
- resolve(result);
47
- }).catch((error)=>{
48
- clearTimeout(timeoutId);
49
- reject(error instanceof Error ? error : new Error(String(error)));
50
- });
51
- });
52
- }
53
- initMessageListener();
54
- return new Promise((resolve, reject)=>{
55
- const timeoutId = setTimeout(()=>{
56
- pendingRequests.delete(requestId);
57
- reject(new Error(timeoutMessage));
58
- }, timeoutMs);
59
- pendingRequests.set(requestId, {
60
- staleMessage,
61
- resolve: (value)=>{
62
- clearTimeout(timeoutId);
63
- resolve(value);
64
- },
65
- reject: (error)=>{
66
- clearTimeout(timeoutId);
67
- reject(error);
68
- }
69
- });
70
- window.parent.postMessage({
71
- type: protocol_DISPATCH_MESSAGE_TYPE,
72
- payload: {
73
- type: protocol_DISPATCH_RPC_REQUEST_TYPE,
74
- payload: request
75
- }
76
- }, '*');
77
- });
78
- };
1
+ import { registerElementExpect } from "@rstest/core/internal/browser-runtime";
2
+ import { createRequestId, DISPATCH_NAMESPACE_BROWSER, dispatchRpc, getRpcTimeout } from "./240~1.js";
79
3
  const getUrlSearchParam = (name)=>{
80
4
  try {
81
5
  const value = new URL(window.location.href).searchParams.get(name);
@@ -89,11 +13,6 @@ const getCurrentTestPath = ()=>{
89
13
  if (!testPath) throw new Error("Browser RPC requires testFile in __RSTEST_BROWSER_OPTIONS__. This usually indicates the runner iframe was not configured by the container or URL.");
90
14
  return testPath;
91
15
  };
92
- const getCurrentRunId = ()=>{
93
- const runId = window.__RSTEST_BROWSER_OPTIONS__?.runId ?? getUrlSearchParam('runId');
94
- if (!runId) throw new Error("Browser RPC requires runId in __RSTEST_BROWSER_OPTIONS__. This usually indicates the runner iframe URL/config is stale or incomplete.");
95
- return runId;
96
- };
97
16
  const createBrowserDispatchRequest = (requestId, request)=>({
98
17
  requestId,
99
18
  namespace: DISPATCH_NAMESPACE_BROWSER,
@@ -110,7 +29,6 @@ const callBrowserRpc = async (payload)=>{
110
29
  const request = {
111
30
  id,
112
31
  testPath: getCurrentTestPath(),
113
- runId: getCurrentRunId(),
114
32
  ...payload
115
33
  };
116
34
  const dispatchRequest = createBrowserDispatchRequest(id, request);
@@ -562,22 +480,5 @@ const api_element = (locator)=>{
562
480
  if (!isLocator(locator)) throw new TypeError('expect.element() expects a Locator returned from @rstest/browser page.getBy* APIs.');
563
481
  return createElementExpect(locator, false);
564
482
  };
565
- const markBrowserElement = ()=>{
566
- Object.defineProperty(api_element, '__rstestBrowser', {
567
- value: true,
568
- configurable: false,
569
- enumerable: false,
570
- writable: false
571
- });
572
- };
573
- const installExpectElement = ()=>{
574
- const api = globalThis.RSTEST_API;
575
- const target = api?.expect;
576
- if (!target) throw new Error('RSTEST_API.expect is not registered yet. This usually indicates @rstest/browser was imported too early.');
577
- if ('function' != typeof target.element || !target.element.__rstestBrowser) {
578
- markBrowserElement();
579
- target.element = api_element;
580
- }
581
- };
582
- installExpectElement();
483
+ registerElementExpect(api_element);
583
484
  export { Locator, page, setTestIdAttribute };
@@ -0,0 +1,225 @@
1
+ import type { BrowserViewport } from '@rstest/core/internal/browser';
2
+ import type { BrowserRuntimeConfig, TestFileResult, TestInfo, TestResult } from '@rstest/core/internal/browser-runtime';
3
+ import type { SnapshotUpdateState } from '@vitest/snapshot';
4
+ export type { BrowserLocatorIR, BrowserRpcRequest, SnapshotRpcCall, SnapshotRpcMethod, SnapshotRpcMethodArgs, SnapshotRpcRequest } from './rpcProtocol.js';
5
+ export { validateBrowserRpcRequest } from './rpcProtocol.js';
6
+ export declare const DISPATCH_MESSAGE_TYPE = '__rstest_dispatch__';
7
+ export declare const DISPATCH_RESPONSE_TYPE = '__rstest_dispatch_response__';
8
+ export declare const DISPATCH_RPC_BRIDGE_NAME = '__rstest_dispatch_rpc__';
9
+ export declare const DISPATCH_RPC_REQUEST_TYPE = 'dispatch-rpc-request';
10
+ export declare const RSTEST_CONFIG_MESSAGE_TYPE = 'RSTEST_CONFIG';
11
+ export declare const NO_RPC_TIMEOUT = -1;
12
+ export declare const DISPATCH_NAMESPACE_RUNNER = 'runner';
13
+ export declare const DISPATCH_NAMESPACE_BROWSER = 'browser';
14
+ export declare const DISPATCH_NAMESPACE_FILE_CLEANUP = 'file-cleanup';
15
+ export declare const DISPATCH_NAMESPACE_SNAPSHOT = 'snapshot';
16
+ export declare const DISPATCH_METHOD_RPC = 'rpc';
17
+ export type SerializedRuntimeConfig = BrowserRuntimeConfig;
18
+ // `BrowserViewport` is a core config type (`@rstest/core` owns the canonical
19
+ // definition used by `NormalizedBrowserModeConfig`). Re-export it so the host
20
+ // assigns the SAME type across the seam instead of a hand-copied duplicate.
21
+ export type { BrowserViewport };
22
+ export type BrowserProjectRuntime = {
23
+ name: string;
24
+ environmentName: string;
25
+ projectRoot: string;
26
+ runtimeConfig: SerializedRuntimeConfig;
27
+ viewport?: BrowserViewport;
28
+ };
29
+ /**
30
+ * Test file info with associated project name.
31
+ * Used to track which project a test file belongs to.
32
+ */ export type TestFileInfo = {
33
+ testPath: string;
34
+ projectName: string;
35
+ };
36
+ export type FileCleanupDispatchMethod = 'start' | 'end';
37
+ export type FileCleanupDispatchPayload = {
38
+ projectName: string;
39
+ result?: TestFileResult;
40
+ runId?: string;
41
+ testPath: string;
42
+ };
43
+ /**
44
+ * The committed test-file set plus its monotonic version. The version is what
45
+ * the container acks once every iframe for that set exists in the DOM, so both
46
+ * halves must travel together — a set without its version cannot be acked.
47
+ */ export type VersionedTestFileSet = {
48
+ files: TestFileInfo[];
49
+ version: number;
50
+ };
51
+ /**
52
+ * Execution mode for browser tests.
53
+ * - 'run': Execute tests and report results (default)
54
+ * - 'collect': Only collect test metadata without running
55
+ */ export type BrowserExecutionMode = 'run' | 'collect';
56
+ /**
57
+ * Wire shape of a `log` client message payload. The host receives this and maps
58
+ * it onto core's {@link UserConsoleLog} (notably `level` → `name`); that mapper
59
+ * (`hostController.ts` `handleLog`) annotates its result as `UserConsoleLog`, so
60
+ * the map→core direction is compiler-checked. Owning the wire shape here as one
61
+ * named type keeps the host's input type from drifting away from the producer.
62
+ */ export type BrowserLogPayload = {
63
+ level: 'log' | 'warn' | 'error' | 'info' | 'debug';
64
+ content: string;
65
+ /**
66
+ * Owning project, resolved by the client from its manifest. The host must
67
+ * not re-derive it from `testPath` — concurrent projects can run the same
68
+ * file, so a path-keyed lookup can attribute the log to the wrong project.
69
+ */ projectName: string;
70
+ taskId?: string;
71
+ taskName?: string;
72
+ taskParentNames?: string[];
73
+ taskType?: 'file' | 'suite' | 'case';
74
+ testPath: string;
75
+ type: 'stdout' | 'stderr';
76
+ trace?: string;
77
+ };
78
+ export type BrowserHostConfig = {
79
+ rootPath: string;
80
+ projects: BrowserProjectRuntime[];
81
+ snapshot: {
82
+ updateSnapshot: SnapshotUpdateState;
83
+ };
84
+ testFile?: string;
85
+ /**
86
+ * The run identity this document executes under — the runner's SOLE identity
87
+ * source, adopted once at boot and stamped on every outbound message. Headed:
88
+ * the container confers its frame's current lease over the config handshake
89
+ * (so even an HMR full reload boots with the run the host is awaiting NOW).
90
+ * Headless: injected host-side as `${run.token}:${session.id}`. Never
91
+ * derivable from the URL.
92
+ */ runId?: string;
93
+ /**
94
+ * Base URL for runner (iframe) pages. Container origin; used as a fallback
95
+ * when a project has no entry in `projectRunnerUrls`.
96
+ */ runnerUrl?: string;
97
+ /**
98
+ * Per-project runner origin base URLs, keyed by project name. Each browser
99
+ * project runs on its own dev server, so the container must load each test
100
+ * file's iframe from that project's own origin.
101
+ */ projectRunnerUrls?: Record<string, string>;
102
+ /**
103
+ * WebSocket port for container RPC.
104
+ */ wsPort?: number;
105
+ /**
106
+ * Execution mode. Defaults to 'run'.
107
+ */ mode?: BrowserExecutionMode;
108
+ /**
109
+ * Debug mode. When true, enables verbose logging in browser.
110
+ */ debug?: boolean;
111
+ /** Timeout for RPC operations in milliseconds; negative values disable it. */ rpcTimeout?: number;
112
+ };
113
+ export declare const RSTEST_BROWSER_CACHE_CLEANERS_KEY = '@rstest/browser/cache-cleaners';
114
+ /**
115
+ * The wrapper every runner document posts over `postMessage` / the headless
116
+ * bridge. Identity rides BESIDE the payload, never inside it: `message`
117
+ * payloads reach core reporting (`RunnerEventSink`, `BlobReporter`) as-is, so a
118
+ * transport identity spread into them would leak a nondeterministic UUID into
119
+ * reporter output. `runId` is the identity the document was granted at boot
120
+ * (headed: the container's config handshake; headless: the injected inline
121
+ * options) — never re-derived from the URL or the frame. Absent only for a
122
+ * document that was never granted one; the headed host drops such messages.
123
+ */ export type RunnerEnvelope = {
124
+ runId?: string;
125
+ message: BrowserClientMessage;
126
+ };
127
+ export type BrowserClientMessage = {
128
+ type: 'ready';
129
+ } | {
130
+ type: 'file-start';
131
+ payload: {
132
+ testPath: string;
133
+ projectName: string;
134
+ };
135
+ } | {
136
+ type: 'case-result';
137
+ payload: TestResult;
138
+ } | {
139
+ type: 'file-complete';
140
+ payload: TestFileResult;
141
+ } | {
142
+ type: 'log';
143
+ payload: BrowserLogPayload;
144
+ } | {
145
+ type: 'fatal';
146
+ payload: {
147
+ message: string;
148
+ stack?: string;
149
+ };
150
+ } | {
151
+ type: 'complete';
152
+ } | {
153
+ type: 'collect-result';
154
+ payload: {
155
+ testPath: string;
156
+ project: string;
157
+ tests: TestInfo[];
158
+ };
159
+ } | {
160
+ type: 'collect-complete';
161
+ } | {
162
+ type: typeof DISPATCH_RPC_REQUEST_TYPE;
163
+ payload: BrowserDispatchRequest;
164
+ };
165
+ /**
166
+ * Lifecycle methods the runner emits via `dispatchRunnerLifecycle()` as
167
+ * dispatch-rpc-requests on the `runner` namespace (as opposed to the
168
+ * {@link BrowserClientMessage} types it `send()`s). The runner client imports
169
+ * this instead of redeclaring the list, so the emit site cannot drift from the
170
+ * host router.
171
+ */ export type RunnerLifecycleMethod = 'file-ready' | 'suite-start' | 'suite-result' | 'case-start';
172
+ /**
173
+ * {@link BrowserClientMessage} types that are forwarded to the `runner`
174
+ * namespace (by message `type`) rather than handled at the transport layer.
175
+ * `Extract` keeps this a checked subset of the message union. `ready` and
176
+ * `complete` are deliberately absent: they still arrive, but their only job
177
+ * is done at the dispatch gate and the router ignores them silently.
178
+ */ type RunnerMessageMethod = Extract<BrowserClientMessage['type'], 'file-start' | 'case-result' | 'file-complete' | 'log' | 'fatal'>;
179
+ /**
180
+ * Single source of truth for every method handled by the `runner` dispatch
181
+ * namespace. The host handler table is keyed by this union (a missing key is a
182
+ * compile error), so adding a runner method here forces a matching handler and
183
+ * cannot silently no-op at runtime.
184
+ */ export type RunnerDispatchMethod = RunnerLifecycleMethod | RunnerMessageMethod;
185
+ /**
186
+ * Transport-agnostic envelope used by host routing.
187
+ * `namespace + method + args + target` describes an operation independent of
188
+ * the underlying message channel, and `runToken` provides run-level isolation.
189
+ */ export type BrowserDispatchRequest = {
190
+ requestId: string;
191
+ // Optional so headed/container paths can adopt the same envelope even when
192
+ // run-token isolation is only enforced in headless scheduling today.
193
+ runToken?: number;
194
+ /**
195
+ * Headed run identity, stamped by the runner's dispatch transport from the
196
+ * identity its document adopted at boot. The headed host accepts a request
197
+ * iff this names a live run; headless keeps using the host-injected
198
+ * `runToken` instead (`runToken` is the CYCLE generation, `runId` is the
199
+ * RUN identity — they are not interchangeable).
200
+ */ runId?: string;
201
+ namespace: string;
202
+ method: string;
203
+ args?: unknown;
204
+ // Routing reads `namespace`, `method`, `runToken`, and `target.sessionId`
205
+ // (see dispatchRouter.ts / dispatchBrowserRpcRequest). `target.testFile` and
206
+ // `target.projectName` are carried for diagnostics / forward-compatibility and
207
+ // are NOT consulted for routing today — adding a routing-relevant field here
208
+ // means wiring a reader on the host side, which structural typing won't force.
209
+ target?: {
210
+ testFile?: string;
211
+ sessionId?: string;
212
+ projectName?: string;
213
+ };
214
+ };
215
+ /**
216
+ * Dispatch response envelope.
217
+ * `stale: true` signals a safe drop from an older run generation, not a failure.
218
+ */ export type BrowserDispatchResponse = {
219
+ requestId: string;
220
+ runToken?: number;
221
+ result?: unknown;
222
+ error?: string;
223
+ stale?: boolean;
224
+ };
225
+ export type BrowserDispatchHandler = (request: BrowserDispatchRequest) => Promise<unknown>;
@@ -0,0 +1,138 @@
1
+ export type BrowserLocatorText = {
2
+ type: 'string';
3
+ value: string;
4
+ } | {
5
+ type: 'regexp';
6
+ source: string;
7
+ flags?: string;
8
+ };
9
+ export type BrowserLocatorStep = {
10
+ type: 'getByRole';
11
+ role: string;
12
+ options?: {
13
+ name?: BrowserLocatorText;
14
+ exact?: boolean;
15
+ checked?: boolean;
16
+ disabled?: boolean;
17
+ expanded?: boolean;
18
+ selected?: boolean;
19
+ pressed?: boolean;
20
+ includeHidden?: boolean;
21
+ level?: number;
22
+ };
23
+ } | {
24
+ type: 'locator';
25
+ selector: string;
26
+ } | {
27
+ type: 'getByText';
28
+ text: BrowserLocatorText;
29
+ options?: {
30
+ exact?: boolean;
31
+ };
32
+ } | {
33
+ type: 'getByLabel';
34
+ text: BrowserLocatorText;
35
+ options?: {
36
+ exact?: boolean;
37
+ };
38
+ } | {
39
+ type: 'getByPlaceholder';
40
+ text: BrowserLocatorText;
41
+ options?: {
42
+ exact?: boolean;
43
+ };
44
+ } | {
45
+ type: 'getByAltText';
46
+ text: BrowserLocatorText;
47
+ options?: {
48
+ exact?: boolean;
49
+ };
50
+ } | {
51
+ type: 'getByTitle';
52
+ text: BrowserLocatorText;
53
+ options?: {
54
+ exact?: boolean;
55
+ };
56
+ } | {
57
+ type: 'getByTestId';
58
+ text: BrowserLocatorText;
59
+ } | {
60
+ type: 'filter';
61
+ options: {
62
+ hasText?: BrowserLocatorText;
63
+ hasNotText?: BrowserLocatorText;
64
+ has?: BrowserLocatorIR;
65
+ hasNot?: BrowserLocatorIR;
66
+ };
67
+ } | {
68
+ type: 'and';
69
+ locator: BrowserLocatorIR;
70
+ } | {
71
+ type: 'or';
72
+ locator: BrowserLocatorIR;
73
+ } | {
74
+ type: 'nth';
75
+ index: number;
76
+ } | {
77
+ type: 'first';
78
+ } | {
79
+ type: 'last';
80
+ };
81
+ export type BrowserLocatorIR = {
82
+ steps: BrowserLocatorStep[];
83
+ };
84
+ export type BrowserRpcRequest = {
85
+ id: string;
86
+ /** Absolute test file path for locating runner iframe */ testPath: string;
87
+ kind: 'locator' | 'expect' | 'config';
88
+ locator: BrowserLocatorIR;
89
+ method: string;
90
+ args: unknown[];
91
+ /**
92
+ * Negation for expect matchers (equivalent to Playwright expect(...).not).
93
+ * Only meaningful for kind === 'expect'.
94
+ */ isNot?: boolean;
95
+ /** Optional assertion timeout override (ms). Falls back to the host-provided assertion timeout. */ timeout?: number;
96
+ };
97
+ export declare const validateBrowserRpcRequest: (payload: unknown) => BrowserRpcRequest;
98
+ /**
99
+ * Single source of truth for snapshot RPC methods and their argument shapes.
100
+ * The request union, the client sender, both host-side mappers, and every
101
+ * exhaustiveness check derive from this map — adding or renaming a method here
102
+ * forces a compile error at every site that has not been updated.
103
+ */ export type SnapshotRpcMethodArgs = {
104
+ resolveSnapshotPath: {
105
+ testPath: string;
106
+ };
107
+ readSnapshotFile: {
108
+ filepath: string;
109
+ };
110
+ saveSnapshotFile: {
111
+ filepath: string;
112
+ content: string;
113
+ };
114
+ removeSnapshotFile: {
115
+ filepath: string;
116
+ };
117
+ };
118
+ export type SnapshotRpcMethod = keyof SnapshotRpcMethodArgs;
119
+ /**
120
+ * Snapshot RPC request from runner iframe.
121
+ * The container will forward these to the host via WebSocket RPC.
122
+ */ export type SnapshotRpcRequest = {
123
+ [M in SnapshotRpcMethod]: {
124
+ id: string;
125
+ method: M;
126
+ args: SnapshotRpcMethodArgs[M];
127
+ };
128
+ }[SnapshotRpcMethod];
129
+ /**
130
+ * Client-side snapshot RPC call (request without the transport `id`).
131
+ * Distributive over {@link SnapshotRpcMethod} so `method` and `args` stay paired
132
+ * at the call site — a mismatched pair fails to compile.
133
+ */ export type SnapshotRpcCall = {
134
+ [M in SnapshotRpcMethod]: {
135
+ method: M;
136
+ args: SnapshotRpcMethodArgs[M];
137
+ };
138
+ }[SnapshotRpcMethod];