@rstest/browser 0.9.4 → 0.9.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 (31) hide show
  1. package/dist/browser-container/container-static/js/{927.514b181bd2.js → 407.89ee95c89d.js} +622 -615
  2. package/dist/browser-container/container-static/js/407.89ee95c89d.js.LICENSE.txt +1 -0
  3. package/dist/browser-container/container-static/js/{index.5acf502b10.js → index.3ad6624086.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 +13 -1
  12. package/dist/index.js +260 -28
  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 +19 -20
  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 +49 -11
  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
@@ -0,0 +1 @@
1
+ /*! LICENSE: 407.89ee95c89d.js.LICENSE.txt */
@@ -4,7 +4,7 @@
4
4
  5645 (e, t, s) {
5
5
  var l = s(6730);
6
6
  let r = "__rstest_dispatch_response__", o = "runner";
7
- var a = s(2650), i = s(1855), n = s(9013), c = s(162), d = s(2739);
7
+ var a = s(7283), i = s(281), n = s(7026), c = s(162), d = s(2739);
8
8
  let u = (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 p = s(9347), h = s(7660), f = s(4335), x = s(6942), m = s(396);
18
+ var p = s(8609), h = s(6490), f = s(4335), x = s(6942), m = s(396);
19
19
  let g = (e, t)=>{
20
20
  if (!t) return e;
21
21
  let s = t.endsWith("/") ? t.slice(0, -1) : t;
@@ -78,7 +78,7 @@
78
78
  })
79
79
  }
80
80
  };
81
- var S = s(4532), F = s(9303), N = s(8814), A = s(1309), P = s(5758), M = s(9031), z = s(3168), O = s(2024);
81
+ var S = s(5446), F = s(8426), N = s(2585), A = s(1309), P = s(5758), M = s(9031), z = s(3168), O = s(2024);
82
82
  let R = {
83
83
  iPhoneSE: {
84
84
  width: 375,
@@ -514,7 +514,7 @@
514
514
  ]
515
515
  });
516
516
  };
517
- var G = s(2936);
517
+ var G = s(324);
518
518
  let Z = (e)=>{
519
519
  let { className: t, style: s, direction: r = "horizontal", children: o, autoSaveId: a, ...i } = e, n = c.Children.toArray(o).filter((e)=>c.isValidElement(e) && e.type === L), d = c.useCallback(()=>{
520
520
  if (!a) return null;
@@ -1585,7 +1585,7 @@
1585
1585
  ]
1586
1586
  });
1587
1587
  };
1588
- var K = s(6920), Y = s(4923), Q = s(8346), ee = s(407), et = s(5952), es = s(5283);
1588
+ var K = s(7239), Y = s(4923), Q = s(8346), ee = s(407), et = s(3571), es = s(7889);
1589
1589
  let el = (0, c.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 eo = s(3451), ea = s(4947), ei = s(2559), en = s(7957), ec = s(719);
1728
+ var eo = s(5860), ea = s(6254), ei = s(2559), en = s(7957), ec = s(719);
1729
1729
  let ed = [
1730
1730
  "pass",
1731
1731
  "fail",
@@ -3069,7 +3069,7 @@
3069
3069
  }, (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));
3070
3070
  var c = n.O(void 0, [
3071
3071
  "783",
3072
- "927"
3072
+ "407"
3073
3073
  ], ()=>n(5645));
3074
3074
  c = n.O(c);
3075
3075
  })();
@@ -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.f905279759.js"></script><script defer src="/container-static/js/927.514b181bd2.js"></script><script defer src="/container-static/js/index.5acf502b10.js"></script><link href="/container-static/css/index.5c72297783.css" rel="stylesheet"></head>
15
+ <script defer src="/container-static/js/lib-react.f905279759.js"></script><script defer src="/container-static/js/407.89ee95c89d.js"></script><script defer src="/container-static/js/index.3ad6624086.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>
@@ -1,5 +1,4 @@
1
1
  import type { BrowserDispatchRequest } from '../protocol';
2
- export declare const DEFAULT_RPC_TIMEOUT_MS = 30000;
3
2
  export declare const getRpcTimeout: () => number;
4
3
  export declare const createRequestId: (prefix: string) => string;
