@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
@@ -2,8 +2,7 @@
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 { BrowserLocatorText } from '../../rpcProtocol.js';
5
+ */ import type { BrowserLocatorText } from '../../rpcProtocol.js';
7
6
  type ExpectedTextValue = {
8
7
  string?: string;
9
8
  regexSource?: string;
@@ -21,4 +20,4 @@ export declare const formatExpectError: (result: {
21
20
  errorMessage?: string;
22
21
  log?: string[];
23
22
  }) => string;
24
- export {};
23
+ export { };
@@ -1,2 +1,2 @@
1
- import type { BrowserProviderImplementation } from '../index.js';
1
+ import type { BrowserProviderImplementation, BrowserProviderRuntime } from '../index.js';
2
2
  export declare const playwrightProviderImplementation: BrowserProviderImplementation;
@@ -1,5 +1,5 @@
1
1
  import type { BrowserProviderRuntime } from '../index.js';
2
- export declare function launchPlaywrightBrowser({ browserName, headless, providerOptions, }: {
2
+ export declare function launchPlaywrightBrowser({ browserName, headless, providerOptions }: {
3
3
  browserName: 'chromium' | 'firefox' | 'webkit';
4
4
  headless: boolean | undefined;
5
5
  providerOptions: Record<string, unknown>;
@@ -83,21 +83,17 @@ export type BrowserLocatorIR = {
83
83
  };
84
84
  export type BrowserRpcRequest = {
85
85
  id: string;
86
- /** Absolute test file path for locating runner iframe */
87
- testPath: string;
88
- /** Run identifier generated by container for stale-request protection. */
89
- runId: string;
86
+ /** Absolute test file path for locating runner iframe */ testPath: string;
87
+ /** Run identifier generated by container for stale-request protection. */ runId: string;
90
88
  kind: 'locator' | 'expect' | 'config';
91
89
  locator: BrowserLocatorIR;
92
90
  method: string;
93
91
  args: unknown[];
94
92
  /**
95
- * Negation for expect matchers (equivalent to Playwright expect(...).not).
96
- * Only meaningful for kind === 'expect'.
97
- */
98
- isNot?: boolean;
99
- /** Optional timeout override (ms). Falls back to browser rpcTimeout. */
100
- timeout?: number;
93
+ * Negation for expect matchers (equivalent to Playwright expect(...).not).
94
+ * Only meaningful for kind === 'expect'.
95
+ */ isNot?: boolean;
96
+ /** Optional timeout override (ms). Falls back to browser rpcTimeout. */ timeout?: number;
101
97
  };
102
98
  export declare const validateBrowserRpcRequest: (payload: unknown) => BrowserRpcRequest;
103
99
  /**
@@ -105,8 +101,7 @@ export declare const validateBrowserRpcRequest: (payload: unknown) => BrowserRpc
105
101
  * The request union, the client sender, both host-side mappers, and every
106
102
  * exhaustiveness check derive from this map — adding or renaming a method here
107
103
  * forces a compile error at every site that has not been updated.
108
- */
109
- export type SnapshotRpcMethodArgs = {
104
+ */ export type SnapshotRpcMethodArgs = {
110
105
  resolveSnapshotPath: {
111
106
  testPath: string;
112
107
  };
@@ -125,8 +120,7 @@ export type SnapshotRpcMethod = keyof SnapshotRpcMethodArgs;
125
120
  /**
126
121
  * Snapshot RPC request from runner iframe.
127
122
  * The container will forward these to the host via WebSocket RPC.
128
- */
129
- export type SnapshotRpcRequest = {
123
+ */ export type SnapshotRpcRequest = {
130
124
  [M in SnapshotRpcMethod]: {
131
125
  id: string;
132
126
  method: M;
@@ -137,8 +131,7 @@ export type SnapshotRpcRequest = {
137
131
  * Client-side snapshot RPC call (request without the transport `id`).
138
132
  * Distributive over {@link SnapshotRpcMethod} so `method` and `args` stay paired
139
133
  * at the call site — a mismatched pair fails to compile.
140
- */
141
- export type SnapshotRpcCall = {
134
+ */ export type SnapshotRpcCall = {
142
135
  [M in SnapshotRpcMethod]: {
143
136
  method: M;
144
137
  args: SnapshotRpcMethodArgs[M];
@@ -1,7 +1,6 @@
1
1
  /**
2
2
  * Run generation/session lifecycle contract shared by browser scheduling paths.
3
- */
4
- export type RunSession = {
3
+ */ export type RunSession = {
5
4
  token: number;
6
5
  cancelled: boolean;
7
6
  cancelSignal: Promise<void>;
@@ -16,8 +15,7 @@ type CancelOptions<T extends RunSession> = {
16
15
  /**
17
16
  * Canonical run-token lifecycle manager.
18
17
  * Centralizes token increment, invalidation, and cancellation semantics.
19
- */
20
- export declare class RunSessionLifecycle<T extends RunSession> {
18
+ */ export declare class RunSessionLifecycle<T extends RunSession> {
21
19
  private currentToken;
22
20
  private active;
23
21
  get activeSession(): T | null;
@@ -30,4 +28,4 @@ export declare class RunSessionLifecycle<T extends RunSession> {
30
28
  cancel(session: T, options?: CancelOptions<T>): Promise<void>;
31
29
  cancelActive(options?: CancelOptions<T>): Promise<void>;
32
30
  }
33
- export {};
31
+ export { };
@@ -17,8 +17,7 @@ type RunnerSessionInput = Omit<RunnerSessionRecord, 'id' | 'createdAt'> & {
17
17
  /**
18
18
  * Execution target index for host scheduling.
19
19
  * Provides lookup by session id, test file, and run token without coupling to UI topology.
20
- */
21
- export declare class RunnerSessionRegistry {
20
+ */ export declare class RunnerSessionRegistry {
22
21
  private nextId;
23
22
  private sessionsById;
24
23
  private sessionIdByTestFile;
@@ -31,4 +30,4 @@ export declare class RunnerSessionRegistry {
31
30
  deleteByTestFile(testFile: string): boolean;
32
31
  clear(): void;
33
32
  }
34
- export {};
33
+ export { };
@@ -4,11 +4,11 @@ type Fetcher = typeof fetch;
4
4
  export declare const normalizeJavaScriptUrl: (value: string, options?: {
5
5
  origin?: string;
6
6
  }) => string | null;
7
- export declare const loadSourceMapWithCache: ({ jsUrl, cache, force, origin, fetcher, }: {
7
+ export declare const loadSourceMapWithCache: ({ jsUrl, cache, force, origin, fetcher }: {
8
8
  jsUrl: string;
9
9
  cache: Map<string, SourceMapPayload | null>;
10
10
  force?: boolean;
11
11
  origin?: string;
12
12
  fetcher?: Fetcher;
13
13
  }) => Promise<SourceMapPayload | null>;
14
- export {};
14
+ export { };
@@ -9,8 +9,7 @@
9
9
  * device list — mirror each device's `screen.vertical` `{ width, height }`:
10
10
  * https://github.com/ChromeDevTools/devtools-frontend/blob/main/front_end/models/emulation/EmulatedDevices.ts
11
11
  * Last verified in sync (all 17): 2026-04-22, devtools-frontend commit abaac05e.
12
- */
13
- export declare const BROWSER_VIEWPORT_PRESET_IDS: readonly ['iPhoneSE', 'iPhoneXR', 'iPhone12Pro', 'iPhone14ProMax', 'Pixel7', 'SamsungGalaxyS8Plus', 'SamsungGalaxyS20Ultra', 'iPadMini', 'iPadAir', 'iPadPro', 'SurfacePro7', 'SurfaceDuo', 'GalaxyZFold5', 'AsusZenbookFold', 'SamsungGalaxyA51A71', 'NestHub', 'NestHubMax'];
12
+ */ export declare const BROWSER_VIEWPORT_PRESET_IDS: readonly ['iPhoneSE', 'iPhoneXR', 'iPhone12Pro', 'iPhone14ProMax', 'Pixel7', 'SamsungGalaxyS8Plus', 'SamsungGalaxyS20Ultra', 'iPadMini', 'iPadAir', 'iPadPro', 'SurfacePro7', 'SurfaceDuo', 'GalaxyZFold5', 'AsusZenbookFold', 'SamsungGalaxyA51A71', 'NestHub', 'NestHubMax'];
14
13
  type BrowserViewportPresetId = (typeof BROWSER_VIEWPORT_PRESET_IDS)[number];
15
14
  type BrowserViewportSize = {
16
15
  width: number;
@@ -18,4 +17,4 @@ type BrowserViewportSize = {
18
17
  };
19
18
  export declare const BROWSER_VIEWPORT_PRESET_DIMENSIONS: Record<BrowserViewportPresetId, BrowserViewportSize>;
20
19
  export declare const resolveBrowserViewportPreset: (presetId: string) => BrowserViewportSize | null;
21
- export {};
20
+ export { };
@@ -1,6 +1,6 @@
1
1
  export declare const isBrowserWatchCliShortcutsEnabled: () => boolean;
2
2
  export declare const getBrowserWatchCliShortcutsHintMessage: () => string;
3
3
  export declare const logBrowserWatchReadyMessage: (enableCliShortcuts: boolean) => void;
4
- export declare function setupBrowserWatchCliShortcuts({ close, }: {
4
+ export declare function setupBrowserWatchCliShortcuts({ close }: {
5
5
  close: () => Promise<void>;
6
6
  }): Promise<() => void>;
@@ -17,5 +17,5 @@ type WatchRerunPlan = {
17
17
  affectedTestFiles: TestFileInfo[];
18
18
  };
19
19
  export declare const collectWatchTestFiles: (projectEntries: WatchPlannerProjectEntry[]) => TestFileInfo[];
20
- export declare const planWatchRerun: ({ projectEntries, previousTestFiles, affectedTestFiles, }: WatchRerunPlannerInput) => WatchRerunPlan;
21
- export {};
20
+ export declare const planWatchRerun: ({ projectEntries, previousTestFiles, affectedTestFiles }: WatchRerunPlannerInput) => WatchRerunPlan;
21
+ export { };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rstest/browser",
3
- "version": "0.10.4",
3
+ "version": "0.10.6",
4
4
  "description": "Browser mode support for Rstest testing framework.",
5
5
  "keywords": [
6
6
  "rstest",
@@ -14,7 +14,7 @@
14
14
  },
15
15
  "repository": {
16
16
  "type": "git",
17
- "url": "https://github.com/web-infra-dev/rstest",
17
+ "url": "git+https://github.com/web-infra-dev/rstest.git",
18
18
  "directory": "packages/browser"
19
19
  },
20
20
  "license": "MIT",
@@ -48,22 +48,21 @@
48
48
  "ws": "^8.21.0"
49
49
  },
50
50
  "devDependencies": {
51
- "@rslib/core": "0.22.0",
51
+ "@rslib/core": "0.23.0",
52
52
  "@types/convert-source-map": "^2.0.3",
53
53
  "@types/picomatch": "^4.0.3",
54
54
  "@types/ws": "^8.18.1",
55
- "@typescript/native-preview": "7.0.0-dev.20260608.1",
56
55
  "@vitest/snapshot": "^3.2.6",
57
56
  "birpc": "^4.0.0",
58
57
  "picomatch": "^4.0.4",
59
- "playwright": "^1.60.0",
60
- "@rstest/core": "0.10.4",
58
+ "playwright": "^1.61.0",
61
59
  "@rstest/browser-ui": "0.0.0",
62
- "@rstest/tsconfig": "0.0.1"
60
+ "@rstest/tsconfig": "0.0.1",
61
+ "@rstest/core": "0.10.6"
63
62
  },
64
63
  "peerDependencies": {
65
64
  "playwright": "^1.49.1",
66
- "@rstest/core": "^0.10.4"
65
+ "@rstest/core": "^0.10.6"
67
66
  },
68
67
  "peerDependenciesMeta": {
69
68
  "playwright": {
@@ -79,7 +78,6 @@
79
78
  },
80
79
  "scripts": {
81
80
  "build": "rslib build",
82
- "dev": "rslib build --watch",
83
- "typecheck": "pnpm -w exec tsc --noEmit -p packages/browser/tsconfig.json"
81
+ "dev": "rslib build --watch"
84
82
  }
85
83
  }
@@ -14,7 +14,7 @@
14
14
  * - Artifacts intentionally excluded for now: screenshot/toMatchScreenshot/
15
15
  * trace/video
16
16
  */
17
- export const supportedLocatorActions = new Set<string>([
17
+ export const supportedLocatorActions: Set<string> = new Set([
18
18
  'click',
19
19
  'dblclick',
20
20
  'fill',
@@ -32,7 +32,7 @@ export const supportedLocatorActions = new Set<string>([
32
32
  'setInputFiles',
33
33
  ]);
34
34
 
35
- export const supportedExpectElementMatchers = new Set<string>([
35
+ export const supportedExpectElementMatchers: Set<string> = new Set([
36
36
  'toBeVisible',
37
37
  'toBeHidden',
38
38
  'toBeEnabled',
@@ -19,7 +19,7 @@ type HeadlessConcurrencyContext = Pick<Rstest, 'command'> & {
19
19
 
20
20
  export const resolveDefaultHeadlessWorkers = (
21
21
  command: HeadlessConcurrencyContext['command'],
22
- numCpus = getNumCpus(),
22
+ numCpus: number = getNumCpus(),
23
23
  ): number => {
24
24
  const baseWorkers = Math.max(
25
25
  Math.min(DEFAULT_MAX_HEADLESS_WORKERS, numCpus - 1),
@@ -1,10 +1,14 @@
1
1
  type HeadedSerialTask = () => Promise<void>;
2
2
 
3
+ type HeadedSerialTaskQueue = {
4
+ enqueue: (task: HeadedSerialTask) => Promise<void>;
5
+ };
6
+
3
7
  /**
4
8
  * Serializes headed browser file execution so only one task runs at a time.
5
9
  * The queue keeps draining even if an earlier task rejects.
6
10
  */
7
- export const createHeadedSerialTaskQueue = () => {
11
+ export const createHeadedSerialTaskQueue = (): HeadedSerialTaskQueue => {
8
12
  let queue: Promise<void> = Promise.resolve();
9
13
 
10
14
  const enqueue = (task: HeadedSerialTask): Promise<void> => {
@@ -600,7 +600,15 @@ export const createBrowserLazyCompilationConfig = (
600
600
  };
601
601
  };
602
602
 
603
- export const createBrowserRsbuildDevConfig = (_isWatchMode: boolean) => {
603
+ export const createBrowserRsbuildDevConfig = (
604
+ _isWatchMode: boolean,
605
+ ): {
606
+ writeToDisk: boolean;
607
+ hmr: boolean;
608
+ client: {
609
+ logLevel: 'error';
610
+ };
611
+ } => {
604
612
  return {
605
613
  writeToDisk: isDebug(),
606
614
  // Keep HMR enabled in browser mode even for one-shot runs.
@@ -621,6 +629,7 @@ const globToRegexp = (glob: string): RegExp => {
621
629
  fastpaths: false,
622
630
  noglobstar: false,
623
631
  bash: false,
632
+ dot: true,
624
633
  });
625
634
 
626
635
  if (!regex) {
@@ -668,44 +677,189 @@ const globPatternsToRegExp = (patterns: string[]): RegExp => {
668
677
  return new RegExp(`(?:${regexParts.join('|')})$`);
669
678
  };
670
679
 
680
+ const REGEXP_SPECIAL_CHARACTERS = /[|\\{}()[\]^$+*?.]/g;
681
+ const PATH_SEPARATOR_SOURCE = String.raw`[\\/]`;
682
+ const WINDOWS_ABSOLUTE_PATH_SOURCE = String.raw`[A-Za-z]:[\\/]`;
683
+
684
+ const escapeRegExp = (value: string): string =>
685
+ value.replace(REGEXP_SPECIAL_CHARACTERS, '\\$&');
686
+
687
+ const normalizePathForRegExp = (value: string): string =>
688
+ normalize(value).replaceAll('\\', '/');
689
+
690
+ const normalizeExcludePatternForRegExp = (value: string): string =>
691
+ value.startsWith('./')
692
+ ? `./${normalizePathForRegExp(value.substring(2))}`
693
+ : normalizePathForRegExp(value);
694
+
695
+ const isAbsolutePatternForRegExp = (value: string): boolean =>
696
+ value.startsWith('/') || /^[A-Za-z]:\//.test(value);
697
+
698
+ const isEscapedRegExpCharacter = (source: string, index: number): boolean => {
699
+ let backslashCount = 0;
700
+ for (
701
+ let current = index - 1;
702
+ current >= 0 && source[current] === '\\';
703
+ current--
704
+ ) {
705
+ backslashCount++;
706
+ }
707
+ return backslashCount % 2 === 1;
708
+ };
709
+
710
+ const replacePathSeparatorsInRegExpSource = (source: string): string => {
711
+ let result = '';
712
+ let inCharacterClass = false;
713
+
714
+ for (let index = 0; index < source.length; index++) {
715
+ const character = source[index];
716
+ const isEscaped = isEscapedRegExpCharacter(source, index);
717
+
718
+ if (character === '[' && !isEscaped) {
719
+ inCharacterClass = true;
720
+ }
721
+
722
+ if (!inCharacterClass && character === '\\' && source[index + 1] === '/') {
723
+ result += PATH_SEPARATOR_SOURCE;
724
+ index++;
725
+ continue;
726
+ }
727
+
728
+ result += character;
729
+
730
+ if (character === ']' && !isEscaped) {
731
+ inCharacterClass = false;
732
+ }
733
+ }
734
+
735
+ return result;
736
+ };
737
+
738
+ type BrowserContextExcludeSource = {
739
+ relative: string;
740
+ absolute: string;
741
+ isAbsolute: boolean;
742
+ };
743
+
744
+ const createRelativeContextExcludeSource = (
745
+ source: string,
746
+ normalizedPattern: string,
747
+ ): string => {
748
+ if (normalizedPattern.startsWith('./')) {
749
+ return source;
750
+ }
751
+
752
+ return normalizedPattern.startsWith('**/')
753
+ ? `(?:(?:${source})|\\.(?:${source}))`
754
+ : `(?:(?:${source})|\\.${PATH_SEPARATOR_SOURCE}(?:${source}))`;
755
+ };
756
+
757
+ const createProjectAbsoluteExcludeSource = (
758
+ source: string,
759
+ normalizedPattern: string,
760
+ ): string =>
761
+ normalizedPattern.startsWith('./') || normalizedPattern.startsWith('**/')
762
+ ? source
763
+ : `${PATH_SEPARATOR_SOURCE}(?:${source})`;
764
+
671
765
  /**
672
766
  * Convert exclude patterns to a RegExp for import.meta.webpackContext's exclude option
673
767
  * This is used at compile time to filter out files during bundling
674
768
  *
675
769
  * Example:
676
770
  * Input: ['**\/node_modules\/**', '**\/dist\/**']
677
- * Output: /[\\/](node_modules|dist)[\\/]/
771
+ * Output: a regexp matching node_modules or dist path segments.
678
772
  */
679
- const excludePatternsToRegExp = (patterns: string[]): RegExp | null => {
680
- const keywords: string[] = [];
681
- for (const pattern of patterns) {
682
- // Extract the core part between ** wildcards
683
- // e.g., '**/node_modules/**' -> 'node_modules'
684
- // e.g., '**/dist/**' -> 'dist'
685
- // e.g., '**/.{idea,git,cache,output,temp}/**' -> extract each part
686
- const match = pattern.match(
687
- /\*\*\/\.?\{?([^/*{}]+(?:,[^/*{}]+)*)\}?\/?\*?\*?/,
688
- );
689
- if (match) {
690
- // Handle {a,b,c} patterns
691
- const parts = match[1]!.split(',');
692
- for (const part of parts) {
693
- // Clean up the part (remove leading dots for hidden dirs)
694
- const cleaned = part.replace(/^\./, '');
695
- if (cleaned && !keywords.includes(cleaned)) {
696
- keywords.push(cleaned);
697
- }
698
- }
773
+ const excludePatternsToRegExpSources = (
774
+ patterns: string[],
775
+ ): BrowserContextExcludeSource[] | null => {
776
+ const sources = patterns.map((pattern) => {
777
+ const normalizedPattern = normalizeExcludePatternForRegExp(pattern);
778
+ const regex = globToRegexp(normalizedPattern);
779
+ let source = regex.source;
780
+ if (source.startsWith('^')) {
781
+ source = source.substring(1);
699
782
  }
783
+ if (source.endsWith('$')) {
784
+ source = source.substring(0, source.length - 1);
785
+ }
786
+
787
+ source = replacePathSeparatorsInRegExpSource(source);
788
+ const isAbsolute = isAbsolutePatternForRegExp(normalizedPattern);
789
+ const absolute = normalizedPattern.startsWith('./')
790
+ ? source.substring(2)
791
+ : source;
792
+
793
+ return {
794
+ relative: isAbsolute
795
+ ? source
796
+ : createRelativeContextExcludeSource(source, normalizedPattern),
797
+ absolute: isAbsolute
798
+ ? absolute
799
+ : createProjectAbsoluteExcludeSource(absolute, normalizedPattern),
800
+ isAbsolute,
801
+ };
802
+ });
803
+
804
+ if (sources.length === 0) {
805
+ return null;
700
806
  }
701
807
 
702
- if (keywords.length === 0) {
808
+ return sources;
809
+ };
810
+
811
+ export const createBrowserContextExcludeRegExp = (
812
+ patterns: string[],
813
+ projectRoot: string,
814
+ ): RegExp | null => {
815
+ const excludeSources = excludePatternsToRegExpSources(patterns);
816
+ if (!excludeSources) {
703
817
  return null;
704
818
  }
705
819
 
706
- // Create regex that matches paths containing these directory names
707
- // Use [\\/] to match both forward and back slashes
708
- return new RegExp(`[\\\\/](${keywords.join('|')})[\\\\/]`);
820
+ const normalizedProjectRoot = normalizePathForRegExp(projectRoot).replace(
821
+ /[\\/]$/,
822
+ '',
823
+ );
824
+ const projectRootSource = normalizedProjectRoot
825
+ .split('/')
826
+ .map(escapeRegExp)
827
+ .join(PATH_SEPARATOR_SOURCE);
828
+ const relativeExcludeSources = excludeSources.filter(
829
+ (source) => !source.isAbsolute,
830
+ );
831
+ const absoluteExcludeSources = excludeSources.filter(
832
+ (source) => source.isAbsolute,
833
+ );
834
+ const sourceBranches: string[] = [];
835
+
836
+ if (relativeExcludeSources.length > 0) {
837
+ const relativePatternSource = `(?:${relativeExcludeSources
838
+ .map((source) => source.relative)
839
+ .join('|')})`;
840
+ const absolutePatternSource = `(?:${relativeExcludeSources
841
+ .map((source) => source.absolute)
842
+ .join('|')})`;
843
+ const relativeSource = `(?:${relativePatternSource})`;
844
+ const absoluteSource = normalizedProjectRoot
845
+ ? `${projectRootSource}(?=${PATH_SEPARATOR_SOURCE})(?:${absolutePatternSource})`
846
+ : `(?:${absolutePatternSource})`;
847
+
848
+ sourceBranches.push(
849
+ `(?!${WINDOWS_ABSOLUTE_PATH_SOURCE}|${PATH_SEPARATOR_SOURCE})${relativeSource}`,
850
+ absoluteSource,
851
+ );
852
+ }
853
+
854
+ if (absoluteExcludeSources.length > 0) {
855
+ sourceBranches.push(
856
+ `(?:${absoluteExcludeSources
857
+ .map((source) => source.relative)
858
+ .join('|')})`,
859
+ );
860
+ }
861
+
862
+ return new RegExp(`^(?:${sourceBranches.join('|')})$`);
709
863
  };
710
864
 
711
865
  type StatsModule = {
@@ -1079,7 +1233,10 @@ const generateManifestModule = ({
1079
1233
  project.normalizedConfig.include,
1080
1234
  );
1081
1235
  const excludePatterns = project.normalizedConfig.exclude.patterns;
1082
- const excludeRegExp = excludePatternsToRegExp(excludePatterns);
1236
+ const excludeRegExp = createBrowserContextExcludeRegExp(
1237
+ excludePatterns,
1238
+ projectRootPosix,
1239
+ );
1083
1240
 
1084
1241
  lines.push(
1085
1242
  `const ${varName} = import.meta.webpackContext(${JSON.stringify(projectRootPosix)}, {`,
@@ -1 +0,0 @@
1
- @import "https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;600&display=swap";@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-space-y-reverse:0;--tw-border-style:solid;--tw-leading:initial;--tw-font-weight:initial;--tw-tracking:initial;--tw-ordinal:initial;--tw-slashed-zero:initial;--tw-numeric-figure:initial;--tw-numeric-spacing:initial;--tw-numeric-fraction:initial;--tw-duration:initial;--tw-ease:initial}}}@layer theme{:root,:host{--font-mono:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--color-zinc-950:#09090b;--color-black:#000;--color-white:#fff;--spacing:.25rem;--text-xs:.75rem;--text-xs--line-height:calc(1 / .75);--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--font-weight-light:300;--font-weight-medium:500;--font-weight-semibold:600;--font-weight-bold:700;--tracking-tight:-.025em;--tracking-wider:.05em;--tracking-widest:.1em;--radius-md:.375rem;--animate-spin:spin 1s linear infinite;--animate-pulse:pulse 2s cubic-bezier(.4, 0, .6, 1) infinite;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1)}@supports (color:lab(0% 0 0)){:root,:host{--color-zinc-950:lab(2.51107% .242703 -.886115)}}}@layer base,components;@layer utilities{.visible{visibility:visible}.absolute{position:absolute}.relative{position:relative}.inset-0{inset:calc(var(--spacing) * 0)}.inset-x-0{inset-inline:calc(var(--spacing) * 0)}.inset-y-0{inset-block:calc(var(--spacing) * 0)}.bottom-0{bottom:calc(var(--spacing) * 0)}.left-0{left:calc(var(--spacing) * 0)}.z-10{z-index:10}.container{width:100%}@media (min-width:40rem){.container{max-width:40rem}}@media (min-width:48rem){.container{max-width:48rem}}@media (min-width:64rem){.container{max-width:64rem}}@media (min-width:80rem){.container{max-width:80rem}}@media (min-width:96rem){.container{max-width:96rem}}.m-0{margin:calc(var(--spacing) * 0)}.mt-3{margin-top:calc(var(--spacing) * 3)}.ml-1{margin-left:calc(var(--spacing) * 1)}.block{display:block}.flex{display:flex}.grid{display:grid}.hidden{display:none}.inline{display:inline}.inline-flex{display:inline-flex}.h-2{height:calc(var(--spacing) * 2)}.h-4{height:calc(var(--spacing) * 4)}.h-5{height:calc(var(--spacing) * 5)}.h-6{height:calc(var(--spacing) * 6)}.h-7{height:calc(var(--spacing) * 7)}.h-8{height:calc(var(--spacing) * 8)}.h-\[1px\]{height:1px}.h-\[48px\]{height:48px}.h-full{height:100%}.h-screen{height:100vh}.min-h-0{min-height:calc(var(--spacing) * 0)}.w-2{width:calc(var(--spacing) * 2)}.w-4{width:calc(var(--spacing) * 4)}.w-5{width:calc(var(--spacing) * 5)}.w-7{width:calc(var(--spacing) * 7)}.w-8{width:calc(var(--spacing) * 8)}.w-\[16px\]{width:16px}.w-\[120px\]{width:120px}.w-\[280px\]{width:280px}.w-full{width:100%}.max-w-\[400px\]{max-width:400px}.flex-1{flex:1}.shrink-0{flex-shrink:0}.animate-pulse{animation:var(--animate-pulse)}.animate-spin{animation:var(--animate-spin)}.cursor-default{cursor:default}.resize{resize:both}.grid-cols-\[auto_minmax\(0\,1fr\)_auto\]{grid-template-columns:auto minmax(0,1fr) auto}.flex-col{flex-direction:column}.items-center{align-items:center}.items-start{align-items:flex-start}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.gap-1{gap:calc(var(--spacing) * 1)}.gap-1\.5{gap:calc(var(--spacing) * 1.5)}.gap-2{gap:calc(var(--spacing) * 2)}.gap-3{gap:calc(var(--spacing) * 3)}:where(.space-y-2>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 2) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 2) * calc(1 - var(--tw-space-y-reverse)))}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-x-hidden{overflow-x:hidden}.overflow-y-auto{overflow-y:auto}.rounded-full{border-radius:3.40282e38px}.rounded-md{border-radius:var(--radius-md)}.border{border-style:var(--tw-border-style);border-width:1px}.border-0{border-style:var(--tw-border-style);border-width:0}.bg-black\/\[0\.02\]{background-color:#00000005}@supports (color:color-mix(in lab, red, red)){.bg-black\/\[0\.02\]{background-color:color-mix(in oklab, var(--color-black) 2%, transparent)}}.bg-transparent{background-color:#0000}.bg-zinc-950{background-color:var(--color-zinc-950)}.p-0{padding:calc(var(--spacing) * 0)}.p-3{padding:calc(var(--spacing) * 3)}.p-4{padding:calc(var(--spacing) * 4)}.px-2{padding-inline:calc(var(--spacing) * 2)}.px-4{padding-inline:calc(var(--spacing) * 4)}.py-0{padding-block:calc(var(--spacing) * 0)}.py-0\.5{padding-block:calc(var(--spacing) * .5)}.py-1\.5{padding-block:calc(var(--spacing) * 1.5)}.py-3{padding-block:calc(var(--spacing) * 3)}.font-mono{font-family:var(--font-mono)}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.text-\[9px\]{font-size:9px}.text-\[10px\]{font-size:10px}.text-\[12px\]{font-size:12px}.text-\[13px\]{font-size:13px}.leading-none{--tw-leading:1;line-height:1}.font-bold{--tw-font-weight:var(--font-weight-bold);font-weight:var(--font-weight-bold)}.font-light{--tw-font-weight:var(--font-weight-light);font-weight:var(--font-weight-light)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.tracking-tight{--tw-tracking:var(--tracking-tight);letter-spacing:var(--tracking-tight)}.tracking-wider{--tw-tracking:var(--tracking-wider);letter-spacing:var(--tracking-wider)}.tracking-widest{--tw-tracking:var(--tracking-widest);letter-spacing:var(--tracking-widest)}.text-\(--accents-3\){color:var(--accents-3)}.text-\(--accents-4\){color:var(--accents-4)}.text-\(--accents-5\){color:var(--accents-5)}.text-\(--accents-6\){color:var(--accents-6)}.text-\(--accents-7\){color:var(--accents-7)}.text-\(--muted-foreground\){color:var(--muted-foreground)}.text-\(--warning\){color:var(--warning)}.text-white{color:var(--color-white)}.uppercase{text-transform:uppercase}.tabular-nums{--tw-numeric-spacing:tabular-nums;font-variant-numeric:var(--tw-ordinal, ) var(--tw-slashed-zero, ) var(--tw-numeric-figure, ) var(--tw-numeric-spacing, ) var(--tw-numeric-fraction, )}.opacity-0{opacity:0}.opacity-40{opacity:.4}.opacity-70{opacity:.7}.opacity-80{opacity:.8}.opacity-90{opacity:.9}.transition-all{transition-property:all;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-opacity{transition-property:opacity;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.duration-200{--tw-duration:.2s;transition-duration:.2s}.duration-500{--tw-duration:.5s;transition-duration:.5s}.ease-\[cubic-bezier\(0\.4\,0\,0\.2\,1\)\]{--tw-ease:cubic-bezier(.4,0,.2,1);transition-timing-function:cubic-bezier(.4,0,.2,1)}.select-none{-webkit-user-select:none;user-select:none}@media (hover:hover){.group-hover\:opacity-100:is(:where(.group):hover *){opacity:1}.hover\:bg-\(--accents-1\):hover{background-color:var(--accents-1)}.hover\:text-\(--accents-6\):hover{color:var(--accents-6)}}}.ant-typography.font-mono{font-family:var(--font-mono)}:root{--font-mono:"JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--background:#fff;--foreground:#000;--ds-gray-100:#fafafa;--ds-gray-200:#eaeaea;--ds-gray-300:#999;--ds-gray-400:#888;--ds-gray-500:#666;--ds-gray-600:#444;--ds-gray-700:#333;--ds-gray-800:#111;--ds-gray-900:#000;--ds-gray-1000:#000;--ds-red-100:#fff0f0;--ds-red-200:#ffebeb;--ds-red-300:#ffe6e6;--ds-red-700:#e5484d;--ds-red-800:#da2f35;--ds-red-900:#cb2a2f;--ds-green-100:#effbef;--ds-green-200:#ebfaeb;--ds-green-300:#daf6da;--ds-green-700:#45a557;--ds-green-800:#398e4a;--ds-green-900:#297a3a;--ds-amber-100:#fff6e6;--ds-amber-200:#fff4d6;--ds-amber-300:#fef0cd;--ds-amber-700:#ffb224;--ds-amber-800:#ff990a;--ds-amber-900:#a35200;--ds-blue-700:#0070f3;--accents-1:var(--ds-gray-100);--accents-2:var(--ds-gray-200);--accents-3:var(--ds-gray-300);--accents-4:var(--ds-gray-400);--accents-5:var(--ds-gray-500);--accents-6:var(--ds-gray-600);--accents-7:var(--ds-gray-700);--accents-8:var(--ds-gray-800);--border:var(--accents-2);--muted:var(--accents-1);--muted-foreground:var(--accents-5);--primary:var(--foreground);--success:var(--ds-green-700);--error:var(--ds-red-800);--warning:var(--ds-amber-700);--lightningcss-light:initial;--lightningcss-dark: ;--lightningcss-light:initial;--lightningcss-dark: ;color-scheme:light}[data-theme=dark]{--background:#000;--foreground:#fff;--ds-gray-100:#111;--ds-gray-200:#333;--ds-gray-300:#444;--ds-gray-400:#666;--ds-gray-500:#888;--ds-gray-600:#999;--ds-gray-700:#eaeaea;--ds-gray-800:#fafafa;--ds-gray-900:#fff;--ds-gray-1000:#fff;--ds-red-100:#2a1314;--ds-red-200:#3c1618;--ds-red-300:#561a1e;--ds-red-700:#e5484d;--ds-red-800:#d93036;--ds-red-900:#ff6166;--ds-green-100:#0b2212;--ds-green-200:#0f2e18;--ds-green-300:#12361b;--ds-green-700:#45a557;--ds-green-800:#398e4a;--ds-green-900:#62c073;--ds-amber-100:#291800;--ds-amber-200:#331b00;--ds-amber-300:#4d2a00;--ds-amber-700:#ffb224;--ds-amber-800:#ff990a;--ds-amber-900:#f2a20d;--ds-blue-700:#0070f3;--accents-1:var(--ds-gray-100);--accents-2:var(--ds-gray-200);--accents-3:var(--ds-gray-300);--accents-4:var(--ds-gray-400);--accents-5:var(--ds-gray-500);--accents-6:var(--ds-gray-600);--accents-7:var(--ds-gray-700);--accents-8:var(--ds-gray-800);--border:var(--accents-2);--muted:var(--accents-1);--muted-foreground:var(--accents-5);--primary:var(--foreground);--success:var(--ds-green-700);--error:var(--ds-red-800);--warning:var(--ds-amber-700);--lightningcss-light: ;--lightningcss-dark:initial;--lightningcss-light: ;--lightningcss-dark:initial;color-scheme:dark}*{box-sizing:border-box}body{background:var(--background);min-height:100vh;color:var(--foreground);margin:0;font-family:Inter,system-ui,-apple-system,sans-serif;overflow:hidden}.ant-input-affix-wrapper:focus,.ant-input-affix-wrapper-focused{border-color:var(--foreground);box-shadow:0 0 0 1px var(--foreground)}.ant-tree .ant-tree-node-content-wrapper.ant-tree-node-selected{transition:none}@keyframes status-flash{0%{filter:brightness()}5%{filter:brightness(2.5)}15%{filter:brightness(1.8)}40%{filter:brightness(1.3)}to{filter:brightness()}}.status-icon-flash{animation:1.5s ease-out status-flash}@keyframes progress-segment-flash{0%{filter:brightness();box-shadow:none}10%{filter:brightness(2.5);box-shadow:0 0 8px 1px}to{filter:brightness();box-shadow:none}}.progress-flash-active{animation:1s cubic-bezier(.4,0,.2,1) progress-segment-flash}@property --tw-space-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-leading{syntax:"*";inherits:false}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-ordinal{syntax:"*";inherits:false}@property --tw-slashed-zero{syntax:"*";inherits:false}@property --tw-numeric-figure{syntax:"*";inherits:false}@property --tw-numeric-spacing{syntax:"*";inherits:false}@property --tw-numeric-fraction{syntax:"*";inherits:false}@property --tw-duration{syntax:"*";inherits:false}@property --tw-ease{syntax:"*";inherits:false}@keyframes spin{to{transform:rotate(360deg)}}@keyframes pulse{50%{opacity:.5}}
@@ -1 +0,0 @@
1
- /*! LICENSE: 3.d3d6c6e4cf.js.LICENSE.txt */
@@ -1,4 +0,0 @@
1
- declare global {
2
- var __coverage__: Record<string, unknown> | undefined;
3
- }
4
- export {};
@@ -1,25 +0,0 @@
1
- export type FakeTimerInstallOpts = Record<string, unknown>;
2
- export type FakeTimerWithContext = {
3
- timers: Record<string, unknown>;
4
- };
5
- export type InstalledClock = {
6
- now: number;
7
- reset: () => void;
8
- uninstall: () => void;
9
- runAll: () => void;
10
- runAllAsync: () => Promise<void>;
11
- runToLast: () => void;
12
- runToLastAsync: () => Promise<void>;
13
- tick: (ms: number) => void;
14
- tickAsync: (ms: number) => Promise<void>;
15
- next: () => void;
16
- nextAsync: () => Promise<void>;
17
- runToFrame: () => void;
18
- runMicrotasks: () => void;
19
- setSystemTime: (now?: number | Date) => void;
20
- countTimers: () => number;
21
- };
22
- export declare const withGlobal: (_global: typeof globalThis) => {
23
- timers: {};
24
- install: (_config?: FakeTimerInstallOpts) => InstalledClock;
25
- };
@@ -1,9 +0,0 @@
1
- /**
2
- * Re-export runtime API from @rstest/core/internal/browser-runtime for browser use.
3
- * This file is used as an alias target for '@rstest/core' in browser mode.
4
- *
5
- * Uses @rstest/core/internal/browser-runtime which only exports the test APIs
6
- * (describe, it, expect, etc.) without any Node.js dependencies.
7
- */
8
- export type { Assertion, Mock } from '@rstest/core';
9
- export * from '@rstest/core/internal/browser-runtime';
@@ -1,29 +0,0 @@
1
- /**
2
- * Browser snapshot environment that proxies file operations to the host
3
- * via postMessage RPC through the container.
4
- */
5
- export declare class BrowserSnapshotEnvironment {
6
- getVersion(): string;
7
- getHeader(): string;
8
- resolveRawPath(_testPath: string, rawPath: string): Promise<string>;
9
- resolvePath(filepath: string): Promise<string>;
10
- prepareDirectory(): Promise<void>;
11
- saveSnapshotFile(filepath: string, snapshot: string): Promise<void>;
12
- readSnapshotFile(filepath: string): Promise<string | null>;
13
- removeSnapshotFile(filepath: string): Promise<void>;
14
- /**
15
- * Process stack trace for inline snapshots.
16
- * Maps bundled URLs back to original source file paths.
17
- */
18
- processStackTrace(stack: {
19
- file: string;
20
- line: number;
21
- column: number;
22
- method: string;
23
- }): {
24
- file: string;
25
- line: number;
26
- column: number;
27
- method: string;
28
- };
29
- }