@rstest/core 0.5.2 → 0.5.4

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/dist/0~816.js CHANGED
@@ -728,6 +728,7 @@ global.__rstest_clean_core_cache__ = __rstest_clean_core_cache__;
728
728
  b: ()=>createPool
729
729
  });
730
730
  var external_node_os_ = __webpack_require__("node:os");
731
+ var pathe_M_eThtNZ = __webpack_require__("../../node_modules/.pnpm/pathe@2.0.3/node_modules/pathe/dist/shared/pathe.M-eThtNZ.mjs");
731
732
  var utils = __webpack_require__("./src/utils/index.ts");
732
733
  var memory = __webpack_require__("./src/utils/memory.ts");
733
734
  var external_node_url_ = __webpack_require__("node:url");
@@ -893,7 +894,6 @@ global.__rstest_clean_core_cache__ = __rstest_clean_core_cache__;
893
894
  while(i--)id += urlAlphabet[64 * random() | 0];
894
895
  return id;
895
896
  }
896
- var pathe_M_eThtNZ = __webpack_require__("../../node_modules/.pnpm/pathe@2.0.3/node_modules/pathe/dist/shared/pathe.M-eThtNZ.mjs");
897
897
  const forks_filename = (0, external_node_url_.fileURLToPath)(import.meta.url);
898
898
  const forks_dirname = (0, pathe_M_eThtNZ.d)(forks_filename);
899
899
  function createChannel(rpcMethods) {
@@ -1047,6 +1047,12 @@ global.__rstest_clean_core_cache__ = __rstest_clean_core_cache__;
1047
1047
  },
1048
1048
  onTestFileStart: async (test)=>{
1049
1049
  await Promise.all(reporters.map((reporter)=>reporter.onTestFileStart?.(test)));
1050
+ },
1051
+ resolveSnapshotPath: (testPath)=>{
1052
+ const snapExtension = '.snap';
1053
+ const resolver = context.normalizedConfig.resolveSnapshotPath || (()=>(0, pathe_M_eThtNZ.j)((0, pathe_M_eThtNZ.d)(testPath), '__snapshots__', `${(0, pathe_M_eThtNZ.c)(testPath)}${snapExtension}`));
1054
+ const snapshotPath = resolver(testPath, snapExtension);
1055
+ return snapshotPath;
1050
1056
  }
1051
1057
  };
