@rspack/test-tools 1.6.0 → 1.6.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/README.md +1 -1
  2. package/dist/case/common.js +2 -2
  3. package/dist/case/defaults.d.ts +1 -1
  4. package/dist/case/defaults.js +1 -1
  5. package/dist/case/diagnostic.js +3 -3
  6. package/dist/case/esm-output.js +1 -1
  7. package/dist/case/hash.js +5 -2
  8. package/dist/case/hook.js +1 -1
  9. package/dist/case/hot-step.js +4 -3
  10. package/dist/case/stats-output.js +1 -1
  11. package/dist/helper/directory.d.ts +1 -1
  12. package/dist/helper/expect/to-match-file-snapshot.d.ts +1 -1
  13. package/dist/helper/expect/to-match-file-snapshot.js +2 -2
  14. package/dist/helper/legacy/createLazyTestEnv.d.ts +3 -3
  15. package/dist/helper/legacy/createLazyTestEnv.js +2 -3
  16. package/dist/helper/setup-env.js +0 -4
  17. package/dist/helper/setup-expect.js +1 -1
  18. package/dist/helper/setup-wasm.js +2 -2
  19. package/dist/runner/node/index.d.ts +0 -1
  20. package/dist/runner/node/index.js +22 -54
  21. package/dist/runner/web/index.d.ts +4 -2
  22. package/dist/runner/web/index.js +61 -18
  23. package/dist/test/creator.js +4 -6
  24. package/dist/type.d.ts +4 -3
  25. package/dist/type.js +1 -1
  26. package/package.json +5 -8
  27. package/rstest.d.ts +24 -0
  28. package/dist/jest/ignore-snapshot-default-reporter.d.ts +0 -2
  29. package/dist/jest/ignore-snapshot-default-reporter.js +0 -57
  30. package/dist/jest/ignore-snapshot-summary-reporter.d.ts +0 -2
  31. package/dist/jest/ignore-snapshot-summary-reporter.js +0 -24
  32. package/dist/jest/patch-node-env.d.ts +0 -5
  33. package/dist/jest/patch-node-env.js +0 -18
  34. package/dist/jest/slash.d.ts +0 -2
  35. package/dist/jest/slash.js +0 -16
  36. package/jest.d.ts +0 -27
package/README.md CHANGED
@@ -16,7 +16,7 @@ We expect to reuse the tests for Rspack wasm target as many as possible and we h
16
16
  2. Set `maxWorkers` to `1`, `maxConcurrency` to `1` and disable concurrent mode to avoid flaky failures.
17
17
  3. `forceExit` is needed.
18
18
 
19
- Also check all the skipped testcases with `!process.env.WASM` in `test.filter.js`s and the skipped testsuits in `jest.config.js`s. They are divided into two categories:
19
+ Also check all the skipped testcases with `!process.env.WASM` in `test.filter.js`s and the skipped testsuits in `rstest.config.ts`s. They are divided into two categories:
20
20
 
21
21
  1. Skip due to lacks of api support, such as tests related to swc wasm plugins, pnp and profiling. We skip them to avoid obsolete snapshot errors.
22
22
  2. Skip temporarily and should be investigate in the future. There could be something wrong with test harness and rspack wasm itself. Since it could be time-consuming to figure out all of them so in this stage we use the wasm test ci to avoid the regression rather than improve its stability.
@@ -132,7 +132,7 @@ async function check(env, context, name) {
132
132
  }
133
133
  async function checkSnapshot(env, context, name, snapshot, filter) {
134
134
  if (path_1.default.extname(snapshot) === ".snap") {
135
- throw new Error("Snapshot with `.snap` will be managed by jest, please use `.snap.txt` instead");
135
+ throw new Error("Snapshot with `.snap` will be managed by rstest, please use `.snap.txt` instead");
136
136
  }
137
137
  const compilerManager = context.getCompiler();
138
138
  const stats = compilerManager.getStats();
@@ -176,7 +176,7 @@ async function checkSnapshot(env, context, name, snapshot, filter) {
176
176
  const snapshotPath = path_1.default.isAbsolute(snapshot)
177
177
  ? snapshot
178
178
  : path_1.default.resolve(context.getSource(), path_1.default.join("__snapshots__", `${snapshot}${total > 1 ? `-${i}` : ""}`));
179
- env.expect(content).toMatchFileSnapshot(snapshotPath);
179
+ env.expect(content).toMatchFileSnapshotSync(snapshotPath);
180
180
  }
181
181
  }
