Skip to content

Commit 126822e

Browse files
authored
test: display error location in jsdom (#11937)
* test: display error location in jsdom * test: display error location in jsdom * test: display error location in jsdom
1 parent a457128 commit 126822e

File tree

4 files changed

+60
-16
lines changed

4 files changed

+60
-16
lines changed

packages/rspack-test-tools/src/helper/legacy/asModule.js

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,17 +16,15 @@ module.exports = async (something, context, unlinked) => {
1616
const code = [...new Set(["default", ...Object.keys(something)])]
1717
.map(
1818
name =>
19-
`const _${name} = ${SYNTHETIC_MODULES_STORE}[${i}]${
20-
name === "default" ? "" : `[${JSON.stringify(name)}]`
19+
`const _${name} = ${SYNTHETIC_MODULES_STORE}[${i}]${name === "default" ? "" : `[${JSON.stringify(name)}]`
2120
}; export { _${name} as ${name}};`
2221
)
2322
.join("\n");
2423
const m = new vm.SourceTextModule(code, {
2524
context
2625
});
2726
if (unlinked) return m;
28-
await m.link(() => {});
29-
if (m.instantiate) m.instantiate();
27+
await m.link(() => { });
3028
await m.evaluate();
3129
return m;
3230
};

packages/rspack-test-tools/src/runner/node/index.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -340,7 +340,7 @@ export class NodeRunner<T extends ECompilerType = ECompilerType.Rspack>
340340
this.requireCache[file.path] = m;
341341

342342
if (!this._options.runInNewContext) {
343-
file.content = `Object.assign(global, _globalAssign);\n ${file.content}`;
343+
file.content = `Object.assign(global, _globalAssign);${file.content}`;
344344
}
345345

346346
const currentModuleScope = this.createModuleScope(
@@ -468,7 +468,6 @@ export class NodeRunner<T extends ECompilerType = ECompilerType.Rspack>
468468
});
469469
}
470470

471-
if ((esm as any).instantiate) (esm as any).instantiate();
472471
await esm.evaluate();
473472
if (context.esmMode === EEsmMode.Evaluated) {
474473
return esm;

packages/rspack-test-tools/src/runner/web/index.ts

Lines changed: 52 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
import fs from "node:fs";
22
import path from "node:path";
33
import { fileURLToPath } from "node:url";
4+
import { Script } from "node:vm";
45
import { JSDOM, ResourceLoader, VirtualConsole } from "jsdom";
56
import { escapeSep } from "../../helper";
67
import EventSource from "../../helper/legacy/EventSourceForNode";
78
import urlToRelativePath from "../../helper/legacy/urlToRelativePath";
89
import type { ECompilerType, TRunnerFile, TRunnerRequirer } from "../../type";
910
import { type INodeRunnerOptions, NodeRunner } from "../node";
1011

12+
const EVAL_LOCATION_REGEX = /<anonymous>:(\d+)/;
1113
export interface IWebRunnerOptions<
1214
T extends ECompilerType = ECompilerType.Rspack
1315
> extends INodeRunnerOptions<T> {
@@ -236,6 +238,41 @@ export class WebRunner<
236238
}
237239
}
238240

241+
const createLocatedError = (e: Error, file: TRunnerFile) => {
242+
const match = (e.stack || e.message).match(EVAL_LOCATION_REGEX);
243+
if (match) {
244+
const [, line] = match;
245+
const realLine = Number(line) - 34;
246+
const codeLines = file.content.split("\n");
247+
const lineContents = [
248+
...codeLines
249+
.slice(Math.max(0, realLine - 3), Math.max(0, realLine - 1))
250+
.map(line => `│ ${line}`),
251+
`│> ${codeLines[realLine - 1]}`,
252+
...codeLines.slice(realLine, realLine + 2).map(line => `│ ${line}`)
253+
];
254+
const message = `Error in JSDOM when running file '${file.path}' at line ${realLine}: ${e.message}\n${lineContents.join("\n")}`;
255+
const finalError = new Error(message);
256+
finalError.stack = undefined;
257+
return finalError;
258+
} else {
259+
return e;
260+
}
261+
};
262+
const originIt = currentModuleScope.it;
263+
currentModuleScope.it = (
264+
description: string,
265+
fn: () => Promise<void> | void
266+
) => {
267+
originIt(description, async () => {
268+
try {
269+
await fn();
270+
} catch (err) {
271+
throw createLocatedError(err as Error, file);
272+
}
273+
});
274+
};
275+
239276
const scopeKey = escapeSep(file!.path);
240277
const args = Object.keys(currentModuleScope).filter(
241278
arg => !["window", "self", "globalThis", "console"].includes(arg)
@@ -245,10 +282,12 @@ export class WebRunner<
245282
.join(", ");
246283
this.dom.window[scopeKey] = currentModuleScope;
247284
this.dom.window["__GLOBAL_SHARED__"] = this.globalContext;
285+
this.dom.window["__FILE__"] = file;
286+
this.dom.window["__CREATE_LOCATED_ERROR__"] = createLocatedError;
287+
248288
return [
249289
m,
250-
`
251-
// hijack document.currentScript for auto public path
290+
`// hijack document.currentScript for auto public path
252291
var $$g$$ = new Proxy(window, {
253292
get(target, prop, receiver) {
254293
if (prop === "document") {
@@ -281,9 +320,12 @@ export class WebRunner<
281320
}
282321
});
283322
(function(window, self, globalThis, console, ${args.join(", ")}) {
284-
${file.content}
285-
})($$g$$, $$self$$, $$g$$, window["console"], ${argValues});
286-
`
323+
try {
324+
${file.content}
325+
} catch (err) {
326+
throw __CREATE_LOCATED_ERROR__(err, __FILE__);
327+
}
328+
})($$g$$, $$self$$, $$g$$, window["console"], ${argValues});`
287329
];
288330
}
289331

@@ -301,7 +343,11 @@ export class WebRunner<
301343
const [m, code] = this.getModuleContent(file);
302344

303345
this.preExecute(code, file);
304-
this.dom.window.eval(code);
346+
347+
const script = new Script(code);
348+
const vmContext = this.dom.getInternalVMContext();
349+
script.runInContext(vmContext);
350+
305351
this.postExecute(m, file);
306352

307353
this.requireCache[file.path] = m;

packages/rspack-test-tools/src/test/creator.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -310,10 +310,11 @@ export class BasicCaseCreator<T extends ECompilerType> {
310310
}
311311
try {
312312
await runFn(fn);
313-
} catch (e) {
314-
throw new Error(
315-
`Error: ${description} failed\n${(e as Error).stack}`
316-
);
313+
} catch (err) {
314+
const e = err as Error;
315+
const message = `Error: ${description} failed:\n${e.message}`;
316+
e.message = message;
317+
throw e;
317318
}
318319
for (const after of afterTasks) {
319320
await runFn(after);

0 commit comments

Comments
 (0)