@rstest/browser 0.10.4 → 0.10.6

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 (43) hide show
  1. package/dist/browser-container/container-static/css/index.0521ff95b1.css +1 -0
  2. package/dist/browser-container/container-static/js/{3.d3d6c6e4cf.js → 854.c59f71483d.js} +5690 -5718
  3. package/dist/browser-container/container-static/js/854.c59f71483d.js.LICENSE.txt +1 -0
  4. package/dist/browser-container/container-static/js/{index.8fb1588e4a.js → index.fedc31dff3.js} +9 -9
  5. package/dist/browser-container/index.html +1 -1
  6. package/dist/browserRpcRegistry.d.ts +1 -2
  7. package/dist/client/api.d.ts +1 -1
  8. package/dist/client/dispatchTransport.d.ts +3 -5
  9. package/dist/client/locator.d.ts +2 -3
  10. package/dist/concurrency.d.ts +2 -0
  11. package/dist/dispatchCapabilities.d.ts +2 -2
  12. package/dist/dispatchRouter.d.ts +2 -3
  13. package/dist/headedSerialTaskQueue.d.ts +5 -5
  14. package/dist/headlessLatestRerunScheduler.d.ts +2 -3
  15. package/dist/headlessTransport.d.ts +2 -3
  16. package/dist/hostController.d.ts +11 -7
  17. package/dist/index.d.ts +1 -1
  18. package/dist/index.js +71 -14
  19. package/dist/protocol.d.ts +42 -46
  20. package/dist/providers/index.d.ts +11 -20
  21. package/dist/providers/playwright/dispatchBrowserRpc.d.ts +5 -3
  22. package/dist/providers/playwright/expectUtils.d.ts +2 -3
  23. package/dist/providers/playwright/implementation.d.ts +1 -1
  24. package/dist/providers/playwright/runtime.d.ts +1 -1
  25. package/dist/rpcProtocol.d.ts +9 -16
  26. package/dist/runSession.d.ts +3 -5
  27. package/dist/sessionRegistry.d.ts +2 -3
  28. package/dist/sourceMap/sourceMapLoader.d.ts +2 -2
  29. package/dist/viewportPresets.d.ts +2 -3
  30. package/dist/watchCliShortcuts.d.ts +1 -1
  31. package/dist/watchRerunPlanner.d.ts +2 -2
  32. package/package.json +8 -10
  33. package/src/browserRpcRegistry.ts +2 -2
  34. package/src/concurrency.ts +1 -1
  35. package/src/headedSerialTaskQueue.ts +5 -1
  36. package/src/hostController.ts +184 -27
  37. package/dist/browser-container/container-static/css/index.5c72297783.css +0 -1
  38. package/dist/browser-container/container-static/js/3.d3d6c6e4cf.js.LICENSE.txt +0 -1
  39. package/dist/client/entry.d.ts +0 -4
  40. package/dist/client/fakeTimersStub.d.ts +0 -25
  41. package/dist/client/public.d.ts +0 -9
  42. package/dist/client/snapshot.d.ts +0 -29
  43. package/dist/client/sourceMapSupport.d.ts +0 -42
@@ -0,0 +1 @@
1
+ /*! LICENSE: 854.c59f71483d.js.LICENSE.txt */
@@ -4,7 +4,7 @@
4
4
  1617 (e, t, s) {
5
5
  var l = s(9793);
6
6
  let r = "__rstest_dispatch_response__";
7
- var o = s(619), a = s(5203), i = s(1499), n = s(405), c = s(7541);
7
+ var o = s(4472), a = s(6961), i = s(6194), n = s(405), c = s(7541);
8
8
  let d = (e)=>{
9
9
  let { message: t } = e;
10
10
  return (0, l.jsx)("div", {
@@ -15,7 +15,7 @@
15
15
  })
16
16
  });
17
17
  };
18
- var u = s(4079), p = s(4198), h = s(3862), f = s(1529), x = s(1051);
18
+ var u = s(165), p = s(179), h = s(8753), f = s(184), x = s(5676);
19
19
  let m = (e, t)=>{
20
20
  if (!t) return e;
21
21
  let s = t.endsWith("/") ? t.slice(0, -1) : t;
@@ -32,7 +32,7 @@
32
32
  }
33
33
  }, "*"), fetch(`/__open-in-editor?file=${encodeURIComponent(e)}`).catch(()=>{});
34
34
  };
35
- var j = s(4759), v = s(9119), y = s(6505), _ = s(1165), C = s(4172);
35
+ var j = s(1910), v = s(8366), y = s(4560), _ = s(4484), C = s(7527);
36
36
  let w = {
37
37
  idle: {
38
38
  label: "Idle",
@@ -78,7 +78,7 @@
78
78
  })
79
79
  }
80
80
  };
81
- var k = s(5910), S = s(4625), F = s(1874), N = s(4776), A = s(2353), P = s(5502), M = s(5087), z = s(8231);
81
+ var k = s(4909), S = s(7602), F = s(3106), N = s(1725), A = s(9122), P = s(1687), M = s(7046), z = s(4668);
82
82
  let O = {
83
83
  iPhoneSE: {
84
84
  width: 375,
@@ -514,7 +514,7 @@
514
514
  ]
515
515
  });