182
182
  async function afterExecute(context, name) {
@@ -5,7 +5,7 @@ export declare function getRspackDefaultConfig(cwd: string, config: RspackOption
5
5
  export type TDefaultsCaseConfig = {
6
6
  options?: (context: ITestContext) => RspackOptions;
7
7
  cwd?: string;
8
- diff: (diff: jest.JestMatchers<RspackTestDiff>, defaults: jest.JestMatchers<RspackOptions>) => Promise<void>;
8
+ diff: (diff: Assertion<RspackTestDiff>, defaults: Assertion<RspackOptions>) => Promise<void>;
9
9
  description: string;
10
10
  };
11
11
  declare class RspackTestDiff {
@@ -88,7 +88,7 @@ async function run(name, processor) {
88
88
  context.emitError(e);
89
89
  }
90
90
  finally {
91
- await processor.check?.({ expect, it, beforeEach, afterEach, jest: global.jest || global.rstest }, context);
91
+ await processor.check?.({ expect, it, beforeEach, afterEach, rstest }, context);
92
92
  await processor.after?.(context);
93
93
  }
94
94
  }
@@ -130,7 +130,7 @@ async function check(env, context, name, options) {
130
130
  const errorOutputPath = node_path_1.default.resolve(context.getSource(options.snapshot));
131
131
  const errorStatsOutputPath = node_path_1.default.resolve(context.getSource(options.snapshotErrors));
132
132
  const warningStatsOutputPath = node_path_1.default.resolve(context.getSource(options.snapshotWarning));
133
- env.expect(output).toMatchFileSnapshot(errorOutputPath);
134
- env.expect(errors).toMatchFileSnapshot(errorStatsOutputPath);
135
- env.expect(warnings).toMatchFileSnapshot(warningStatsOutputPath);
133
+ env.expect(output).toMatchFileSnapshotSync(errorOutputPath);
134
+ env.expect(errors).toMatchFileSnapshotSync(errorStatsOutputPath);
135
+ env.expect(warnings).toMatchFileSnapshotSync(warningStatsOutputPath);
136
136
  }
@@ -35,7 +35,7 @@ const creator = new creator_1.BasicCaseCreator({
35
35
  target = plugin;
36
36
  }
37
37
  return !isTarget;
38
- });
38
+ }) ?? [];
39
39
  options.plugins = [
40
40
  ...otherPlugins,
41
41
  new core_1.default.experiments.EsmLibraryPlugin({
package/dist/case/hash.js CHANGED
@@ -72,8 +72,11 @@ async function check(env, context, name) {
72
72
  const stats = compiler.getStats();
73
73
  const testConfig = context.getTestConfig();
74
74
  if (!stats) {
75
- env.expect(false);
76
- return;
75
+ throw new Error("No stats found\n" +
76
+ context
77
+ .getError()
78
+ .map(e => e.stack)
79
+ .join("\n"));
77
80
  }
78
81
  if (REG_ERROR_CASE.test(name)) {
79
82
  env.expect(stats.hasErrors());
package/dist/case/hook.js CHANGED
@@ -189,7 +189,7 @@ class HookCasesContext extends context_1.TestContext {
189
189
  }, "");
190
190
  env
191
191
  .expect(snapshots)
192
- .toMatchFileSnapshot(node_path_1.default.join(this.src, "hooks.snap.txt"), options);
192
+ .toMatchFileSnapshotSync(node_path_1.default.join(this.src, "hooks.snap.txt"), options);
193
193
  }
194
194
  }
195
195
  exports.HookCasesContext = HookCasesContext;
@@ -96,8 +96,9 @@ function createHotStepProcessor(name, src, temp, target) {
96
96
  return str.split(raw).join(replacement);
97
97
  }, str);
98
98
  };
