@rspack-canary/test-tools 1.6.0-canary-beafb11e-20251019174144 → 1.6.0-canary-0eb13821-20251021173640

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 (39) hide show
  1. package/dist/case/cache.js +3 -0
  2. package/dist/case/common.d.ts +1 -0
  3. package/dist/case/common.js +15 -12
  4. package/dist/case/config.js +4 -1
  5. package/dist/case/esm-output.js +28 -2
  6. package/dist/case/hot.d.ts +1 -1
  7. package/dist/case/hot.js +4 -3
  8. package/dist/case/incremental.d.ts +1 -1
  9. package/dist/case/incremental.js +1 -20
  10. package/dist/case/normal.js +3 -0
  11. package/dist/case/runner.d.ts +1 -1
  12. package/dist/case/runner.js +4 -3
  13. package/dist/case/watch.d.ts +3 -1
  14. package/dist/case/watch.js +5 -4
  15. package/dist/helper/hot-update/plugin.js +1 -1
  16. package/dist/helper/legacy/asModule.js +0 -2
  17. package/dist/helper/legacy/createLazyTestEnv.d.ts +1 -0
  18. package/dist/helper/legacy/createLazyTestEnv.js +3 -1
  19. package/dist/helper/legacy/supportsTextDecoder.d.ts +2 -0
  20. package/dist/helper/legacy/supportsTextDecoder.js +9 -0
  21. package/dist/helper/setup-env.js +15 -0
  22. package/dist/runner/node/index.js +7 -3
  23. package/dist/runner/web/index.d.ts +20 -7
  24. package/dist/runner/web/index.js +293 -18
  25. package/dist/test/creator.js +13 -7
  26. package/dist/test/tester.d.ts +1 -0
  27. package/dist/test/tester.js +5 -0
  28. package/dist/type.d.ts +5 -5
  29. package/dist/type.js +1 -6
  30. package/jest.d.ts +2 -0
  31. package/package.json +3 -3
  32. package/dist/helper/legacy/FakeDocument.d.ts +0 -54
  33. package/dist/helper/legacy/FakeDocument.js +0 -280
  34. package/dist/helper/legacy/walkCssTokens.d.ts +0 -40
  35. package/dist/helper/legacy/walkCssTokens.js +0 -761
  36. package/dist/runner/web/fake.d.ts +0 -15
  37. package/dist/runner/web/fake.js +0 -215
  38. package/dist/runner/web/jsdom.d.ts +0 -24
  39. package/dist/runner/web/jsdom.js +0 -241
@@ -1,32 +1,307 @@
1
1
  "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
2
5
  Object.defineProperty(exports, "__esModule", { value: true });
3
6
  exports.WebRunner = void 0;
