@rstest/browser 0.9.3 → 0.9.5

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 (31) hide show
  1. package/dist/browser-container/container-static/js/{927.514b181bd2.js → 677.d1243053e0.js} +1205 -1211
  2. package/dist/browser-container/container-static/js/677.d1243053e0.js.LICENSE.txt +1 -0
  3. package/dist/browser-container/container-static/js/{index.5acf502b10.js → index.cb4870ffcc.js} +7 -7
  4. package/dist/browser-container/index.html +1 -1
  5. package/dist/client/dispatchTransport.d.ts +0 -1
  6. package/dist/client/sourceMapSupport.d.ts +2 -5
  7. package/dist/concurrency.d.ts +2 -2
  8. package/dist/dispatchCapabilities.d.ts +1 -1
  9. package/dist/headedSerialTaskQueue.d.ts +2 -1
  10. package/dist/headlessLatestRerunScheduler.d.ts +1 -1
  11. package/dist/hostController.d.ts +2 -1
  12. package/dist/index.js +255 -32
  13. package/dist/protocol.d.ts +1 -5
  14. package/dist/rpcProtocol.d.ts +0 -13
  15. package/dist/sessionRegistry.d.ts +1 -1
  16. package/dist/watchRerunPlanner.d.ts +2 -2
  17. package/package.json +17 -18
  18. package/src/client/dispatchTransport.ts +1 -1
  19. package/src/client/sourceMapSupport.ts +1 -9
  20. package/src/concurrency.ts +2 -2
  21. package/src/configValidation.ts +7 -1
  22. package/src/dispatchCapabilities.ts +1 -1
  23. package/src/headedSerialTaskQueue.ts +1 -1
  24. package/src/headlessLatestRerunScheduler.ts +1 -1
  25. package/src/hostController.ts +45 -34
  26. package/src/protocol.ts +0 -9
  27. package/src/rpcProtocol.ts +0 -15
  28. package/src/sessionRegistry.ts +1 -1
  29. package/src/watchCliShortcuts.ts +3 -1
  30. package/src/watchRerunPlanner.ts +2 -2
  31. package/dist/browser-container/container-static/js/927.514b181bd2.js.LICENSE.txt +0 -1
@@ -1,5 +1,5 @@
1
1
  import type { TestFileInfo } from './protocol';
