@rstest/core 0.9.2 → 0.9.3

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.
package/LICENSE.md CHANGED
@@ -1183,7 +1183,7 @@ Licensed under MIT license in the repository at https://github.com/facebook/reac
1183
1183
 
1184
1184
  ### readdirp
1185
1185
 
1186
- Licensed under MIT license in the repository at git://github.com/paulmillr/readdirp.git.
1186
+ Licensed under MIT license in the repository at https://github.com/paulmillr/readdirp.git.
1187
1187
 
1188
1188
  > MIT License
1189
1189
  >
package/dist/0~8843.js CHANGED
@@ -9,7 +9,7 @@ import node_path from "node:path";
9
9
  import { isBuiltin } from "node:module";
10
10
  import node_inspector from "node:inspector";
11
11
  import node_fs from "node:fs";
12
- import { basename, bgColor, isDeno, dirname, castArray, resolve as pathe_M_eThtNZ_resolve, isDebug, color, getForceColorEnv, ADDITIONAL_NODE_BUILTINS, needFlagExperimentalDetectModule, join } from "./6830.js";
12
+ import { basename, bgColor, isDeno, dirname, castArray, resolve as pathe_M_eThtNZ_resolve, isDebug, color as logger_color, getForceColorEnv, ADDITIONAL_NODE_BUILTINS, needFlagExperimentalDetectModule, join } from "./6830.js";
13
13
  import { parseWorkerMetaMessage, createBirpc } from "./1983.js";
14
14
  import { TEMP_RSTEST_OUTPUT_DIR, TEMP_RSTEST_OUTPUT_DIR_GLOB } from "./4411.js";
15
15
  import { posix } from "./7011.js";