4
- const type_1 = require("../../type");
5
- const fake_1 = require("./fake");
6
- const jsdom_1 = require("./jsdom");
7
- class WebRunner {
7
+ const node_fs_1 = __importDefault(require("node:fs"));
8
+ const node_path_1 = __importDefault(require("node:path"));
9
+ const node_url_1 = require("node:url");
10
+ const node_vm_1 = require("node:vm");
11
+ const jsdom_1 = require("jsdom");
12
+ const helper_1 = require("../../helper");
13
+ const EventSourceForNode_1 = __importDefault(require("../../helper/legacy/EventSourceForNode"));
14
+ const urlToRelativePath_1 = __importDefault(require("../../helper/legacy/urlToRelativePath"));
15
+ const node_1 = require("../node");
16
+ const EVAL_LOCATION_REGEX = /<anonymous>:(\d+)/;
17
+ // Compatibility code to suppress iconv-lite warnings
18
+ require("iconv-lite").skipDecodeWarning = true;
19
+ const FAKE_HOSTS = [
20
+ "https://example.com/public/path",
21
+ "https://example.com",
22
+ "https://test.cases/path/",
23
+ "https://test.cases/server/",
24
+ "https://test.cases"
25
+ ];
26
+ const FAKE_TEST_ROOT_HOST = "https://test.cases/root/";
27
+ class WebRunner extends node_1.NodeRunner {
8
28
  constructor(_webOptions) {
29
+ super(_webOptions);
9
30
  this._webOptions = _webOptions;
10
- this.originMethods = {};
11
- const { dom } = _webOptions;
12
- if (dom === type_1.EDocumentType.Fake) {
13
- this.implement = new fake_1.FakeDocumentWebRunner(_webOptions);
31
+ const virtualConsole = new jsdom_1.VirtualConsole({});
32
+ virtualConsole.sendTo(console, {
33
+ omitJSDOMErrors: true
34
+ });
35
+ this.dom = new jsdom_1.JSDOM(`
36
+ <!doctype html>
37
+ <html>
38
+ <head></head>
39
+ <body></body>
40
+ </html>
41
+ `, {
42
+ url: this._webOptions.location,
43
+ resources: this.createResourceLoader(),
44
+ runScripts: "dangerously",
45
+ virtualConsole
46
+ });
47
+ this.dom.window.console = console;
48
+ // compat with FakeDocument
49
+ this.dom.window.eval(`
50
+ Object.defineProperty(document.head, "_children", {
51
+ get: function() {
52
+ return Array.from(document.head.children).map(function(ele) {
53
+ var type = ele.tagName.toLowerCase();
54
+ return new Proxy(ele, {
55
+ get(target, prop, receiver) {
56
+ if (prop === "_type") {
57
+ return target.tagName.toLowerCase();
58
+ }
59
+ if (prop === "_href") {
60
+ return Reflect.get(target, "href", receiver);
61
+ }
62
+ return Reflect.get(target, prop, receiver);
63
+ },
64
+ });
65
+ });
14
66
  }
15
- else if (dom === type_1.EDocumentType.JSDOM) {
16
- this.implement = new jsdom_1.JSDOMWebRunner(_webOptions);
17
- }
18
- else {
19
- throw new Error(`Dom type "${dom}" of web runner is not support yet`);
67
+ });
68
+ `);
69
+ if (this._options.compilerOptions.node !== false) {
70
+ const vmContext = this.dom.getInternalVMContext();
71
+ vmContext.global = {};
20
72
  }
21
73
  }
22
74
  run(file) {
23
- return this.implement.run(file);
24
- }
25
- getRequire() {
26
- return this.implement.getRequire();
75
+ if (!file.endsWith(".js") && !file.endsWith(".mjs")) {
76
+ const cssElement = this.dom.window.document.createElement("link");
77
+ cssElement.href = file;
78
+ cssElement.rel = "stylesheet";
79
+ this.dom.window.document.head.appendChild(cssElement);
80
+ return Promise.resolve();
81
+ }
82
+ return super.run(file);
27
83
  }
28
84
  getGlobal(name) {
29
- return this.implement.getGlobal(name);
85
+ return this.globalContext[name];
86
+ }
87
+ createResourceLoader() {
88
+ const that = this;
89
+ class CustomResourceLoader extends jsdom_1.ResourceLoader {
90
+ fetch(url, _) {
91
+ const filePath = that.urlToPath(url);
92
+ let finalCode;
93
+ if (node_path_1.default.extname(filePath) === ".js") {
94
+ const currentDirectory = node_path_1.default.dirname(filePath);
95
+ const file = that.getFile(filePath, currentDirectory);
96
+ if (!file) {
97
+ throw new Error(`File not found: ${filePath}`);
98
+ }
99
+ const [_m, code] = that.getModuleContent(file);
100
+ finalCode = code;
101
+ }
102
+ else {
103
+ finalCode = node_fs_1.default.readFileSync(filePath);
104
+ }
105
+ try {
106
+ that.dom.window["__LINK_SHEET__"] ??= {};
107
+ that.dom.window["__LINK_SHEET__"][url] = finalCode.toString();
108
+ return Promise.resolve(finalCode);
109
+ }
110
+ catch (err) {
111
+ console.error(err);
112
+ if (err.code === "ENOENT") {
113
+ return null;
114
+ }
115
+ throw err;
116
+ }
117
+ }
118
+ }
119
+ return new CustomResourceLoader();
120
+ }
121
+ urlToPath(url) {
122
+ if (url.startsWith("file://")) {
123
+ return (0, node_url_1.fileURLToPath)(url);
124
+ }
125
+ if (url.startsWith(FAKE_TEST_ROOT_HOST)) {
126
+ return node_path_1.default.resolve(__TEST_PATH__, `./${url.slice(FAKE_TEST_ROOT_HOST.length)}`);
127
+ }
128
+ let dist = url;
129
+ for (const host of FAKE_HOSTS) {
130
+ if (url.startsWith(host)) {
131
+ dist = url.slice(host.length);
132
+ break;
133
+ }
134
+ }
135
+ return node_path_1.default.resolve(this._webOptions.dist, `./${dist}`).split("?")[0];
136
+ }
137
+ createBaseModuleScope() {
138
+ const moduleScope = super.createBaseModuleScope();
139
+ moduleScope.EventSource = EventSourceForNode_1.default;
140
+ moduleScope.fetch = async (url) => {
141
+ try {
142
+ const buffer = await new Promise((resolve, reject) => node_fs_1.default.readFile(this.urlToPath(url), (err, b) => err ? reject(err) : resolve(b)));
143
+ return {
144
+ status: 200,
145
+ ok: true,
146
+ json: async () => JSON.parse(buffer.toString("utf-8"))
147
+ };
148
+ }
149
+ catch (err) {
150
+ if (err.code === "ENOENT") {
151
+ return {
152
+ status: 404,
153
+ ok: false
154
+ };
155
+ }
156
+ throw err;
157
+ }
158
+ };
159
+ moduleScope.URL = URL;
160
+ moduleScope.importScripts = (url) => {
161
+ this._options.env.expect(url).toMatch(/^https:\/\/test\.cases\/path\//);
162
+ this.requirers.get("entry")(this._options.dist, (0, urlToRelativePath_1.default)(url));
163
+ };
164
+ moduleScope.getComputedStyle = (element) => {
165
+ const computedStyle = this.dom.window.getComputedStyle(element);
166
+ const getPropertyValue = computedStyle.getPropertyValue.bind(computedStyle);
167
+ return {
168
+ ...computedStyle,
169
+ getPropertyValue(v) {
170
+ return getPropertyValue(v);
171
+ }
172
+ };
173
+ };
174
+ moduleScope.window = this.dom.window;
175
+ moduleScope.document = this.dom.window.document;
176
+ moduleScope.getLinkSheet = (link) => {
177
+ return this.dom.window["__LINK_SHEET__"][link.href];
178
+ };
179
+ return moduleScope;
180
+ }
181
+ getModuleContent(file) {
182
+ const m = {
183
+ exports: {}
184
+ };
185
+ const currentModuleScope = this.createModuleScope(this.getRequire(), m, file);
186
+ if (this._options.testConfig.moduleScope) {
187
+ this._options.testConfig.moduleScope(currentModuleScope, this._options.stats, this._options.compilerOptions);
188
+ }
189
+ if (file.content.includes("__STATS__")) {
190
+ currentModuleScope.__STATS__ = this._options.stats?.();
191
+ }
192
+ if (file.content.includes("__STATS_I__")) {
193
+ const statsIndex = this._options.stats?.()?.__index__;
194
+ if (typeof statsIndex === "number") {
195
+ currentModuleScope.__STATS_I__ = statsIndex;
196
+ }
197
+ }
198
+ const createLocatedError = (e, file) => {
199
+ const match = (e.stack || e.message).match(EVAL_LOCATION_REGEX);
200
+ if (match) {
201
+ const [, line] = match;
202
+ const realLine = Number(line) - 34;
203
+ const codeLines = file.content.split("\n");
204
+ const lineContents = [
205
+ ...codeLines
206
+ .slice(Math.max(0, realLine - 3), Math.max(0, realLine - 1))
207
+ .map(line => `│ ${line}`),
208
+ `│> ${codeLines[realLine - 1]}`,
209
+ ...codeLines.slice(realLine, realLine + 2).map(line => `│ ${line}`)
210
+ ];
211
+ const message = `Error in JSDOM when running file '${file.path}' at line ${realLine}: ${e.message}\n${lineContents.join("\n")}`;
212
+ const finalError = new Error(message);
213
+ finalError.stack = undefined;
214
+ return finalError;
215
+ }
216
+ else {
217
+ return e;
218
+ }
219
+ };
220
+ const originIt = currentModuleScope.it;
221
+ currentModuleScope.it = (description, fn) => {
222
+ originIt(description, async () => {
223
+ try {
224
+ await fn();
225
+ }
226
+ catch (err) {
227
+ throw createLocatedError(err, file);
228
+ }
229
+ });
230
+ };
231
+ const scopeKey = (0, helper_1.escapeSep)(file.path);
232
+ const args = Object.keys(currentModuleScope).filter(arg => !["window", "self", "globalThis", "console"].includes(arg));
233
+ const argValues = args
234
+ .map(arg => `window["${scopeKey}"]["${arg}"]`)
235
+ .join(", ");
236
+ this.dom.window[scopeKey] = currentModuleScope;
237
+ this.dom.window["__GLOBAL_SHARED__"] = this.globalContext;
238
+ this.dom.window["__FILE__"] = file;
239
+ this.dom.window["__CREATE_LOCATED_ERROR__"] = createLocatedError;
240
+ return [
241
+ m,
242
+ `// hijack document.currentScript for auto public path
243
+ var $$g$$ = new Proxy(window, {
244
+ get(target, prop, receiver) {
245
+ if (prop === "document") {
246
+ return new Proxy(window.document, {
247
+ get(target, prop, receiver) {
248
+ if (prop === "currentScript") {
249
+ var script = target.createElement("script");
250
+ script.src = "https://test.cases/path/${(0, helper_1.escapeSep)(file.subPath)}index.js";
251
+ return script;
252
+ }
253
+ return Reflect.get(target, prop, receiver);
254
+ }
255
+ });
256
+ }
257
+ return Reflect.get(target, prop, receiver);
258
+ },
259
+ });
260
+ var $$self$$ = new Proxy(window, {
261
+ get(target, prop, receiver) {
262
+ if (prop === "__HMR_UPDATED_RUNTIME__") {
263
+ return window["__GLOBAL_SHARED__"]["__HMR_UPDATED_RUNTIME__"];
264
+ }
265
+ return Reflect.get(target, prop, receiver);
266
+ },
267
+ set(target, prop, value, receiver) {
268
+ if (prop === "__HMR_UPDATED_RUNTIME__") {
269
+ window["__GLOBAL_SHARED__"]["__HMR_UPDATED_RUNTIME__"] = value;
270
+ }
271
+ return Reflect.set(target, prop, value, receiver);
272
+ }
273
+ });
274
+ (function(window, self, globalThis, console, ${args.join(", ")}) {
275
+ try {
276
+ ${file.content}
277
+ } catch (err) {
278
+ throw __CREATE_LOCATED_ERROR__(err, __FILE__);
279
+ }
280
+ })($$g$$, $$self$$, $$g$$, window["console"], ${argValues});`
281
+ ];
282
+ }
283
+ createJSDOMRequirer() {
284
+ return (currentDirectory, modulePath, context = {}) => {
285
+ const file = context.file || this.getFile(modulePath, currentDirectory);
286
+ if (!file) {
287
+ return this.requirers.get("miss")(currentDirectory, modulePath);
288
+ }
289
+ if (file.path in this.requireCache) {
290
+ return this.requireCache[file.path].exports;
291
+ }
292
+ const [m, code] = this.getModuleContent(file);
293
+ this.preExecute(code, file);
294
+ const script = new node_vm_1.Script(code);
295
+ const vmContext = this.dom.getInternalVMContext();
296
+ script.runInContext(vmContext);
297
+ this.postExecute(m, file);
298
+ this.requireCache[file.path] = m;
299
+ return m.exports;
300
+ };
301
+ }
302
+ createRunner() {
303
+ super.createRunner();
304
+ this.requirers.set("cjs", this.createJSDOMRequirer());
30
305
  }
31
306
  }
32
307
  exports.WebRunner = WebRunner;
@@ -97,10 +97,11 @@ class BasicCaseCreator {
97
97
  : index
98
98
  ? `step [${index}] should pass`
99
99
  : "should pass";
100
- it(description, cb => {
101
- stepSignal.then((e) => {
102
- cb(e);
103
- });
100
+ it(description, async () => {
101
+ const e = await stepSignal;
102
+ if (e) {
103
+ throw e;
104
+ }
104
105
  }, options.timeout || 300000);
105
106
  chain = chain.then(async () => {
106
107
  try {
@@ -108,6 +109,7 @@ class BasicCaseCreator {
108
109
  await tester.compile();
109
110
  await tester.check(env);
110
111
  await env.run();
112
+ await tester.after();
111
113
  const context = tester.getContext();
112
114
  if (!tester.next() && context.hasError()) {
113
115
  const errors = context
@@ -215,8 +217,11 @@ class BasicCaseCreator {
215
217
  try {
216
218
  await runFn(fn);
217
219
  }
218
- catch (e) {
219
- throw new Error(`Error: ${description} failed\n${e.stack}`);
220
+ catch (err) {
221
+ const e = err;
222
+ const message = `Error: ${description} failed:\n${e.message}`;
223
+ e.message = message;
224
+ throw e;
220
225
  }
221
226
  for (const after of afterTasks) {
222
227
  await runFn(after);
@@ -237,7 +242,8 @@ class BasicCaseCreator {
237
242
  expect(typeof fn === "function");
238
243
  afterTasks.push(fn);
239
244
  },
240
- jest
245
+ jest: global.jest || global.rstest,
246
+ rstest: global.rstest
241
247
  };
242
248
  }
243
249
  createEnv(testConfig, options) {
@@ -10,6 +10,7 @@ export declare class Tester implements ITester {
10
10
  prepare(): Promise<void>;
11
11
  compile(): Promise<void>;
12
12
  check(env: ITestEnv): Promise<void>;
13
+ after(): Promise<void>;
13
14
  next(): boolean;
14
15
  resume(): Promise<void>;
15
16
  private runStepMethods;
@@ -55,6 +55,11 @@ class Tester {
55
55
  if (!currentStep)
56
56
  return;
57
57
  await this.runCheckStepMethods(currentStep, env, this.context.hasError() ? ["check"] : ["run", "check"]);
58
+ }
59
+ async after() {
60
+ const currentStep = this.steps[this.step];
61
+ if (!currentStep)
62
+ return;
58
63
  await this.runStepMethods(currentStep, ["after"], true);
59
64
  }
60
65
  next() {
package/dist/type.d.ts CHANGED
@@ -63,6 +63,7 @@ export interface ITester {
63
63
  prepare(): Promise<void>;
64
64
  compile(): Promise<void>;
65
65
  check(env: ITestEnv): Promise<void>;
66
+ after(): Promise<void>;
66
67
  next(): boolean;
67
68
  resume(): Promise<void>;
68
69
  }
@@ -129,12 +130,8 @@ export interface ITestEnv {
129
130
  afterEach: (...args: any[]) => void;
130
131
  [key: string]: unknown;
131
132
  }
132
- export declare enum EDocumentType {
133
- Fake = "fake",
134
- JSDOM = "jsdom"
135
- }
136
133
  export type TTestConfig<T extends ECompilerType> = {
137
- documentType?: EDocumentType;
134
+ location?: string;
138
135
  validate?: (stats: TCompilerStats<T> | TCompilerMultiStats<T>, stderr?: string) => void;
139
136
  noTests?: boolean;
140
137
  writeStatsOuptut?: boolean;
@@ -152,6 +149,9 @@ export type TTestConfig<T extends ECompilerType> = {
152
149
  snapshotContent?(content: string): string;
153
150
  checkSteps?: boolean;
154
151
  ignoreNotFriendlyForIncrementalWarnings?: boolean;
152
+ esmLibPluginOptions?: {
153
+ preserveModules?: string;
154
+ };
155
155
  };
156
156
  export type TTestFilter<T extends ECompilerType> = (creatorConfig: Record<string, unknown>, testConfig: TTestConfig<T>) => boolean | string;
157
157
  export interface ITestRunner {
package/dist/type.js CHANGED
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  /// <reference types="../jest.d.ts" />
3
3
  Object.defineProperty(exports, "__esModule", { value: true });
4
- exports.EEsmMode = exports.EDocumentType = exports.ECompareResultType = exports.ECompilerType = void 0;
4
+ exports.EEsmMode = exports.ECompareResultType = exports.ECompilerType = void 0;
5
5
  var ECompilerType;
6
6
  (function (ECompilerType) {
7
7
  ECompilerType["Rspack"] = "rspack";
@@ -15,11 +15,6 @@ var ECompareResultType;
15
15
  ECompareResultType["OnlySource"] = "only-source";
16
16
  ECompareResultType["Different"] = "different";
17
17
  })(ECompareResultType || (exports.ECompareResultType = ECompareResultType = {}));
18
- var EDocumentType;
19
- (function (EDocumentType) {
20
- EDocumentType["Fake"] = "fake";
21
- EDocumentType["JSDOM"] = "jsdom";
22
- })(EDocumentType || (exports.EDocumentType = EDocumentType = {}));
23
18
  var EEsmMode;
24
19
  (function (EEsmMode) {
25
20
  EEsmMode[EEsmMode["Unknown"] = 0] = "Unknown";
package/jest.d.ts CHANGED
@@ -22,4 +22,6 @@ declare global {
22
22
  ) => void;
23
23
  }
24
24
  }
25
+
26
+ var rstest = jest;
25
27
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rspack-canary/test-tools",
3
- "version": "1.6.0-canary-beafb11e-20251019174144",
3
+ "version": "1.6.0-canary-0eb13821-20251021173640",
4
4
  "license": "MIT",
5
5
  "description": "Test tools for rspack",
6
6
  "main": "dist/index.js",
@@ -58,7 +58,7 @@
58
58
  "rimraf": "^5.0.10",
59
59
  "source-map": "^0.7.6",
60
60
  "terser-webpack-plugin": "^5.3.14",
61
- "webpack": "5.99.9",
61
+ "webpack": "5.102.1",
62
62
  "webpack-merge": "6.0.1",
63
63
  "webpack-sources": "3.3.3"
64
64
  },
@@ -72,7 +72,7 @@
72
72
  "terser": "5.43.1",
73
73
  "typescript": "^5.9.3",
74
74
  "wast-loader": "^1.14.1",
75
- "@rspack/core": "npm:@rspack-canary/core@1.6.0-canary-beafb11e-20251019174144"
75
+ "@rspack/core": "npm:@rspack-canary/core@1.6.0-canary-0eb13821-20251021173640"
76
76
  },
77
77
  "peerDependencies": {
78
78
  "@rspack/core": ">=1.0.0"
@@ -1,54 +0,0 @@
1
- export default class FakeDocument {
2
- constructor(basePath: any, options?: {});
3
- head: FakeElement;
4
- body: FakeElement;
5
- baseURI: string;
6
- _elementsByTagName: Map<string, FakeElement[]>;
7
- _basePath: any;
8
- currentScript: any;
9
- _options: {};
10
- createElement(type: any): FakeElement;
11
- _onElementAttached(element: any): void;
12
- _onElementRemoved(element: any): void;
13
- getElementsByTagName(name: any): FakeElement[];
14
- querySelectorAll(name: any): FakeElement[];
15
- getComputedStyle(element: any): {
16
- getPropertyValue: (property: any) => any;
17
- };
18
- }
19
- export class FakeElement {
20
- constructor(document: any, type: any, basePath: any);
21
- _document: any;
22
- _type: any;
23
- _basePath: any;
24
- _children: any[];
25
- _attributes: any;
26
- _src: any;
27
- _href: any;
28
- rel: any;
29
- parentNode: any;
30
- sheet: FakeSheet | undefined;
31
- cloneNode(): FakeElement;
32
- addEventListener(): void;
33
- insertBefore(node: any, before: any): void;
34
- appendChild(node: any): void;
35
- removeChild(node: any): void;
36
- setAttribute(name: any, value: any): void;
37
- removeAttribute(name: any): void;
38
- getAttribute(name: any): any;
39
- _toRealUrl(value: any): any;
40
- set src(value: any);
41
- get src(): any;
42
- get children(): any[];
43
- set href(value: any);
44
- get href(): any;
45
- }
46
- export class FakeSheet {
47
- constructor(element: any, basePath: any);
48
- _element: any;
49
- _basePath: any;
50
- cachedCss: string | undefined;
51
- cachedCssRules: any[] | undefined;
52
- get css(): string;
53
- get cssRules(): any[];
54
- }