2
- export type WatchPlannerProjectEntry = {
2
+ type WatchPlannerProjectEntry = {
3
3
  project: {
4
4
  name: string;
5
5
  };
@@ -10,7 +10,7 @@ type WatchRerunPlannerInput = {
10
10
  previousTestFiles: TestFileInfo[];
11
11
  affectedTestFiles: string[];
12
12
  };
13
- export type WatchRerunPlan = {
13
+ type WatchRerunPlan = {
14
14
  currentTestFiles: TestFileInfo[];
15
15
  filesChanged: boolean;
16
16
  normalizedAffectedTestFiles: string[];
package/package.json CHANGED
@@ -1,7 +1,14 @@
1
1
  {
2
2
  "name": "@rstest/browser",
3
- "version": "0.9.3",
3
+ "version": "0.9.5",
4
4
  "description": "Browser mode support for Rstest testing framework.",
5
+ "keywords": [
6
+ "rstest",
7
+ "browser",
8
+ "test",
9
+ "rstack",
10
+ "rspack"
11
+ ],
5
12
  "bugs": {
6
13
  "url": "https://github.com/web-infra-dev/rstest/issues"
7
14
  },
@@ -10,16 +17,8 @@
10
17
  "url": "https://github.com/web-infra-dev/rstest",
11
18
  "directory": "packages/browser"
12
19
  },
13
- "keywords": [
14
- "rstest",
15
- "browser",
16
- "test",
17
- "rstack",
18
- "rspack"
19
- ],
20
20
  "license": "MIT",
21
21
  "type": "module",
22
- "main": "./dist/index.js",
23
22
  "exports": {
24
23
  ".": {
25
24
  "types": "./dist/browser.d.ts",
@@ -33,6 +32,7 @@
33
32
  "default": "./package.json"
34
33
  }
35
34
  },
35
+ "main": "./dist/index.js",
36
36
  "files": [
37
37
  "dist",
38
38
  "src",
@@ -45,7 +45,7 @@
45
45
  "open-editor": "^6.0.0",
46
46
  "pathe": "^2.0.3",
47
47
  "sirv": "^3.0.2",
48
- "ws": "^8.19.0"
48
+ "ws": "^8.20.0"
49
49
  },
50
50
  "devDependencies": {
51
51
  "@rslib/core": "0.20.0",
@@ -55,16 +55,15 @@
55
55
  "@typescript/native-preview": "7.0.0-dev.20260317.1",
56
56
  "@vitest/snapshot": "^3.2.4",
57
57
  "birpc": "^4.0.0",
58
- "picocolors": "^1.1.1",
59
- "picomatch": "^4.0.3",
58
+ "picomatch": "^4.0.4",
60
59
  "playwright": "^1.58.2",
61
- "@rstest/core": "0.9.3",
62
- "@rstest/tsconfig": "0.0.1",
63
- "@rstest/browser-ui": "0.0.0"
60
+ "@rstest/core": "0.9.5",
61
+ "@rstest/browser-ui": "0.0.0",
62
+ "@rstest/tsconfig": "0.0.1"
64
63
  },
65
64
  "peerDependencies": {
66
65
  "playwright": "^1.49.1",
67
- "@rstest/core": "^0.9.3"
66
+ "@rstest/core": "^0.9.5"
68
67
  },
69
68
  "peerDependenciesMeta": {
70
69
  "playwright": {
@@ -80,7 +79,7 @@
80
79
  },
81
80
  "scripts": {
82
81
  "build": "rslib build",
83
- "typecheck": "tsc --noEmit",
84
- "dev": "rslib build --watch"
82
+ "dev": "rslib build --watch",
83
+ "typecheck": "tsc --noEmit"
85
84
  }
86
85
  }
@@ -8,7 +8,7 @@ import {
8
8
  DISPATCH_RPC_REQUEST_TYPE,
9
9
  } from '../protocol';
10
10
 
11
- export const DEFAULT_RPC_TIMEOUT_MS = 30_000;
11
+ const DEFAULT_RPC_TIMEOUT_MS = 30_000;
12
12
 
13
13
  export const getRpcTimeout = (): number => {
14
14
  return (
@@ -111,18 +111,10 @@ export const preloadRunnerSourceMap = async (): Promise<void> => {
111
111
  await preloadSourceMap(runnerUrl);
112
112
  };
113
113
 
114
- /**
115
- * Clear cache (for testing purposes)
116
- */
117
- export const clearCache = (): void => {
118
- sourceMapCache.clear();
119
- sourceMapPayloadCache.clear();
120
- };
121
-
122
114
  /**
123
115
  * Stack frame interface matching @vitest/snapshot's format
124
116
  */
125
- export interface StackFrame {
117
+ interface StackFrame {
126
118
  file: string;
127
119
  line: number;
128
120
  column: number;
@@ -5,7 +5,7 @@ import type { Rstest } from '@rstest/core/browser';
5
5
  // Keep this in one place so executors reuse the same worker semantics.
6
6
  const DEFAULT_MAX_HEADLESS_WORKERS = 12;
7
7
 
8
- export type HeadlessConcurrencyContext = Pick<Rstest, 'command'> & {
8
+ type HeadlessConcurrencyContext = Pick<Rstest, 'command'> & {
9
9
  normalizedConfig: {
10
10
  pool: {
11
11
  maxWorkers?: string | number;
@@ -13,7 +13,7 @@ export type HeadlessConcurrencyContext = Pick<Rstest, 'command'> & {
13
13
  };
14
14
  };
15
15
 
16
- export const getNumCpus = (): number => {
16
+ const getNumCpus = (): number => {
17
17
  return os.availableParallelism?.() ?? os.cpus().length;
18
18
  };
19
19
 
@@ -44,7 +44,7 @@ const validateViewport = (viewport: unknown): void => {
44
44
 
45
45
  export const validateBrowserConfig = (context: Rstest): void => {
46
46
  for (const project of context.projects) {
47
- const browser = project.normalizedConfig.browser;
47
+ const { browser, output } = project.normalizedConfig;
48
48
  if (!browser.enabled) {
49
49
  continue;
50
50
  }
@@ -66,5 +66,11 @@ export const validateBrowserConfig = (context: Rstest): void => {
66
66
  if (!isPlainObject(browser.providerOptions)) {
67
67
  throw new Error('browser.providerOptions must be a plain object.');
68
68
  }
69
+
70
+ if (output?.bundleDependencies === false) {
71
+ throw new Error(
72
+ 'output.bundleDependencies false is not supported in browser mode.',
73
+ );
74
+ }
69
75
  }
70
76
  };
@@ -27,7 +27,7 @@ type RunnerDispatchSuiteStartPayload = ReporterHookArg<'onTestSuiteStart'>;
27
27
  type RunnerDispatchSuiteResultPayload = ReporterHookArg<'onTestSuiteResult'>;
28
28
  type RunnerDispatchCaseStartPayload = ReporterHookArg<'onTestCaseStart'>;
29
29
 
30
- export type RunnerDispatchCallbacks = {
30
+ type RunnerDispatchCallbacks = {
31
31
  onTestFileStart: (payload: RunnerPayload<'file-start'>) => Promise<void>;
32
32
  onTestFileReady: (payload: RunnerDispatchFileReadyPayload) => Promise<void>;
33
33
  onTestSuiteStart: (payload: RunnerDispatchSuiteStartPayload) => Promise<void>;
@@ -1,4 +1,4 @@
1
- export type HeadedSerialTask = () => Promise<void>;
1
+ type HeadedSerialTask = () => Promise<void>;
2
2
 
3
3
  /**
4
4
  * Serializes headed browser file execution so only one task runs at a time.
@@ -1,4 +1,4 @@
1
- export type HeadlessLatestRerunScheduler<TFile> = {
1
+ type HeadlessLatestRerunScheduler<TFile> = {
2
2
  enqueueLatest: (files: TFile[]) => Promise<void>;
3
3
  whenIdle: () => Promise<void>;
4
4
  };
@@ -22,7 +22,6 @@ import {
22
22
  type RuntimeConfig,
23
23
  rsbuild,
24
24
  serializableConfig,
25
- TEMP_RSTEST_OUTPUT_DIR,
26
25
  type Test,
27
26
  type TestFileResult,
28
27
  type TestResult,
@@ -543,11 +542,12 @@ export const createBrowserLazyCompilationConfig = (
543
542
  };
544
543
  };
545
544
 
546
- export const createBrowserRsbuildDevConfig = (isWatchMode: boolean) => {
545
+ export const createBrowserRsbuildDevConfig = (_isWatchMode: boolean) => {
547
546
  return {
548
- // Disable HMR in non-watch mode (tests run once and exit).
549
- // Aligns with node mode behavior (packages/core/src/core/rsbuild.ts).
550
- hmr: isWatchMode,
547
+ writeToDisk: isDebug(),
548
+ // Keep HMR enabled in browser mode even for one-shot runs.
549
+ // lazyCompilation depends on HMR runtime wiring for async import chains.
550
+ hmr: true,
551
551
  client: {
552
552
  logLevel: 'error' as const,
553
553
  },
@@ -873,35 +873,33 @@ const resolveProviderForTestPath = ({
873
873
  const collectProjectEntries = async (
874
874
  context: Rstest,
875
875
  ): Promise<BrowserProjectEntries[]> => {
876
- const projectEntries: BrowserProjectEntries[] = [];
877
-
878
876
  // Only collect entries for browser mode projects
879
877
  const browserProjects = getBrowserProjects(context);
880
878
 
881
- for (const project of browserProjects) {
882
- const {
883
- normalizedConfig: { include, exclude, includeSource, setupFiles },
884
- } = project;
885
-
886
- const tests = await getTestEntries({
887
- include,
888
- exclude: exclude.patterns,
889
- includeSource,
890
- rootPath: context.rootPath,
891
- projectRoot: project.rootPath,
892
- fileFilters: context.fileFilters || [],
893
- });
879
+ return Promise.all(
880
+ browserProjects.map(async (project) => {
881
+ const {
882
+ normalizedConfig: { include, exclude, includeSource, setupFiles },
883
+ } = project;
884
+
885
+ const tests = await getTestEntries({
886
+ include,
887
+ exclude: exclude.patterns,
888
+ includeSource,
889
+ rootPath: context.rootPath,
890
+ projectRoot: project.rootPath,
891
+ fileFilters: context.fileFilters || [],
892
+ });
894
893
 
895
- const setup = getSetupFiles(setupFiles, project.rootPath);
894
+ const setup = getSetupFiles(setupFiles, project.rootPath);
896
895
 
897
- projectEntries.push({
898
- project,
899
- setupFiles: Object.values(setup),
900
- testFiles: Object.values(tests),
901
- });
902
- }
903
-
904
- return projectEntries;
896
+ return {
897
+ project,
898
+ setupFiles: Object.values(setup),
899
+ testFiles: Object.values(tests),
900
+ };
901
+ }),
902
+ );
905
903
  };
906
904
 
907
905
  const resolveBrowserFile = (relativePath: string): string => {
@@ -1391,6 +1389,18 @@ const createBrowserRuntime = async ({
1391
1389
  getPortSilently: true,
1392
1390
  });
1393
1391
 
1392
+ if (isDebug()) {
1393
+ await rsbuildInstance.inspectConfig({
1394
+ writeToDisk: true,
1395
+ extraConfigs: {
1396
+ rstest: {
1397
+ ...context.normalizedConfig,
1398
+ projects: browserProjects.map((p) => p.normalizedConfig),
1399
+ },
1400
+ },
1401
+ });
1402
+ }
1403
+
1394
1404
  // Serve prebuilt container assets (SPA) via sirv
1395
1405
  const serveContainer = containerDistPath
1396
1406
  ? sirv(containerDistPath, {
@@ -1576,10 +1586,10 @@ const createBrowserRuntime = async ({
1576
1586
  dispatchHandlers,
1577
1587
  wss,
1578
1588
  };
1579
- } catch (_error) {
1589
+ } catch (error) {
1580
1590
  wss.close();
1581
1591
  await devServer.close();
1582
- throw _error;
1592
+ throw error;
1583
1593
  }
1584
1594
  };
1585
1595
 
@@ -1833,14 +1843,15 @@ export const runBrowserController = async (
1833
1843
 
1834
1844
  const isWatchMode = context.command === 'watch';
1835
1845
  const enableCliShortcuts = isWatchMode && isBrowserWatchCliShortcutsEnabled();
1846
+ const browserTempOutputRoot = context.normalizedConfig.output.distPath.root;
1836
1847
  const tempDir =
1837
1848
  isWatchMode && watchContext.runtime
1838
1849
  ? watchContext.runtime.tempDir
1839
1850
  : isWatchMode
1840
- ? join(context.rootPath, TEMP_RSTEST_OUTPUT_DIR, 'browser', 'watch')
1851
+ ? join(context.rootPath, browserTempOutputRoot, 'browser', 'watch')
1841
1852
  : join(
1842
1853
  context.rootPath,
1843
- TEMP_RSTEST_OUTPUT_DIR,
1854
+ browserTempOutputRoot,
1844
1855
  'browser',
1845
1856
  Date.now().toString(),
1846
1857
  );
@@ -3227,7 +3238,7 @@ export const listBrowserTests = async (
3227
3238
 
3228
3239
  const tempDir = join(
3229
3240
  context.rootPath,
3230
- TEMP_RSTEST_OUTPUT_DIR,
3241
+ context.normalizedConfig.output.distPath.root,
3231
3242
  'browser',
3232
3243
  `list-${Date.now()}`,
3233
3244
  );
package/src/protocol.ts CHANGED
@@ -9,12 +9,8 @@ import type { SnapshotUpdateState } from '@vitest/snapshot';
9
9
 
10
10
  export type {
11
11
  BrowserLocatorIR,
12
- BrowserLocatorStep,
13
- BrowserLocatorText,
14
12
  BrowserRpcRequest,
15
- BrowserRpcResponse,
16
13
  SnapshotRpcRequest,
17
- SnapshotRpcResponse,
18
14
  } from './rpcProtocol';
19
15
  export { validateBrowserRpcRequest } from './rpcProtocol';
20
16
 
@@ -166,11 +162,6 @@ export type BrowserDispatchResponse = {
166
162
  stale?: boolean;
167
163
  };
168
164
 
169
- export type BrowserDispatchResponseEnvelope = {
170
- type: typeof DISPATCH_RESPONSE_TYPE;
171
- payload: BrowserDispatchResponse;
172
- };
173
-
174
165
  export type BrowserDispatchHandler = (
175
166
  request: BrowserDispatchRequest,
176
167
  ) => Promise<unknown>;
@@ -178,12 +178,6 @@ export const validateBrowserRpcRequest = (
178
178
  return request;
179
179
  };
180
180
 
181
- export type BrowserRpcResponse = {
182
- id: string;
183
- result?: unknown;
184
- error?: string;
185
- };
186
-
187
181
  /**
188
182
  * Snapshot RPC request from runner iframe.
189
183
  * The container will forward these to the host via WebSocket RPC.
@@ -209,12 +203,3 @@ export type SnapshotRpcRequest =
209
203
  method: 'removeSnapshotFile';
210
204
  args: { filepath: string };
211
205
  };
212
-
213
- /**
214
- * Snapshot RPC response from container to runner iframe.
215
- */
216
- export type SnapshotRpcResponse = {
217
- id: string;
218
- result?: unknown;
219
- error?: string;
220
- };
@@ -1,6 +1,6 @@
1
1
  import type { BrowserProviderContext, BrowserProviderPage } from './providers';
2
2
 
3
- export type RunnerSessionRecord = {
3
+ type RunnerSessionRecord = {
4
4
  id: string;
5
5
  testFile: string;
6
6
  projectName: string;
@@ -70,7 +70,9 @@ export async function setupBrowserWatchCliShortcuts({
70
70
  try {
71
71
  process.stdin.setRawMode(false);
72
72
  process.stdin.pause();
73
- } catch {}
73
+ } catch {
74
+ // do nothing
75
+ }
74
76
 
75
77
  process.stdin.off('keypress', handleKeypress);
76
78
  };
@@ -1,7 +1,7 @@
1
1
  import { normalize } from 'pathe';
2
2
  import type { TestFileInfo } from './protocol';
3
3
 
4
- export type WatchPlannerProjectEntry = {
4
+ type WatchPlannerProjectEntry = {
5
5
  project: {
6
6
  name: string;
7
7
  };
@@ -14,7 +14,7 @@ type WatchRerunPlannerInput = {
14
14
  affectedTestFiles: string[];
15
15
  };
16
16
 
17
- export type WatchRerunPlan = {
17
+ type WatchRerunPlan = {
18
18
  currentTestFiles: TestFileInfo[];
19
19
  filesChanged: boolean;
20
20
  normalizedAffectedTestFiles: string[];
@@ -1 +0,0 @@
1
- /*! LICENSE: 927.514b181bd2.js.LICENSE.txt */