@@ -454,8 +454,8 @@ const createPool = async ({ context, recommendWorkerCount = 1 / 0 })=>{
454
454
  const runningModule = context.stateManager.runningModules.get(entryInfo.testPath);
455
455
  if (runningModule?.runningTests.length) {
456
456
  const getCaseName = (test)=>`"${test.name}"${test.parentNames?.length ? ` (Under suite: ${test.parentNames?.join(' > ')})` : ''}`;
457
- if (runningModule?.runningTests.length === 1) err.message += `\n\n${color.white(`Maybe relevant test case: ${getCaseName(runningModule.runningTests[0])} which is running when the error occurs.`)}`;
458
- else err.message += `\n\n${color.white(`The below test cases may be relevant, as they were running when the error occurred:\n - ${runningModule.runningTests.map((t)=>getCaseName(t)).join('\n - ')}`)}`;
457
+ if (runningModule?.runningTests.length === 1) err.message += `\n\n${logger_color.white(`Maybe relevant test case: ${getCaseName(runningModule.runningTests[0])} which is running when the error occurs.`)}`;
458
+ else err.message += `\n\n${logger_color.white(`The below test cases may be relevant, as they were running when the error occurred:\n - ${runningModule.runningTests.map((t)=>getCaseName(t)).join('\n - ')}`)}`;
459
459
  }
460
460
  return {
461
461
  testId: '0',
@@ -598,8 +598,8 @@ async function runGlobalTeardown() {
598
598
  await teardown();
599
599
  } catch (error) {
600
600
  console.error(bgColor('bgRed', 'Error during global teardown'));
601
- if (error instanceof Error) error.stack ? console.error(color.red(error.stack)) : console.error(color.red(error.message));
602
- else console.error(color.red(String(error)));
601
+ if (error instanceof Error) error.stack ? console.error(logger_color.red(error.stack)) : console.error(logger_color.red(error.message));
602
+ else console.error(logger_color.red(String(error)));
603
603
  process.exitCode = 1;
604
604
  }
605
605
  }
@@ -2,9 +2,9 @@ import "node:module";
2
2
  import { createRequire } from "node:module";
3
3
  import { pathToFileURL } from "node:url";
4
4
  import "./4411.js";
5
- import { logger as logger_logger, color } from "./6830.js";
5
+ import { logger as logger_logger, color as logger_color } from "./6830.js";
6
6
  async function loadBrowserModule(options = {}) {
7
- const coreVersion = "0.9.2";
7
+ const coreVersion = "0.9.3";
8
8
  const { projectRoots = [] } = options;
9
9
  let browserModule;
10
10
  let browserVersion;
@@ -24,9 +24,9 @@ async function loadBrowserModule(options = {}) {
24
24
  const browserPkg = userRequire(browserPkgPath);
25
25
  browserVersion = browserPkg.version;
26
26
  if (browserVersion !== coreVersion) {
27
- logger_logger.error(`\n${color.red('Error:')} Version mismatch between ${color.cyan('@rstest/core')} and ${color.cyan('@rstest/browser')}.\n`);
28
- logger_logger.error(` @rstest/core version: ${color.yellow(coreVersion)}\n @rstest/browser version: ${color.yellow(browserVersion)}\n`);
29
- logger_logger.error(`Please ensure both packages have the same version:\n\n ${color.cyan(`npm install @rstest/browser@${coreVersion}`)}\n`);
27
+ logger_logger.error(`\n${logger_color.red('Error:')} Version mismatch between ${logger_color.cyan('@rstest/core')} and ${logger_color.cyan('@rstest/browser')}.\n`);
28
+ logger_logger.error(` @rstest/core version: ${logger_color.yellow(coreVersion)}\n @rstest/browser version: ${logger_color.yellow(browserVersion)}\n`);
29
+ logger_logger.error(`Please ensure both packages have the same version:\n\n ${logger_color.cyan(`npm install @rstest/browser@${coreVersion}`)}\n`);
30
30
  process.exit(1);
31
31
  }
32
32
  return browserModule;
@@ -35,9 +35,9 @@ async function loadBrowserModule(options = {}) {
35
35
  if ('ERR_MODULE_NOT_FOUND' === err.code || 'MODULE_NOT_FOUND' === err.code) continue;
36
36
  throw error;
37
37
  }
38
- logger_logger.error(`\n${color.red('Error:')} Browser mode requires ${color.cyan('@rstest/browser')} to be installed.\n`);
39
- logger_logger.error(`Please install it with:\n\n ${color.cyan(`npm install @rstest/browser@${coreVersion}`)}\n`);
40
- logger_logger.error(`Or if using pnpm:\n\n ${color.cyan(`pnpm add @rstest/browser@${coreVersion}`)}\n`);
38
+ logger_logger.error(`\n${logger_color.red('Error:')} Browser mode requires ${logger_color.cyan('@rstest/browser')} to be installed.\n`);
39
+ logger_logger.error(`Please install it with:\n\n ${logger_color.cyan(`npm install @rstest/browser@${coreVersion}`)}\n`);
40
+ logger_logger.error(`Or if using pnpm:\n\n ${logger_color.cyan(`pnpm add @rstest/browser@${coreVersion}`)}\n`);
41
41
  process.exit(1);
42
42
  }
43
43
  export { loadBrowserModule };
@@ -4,7 +4,7 @@ import node_fs from "node:fs";
4
4
  import { detect, resolveCommand } from "./3145.js";
5
5
  import { confirm as Rt, intro as dist_Wt, log as R, note as dist_Vt, outro as Gt, cancel as Nt, isCancel as Ct, spinner as be, select as Jt } from "./0~dist.js";
6
6
  import "./4411.js";
7
- import { determineAgent, color } from "./6830.js";
7
+ import { determineAgent, color as logger_color } from "./6830.js";
8
8
  function getUniqueBaseName(dir, baseName, ext) {
9
9
  const fullPath = node_path.join(dir, `${baseName}${ext}`);
10
10
  if (!node_fs.existsSync(fullPath)) return baseName;
@@ -323,14 +323,14 @@ async function createNonInteractive(cwd, projectInfo) {
323
323
  const { agent, testDir, framework, reactVersion } = projectInfo;
324
324
  const provider = 'playwright';
325
325
  console.log();
326
- console.log(color.cyan('◆'), color.bold('rstest init browser --yes'));
326
+ console.log(logger_color.cyan('◆'), logger_color.bold('rstest init browser --yes'));
327
327
  console.log();
328
328
  console.log(' Detecting project...');
329
- if ('react' === framework && reactVersion) console.log(color.green(' ✓'), `Found React ${reactVersion}`);
330
- else if ('react' === framework) console.log(color.green(' ✓'), 'Found React');
331
- else console.log(color.yellow(' ⚠'), 'Framework not detected, generating vanilla DOM example');
332
- console.log(color.green(' ✓'), 'Using playwright as browser provider');
333
- console.log(color.green(' ✓'), `Test directory: ${testDir}/`);
329
+ if ('react' === framework && reactVersion) console.log(logger_color.green(' ✓'), `Found React ${reactVersion}`);
330
+ else if ('react' === framework) console.log(logger_color.green(' ✓'), 'Found React');
331
+ else console.log(logger_color.yellow(' ⚠'), 'Framework not detected, generating vanilla DOM example');
332
+ console.log(logger_color.green(' ✓'), 'Using playwright as browser provider');
333
+ console.log(logger_color.green(' ✓'), `Test directory: ${testDir}/`);
334
334
  console.log();
335
335
  const createdFiles = await generateFiles(cwd, projectInfo, provider);
336
336
  console.log(' Created files:');
@@ -342,20 +342,20 @@ async function createNonInteractive(cwd, projectInfo) {
342
342
  console.log(` ${getPlaywrightInstallCommand(agent, provider)}`);
343
343
  console.log(` ${getRunCommand(agent)}`);
344
344
  console.log();
345
- console.log(color.green('└'), 'Done!');
345
+ console.log(logger_color.green('└'), 'Done!');
346
346
  }
347
347
  async function createInteractive(cwd, projectInfo, isAgent) {
348
348
  const { agent, language, testDir, framework, reactVersion } = projectInfo;
349
349
  const effectiveFramework = 'react' === framework ? 'react' : 'vanilla';
350
- dist_Wt(color.bgCyan(color.black(' rstest init browser ')));
350
+ dist_Wt(logger_color.bgCyan(logger_color.black(' rstest init browser ')));
351
351
  const detectionLines = [];
352
- if ('react' === framework && reactVersion) detectionLines.push(`${color.green('✓')} Found React ${reactVersion}`);
353
- else if ('react' === framework) detectionLines.push(`${color.green('✓')} Found React`);
354
- else detectionLines.push(`${color.yellow('⚠')} Framework not detected, will generate vanilla DOM example`);
355
- detectionLines.push(`${color.green('✓')} Found ${'ts' === language ? 'TypeScript' : 'JavaScript'}`);
356
- detectionLines.push(`${color.green('✓')} Test directory: ${testDir}/`);
352
+ if ('react' === framework && reactVersion) detectionLines.push(`${logger_color.green('✓')} Found React ${reactVersion}`);
353
+ else if ('react' === framework) detectionLines.push(`${logger_color.green('✓')} Found React`);
354
+ else detectionLines.push(`${logger_color.yellow('⚠')} Framework not detected, will generate vanilla DOM example`);
355
+ detectionLines.push(`${logger_color.green('✓')} Found ${'ts' === language ? 'TypeScript' : 'JavaScript'}`);
356
+ detectionLines.push(`${logger_color.green('✓')} Test directory: ${testDir}/`);
357
357
  dist_Vt(detectionLines.join('\n'), 'Detecting project...');
358
- if (isAgent) R.info(`AI Agent detected. For non-interactive mode, run:\n ${color.cyan('npx rstest init browser --yes')}`);
358
+ if (isAgent) R.info(`AI Agent detected. For non-interactive mode, run:\n ${logger_color.cyan('npx rstest init browser --yes')}`);
359
359
  const providerSelection = await Jt({
360
360
  message: 'Choose a browser provider (so far, only Playwright)',
361
361
  options: [
@@ -372,15 +372,15 @@ async function createInteractive(cwd, projectInfo, isAgent) {
372
372
  }
373
373
  const provider = providerSelection;
374
374
  const preview = computeFilePreview(cwd, projectInfo);
375
- const deps = getDependenciesWithVersions(effectiveFramework, provider, "0.9.2");
375
+ const deps = getDependenciesWithVersions(effectiveFramework, provider, "0.9.3");
376
376
  const depsList = Object.entries(deps).map(([name, version])=>`${name}@${version}`).join(', ');
377
377
  const previewLines = [
378
- `${color.cyan('+')} Create ${preview.configFile}`,
379
- `${color.cyan('+')} Create ${preview.componentFile}`,
380
- `${color.cyan('+')} Create ${preview.testFile}`,
381
- `${color.yellow('~')} Modify package.json`,
378
+ `${logger_color.cyan('+')} Create ${preview.configFile}`,
379
+ `${logger_color.cyan('+')} Create ${preview.componentFile}`,
380
+ `${logger_color.cyan('+')} Create ${preview.testFile}`,
381
+ `${logger_color.yellow('~')} Modify package.json`,
382
382
  ' - Add "test:browser" script',
383
- ` - Add devDependencies: ${color.dim(depsList)}`
383
+ ` - Add devDependencies: ${logger_color.dim(depsList)}`
384
384
  ];
385
385
  dist_Vt(previewLines.join('\n'), 'Changes to be made');
386
386
  const confirmed = await Rt({
@@ -395,21 +395,21 @@ async function createInteractive(cwd, projectInfo, isAgent) {
395
395
  s.start('Creating files...');
396
396
  const createdFiles = await generateFiles(cwd, projectInfo, provider);
397
397
  s.stop('Created files');
398
- const fileLines = createdFiles.map((f)=>`${color.green('✓')} Created ${f}`);
399
- fileLines.push(`${color.green('✓')} Updated package.json`);
398
+ const fileLines = createdFiles.map((f)=>`${logger_color.green('✓')} Created ${f}`);
399
+ fileLines.push(`${logger_color.green('✓')} Updated package.json`);
400
400
  dist_Vt(fileLines.join('\n'), 'Files');
401
401
  const nextStepsLines = [
402
- `${color.bold('1.')} Install dependencies:`,
403
- ` ${color.cyan(getInstallCommand(agent))}`,
402
+ `${logger_color.bold('1.')} Install dependencies:`,
403
+ ` ${logger_color.cyan(getInstallCommand(agent))}`,
404
404
  '',
405
- `${color.bold('2.')} Install Playwright browsers:`,
406
- ` ${color.cyan(getPlaywrightInstallCommand(agent, provider))}`,
405
+ `${logger_color.bold('2.')} Install Playwright browsers:`,
406
+ ` ${logger_color.cyan(getPlaywrightInstallCommand(agent, provider))}`,
407
407
  '',
408
- `${color.bold('3.')} Run your tests:`,
409
- ` ${color.cyan(getRunCommand(agent))}`
408
+ `${logger_color.bold('3.')} Run your tests:`,
409
+ ` ${logger_color.cyan(getRunCommand(agent))}`
410
410
  ];
411
411
  dist_Vt(nextStepsLines.join('\n'), 'Next steps');
412
- Gt(color.green('Done! Happy testing with Rstest!'));
412
+ Gt(logger_color.green('Done! Happy testing with Rstest!'));
413
413
  }
414
414
  async function generateFiles(cwd, projectInfo, provider) {
415
415
  const { language, testDir, framework } = projectInfo;
@@ -450,7 +450,7 @@ async function generateFiles(cwd, projectInfo, provider) {
450
450
  updatePackageJsonScripts(cwd, {
451
451
  'test:browser': 'rstest --config=rstest.browser.config.ts'
452
452
  });
453
- const deps = getDependenciesWithVersions(effectiveFramework, provider, "0.9.2");
453
+ const deps = getDependenciesWithVersions(effectiveFramework, provider, "0.9.3");
454
454
  updatePackageJsonDevDeps(cwd, deps);
455
455
  return createdFiles;
456
456
  }
@@ -1,7 +1,7 @@
1
1
  import "node:module";
2
2
  import { __webpack_require__ } from "./rslib-runtime.js";
3
3
  import "./4411.js";
4
- import { relative, color } from "./6830.js";
4
+ import { relative, color as logger_color } from "./6830.js";
5
5
  const picomatch = __webpack_require__("../../node_modules/.pnpm/picomatch@4.0.3/node_modules/picomatch/index.js");
6
6
  var picomatch_default = /*#__PURE__*/ __webpack_require__.n(picomatch);
7
7
  const THRESHOLD_KEYS = [
@@ -34,7 +34,7 @@ function checkThresholds({ coverageMap, thresholds, coverageProvider, rootPath }
34
34
  const matcher = picomatch_default()(key);
35
35
  const matchedFiles = allFiles.filter((file)=>matcher(relative(rootPath, file)));
36
36
  if (!matchedFiles.length) {
37
- failedThresholds.push(`${color.red('Error')}: coverage data for "${key}" was not found`);
37
+ failedThresholds.push(`${logger_color.red('Error')}: coverage data for "${key}" was not found`);
38
38
  continue;
39
39
  }
40
40
  for (const file of matchedFiles){
@@ -52,10 +52,10 @@ function checkThresholds({ coverageMap, thresholds, coverageProvider, rootPath }
52
52
  if (void 0 !== expected) {
53
53
  if (expected < 0) {
54
54
  const uncovered = actual.total - actual.covered;
55
- if (uncovered > -expected) errorMsg += `uncovered ${name} ${color.red(`${uncovered}`)} exceeds maximum ${'global' === type ? 'global' : `"${type}"`} threshold allowed ${color.yellow(`${-expected}`)}`;
56
- } else if (actual.pct < expected) errorMsg += `coverage for ${name} ${color.red(`${actual.pct}%`)} does not meet ${'global' === type ? 'global' : `"${type}"`} threshold ${color.yellow(`${expected}%`)}`;
55
+ if (uncovered > -expected) errorMsg += `uncovered ${name} ${logger_color.red(`${uncovered}`)} exceeds maximum ${'global' === type ? 'global' : `"${type}"`} threshold allowed ${logger_color.yellow(`${-expected}`)}`;
56
+ } else if (actual.pct < expected) errorMsg += `coverage for ${name} ${logger_color.red(`${actual.pct}%`)} does not meet ${'global' === type ? 'global' : `"${type}"`} threshold ${logger_color.yellow(`${expected}%`)}`;
57
57
  }
58
- if (errorMsg) failedThresholds.push(`${color.red('Error')}: ${file ? `${relative(rootPath, file)} ` : ''}${errorMsg}`);
58
+ if (errorMsg) failedThresholds.push(`${logger_color.red('Error')}: ${file ? `${relative(rootPath, file)} ` : ''}${errorMsg}`);
59
59
  };
60
60
  thresholdGroup.forEach(({ name, coverageMap, ...thresholds })=>{
61
61
  const summaries = thresholds.perFile ? coverageMap.files().map((file)=>({
@@ -1,10 +1,9 @@
1
- /*! LICENSE: 0~esm.js.LICENSE.txt */
1
+ /*! LICENSE: 0~chokidar.js.LICENSE.txt */
2
2
  import "node:module";
3
+ import { EventEmitter } from "node:events";
3
4
  import { stat as external_node_fs_stat, unwatchFile, watch, watchFile } from "node:fs";
4
- import { lstat as promises_lstat, open as promises_open, readdir, realpath as external_fs_promises_realpath, stat as promises_stat } from "fs/promises";
5
- import { EventEmitter } from "events";
5
+ import { lstat, open as promises_open, readdir, realpath as promises_realpath, stat as promises_stat } from "node:fs/promises";
6
6
  import { basename as external_node_path_basename, dirname as external_node_path_dirname, extname, isAbsolute, join, normalize, relative as external_node_path_relative, resolve as external_node_path_resolve, sep } from "node:path";
7
- import { lstat, readdir as promises_readdir, realpath as promises_realpath, stat as external_node_fs_promises_stat } from "node:fs/promises";
8
7
  import { Readable } from "node:stream";
9
8
  import { type as external_node_os_type } from "node:os";
10
9
  const EntryTypes = {
@@ -65,6 +64,20 @@ const normalizeFilter = (filter)=>{
65
64
  return emptyFn;
66
65
  };
67
66
  class ReaddirpStream extends Readable {
67
+ parents;
68
+ reading;
69
+ parent;
70
+ _stat;
71
+ _maxDepth;
72
+ _wantsDir;
73
+ _wantsFile;
74
+ _wantsEverything;
75
+ _root;
76
+ _isDirent;
77
+ _statsProp;
78
+ _rdOptions;
79
+ _fileFilter;
80
+ _directoryFilter;
68
81
  constructor(options = {}){
69
82
  super({
70
83
  objectMode: true,
@@ -78,12 +91,12 @@ class ReaddirpStream extends Readable {
78
91
  const { root, type } = opts;
79
92
  this._fileFilter = normalizeFilter(opts.fileFilter);
80
93
  this._directoryFilter = normalizeFilter(opts.directoryFilter);
81
- const statMethod = opts.lstat ? lstat : external_node_fs_promises_stat;
94
+ const statMethod = opts.lstat ? lstat : promises_stat;
82
95
  if (wantBigintFsStats) this._stat = (path)=>statMethod(path, {
83
96
  bigint: true
84
97
  });
85
98
  else this._stat = statMethod;
86
- this._maxDepth = opts.depth ?? defaultOptions.depth;
99
+ this._maxDepth = null != opts.depth && Number.isSafeInteger(opts.depth) ? opts.depth : defaultOptions.depth;
87
100
  this._wantsDir = type ? DIR_TYPES.has(type) : false;
88
101
  this._wantsFile = type ? FILE_TYPES.has(type) : false;
89
102
  this._wantsEverything = type === EntryTypes.EVERYTHING_TYPE;
@@ -147,7 +160,7 @@ class ReaddirpStream extends Readable {
147
160
  async _exploreDir(path, depth) {
148
161
  let files;
149
162
  try {
150
- files = await promises_readdir(path, this._rdOptions);
163
+ files = await readdir(path, this._rdOptions);
151
164
  } catch (error) {
152
165
  this._onError(error);
153
166
  }
@@ -244,7 +257,7 @@ const EVENTS = {
244
257
  const EV = EVENTS;
245
258
  const THROTTLE_MODE_WATCH = 'watch';
246
259
  const statMethods = {
247
- lstat: promises_lstat,
260
+ lstat: lstat,
248
261
  stat: promises_stat
249
262
  };
250
263
  const KEY_LISTENERS = 'listeners';
@@ -655,6 +668,8 @@ const setFsWatchFileListener = (path, fullPath, options, handlers)=>{
655
668
  };
656
669
  };
657
670
  class NodeFsHandler {
671
+ fsw;
672
+ _boundHandleError;
658
673
  constructor(fsW){
659
674
  this.fsw = fsW;
660
675
  this._boundHandleError = (error)=>fsW._handleError(error);
@@ -732,7 +747,7 @@ class NodeFsHandler {
732
747
  this.fsw._incrReadyCount();
733
748
  let linkPath;
734
749
  try {
735
- linkPath = await external_fs_promises_realpath(path);
750
+ linkPath = await promises_realpath(path);
736
751
  } catch (e) {
737
752
  this.fsw._emitReady();
738
753
  return true;
@@ -756,7 +771,8 @@ class NodeFsHandler {
756
771
  }
757
772
  _handleRead(directory, initialAdd, wh, target, dir, depth, throttler) {
758
773
  directory = join(directory, '');
759
- throttler = this.fsw._throttle('readdir', directory, 1000);
774
+ const throttleKey = target ? `${directory}:${target}` : directory;
775
+ throttler = this.fsw._throttle('readdir', throttleKey, 1000);
760
776
  if (!throttler) return;
761
777
  const previous = this.fsw._getWatchedDir(wh.path);
762
778
  const current = new Set();
@@ -844,13 +860,13 @@ class NodeFsHandler {
844
860
  let closer;
845
861
  if (stats.isDirectory()) {
846
862
  const absPath = external_node_path_resolve(path);
847
- const targetPath = follow ? await external_fs_promises_realpath(path) : path;
863
+ const targetPath = follow ? await promises_realpath(path) : path;
848
864
  if (this.fsw.closed) return;
849
865
  closer = await this._handleDir(wh.watchPath, stats, initialAdd, depth, target, wh, targetPath);
850
866
  if (this.fsw.closed) return;
851
867
  if (absPath !== targetPath && void 0 !== targetPath) this.fsw._symlinkPaths.set(absPath, targetPath);
852
868
  } else if (stats.isSymbolicLink()) {
853
- const targetPath = follow ? await external_fs_promises_realpath(path) : path;
869
+ const targetPath = follow ? await promises_realpath(path) : path;
854
870
  if (this.fsw.closed) return;
855
871
  const parent = external_node_path_dirname(wh.watchPath);
856
872
  this.fsw._getWatchedDir(parent).add(wh.watchPath);
@@ -876,7 +892,7 @@ const ONE_DOT = '.';
876
892
  const TWO_DOTS = '..';
877
893
  const STRING_TYPE = 'string';
878
894
  const BACK_SLASH_RE = /\\/g;
879
- const esm_DOUBLE_SLASH_RE = /\/\//;
895
+ const DOUBLE_SLASH_RE = /\/\//g;
880
896
  const DOT_RE = /\..*\.(sw[px])$|~$|\.subl.*\.tmp/;
881
897
  const REPLACER_RE = /^\.[/\\]/;
882
898
  function arrify(item) {
@@ -906,8 +922,7 @@ function normalizePath(path) {
906
922
  path = path.replace(/\\/g, '/');
907
923
  let prepend = false;
908
924
  if (path.startsWith('//')) prepend = true;
909
- const DOUBLE_SLASH_RE = /\/\//;
910
- while(path.match(DOUBLE_SLASH_RE))path = path.replace(DOUBLE_SLASH_RE, '/');
925
+ path = path.replace(DOUBLE_SLASH_RE, '/');
911
926
  if (prepend) path = '/' + path;
912
927
  return path;
913
928
  }
@@ -935,7 +950,7 @@ const toUnix = (string)=>{
935
950
  let str = string.replace(BACK_SLASH_RE, SLASH);
936
951
  let prepend = false;
937
952
  if (str.startsWith(SLASH_SLASH)) prepend = true;
938
- while(str.match(esm_DOUBLE_SLASH_RE))str = str.replace(esm_DOUBLE_SLASH_RE, SLASH);
953
+ str = str.replace(DOUBLE_SLASH_RE, SLASH);
939
954
  if (prepend) str = SLASH + str;
940
955
  return str;
941
956
  };
@@ -950,6 +965,9 @@ const getAbsolutePath = (path, cwd)=>{
950
965
  };
951
966
  const EMPTY_SET = Object.freeze(new Set());
952
967
  class DirEntry {
968
+ path;
969
+ _removeWatcher;
970
+ items;
953
971
  constructor(dir, removeWatcher){
954
972
  this.path = dir;
955
973
  this._removeWatcher = removeWatcher;
@@ -995,6 +1013,13 @@ class DirEntry {
995
1013
  const STAT_METHOD_F = 'stat';
996
1014
  const STAT_METHOD_L = 'lstat';
997
1015
  class WatchHelper {
1016
+ fsw;
1017
+ path;
1018
+ watchPath;
1019
+ fullWatchPath;
1020
+ dirParts;
1021
+ followSymlinks;
1022
+ statMethod;
998
1023
  constructor(path, follow, fsw){
999
1024
  this.fsw = fsw;
1000
1025
  const watchPath = path;
@@ -1022,6 +1047,24 @@ class WatchHelper {
1022
1047
  }
1023
1048
  }
1024
1049
  class FSWatcher extends EventEmitter {
1050
+ closed;
1051
+ options;
1052
+ _closers;
1053
+ _ignoredPaths;
1054
+ _throttled;
1055
+ _streams;
1056
+ _symlinkPaths;
1057
+ _watched;
1058
+ _pendingWrites;
1059
+ _pendingUnlinks;
1060
+ _readyCount;
1061
+ _emitReady;
1062
+ _closePromise;
1063
+ _userIgnored;
1064
+ _readyEmitted;
1065
+ _emitRaw;
1066
+ _boundRemove;
1067
+ _nodeFsHandler;
1025
1068
  constructor(_opts = {}){
1026
1069
  super();
1027
1070
  this.closed = false;
@@ -1413,9 +1456,9 @@ class FSWatcher extends EventEmitter {
1413
1456
  return stream;
1414
1457
  }
1415
1458
  }
1416
- function esm_watch(paths, options = {}) {
1459
+ function chokidar_watch(paths, options = {}) {
1417
1460
  const watcher = new FSWatcher(options);
1418
1461
  watcher.add(paths);
1419
1462
  return watcher;
1420
1463
  }
1421
- export { esm_watch as watch };
1464
+ export { chokidar_watch as watch };
package/dist/0~console.js CHANGED
@@ -2,7 +2,7 @@ import "node:module";
2
2
  import { AssertionError, strict } from "node:assert";
3
3
  import { Console } from "node:console";
4
4
  import { format, formatWithOptions, inspect } from "node:util";
5
- import { prettyTime, color } from "./6830.js";
5
+ import { prettyTime, color as logger_color } from "./6830.js";
6
6
  const RealDate = Date;
7
7
  function createCustomConsole({ rpc, testPath, printConsoleTrace }) {
8
8
  const getConsoleTrace = ()=>{
@@ -21,13 +21,13 @@ function createCustomConsole({ rpc, testPath, printConsoleTrace }) {
21
21
  getPrettyName(type) {
22
22
  switch(type){
23
23
  case 'error':
24
- return color.red(type);
24
+ return logger_color.red(type);
25
25
  case 'warn':
26
- return color.yellow(type);
26
+ return logger_color.yellow(type);
27
27
  case 'info':
28
- return color.cyan(type);
28
+ return logger_color.cyan(type);
29
29
  default:
30
- return color.gray(type);
30
+ return logger_color.gray(type);
31
31
  }
32
32
  }
33
33
  _log(name, message, type = 'stdout') {
@@ -69,11 +69,11 @@ function createCustomConsole({ rpc, testPath, printConsoleTrace }) {
69
69
  }
70
70
  group(title, ...args) {
71
71
  this._groupDepth++;
72
- if (null != title || args.length > 0) this._log('group', color.bold(format(title, ...args)));
72
+ if (null != title || args.length > 0) this._log('group', logger_color.bold(format(title, ...args)));
73
73
  }
74
74
  groupCollapsed(title, ...args) {
75
75
  this._groupDepth++;
76
- if (null != title || args.length > 0) this._log('groupCollapsed', color.bold(format(title, ...args)));
76
+ if (null != title || args.length > 0) this._log('groupCollapsed', logger_color.bold(format(title, ...args)));
77
77
  }
78
78
  groupEnd() {
79
79
  if (this._groupDepth > 0) this._groupDepth--;
@@ -22,6 +22,10 @@ async function generateCoverage(context, results, coverageProvider) {
22
22
  try {
23
23
  const finalCoverageMap = coverageProvider.createCoverageMap();
24
24
  for (const result of results)if (result.coverage) finalCoverageMap.merge(result.coverage);
25
+ if (!coverage.allowExternal) finalCoverageMap.filter((filePath)=>{
26
+ const normalizedFile = normalize(filePath);
27
+ return normalizedFile.startsWith(normalize(rootPath));
28
+ });
25
29
  if (coverage.include?.length) {
26
30
  const coveredFiles = finalCoverageMap.files().map(normalize);
27
31
  let isTimeout = false;
@@ -3,7 +3,7 @@ import { mkdirSync, writeFileSync } from "node:fs";
3
3
  import { dirname, isAbsolute, join, relative } from "node:path";
4
4
  import { prepareRsbuild, createPool, createRsbuildServer, runGlobalTeardown, runGlobalSetup } from "./0~8843.js";
5
5
  import { getTestEntries, resolveShardedEntries, prettyTestPath, ROOT_SUITE_NAME } from "./4411.js";
6
- import { logger as logger_logger, getTaskNameWithPrefix, color, bgColor } from "./6830.js";
6
+ import { logger as logger_logger, getTaskNameWithPrefix, color as logger_color, bgColor } from "./6830.js";
7
7
  const collectNodeTests = async ({ context, nodeProjects, globTestSourceEntries })=>{
8
8
  const { getSetupFiles } = await import("./255.js");
9
9
  if (0 === nodeProjects.length) return {
@@ -262,7 +262,7 @@ async function listTests(context, { filesOnly, json, printLocation, includeSuite
262
262
  } else for (const test of tests){
263
263
  let shortPath = relative(rootPath, test.file);
264
264
  if (test.location && printLocation) shortPath = `${shortPath}:${test.location.line}:${test.location.column}`;
265
- logger_logger.log(test.name ? `${color.dim(`${shortPath} > `)}${test.name}` : prettyTestPath(shortPath));
265
+ logger_logger.log(test.name ? `${logger_color.dim(`${shortPath} > `)}${test.name}` : prettyTestPath(shortPath));
266
266
  }
267
267
  await close();
268
268
  return list;
@@ -0,0 +1,127 @@
1
+ import "node:module";
2
+ import { existsSync, readFileSync, readdirSync, rmSync } from "node:fs";
3
+ import { createCoverageProvider } from "./7704.js";
4
+ import "./4411.js";
5
+ import { prettyTime, logger as logger_logger, relative, color as logger_color, join } from "./6830.js";
6
+ const DEFAULT_BLOB_DIR = '.rstest-reports';
7
+ function loadBlobFiles(blobDir) {
8
+ if (!existsSync(blobDir)) throw new Error(`Blob reports directory not found: ${logger_color.cyan(blobDir)}\nRun tests with --reporter=blob first to generate shard reports.`);
9
+ const files = readdirSync(blobDir).filter((f)=>/^blob(-\d+-\d+)?\.json$/.test(f)).sort();
10
+ if (0 === files.length) throw new Error(`No blob report files found in: ${logger_color.cyan(blobDir)}\nRun tests with --reporter=blob first to generate shard reports.`);
11
+ return files.map((file)=>{
12
+ const content = readFileSync(join(blobDir, file), 'utf-8');
13
+ return JSON.parse(content);
14
+ });
15
+ }
16
+ function mergeSnapshots(summaries) {
17
+ const merged = {
18
+ added: 0,
19
+ didUpdate: false,
20
+ failure: false,
21
+ filesAdded: 0,
22
+ filesRemoved: 0,
23
+ filesRemovedList: [],
24
+ filesUnmatched: 0,
25
+ filesUpdated: 0,
26
+ matched: 0,
27
+ total: 0,
28
+ unchecked: 0,
29
+ uncheckedKeysByFile: [],
30
+ unmatched: 0,
31
+ updated: 0
32
+ };
33
+ for (const s of summaries){
34
+ merged.added += s.added;
35
+ merged.filesAdded += s.filesAdded;
36
+ merged.filesRemoved += s.filesRemoved;
37
+ merged.filesRemovedList.push(...s.filesRemovedList);
38
+ merged.filesUnmatched += s.filesUnmatched;
39
+ merged.filesUpdated += s.filesUpdated;
40
+ merged.matched += s.matched;
41
+ merged.total += s.total;
42
+ merged.unchecked += s.unchecked;
43
+ merged.uncheckedKeysByFile.push(...s.uncheckedKeysByFile);
44
+ merged.unmatched += s.unmatched;
45
+ merged.updated += s.updated;
46
+ if (s.didUpdate) merged.didUpdate = true;
47
+ if (s.failure) merged.failure = true;
48
+ }
49
+ return merged;
50
+ }
51
+ function mergeDurations(durations) {
52
+ let totalTime = 0;
53
+ let buildTime = 0;
54
+ let testTime = 0;
55
+ for (const d of durations){
56
+ totalTime += d.totalTime;
57
+ buildTime += d.buildTime;
58
+ testTime += d.testTime;
59
+ }
60
+ return {
61
+ totalTime,
62
+ buildTime,
63
+ testTime
64
+ };
65
+ }
66
+ async function mergeReports(context, options) {
67
+ const { path, cleanup } = options || {};
68
+ const blobDir = path ? join(context.rootPath, path) : join(context.rootPath, DEFAULT_BLOB_DIR);
69
+ const blobs = loadBlobFiles(blobDir);
70
+ const relativeBlobDir = relative(context.rootPath, blobDir) || '.';
71
+ logger_logger.log(`\nMerging ${logger_color.bold(String(blobs.length))} blob ${1 === blobs.length ? 'report' : 'reports'} from ${logger_color.cyan(relativeBlobDir)}\n`);
72
+ const allResults = [];
73
+ const allTestResults = [];
74
+ const allDurations = [];
75
+ const shardDurations = [];
76
+ const allSnapshotSummaries = [];
77
+ const allUnhandledErrors = [];
78
+ for (const blob of blobs){
79
+ allResults.push(...blob.results);
80
+ allTestResults.push(...blob.testResults);
81
+ allDurations.push(blob.duration);
82
+ allSnapshotSummaries.push(blob.snapshotSummary);
83
+ const shardLabel = blob.shard ? `Shard ${blob.shard.index}/${blob.shard.count}` : 'Shard';
84
+ shardDurations.push({
85
+ label: shardLabel,
86
+ duration: blob.duration
87
+ });
88
+ if (blob.unhandledErrors) for (const e of blob.unhandledErrors){
89
+ const error = new Error(e.message);
90
+ error.name = e.name || 'Error';
91
+ error.stack = e.stack;
92
+ allUnhandledErrors.push(error);
93
+ }
94
+ if (blob.consoleLogs) for (const log of blob.consoleLogs)for (const reporter of context.reporters)reporter.onUserConsoleLog?.(log);
95
+ }
96
+ const mergedDuration = mergeDurations(allDurations);
97
+ const mergedSnapshotSummary = mergeSnapshots(allSnapshotSummaries);
98
+ const hasFailure = allResults.some((r)=>'fail' === r.status) || allUnhandledErrors.length > 0;
99
+ if (hasFailure) process.exitCode = 1;
100
+ for (const reporter of context.reporters)await reporter.onTestRunStart?.();
101
+ for (const { label, duration } of shardDurations)logger_logger.log(logger_color.gray(` ${label}: ${prettyTime(duration.totalTime)} (build ${prettyTime(duration.buildTime)}, tests ${prettyTime(duration.testTime)})`));
102
+ if (shardDurations.length > 0) logger_logger.log('');
103
+ for (const result of allResults)for (const reporter of context.reporters)reporter.onTestFileResult?.(result);
104
+ for (const reporter of context.reporters)await reporter.onTestRunEnd?.({
105
+ results: allResults,
106
+ testResults: allTestResults,
107
+ duration: mergedDuration,
108
+ snapshotSummary: mergedSnapshotSummary,
109
+ unhandledErrors: allUnhandledErrors.length ? allUnhandledErrors : void 0,
110
+ getSourcemap: async ()=>null
111
+ });
112
+ const { coverage } = context.normalizedConfig;
113
+ if (coverage.enabled && (!hasFailure || coverage.reportOnFailure)) {
114
+ const coverageProvider = await createCoverageProvider(coverage, context.rootPath);
115
+ if (coverageProvider) {
116
+ const { generateCoverage } = await import("./0~generate.js");
117
+ await generateCoverage(context, allResults, coverageProvider);
118
+ }
119
+ }
120
+ if (cleanup && existsSync(blobDir)) {
121
+ rmSync(blobDir, {
122
+ recursive: true
123
+ });
124
+ logger_logger.log(logger_color.gray(`Cleaned up blob reports directory: ${relativeBlobDir}\n`));
125
+ }
126
+ }
127
+ export { mergeReports };