516
516
  };
517
- var D = s(3938);
517
+ var D = s(3401);
518
518
  let G = (e)=>{
519
519
  let { className: t, style: s, direction: r = "horizontal", children: o, autoSaveId: a, ...i } = e, c = n.Children.toArray(o).filter((e)=>n.isValidElement(e) && e.type === Z), d = n.useCallback(()=>{
520
520
  if (!a) return null;
@@ -567,7 +567,7 @@
567
567
  children: t
568
568
  });
569
569
  };
570
- var L = s(8602), q = s(1572), H = s(3573);
570
+ var L = s(7795), q = s(7319), H = s(7752);
571
571
  let J = (e)=>(0, l.jsxs)("svg", {
572
572
  xmlns: "http://www.w3.org/2000/svg",
573
573
  fill: "none",
@@ -1585,7 +1585,7 @@
1585
1585
  ]
1586
1586
  });
1587
1587
  };
1588
- var X = s(7778), K = s(6946), Y = s(6765), Q = s(6822), ee = s(8946), et = s(9885);
1588
+ var X = s(2524), K = s(4333), Y = s(3534), Q = s(5749), ee = s(1695), et = s(1255);
1589
1589
  let es = (0, n.memo)((e)=>{
1590
1590
  let { counts: t, isRunning: s } = e, r = s && 0 === t.running;
1591
1591
  return (0, l.jsx)("div", {
@@ -1725,7 +1725,7 @@
1725
1725
  ]
1726
1726
  });
1727
1727
  };
1728
- var er = s(7944), eo = s(5119), ea = s(9886), ei = s(640), en = s(7094);
1728
+ var er = s(6530), eo = s(9790), ea = s(2741), ei = s(2669), en = s(6405);
1729
1729
  let ec = (e)=>`__project__${e}`, ed = (e, t)=>`${e}::suite::${t.join("::")}`, eu = (e, t)=>{
1730
1730
  let s = e;
1731
1731
  for(let e = 1; e <= t.length; e++)s = ed(s, t.slice(0, e));
@@ -3045,7 +3045,7 @@
3045
3045
  }, (o = self.rspackChunk_rstest_browser_ui = self.rspackChunk_rstest_browser_ui || []).forEach(r.bind(null, 0)), o.push = r.bind(null, o.push.bind(o));
3046
3046
  var c = n.O(void 0, [
3047
3047
  "783",
3048
- "3"
3048
+ "854"
3049
3049
  ], ()=>n(1617));
3050
3050
  c = n.O(c);
3051
3051
  })();
@@ -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.62b27a21db.js"></script><script defer src="/container-static/js/3.d3d6c6e4cf.js"></script><script defer src="/container-static/js/index.8fb1588e4a.js"></script><link href="/container-static/css/index.5c72297783.css" rel="stylesheet"></head>
15
+ <script defer src="/container-static/js/lib-react.62b27a21db.js"></script><script defer src="/container-static/js/854.c59f71483d.js"></script><script defer src="/container-static/js/index.fedc31dff3.js"></script><link href="/container-static/css/index.0521ff95b1.css" rel="stylesheet"></head>
16
16
  <body>
17
17
  <div id="root"></div>
18
18
  </body>
@@ -13,6 +13,5 @@
13
13
  * toHaveValues
14
14
  * - Artifacts intentionally excluded for now: screenshot/toMatchScreenshot/
15
15
  * trace/video
16
- */
17
- export declare const supportedLocatorActions: Set<string>;
16
+ */ export declare const supportedLocatorActions: Set<string>;
18
17
  export declare const supportedExpectElementMatchers: Set<string>;
@@ -1,3 +1,3 @@
1
1
  import { Locator, page, setTestIdAttribute } from './locator.js';
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.js';
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.js';
3
3
  export { Locator, page, setTestIdAttribute };
@@ -9,8 +9,7 @@ export declare const createRequestId: (prefix: string) => string;
9
9
  * {@link sendRunnerLifecycle}, so the request id only needs to be unique — it is
10
10
  * produced by the shared {@link createRequestId} factory rather than a bespoke
11
11
  * per-runner counter.