99
- const fileList = stats
100
- .assets.map(i => {
99
+ const assets = stats.assets.sort((a, b) => a.name.localeCompare(b.name));
100
+ const fileList = assets
101
+ .map(i => {
101
102
  const fileName = i.name;
102
103
  const renderName = replaceFileName(fileName);
103
104
  const content = replaceContent(fs_extra_1.default.readFileSync(context.getDist(fileName), "utf-8"));
@@ -238,7 +239,7 @@ ${runtime.javascript.disposedModules.map(i => `- ${i}`).join("\n")}
238
239
  return match.replace(capture, "PORT");
239
240
  })
240
241
  .trim();
241
- env.expect(content).toMatchFileSnapshot(snapshotPath);
242
+ env.expect(content).toMatchFileSnapshotSync(snapshotPath);
242
243
  }
243
244
  const originRun = processor.run;
244
245
  processor.run = async function (env, context) {
@@ -180,7 +180,7 @@ async function check(env, context, name, writeStatsOuptut, snapshot, stderr) {
180
180
  const snapshotPath = node_path_1.default.isAbsolute(snapshot)
181
181
  ? snapshot
182
182
  : node_path_1.default.resolve(context.getSource(), `./__snapshots__/${snapshot}`);
183
- env.expect(new RspackStats(actual)).toMatchFileSnapshot(snapshotPath);
183
+ env.expect(new RspackStats(actual)).toMatchFileSnapshotSync(snapshotPath);
184
184
  const testConfig = context.getTestConfig();
185
185
  if (typeof testConfig?.validate === "function") {
186
186
  testConfig.validate(stats, stderr.toString());
@@ -7,6 +7,6 @@ export declare function describeByWalk(testFile: string, createCase: (name: stri
7
7
  source?: string;
8
8
  dist?: string;
9
9
  absoluteDist?: boolean;
10
- describe?: jest.Describe;
10
+ describe?: Describe;
11
11
  exclude?: RegExp[];
12
12
  }): void;
@@ -5,7 +5,7 @@
5
5
  * @param filepath Path to the file to match against
6
6
  * @param options Additional options for matching
7
7
  */
8
- export declare function toMatchFileSnapshot(this: {
8
+ export declare function toMatchFileSnapshotSync(this: {
9
9
  testPath: string;
10
10
  currentTestName: string;
11
11
  assertionCalls: number;
@@ -4,7 +4,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  return (mod && mod.__esModule) ? mod : { "default": mod };
5
5
  };
6
6
  Object.defineProperty(exports, "__esModule", { value: true });
7
- exports.toMatchFileSnapshot = toMatchFileSnapshot;
7
+ exports.toMatchFileSnapshotSync = toMatchFileSnapshotSync;
8
8
  /* istanbul ignore file */
9
9
  const node_fs_1 = __importDefault(require("node:fs"));
10
10
  const node_path_1 = __importDefault(require("node:path"));
@@ -29,7 +29,7 @@ const isEqual = (a, b) => {
29
29
  * @param filepath Path to the file to match against
30
30
  * @param options Additional options for matching
31
31
  */
32
- function toMatchFileSnapshot(rawContent, filepath, options = {}) {
32
+ function toMatchFileSnapshotSync(rawContent, filepath, options = {}) {
33
33
  const content = Buffer.isBuffer(rawContent)
34
34
  ? rawContent
35
35
  : serialize(rawContent, /* ident */ 2, {
@@ -4,8 +4,8 @@ declare function _exports(globalTimeout?: number, nameSuffix?: string): {
4
4
  it(...args: any[]): void;
5
5
  beforeEach(...args: any[]): void;
6
6
  afterEach(...args: any[]): void;
7
- expect: jest.Expect;
8
- jest: typeof jest;
9
- rstest: typeof jest;
7
+ /** @type {import('@rstest/core').Expect} */
8
+ expect: import("@rstest/core").Expect;
9
+ rstest: import("@rstest/core", { with: { "resolution-mode": "import" } }).RstestUtilities;
10
10
  };
11
11
  export = _exports;
@@ -109,9 +109,8 @@ module.exports = (globalTimeout = 2000, nameSuffix = "") => {
109
109
  fixAsyncError(currentDescribeBlock.hooks[currentDescribeBlock.hooks.length - 1]);
110
110
  });
111
111
  },
112
+ /** @type {import('@rstest/core').Expect} */
112
113
  expect,
113
- jest,
114
- // Compatible with rstest
115
- rstest: global.rstest || global.jest
114
+ rstest,
116
115
  };
117
116
  };
@@ -18,10 +18,6 @@ if (process.env.RSTEST) {
18
18
  global.__RSPACK_TEST_TOOLS_PATH__ ??= process.env.__RSPACK_TEST_TOOLS_PATH__;
19
19
  global.__DEBUG__ ??= process.env.DEBUG === "test";
20
20
  }
21
- else {
22
- // Compatible with wasm tests (lazyTestEnv)
23
- global.rstest = jest;
24
- }
25
21
  if (process.env.ALTERNATIVE_SORT) {
26
22
  const oldSort = Array.prototype.sort;
27
23
  Array.prototype.sort = function (cmp) {
@@ -7,7 +7,7 @@ const serializers_1 = require("./serializers");
7
7
  expect.extend({
8
8
  // CHANGE: new test matcher for `rspack-test-tools`
9
9
  // @ts-expect-error
10
- toMatchFileSnapshot: to_match_file_snapshot_1.toMatchFileSnapshot,
10
+ toMatchFileSnapshotSync: to_match_file_snapshot_1.toMatchFileSnapshotSync,
11
11
  toBeTypeOf: to_be_typeof_1.toBeTypeOf,
12
12
  toEndWith: to_end_with_1.toEndWith
13
13
  });
@@ -9,11 +9,11 @@ function toMatchSnapshot() {
9
9
  function toMatchInlineSnapshot() {
10
10
  return { pass: true, message: () => "" };
11
11
  }
12
- function toMatchFileSnapshot() {
12
+ function toMatchFileSnapshotSync() {
13
13
  return { pass: true, message: () => "" };
14
14
  }
15
15
  expect.extend({
16
16
  toMatchSnapshot,
17
17
  toMatchInlineSnapshot,
18
- toMatchFileSnapshot
18
+ toMatchFileSnapshotSync
19
19
  });
@@ -39,4 +39,3 @@ export declare class NodeRunner implements ITestRunner {
39
39
  protected createCjsRequirer(): TRunnerRequirer;
40
40
  protected createEsmRequirer(): TRunnerRequirer;
41
41
  }
42
- export declare const createLocatedError: (collectedErrors: Error[], offset: number) => (e: Error, file: TRunnerFile) => Error;
@@ -36,7 +36,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
36
36
  return (mod && mod.__esModule) ? mod : { "default": mod };
37
37
  };
38
38
  Object.defineProperty(exports, "__esModule", { value: true });
39
- exports.createLocatedError = exports.NodeRunner = void 0;
39
+ exports.NodeRunner = void 0;
40
40
  const node_fs_1 = __importDefault(require("node:fs"));
41
41
  const node_path_1 = __importDefault(require("node:path"));
42
42
  const node_url_1 = require("node:url");
@@ -45,7 +45,6 @@ const asModule_1 = __importDefault(require("../../helper/legacy/asModule"));
45
45
  const createFakeWorker_1 = __importDefault(require("../../helper/legacy/createFakeWorker"));
46
46
  const urlToRelativePath_1 = __importDefault(require("../../helper/legacy/urlToRelativePath"));
47
47
  const type_1 = require("../../type");
48
- const EVAL_LOCATION_REGEX = /<anonymous>:(\d+)/;
49
48
  const isRelativePath = (p) => /^\.\.?\//.test(p);
50
49
  const getSubPath = (p) => {
51
50
  const lastSlash = p.lastIndexOf("/");
@@ -179,6 +178,7 @@ class NodeRunner {
179
178
  Buffer,
180
179
  setImmediate,
181
180
  self: this.globalContext,
181
+ __TEST_PATH__: __TEST_PATH__,
182
182
  __MODE__: this._options.compilerOptions.mode,
183
183
  __SNAPSHOT__: node_path_1.default.join(this._options.source, "__snapshot__"),
184
184
  Worker: (0, createFakeWorker_1.default)(this._options.env, {
@@ -347,37 +347,31 @@ class NodeRunner {
347
347
  currentModuleScope.__STATS_I__ = statsIndex;
348
348
  }
349
349
  }
350
- const createNodeLocatedError = (0, exports.createLocatedError)(this._options.errors || [], 2);
351
- const originIt = currentModuleScope.it;
352
- currentModuleScope.it = (description, fn) => {
353
- originIt(description, async () => {
354
- try {
355
- await fn();
356
- }
357
- catch (err) {
358
- throw createNodeLocatedError(err, file);
359
- }
360
- });
361
- };
362
- currentModuleScope.__CREATE_LOCATED_ERROR__ = createNodeLocatedError;
363
- currentModuleScope.__FILE__ = file;
364
350
  const args = Object.keys(currentModuleScope);
365
351
  const argValues = args.map(arg => currentModuleScope[arg]);
366
352
  const code = `(function(${args.join(", ")}) {
367
- try {
368
- ${file.content}
369
- } catch(err) {
370
- throw __CREATE_LOCATED_ERROR__(err, __FILE__);
371
- }
353
+ ${file.content}
372
354
  })`;
373
355
  this.preExecute(code, file);
374
356
  this.log(`run mode: ${this._options.runInNewContext ? "new context" : "this context"}`);
375
- const fn = this._options.runInNewContext
376
- ? node_vm_1.default.runInNewContext(code, this.globalContext)
377
- : node_vm_1.default.runInThisContext(code);
378
- fn.call(this._options.testConfig.nonEsmThis
379
- ? this._options.testConfig.nonEsmThis(modulePath)
380
- : m.exports, ...argValues);
357
+ try {
358
+ const fn = this._options.runInNewContext
359
+ ? node_vm_1.default.runInNewContext(code, this.globalContext, {
360
+ filename: file.path,
361
+ lineOffset: -1
362
+ })
363
+ : node_vm_1.default.runInThisContext(code, {
364
+ filename: file.path,
365
+ lineOffset: -1
366
+ });
367
+ fn.call(this._options.testConfig.nonEsmThis
368
+ ? this._options.testConfig.nonEsmThis(modulePath)
369
+ : m.exports, ...argValues);
370
+ }
371
+ catch (e) {
372
+ this._options.errors?.push(e);
373
+ throw e;
374
+ }
381
375
  this.postExecute(m, file);
382
376
  this.log(`end cjs: ${modulePath}`);
383
377
  return m.exports;
@@ -391,7 +385,7 @@ class NodeRunner {
391
385
  const esmIdentifier = this._options.name;
392
386
  return (currentDirectory, modulePath, context = {}) => {
393
387
  if (!node_vm_1.SourceTextModule) {
394
- throw new Error("Running this test requires '--experimental-vm-modules'.\nRun with 'node --experimental-vm-modules node_modules/jest-cli/bin/jest'.");
388
+ throw new Error("Running this test requires '--experimental-vm-modules'.\nRun with 'node --experimental-vm-modules node_modules/@rstest/core/bin/rstest'.");
395
389
  }
396
390
  const _require = this.getRequire();
397
391
  const file = context.file || this.getFile(modulePath, currentDirectory);
@@ -454,29 +448,3 @@ class NodeRunner {
454
448
  }
455
449
  }
456
450
  exports.NodeRunner = NodeRunner;
457
- const createLocatedError = (collectedErrors, offset) => {
458
- return (e, file) => {
459
- const match = (e.stack || e.message).match(EVAL_LOCATION_REGEX);
460
- if (match) {
461
- const [, line] = match;
462
- const realLine = Number(line) - offset;
463
- const codeLines = file.content.split("\n");
464
- const lineContents = [
465
- ...codeLines
466
- .slice(Math.max(0, realLine - 3), Math.max(0, realLine - 1))
467
- .map(line => `│ ${line}`),
468
- `│> ${codeLines[realLine - 1]}`,
469
- ...codeLines.slice(realLine, realLine + 2).map(line => `│ ${line}`)
470
- ];
471
- const message = `Error in JSDOM when running file '${file.path}' at line ${realLine}: ${e.message}\n${lineContents.join("\n")}`;
472
- const finalError = new Error(message);
473
- finalError.stack = undefined;
474
- collectedErrors.push(finalError);
475
- return finalError;
476
- }
477
- else {
478
- return e;
479
- }
480
- };
481
- };
482
- exports.createLocatedError = createLocatedError;
@@ -11,7 +11,7 @@ export declare class WebRunner extends NodeRunner {
11
11
  getGlobal(name: string): unknown;
12
12
  protected log(message: string): void;
13
13
  protected createResourceLoader(): {
14
- fetch(url: string, _: {
14
+ fetch(url: string, options: {
15
15
  element: HTMLScriptElement;
16
16
  }): any;
17
17
  };
@@ -21,8 +21,10 @@ export declare class WebRunner extends NodeRunner {
21
21
  {
22
22
  exports: Record<string, unknown>;
23
23
  },
24
- string
24
+ string,
25
+ number
25
26
  ];
26
27
  protected createJSDOMRequirer(): TRunnerRequirer;
27
28
  protected createRunner(): void;
28
29
  }
30
+ export declare const createLocatedError: (collectedErrors: Error[], offset: number) => (e: Error, file: TRunnerFile) => Error;
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.WebRunner = void 0;
6
+ exports.createLocatedError = exports.WebRunner = void 0;
7
7
  const node_fs_1 = __importDefault(require("node:fs"));
8
8
  const node_path_1 = __importDefault(require("node:path"));
9
9
  const node_url_1 = require("node:url");
@@ -90,7 +90,18 @@ class WebRunner extends node_1.NodeRunner {
90
90
  createResourceLoader() {
91
91
  const that = this;
92
92
  class CustomResourceLoader extends jsdom_1.ResourceLoader {
93
- fetch(url, _) {
93
+ fetch(url, options) {
94
+ if (that._options.testConfig.resourceLoader) {
95
+ that.log(`resource custom loader: start ${url}`);
96
+ const content = that._options.testConfig.resourceLoader(url, options.element);
97
+ if (content !== undefined) {
98
+ that.log(`resource custom loader: accepted`);
99
+ return Promise.resolve(content);
100
+ }
101
+ else {
102
+ that.log(`resource custom loader: not found`);
103
+ }
104
+ }
94
105
  const filePath = that.urlToPath(url);
95
106
  that.log(`resource loader: ${url} -> ${filePath}`);
96
107
  let finalCode;
@@ -234,15 +245,16 @@ class WebRunner extends node_1.NodeRunner {
234
245
  return Reflect.set(target, prop, value, receiver);
235
246
  }
236
247
  });`;
237
- const createJSDOMLocatedError = (0, node_1.createLocatedError)(this._options.errors || [], proxyCode.split("\n").length + 2);
248
+ const proxyLines = proxyCode.split("\n");
249
+ const locatedError = (0, exports.createLocatedError)(this._options.errors || [], proxyLines.length + 1);
238
250
  const originIt = currentModuleScope.it;
239
251
  currentModuleScope.it = (description, fn) => {
240
- originIt(description, async () => {
252
+ return originIt(description, async (...args) => {
241
253
  try {
242
- await fn();
254
+ return await fn(...args);
243
255
  }
244
- catch (err) {
245
- throw createJSDOMLocatedError(err, file);
256
+ catch (e) {
257
+ throw locatedError(e, file);
246
258
  }
247
259
  });
248
260
  };
@@ -253,18 +265,17 @@ class WebRunner extends node_1.NodeRunner {
253
265
  .join(", ");
254
266
  this.dom.window[scopeKey] = currentModuleScope;
255
267
  this.dom.window["__GLOBAL_SHARED__"] = this.globalContext;
268
+ this.dom.window["__LOCATED_ERROR__"] = locatedError;
256
269
  this.dom.window["__FILE__"] = file;
257
- this.dom.window["__CREATE_LOCATED_ERROR__"] = createJSDOMLocatedError;
258
270
  return [
259
271
  m,
260
272
  `${proxyCode}
261
- (function(window, self, globalThis, console, ${args.join(", ")}) {
262
- try {
263
- ${file.content}
264
- } catch (err) {
265
- throw __CREATE_LOCATED_ERROR__(err, __FILE__);
266
- }
267
- })($$g$$, $$self$$, $$g$$, window["console"], ${argValues});`
273
+ (function(window, self, globalThis, console, ${args.join(", ")}) { try {
274
+ ${file.content}
275
+ } catch (e) {
276
+ throw __LOCATED_ERROR__(e, window["__FILE__"]);
277
+ }})($$g$$, $$self$$, $$g$$, window["console"], ${argValues});`,
278
+ proxyLines.length + 1
268
279
  ];
269
280
  }
270
281
  createJSDOMRequirer() {
@@ -277,15 +288,21 @@ class WebRunner extends node_1.NodeRunner {
277
288
  if (file.path in this.requireCache) {
278
289
  return this.requireCache[file.path].exports;
279
290
  }
280
- const [m, code] = this.getModuleContent(file);
291
+ const [m, code, lineOffset] = this.getModuleContent(file);
281
292
  this.preExecute(code, file);
282
293
  try {
283
294
  const script = new node_vm_1.Script(code);
284
295
  const vmContext = this.dom.getInternalVMContext();
285
- script.runInContext(vmContext);
296
+ script.runInContext(vmContext, {
297
+ filename: file.path,
298
+ lineOffset: -lineOffset
299
+ });
286
300
  }
287
301
  catch (e) {
288
- throw new Error(`Parse script '${file.path}' failed: ${e.message}`);
302
+ const error = new Error(`Parse script '${file.path}' failed:\n${e.message}`);
303
+ error.stack = `${error.message}\n${e.stack}`;
304
+ this._options.errors?.push(error);
305
+ throw error;
289
306
  }
290
307
  this.postExecute(m, file);
291
308
  this.requireCache[file.path] = m;
@@ -298,3 +315,29 @@ class WebRunner extends node_1.NodeRunner {
298
315
  }
299
316
  }
300
317
  exports.WebRunner = WebRunner;
318
+ const createLocatedError = (collectedErrors, offset) => {
319
+ return (e, file) => {
320
+ const match = (e.stack || e.message).match(/<anonymous>:(\d+)/);
321
+ if (match) {
322
+ const [, line] = match;
323
+ const realLine = Number(line) - offset;
324
+ const codeLines = file.content.split("\n");
325
+ const lineContents = [
326
+ ...codeLines
327
+ .slice(Math.max(0, realLine - 3), Math.max(0, realLine - 1))
328
+ .map(line => `│ ${line}`),
329
+ `│> ${codeLines[realLine - 1]}`,
330
+ ...codeLines.slice(realLine, realLine + 2).map(line => `│ ${line}`)
331
+ ];
332
+ const message = `Error in JSDOM when running file '${file.path}' at line ${realLine}: ${e.message}\n${lineContents.join("\n")}`;
333
+ const finalError = new Error(message);
334
+ finalError.stack = `${message}\n${e.stack}`;
335
+ collectedErrors.push(finalError);
336
+ return finalError;
337
+ }
338
+ else {
339
+ return e;
340
+ }
341
+ };
342
+ };
343
+ exports.createLocatedError = createLocatedError;
@@ -9,7 +9,7 @@ const node_path_1 = __importDefault(require("node:path"));
9
9
  const rimraf_1 = require("rimraf");
10
10
  const createLazyTestEnv_1 = __importDefault(require("../helper/legacy/createLazyTestEnv"));
11
11
  const tester_1 = require("./tester");
12
- const DEFAULT_MAX_CONCURRENT = 5;
12
+ const DEFAULT_MAX_CONCURRENT = process.env.WASM ? 1 : 5;
13
13
  class BasicCaseCreator {
14
14
  constructor(_options) {
15
15
  this._options = _options;
@@ -36,7 +36,7 @@ class BasicCaseCreator {
36
36
  const run = this.shouldRun(name);
37
37
  const tester = this.createTester(name, src, dist, temp, testConfig, options);
38
38
  const concurrent = process.env.WASM
39
- ? false
39
+ ? 1
40
40
  : testConfig.concurrent || options.concurrent;
41
41
  if (options.describe) {
42
42
  if (run) {
@@ -242,8 +242,7 @@ class BasicCaseCreator {
242
242
  expect(typeof fn === "function");
243
243
  afterTasks.push(fn);
244
244
  },
245
- jest: global.jest || global.rstest,
246
- rstest: global.rstest
245
+ rstest
247
246
  };
248
247
  }
249
248
  createEnv(testConfig, options) {
@@ -255,8 +254,7 @@ class BasicCaseCreator {
255
254
  it,
256
255
  beforeEach,
257
256
  afterEach,
258
- jest: global.jest || global.rstest,
259
- rstest: global.rstest
257
+ rstest
260
258
  };
261
259
  }
262
260
  clean(folders) {
package/dist/type.d.ts CHANGED
@@ -108,10 +108,10 @@ export type TDiffStatsItem = {
108
108
  };
109
109
  export type TDiffStats = {
110
110
  root: string;
111
- data: Array<TDiffStatsItem>;
111
+ data: TDiffStatsItem[];
112
112
  };
113
113
  export interface ITestEnv {
114
- expect: jest.Expect;
114
+ expect: Expect;
115
115
  it: (...args: any[]) => void;
116
116
  beforeEach: (...args: any[]) => void;
117
117
  afterEach: (...args: any[]) => void;
@@ -139,6 +139,7 @@ export type TTestConfig = {
139
139
  esmLibPluginOptions?: {
140
140
  preserveModules?: string;
141
141
  };
142
+ resourceLoader?: (url: string, element: HTMLScriptElement) => Buffer | null;
142
143
  };
143
144
  export type TTestFilter = (creatorConfig: Record<string, unknown>, testConfig: TTestConfig) => boolean | string;
144
145
  export interface ITestRunner {
@@ -171,7 +172,7 @@ export declare enum EEsmMode {
171
172
  }
172
173
  export interface IModuleScope extends ITestEnv {
173
174
  console: Record<string, (...args: any[]) => void>;
174
- expect: jest.Expect;
175
+ expect: Expect;
175
176
  [key: string]: any;
176
177
  }
177
178
  export interface IGlobalContext {
package/dist/type.js CHANGED
@@ -1,5 +1,5 @@
1
1
  "use strict";
2
- /// <reference types="../jest.d.ts" />
2
+ /// <reference types="../rstest.d.ts" />
3
3
  Object.defineProperty(exports, "__esModule", { value: true });
4
4
  exports.EEsmMode = exports.ECompareResultType = void 0;
5
5
  var ECompareResultType;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rspack/test-tools",
3
- "version": "1.6.0",
3
+ "version": "1.6.2",
4
4
  "license": "MIT",
5
5
  "description": "Test tools for rspack",
6
6
  "main": "dist/index.js",
@@ -15,14 +15,13 @@
15
15
  "./package.json": "./package.json",
16
16
  "./helper/*": "./dist/helper/*.js",
17
17
  "./helper/legacy/*": "./dist/helper/legacy/*.js",
18
- "./helper/util/*": "./dist/helper/util/*.js",
19
- "./jest/*": "./dist/jest/*.js"
18
+ "./helper/util/*": "./dist/helper/util/*.js"
20
19
  },
21
20
  "files": [
22
21
  "client",
23
22
  "dist",
24
23
  "template",
25
- "jest.d.ts"
24
+ "rstest.d.ts"
26
25
  ],
27
26
  "publishConfig": {
28
27
  "access": "public",
@@ -40,15 +39,13 @@
40
39
  "@babel/parser": "7.28.5",
41
40
  "@babel/traverse": "7.28.5",
42
41
  "@babel/types": "7.28.5",
43
- "@jest/reporters": "29.7.0",
44
42
  "cross-env": "^10.1.0",
45
43
  "filenamify": "4.3.0",
46
44
  "fs-extra": "^11.3.2",
47
- "iconv-lite": "^0.6.3",
45
+ "iconv-lite": "^0.7.0",
48
46
  "javascript-stringify": "^2.1.0",
49
47
  "jest-diff": "^29.7.0",
50
48
  "jest-snapshot": "29.7.0",
51
- "jest-environment-node": "29.7.0",
52
49
  "jsdom": "^26.1.0",
53
50
  "memfs": "4.48.1",
54
51
  "path-serializer": "0.5.1",
@@ -68,7 +65,7 @@
68
65
  "@types/jsdom": "^21.1.7",
69
66
  "typescript": "^5.9.3",
70
67
  "wast-loader": "^1.14.1",
71
- "@rspack/core": "1.6.0"
68
+ "@rspack/core": "1.6.2"
72
69
  },
73
70
  "peerDependencies": {
74
71
  "@rspack/core": ">=1.0.0"
package/rstest.d.ts ADDED
@@ -0,0 +1,24 @@
1
+ /// <reference types="@rstest/core/globals" />
2
+
3
+ import type { DiffOptions } from "jest-diff";
4
+
5
+ declare interface FileMatcherOptions {
6
+ diff?: DiffOptions;
7
+ }
8
+
9
+ declare module "@rstest/core" {
10
+ interface Assertion {
11
+ toMatchFileSnapshotSync: (
12
+ filename?: string,
13
+ options?: FileMatcherOptions
14
+ ) => void;
15
+ }
16
+ }
17
+
18
+ declare global {
19
+ type Expect = import("@rstest/core").Expect;
20
+ type Describe = import("@rstest/core").Describe;
21
+ type Assertion<T> = import("@rstest/core").Assertion<T>;
22
+ }
23
+
24
+ export {};
@@ -1,2 +0,0 @@
1
- export = DefaultReporter;
2
- import { DefaultReporter } from "@jest/reporters";
@@ -1,57 +0,0 @@
1
- "use strict";
2
- // @ts-nocheck
3
- const { DefaultReporter } = require("@jest/reporters");
4
- const chalk = require.cache[require.resolve("@jest/reporters")].require("chalk");
5
- const jestUtil = require.cache[require.resolve("@jest/reporters")].require("jest-util");
6
- const ARROW = " \u203A ";
7
- const DOT = " \u2022 ";
8
- const FAIL_COLOR = chalk.bold.red;
9
- const SNAPSHOT_ADDED = chalk.bold.green;
10
- const SNAPSHOT_UPDATED = chalk.bold.green;
11
- const SNAPSHOT_OUTDATED = chalk.bold.yellow;
12
- function getSnapshotStatus(snapshot, afterUpdate) {
13
- const statuses = [];
14
- if (snapshot.added) {
15
- statuses.push(SNAPSHOT_ADDED(`${ARROW + jestUtil.pluralize("snapshot", snapshot.added)} written.`));
16
- }
17
- if (snapshot.updated) {
18
- statuses.push(SNAPSHOT_UPDATED(`${ARROW + jestUtil.pluralize("snapshot", snapshot.updated)} updated.`));
19
- }
20
- if (snapshot.unmatched) {
21
- statuses.push(FAIL_COLOR(`${ARROW + jestUtil.pluralize("snapshot", snapshot.unmatched)} failed.`));
22
- }
23
- if (snapshot.unchecked) {
24
- if (afterUpdate) {
25
- statuses.push(SNAPSHOT_UPDATED(`${ARROW + jestUtil.pluralize("snapshot", snapshot.unchecked)} removed.`));
26
- for (const key of snapshot.uncheckedKeys) {
27
- statuses.push(` ${DOT}${key}`);
28
- }
29
- }
30
- else {
31
- statuses.push(`${SNAPSHOT_OUTDATED(`${ARROW + jestUtil.pluralize("snapshot", snapshot.unchecked)} obsolete`)}.`);
32
- }
33
- }
34
- if (snapshot.fileDeleted) {
35
- statuses.push(SNAPSHOT_UPDATED(`${ARROW}snapshot file removed.`));
36
- }
37
- return statuses;
38
- }
39
- const isUpdate = process.argv.includes("-u") || process.argv.includes("--updateSnapshot");
40
- const isFiltering = process.argv.includes("-t") || process.argv.includes("--testNamePattern");
41
- const isVerbose = process.argv.includes("--verbose");
42
- if (!isVerbose && !isUpdate && isFiltering) {
43
- class IgnoreSnapshotDefaultReporter extends DefaultReporter {
44
- printTestFileFailureMessage(_testPath, _config, result) {
45
- if (result.failureMessage) {
46
- this.log(result.failureMessage);
47
- }
48
- const didUpdate = this._globalConfig.updateSnapshot === "all";
49
- const snapshotStatuses = getSnapshotStatus(result.snapshot, didUpdate);
50
- snapshotStatuses.forEach(this.log);
51
- }
52
- }
53
- module.exports = IgnoreSnapshotDefaultReporter;
54
- }
55
- else {
56
- module.exports = DefaultReporter;
57
- }
@@ -1,2 +0,0 @@
1
- export = SummaryReporter;
2
- import { SummaryReporter } from "@jest/reporters";
@@ -1,24 +0,0 @@
1
- "use strict";
2
- // @ts-nocheck
3
- const { SummaryReporter } = require("@jest/reporters");
4
- const chalk = require.cache[require.resolve("@jest/reporters")].require("chalk");
5
- const isUpdate = process.argv.includes("-u") || process.argv.includes("--updateSnapshot");
6
- const isFiltering = process.argv.includes("-t") || process.argv.includes("--testNamePattern");
7
- const isVerbose = process.argv.includes("--verbose");
8
- if (!isVerbose && !isUpdate && isFiltering) {
9
- class IgnoreSnapshotSummaryReporter extends SummaryReporter {
10
- _printSnapshotSummary(snapshots, globalConfig) {
11
- if (snapshots.added ||
12
- snapshots.filesRemoved ||
13
- snapshots.unchecked ||
14
- snapshots.unmatched ||
15
- snapshots.updated) {
16
- this.log(chalk.bold.yellow("Some snapshots are obsoleted, flush with `npm run test -- -u` if necessary.\n"));
17
- }
18
- }
19
- }
20
- module.exports = IgnoreSnapshotSummaryReporter;
21
- }
22
- else {
23
- module.exports = SummaryReporter;
24
- }
@@ -1,5 +0,0 @@
1
- export = CustomEnvironment;
2
- declare const CustomEnvironment_base: typeof import("jest-environment-node").default;
3
- declare class CustomEnvironment extends CustomEnvironment_base {
4
- handleTestEvent(event: any, state: any): Promise<void>;
5
- }
@@ -1,18 +0,0 @@
1
- "use strict";
2
- // @ts-nocheck
3
- // Copied from <https://github.com/webpack/webpack/blob/main/test/patch-node-env.js>
4
- //
5
- const NodeEnvironment =
6
- // For jest@29
7
- require("jest-environment-node").TestEnvironment ||
8
- // For jest@27
9
- require("jest-environment-node");
10
- class CustomEnvironment extends NodeEnvironment {
11
- // Workaround for `Symbol('JEST_STATE_SYMBOL')`
12
- async handleTestEvent(event, state) {
13
- if (!this.global.JEST_STATE_SYMBOL) {
14
- this.global.JEST_STATE_SYMBOL = state;
15
- }
16
- }
17
- }
18
- module.exports = CustomEnvironment;
@@ -1,2 +0,0 @@
1
- declare function _exports(path: any): any;
2
- export = _exports;
@@ -1,16 +0,0 @@
1
- "use strict";
2
- // @ts-nocheck
3
- /**
4
- * The following code is copied from
5
- * https://github.com/sindresorhus/slash/blob/98b618f5a3bfcb5dd374b204868818845b87bb2f/index.js
6
- *
7
- * MIT Licensed
8
- * Author Sindre Sorhus @sindresorhus
9
- */
10
- module.exports = function slash(path) {
11
- const isExtendedLengthPath = path.startsWith("\\\\?\\");
12
- if (isExtendedLengthPath) {
13
- return path;
14
- }
15
- return path.replace(/\\/g, "/");
16
- };
package/jest.d.ts DELETED
@@ -1,27 +0,0 @@
1
- /// <reference types="jest" />
2
-
3
- import type { DiffOptions } from "jest-diff";
4
-
5
- declare interface FileMatcherOptions {
6
- diff?: DiffOptions;
7
- }
8
-
9
- declare global {
10
- namespace jest {
11
- interface Matchers<R, T> {
12
- toMatchFileSnapshot: (
13
- filename?: string,
14
- options?: FileMatcherOptions
15
- ) => void;
16
- }
17
-
18
- interface Expect {
19
- toMatchFileSnapshot: (
20
- filename?: string,
21
- options?: FileMatcherOptions
22
- ) => void;
23
- }
24
- }
25
-
26
- var rstest = jest;
27
- }