5
4
  export declare const dispatchRpc: <T>({ requestId, request, timeoutMs, timeoutMessage, staleMessage, }: {
@@ -25,14 +25,10 @@ export declare const preloadTestFileSourceMap: (chunkUrl: string) => Promise<voi
25
25
  * to the original source files.
26
26
  */
27
27
  export declare const preloadRunnerSourceMap: () => Promise<void>;
28
- /**
29
- * Clear cache (for testing purposes)
30
- */
31
- export declare const clearCache: () => void;
32
28
  /**
33
29
  * Stack frame interface matching @vitest/snapshot's format
34
30
  */
35
- export interface StackFrame {
31
+ interface StackFrame {
36
32
  file: string;
37
33
  line: number;
38
34
  column: number;
@@ -43,3 +39,4 @@ export interface StackFrame {
43
39
  * This is used by BrowserSnapshotEnvironment.processStackTrace
44
40
  */
45
41
  export declare const mapStackFrame: (frame: StackFrame) => StackFrame;
42
+ export {};
@@ -1,12 +1,12 @@
1
1
  import type { Rstest } from '@rstest/core/browser';
2
- export type HeadlessConcurrencyContext = Pick<Rstest, 'command'> & {
2
+ type HeadlessConcurrencyContext = Pick<Rstest, 'command'> & {
3
3
  normalizedConfig: {
4
4
  pool: {
5
5
  maxWorkers?: string | number;
6
6
  };
7
7
  };
8
8
  };
9
- export declare const getNumCpus: () => number;
10
9
  export declare const parseWorkers: (maxWorkers: string | number, numCpus?: number) => number;
11
10
  export declare const resolveDefaultHeadlessWorkers: (command: HeadlessConcurrencyContext["command"], numCpus?: number) => number;
12
11
  export declare const getHeadlessConcurrency: (context: HeadlessConcurrencyContext, totalTests: number) => number;
12
+ export {};
@@ -12,7 +12,7 @@ type RunnerDispatchFileReadyPayload = ReporterHookArg<'onTestFileReady'>;
12
12
  type RunnerDispatchSuiteStartPayload = ReporterHookArg<'onTestSuiteStart'>;
13
13
  type RunnerDispatchSuiteResultPayload = ReporterHookArg<'onTestSuiteResult'>;
14
14
  type RunnerDispatchCaseStartPayload = ReporterHookArg<'onTestCaseStart'>;
15
- export type RunnerDispatchCallbacks = {
15
+ type RunnerDispatchCallbacks = {
16
16
  onTestFileStart: (payload: RunnerPayload<'file-start'>) => Promise<void>;
17
17
  onTestFileReady: (payload: RunnerDispatchFileReadyPayload) => Promise<void>;
18
18
  onTestSuiteStart: (payload: RunnerDispatchSuiteStartPayload) => Promise<void>;
@@ -1,4 +1,4 @@
1
- export type HeadedSerialTask = () => Promise<void>;
1
+ type HeadedSerialTask = () => Promise<void>;
2
2
  /**
3
3
  * Serializes headed browser file execution so only one task runs at a time.
4
4
  * The queue keeps draining even if an earlier task rejects.
@@ -6,3 +6,4 @@ export type HeadedSerialTask = () => Promise<void>;
6
6
  export declare const createHeadedSerialTaskQueue: () => {
7
7
  enqueue: (task: HeadedSerialTask) => Promise<void>;
8
8
  };
9
+ export {};
@@ -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
  };
@@ -7,8 +7,20 @@ type BrowserLazyCompilationConfig = {
7
7
  entries: false;
8
8
  test?: (module: LazyCompilationModule) => boolean;
9
9
  };
10
+ /**
11
+ * Resolve the actual port the dev server is listening on.
12
+ *
13
+ * Rsbuild's `devServer.listen()` may return `0` when configured with
14
+ * `server.port: 0` because its internal `getPort` never reads back the
15
+ * OS-assigned ephemeral port. This helper falls back to
16
+ * `httpServer.address()` to obtain the real bound port.
17
+ */
18
+ export declare const resolveListenPort: (listenPort: number, httpServer: {
19
+ address: () => ReturnType<import("node:net").Server["address"]>;
20
+ } | null) => number;
10
21
  export declare const createBrowserLazyCompilationConfig: (setupFiles: string[]) => BrowserLazyCompilationConfig;
11
- export declare const createBrowserRsbuildDevConfig: (isWatchMode: boolean) => {
22
+ export declare const createBrowserRsbuildDevConfig: (_isWatchMode: boolean) => {
23
+ writeToDisk: boolean;
12
24
  hmr: boolean;
13
25
  client: {
14
26
  logLevel: "error";
package/dist/index.js CHANGED
@@ -1,20 +1,20 @@
1
- import { __webpack_require__ } from "./rslib-runtime.js";
2
1
  import { existsSync } from "node:fs";
3
2
  import promises from "node:fs/promises";
4
3
  import { fileURLToPath } from "node:url";
5
4
  import { isDeepStrictEqual } from "node:util";
6
- import { TEMP_RSTEST_OUTPUT_DIR, color, getSetupFiles, getTestEntries, isDebug, loadCoverageProvider, logger, rsbuild, serializableConfig } from "@rstest/core/browser";
5
+ import { color, getSetupFiles, getTestEntries, isDebug, loadCoverageProvider, logger, rsbuild, serializableConfig } from "@rstest/core/browser";
7
6
  import open_editor from "open-editor";
8
7
  import { basename, dirname, join, normalize, relative, resolve as external_pathe_resolve } from "pathe";
9
8
  import sirv from "sirv";
10
9
  import { WebSocketServer } from "ws";
11
10
  import node_os from "node:os";
12
11
  import convert_source_map from "convert-source-map";
12
+ import { __webpack_require__ } from "./rslib-runtime.js";
13
13
  import { DISPATCH_RPC_BRIDGE_NAME, DISPATCH_MESSAGE_TYPE, DISPATCH_NAMESPACE_RUNNER } from "./323.js";
14
14
  __webpack_require__.add({
15
- "../../node_modules/.pnpm/picomatch@4.0.3/node_modules/picomatch/index.js" (module, __unused_rspack_exports, __webpack_require__) {
16
- const pico = __webpack_require__("../../node_modules/.pnpm/picomatch@4.0.3/node_modules/picomatch/lib/picomatch.js");
17
- const utils = __webpack_require__("../../node_modules/.pnpm/picomatch@4.0.3/node_modules/picomatch/lib/utils.js");
15
+ "../../node_modules/.pnpm/picomatch@4.0.4/node_modules/picomatch/index.js" (module, __unused_rspack_exports, __webpack_require__) {
16
+ const pico = __webpack_require__("../../node_modules/.pnpm/picomatch@4.0.4/node_modules/picomatch/lib/picomatch.js");
17
+ const utils = __webpack_require__("../../node_modules/.pnpm/picomatch@4.0.4/node_modules/picomatch/lib/utils.js");
18
18
  function picomatch(glob, options, returnState = false) {
19
19
  if (options && (null === options.windows || void 0 === options.windows)) options = {
20
20
  ...options,
@@ -25,9 +25,10 @@ __webpack_require__.add({
25
25
  Object.assign(picomatch, pico);
26
26
  module.exports = picomatch;
27
27
  },
28
- "../../node_modules/.pnpm/picomatch@4.0.3/node_modules/picomatch/lib/constants.js" (module) {
28
+ "../../node_modules/.pnpm/picomatch@4.0.4/node_modules/picomatch/lib/constants.js" (module) {
29
29
  const WIN_SLASH = '\\\\/';
30
30
  const WIN_NO_SLASH = `[^${WIN_SLASH}]`;
31
+ const DEFAULT_MAX_EXTGLOB_RECURSION = 0;
31
32
  const DOT_LITERAL = '\\.';
32
33
  const PLUS_LITERAL = '\\+';
33
34
  const QMARK_LITERAL = '\\?';
@@ -78,6 +79,7 @@ __webpack_require__.add({
78
79
  SEP: '\\'
79
80
  };
80
81
  const POSIX_REGEX_SOURCE = {
82
+ __proto__: null,
81
83
  alnum: 'a-zA-Z0-9',
82
84
  alpha: 'a-zA-Z',
83
85
  ascii: '\\x00-\\x7F',
@@ -94,6 +96,7 @@ __webpack_require__.add({
94
96
  xdigit: 'A-Fa-f0-9'
95
97
  };
96
98
  module.exports = {
99
+ DEFAULT_MAX_EXTGLOB_RECURSION,
97
100
  MAX_LENGTH: 65536,
98
101
  POSIX_REGEX_SOURCE,
99
102
  REGEX_BACKSLASH: /\\(?![*+?^${}(|)[\]])/g,
@@ -185,9 +188,9 @@ __webpack_require__.add({
185
188
  }
186
189
  };
187
190
  },
188
- "../../node_modules/.pnpm/picomatch@4.0.3/node_modules/picomatch/lib/parse.js" (module, __unused_rspack_exports, __webpack_require__) {
189
- const constants = __webpack_require__("../../node_modules/.pnpm/picomatch@4.0.3/node_modules/picomatch/lib/constants.js");
190
- const utils = __webpack_require__("../../node_modules/.pnpm/picomatch@4.0.3/node_modules/picomatch/lib/utils.js");
191
+ "../../node_modules/.pnpm/picomatch@4.0.4/node_modules/picomatch/lib/parse.js" (module, __unused_rspack_exports, __webpack_require__) {
192
+ const constants = __webpack_require__("../../node_modules/.pnpm/picomatch@4.0.4/node_modules/picomatch/lib/constants.js");
193
+ const utils = __webpack_require__("../../node_modules/.pnpm/picomatch@4.0.4/node_modules/picomatch/lib/utils.js");
191
194
  const { MAX_LENGTH, POSIX_REGEX_SOURCE, REGEX_NON_SPECIAL_CHARS, REGEX_SPECIAL_CHARS_BACKREF, REPLACEMENTS } = constants;
192
195
  const expandRange = (args, options)=>{
193
196
  if ('function' == typeof options.expandRange) return options.expandRange(...args, options);
@@ -201,6 +204,189 @@ __webpack_require__.add({
201
204
  return value;
202
205
  };
203
206
  const syntaxError = (type, char)=>`Missing ${type}: "${char}" - use "\\\\${char}" to match literal characters`;
207
+ const splitTopLevel = (input)=>{
208
+ const parts = [];
209
+ let bracket = 0;
210
+ let paren = 0;
211
+ let quote = 0;
212
+ let value = '';
213
+ let escaped = false;
214
+ for (const ch of input){
215
+ if (true === escaped) {
216
+ value += ch;
217
+ escaped = false;
218
+ continue;
219
+ }
220
+ if ('\\' === ch) {
221
+ value += ch;
222
+ escaped = true;
223
+ continue;
224
+ }
225
+ if ('"' === ch) {
226
+ quote = 1 === quote ? 0 : 1;
227
+ value += ch;
228
+ continue;
229
+ }
230
+ if (0 === quote) {
231
+ if ('[' === ch) bracket++;
232
+ else if (']' === ch && bracket > 0) bracket--;
233
+ else if (0 === bracket) {
234
+ if ('(' === ch) paren++;
235
+ else if (')' === ch && paren > 0) paren--;
236
+ else if ('|' === ch && 0 === paren) {
237
+ parts.push(value);
238
+ value = '';
239
+ continue;
240
+ }
241
+ }
242
+ }
243
+ value += ch;
244
+ }
245
+ parts.push(value);
246
+ return parts;
247
+ };
248
+ const isPlainBranch = (branch)=>{
249
+ let escaped = false;
250
+ for (const ch of branch){
251
+ if (true === escaped) {
252
+ escaped = false;
253
+ continue;
254
+ }
255
+ if ('\\' === ch) {
256
+ escaped = true;
257
+ continue;
258
+ }
259
+ if (/[?*+@!()[\]{}]/.test(ch)) return false;
260
+ }
261
+ return true;
262
+ };
263
+ const normalizeSimpleBranch = (branch)=>{
264
+ let value = branch.trim();
265
+ let changed = true;
266
+ while(true === changed){
267
+ changed = false;
268
+ if (/^@\([^\\()[\]{}|]+\)$/.test(value)) {
269
+ value = value.slice(2, -1);
270
+ changed = true;
271
+ }
272
+ }
273
+ if (!isPlainBranch(value)) return;
274
+ return value.replace(/\\(.)/g, '$1');
275
+ };
276
+ const hasRepeatedCharPrefixOverlap = (branches)=>{
277
+ const values = branches.map(normalizeSimpleBranch).filter(Boolean);
278
+ for(let i = 0; i < values.length; i++)for(let j = i + 1; j < values.length; j++){
279
+ const a = values[i];
280
+ const b = values[j];
281
+ const char = a[0];
282
+ if (char && a === char.repeat(a.length) && b === char.repeat(b.length)) {
283
+ if (a === b || a.startsWith(b) || b.startsWith(a)) return true;
284
+ }
285
+ }
286
+ return false;
287
+ };
288
+ const parseRepeatedExtglob = (pattern, requireEnd = true)=>{
289
+ if ('+' !== pattern[0] && '*' !== pattern[0] || '(' !== pattern[1]) return;
290
+ let bracket = 0;
291
+ let paren = 0;
292
+ let quote = 0;
293
+ let escaped = false;
294
+ for(let i = 1; i < pattern.length; i++){
295
+ const ch = pattern[i];
296
+ if (true === escaped) {
297
+ escaped = false;
298
+ continue;
299
+ }
300
+ if ('\\' === ch) {
301
+ escaped = true;
302
+ continue;
303
+ }
304
+ if ('"' === ch) {
305
+ quote = 1 === quote ? 0 : 1;
306
+ continue;
307
+ }
308
+ if (1 !== quote) {
309
+ if ('[' === ch) {
310
+ bracket++;
311
+ continue;
312
+ }
313
+ if (']' === ch && bracket > 0) {
314
+ bracket--;
315
+ continue;
316
+ }
317
+ if (!(bracket > 0)) {
318
+ if ('(' === ch) {
319
+ paren++;
320
+ continue;
321
+ }
322
+ if (')' === ch) {
323
+ paren--;
324
+ if (0 === paren) {
325
+ if (true === requireEnd && i !== pattern.length - 1) return;
326
+ return {
327
+ type: pattern[0],
328
+ body: pattern.slice(2, i),
329
+ end: i
330
+ };
331
+ }
332
+ }
333
+ }
334
+ }
335
+ }
336
+ };
337
+ const getStarExtglobSequenceOutput = (pattern)=>{
338
+ let index = 0;
339
+ const chars = [];
340
+ while(index < pattern.length){
341
+ const match = parseRepeatedExtglob(pattern.slice(index), false);
342
+ if (!match || '*' !== match.type) return;
343
+ const branches = splitTopLevel(match.body).map((branch)=>branch.trim());
344
+ if (1 !== branches.length) return;
345
+ const branch = normalizeSimpleBranch(branches[0]);
346
+ if (!branch || 1 !== branch.length) return;
347
+ chars.push(branch);
348
+ index += match.end + 1;
349
+ }
350
+ if (chars.length < 1) return;
351
+ const source = 1 === chars.length ? utils.escapeRegex(chars[0]) : `[${chars.map((ch)=>utils.escapeRegex(ch)).join('')}]`;
352
+ return `${source}*`;
353
+ };
354
+ const repeatedExtglobRecursion = (pattern)=>{
355
+ let depth = 0;
356
+ let value = pattern.trim();
357
+ let match = parseRepeatedExtglob(value);
358
+ while(match){
359
+ depth++;
360
+ value = match.body.trim();
361
+ match = parseRepeatedExtglob(value);
362
+ }
363
+ return depth;
364
+ };
365
+ const analyzeRepeatedExtglob = (body, options)=>{
366
+ if (false === options.maxExtglobRecursion) return {
367
+ risky: false
368
+ };
369
+ const max = 'number' == typeof options.maxExtglobRecursion ? options.maxExtglobRecursion : constants.DEFAULT_MAX_EXTGLOB_RECURSION;
370
+ const branches = splitTopLevel(body).map((branch)=>branch.trim());
371
+ if (branches.length > 1) {
372
+ if (branches.some((branch)=>'' === branch) || branches.some((branch)=>/^[*?]+$/.test(branch)) || hasRepeatedCharPrefixOverlap(branches)) return {
373
+ risky: true
374
+ };
375
+ }
376
+ for (const branch of branches){
377
+ const safeOutput = getStarExtglobSequenceOutput(branch);
378
+ if (safeOutput) return {
379
+ risky: true,
380
+ safeOutput
381
+ };
382
+ if (repeatedExtglobRecursion(branch) > max) return {
383
+ risky: true
384
+ };
385
+ }
386
+ return {
387
+ risky: false
388
+ };
389
+ };
204
390
  const parse = (input, options)=>{
205
391
  if ('string' != typeof input) throw new TypeError('Expected a string');
206
392
  input = REPLACEMENTS[input] || input;
@@ -316,6 +502,8 @@ __webpack_require__.add({
316
502
  token.prev = prev;
317
503
  token.parens = state.parens;
318
504
  token.output = state.output;
505
+ token.startIndex = state.index;
506
+ token.tokensIndex = tokens.length;
319
507
  const output = (opts.capture ? '(' : '') + token.open;
320
508
  increment('parens');
321
509
  push({
@@ -332,6 +520,31 @@ __webpack_require__.add({
332
520
  extglobs.push(token);
333
521
  };
334
522
  const extglobClose = (token)=>{
523
+ const literal = input.slice(token.startIndex, state.index + 1);
524
+ const body = input.slice(token.startIndex + 2, state.index);
525
+ const analysis = analyzeRepeatedExtglob(body, opts);
526
+ if (('plus' === token.type || 'star' === token.type) && analysis.risky) {
527
+ const safeOutput = analysis.safeOutput ? (token.output ? '' : ONE_CHAR) + (opts.capture ? `(${analysis.safeOutput})` : analysis.safeOutput) : void 0;
528
+ const open = tokens[token.tokensIndex];
529
+ open.type = 'text';
530
+ open.value = literal;
531
+ open.output = safeOutput || utils.escapeRegex(literal);
532
+ for(let i = token.tokensIndex + 1; i < tokens.length; i++){
533
+ tokens[i].value = '';
534
+ tokens[i].output = '';
535
+ delete tokens[i].suffix;
536
+ }
537
+ state.output = token.output + open.output;
538
+ state.backtrack = true;
539
+ push({
540
+ type: 'paren',
541
+ extglob: true,
542
+ value,
543
+ output: ''
544
+ });
545
+ decrement('parens');
546
+ return;
547
+ }
335
548
  let output = token.close + (opts.capture ? ')' : '');
336
549
  let rest;
337
550
  if ('negate' === token.type) {
@@ -973,11 +1186,11 @@ __webpack_require__.add({
973
1186
  };
974
1187
  module.exports = parse;
975
1188
  },
976
- "../../node_modules/.pnpm/picomatch@4.0.3/node_modules/picomatch/lib/picomatch.js" (module, __unused_rspack_exports, __webpack_require__) {
977
- const scan = __webpack_require__("../../node_modules/.pnpm/picomatch@4.0.3/node_modules/picomatch/lib/scan.js");
978
- const parse = __webpack_require__("../../node_modules/.pnpm/picomatch@4.0.3/node_modules/picomatch/lib/parse.js");
979
- const utils = __webpack_require__("../../node_modules/.pnpm/picomatch@4.0.3/node_modules/picomatch/lib/utils.js");
980
- const constants = __webpack_require__("../../node_modules/.pnpm/picomatch@4.0.3/node_modules/picomatch/lib/constants.js");
1189
+ "../../node_modules/.pnpm/picomatch@4.0.4/node_modules/picomatch/lib/picomatch.js" (module, __unused_rspack_exports, __webpack_require__) {
1190
+ const scan = __webpack_require__("../../node_modules/.pnpm/picomatch@4.0.4/node_modules/picomatch/lib/scan.js");
1191
+ const parse = __webpack_require__("../../node_modules/.pnpm/picomatch@4.0.4/node_modules/picomatch/lib/parse.js");
1192
+ const utils = __webpack_require__("../../node_modules/.pnpm/picomatch@4.0.4/node_modules/picomatch/lib/utils.js");
1193
+ const constants = __webpack_require__("../../node_modules/.pnpm/picomatch@4.0.4/node_modules/picomatch/lib/constants.js");
981
1194
  const isObject = (val)=>val && 'object' == typeof val && !Array.isArray(val);
982
1195
  const picomatch = (glob, options, returnState = false)=>{
983
1196
  if (Array.isArray(glob)) {
@@ -1106,9 +1319,9 @@ __webpack_require__.add({
1106
1319
  picomatch.constants = constants;
1107
1320
  module.exports = picomatch;
1108
1321
  },
1109
- "../../node_modules/.pnpm/picomatch@4.0.3/node_modules/picomatch/lib/scan.js" (module, __unused_rspack_exports, __webpack_require__) {
1110
- const utils = __webpack_require__("../../node_modules/.pnpm/picomatch@4.0.3/node_modules/picomatch/lib/utils.js");
1111
- const { CHAR_ASTERISK, CHAR_AT, CHAR_BACKWARD_SLASH, CHAR_COMMA, CHAR_DOT, CHAR_EXCLAMATION_MARK, CHAR_FORWARD_SLASH, CHAR_LEFT_CURLY_BRACE, CHAR_LEFT_PARENTHESES, CHAR_LEFT_SQUARE_BRACKET, CHAR_PLUS, CHAR_QUESTION_MARK, CHAR_RIGHT_CURLY_BRACE, CHAR_RIGHT_PARENTHESES, CHAR_RIGHT_SQUARE_BRACKET } = __webpack_require__("../../node_modules/.pnpm/picomatch@4.0.3/node_modules/picomatch/lib/constants.js");
1322
+ "../../node_modules/.pnpm/picomatch@4.0.4/node_modules/picomatch/lib/scan.js" (module, __unused_rspack_exports, __webpack_require__) {
1323
+ const utils = __webpack_require__("../../node_modules/.pnpm/picomatch@4.0.4/node_modules/picomatch/lib/utils.js");
1324
+ const { CHAR_ASTERISK, CHAR_AT, CHAR_BACKWARD_SLASH, CHAR_COMMA, CHAR_DOT, CHAR_EXCLAMATION_MARK, CHAR_FORWARD_SLASH, CHAR_LEFT_CURLY_BRACE, CHAR_LEFT_PARENTHESES, CHAR_LEFT_SQUARE_BRACKET, CHAR_PLUS, CHAR_QUESTION_MARK, CHAR_RIGHT_CURLY_BRACE, CHAR_RIGHT_PARENTHESES, CHAR_RIGHT_SQUARE_BRACKET } = __webpack_require__("../../node_modules/.pnpm/picomatch@4.0.4/node_modules/picomatch/lib/constants.js");
1112
1325
  const isPathSeparator = (code)=>code === CHAR_FORWARD_SLASH || code === CHAR_BACKWARD_SLASH;
1113
1326
  const depth = (token)=>{
1114
1327
  if (true !== token.isPrefix) token.depth = token.isGlobstar ? 1 / 0 : 1;
@@ -1374,8 +1587,8 @@ __webpack_require__.add({
1374
1587
  };
1375
1588
  module.exports = scan;
1376
1589
  },
1377
- "../../node_modules/.pnpm/picomatch@4.0.3/node_modules/picomatch/lib/utils.js" (__unused_rspack_module, exports, __webpack_require__) {
1378
- const { REGEX_BACKSLASH, REGEX_REMOVE_BACKSLASH, REGEX_SPECIAL_CHARS, REGEX_SPECIAL_CHARS_GLOBAL } = __webpack_require__("../../node_modules/.pnpm/picomatch@4.0.3/node_modules/picomatch/lib/constants.js");
1590
+ "../../node_modules/.pnpm/picomatch@4.0.4/node_modules/picomatch/lib/utils.js" (__unused_rspack_module, exports, __webpack_require__) {
1591
+ const { REGEX_BACKSLASH, REGEX_REMOVE_BACKSLASH, REGEX_SPECIAL_CHARS, REGEX_SPECIAL_CHARS_GLOBAL } = __webpack_require__("../../node_modules/.pnpm/picomatch@4.0.4/node_modules/picomatch/lib/constants.js");
1379
1592
  exports.isObject = (val)=>null !== val && 'object' == typeof val && !Array.isArray(val);
1380
1593
  exports.hasRegexChars = (str)=>REGEX_SPECIAL_CHARS.test(str);
1381
1594
  exports.isRegexChar = (str)=>1 === str.length && exports.hasRegexChars(str);
@@ -2582,7 +2795,7 @@ const planWatchRerun = ({ projectEntries, previousTestFiles, affectedTestFiles }
2582
2795
  affectedTestFiles: matchedAffectedFiles
2583
2796
  };
2584
2797
  };
2585
- const picomatch = __webpack_require__("../../node_modules/.pnpm/picomatch@4.0.3/node_modules/picomatch/index.js");
2798
+ const picomatch = __webpack_require__("../../node_modules/.pnpm/picomatch@4.0.4/node_modules/picomatch/index.js");
2586
2799
  var picomatch_default = /*#__PURE__*/ __webpack_require__.n(picomatch);
2587
2800
  const { createRsbuild: createRsbuild, rspack: rspack } = rsbuild;
2588
2801
  const hostController_dirname = dirname(fileURLToPath(import.meta.url));
@@ -2738,6 +2951,12 @@ const applyDefaultWatchOptions = (rspackConfig, isWatchMode)=>{
2738
2951
  if (0 === rspackConfig.watchOptions.ignored.length) rspackConfig.watchOptions.ignored.push('**/.git', '**/node_modules');
2739
2952
  rspackConfig.output?.path && rspackConfig.watchOptions.ignored.push(rspackConfig.output.path);
2740
2953
  };
2954
+ const resolveListenPort = (listenPort, httpServer)=>{
2955
+ if (listenPort) return listenPort;
2956
+ const addr = httpServer?.address();
2957
+ if (addr && 'object' == typeof addr) return addr.port;
2958
+ return listenPort;
2959
+ };
2741
2960
  const createBrowserLazyCompilationConfig = (setupFiles)=>{
2742
2961
  const eagerSetupFiles = new Set(setupFiles.map((filePath)=>normalize(filePath)));
2743
2962
  if (0 === eagerSetupFiles.size) return {
@@ -2753,8 +2972,9 @@ const createBrowserLazyCompilationConfig = (setupFiles)=>{
2753
2972
  }
2754
2973
  };
2755
2974
  };
2756
- const createBrowserRsbuildDevConfig = (isWatchMode)=>({
2757
- hmr: isWatchMode,
2975
+ const createBrowserRsbuildDevConfig = (_isWatchMode)=>({
2976
+ writeToDisk: isDebug(),
2977
+ hmr: true,
2758
2978
  client: {
2759
2979
  logLevel: 'error'
2760
2980
  }
@@ -3188,6 +3408,15 @@ const createBrowserRuntime = async ({ context, manifestPath, manifestSource, tem
3188
3408
  const devServer = await rsbuildInstance.createDevServer({
3189
3409
  getPortSilently: true
3190
3410
  });
3411
+ if (isDebug()) await rsbuildInstance.inspectConfig({
3412
+ writeToDisk: true,
3413
+ extraConfigs: {
3414
+ rstest: {
3415
+ ...context.normalizedConfig,
3416
+ projects: browserProjects.map((p)=>p.normalizedConfig)
3417
+ }
3418
+ }
3419
+ });
3191
3420
  const serveContainer = containerDistPath ? sirv(containerDistPath, {
3192
3421
  dev: false,
3193
3422
  single: 'index.html'
@@ -3284,7 +3513,8 @@ const createBrowserRuntime = async ({ context, manifestPath, manifestSource, tem
3284
3513
  }
3285
3514
  next();
3286
3515
  });
3287
- const { port } = await devServer.listen();
3516
+ const { port: listenPort } = await devServer.listen();
3517
+ const port = resolveListenPort(listenPort, devServer.httpServer);
3288
3518
  const wss = new WebSocketServer({
3289
3519
  port: 0
3290
3520
  });
@@ -3316,10 +3546,10 @@ const createBrowserRuntime = async ({ context, manifestPath, manifestSource, tem
3316
3546
  dispatchHandlers,
3317
3547
  wss
3318
3548
  };
3319
- } catch (_error) {
3549
+ } catch (error) {
3320
3550
  wss.close();
3321
3551
  await devServer.close();
3322
- throw _error;
3552
+ throw error;
3323
3553
  }
3324
3554
  };
3325
3555
  async function resolveProjectEntries(context, shardedEntries) {
@@ -3466,7 +3696,8 @@ const runBrowserController = async (context, options)=>{
3466
3696
  await notifyTestRunStart();
3467
3697
  const isWatchMode = 'watch' === context.command;
3468
3698
  const enableCliShortcuts = isWatchMode && isBrowserWatchCliShortcutsEnabled();
3469
- const tempDir = isWatchMode && watchContext.runtime ? watchContext.runtime.tempDir : isWatchMode ? join(context.rootPath, TEMP_RSTEST_OUTPUT_DIR, 'browser', 'watch') : join(context.rootPath, TEMP_RSTEST_OUTPUT_DIR, 'browser', Date.now().toString());
3699
+ const browserTempOutputRoot = context.normalizedConfig.output.distPath.root;
3700
+ const tempDir = isWatchMode && watchContext.runtime ? watchContext.runtime.tempDir : isWatchMode ? join(context.rootPath, browserTempOutputRoot, 'browser', 'watch') : join(context.rootPath, browserTempOutputRoot, 'browser', Date.now().toString());
3470
3701
  const manifestPath = join(tempDir, VIRTUAL_MANIFEST_FILENAME);
3471
3702
  const manifestSource = generateManifestModule({
3472
3703
  manifestPath,
@@ -4285,7 +4516,7 @@ const listBrowserTests = async (context, options)=>{
4285
4516
  list: [],
4286
4517
  close: async ()=>{}
4287
4518
  };
4288
- const tempDir = join(context.rootPath, TEMP_RSTEST_OUTPUT_DIR, 'browser', `list-${Date.now()}`);
4519
+ const tempDir = join(context.rootPath, context.normalizedConfig.output.distPath.root, 'browser', `list-${Date.now()}`);
4289
4520
  const manifestPath = join(tempDir, VIRTUAL_MANIFEST_FILENAME);
4290
4521
  const manifestSource = generateManifestModule({
4291
4522
  manifestPath,
@@ -4448,12 +4679,13 @@ const validateViewport = (viewport)=>{
4448
4679
  };
4449
4680
  const validateBrowserConfig = (context)=>{
4450
4681
  for (const project of context.projects){
4451
- const browser = project.normalizedConfig.browser;
4682
+ const { browser, output } = project.normalizedConfig;
4452
4683
  if (browser.enabled) {
4453
4684
  if (!browser.provider) throw new Error('browser.provider is required when browser.enabled is true.');
4454
4685
  if (!SUPPORTED_PROVIDERS.includes(browser.provider)) throw new Error(`browser.provider must be one of: ${SUPPORTED_PROVIDERS.join(', ')}.`);
4455
4686
  validateViewport(browser.viewport);
4456
4687
  if (!isPlainObject(browser.providerOptions)) throw new Error('browser.providerOptions must be a plain object.');
4688
+ if (output?.bundleDependencies === false) throw new Error('output.bundleDependencies false is not supported in browser mode.');
4457
4689
  }
4458
4690
  }
4459
4691
  };
@@ -1,7 +1,7 @@
1
1
  import type { DevicePreset } from '@rstest/core/browser';
2
2
  import type { RuntimeConfig, TestFileResult, TestInfo, TestResult } from '@rstest/core/browser-runtime';
3
3
  import type { SnapshotUpdateState } from '@vitest/snapshot';
4
- export type { BrowserLocatorIR, BrowserLocatorStep, BrowserLocatorText, BrowserRpcRequest, BrowserRpcResponse, SnapshotRpcRequest, SnapshotRpcResponse, } from './rpcProtocol';
4
+ export type { BrowserLocatorIR, BrowserRpcRequest, SnapshotRpcRequest, } from './rpcProtocol';
5
5
  export { validateBrowserRpcRequest } from './rpcProtocol';
6
6
  export declare const DISPATCH_MESSAGE_TYPE = "__rstest_dispatch__";
7
7
  export declare const DISPATCH_RESPONSE_TYPE = "__rstest_dispatch_response__";
@@ -144,8 +144,4 @@ export type BrowserDispatchResponse = {
144
144
  error?: string;
145
145
  stale?: boolean;
146
146
  };
147
- export type BrowserDispatchResponseEnvelope = {
148
- type: typeof DISPATCH_RESPONSE_TYPE;
149
- payload: BrowserDispatchResponse;
150
- };
151
147
  export type BrowserDispatchHandler = (request: BrowserDispatchRequest) => Promise<unknown>;
@@ -100,11 +100,6 @@ export type BrowserRpcRequest = {
100
100
  timeout?: number;
101
101
  };
102
102
  export declare const validateBrowserRpcRequest: (payload: unknown) => BrowserRpcRequest;
103
- export type BrowserRpcResponse = {
104
- id: string;
105
- result?: unknown;
106
- error?: string;
107
- };
108
103
  /**
109
104
  * Snapshot RPC request from runner iframe.
110
105
  * The container will forward these to the host via WebSocket RPC.
@@ -135,11 +130,3 @@ export type SnapshotRpcRequest = {
135
130
  filepath: string;
136
131
  };
137
132
  };
138
- /**
139
- * Snapshot RPC response from container to runner iframe.
140
- */
141
- export type SnapshotRpcResponse = {
142
- id: string;
143
- result?: unknown;
144
- error?: string;
145
- };