@rstest/browser 0.8.5 → 0.9.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.
Files changed (79) hide show
  1. package/LICENSE-APACHE-2.0 +202 -0
  2. package/NOTICE +11 -0
  3. package/dist/361.js +8 -0
  4. package/dist/augmentExpect.d.ts +73 -0
  5. package/dist/browser-container/container-static/css/index.5c72297783.css +1 -0
  6. package/dist/browser-container/container-static/js/{565.226c9ef5.js → 101.36a8ccdf84.js} +4024 -3856
  7. package/dist/browser-container/container-static/js/101.36a8ccdf84.js.LICENSE.txt +1 -0
  8. package/dist/browser-container/container-static/js/{index.c1d17467.js → index.0687a8142a.js} +742 -692
  9. package/dist/browser-container/container-static/js/{lib-react.97ee79b0.js → lib-react.dcf2a5e57a.js} +10 -10
  10. package/dist/browser-container/container-static/js/lib-react.dcf2a5e57a.js.LICENSE.txt +1 -0
  11. package/dist/browser-container/index.html +1 -1
  12. package/dist/browser.d.ts +2 -0
  13. package/dist/browser.js +583 -0
  14. package/dist/browserRpcRegistry.d.ts +18 -0
  15. package/dist/client/api.d.ts +3 -0
  16. package/dist/client/browserRpc.d.ts +2 -0
  17. package/dist/client/dispatchTransport.d.ts +11 -0
  18. package/dist/client/entry.d.ts +1 -5
  19. package/dist/client/locator.d.ts +125 -0
  20. package/dist/client/snapshot.d.ts +0 -6
  21. package/dist/concurrency.d.ts +12 -0
  22. package/dist/dispatchCapabilities.d.ts +34 -0
  23. package/dist/dispatchRouter.d.ts +20 -0
  24. package/dist/headlessLatestRerunScheduler.d.ts +19 -0
  25. package/dist/headlessTransport.d.ts +12 -0
  26. package/dist/index.js +1580 -258
  27. package/dist/protocol.d.ts +44 -33
  28. package/dist/providers/index.d.ts +79 -0
  29. package/dist/providers/playwright/compileLocator.d.ts +3 -0
  30. package/dist/providers/playwright/dispatchBrowserRpc.d.ts +13 -0
  31. package/dist/providers/playwright/expectUtils.d.ts +24 -0
  32. package/dist/providers/playwright/implementation.d.ts +2 -0
  33. package/dist/providers/playwright/index.d.ts +1 -0
  34. package/dist/providers/playwright/runtime.d.ts +5 -0
  35. package/dist/providers/playwright/textMatcher.d.ts +8 -0
  36. package/dist/rpcProtocol.d.ts +145 -0
  37. package/dist/runSession.d.ts +33 -0
  38. package/dist/sessionRegistry.d.ts +34 -0
  39. package/dist/sourceMap/sourceMapLoader.d.ts +14 -0
  40. package/dist/watchRerunPlanner.d.ts +21 -0
  41. package/package.json +15 -10
  42. package/src/AGENTS.md +128 -0
  43. package/src/augmentExpect.ts +62 -0
  44. package/src/browser.ts +3 -0
  45. package/src/browserRpcRegistry.ts +57 -0
  46. package/src/client/AGENTS.md +82 -0
  47. package/src/client/api.ts +213 -0
  48. package/src/client/browserRpc.ts +86 -0
  49. package/src/client/dispatchTransport.ts +178 -0
  50. package/src/client/entry.ts +96 -33
  51. package/src/client/locator.ts +452 -0
  52. package/src/client/snapshot.ts +32 -97
  53. package/src/client/sourceMapSupport.ts +26 -37
  54. package/src/concurrency.ts +62 -0
  55. package/src/dispatchCapabilities.ts +162 -0
  56. package/src/dispatchRouter.ts +82 -0
  57. package/src/env.d.ts +8 -1
  58. package/src/headlessLatestRerunScheduler.ts +76 -0
  59. package/src/headlessTransport.ts +28 -0
  60. package/src/hostController.ts +1292 -367
  61. package/src/protocol.ts +66 -31
  62. package/src/providers/index.ts +103 -0
  63. package/src/providers/playwright/compileLocator.ts +130 -0
  64. package/src/providers/playwright/dispatchBrowserRpc.ts +372 -0
  65. package/src/providers/playwright/expectUtils.ts +57 -0
  66. package/src/providers/playwright/implementation.ts +33 -0
  67. package/src/providers/playwright/index.ts +1 -0
  68. package/src/providers/playwright/runtime.ts +32 -0
  69. package/src/providers/playwright/textMatcher.ts +10 -0
  70. package/src/rpcProtocol.ts +220 -0
  71. package/src/runSession.ts +110 -0
  72. package/src/sessionRegistry.ts +89 -0
  73. package/src/sourceMap/sourceMapLoader.ts +96 -0
  74. package/src/watchRerunPlanner.ts +77 -0
  75. package/dist/browser-container/container-static/css/index.5a71c757.css +0 -1
  76. package/dist/browser-container/container-static/js/565.226c9ef5.js.LICENSE.txt +0 -1
  77. package/dist/browser-container/container-static/js/lib-react.97ee79b0.js.LICENSE.txt +0 -1
  78. package/dist/browser-container/container-static/js/scheduler.5accca0c.js +0 -407
  79. package/dist/browser-container/scheduler.html +0 -19