12
- */
13
- export declare const createRunnerLifecycleRequest: (method: string, args: unknown) => BrowserDispatchRequest;
12
+ */ export declare const createRunnerLifecycleRequest: (method: string, args: unknown) => BrowserDispatchRequest;
14
13
  /**
15
14
  * Deliver a runner-lifecycle request fire-and-forget.
16
15
  *
@@ -18,9 +17,8 @@ export declare const createRunnerLifecycleRequest: (method: string, args: unknow
18
17
  * out: the host echoes a response but the runner ignores it. Failures surface
19
18
  * only through the optional `onError` hook (debug logging at the call site),
20
19
  * keeping the hot test loop non-blocking.
21
- */
22
- export declare const sendRunnerLifecycle: (request: BrowserDispatchRequest, onError?: (error: unknown) => void) => void;
23
- export declare const dispatchRpc: <T>({ requestId, request, timeoutMs, timeoutMessage, staleMessage, }: {
20
+ */ export declare const sendRunnerLifecycle: (request: BrowserDispatchRequest, onError?: (error: unknown) => void) => void;
21
+ export declare const dispatchRpc: <T>({ requestId, request, timeoutMs, timeoutMessage, staleMessage }: {
24
22
  requestId: string;
25
23
  request: BrowserDispatchRequest;
26
24
  timeoutMs: number;
@@ -120,6 +120,5 @@ export declare const isLocator: (value: unknown) => value is Locator;
120
120
  * Forwards to the host provider (e.g. Playwright `selectors.setTestIdAttribute()`).
121
121
  *
122
122
  * @default 'data-testid'
123
- */
124
- export declare const setTestIdAttribute: (attribute: string) => Promise<void>;
125
- export {};
123
+ */ export declare const setTestIdAttribute: (attribute: string) => Promise<void>;
124
+ export { };
@@ -1,5 +1,7 @@
1
1
  import { getNumCpus, parseWorkers } from '@rstest/core/internal/browser';
2
2
  import type { Rstest } from '@rstest/core/internal/browser';
3
+ // Re-export the shared worker primitives so existing consumers (and unit tests
4
+ // importing from `../src/concurrency`) keep a stable import surface.
3
5
  export { getNumCpus, parseWorkers };
4
6
  type HeadlessConcurrencyContext = Pick<Rstest, 'command'> & {
5
7
  normalizedConfig: {
@@ -30,5 +30,5 @@ type CreateHostDispatchRouterOptions = {
30
30
  extensionHandlers?: Map<string, BrowserDispatchHandler>;
31
31
  onDuplicateNamespace?: (namespace: string) => void;
32
32
  };
33
- export declare const createHostDispatchRouter: ({ routerOptions, runnerCallbacks, runSnapshotRpc, extensionHandlers, onDuplicateNamespace, }: CreateHostDispatchRouterOptions) => HostDispatchRouter;
34
- export {};
33
+ export declare const createHostDispatchRouter: ({ routerOptions, runnerCallbacks, runSnapshotRpc, extensionHandlers, onDuplicateNamespace }: CreateHostDispatchRouterOptions) => HostDispatchRouter;
34
+ export { };
@@ -7,8 +7,7 @@ type HostDispatchRouterOptions = {
7
7
  /**
8
8
  * Host-side routing layer for dispatch envelopes.
9
9
  * Capabilities are registered by namespace, while routing stays transport-agnostic.
10
- */
11
- export declare class HostDispatchRouter {
10
+ */ export declare class HostDispatchRouter {
12
11
  private handlers;
13
12
  private options;
14
13
  constructor(options?: HostDispatchRouterOptions);
@@ -17,4 +16,4 @@ export declare class HostDispatchRouter {
17
16
  has(namespace: string): boolean;
18
17
  dispatch(request: BrowserDispatchRequest): Promise<BrowserDispatchResponse>;
19
18
  }
20
- export {};
19
+ export { };
@@ -1,9 +1,9 @@
1
1
  type HeadedSerialTask = () => Promise<void>;
2
+ type HeadedSerialTaskQueue = {
3
+ enqueue: (task: HeadedSerialTask) => Promise<void>;
4
+ };
2
5
  /**
3
6
  * Serializes headed browser file execution so only one task runs at a time.
4
7
  * The queue keeps draining even if an earlier task rejects.
5
- */
6
- export declare const createHeadedSerialTaskQueue: () => {
7
- enqueue: (task: HeadedSerialTask) => Promise<void>;
8
- };
9
- export {};
8
+ */ export declare const createHeadedSerialTaskQueue: () => HeadedSerialTaskQueue;
9
+ export { };
@@ -14,6 +14,5 @@ type HeadlessLatestRerunSchedulerOptions<TFile, TRun> = {
14
14
  /**
15
15
  * Latest-only rerun scheduler for headless watch mode.
16
16
  * Keeps only the newest pending payload and interrupts active run generations.
17
- */
18
- export declare const createHeadlessLatestRerunScheduler: <TFile, TRun>(options: HeadlessLatestRerunSchedulerOptions<TFile, TRun>) => HeadlessLatestRerunScheduler<TFile>;
19
- export {};
17
+ */ export declare const createHeadlessLatestRerunScheduler: <TFile, TRun>(options: HeadlessLatestRerunSchedulerOptions<TFile, TRun>) => HeadlessLatestRerunScheduler<TFile>;
18
+ export { };
@@ -7,6 +7,5 @@ type HeadlessRunnerTransportHandlers = {
7
7
  /**
8
8
  * Headless transport adapter.
9
9
  * This only binds page bridge functions and delegates all scheduling decisions upstream.
10
- */
11
- export declare const attachHeadlessRunnerTransport: (page: BrowserProviderPage, handlers: HeadlessRunnerTransportHandlers) => Promise<void>;
12
- export {};
10
+ */ export declare const attachHeadlessRunnerTransport: (page: BrowserProviderPage, handlers: HeadlessRunnerTransportHandlers) => Promise<void>;
11
+ export { };
@@ -14,8 +14,7 @@ type BrowserLazyCompilationConfig = {
14
14
  * `server.port: 0` because its internal `getPort` never reads back the
15
15
  * OS-assigned ephemeral port. This helper falls back to
16
16
  * `httpServer.address()` to obtain the real bound port.
17
- */
18
- export declare const resolveListenPort: (listenPort: number, httpServer: {
17
+ */ export declare const resolveListenPort: (listenPort: number, httpServer: {
19
18
  address: () => ReturnType<import('node:net').Server['address']>;
20
19
  } | null) => number;
21
20
  export declare const createBrowserLazyCompilationConfig: (setupFiles: string[]) => BrowserLazyCompilationConfig;
@@ -26,13 +25,19 @@ export declare const createBrowserRsbuildDevConfig: (_isWatchMode: boolean) => {
26
25
  logLevel: 'error';
27
26
  };
28
27
  };
28
+ export declare const createBrowserContextExcludeRegExp: (patterns: string[], projectRoot: string) => RegExp | null;
29
+ // ============================================================================
30
+ // Main Entry Point
31
+ // ============================================================================
29
32
  export declare const runBrowserController: (context: RstestContext, options?: BrowserTestRunOptions) => Promise<BrowserTestRunResult | void>;
33
+ // ============================================================================
34
+ // List Browser Tests
35
+ // ============================================================================
30
36
  /**
31
37
  * Result from collecting browser tests.
32
38
  * This is the return type for listBrowserTests, designed for future extraction
33
39
  * to a separate browser package.
34
- */
35
- export type ListBrowserTestsResult = {
40
+ */ export type ListBrowserTestsResult = {
36
41
  list: ListCommandResult[];
37
42
  close: () => Promise<void>;
38
43
  };
@@ -40,10 +45,9 @@ export type ListBrowserTestsResult = {
40
45
  * Collect test metadata from browser mode projects without running them.
41
46
  * This function creates a headless browser runtime, loads test files,
42
47
  * and collects their test structure (describe/test declarations).
43
- */
44
- export declare const listBrowserTests: (context: RstestContext, options?: {
48
+ */ export declare const listBrowserTests: (context: RstestContext, options?: {
45
49
  shardedEntries?: Map<string, {
46
50
  entries: Record<string, string>;
47
51
  }>;
48
52
  }) => Promise<ListBrowserTestsResult>;
49
- export {};
53
+ export { };
package/dist/index.d.ts CHANGED
@@ -4,4 +4,4 @@ import { type ListBrowserTestsResult } from './hostController.js';
4
4
  export { validateBrowserConfig };
5
5
  export declare function runBrowserTests(context: RstestContext, options?: BrowserTestRunOptions): Promise<BrowserTestRunResult | void>;
6
6
  export declare function listBrowserTests(context: RstestContext, options?: Pick<BrowserTestRunOptions, 'shardedEntries'>): Promise<ListBrowserTestsResult>;
7
- export type { BrowserTestRunOptions, BrowserTestRunResult, ListBrowserTestsResult, };
7
+ export type { BrowserTestRunOptions, BrowserTestRunResult, ListBrowserTestsResult };
package/dist/index.js CHANGED
@@ -3002,7 +3002,8 @@ const globToRegexp = (glob)=>{
3002
3002
  const regex = picomatch_default().makeRe(glob, {
3003
3003
  fastpaths: false,
3004
3004
  noglobstar: false,
3005
- bash: false
3005
+ bash: false,
3006
+ dot: true
3006
3007
  });
3007
3008
  if (!regex) throw new Error(`Invalid glob pattern: ${glob}`);
3008
3009
  if (!glob.startsWith('./')) return regex;
@@ -3022,20 +3023,76 @@ const globPatternsToRegExp = (patterns)=>{
3022
3023
  });
3023
3024
  return new RegExp(`(?:${regexParts.join('|')})$`);
3024
3025
  };
3025
- const excludePatternsToRegExp = (patterns)=>{
3026
- const keywords = [];
3027
- for (const pattern of patterns){
3028
- const match = pattern.match(/\*\*\/\.?\{?([^/*{}]+(?:,[^/*{}]+)*)\}?\/?\*?\*?/);
3029
- if (match) {
3030
- const parts = match[1].split(',');
3031
- for (const part of parts){
3032
- const cleaned = part.replace(/^\./, '');
3033
- if (cleaned && !keywords.includes(cleaned)) keywords.push(cleaned);
3034
- }
3026
+ const REGEXP_SPECIAL_CHARACTERS = /[|\\{}()[\]^$+*?.]/g;
3027
+ const PATH_SEPARATOR_SOURCE = String.raw`[\\/]`;
3028
+ const WINDOWS_ABSOLUTE_PATH_SOURCE = String.raw`[A-Za-z]:[\\/]`;
3029
+ const escapeRegExp = (value)=>value.replace(REGEXP_SPECIAL_CHARACTERS, '\\$&');
3030
+ const normalizePathForRegExp = (value)=>normalize(value).replaceAll('\\', '/');
3031
+ const normalizeExcludePatternForRegExp = (value)=>value.startsWith('./') ? `./${normalizePathForRegExp(value.substring(2))}` : normalizePathForRegExp(value);
3032
+ const isAbsolutePatternForRegExp = (value)=>value.startsWith('/') || /^[A-Za-z]:\//.test(value);
3033
+ const isEscapedRegExpCharacter = (source, index)=>{
3034
+ let backslashCount = 0;
3035
+ for(let current = index - 1; current >= 0 && '\\' === source[current]; current--)backslashCount++;
3036
+ return backslashCount % 2 === 1;
3037
+ };
3038
+ const replacePathSeparatorsInRegExpSource = (source)=>{
3039
+ let result = '';
3040
+ let inCharacterClass = false;
3041
+ for(let index = 0; index < source.length; index++){
3042
+ const character = source[index];
3043
+ const isEscaped = isEscapedRegExpCharacter(source, index);
3044
+ if ('[' === character && !isEscaped) inCharacterClass = true;
3045
+ if (!inCharacterClass && '\\' === character && '/' === source[index + 1]) {
3046
+ result += PATH_SEPARATOR_SOURCE;
3047
+ index++;
3048
+ continue;
3035
3049
  }
3050
+ result += character;
3051
+ if (']' === character && !isEscaped) inCharacterClass = false;
3052
+ }
3053
+ return result;
3054
+ };
3055
+ const createRelativeContextExcludeSource = (source, normalizedPattern)=>{
3056
+ if (normalizedPattern.startsWith('./')) return source;
3057
+ return normalizedPattern.startsWith('**/') ? `(?:(?:${source})|\\.(?:${source}))` : `(?:(?:${source})|\\.${PATH_SEPARATOR_SOURCE}(?:${source}))`;
3058
+ };
3059
+ const createProjectAbsoluteExcludeSource = (source, normalizedPattern)=>normalizedPattern.startsWith('./') || normalizedPattern.startsWith('**/') ? source : `${PATH_SEPARATOR_SOURCE}(?:${source})`;
3060
+ const excludePatternsToRegExpSources = (patterns)=>{
3061
+ const sources = patterns.map((pattern)=>{
3062
+ const normalizedPattern = normalizeExcludePatternForRegExp(pattern);
3063
+ const regex = globToRegexp(normalizedPattern);
3064
+ let source = regex.source;
3065
+ if (source.startsWith('^')) source = source.substring(1);
3066
+ if (source.endsWith('$')) source = source.substring(0, source.length - 1);
3067
+ source = replacePathSeparatorsInRegExpSource(source);
3068
+ const isAbsolute = isAbsolutePatternForRegExp(normalizedPattern);
3069
+ const absolute = normalizedPattern.startsWith('./') ? source.substring(2) : source;
3070
+ return {
3071
+ relative: isAbsolute ? source : createRelativeContextExcludeSource(source, normalizedPattern),
3072
+ absolute: isAbsolute ? absolute : createProjectAbsoluteExcludeSource(absolute, normalizedPattern),
3073
+ isAbsolute
3074
+ };
3075
+ });
3076
+ if (0 === sources.length) return null;
3077
+ return sources;
3078
+ };
3079
+ const createBrowserContextExcludeRegExp = (patterns, projectRoot)=>{
3080
+ const excludeSources = excludePatternsToRegExpSources(patterns);
3081
+ if (!excludeSources) return null;
3082
+ const normalizedProjectRoot = normalizePathForRegExp(projectRoot).replace(/[\\/]$/, '');
3083
+ const projectRootSource = normalizedProjectRoot.split('/').map(escapeRegExp).join(PATH_SEPARATOR_SOURCE);
3084
+ const relativeExcludeSources = excludeSources.filter((source)=>!source.isAbsolute);
3085
+ const absoluteExcludeSources = excludeSources.filter((source)=>source.isAbsolute);
3086
+ const sourceBranches = [];
3087
+ if (relativeExcludeSources.length > 0) {
3088
+ const relativePatternSource = `(?:${relativeExcludeSources.map((source)=>source.relative).join('|')})`;
3089
+ const absolutePatternSource = `(?:${relativeExcludeSources.map((source)=>source.absolute).join('|')})`;
3090
+ const relativeSource = `(?:${relativePatternSource})`;
3091
+ const absoluteSource = normalizedProjectRoot ? `${projectRootSource}(?=${PATH_SEPARATOR_SOURCE})(?:${absolutePatternSource})` : `(?:${absolutePatternSource})`;
3092
+ sourceBranches.push(`(?!${WINDOWS_ABSOLUTE_PATH_SOURCE}|${PATH_SEPARATOR_SOURCE})${relativeSource}`, absoluteSource);
3036
3093
  }
3037
- if (0 === keywords.length) return null;
3038
- return new RegExp(`[\\\\/](${keywords.join('|')})[\\\\/]`);
3094
+ if (absoluteExcludeSources.length > 0) sourceBranches.push(`(?:${absoluteExcludeSources.map((source)=>source.relative).join('|')})`);
3095
+ return new RegExp(`^(?:${sourceBranches.join('|')})$`);
3039
3096
  };
3040
3097
  const findTestFileInModules = (modules, entryTestFiles)=>{
3041
3098
  if (!modules) return null;
@@ -3211,7 +3268,7 @@ const generateManifestModule = ({ manifestPath, entries })=>{
3211
3268
  const projectRootPosix = normalize(project.rootPath);
3212
3269
  const includeRegExp = globPatternsToRegExp(project.normalizedConfig.include);
3213
3270
  const excludePatterns = project.normalizedConfig.exclude.patterns;
3214
- const excludeRegExp = excludePatternsToRegExp(excludePatterns);
3271
+ const excludeRegExp = createBrowserContextExcludeRegExp(excludePatterns, projectRootPosix);
3215
3272
  lines.push(`const ${varName} = import.meta.webpackContext(${JSON.stringify(projectRootPosix)}, {`);
3216
3273
  lines.push(' recursive: true,');
3217
3274
  lines.push(` regExp: ${includeRegExp.toString()},`);
@@ -1,18 +1,21 @@
1
1
  import type { BrowserViewport } from '@rstest/core/internal/browser';
2
2
  import type { RuntimeConfig, TestFileResult, TestInfo, TestResult } from '@rstest/core/internal/browser-runtime';
3
3
  import type { SnapshotUpdateState } from '@vitest/snapshot';
4
- export type { BrowserLocatorIR, BrowserRpcRequest, SnapshotRpcCall, SnapshotRpcMethod, SnapshotRpcMethodArgs, SnapshotRpcRequest, } from './rpcProtocol.js';
4
+ export type { BrowserLocatorIR, BrowserRpcRequest, SnapshotRpcCall, SnapshotRpcMethod, SnapshotRpcMethodArgs, SnapshotRpcRequest } from './rpcProtocol.js';
5
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 DISPATCH_NAMESPACE_RUNNER = "runner";
12
- export declare const DISPATCH_NAMESPACE_BROWSER = "browser";
13
- export declare const DISPATCH_NAMESPACE_SNAPSHOT = "snapshot";
14
- export declare const DISPATCH_METHOD_RPC = "rpc";
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 DISPATCH_NAMESPACE_RUNNER = 'runner';
12
+ export declare const DISPATCH_NAMESPACE_BROWSER = 'browser';
13
+ export declare const DISPATCH_NAMESPACE_SNAPSHOT = 'snapshot';
14
+ export declare const DISPATCH_METHOD_RPC = 'rpc';
15
15
  export type SerializedRuntimeConfig = RuntimeConfig;
16
+ // `BrowserViewport` is a core config type (`@rstest/core` owns the canonical
17
+ // definition used by `NormalizedBrowserModeConfig`). Re-export it so the host
18
+ // assigns the SAME type across the seam instead of a hand-copied duplicate.
16
19
  export type { BrowserViewport };
17
20
  export type BrowserProjectRuntime = {
18
21
  name: string;
@@ -24,8 +27,7 @@ export type BrowserProjectRuntime = {
24
27
  /**
25
28
  * Test file info with associated project name.
26
29
  * Used to track which project a test file belongs to.
27
- */
28
- export type TestFileInfo = {
30
+ */ export type TestFileInfo = {
29
31
  testPath: string;
30
32
  projectName: string;
31
33
  };
@@ -33,16 +35,14 @@ export type TestFileInfo = {
33
35
  * Execution mode for browser tests.
34
36
  * - 'run': Execute tests and report results (default)
35
37
  * - 'collect': Only collect test metadata without running
36
- */
37
- export type BrowserExecutionMode = 'run' | 'collect';
38
+ */ export type BrowserExecutionMode = 'run' | 'collect';
38
39
  /**
39
40
  * Wire shape of a `log` client message payload. The host receives this and maps
40
41
  * it onto core's {@link UserConsoleLog} (notably `level` → `name`); that mapper
41
42
  * (`hostController.ts` `handleLog`) annotates its result as `UserConsoleLog`, so
42
43
  * the map→core direction is compiler-checked. Owning the wire shape here as one
43
44
  * named type keeps the host's input type from drifting away from the producer.
44
- */
45
- export type BrowserLogPayload = {
45
+ */ export type BrowserLogPayload = {
46
46
  level: 'log' | 'warn' | 'error' | 'info' | 'debug';
47
47
  content: string;
48
48
  taskId?: string;
@@ -61,31 +61,25 @@ export type BrowserHostConfig = {
61
61
  };
62
62
  testFile?: string;
63
63
  /**
64
- * Per-run identifier assigned by the container.
65
- * Used by browser RPC calls to prevent stale requests from previous reruns.
66
- */
67
- runId?: string;
64
+ * Per-run identifier assigned by the container.
65
+ * Used by browser RPC calls to prevent stale requests from previous reruns.
66
+ */ runId?: string;
68
67
  /**
69
- * Base URL for runner (iframe) pages.
70
- */
71
- runnerUrl?: string;
68
+ * Base URL for runner (iframe) pages.
69
+ */ runnerUrl?: string;
72
70
  /**
73
- * WebSocket port for container RPC.
74
- */
75
- wsPort?: number;
71
+ * WebSocket port for container RPC.
72
+ */ wsPort?: number;
76
73
  /**
77
- * Execution mode. Defaults to 'run'.
78
- */
79
- mode?: BrowserExecutionMode;
74
+ * Execution mode. Defaults to 'run'.
75
+ */ mode?: BrowserExecutionMode;
80
76
  /**
81
- * Debug mode. When true, enables verbose logging in browser.
82
- */
83
- debug?: boolean;
77
+ * Debug mode. When true, enables verbose logging in browser.
78
+ */ debug?: boolean;
84
79
  /**
85
- * Timeout for RPC operations in milliseconds (e.g., snapshot file operations).
86
- * Derived from testTimeout config.
87
- */
88
- rpcTimeout?: number;
80
+ * Timeout for RPC operations in milliseconds (e.g., snapshot file operations).
81
+ * Derived from testTimeout config.
82
+ */ rpcTimeout?: number;
89
83
  };
90
84
  export type BrowserClientMessage = {
91
85
  type: 'ready';
@@ -131,33 +125,36 @@ export type BrowserClientMessage = {
131
125
  * {@link BrowserClientMessage} types it `send()`s). The runner client imports
132
126
  * this instead of redeclaring the list, so the emit site cannot drift from the
133
127
  * host router.
134
- */
135
- export type RunnerLifecycleMethod = 'file-ready' | 'suite-start' | 'suite-result' | 'case-start';
128
+ */ export type RunnerLifecycleMethod = 'file-ready' | 'suite-start' | 'suite-result' | 'case-start';
136
129
  /**
137
130
  * {@link BrowserClientMessage} types that are forwarded to the `runner`
138
131
  * namespace (by message `type`) rather than handled at the transport layer.
139
132
  * `Extract` keeps this a checked subset of the message union — renaming a
140
133
  * message type drops it here, surfacing as a missing handler downstream.
141
- */
142
- type RunnerMessageMethod = Extract<BrowserClientMessage['type'], 'file-start' | 'case-result' | 'file-complete' | 'log' | 'fatal'>;
134
+ */ type RunnerMessageMethod = Extract<BrowserClientMessage['type'], 'file-start' | 'case-result' | 'file-complete' | 'log' | 'fatal'>;
143
135
  /**
144
136
  * Single source of truth for every method handled by the `runner` dispatch
145
137
  * namespace. The host handler table is keyed by this union (a missing key is a
146
138
  * compile error), so adding a runner method here forces a matching handler and
147
139
  * cannot silently no-op at runtime.
148
- */
149
- export type RunnerDispatchMethod = RunnerLifecycleMethod | RunnerMessageMethod;
140
+ */ export type RunnerDispatchMethod = RunnerLifecycleMethod | RunnerMessageMethod;
150
141
  /**
151
142
  * Transport-agnostic envelope used by host routing.
152
143
  * `namespace + method + args + target` describes an operation independent of
153
144
  * the underlying message channel, and `runToken` provides run-level isolation.
154
- */
155
- export type BrowserDispatchRequest = {
145
+ */ export type BrowserDispatchRequest = {
156
146
  requestId: string;
147
+ // Optional so headed/container paths can adopt the same envelope even when
148
+ // run-token isolation is only enforced in headless scheduling today.
157
149
  runToken?: number;
158
150
  namespace: string;
159
151
  method: string;
160
152
  args?: unknown;
153
+ // Routing reads `namespace`, `method`, `runToken`, and `target.sessionId`
154
+ // (see dispatchRouter.ts / dispatchBrowserRpcRequest). `target.testFile` and
155
+ // `target.projectName` are carried for diagnostics / forward-compatibility and
156
+ // are NOT consulted for routing today — adding a routing-relevant field here
157
+ // means wiring a reader on the host side, which structural typing won't force.
161
158
  target?: {
162
159
  testFile?: string;
163
160
  sessionId?: string;
@@ -167,8 +164,7 @@ export type BrowserDispatchRequest = {
167
164
  /**
168
165
  * Dispatch response envelope.
169
166
  * `stale: true` signals a safe drop from an older run generation, not a failure.
170
- */
171
- export type BrowserDispatchResponse = {
167
+ */ export type BrowserDispatchResponse = {
172
168
  requestId: string;
173
169
  runToken?: number;
174
170
  result?: unknown;
@@ -19,10 +19,8 @@ import type { BrowserRpcRequest } from '../rpcProtocol.js';
19
19
  * (peer-dependency direction). `providerImplementations` below is keyed by the
20
20
  * re-exported union, so a provider added in core without an implementation here
21
21
  * is a compile error.
22
- */
23
- export type { BrowserProvider };
24
- /** Minimal console shape needed by host logging bridge. */
25
- export type BrowserConsoleMessage = {
22
+ */ export type { BrowserProvider };
23
+ /** Minimal console shape needed by host logging bridge. */ export type BrowserConsoleMessage = {
26
24
  text: () => string;
27
25
  };
28
26
  /**
@@ -34,29 +32,26 @@ export type BrowserConsoleMessage = {
34
32
  * (e.g. WebDriver BiDi), consider pushing page-level orchestration (goto,
35
33
  * exposeFunction, addInitScript, event listeners) into provider-specific
36
34
  * implementations so hostController only calls high-level semantic methods.
37
- */
38
- export type BrowserProviderPage = {
35
+ */ export type BrowserProviderPage = {
39
36
  goto: (url: string, options?: {
40
37
  waitUntil?: 'load';
41
38
  }) => Promise<unknown>;
42
39
  exposeFunction: (name: string, fn: (...args: any[]) => any) => Promise<void>;
43
40
  addInitScript: (script: string) => Promise<void>;
44
41
  on: {
45
- (event: 'popup', listener: (page: BrowserProviderPage) => void): void;
46
- (event: 'console', listener: (message: BrowserConsoleMessage) => void): void;
42
+ (event: 'popup', listener: (page: BrowserProviderPage) => void) : void;
43
+ (event: 'console', listener: (message: BrowserConsoleMessage) => void) : void;
47
44
  };
48
45
  close: () => Promise<void>;
49
46
  [Symbol.asyncDispose]: () => Promise<void>;
50
47
  };
51
- /** Minimal browser context API surface required by hostController. */
52
- export type BrowserProviderContext = {
48
+ /** Minimal browser context API surface required by hostController. */ export type BrowserProviderContext = {
53
49
  newPage: () => Promise<BrowserProviderPage>;
54
50
  on: (event: 'page', listener: (page: BrowserProviderPage) => void) => void;
55
51
  close: () => Promise<void>;
56
52
  [Symbol.asyncDispose]: () => Promise<void>;
57
53
  };
58
- /** Minimal browser API surface required by hostController. */
59
- export type BrowserProviderBrowser = {
54
+ /** Minimal browser API surface required by hostController. */ export type BrowserProviderBrowser = {
60
55
  close: () => Promise<void>;
61
56
  [Symbol.asyncDispose]: () => Promise<void>;
62
57
  newContext: (options: {
@@ -67,18 +62,15 @@ export type BrowserProviderBrowser = {
67
62
  providerOptions?: Record<string, unknown>;
68
63
  }) => Promise<BrowserProviderContext>;
69
64
  };
70
- /** Provider launch result consumed by hostController. */
71
- export type BrowserProviderRuntime = {
65
+ /** Provider launch result consumed by hostController. */ export type BrowserProviderRuntime = {
72
66
  browser: BrowserProviderBrowser;
73
67
  };
74
- /** Input contract for browser launch. */
75
- export type LaunchBrowserInput = {
68
+ /** Input contract for browser launch. */ export type LaunchBrowserInput = {
76
69
  browserName: 'chromium' | 'firefox' | 'webkit';
77
70
  headless: boolean | undefined;
78
71
  providerOptions: Record<string, unknown>;
79
72
  };
80
- /** Input contract for provider-side browser RPC dispatch. */
81
- export type DispatchBrowserRpcInput = {
73
+ /** Input contract for provider-side browser RPC dispatch. */ export type DispatchBrowserRpcInput = {
82
74
  containerPage?: BrowserProviderPage;
83
75
  runnerPage?: BrowserProviderPage;
84
76
  request: BrowserRpcRequest;
@@ -90,8 +82,7 @@ export type DispatchBrowserRpcInput = {
90
82
  * Any new built-in provider must:
91
83
  * - launch browser runtime for test execution
92
84
  * - execute browser RPC requests (locator actions + assertions)
93
- */
94
- export type BrowserProviderImplementation = {
85
+ */ export type BrowserProviderImplementation = {
95
86
  name: BrowserProvider;
96
87
  launchRuntime: (input: LaunchBrowserInput) => Promise<BrowserProviderRuntime>;
97
88
  dispatchRpc: (input: DispatchBrowserRpcInput) => Promise<unknown>;
@@ -2,10 +2,12 @@
2
2
  * Contains adapted logic from Playwright matchers:
3
3
  * https://github.com/microsoft/playwright/blob/main/packages/playwright/src/matchers/matchers.ts
4
4
  * Copyright (c) Microsoft Corporation, Apache-2.0.
5
- */
6
- import type { Page } from 'playwright';
5
+ */ import type { Page } from 'playwright';
7
6
  import type { BrowserRpcRequest } from '../../rpcProtocol.js';
8
- export declare function dispatchPlaywrightBrowserRpc({ containerPage, runnerPage, request, timeoutFallbackMs, }: {
7
+ // ---------------------------------------------------------------------------
8
+ // Public entry
9
+ // ---------------------------------------------------------------------------
10
+ export declare function dispatchPlaywrightBrowserRpc({ containerPage, runnerPage, request, timeoutFallbackMs }: {
9
11
  containerPage?: Page;
10
12
  runnerPage?: Page;
11
13
  request: BrowserRpcRequest;