@rstest/core 0.6.3 → 0.6.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/0~470.js CHANGED
@@ -198,6 +198,7 @@ async function runTests(context) {
198
198
  let testStart;
199
199
  const currentEntries = [];
200
200
  const currentDeletedEntries = [];
201
+ context.stateManager.reset();
201
202
  const returns = await Promise.all(context.projects.map(async (p)=>{
202
203
  const { assetNames, entries, setupEntries, getAssetFiles, getSourceMaps, affectedEntries, deletedEntries } = await getRsbuildStats({
203
204
  environmentName: p.environmentName,
package/dist/0~764.js CHANGED
@@ -11767,6 +11767,9 @@ use(JestExtend);
11767
11767
  use(JestChaiExpect);
11768
11768
  use(SnapshotPlugin);
11769
11769
  use(JestAsymmetricMatchers);
11770
+ function setupChaiConfig(config) {
11771
+ Object.assign(chai_config, config);
11772
+ }
11770
11773
  function createExpect({ getCurrentTest, workerState }) {
11771
11774
  const expect = (value, message)=>{
11772
11775
  const { assertionCalls } = getState(expect);
@@ -12081,7 +12084,7 @@ class TestRunner {
12081
12084
  workerState;
12082
12085
  async runTests({ tests, testPath, state, hooks, api }) {
12083
12086
  this.workerState = state;
12084
- const { runtimeConfig: { passWithNoTests, retry, maxConcurrency }, project, snapshotOptions } = state;
12087
+ const { runtimeConfig: { passWithNoTests, retry, maxConcurrency, bail }, project, snapshotOptions } = state;
12085
12088
  const results = [];
12086
12089
  const errors = [];
12087
12090
  let defaultStatus = 'pass';
@@ -12226,6 +12229,10 @@ class TestRunner {
12226
12229
  }
12227
12230
  };
12228
12231
  const runTest = async (test, parentHooks)=>{
12232
+ if (bail && await hooks.getCountOfFailedTests() >= bail) {
12233
+ defaultStatus = 'skip';
12234
+ return;
12235
+ }
12229
12236
  if ('suite' === test.type) {
12230
12237
  if (0 === test.tests.length) {
12231
12238
  if ([
@@ -13258,6 +13265,7 @@ const createRstestRuntime = (workerState)=>{
13258
13265
  const { runner, api: runnerAPI } = createRunner({
13259
13266
  workerState
13260
13267
  });
13268
+ if (workerState.runtimeConfig.chaiConfig) setupChaiConfig(workerState.runtimeConfig.chaiConfig);
13261
13269
  const expect = createExpect({
13262
13270
  workerState,
13263
13271
  getCurrentTest: ()=>runner.getCurrentTest()
package/dist/0~814.js CHANGED
@@ -100,7 +100,7 @@ const parseWorkers = (maxWorkers)=>{
100
100
  return parsed > 0 ? parsed : 1;
101
101
  };
102
102
  const getRuntimeConfig = (context)=>{
103
- const { testNamePattern, testTimeout, passWithNoTests, retry, globals, clearMocks, resetMocks, restoreMocks, unstubEnvs, unstubGlobals, maxConcurrency, printConsoleTrace, disableConsoleIntercept, testEnvironment, hookTimeout, isolate, coverage, snapshotFormat, env, logHeapUsage } = context.normalizedConfig;
103
+ const { testNamePattern, testTimeout, passWithNoTests, retry, globals, clearMocks, resetMocks, restoreMocks, unstubEnvs, unstubGlobals, maxConcurrency, printConsoleTrace, disableConsoleIntercept, testEnvironment, hookTimeout, isolate, coverage, snapshotFormat, env, logHeapUsage, bail, chaiConfig } = context.normalizedConfig;
104
104
  return {
105
105
  env,
106
106
  testNamePattern,
@@ -121,7 +121,9 @@ const getRuntimeConfig = (context)=>{
121
121
  isolate,
122
122
  coverage,
123
123
  snapshotFormat,
124
- logHeapUsage
124
+ logHeapUsage,
125
+ bail,
126
+ chaiConfig
125
127
  };
126
128
  };
127
129
  const filterAssetsByEntry = async (entryInfo, getAssetFiles, getSourceMaps, setupAssets)=>{
@@ -166,12 +168,15 @@ const createPool = async ({ context, recommendWorkerCount = 1 / 0 })=>{
166
168
  });
167
169
  const rpcMethods = {
168
170
  onTestCaseResult: async (result)=>{
171
+ context.stateManager.onTestCaseResult(result);
169
172
  await Promise.all(reporters.map((reporter)=>reporter.onTestCaseResult?.(result)));
170
173
  },
174
+ getCountOfFailedTests: async ()=>context.stateManager.getCountOfFailedTests(),
171
175
  onConsoleLog: async (log)=>{
172
176
  await Promise.all(reporters.map((reporter)=>reporter.onUserConsoleLog?.(log)));
173
177
  },
174
178
  onTestFileStart: async (test)=>{
179
+ context.stateManager.onTestFileStart(test.testPath);
175
180
  await Promise.all(reporters.map((reporter)=>reporter.onTestFileStart?.(test)));
176
181
  },
177
182
  resolveSnapshotPath: (testPath)=>{
@@ -219,6 +224,7 @@ const createPool = async ({ context, recommendWorkerCount = 1 / 0 })=>{
219
224
  ]
220
225
  };
221
226
  });
227
+ context.stateManager.onTestFileResult(result);
222
228
  reporters.map((reporter)=>reporter.onTestFileResult?.(result));
223
229
  return result;
224
230
  }));
package/dist/0~971.js CHANGED
@@ -7,23 +7,7 @@ const external_node_fs_ = __webpack_require__("node:fs");
7
7
  const external_node_path_ = __webpack_require__("node:path");
8
8
  const picocolors = __webpack_require__("../../node_modules/.pnpm/picocolors@1.1.1/node_modules/picocolors/picocolors.js");
9
9
  var picocolors_default = /*#__PURE__*/ __webpack_require__.n(picocolors);
10
- async function listTests(context, { filesOnly, json }) {
11
- const { rootPath } = context;
12
- const testEntries = {};
13
- const globTestSourceEntries = async (name)=>{
14
- if (testEntries[name]) return testEntries[name];
15
- const { include, exclude, includeSource, root } = context.projects.find((p)=>p.environmentName === name).normalizedConfig;
16
- const entries = await getTestEntries({
17
- include,
18
- exclude: exclude.patterns,
19
- rootPath,
20
- projectRoot: root,
21
- fileFilters: context.fileFilters || [],
22
- includeSource
23
- });
24
- testEntries[name] = entries;
25
- return entries;
26
- };
10
+ const collectTests = async ({ context, globTestSourceEntries })=>{
27
11
  const setupFiles = Object.fromEntries(context.projects.map((project)=>{
28
12
  const { environmentName, rootPath, normalizedConfig: { setupFiles } } = project;
29
13
  return [
@@ -40,7 +24,7 @@ async function listTests(context, { filesOnly, json }) {
40
24
  },
41
25
  setupFiles,
42
26
  rsbuildInstance,
43
- rootPath
27
+ rootPath: context.rootPath
44
28
  });
45
29
  const pool = await createPool({
46
30
  context
@@ -64,7 +48,60 @@ async function listTests(context, { filesOnly, json }) {
64
48
  assetNames
65
49
  };
66
50
  }));
67
- const list = returns.flatMap((r)=>r.list);
51
+ return {
52
+ list: returns.flatMap((r)=>r.list),
53
+ getSourceMap: async (name)=>{
54
+ const resource = returns.find((r)=>r.assetNames.includes(name));
55
+ return (await resource?.getSourceMaps([
56
+ name
57
+ ]))?.[name];
58
+ },
59
+ close: async ()=>{
60
+ await closeServer();
61
+ await pool.close();
62
+ }
63
+ };
64
+ };
65
+ const collectTestFiles = async ({ context, globTestSourceEntries })=>{
66
+ const list = [];
67
+ for (const project of context.projects){
68
+ const files = await globTestSourceEntries(project.environmentName);
69
+ list.push(...Object.values(files).map((testPath)=>({
70
+ testPath,
71
+ project: project.name,
72
+ tests: []
73
+ })));
74
+ }
75
+ return {
76
+ close: async ()=>{},
77
+ list,
78
+ getSourceMap: async (_name)=>null
79
+ };
80
+ };
81
+ async function listTests(context, { filesOnly, json }) {
82
+ const { rootPath } = context;
83
+ const testEntries = {};
84
+ const globTestSourceEntries = async (name)=>{
85
+ if (testEntries[name]) return testEntries[name];
86
+ const { include, exclude, includeSource, root } = context.projects.find((p)=>p.environmentName === name).normalizedConfig;
87
+ const entries = await getTestEntries({
88
+ include,
89
+ exclude: exclude.patterns,
90
+ rootPath,
91
+ projectRoot: root,
92
+ fileFilters: context.fileFilters || [],
93
+ includeSource
94
+ });
95
+ testEntries[name] = entries;
96
+ return entries;
97
+ };
98
+ const { list, close, getSourceMap } = filesOnly ? await collectTestFiles({
99
+ context,
100
+ globTestSourceEntries
101
+ }) : await collectTests({
102
+ context,
103
+ globTestSourceEntries
104
+ });
68
105
  const tests = [];
69
106
  const traverseTests = (test)=>{
70
107
  if ([
@@ -94,16 +131,12 @@ async function listTests(context, { filesOnly, json }) {
94
131
  if (file.errors?.length) {
95
132
  src_logger.log(`${picocolors_default().bgRed(' FAIL ')} ${relativePath}`);
96
133
  for (const error of file.errors)await printError(error, async (name)=>{
97
- const resource = returns.find((r)=>r.assetNames.includes(name));
98
- const sourceMap = (await resource?.getSourceMaps([
99
- name
100
- ]))?.[name];
134
+ const sourceMap = await getSourceMap(name);
101
135
  return sourceMap ? JSON.parse(sourceMap) : null;
102
136
  }, rootPath);
103
137
  }
104
138
  }
105
- await closeServer();
106
- await pool.close();
139
+ await close();
107
140
  return;
108
141
  }
109
142
  for (const file of list){
@@ -132,7 +165,6 @@ async function listTests(context, { filesOnly, json }) {
132
165
  const shortPath = (0, external_node_path_.relative)(rootPath, test.file);
133
166
  src_logger.log(test.name ? `${picocolors_default().dim(`${shortPath} > `)}${test.name}` : prettyTestPath(shortPath));
134
167
  }
135
- await closeServer();
136
- await pool.close();
168
+ await close();
137
169
  }
138
170
  export { listTests };
package/dist/index.js CHANGED
@@ -3,7 +3,7 @@ import 'module';
3
3
  import { __webpack_require__ } from "./rslib-runtime.js";
4
4
  import { EventEmitter } from "events";
5
5
  import { createRsbuild, loadConfig, logger, mergeRsbuildConfig } from "@rsbuild/core";
6
- import { basename, DEFAULT_CONFIG_EXTENSIONS, TS_CONFIG_FILE, DEFAULT_CONFIG_NAME, dirname, posix, resolve as pathe_M_eThtNZ_resolve, pathe_M_eThtNZ_relative, globalApis, formatTestPath, getAbsolutePath, filterProjects, formatRootStr, join, isDynamicPattern, glob, writeFile, castArray, src_logger, prettyTestPath, prettyTime, isDebug, isAbsolute, getTaskNameWithPrefix, formatError, normalize, TEMP_RSTEST_OUTPUT_DIR_GLOB } from "./857.js";
6
+ import { basename, DEFAULT_CONFIG_EXTENSIONS, TS_CONFIG_FILE, isTTY, dirname, posix, resolve as pathe_M_eThtNZ_resolve, pathe_M_eThtNZ_relative, DEFAULT_CONFIG_NAME, globalApis, formatTestPath, getAbsolutePath, filterProjects, join, formatRootStr, isDynamicPattern, glob, writeFile, castArray, src_logger, prettyTestPath, prettyTime, isDebug, isAbsolute, getTaskNameWithPrefix, formatError, normalize, TEMP_RSTEST_OUTPUT_DIR_GLOB } from "./857.js";
7
7
  import { decode } from "./597.js";
8
8
  function toArr(any) {
9
9
  return null == any ? [] : Array.isArray(any) ? any : [
@@ -500,13 +500,13 @@ function prepareCli() {
500
500
  if (!npm_execpath || npm_execpath.includes('npx-cli.js') || npm_execpath.includes('.bun')) console.log();
501
501
  }
502
502
  function showRstest() {
503
- src_logger.greet(" Rstest v0.6.3");
503
+ src_logger.greet(" Rstest v0.6.5");
504
504
  src_logger.log('');
505
505
  }
506
506
  const applyCommonOptions = (cli)=>{
507
507
  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`', {
508
508
  default: 'jiti'
509
- }).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('--logHeapUsage', 'Log heap usage after each test').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');
509
+ }).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('--logHeapUsage', 'Log heap usage after each test').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('--bail <number>', 'Stop running tests after n failures. Set to 0 to run all tests regardless of failures').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');
510
510
  };
511
511
  const runRest = async ({ options, filters, command })=>{
512
512
  let rstest;
@@ -544,7 +544,7 @@ const runRest = async ({ options, filters, command })=>{
544
544
  function setupCommands() {
545
545
  const cli = dist('rstest');
546
546
  cli.help();
547
- cli.version("0.6.3");
547
+ cli.version("0.6.5");
548
548
  applyCommonOptions(cli);
549
549
  cli.command('[...filters]', 'run tests').option('-w, --watch', 'Run tests in watch mode').action(async (filters, options)=>{
550
550
  showRstest();
@@ -697,6 +697,7 @@ const createDefaultConfig = ()=>({
697
697
  env: {},
698
698
  hideSkippedTests: false,
699
699
  logHeapUsage: false,
700
+ bail: 0,
700
701
  coverage: {
701
702
  exclude: [
702
703
  '**/node_modules/**',
@@ -707,9 +708,9 @@ const createDefaultConfig = ()=>({
707
708
  '**/__mocks__/**',
708
709
  '**/*.d.ts',
709
710
  '**/*.{test,spec}.[jt]s',
710
- '**/*.{test,spec}.[c|m][jt]s',
711
+ '**/*.{test,spec}.[cm][jt]s',
711
712
  '**/*.{test,spec}.[jt]sx',
712
- '**/*.{test,spec}.[c|m][jt]sx'
713
+ '**/*.{test,spec}.[cm][jt]sx'
713
714
  ],
714
715
  enabled: false,
715
716
  provider: 'istanbul',
@@ -771,7 +772,8 @@ async function resolveConfig(options) {
771
772
  'disableConsoleIntercept',
772
773
  'testEnvironment',
773
774
  'hideSkippedTests',
774
- 'logHeapUsage'
775
+ 'logHeapUsage',
776
+ 'bail'
775
777
  ];
776
778
  for (const key of keys)if (void 0 !== options[key]) config[key] = options[key];
777
779
  if (options.reporter) config.reporters = castArray(options.reporter);
@@ -1650,7 +1652,7 @@ class DefaultReporter {
1650
1652
  this.rootPath = rootPath;
1651
1653
  this.config = config;
1652
1654
  this.options = options;
1653
- if (!T) this.statusRenderer = new StatusRenderer(rootPath);
1655
+ if (isTTY()) this.statusRenderer = new StatusRenderer(rootPath);
1654
1656
  }
1655
1657
  onTestFileStart(test) {
1656
1658
  this.statusRenderer?.onTestFileStart(test.testPath);
@@ -2308,6 +2310,31 @@ class VerboseReporter extends DefaultReporter {
2308
2310
  });
2309
2311
  }
2310
2312
  }
2313
+ class TestStateManager {
2314
+ runningModules = new Map();
2315
+ testModules = [];
2316
+ onTestFileStart(testPath) {
2317
+ this.runningModules.set(testPath, []);
2318
+ }
2319
+ onTestCaseResult(result) {
2320
+ this.runningModules.set(result.testPath, [
2321
+ ...this.runningModules.get(result.testPath) || [],
2322
+ result
2323
+ ]);
2324
+ }
2325
+ getCountOfFailedTests() {
2326
+ const testResults = Array.from(this.runningModules.values()).flat().concat(this.testModules.flatMap((mod)=>mod.results));
2327
+ return testResults.filter((t)=>'fail' === t.status).length;
2328
+ }
2329
+ onTestFileResult(test) {
2330
+ this.runningModules.delete(test.testPath);
2331
+ this.testModules.push(test);
2332
+ }
2333
+ reset() {
2334
+ this.runningModules.clear();
2335
+ this.testModules = [];
2336
+ }
2337
+ }
2311
2338
  function formatEnvironmentName(name) {
2312
2339
  return name.replace(/[^a-zA-Z0-9\-_$]/g, '_');
2313
2340
  }
@@ -2322,11 +2349,11 @@ class Rstest {
2322
2349
  rootPath;
2323
2350
  originalConfig;
2324
2351
  normalizedConfig;
2325
- idMap = new Map();
2326
2352
  reporterResults = {
2327
2353
  results: [],
2328
2354
  testResults: []
2329
2355
  };
2356
+ stateManager = new TestStateManager();
2330
2357
  projects = [];
2331
2358
  constructor({ cwd = process.cwd(), command, fileFilters, configFilePath, projects }, userConfig){
2332
2359
  this.cwd = cwd;
@@ -2347,7 +2374,7 @@ class Rstest {
2347
2374
  });
2348
2375
  this.reporters = reporters;
2349
2376
  this.snapshotManager = snapshotManager;
2350
- this.version = "0.6.3";
2377
+ this.version = "0.6.5";
2351
2378
  this.rootPath = rootPath;
2352
2379
  this.originalConfig = userConfig;
2353
2380
  this.normalizedConfig = rstestConfig;
@@ -2355,9 +2382,11 @@ class Rstest {
2355
2382
  project.config.root = getAbsolutePath(rootPath, project.config.root);
2356
2383
  const config = withDefaultConfig(project.config);
2357
2384
  config.isolate = rstestConfig.isolate;
2358
- config.source ??= {};
2359
2385
  config.coverage = rstestConfig.coverage;
2360
- if (!config.source.tsconfigPath) {
2386
+ config.bail = rstestConfig.bail;
2387
+ config.source ??= {};
2388
+ if (config.source.tsconfigPath) config.source.tsconfigPath = getAbsolutePath(config.root, config.source.tsconfigPath);
2389
+ else {
2361
2390
  const tsconfigPath = join(config.root, TS_CONFIG_FILE);
2362
2391
  if ((0, external_node_fs_.existsSync)(tsconfigPath)) config.source.tsconfigPath = tsconfigPath;
2363
2392
  }
package/dist/worker.js CHANGED
@@ -7129,7 +7129,7 @@ const loadFiles = async ({ setupEntries, assetFiles, rstestContext, distPath, te
7129
7129
  };
7130
7130
  const runInPool = async (options)=>{
7131
7131
  isTeardown = false;
7132
- const { entryInfo: { distPath, testPath }, setupEntries, assets, type, context: { project, runtimeConfig: { isolate } } } = options;
7132
+ const { entryInfo: { distPath, testPath }, setupEntries, assets, type, context: { project, runtimeConfig: { isolate, bail } } } = options;
7133
7133
  const cleanups = [];
7134
7134
  const exit = process.exit.bind(process);
7135
7135
  process.exit = (code = process.exitCode || 0)=>{
@@ -7182,6 +7182,13 @@ const runInPool = async (options)=>{
7182
7182
  }
7183
7183
  try {
7184
7184
  const { rstestContext, runner, rpc, api, cleanup, unhandledErrors, interopDefault } = await preparePool(options);
7185
+ if (bail && await rpc.getCountOfFailedTests() >= bail) return {
7186
+ project,
7187
+ testPath,
7188
+ status: 'skip',
7189
+ name: '',
7190
+ results: []
7191
+ };
7185
7192
  const coverageProvider = await createCoverageProvider(options.context.runtimeConfig.coverage || {}, options.context.rootPath);
7186
7193
  if (coverageProvider) coverageProvider.init();
7187
7194
  const { assetFiles, sourceMaps: sourceMapsFromAssets } = assets || await rpc.getAssetsByEntry();
@@ -7202,7 +7209,8 @@ const runInPool = async (options)=>{
7202
7209
  const results = await runner.runTests(testPath, {
7203
7210
  onTestCaseResult: async (result)=>{
7204
7211
  await rpc.onTestCaseResult(result);
7205
- }
7212
+ },
7213
+ getCountOfFailedTests: async ()=>rpc.getCountOfFailedTests()
7206
7214
  }, api);
7207
7215
  if (unhandledErrors.length > 0) {
7208
7216
  results.status = 'fail';
@@ -1,4 +1,5 @@
1
1
  import type { assert as assert_2 } from 'chai';
2
+ import type { config } from 'chai';
2
3
  import { LoadConfigOptions } from '@rsbuild/core';
3
4
  import type { RsbuildConfig } from '@rsbuild/core';
4
5
  import type { RsbuildPlugin } from '@rsbuild/core';
@@ -272,6 +273,8 @@ declare type BuiltinReporterOptions = {
272
273
  default: DefaultReporterOptions;
273
274
  };
274
275
 
276
+ declare type ChaiConfig = Partial<Omit<typeof config, 'useProxy' | 'proxyExcludedKeys' | 'deepEqual'>>;
277
+
275
278
  declare interface CloverOptions extends FileOptions, ProjectOptions {}
276
279
 
277
280
  declare interface CoberturaOptions extends FileOptions, ProjectOptions {}
@@ -334,6 +337,7 @@ declare type CommonOptions = {
334
337
  maxConcurrency?: number;
335
338
  slowTestThreshold?: number;
336
339
  hideSkippedTests?: boolean;
340
+ bail?: number;
337
341
  };
338
342
 
339
343
  declare type CompareKeys = ((a: string, b: string) => number) | null | undefined;
@@ -634,20 +638,20 @@ export declare function defineProject(config: ProjectConfigSyncFn): ProjectConfi
634
638
 
635
639
  export declare function defineProject(config: ProjectConfigAsyncFn): ProjectConfigAsyncFn;
636
640
 
637
- export declare const describe: Rstest['describe'];
638
-
639
- declare type DescribeAPI = DescribeFn & {
641
+ export declare type Describe = DescribeFn & {
640
642
  each: DescribeEachFn;
641
643
  for: DescribeForFn;
642
- only: DescribeAPI;
643
- skip: DescribeAPI;
644
- runIf: (condition: boolean) => DescribeAPI;
645
- skipIf: (condition: boolean) => DescribeAPI;
646
- todo: DescribeAPI;
647
- concurrent: DescribeAPI;
648
- sequential: DescribeAPI;
644
+ only: Describe;
645
+ skip: Describe;
646
+ runIf: (condition: boolean) => Describe;
647
+ skipIf: (condition: boolean) => Describe;
648
+ todo: Describe;
649
+ concurrent: Describe;
650
+ sequential: Describe;
649
651
  };
650
652
 
653
+ export declare const describe: Rstest['describe'];
654
+
651
655
  declare interface DescribeEachFn {
652
656
  <T extends Record<string, unknown>>(cases: readonly T[]): (description: string, fn?: (param: T) => MaybePromise<void>) => void;
653
657
  <T extends readonly [unknown, ...unknown[]]>(cases: readonly T[]): (description: string, fn: (...args: [...T]) => MaybePromise<void>) => void;
@@ -712,6 +716,8 @@ declare interface EncodedSourceMap extends SourceMapV3 {
712
716
 
713
717
  declare type EncodedSourceMapXInput = EncodedSourceMap & XInput;
714
718
 
719
+ export declare type Expect = ExpectStatic;
720
+
715
721
  export declare const expect: Rstest['expect'];
716
722
 
717
723
  declare type ExpectationResult = SyncExpectationResult | AsyncExpectationResult;
@@ -1950,7 +1956,7 @@ declare type OnTestFinishedHandler = (params: {
1950
1956
  };
1951
1957
  }) => MaybePromise<void>;
1952
1958
 
1953
- declare type OptionalKeys = 'testNamePattern' | 'plugins' | 'source' | 'resolve' | 'output' | 'performance' | 'tools' | 'dev' | 'onConsoleLog' | 'resolveSnapshotPath';
1959
+ declare type OptionalKeys = 'testNamePattern' | 'plugins' | 'source' | 'resolve' | 'output' | 'performance' | 'tools' | 'dev' | 'onConsoleLog' | 'chaiConfig' | 'resolveSnapshotPath';
1954
1960
 
1955
1961
  declare type OptionsReceived = PrettyFormatOptions;
1956
1962
 
@@ -2007,7 +2013,7 @@ declare type Project = {
2007
2013
  configFilePath?: string;
2008
2014
  };
2009
2015
 
2010
- export declare type ProjectConfig = Omit<RstestConfig, 'projects' | 'reporters' | 'pool' | 'isolate' | 'coverage' | 'resolveSnapshotPath' | 'onConsoleLog' | 'hideSkippedTests'>;
2016
+ export declare type ProjectConfig = Omit<RstestConfig, 'projects' | 'reporters' | 'pool' | 'isolate' | 'coverage' | 'resolveSnapshotPath' | 'onConsoleLog' | 'hideSkippedTests' | 'bail'>;
2011
2017
 
2012
2018
  declare type ProjectConfigAsyncFn = () => Promise<ProjectConfig>;
2013
2019
 
@@ -2129,8 +2135,8 @@ export declare const rs: RstestUtilities;
2129
2135
 
2130
2136
  export { RsbuildPlugin }
2131
2137
 
2132
- declare type Rstest = RunnerAPI & {
2133
- expect: RstestExpect;
2138
+ export declare type Rstest = RunnerAPI & {
2139
+ expect: Expect;
2134
2140
  assert: typeof assert_2;
2135
2141
  rstest: RstestUtilities;
2136
2142
  rs: RstestUtilities;
@@ -2219,6 +2225,13 @@ export declare interface RstestConfig {
2219
2225
  * @default 'node'
2220
2226
  */
2221
2227
  testEnvironment?: 'node' | 'jsdom' | 'happy-dom';
2228
+ /**
2229
+ * Stop running tests after n failures.
2230
+ * Set to 0 to run all tests regardless of failures.
2231
+ *
2232
+ * @default 0
2233
+ */
2234
+ bail?: number;
2222
2235
  /**
2223
2236
  * print console traces when calling any console method.
2224
2237
  *
@@ -2320,6 +2333,10 @@ export declare interface RstestConfig {
2320
2333
  * Coverage options
2321
2334
  */
2322
2335
  coverage?: CoverageOptions;
2336
+ /**
2337
+ * chai configuration options
2338
+ */
2339
+ chaiConfig?: ChaiConfig;
2323
2340
  plugins?: RsbuildConfig['plugins'];
2324
2341
  source?: Pick<NonNullable<RsbuildConfig['source']>, 'define' | 'tsconfigPath' | 'decorators' | 'include' | 'exclude'>;
2325
2342
  performance?: Pick<NonNullable<RsbuildConfig['performance']>, 'bundleAnalyze'>;
@@ -2362,10 +2379,9 @@ declare type RstestContext = {
2362
2379
  command: RstestCommand;
2363
2380
  reporters: Reporter[];
2364
2381
  snapshotManager: SnapshotManager;
2382
+ stateManager: TestStateManager;
2365
2383
  };
2366
2384
 
2367
- declare type RstestExpect = ExpectStatic;
2368
-
2369
2385
  declare type RstestInstance = {
2370
2386
  context: RstestContext;
2371
2387
  runTests: () => Promise<void>;
@@ -2385,7 +2401,7 @@ declare type RstestPoolOptions = {
2385
2401
 
2386
2402
  declare type RstestPoolType = 'forks';
2387
2403
 
2388
- declare interface RstestUtilities {
2404
+ export declare interface RstestUtilities {
2389
2405
  /**
2390
2406
  * Creates a spy on a function.
2391
2407
  */
@@ -2512,7 +2528,7 @@ declare interface RstestUtilities {
2512
2528
  export declare function runCLI(): Promise<void>;
2513
2529
 
2514
2530
  declare type RunnerAPI = {
2515
- describe: DescribeAPI;
2531
+ describe: Describe;
2516
2532
  it: TestAPIs;
2517
2533
  test: TestAPIs;
2518
2534
  beforeAll: (fn: BeforeAllListener, timeout?: number) => MaybePromise<void>;
@@ -2523,7 +2539,7 @@ declare type RunnerAPI = {
2523
2539
  onTestFailed: (fn: OnTestFailedHandler, timeout?: number) => void;
2524
2540
  };
2525
2541
 
2526
- declare type RuntimeConfig = Pick<RstestContext['normalizedConfig'], 'testTimeout' | 'testNamePattern' | 'globals' | 'passWithNoTests' | 'retry' | 'clearMocks' | 'resetMocks' | 'restoreMocks' | 'unstubEnvs' | 'unstubGlobals' | 'maxConcurrency' | 'printConsoleTrace' | 'disableConsoleIntercept' | 'testEnvironment' | 'isolate' | 'hookTimeout' | 'coverage' | 'snapshotFormat' | 'env' | 'logHeapUsage'>;
2542
+ declare type RuntimeConfig = Pick<RstestContext['normalizedConfig'], 'testTimeout' | 'testNamePattern' | 'globals' | 'passWithNoTests' | 'retry' | 'clearMocks' | 'resetMocks' | 'restoreMocks' | 'unstubEnvs' | 'unstubGlobals' | 'maxConcurrency' | 'printConsoleTrace' | 'disableConsoleIntercept' | 'testEnvironment' | 'isolate' | 'hookTimeout' | 'coverage' | 'snapshotFormat' | 'env' | 'logHeapUsage' | 'bail' | 'chaiConfig'>;
2527
2543
 
2528
2544
  declare type RuntimeOptions = Partial<Pick<RuntimeConfig, 'testTimeout' | 'hookTimeout' | 'clearMocks' | 'resetMocks' | 'restoreMocks' | 'maxConcurrency' | 'retry'>>;
2529
2545
 
@@ -2758,7 +2774,7 @@ declare type TestAPIs<ExtraContext = object> = TestAPI<ExtraContext> & {
2758
2774
  declare type TestCallbackFn<ExtraContext = object> = (context: TestContext & ExtraContext) => MaybePromise<void>;
2759
2775
 
2760
2776
  declare type TestContext = {
2761
- expect: RstestExpect;
2777
+ expect: Expect;
2762
2778
  onTestFinished: RunnerAPI['onTestFinished'];
2763
2779
  onTestFailed: RunnerAPI['onTestFailed'];
2764
2780
  };
@@ -2813,6 +2829,16 @@ export declare type TestResult = {
2813
2829
 
2814
2830
  declare type TestResultStatus = 'skip' | 'pass' | 'fail' | 'todo';
2815
2831
 
2832
+ declare class TestStateManager {
2833
+ runningModules: Map<string, TestResult[]>;
2834
+ testModules: TestFileResult[];
2835
+ onTestFileStart(testPath: string): void;
2836
+ onTestCaseResult(result: TestResult): void;
2837
+ getCountOfFailedTests(): number;
2838
+ onTestFileResult(test: TestFileResult): void;
2839
+ reset(): void;
2840
+ }
2841
+
2816
2842
  declare type TextLcovOptions = ProjectOptions;
2817
2843
 
2818
2844
  declare interface TextOptions extends FileOptions {
@@ -1,3 +1,4 @@
1
+ import type { config } from 'chai';
1
2
  import type { RsbuildConfig } from '@rsbuild/core';
2
3
 
3
4
  /**
@@ -259,6 +260,8 @@ declare type BuiltinReporterOptions = {
259
260
  default: DefaultReporterOptions;
260
261
  };
261
262
 
263
+ declare type ChaiConfig = Partial<Omit<typeof config, 'useProxy' | 'proxyExcludedKeys' | 'deepEqual'>>;
264
+
262
265
  declare interface CloverOptions extends FileOptions, ProjectOptions {}
263
266
 
264
267
  declare interface CoberturaOptions extends FileOptions, ProjectOptions {}
@@ -1614,7 +1617,7 @@ declare type OnTestFinishedHandler = (params: {
1614
1617
  };
1615
1618
  }) => MaybePromise<void>;
1616
1619
 
1617
- declare type OptionalKeys = 'testNamePattern' | 'plugins' | 'source' | 'resolve' | 'output' | 'performance' | 'tools' | 'dev' | 'onConsoleLog' | 'resolveSnapshotPath';
1620
+ declare type OptionalKeys = 'testNamePattern' | 'plugins' | 'source' | 'resolve' | 'output' | 'performance' | 'tools' | 'dev' | 'onConsoleLog' | 'chaiConfig' | 'resolveSnapshotPath';
1618
1621
 
1619
1622
  declare type OptionsReceived = PrettyFormatOptions;
1620
1623
 
@@ -1664,7 +1667,7 @@ declare function printWithType<T>(name: string, value: T, print: (value: T) => s
1664
1667
 
1665
1668
  declare type Procedure = (...args: any[]) => any;
1666
1669
 
1667
- declare type ProjectConfig = Omit<RstestConfig, 'projects' | 'reporters' | 'pool' | 'isolate' | 'coverage' | 'resolveSnapshotPath' | 'onConsoleLog' | 'hideSkippedTests'>;
1670
+ declare type ProjectConfig = Omit<RstestConfig, 'projects' | 'reporters' | 'pool' | 'isolate' | 'coverage' | 'resolveSnapshotPath' | 'onConsoleLog' | 'hideSkippedTests' | 'bail'>;
1668
1671
 
1669
1672
  declare type ProjectContext = {
1670
1673
  name: string;
@@ -1859,6 +1862,13 @@ declare interface RstestConfig {
1859
1862
  * @default 'node'
1860
1863
  */
1861
1864
  testEnvironment?: 'node' | 'jsdom' | 'happy-dom';
1865
+ /**
1866
+ * Stop running tests after n failures.
1867
+ * Set to 0 to run all tests regardless of failures.
1868
+ *
1869
+ * @default 0
1870
+ */
1871
+ bail?: number;
1862
1872
  /**
1863
1873
  * print console traces when calling any console method.
1864
1874
  *
@@ -1960,6 +1970,10 @@ declare interface RstestConfig {
1960
1970
  * Coverage options
1961
1971
  */
1962
1972
  coverage?: CoverageOptions;
1973
+ /**
1974
+ * chai configuration options
1975
+ */
1976
+ chaiConfig?: ChaiConfig;
1963
1977
  plugins?: RsbuildConfig['plugins'];
1964
1978
  source?: Pick<NonNullable<RsbuildConfig['source']>, 'define' | 'tsconfigPath' | 'decorators' | 'include' | 'exclude'>;
1965
1979
  performance?: Pick<NonNullable<RsbuildConfig['performance']>, 'bundleAnalyze'>;
@@ -1996,6 +2010,7 @@ declare type RstestContext = {
1996
2010
  command: RstestCommand;
1997
2011
  reporters: Reporter[];
1998
2012
  snapshotManager: SnapshotManager;
2013
+ stateManager: TestStateManager;
1999
2014
  };
2000
2015
 
2001
2016
  declare type RstestExpect = ExpectStatic;
@@ -2031,7 +2046,7 @@ declare type RunnerAPI = {
2031
2046
  onTestFailed: (fn: OnTestFailedHandler, timeout?: number) => void;
2032
2047
  };
2033
2048
 
2034
- declare type RuntimeConfig = Pick<RstestContext['normalizedConfig'], 'testTimeout' | 'testNamePattern' | 'globals' | 'passWithNoTests' | 'retry' | 'clearMocks' | 'resetMocks' | 'restoreMocks' | 'unstubEnvs' | 'unstubGlobals' | 'maxConcurrency' | 'printConsoleTrace' | 'disableConsoleIntercept' | 'testEnvironment' | 'isolate' | 'hookTimeout' | 'coverage' | 'snapshotFormat' | 'env' | 'logHeapUsage'>;
2049
+ declare type RuntimeConfig = Pick<RstestContext['normalizedConfig'], 'testTimeout' | 'testNamePattern' | 'globals' | 'passWithNoTests' | 'retry' | 'clearMocks' | 'resetMocks' | 'restoreMocks' | 'unstubEnvs' | 'unstubGlobals' | 'maxConcurrency' | 'printConsoleTrace' | 'disableConsoleIntercept' | 'testEnvironment' | 'isolate' | 'hookTimeout' | 'coverage' | 'snapshotFormat' | 'env' | 'logHeapUsage' | 'bail' | 'chaiConfig'>;
2035
2050
 
2036
2051
  /** Runtime to Server */
2037
2052
  declare type RuntimeRPC = {
@@ -2041,6 +2056,7 @@ declare type RuntimeRPC = {
2041
2056
  sourceMaps: Record<string, string>;
2042
2057
  }>;
2043
2058
  onTestCaseResult: (result: TestResult) => Promise<void>;
2059
+ getCountOfFailedTests: () => Promise<number>;
2044
2060
  onConsoleLog: (log: UserConsoleLog) => void;
2045
2061
  resolveSnapshotPath: (filepath: string) => string;
2046
2062
  };
@@ -2396,6 +2412,16 @@ declare type TestResultStatus = 'skip' | 'pass' | 'fail' | 'todo';
2396
2412
 
2397
2413
  declare type TestRunMode = 'run' | 'skip' | 'todo' | 'only';
2398
2414
 
2415
+ declare class TestStateManager {
2416
+ runningModules: Map<string, TestResult[]>;
2417
+ testModules: TestFileResult[];
2418
+ onTestFileStart(testPath: string): void;
2419
+ onTestCaseResult(result: TestResult): void;
2420
+ getCountOfFailedTests(): number;
2421
+ onTestFileResult(test: TestFileResult): void;
2422
+ reset(): void;
2423
+ }
2424
+
2399
2425
  declare type TestSuite = {
2400
2426
  name: string;
2401
2427
  parentNames?: string[];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rstest/core",
3
- "version": "0.6.3",
3
+ "version": "0.6.5",
4
4
  "description": "The Rsbuild-based test tool.",
5
5
  "bugs": {
6
6
  "url": "https://github.com/web-infra-dev/rstest/issues"