@@ -1,12 +1,12 @@
1
- /*! For license information please see lib-react.97ee79b0.js.LICENSE.txt */
2
- /*! For license information please see lib-react.97ee79b0.js.LICENSE.txt */ "use strict";
3
- (self.webpackChunk_rstest_browser_ui = self.webpackChunk_rstest_browser_ui || []).push([
1
+ /*! For license information please see lib-react.dcf2a5e57a.js.LICENSE.txt */
2
+ /*! LICENSE: lib-react.dcf2a5e57a.js.LICENSE.txt */ "use strict";
3
+ (self.rspackChunk_rstest_browser_ui = self.rspackChunk_rstest_browser_ui || []).push([
4
4
  [
5
5
  "783"
6
6
  ],
7
7
  {
8
8
  7816 (e, t, n) {
9
- var r, l = n(1099), a = n(162), o = n(5466);
9
+ var r, l = n(1099), a = n(162), o = n(3085);
10
10
  function i(e) {
11
11
  var t = "https://react.dev/errors/" + e;
12
12
  if (1 < arguments.length) {
@@ -1865,19 +1865,19 @@
1865
1865
  }
1866
1866
  var r7 = D.S;
1867
1867
  D.S = function(e, t) {
1868
- i3 = el(), "object" == typeof t && null !== t && "function" == typeof t.then && function(e, t) {
1868
+ i3 = el(), "object" == typeof t && null !== t && "function" == typeof t.then && function(e) {
1869
1869
  if (null === r4) {
1870
- var n = r4 = [];
1870
+ var t = r4 = [];
1871
1871
  r8 = 0, r6 = uJ(), r5 = {
1872
1872
  status: "pending",
1873
1873
  value: void 0,
1874
1874
  then: function(e) {
1875
- n.push(e);
1875
+ t.push(e);
1876
1876
  }
1877
1877
  };
1878
1878
  }
1879
- r8++, t.then(r9, r9);
1880
- }(0, t), null !== r7 && r7(e, t);
1879
+ r8++, e.then(r9, r9);
1880
+ }(t), null !== r7 && r7(e, t);
1881
1881
  };
1882
1882
  var le = I(null);
1883
1883
  function lt() {
@@ -7947,7 +7947,7 @@
7947
7947
  }
7948
7948
  })(), e.exports = n(7816);
7949
7949
  },
7950
- 5466 (e, t, n) {
7950
+ 3085 (e, t, n) {
7951
7951
  (function e() {
7952
7952
  if ("u" > typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ && "function" == typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE) try {
7953
7953
  __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(e);
@@ -0,0 +1 @@
1
+ /*! LICENSE: lib-react.dcf2a5e57a.js.LICENSE.txt */
@@ -12,7 +12,7 @@
12
12
  <script>
13
13
  window.__RSTEST_BROWSER_OPTIONS__ = __RSTEST_OPTIONS_PLACEHOLDER__;
14
14
  </script>
15
- <script defer src="/container-static/js/lib-react.97ee79b0.js"></script><script defer src="/container-static/js/565.226c9ef5.js"></script><script defer src="/container-static/js/index.c1d17467.js"></script><link href="/container-static/css/index.5a71c757.css" rel="stylesheet"></head>
15
+ <script defer src="/container-static/js/lib-react.dcf2a5e57a.js"></script><script defer src="/container-static/js/101.36a8ccdf84.js"></script><script defer src="/container-static/js/index.0687a8142a.js"></script><link href="/container-static/css/index.5c72297783.css" rel="stylesheet"></head>
16
16
  <body>
17
17
  <div id="root"></div>
18
18
  </body>
@@ -0,0 +1,2 @@
1
+ import './augmentExpect';
2
+ export * from './client/api';
@@ -0,0 +1,583 @@
1
+ import { DISPATCH_RESPONSE_TYPE, DISPATCH_METHOD_RPC, DISPATCH_RPC_REQUEST_TYPE, DISPATCH_MESSAGE_TYPE, DISPATCH_NAMESPACE_BROWSER } from "./361.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.__rstest_dispatch_rpc__;
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: DISPATCH_MESSAGE_TYPE,
72
+ payload: {
73
+ type: DISPATCH_RPC_REQUEST_TYPE,
74
+ payload: request
75
+ }
76
+ }, '*');
77
+ });
78
+ };
79
+ const getUrlSearchParam = (name)=>{
80
+ try {
81
+ const value = new URL(window.location.href).searchParams.get(name);
82
+ return value ?? void 0;
83
+ } catch {
84
+ return;
85
+ }
86
+ };
87
+ const getCurrentTestPath = ()=>{
88
+ const testPath = window.__RSTEST_BROWSER_OPTIONS__?.testFile ?? getUrlSearchParam('testFile');
89
+ 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
+ return testPath;
91
+ };
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
+ const createBrowserDispatchRequest = (requestId, request)=>({
98
+ requestId,
99
+ namespace: DISPATCH_NAMESPACE_BROWSER,
100
+ method: DISPATCH_METHOD_RPC,
101
+ args: request,
102
+ target: {
103
+ testFile: request.testPath
104
+ }
105
+ });
106
+ const callBrowserRpc = async (payload)=>{
107
+ if ('config' === payload.kind && window.__RSTEST_BROWSER_OPTIONS__?.mode === 'collect') return;
108
+ const id = createRequestId('browser-rpc');
109
+ const rpcTimeout = getRpcTimeout();
110
+ const request = {
111
+ id,
112
+ testPath: getCurrentTestPath(),
113
+ runId: getCurrentRunId(),
114
+ ...payload
115
+ };
116
+ const dispatchRequest = createBrowserDispatchRequest(id, request);
117
+ return dispatchRpc({
118
+ requestId: id,
119
+ request: dispatchRequest,
120
+ timeoutMs: rpcTimeout,
121
+ staleMessage: 'Stale browser RPC request ignored.',
122
+ timeoutMessage: `Browser RPC timeout after ${rpcTimeout / 1000}s: ${request.kind}.${request.method}`
123
+ });
124
+ };
125
+ const serializeText = (value)=>{
126
+ if ('string' == typeof value) return {
127
+ type: 'string',
128
+ value
129
+ };
130
+ return {
131
+ type: 'regexp',
132
+ source: value.source,
133
+ flags: value.flags
134
+ };
135
+ };
136
+ class Locator {
137
+ ir;
138
+ constructor(ir){
139
+ this.ir = ir;
140
+ }
141
+ getByRole(role, options) {
142
+ const next = {
143
+ steps: [
144
+ ...this.ir.steps,
145
+ {
146
+ type: 'getByRole',
147
+ role,
148
+ options: options ? {
149
+ ...options,
150
+ name: void 0 === options.name ? void 0 : serializeText(options.name)
151
+ } : void 0
152
+ }
153
+ ]
154
+ };
155
+ return new Locator(next);
156
+ }
157
+ locator(selector) {
158
+ return new Locator({
159
+ steps: [
160
+ ...this.ir.steps,
161
+ {
162
+ type: 'locator',
163
+ selector
164
+ }
165
+ ]
166
+ });
167
+ }
168
+ getByText(text, options) {
169
+ return new Locator({
170
+ steps: [
171
+ ...this.ir.steps,
172
+ {
173
+ type: 'getByText',
174
+ text: serializeText(text),
175
+ options
176
+ }
177
+ ]
178
+ });
179
+ }
180
+ getByLabel(text, options) {
181
+ return new Locator({
182
+ steps: [
183
+ ...this.ir.steps,
184
+ {
185
+ type: 'getByLabel',
186
+ text: serializeText(text),
187
+ options
188
+ }
189
+ ]
190
+ });
191
+ }
192
+ getByPlaceholder(text, options) {
193
+ return new Locator({
194
+ steps: [
195
+ ...this.ir.steps,
196
+ {
197
+ type: 'getByPlaceholder',
198
+ text: serializeText(text),
199
+ options
200
+ }
201
+ ]
202
+ });
203
+ }
204
+ getByAltText(text, options) {
205
+ return new Locator({
206
+ steps: [
207
+ ...this.ir.steps,
208
+ {
209
+ type: 'getByAltText',
210
+ text: serializeText(text),
211
+ options
212
+ }
213
+ ]
214
+ });
215
+ }
216
+ getByTitle(text, options) {
217
+ return new Locator({
218
+ steps: [
219
+ ...this.ir.steps,
220
+ {
221
+ type: 'getByTitle',
222
+ text: serializeText(text),
223
+ options
224
+ }
225
+ ]
226
+ });
227
+ }
228
+ getByTestId(text) {
229
+ return new Locator({
230
+ steps: [
231
+ ...this.ir.steps,
232
+ {
233
+ type: 'getByTestId',
234
+ text: serializeText(text)
235
+ }
236
+ ]
237
+ });
238
+ }
239
+ filter(options) {
240
+ return new Locator({
241
+ steps: [
242
+ ...this.ir.steps,
243
+ {
244
+ type: 'filter',
245
+ options: {
246
+ hasText: options.hasText ? serializeText(options.hasText) : void 0,
247
+ hasNotText: options.hasNotText ? serializeText(options.hasNotText) : void 0,
248
+ has: void 0 === options.has ? void 0 : isLocator(options.has) ? options.has.ir : (()=>{
249
+ throw new TypeError('Locator.filter({ has }) expects a Locator returned from @rstest/browser page.getBy* APIs.');
250
+ })(),
251
+ hasNot: void 0 === options.hasNot ? void 0 : isLocator(options.hasNot) ? options.hasNot.ir : (()=>{
252
+ throw new TypeError('Locator.filter({ hasNot }) expects a Locator returned from @rstest/browser page.getBy* APIs.');
253
+ })()
254
+ }
255
+ }
256
+ ]
257
+ });
258
+ }
259
+ and(other) {
260
+ if (!isLocator(other)) throw new TypeError('Locator.and() expects a Locator returned from @rstest/browser page.getBy* APIs.');
261
+ return new Locator({
262
+ steps: [
263
+ ...this.ir.steps,
264
+ {
265
+ type: 'and',
266
+ locator: other.ir
267
+ }
268
+ ]
269
+ });
270
+ }
271
+ or(other) {
272
+ if (!isLocator(other)) throw new TypeError('Locator.or() expects a Locator returned from @rstest/browser page.getBy* APIs.');
273
+ return new Locator({
274
+ steps: [
275
+ ...this.ir.steps,
276
+ {
277
+ type: 'or',
278
+ locator: other.ir
279
+ }
280
+ ]
281
+ });
282
+ }
283
+ nth(index) {
284
+ return new Locator({
285
+ steps: [
286
+ ...this.ir.steps,
287
+ {
288
+ type: 'nth',
289
+ index
290
+ }
291
+ ]
292
+ });
293
+ }
294
+ first() {
295
+ return new Locator({
296
+ steps: [
297
+ ...this.ir.steps,
298
+ {
299
+ type: 'first'
300
+ }
301
+ ]
302
+ });
303
+ }
304
+ last() {
305
+ return new Locator({
306
+ steps: [
307
+ ...this.ir.steps,
308
+ {
309
+ type: 'last'
310
+ }
311
+ ]
312
+ });
313
+ }
314
+ async click(options) {
315
+ await this.callLocator('click', void 0 === options ? [] : [
316
+ options
317
+ ]);
318
+ }
319
+ async dblclick(options) {
320
+ await this.callLocator('dblclick', void 0 === options ? [] : [
321
+ options
322
+ ]);
323
+ }
324
+ async fill(value, options) {
325
+ await this.callLocator('fill', void 0 === options ? [
326
+ value
327
+ ] : [
328
+ value,
329
+ options
330
+ ]);
331
+ }
332
+ async hover(options) {
333
+ await this.callLocator('hover', void 0 === options ? [] : [
334
+ options
335
+ ]);
336
+ }
337
+ async press(key, options) {
338
+ await this.callLocator('press', void 0 === options ? [
339
+ key
340
+ ] : [
341
+ key,
342
+ options
343
+ ]);
344
+ }
345
+ async clear() {
346
+ await this.callLocator('clear', []);
347
+ }
348
+ async check(options) {
349
+ await this.callLocator('check', void 0 === options ? [] : [
350
+ options
351
+ ]);
352
+ }
353
+ async uncheck(options) {
354
+ await this.callLocator('uncheck', void 0 === options ? [] : [
355
+ options
356
+ ]);
357
+ }
358
+ async focus(options) {
359
+ await this.callLocator('focus', void 0 === options ? [] : [
360
+ options
361
+ ]);
362
+ }
363
+ async blur(options) {
364
+ await this.callLocator('blur', void 0 === options ? [] : [
365
+ options
366
+ ]);
367
+ }
368
+ async scrollIntoViewIfNeeded(options) {
369
+ await this.callLocator('scrollIntoViewIfNeeded', void 0 === options ? [] : [
370
+ options
371
+ ]);
372
+ }
373
+ async waitFor(options) {
374
+ await this.callLocator('waitFor', void 0 === options ? [] : [
375
+ options
376
+ ]);
377
+ }
378
+ async dispatchEvent(type, eventInit) {
379
+ if ('string' != typeof type || !type) throw new TypeError('Locator.dispatchEvent() expects a non-empty event type string.');
380
+ await this.callLocator('dispatchEvent', void 0 === eventInit ? [
381
+ type
382
+ ] : [
383
+ type,
384
+ eventInit
385
+ ]);
386
+ }
387
+ async selectOption(value, options) {
388
+ if ('string' != typeof value && !(Array.isArray(value) && value.every((v)=>'string' == typeof v))) throw new TypeError('Locator.selectOption() only supports string or string[] values in browser mode.');
389
+ await this.callLocator('selectOption', void 0 === options ? [
390
+ value
391
+ ] : [
392
+ value,
393
+ options
394
+ ]);
395
+ }
396
+ async setInputFiles(files, options) {
397
+ if ('string' != typeof files && !(Array.isArray(files) && files.every((v)=>'string' == typeof v))) throw new TypeError('Locator.setInputFiles() only supports file path string or string[] in browser mode.');
398
+ await this.callLocator('setInputFiles', void 0 === options ? [
399
+ files
400
+ ] : [
401
+ files,
402
+ options
403
+ ]);
404
+ }
405
+ async callLocator(method, args) {
406
+ await callBrowserRpc({
407
+ kind: 'locator',
408
+ locator: this.ir,
409
+ method,
410
+ args
411
+ });
412
+ }
413
+ }
414
+ const browserPageQueryMethods = [
415
+ 'locator',
416
+ 'getByRole',
417
+ 'getByText',
418
+ 'getByLabel',
419
+ 'getByPlaceholder',
420
+ 'getByAltText',
421
+ 'getByTitle',
422
+ 'getByTestId'
423
+ ];
424
+ const rootLocator = new Locator({
425
+ steps: []
426
+ });
427
+ const createBrowserPage = ()=>Object.fromEntries(browserPageQueryMethods.map((methodName)=>[
428
+ methodName,
429
+ rootLocator[methodName].bind(rootLocator)
430
+ ]));
431
+ const page = createBrowserPage();
432
+ const isLocator = (value)=>value instanceof Locator;
433
+ const setTestIdAttribute = async (attribute)=>{
434
+ await callBrowserRpc({
435
+ kind: 'config',
436
+ locator: {
437
+ steps: []
438
+ },
439
+ method: 'setTestIdAttribute',
440
+ args: [
441
+ attribute
442
+ ]
443
+ });
444
+ };
445
+ const serializeMatcherText = (value)=>serializeText(value);
446
+ const createElementExpect = (locator, isNot)=>{
447
+ const callExpect = async (method, args, timeout)=>{
448
+ await callBrowserRpc({
449
+ kind: 'expect',
450
+ locator: locator.ir,
451
+ method,
452
+ args,
453
+ isNot,
454
+ timeout
455
+ });
456
+ };
457
+ const api = {
458
+ async toBeVisible (options) {
459
+ await callExpect('toBeVisible', [], options?.timeout);
460
+ },
461
+ async toBeHidden (options) {
462
+ await callExpect('toBeHidden', [], options?.timeout);
463
+ },
464
+ async toBeEnabled (options) {
465
+ await callExpect('toBeEnabled', [], options?.timeout);
466
+ },
467
+ async toBeDisabled (options) {
468
+ await callExpect('toBeDisabled', [], options?.timeout);
469
+ },
470
+ async toBeChecked (options) {
471
+ await callExpect('toBeChecked', [], options?.timeout);
472
+ },
473
+ async toBeUnchecked (options) {
474
+ await callExpect('toBeUnchecked', [], options?.timeout);
475
+ },
476
+ async toBeAttached (options) {
477
+ await callExpect('toBeAttached', [], options?.timeout);
478
+ },
479
+ async toBeDetached (options) {
480
+ await callExpect('toBeDetached', [], options?.timeout);
481
+ },
482
+ async toBeEditable (options) {
483
+ await callExpect('toBeEditable', [], options?.timeout);
484
+ },
485
+ async toBeFocused (options) {
486
+ await callExpect('toBeFocused', [], options?.timeout);
487
+ },
488
+ async toBeEmpty (options) {
489
+ await callExpect('toBeEmpty', [], options?.timeout);
490
+ },
491
+ async toBeInViewport (options) {
492
+ const ratio = options?.ratio;
493
+ await callExpect('toBeInViewport', void 0 === ratio ? [] : [
494
+ ratio
495
+ ], options?.timeout);
496
+ },
497
+ async toHaveText (text, options) {
498
+ await callExpect('toHaveText', [
499
+ serializeMatcherText(text)
500
+ ], options?.timeout);
501
+ },
502
+ async toContainText (text, options) {
503
+ await callExpect('toContainText', [
504
+ serializeMatcherText(text)
505
+ ], options?.timeout);
506
+ },
507
+ async toHaveValue (value, options) {
508
+ await callExpect('toHaveValue', [
509
+ serializeMatcherText(value)
510
+ ], options?.timeout);
511
+ },
512
+ async toHaveId (value, options) {
513
+ await callExpect('toHaveId', [
514
+ serializeMatcherText(value)
515
+ ], options?.timeout);
516
+ },
517
+ async toHaveAttribute (name, value, options) {
518
+ const args = void 0 === value ? [
519
+ name
520
+ ] : [
521
+ name,
522
+ serializeMatcherText(value)
523
+ ];
524
+ await callExpect('toHaveAttribute', args, options?.timeout);
525
+ },
526
+ async toHaveClass (value, options) {
527
+ await callExpect('toHaveClass', [
528
+ serializeMatcherText(value)
529
+ ], options?.timeout);
530
+ },
531
+ async toHaveCount (count, options) {
532
+ await callExpect('toHaveCount', [
533
+ count
534
+ ], options?.timeout);
535
+ },
536
+ async toHaveCSS (name, value, options) {
537
+ if ('string' != typeof name || !name) throw new TypeError('toHaveCSS expects a non-empty CSS property name');
538
+ await callExpect('toHaveCSS', [
539
+ name,
540
+ serializeMatcherText(value)
541
+ ], options?.timeout);
542
+ },
543
+ async toHaveJSProperty (name, value, options) {
544
+ if ('string' != typeof name || !name) throw new TypeError('toHaveJSProperty expects a non-empty property name');
545
+ await callExpect('toHaveJSProperty', [
546
+ name,
547
+ value
548
+ ], options?.timeout);
549
+ }
550
+ };
551
+ const withNot = api;
552
+ Object.defineProperty(withNot, 'not', {
553
+ configurable: false,
554
+ enumerable: false,
555
+ get () {
556
+ return createElementExpect(locator, !isNot);
557
+ }
558
+ });
559
+ return withNot;
560
+ };
561
+ const api_element = (locator)=>{
562
+ if (!isLocator(locator)) throw new TypeError('expect.element() expects a Locator returned from @rstest/browser page.getBy* APIs.');
563
+ return createElementExpect(locator, false);
564
+ };
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();
583
+ export { Locator, page, setTestIdAttribute };
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Runtime allowlists for Browser RPC methods.
3
+ *
4
+ * Planned capabilities are intentionally documented in comments (not runtime
5
+ * data) to keep this module focused on host-side validation.
6
+ *
7
+ * Planned gaps (non-exhaustive):
8
+ * - Locator query/interop: filter({ hasNot, hasNotText }), locator.selector/length,
9
+ * locator.query()/element()/elements()/all(), page.elementLocator(element),
10
+ * locators.extend(...)
11
+ * - Locator actions: tripleClick, hover out, drag/drop helpers
12
+ * - Assertions: a11y matchers (accessible name/description), toHaveRole,
13
+ * toHaveValues
14
+ * - Artifacts intentionally excluded for now: screenshot/toMatchScreenshot/
15
+ * trace/video
16
+ */
17
+ export declare const supportedLocatorActions: Set<string>;
18
+ export declare const supportedExpectElementMatchers: Set<string>;
@@ -0,0 +1,3 @@
1
+ import { Locator, page, setTestIdAttribute } from './locator';
2
+ export type { BrowserPage, BrowserSerializable, LocatorBlurOptions, LocatorCheckOptions, LocatorClickOptions, LocatorDblclickOptions, LocatorDispatchEventInit, LocatorFillOptions, LocatorFilterOptions, LocatorFocusOptions, LocatorGetByRoleOptions, LocatorHoverOptions, LocatorKeyboardModifier, LocatorMouseButton, LocatorPosition, LocatorPressOptions, LocatorScrollIntoViewIfNeededOptions, LocatorSelectOptionOptions, LocatorSetInputFilesOptions, LocatorTextOptions, LocatorWaitForOptions, } from './locator';
3
+ export { Locator, page, setTestIdAttribute };
@@ -0,0 +1,2 @@
1
+ import type { BrowserRpcRequest } from '../rpcProtocol';
2
+ export declare const callBrowserRpc: <T>(payload: Omit<BrowserRpcRequest, "id" | "testPath" | "runId">) => Promise<T>;
@@ -0,0 +1,11 @@
1
+ import type { BrowserDispatchRequest } from '../protocol';
2
+ export declare const DEFAULT_RPC_TIMEOUT_MS = 30000;
3
+ export declare const getRpcTimeout: () => number;
4
+ export declare const createRequestId: (prefix: string) => string;
5
+ export declare const dispatchRpc: <T>({ requestId, request, timeoutMs, timeoutMessage, staleMessage, }: {
6
+ requestId: string;
7
+ request: BrowserDispatchRequest;
8
+ timeoutMs: number;
9
+ timeoutMessage: string;
10
+ staleMessage: string;
11
+ }) => Promise<T>;