1052
1058
  return {
package/dist/0~85.js CHANGED
@@ -621,9 +621,6 @@ export const __webpack_modules__ = {
621
621
  const results = [];
622
622
  const errors = [];
623
623
  let defaultStatus = 'pass';
624
- hooks.onTestFileStart?.({
625
- testPath
626
- });
627
624
  const snapshotClient = getSnapshotClient();
628
625
  await snapshotClient.setup(testPath, snapshotOptions);
629
626
  const runTestsCase = async (test, parentHooks)=>{
package/dist/index.js CHANGED
@@ -2076,7 +2076,7 @@ ${section.body}` : section.body).join("\n\n"));
2076
2076
  const applyCommonOptions = (cli)=>{
2077
2077
  cli.option('-c, --config <config>', 'Specify the configuration file, can be a relative or absolute path').option('--config-loader <loader>', 'Specify the loader to load the config file, can be `jiti` or `native`', {
2078
2078
  default: 'jiti'
2079
- }).option('-r, --root <root>', 'Specify the project root directory, can be an absolute path or a path relative to cwd').option('--globals', 'Provide global APIs').option('--isolate', 'Run tests in an isolated environment').option('--include <include>', 'Match test files').option('--exclude <exclude>', 'Exclude files from test').option('-u, --update', 'Update snapshot files').option('--coverage', 'Enable code coverage collection').option('--project <name>', 'Run only projects that match the name, can be a full name or wildcards pattern').option('--passWithNoTests', 'Allows the test suite to pass when no files are found').option('--printConsoleTrace', 'Print console traces when calling any console method').option('--disableConsoleIntercept', 'Disable console intercept').option('--slowTestThreshold <value>', 'The number of milliseconds after which a test or suite is considered slow').option('--reporter <reporter>', 'Specify the reporter to use').option('-t, --testNamePattern <value>', 'Run only tests with a name that matches the regex').option('--testEnvironment <name>', 'The environment that will be used for testing').option('--testTimeout <value>', 'Timeout of a test in milliseconds').option('--hookTimeout <value>', 'Timeout of hook in milliseconds').option('--retry <retry>', 'Number of times to retry a test if it fails').option('--maxConcurrency <value>', 'Maximum number of concurrent tests').option('--clearMocks', 'Automatically clear mock calls, instances, contexts and results before every test').option('--resetMocks', 'Automatically reset mock state before every test').option('--restoreMocks', 'Automatically restore mock state and implementation before every test').option('--unstubGlobals', 'Restores all global variables that were changed with `rstest.stubGlobal` before every test').option('--unstubEnvs', 'Restores all `process.env` values that were changed with `rstest.stubEnv` before every test');
2079
+ }).option('-r, --root <root>', 'Specify the project root directory, can be an absolute path or a path relative to cwd').option('--globals', 'Provide global APIs').option('--isolate', 'Run tests in an isolated environment').option('--include <include>', 'Match test files').option('--exclude <exclude>', 'Exclude files from test').option('-u, --update', 'Update snapshot files').option('--coverage', 'Enable code coverage collection').option('--project <name>', 'Run only projects that match the name, can be a full name or wildcards pattern').option('--passWithNoTests', 'Allows the test suite to pass when no files are found').option('--printConsoleTrace', 'Print console traces when calling any console method').option('--disableConsoleIntercept', 'Disable console intercept').option('--slowTestThreshold <value>', 'The number of milliseconds after which a test or suite is considered slow').option('--reporter <reporter>', 'Specify the reporter to use').option('-t, --testNamePattern <value>', 'Run only tests with a name that matches the regex').option('--testEnvironment <name>', 'The environment that will be used for testing').option('--testTimeout <value>', 'Timeout of a test in milliseconds').option('--hookTimeout <value>', 'Timeout of hook in milliseconds').option('--hideSkippedTests', 'Hide skipped tests from the output').option('--retry <retry>', 'Number of times to retry a test if it fails').option('--maxConcurrency <value>', 'Maximum number of concurrent tests').option('--clearMocks', 'Automatically clear mock calls, instances, contexts and results before every test').option('--resetMocks', 'Automatically reset mock state before every test').option('--restoreMocks', 'Automatically restore mock state and implementation before every test').option('--unstubGlobals', 'Restores all global variables that were changed with `rstest.stubGlobal` before every test').option('--unstubEnvs', 'Restores all `process.env` values that were changed with `rstest.stubEnv` before every test');
2080
2080
  };
2081
2081
  const runRest = async ({ options, filters, command })=>{
2082
2082
  let rstest;
@@ -2108,7 +2108,7 @@ ${section.body}` : section.body).join("\n\n"));
2108
2108
  function setupCommands() {
2109
2109
  const cli = dist('rstest');
2110
2110
  cli.help();
2111
- cli.version("0.5.2");
2111
+ cli.version("0.5.4");
2112
2112
  applyCommonOptions(cli);
2113
2113
  cli.command('[...filters]', 'run tests').option('-w, --watch', 'Run tests in watch mode').action(async (filters, options)=>{
2114
2114
  (0, prepare.N)();
@@ -2215,7 +2215,8 @@ ${section.body}` : section.body).join("\n\n"));
2215
2215
  'maxConcurrency',
2216
2216
  'printConsoleTrace',
2217
2217
  'disableConsoleIntercept',
2218
- 'testEnvironment'
2218
+ 'testEnvironment',
2219
+ 'hideSkippedTests'
2219
2220
  ];
2220
2221
  for (const key of keys)if (void 0 !== options[key]) config[key] = options[key];
2221
2222
  if (options.reporter) config.reporters = (0, utils.bg)(options.reporter);
@@ -2347,7 +2348,7 @@ ${conflictProjects.map((p)=>`- ${p.configFilePath || p.config.root}`).join('\n')
2347
2348
  if (!npm_execpath || npm_execpath.includes('npx-cli.js') || npm_execpath.includes('.bun')) console.log();
2348
2349
  }
2349
2350
  function showRstest() {
2350
- _utils_logger__WEBPACK_IMPORTED_MODULE_0__.vF.greet(" Rstest v0.5.2");
2351
+ _utils_logger__WEBPACK_IMPORTED_MODULE_0__.vF.greet(" Rstest v0.5.4");
2351
2352
  _utils_logger__WEBPACK_IMPORTED_MODULE_0__.vF.log('');
2352
2353
  }
2353
2354
  },
@@ -2452,6 +2453,7 @@ ${conflictProjects.map((p)=>`- ${p.configFilePath || p.config.root}`).join('\n')
2452
2453
  disableConsoleIntercept: false,
2453
2454
  snapshotFormat: {},
2454
2455
  env: {},
2456
+ hideSkippedTests: false,
2455
2457
  coverage: {
2456
2458
  exclude: [
2457
2459
  '**/node_modules/**',
@@ -2889,6 +2891,77 @@ ${conflictProjects.map((p)=>`- ${p.configFilePath || p.config.root}`).join('\n')
2889
2891
  var src_config = __webpack_require__("./src/config.ts");
2890
2892
  var stack_trace_parser_esm = __webpack_require__("../../node_modules/.pnpm/stacktrace-parser@0.1.11/node_modules/stacktrace-parser/dist/stack-trace-parser.esm.js");
2891
2893
  var utils = __webpack_require__("./src/utils/index.ts");
2894
+ var dist = __webpack_require__("../../node_modules/.pnpm/pathe@2.0.3/node_modules/pathe/dist/index.mjs");
2895
+ const getSummaryStatusString = (tasks, name = 'tests', showTotal = true)=>{
2896
+ if (0 === tasks.length) return utils.yW.dim(`no ${name}`);
2897
+ const passed = tasks.filter((result)=>'pass' === result.status);
2898
+ const failed = tasks.filter((result)=>'fail' === result.status);
2899
+ const skipped = tasks.filter((result)=>'skip' === result.status);
2900
+ const todo = tasks.filter((result)=>'todo' === result.status);
2901
+ const status = [
2902
+ failed.length ? utils.yW.bold(utils.yW.red(`${failed.length} failed`)) : null,
2903
+ passed.length ? utils.yW.bold(utils.yW.green(`${passed.length} passed`)) : null,
2904
+ skipped.length ? utils.yW.yellow(`${skipped.length} skipped`) : null,
2905
+ todo.length ? utils.yW.gray(`${todo.length} todo`) : null
2906
+ ].filter(Boolean);
2907
+ return status.join(utils.yW.dim(' | ')) + (showTotal && status.length > 1 ? utils.yW.gray(` (${tasks.length})`) : '');
2908
+ };
2909
+ const printSnapshotSummaryLog = (snapshots, rootDir)=>{
2910
+ const summary = [];
2911
+ if (snapshots.added) summary.push(utils.yW.bold(utils.yW.green(`${snapshots.added} written`)));
2912
+ if (snapshots.unmatched) summary.push(utils.yW.bold(utils.yW.red(`${snapshots.unmatched} failed`)));
2913
+ if (snapshots.updated) summary.push(utils.yW.bold(utils.yW.green(`${snapshots.updated} updated `)));
2914
+ if (snapshots.filesRemoved) if (snapshots.didUpdate) summary.push(utils.yW.bold(utils.yW.green(`${snapshots.filesRemoved} files removed `)));
2915
+ else summary.push(utils.yW.bold(utils.yW.yellow(`${snapshots.filesRemoved} files obsolete `)));
2916
+ const POINTER = '➜';
2917
+ if (snapshots.filesRemovedList?.length) {
2918
+ const [head, ...tail] = snapshots.filesRemovedList;
2919
+ summary.push(`${utils.yW.gray(POINTER)} ${(0, utils.XJ)(rootDir, head)}`);
2920
+ for (const key of tail)summary.push(` ${(0, utils.XJ)(rootDir, key)}`);
2921
+ }
2922
+ if (snapshots.unchecked) {
2923
+ if (snapshots.didUpdate) summary.push(utils.yW.bold(utils.yW.green(`${snapshots.unchecked} removed`)));
2924
+ else summary.push(utils.yW.bold(utils.yW.yellow(`${snapshots.unchecked} obsolete`)));
2925
+ for (const uncheckedFile of snapshots.uncheckedKeysByFile){
2926
+ summary.push(`${utils.yW.gray(POINTER)} ${(0, utils.XJ)(rootDir, uncheckedFile.filePath)}`);
2927
+ for (const key of uncheckedFile.keys)summary.push(` ${key}`);
2928
+ }
2929
+ }
2930
+ for (const [index, snapshot] of summary.entries()){
2931
+ const title = 0 === index ? 'Snapshots' : '';
2932
+ utils.vF.log(`${utils.yW.gray(title.padStart(12))} ${snapshot}`);
2933
+ }
2934
+ };
2935
+ const TestFileSummaryLabel = utils.yW.gray('Test Files'.padStart(11));
2936
+ const TestSummaryLabel = utils.yW.gray('Tests'.padStart(11));
2937
+ const DurationLabel = utils.yW.gray('Duration'.padStart(11));
2938
+ const printSummaryLog = ({ results, testResults, snapshotSummary, duration, rootPath })=>{
2939
+ utils.vF.log('');
2940
+ printSnapshotSummaryLog(snapshotSummary, rootPath);
2941
+ utils.vF.log(`${TestFileSummaryLabel} ${getSummaryStatusString(results)}`);
2942
+ utils.vF.log(`${TestSummaryLabel} ${getSummaryStatusString(testResults)}`);
2943
+ utils.vF.log(`${DurationLabel} ${(0, utils.kV)(duration.totalTime)} ${utils.yW.gray(`(build ${(0, utils.kV)(duration.buildTime)}, tests ${(0, utils.kV)(duration.testTime)})`)}`);
2944
+ utils.vF.log('');
2945
+ };
2946
+ const printSummaryErrorLogs = async ({ testResults, results, rootPath, getSourcemap, filterRerunTestPaths })=>{
2947
+ const failedTests = [
2948
+ ...results.filter((i)=>'fail' === i.status && i.errors?.length && (filterRerunTestPaths ? filterRerunTestPaths.includes(i.testPath) : true)),
2949
+ ...testResults.filter((i)=>'fail' === i.status && (filterRerunTestPaths ? filterRerunTestPaths.includes(i.testPath) : true))
2950
+ ];
2951
+ if (0 === failedTests.length) return;
2952
+ utils.vF.log('');
2953
+ utils.vF.log(utils.yW.bold('Summary of all failing tests:'));
2954
+ utils.vF.log('');
2955
+ for (const test of failedTests){
2956
+ const relativePath = dist.Ay.relative(rootPath, test.testPath);
2957
+ const nameStr = (0, utils.fN)(test);
2958
+ utils.vF.log(`${utils.yW.bgRed(' FAIL ')} ${(0, utils.EQ)(relativePath)} ${nameStr.length ? `${utils.yW.dim(utils.vO)} ${nameStr}` : ''}`);
2959
+ if (test.errors) {
2960
+ const { printError } = await Promise.resolve().then(__webpack_require__.bind(__webpack_require__, "./src/utils/error.ts"));
2961
+ for (const error of test.errors)await printError(error, getSourcemap, rootPath);
2962
+ }
2963
+ }
2964
+ };
2892
2965
  const DEFAULT_RENDER_INTERVAL_MS = 1000;
2893
2966
  const ESC = '\x1B[';
2894
2967
  const CLEAR_LINE = `${ESC}K`;
@@ -3009,7 +3082,9 @@ ${conflictProjects.map((p)=>`- ${p.configFilePath || p.config.root}`).join('\n')
3009
3082
  class StatusRenderer {
3010
3083
  rootPath;
3011
3084
  renderer;
3012
- runningModules = new Set();
3085
+ runningModules = new Map();
3086
+ testModules = [];
3087
+ startTime = void 0;
3013
3088
  constructor(rootPath){
3014
3089
  this.rootPath = rootPath;
3015
3090
  this.renderer = new WindowRenderer({
@@ -3022,95 +3097,43 @@ ${conflictProjects.map((p)=>`- ${p.configFilePath || p.config.root}`).join('\n')
3022
3097
  });
3023
3098
  }
3024
3099
  getContent() {
3100
+ this.startTime ??= Date.now();
3025
3101
  const summary = [];
3026
- for (const module of this.runningModules){
3102
+ for (const module of this.runningModules.keys()){
3027
3103
  const relativePath = (0, pathe_M_eThtNZ.b)(this.rootPath, module);
3028
3104
  summary.push(`${utils.yW.bgYellow(utils.yW.bold(' RUNS '))} ${(0, utils.EQ)(relativePath)}`);
3029
3105
  }
3030
3106
  summary.push('');
3107
+ if (0 === this.testModules.length) summary.push(`${TestFileSummaryLabel} ${this.runningModules.size} total`);
3108
+ else summary.push(`${TestFileSummaryLabel} ${getSummaryStatusString(this.testModules, '', false)} ${utils.yW.dim('|')} ${this.runningModules.size + this.testModules.length} total`);
3109
+ const testResults = Array.from(this.runningModules.values()).flat().concat(this.testModules.flatMap((mod)=>mod.results));
3110
+ if (testResults.length) summary.push(`${TestSummaryLabel} ${getSummaryStatusString(testResults, '', false)}`);
3111
+ summary.push(`${DurationLabel} ${(0, utils.kV)(Date.now() - this.startTime)}`);
3112
+ summary.push('');
3031
3113
  return summary;
3032
3114
  }
3033
- addRunningModule(testPath) {
3034
- this.runningModules.add(testPath);
3115
+ onTestFileStart(testPath) {
3116
+ this.runningModules.set(testPath, []);
3035
3117
  this.renderer?.schedule();
3036
3118
  }
3037
- removeRunningModule(testPath) {
3038
- this.runningModules.delete(testPath);
3119
+ onTestCaseResult(result) {
3120
+ this.runningModules.set(result.testPath, [
3121
+ ...this.runningModules.get(result.testPath) || [],
3122
+ result
3123
+ ]);
3124
+ }
3125
+ onTestFileResult(test) {
3126
+ this.runningModules.delete(test.testPath);
3127
+ this.testModules.push(test);
3039
3128
  this.renderer?.schedule();
3040
3129
  }
3041
3130
  clear() {
3131
+ this.testModules.length = 0;
3042
3132
  this.runningModules.clear();
3133
+ this.startTime = void 0;
3043
3134
  this.renderer?.finish();
3044
3135
  }
3045
3136
  }
3046
- var dist = __webpack_require__("../../node_modules/.pnpm/pathe@2.0.3/node_modules/pathe/dist/index.mjs");
3047
- const getSummaryStatusString = (tasks, name = 'tests', showTotal = true)=>{
3048
- if (0 === tasks.length) return utils.yW.dim(`no ${name}`);
3049
- const passed = tasks.filter((result)=>'pass' === result.status);
3050
- const failed = tasks.filter((result)=>'fail' === result.status);
3051
- const skipped = tasks.filter((result)=>'skip' === result.status);
3052
- const todo = tasks.filter((result)=>'todo' === result.status);
3053
- const status = [
3054
- failed.length ? utils.yW.bold(utils.yW.red(`${failed.length} failed`)) : null,
3055
- passed.length ? utils.yW.bold(utils.yW.green(`${passed.length} passed`)) : null,
3056
- skipped.length ? utils.yW.yellow(`${skipped.length} skipped`) : null,
3057
- todo.length ? utils.yW.gray(`${todo.length} todo`) : null
3058
- ].filter(Boolean);
3059
- return status.join(utils.yW.dim(' | ')) + (showTotal && status.length > 1 ? utils.yW.gray(` (${tasks.length})`) : '');
3060
- };
3061
- const printSnapshotSummaryLog = (snapshots, rootDir)=>{
3062
- const summary = [];
3063
- if (snapshots.added) summary.push(utils.yW.bold(utils.yW.green(`${snapshots.added} written`)));
3064
- if (snapshots.unmatched) summary.push(utils.yW.bold(utils.yW.red(`${snapshots.unmatched} failed`)));
3065
- if (snapshots.updated) summary.push(utils.yW.bold(utils.yW.green(`${snapshots.updated} updated `)));
3066
- if (snapshots.filesRemoved) if (snapshots.didUpdate) summary.push(utils.yW.bold(utils.yW.green(`${snapshots.filesRemoved} files removed `)));
3067
- else summary.push(utils.yW.bold(utils.yW.yellow(`${snapshots.filesRemoved} files obsolete `)));
3068
- const POINTER = '➜';
3069
- if (snapshots.filesRemovedList?.length) {
3070
- const [head, ...tail] = snapshots.filesRemovedList;
3071
- summary.push(`${utils.yW.gray(POINTER)} ${(0, utils.XJ)(rootDir, head)}`);
3072
- for (const key of tail)summary.push(` ${(0, utils.XJ)(rootDir, key)}`);
3073
- }
3074
- if (snapshots.unchecked) {
3075
- if (snapshots.didUpdate) summary.push(utils.yW.bold(utils.yW.green(`${snapshots.unchecked} removed`)));
3076
- else summary.push(utils.yW.bold(utils.yW.yellow(`${snapshots.unchecked} obsolete`)));
3077
- for (const uncheckedFile of snapshots.uncheckedKeysByFile){
3078
- summary.push(`${utils.yW.gray(POINTER)} ${(0, utils.XJ)(rootDir, uncheckedFile.filePath)}`);
3079
- for (const key of uncheckedFile.keys)summary.push(` ${key}`);
3080
- }
3081
- }
3082
- for (const [index, snapshot] of summary.entries()){
3083
- const title = 0 === index ? 'Snapshots' : '';
3084
- utils.vF.log(`${utils.yW.gray(title.padStart(12))} ${snapshot}`);
3085
- }
3086
- };
3087
- const printSummaryLog = ({ results, testResults, snapshotSummary, duration, rootPath })=>{
3088
- utils.vF.log('');
3089
- printSnapshotSummaryLog(snapshotSummary, rootPath);
3090
- utils.vF.log(`${utils.yW.gray('Test Files'.padStart(11))} ${getSummaryStatusString(results)}`);
3091
- utils.vF.log(`${utils.yW.gray('Tests'.padStart(11))} ${getSummaryStatusString(testResults)}`);
3092
- utils.vF.log(`${utils.yW.gray('Duration'.padStart(11))} ${(0, utils.kV)(duration.totalTime)} ${utils.yW.gray(`(build ${(0, utils.kV)(duration.buildTime)}, tests ${(0, utils.kV)(duration.testTime)})`)}`);
3093
- utils.vF.log('');
3094
- };
3095
- const printSummaryErrorLogs = async ({ testResults, results, rootPath, getSourcemap, filterRerunTestPaths })=>{
3096
- const failedTests = [
3097
- ...results.filter((i)=>'fail' === i.status && i.errors?.length && (filterRerunTestPaths ? filterRerunTestPaths.includes(i.testPath) : true)),
3098
- ...testResults.filter((i)=>'fail' === i.status && (filterRerunTestPaths ? filterRerunTestPaths.includes(i.testPath) : true))
3099
- ];
3100
- if (0 === failedTests.length) return;
3101
- utils.vF.log('');
3102
- utils.vF.log(utils.yW.bold('Summary of all failing tests:'));
3103
- utils.vF.log('');
3104
- for (const test of failedTests){
3105
- const relativePath = dist.Ay.relative(rootPath, test.testPath);
3106
- const nameStr = (0, utils.fN)(test);
3107
- utils.vF.log(`${utils.yW.bgRed(' FAIL ')} ${(0, utils.EQ)(relativePath)} ${nameStr.length ? `${utils.yW.dim(utils.vO)} ${nameStr}` : ''}`);
3108
- if (test.errors) {
3109
- const { printError } = await Promise.resolve().then(__webpack_require__.bind(__webpack_require__, "./src/utils/error.ts"));
3110
- for (const error of test.errors)await printError(error, getSourcemap, rootPath);
3111
- }
3112
- }
3113
- };
3114
3137
  const statusStr = {
3115
3138
  fail: '✗',
3116
3139
  pass: '✓',
@@ -3123,8 +3146,9 @@ ${conflictProjects.map((p)=>`- ${p.configFilePath || p.config.root}`).join('\n')
3123
3146
  todo: utils.yW.gray(statusStr.todo),
3124
3147
  skip: utils.yW.gray(statusStr.skip)
3125
3148
  };
3126
- const logCase = (result, slowTestThreshold)=>{
3127
- const isSlowCase = (result.duration || 0) > slowTestThreshold;
3149
+ const logCase = (result, options)=>{
3150
+ const isSlowCase = (result.duration || 0) > options.slowTestThreshold;
3151
+ if (options.hideSkippedTests && 'skip' === result.status) return;
3128
3152
  const icon = isSlowCase && 'pass' === result.status ? utils.yW.yellow(statusStr[result.status]) : statusColorfulStr[result.status];
3129
3153
  const nameStr = (0, utils.fN)(result);
3130
3154
  const duration = void 0 !== result.duration ? ` (${(0, utils.kV)(result.duration)})` : '';
@@ -3132,12 +3156,11 @@ ${conflictProjects.map((p)=>`- ${p.configFilePath || p.config.root}`).join('\n')
3132
3156
  utils.vF.log(` ${icon} ${nameStr}${utils.yW.gray(duration)}${retry}`);
3133
3157
  if (result.errors) for (const error of result.errors)console.error(utils.yW.red(` ${error.message}`));
3134
3158
  };
3135
- const logFileTitle = (test, relativePath, slowTestThreshold, alwaysShowTime = false)=>{
3159
+ const logFileTitle = (test, relativePath, alwaysShowTime = false)=>{
3136
3160
  let title = ` ${utils.yW.bold(statusColorfulStr[test.status])} ${(0, utils.EQ)(relativePath)}`;
3137
- const formatDuration = (duration)=>utils.yW[duration > slowTestThreshold ? 'yellow' : 'green']((0, utils.kV)(duration));
3161
+ const formatDuration = (duration)=>utils.yW.green((0, utils.kV)(duration));
3138
3162
  title += ` ${utils.yW.gray(`(${test.results.length})`)}`;
3139
- const isTooSlow = test.duration && test.duration > slowTestThreshold;
3140
- if (alwaysShowTime || isTooSlow) title += ` ${formatDuration(test.duration)}`;
3163
+ if (alwaysShowTime) title += ` ${formatDuration(test.duration)}`;
3141
3164
  utils.vF.log(title);
3142
3165
  };
3143
3166
  class DefaultReporter {
@@ -3152,38 +3175,37 @@ ${conflictProjects.map((p)=>`- ${p.configFilePath || p.config.root}`).join('\n')
3152
3175
  if (!T) this.statusRenderer = new StatusRenderer(rootPath);
3153
3176
  }
3154
3177
  onTestFileStart(test) {
3155
- this.statusRenderer?.addRunningModule(test.testPath);
3178
+ this.statusRenderer?.onTestFileStart(test.testPath);
3156
3179
  }
3157
3180
  onTestFileResult(test) {
3158
- this.statusRenderer?.removeRunningModule(test.testPath);
3181
+ this.statusRenderer?.onTestFileResult(test);
3159
3182
  const relativePath = (0, pathe_M_eThtNZ.b)(this.rootPath, test.testPath);
3160
3183
  const { slowTestThreshold } = this.config;
3161
- logFileTitle(test, relativePath, slowTestThreshold);
3162
- const isTooSlow = test.duration && test.duration > slowTestThreshold;
3163
- const hasRetryCase = test.results.some((result)=>(result.retryCount || 0) > 0);
3164
- if ('fail' !== test.status && !isTooSlow && !hasRetryCase) return;
3165
- const showAllCases = isTooSlow && !test.results.some((result)=>(result.duration || 0) > slowTestThreshold);
3184
+ logFileTitle(test, relativePath);
3166
3185
  for (const result of test.results){
3167
- const isSlowCase = (result.duration || 0) > slowTestThreshold;
3168
- const retried = (result.retryCount || 0) > 0;
3169
- if (showAllCases || 'fail' === result.status || isSlowCase || retried) logCase(result, slowTestThreshold);
3186
+ const isDisplayed = 'fail' === result.status || (result.duration ?? 0) > slowTestThreshold || (result.retryCount ?? 0) > 0;
3187
+ isDisplayed && logCase(result, {
3188
+ slowTestThreshold,
3189
+ hideSkippedTests: this.config.hideSkippedTests
3190
+ });
3170
3191
  }
3171
3192
  }
3172
- onTestCaseResult(_result) {}
3193
+ onTestCaseResult(result) {
3194
+ this.statusRenderer?.onTestCaseResult(result);
3195
+ }
3173
3196
  onUserConsoleLog(log) {
3174
3197
  const shouldLog = this.config.onConsoleLog?.(log.content) ?? true;
3175
3198
  if (!shouldLog) return;
3176
- const titles = [
3177
- log.name
3178
- ];
3199
+ const titles = [];
3179
3200
  const testPath = (0, pathe_M_eThtNZ.b)(this.rootPath, log.testPath);
3180
3201
  if (log.trace) {
3181
3202
  const [frame] = (0, stack_trace_parser_esm.q)(log.trace);
3182
3203
  const filePath = (0, pathe_M_eThtNZ.b)(this.rootPath, frame.file || '');
3183
- if (filePath !== testPath) titles.push((0, utils.EQ)(testPath));
3184
- titles.push((0, utils.EQ)(filePath) + utils.yW.gray(`:${frame.lineNumber}:${frame.column}`));
3185
- } else titles.push((0, utils.EQ)(testPath));
3186
- utils.vF.log(titles.join(utils.yW.gray(' | ')));
3204
+ if (filePath !== testPath) titles.push(testPath);
3205
+ titles.push(`${filePath}:${frame.lineNumber}:${frame.column}`);
3206
+ } else titles.push(testPath);
3207
+ utils.vF.log('');
3208
+ utils.vF.log(`${log.name}${utils.yW.gray(utils.yW.dim(` | ${titles.join(utils.yW.gray(utils.yW.dim(' | ')))}`))}`);
3187
3209
  utils.vF.log(log.content);
3188
3210
  utils.vF.log('');
3189
3211
  }
@@ -3397,11 +3419,14 @@ ${conflictProjects.map((p)=>`- ${p.configFilePath || p.config.root}`).join('\n')
3397
3419
  }
3398
3420
  class VerboseReporter extends DefaultReporter {
3399
3421
  onTestFileResult(test) {
3400
- this.statusRenderer?.removeRunningModule(test.testPath);
3422
+ this.statusRenderer?.onTestFileResult(test);
3401
3423
  const relativePath = (0, pathe_M_eThtNZ.b)(this.rootPath, test.testPath);
3402
3424
  const { slowTestThreshold } = this.config;
3403
- logFileTitle(test, relativePath, slowTestThreshold, true);
3404
- for (const result of test.results)logCase(result, slowTestThreshold);
3425
+ logFileTitle(test, relativePath, true);
3426
+ for (const result of test.results)logCase(result, {
3427
+ slowTestThreshold,
3428
+ hideSkippedTests: this.config.hideSkippedTests
3429
+ });
3405
3430
  }
3406
3431
  }
3407
3432
  function formatEnvironmentName(name) {
@@ -3443,11 +3468,12 @@ ${conflictProjects.map((p)=>`- ${p.configFilePath || p.config.root}`).join('\n')
3443
3468
  });
3444
3469
  this.reporters = reporters;
3445
3470
  this.snapshotManager = snapshotManager;
3446
- this.version = "0.5.2";
3471
+ this.version = "0.5.4";
3447
3472
  this.rootPath = rootPath;
3448
3473
  this.originalConfig = userConfig;
3449
3474
  this.normalizedConfig = rstestConfig;
3450
3475
  this.projects = projects.length ? projects.map((project)=>{
3476
+ project.config.root = (0, utils.FI)(rootPath, project.config.root);
3451
3477
  const config = (0, src_config.wX)(project.config);
3452
3478
  config.isolate = rstestConfig.isolate;
3453
3479
  config.source ??= {};
@@ -3997,6 +4023,18 @@ ${conflictProjects.map((p)=>`- ${p.configFilePath || p.config.root}`).join('\n')
3997
4023
  }
3998
4024
  var stack_trace_parser_esm = __webpack_require__("../../node_modules/.pnpm/stacktrace-parser@0.1.11/node_modules/stacktrace-parser/dist/stack-trace-parser.esm.js");
3999
4025
  var utils = __webpack_require__("./src/utils/index.ts");
4026
+ const hintNotDefinedError = (message)=>{
4027
+ const [, varName] = message.match(/(\w+) is not defined/) || [];
4028
+ if (varName) {
4029
+ if (utils.TE.includes(varName)) return message.replace(`${varName} is not defined`, `${varName} is not defined. Did you forget to enable "globals" configuration?`);
4030
+ if ([
4031
+ 'jest',
4032
+ 'vitest'
4033
+ ].includes(varName)) return message.replace(`${varName} is not defined`, `${varName} is not defined. Did you mean rstest?`);
4034
+ if ('React' === varName) return message.replace(`${varName} is not defined`, `${varName} is not defined. Did you forget to install "${utils.yW.yellow('@rsbuild/plugin-react')}" plugin?`);
4035
+ }
4036
+ return message;
4037
+ };
4000
4038
  async function printError(error, getSourcemap, rootPath) {
4001
4039
  const errorName = error.name || 'Unknown Error';
4002
4040
  if (error.message.includes('Vitest failed to access its internal state')) {
@@ -4009,16 +4047,7 @@ ${conflictProjects.map((p)=>`- ${p.configFilePath || p.config.root}`).join('\n')
4009
4047
  utils.vF.log(`${utils.yW.red(tips.join('\n'))}\n`);
4010
4048
  return;
4011
4049
  }
4012
- if (error.message.includes('is not defined')) {
4013
- const [, varName] = error.message.match(/(.*) is not defined/) || [];
4014
- if (varName) {
4015
- if (utils.TE.includes(varName)) error.message = error.message.replace(`${varName} is not defined`, `${varName} is not defined. Did you forget to enable "globals" configuration?`);
4016
- else if ([
4017
- 'jest',
4018
- 'vitest'
4019
- ].includes(varName)) error.message = error.message.replace(`${varName} is not defined`, `${varName} is not defined. Did you mean rstest?`);
4020
- }
4021
- }
4050
+ if (error.message.includes('is not defined')) error.message = hintNotDefinedError(error.message);
4022
4051
  utils.vF.log(`${utils.yW.red(utils.yW.bold(errorName))}${utils.yW.red(`: ${error.message}`)}\n`);
4023
4052
  if (error.diff) {
4024
4053
  utils.vF.log(error.diff);
package/dist/worker.js CHANGED
@@ -8199,9 +8199,17 @@ class NodeSnapshotEnvironment {
8199
8199
  }
8200
8200
  }
8201
8201
  class RstestSnapshotEnvironment extends NodeSnapshotEnvironment {
8202
+ resolveSnapshotPath;
8203
+ constructor(options){
8204
+ super();
8205
+ this.resolveSnapshotPath = options.resolveSnapshotPath;
8206
+ }
8202
8207
  getHeader() {
8203
8208
  return `// Rstest Snapshot v${this.getVersion()}`;
8204
8209
  }
8210
+ resolvePath(filepath) {
8211
+ return this.resolveSnapshotPath(filepath);
8212
+ }
8205
8213
  }
8206
8214
  let sourceMaps = {};
8207
8215
  (0, source_map_support.install)({
@@ -8242,7 +8250,9 @@ const preparePool = async ({ entryInfo: { distPath, testPath }, updateSnapshot,
8242
8250
  ...context,
8243
8251
  snapshotOptions: {
8244
8252
  updateSnapshot,
8245
- snapshotEnvironment: new RstestSnapshotEnvironment(),
8253
+ snapshotEnvironment: new RstestSnapshotEnvironment({
8254
+ resolveSnapshotPath: (filepath)=>rpc.resolveSnapshotPath(filepath)
8255
+ }),
8246
8256
  snapshotFormat
8247
8257
  },
8248
8258
  distPath,
@@ -8407,6 +8417,9 @@ const runInPool = async (options)=>{
8407
8417
  const { assetFiles, sourceMaps: sourceMapsFromAssets } = assets || await rpc.getAssetsByEntry();
8408
8418
  sourceMaps = sourceMapsFromAssets;
8409
8419
  cleanups.push(cleanup);
8420
+ rpc.onTestFileStart?.({
8421
+ testPath
8422
+ });
8410
8423
  await loadFiles({
8411
8424
  rstestContext,
8412
8425
  distPath,
@@ -8417,9 +8430,6 @@ const runInPool = async (options)=>{
8417
8430
  isolate
8418
8431
  });
8419
8432
  const results = await runner.runTests(testPath, {
8420
- onTestFileStart: async (test)=>{
8421
- await rpc.onTestFileStart(test);
8422
- },
8423
8433
  onTestCaseResult: async (result)=>{
8424
8434
  await rpc.onTestCaseResult(result);
8425
8435
  }
@@ -332,6 +332,7 @@ declare type CommonOptions = {
332
332
  retry?: number;
333
333
  maxConcurrency?: number;
334
334
  slowTestThreshold?: number;
335
+ hideSkippedTests?: boolean;
335
336
  };
336
337
 
337
338
  declare type CompareKeys = ((a: string, b: string) => number) | null | undefined;
@@ -589,7 +590,7 @@ declare class DefaultReporter implements Reporter {
589
590
  });
590
591
  onTestFileStart(test: TestFileInfo): void;
591
592
  onTestFileResult(test: TestFileResult): void;
592
- onTestCaseResult(_result: TestResult): void;
593
+ onTestCaseResult(result: TestResult): void;
593
594
  onUserConsoleLog(log: UserConsoleLog): void;
594
595
  onExit(): Promise<void>;
595
596
  onTestRunEnd({ results, testResults, duration, getSourcemap, snapshotSummary, filterRerunTestPaths, }: {
@@ -1938,7 +1939,7 @@ declare type OnTestFinishedHandler = (params: {
1938
1939
  };
1939
1940
  }) => MaybePromise<void>;
1940
1941
 
1941
- declare type OptionalKeys = 'testNamePattern' | 'plugins' | 'source' | 'resolve' | 'output' | 'performance' | 'tools' | 'dev' | 'onConsoleLog';
1942
+ declare type OptionalKeys = 'testNamePattern' | 'plugins' | 'source' | 'resolve' | 'output' | 'performance' | 'tools' | 'dev' | 'onConsoleLog' | 'resolveSnapshotPath';
1942
1943
 
1943
1944
  declare type OptionsReceived = PrettyFormatOptions;
1944
1945
 
@@ -2226,6 +2227,12 @@ export declare interface RstestConfig {
2226
2227
  * @default ['default']
2227
2228
  */
2228
2229
  reporters?: Reporter | BuiltInReporterNames | (Reporter | BuiltInReporterNames | [BuiltInReporterNames] | ReporterWithOptions)[];
2230
+ /**
2231
+ * Hide skipped tests logs.
2232
+ *
2233
+ * @default false
2234
+ */
2235
+ hideSkippedTests?: boolean;
2229
2236
  /**
2230
2237
  * Run only tests with a name that matches the regex.
2231
2238
  */
@@ -2281,6 +2288,10 @@ export declare interface RstestConfig {
2281
2288
  onConsoleLog?: (content: string) => boolean | void;
2282
2289
  /** Format snapshot output */
2283
2290
  snapshotFormat?: SnapshotFormat;
2291
+ /**
2292
+ * Resolve custom snapshot path
2293
+ */
2294
+ resolveSnapshotPath?: (testPath: string, snapExtension: string) => string;
2284
2295
  /**
2285
2296
  * Custom environment variables available on `process.env` during tests.
2286
2297
  */
@@ -2670,10 +2681,13 @@ declare class StatusRenderer {
2670
2681
  private rootPath;
2671
2682
  private renderer;
2672
2683
  private runningModules;
2684
+ private testModules;
2685
+ private startTime;
2673
2686
  constructor(rootPath: string);
2674
2687
  getContent(): string[];
2675
- addRunningModule(testPath: string): void;
2676
- removeRunningModule(testPath: string): void;
2688
+ onTestFileStart(testPath: string): void;
2689
+ onTestCaseResult(result: TestResult): void;
2690
+ onTestFileResult(test: TestFileResult): void;
2677
2691
  clear(): void;
2678
2692
  }
2679
2693
 
@@ -498,7 +498,7 @@ declare class DefaultReporter implements Reporter {
498
498
  });
499
499
  onTestFileStart(test: TestFileInfo): void;
500
500
  onTestFileResult(test: TestFileResult): void;
501
- onTestCaseResult(_result: TestResult): void;
501
+ onTestCaseResult(result: TestResult): void;
502
502
  onUserConsoleLog(log: UserConsoleLog): void;
503
503
  onExit(): Promise<void>;
504
504
  onTestRunEnd({ results, testResults, duration, getSourcemap, snapshotSummary, filterRerunTestPaths, }: {
@@ -1614,7 +1614,7 @@ declare type OnTestFinishedHandler = (params: {
1614
1614
  };
1615
1615
  }) => MaybePromise<void>;
1616
1616
 
1617
- declare type OptionalKeys = 'testNamePattern' | 'plugins' | 'source' | 'resolve' | 'output' | 'performance' | 'tools' | 'dev' | 'onConsoleLog';
1617
+ declare type OptionalKeys = 'testNamePattern' | 'plugins' | 'source' | 'resolve' | 'output' | 'performance' | 'tools' | 'dev' | 'onConsoleLog' | 'resolveSnapshotPath';
1618
1618
 
1619
1619
  declare type OptionsReceived = PrettyFormatOptions;
1620
1620
 
@@ -1882,6 +1882,12 @@ declare interface RstestConfig {
1882
1882
  * @default ['default']
1883
1883
  */
1884
1884
  reporters?: Reporter | BuiltInReporterNames | (Reporter | BuiltInReporterNames | [BuiltInReporterNames] | ReporterWithOptions)[];
1885
+ /**
1886
+ * Hide skipped tests logs.
1887
+ *
1888
+ * @default false
1889
+ */
1890
+ hideSkippedTests?: boolean;
1885
1891
  /**
1886
1892
  * Run only tests with a name that matches the regex.
1887
1893
  */
@@ -1937,6 +1943,10 @@ declare interface RstestConfig {
1937
1943
  onConsoleLog?: (content: string) => boolean | void;
1938
1944
  /** Format snapshot output */
1939
1945
  snapshotFormat?: SnapshotFormat;
1946
+ /**
1947
+ * Resolve custom snapshot path
1948
+ */
1949
+ resolveSnapshotPath?: (testPath: string, snapExtension: string) => string;
1940
1950
  /**
1941
1951
  * Custom environment variables available on `process.env` during tests.
1942
1952
  */
@@ -2027,6 +2037,7 @@ declare type RuntimeRPC = {
2027
2037
  }>;
2028
2038
  onTestCaseResult: (result: TestResult) => Promise<void>;
2029
2039
  onConsoleLog: (log: UserConsoleLog) => void;
2040
+ resolveSnapshotPath: (filepath: string) => string;
2030
2041
  };
2031
2042
 
2032
2043
  declare type RunWorkerOptions = {
@@ -2219,10 +2230,13 @@ declare class StatusRenderer {
2219
2230
  private rootPath;
2220
2231
  private renderer;
2221
2232
  private runningModules;
2233
+ private testModules;
2234
+ private startTime;
2222
2235
  constructor(rootPath: string);
2223
2236
  getContent(): string[];
2224
- addRunningModule(testPath: string): void;
2225
- removeRunningModule(testPath: string): void;
2237
+ onTestFileStart(testPath: string): void;
2238
+ onTestCaseResult(result: TestResult): void;
2239
+ onTestFileResult(test: TestFileResult): void;
2226
2240
  clear(): void;
2227
2241
  }
2228
2242
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rstest/core",
3
- "version": "0.5.2",
3
+ "version": "0.5.4",
4
4
  "description": "The Rsbuild-based test tool.",
5
5
  "bugs": {
6
6
  "url": "https://github.com/web-infra-dev/rstest/issues"