qunitx-cli 0.23.3 → 0.23.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/README.md +5 -4
- package/bin/qunitx.js +11 -1
- package/dist/cli.js +90 -64
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -306,10 +306,11 @@ Don't forget to add the plugin's file extension(s) to `qunitx.extensions` so dir
|
|
|
306
306
|
|
|
307
307
|
### Environment variables
|
|
308
308
|
|
|
309
|
-
| Variable
|
|
310
|
-
|
|
|
311
|
-
| `CHROME_BIN`
|
|
312
|
-
| `QUNITX_BROWSER`
|
|
309
|
+
| Variable | Description |
|
|
310
|
+
| --------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
311
|
+
| `CHROME_BIN` | Path to the Chrome/Chromium executable. Required on systems where Chrome is not on `PATH` (e.g. many CI environments). Set automatically when using `browser-actions/setup-chrome` in GitHub Actions. |
|
|
312
|
+
| `QUNITX_BROWSER` | Browser engine to use (`chromium`, `firefox`, `webkit`). Equivalent to `--browser` on the CLI. Useful in CI matrix jobs. |
|
|
313
|
+
| `NODE_COMPILE_CACHE` | Standard Node env, auto-enabled by qunitx. Stores V8 bytecode for the CLI + its dep graph on disk so the second and subsequent `qunitx` runs skip the parser pass — measured ~8% faster end-to-end (more on slow CI disks). Defaults to `${TMPDIR}/node-compile-cache`; set to a path to relocate (handy for a CI cache key) or `""` to disable. |
|
|
313
314
|
|
|
314
315
|
If you do not provide any HTML template, qunitx falls back to its built-in `test/tests.html` boilerplate internally, so `qunitx init` is optional.
|
|
315
316
|
|
package/bin/qunitx.js
CHANGED
|
@@ -3,12 +3,22 @@
|
|
|
3
3
|
// Prefers a pre-built SEA binary from the matching optional platform package
|
|
4
4
|
// (qunitx-cli-linux-x64, qunitx-cli-darwin-arm64, etc.) when available.
|
|
5
5
|
// Falls back to the bundled JS CLI (dist/cli.js) which requires Node.js + node_modules.
|
|
6
|
+
import nodeModule, { createRequire } from 'node:module';
|
|
6
7
|
import { spawn } from 'node:child_process';
|
|
7
8
|
import { access, constants, readFile } from 'node:fs/promises';
|
|
8
|
-
import { createRequire } from 'node:module';
|
|
9
9
|
import { fileURLToPath } from 'node:url';
|
|
10
10
|
import { dirname, join } from 'node:path';
|
|
11
11
|
|
|
12
|
+
// Turn on V8's on-disk compile cache before importing dist/cli.js — caches
|
|
13
|
+
// the bundle + its external deps (esbuild, playwright-core, ws) across cold
|
|
14
|
+
// invocations. The active dir is written back to process.env so any child
|
|
15
|
+
// spawn (SEA binary below, daemon auto-spawn from cli.ts) inherits and also
|
|
16
|
+
// auto-enables from boot. `in` check preserves a user-set empty string.
|
|
17
|
+
const cacheResult = nodeModule.enableCompileCache?.();
|
|
18
|
+
if (cacheResult?.directory && !('NODE_COMPILE_CACHE' in process.env)) {
|
|
19
|
+
process.env.NODE_COMPILE_CACHE = cacheResult.directory;
|
|
20
|
+
}
|
|
21
|
+
|
|
12
22
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
13
23
|
const require = createRequire(import.meta.url);
|
|
14
24
|
|
package/dist/cli.js
CHANGED
|
@@ -374,7 +374,7 @@ var init_package = __esm({
|
|
|
374
374
|
package_default = {
|
|
375
375
|
name: "qunitx-cli",
|
|
376
376
|
type: "module",
|
|
377
|
-
version: "0.23.
|
|
377
|
+
version: "0.23.5",
|
|
378
378
|
description: "Browser runner for QUnitx: run your qunitx tests in google-chrome",
|
|
379
379
|
author: "Izel Nakri",
|
|
380
380
|
license: "MIT",
|
|
@@ -397,7 +397,7 @@ var init_package = __esm({
|
|
|
397
397
|
prepublishOnly: "npm run build",
|
|
398
398
|
format: 'prettier --check "lib/**/*.ts" "test/**/*.ts" "scripts/**/*.js" "bin/**/*.js" "*.ts" "package.json" ".github/**/*.yml"',
|
|
399
399
|
"format:fix": 'prettier --write "lib/**/*.ts" "test/**/*.ts" "scripts/**/*.js" "bin/**/*.js" "*.ts" "package.json" ".github/**/*.yml"',
|
|
400
|
-
lint: "deno lint lib/ bin/ cli.ts",
|
|
400
|
+
lint: "deno lint lib/ bin/ test/ scripts/ cli.ts",
|
|
401
401
|
"lint:docs": "node scripts/lint-docs.js",
|
|
402
402
|
docs: `deno doc --html --name="qunitx-cli" --output=docs/lib 'lib/**/*.ts' README.md`,
|
|
403
403
|
"changelog:unreleased": "git-cliff --unreleased --strip all",
|
|
@@ -519,6 +519,7 @@ ${color("--browser")} : browser engine to run tests in: chromium, firefox, webki
|
|
|
519
519
|
${color("--before")} : run a script before the tests(i.e start a new web server before tests)
|
|
520
520
|
${color("--after")} : run a script after the tests(i.e save test results to a file)
|
|
521
521
|
${color("--no-daemon")} : don't use the daemon for this run \u2014 skips a running daemon and prevents ${color("QUNITX_DAEMON")} auto-spawn
|
|
522
|
+
${color("--trace-perf")} : write timestamped startup-perf trace lines to stderr (Chrome pre-launch, module load, browser bind)
|
|
522
523
|
|
|
523
524
|
${highlight("Example:")} $ ${color("qunitx test/foo.ts app/e2e --debug --watch --before=scripts/start-new-webserver.js --after=scripts/write-test-results.js")}
|
|
524
525
|
|
|
@@ -530,6 +531,8 @@ ${color("$ qunitx daemon <start|stop|status>")} # Optional persistent daemo
|
|
|
530
531
|
${highlight("Environment:")}
|
|
531
532
|
${color("QUNITX_DAEMON=1")} : auto-spawn the daemon on the first qunitx run; reuse it on every run after (overrides the CI=1 bypass)
|
|
532
533
|
${color("QUNITX_NO_DAEMON=1")} : never use the daemon for this run
|
|
534
|
+
${color("QUNITX_BROWSER=...")} : default browser engine when ${color("--browser")} is not passed (chromium, firefox, webkit)
|
|
535
|
+
${color("QUNITX_DEBUG=1")} : enables ${color("--debug")} for every run; per-invocation ${color("--debug=false")} still wins
|
|
533
536
|
`);
|
|
534
537
|
}
|
|
535
538
|
var highlight, color;
|
|
@@ -877,7 +880,7 @@ function awaitClose(socket) {
|
|
|
877
880
|
async function pingDaemon() {
|
|
878
881
|
const socket = await tryConnect();
|
|
879
882
|
if (!socket) return null;
|
|
880
|
-
const
|
|
883
|
+
const result2 = new Promise((resolve) => {
|
|
881
884
|
attachLineParser(socket, (chunk) => {
|
|
882
885
|
if (chunk.type === "pong") resolve(chunk);
|
|
883
886
|
});
|
|
@@ -885,7 +888,7 @@ async function pingDaemon() {
|
|
|
885
888
|
socket.once("error", () => resolve(null));
|
|
886
889
|
});
|
|
887
890
|
send(socket, { type: "ping" });
|
|
888
|
-
const pong = await
|
|
891
|
+
const pong = await result2;
|
|
889
892
|
socket.end();
|
|
890
893
|
return pong;
|
|
891
894
|
}
|
|
@@ -1085,32 +1088,32 @@ var init_test_file_paths = __esm({
|
|
|
1085
1088
|
import path5 from "node:path";
|
|
1086
1089
|
function parseCliFlags(projectRoot) {
|
|
1087
1090
|
const providedFlags = process.argv.slice(2).reduce(
|
|
1088
|
-
(
|
|
1091
|
+
(result2, arg) => {
|
|
1089
1092
|
if (arg.startsWith("--debug")) {
|
|
1090
|
-
return Object.assign(
|
|
1093
|
+
return Object.assign(result2, { debug: parseBoolean(arg.split("=")[1]) });
|
|
1091
1094
|
} else if (arg.startsWith("--watch")) {
|
|
1092
|
-
return Object.assign(
|
|
1095
|
+
return Object.assign(result2, { watch: parseBoolean(arg.split("=")[1]) });
|
|
1093
1096
|
} else if (arg === "-o" || arg.startsWith("-o=") || arg.startsWith("--open")) {
|
|
1094
1097
|
const value = arg.split("=")[1];
|
|
1095
1098
|
const open = value === void 0 || value === "true" ? true : value === "false" ? false : value;
|
|
1096
|
-
return Object.assign(
|
|
1099
|
+
return Object.assign(result2, { open });
|
|
1097
1100
|
} else if (arg.startsWith("--failfast") || arg.startsWith("--failFast")) {
|
|
1098
|
-
return Object.assign(
|
|
1101
|
+
return Object.assign(result2, { failFast: parseBoolean(arg.split("=")[1]) });
|
|
1099
1102
|
} else if (arg.startsWith("--timeout")) {
|
|
1100
|
-
return Object.assign(
|
|
1103
|
+
return Object.assign(result2, { timeout: Number(arg.split("=")[1]) || FALLBACK_TIMEOUT_MS });
|
|
1101
1104
|
} else if (arg.startsWith("--output")) {
|
|
1102
|
-
return Object.assign(
|
|
1105
|
+
return Object.assign(result2, { output: arg.split("=")[1] });
|
|
1103
1106
|
} else if (arg.endsWith(".html")) {
|
|
1104
|
-
if (
|
|
1105
|
-
|
|
1107
|
+
if (result2.htmlPaths) {
|
|
1108
|
+
result2.htmlPaths.push(arg);
|
|
1106
1109
|
} else {
|
|
1107
|
-
|
|
1110
|
+
result2.htmlPaths = [arg];
|
|
1108
1111
|
}
|
|
1109
|
-
return
|
|
1112
|
+
return result2;
|
|
1110
1113
|
} else if (arg.startsWith("--port")) {
|
|
1111
|
-
return Object.assign(
|
|
1114
|
+
return Object.assign(result2, { port: Number(arg.split("=")[1]), portExplicit: true });
|
|
1112
1115
|
} else if (arg.startsWith("--extensions")) {
|
|
1113
|
-
return Object.assign(
|
|
1116
|
+
return Object.assign(result2, {
|
|
1114
1117
|
extensions: arg.split("=")[1].split(",").map((extension) => extension.trim())
|
|
1115
1118
|
});
|
|
1116
1119
|
} else if (arg.startsWith("--browser")) {
|
|
@@ -1121,22 +1124,22 @@ function parseCliFlags(projectRoot) {
|
|
|
1121
1124
|
);
|
|
1122
1125
|
process.exit(1);
|
|
1123
1126
|
}
|
|
1124
|
-
return Object.assign(
|
|
1127
|
+
return Object.assign(result2, { browser: value });
|
|
1125
1128
|
} else if (arg.startsWith("--before")) {
|
|
1126
|
-
return Object.assign(
|
|
1129
|
+
return Object.assign(result2, { before: parseModule(arg.split("=")[1]) });
|
|
1127
1130
|
} else if (arg.startsWith("--after")) {
|
|
1128
|
-
return Object.assign(
|
|
1131
|
+
return Object.assign(result2, { after: parseModule(arg.split("=")[1]) });
|
|
1129
1132
|
} else if (arg === "--trace-perf") {
|
|
1130
|
-
return
|
|
1133
|
+
return result2;
|
|
1131
1134
|
}
|
|
1132
1135
|
if (arg.startsWith("-")) {
|
|
1133
1136
|
console.warn(`# Warning: Unknown flag "${arg}" \u2014 ignored`);
|
|
1134
|
-
return
|
|
1137
|
+
return result2;
|
|
1135
1138
|
}
|
|
1136
|
-
|
|
1139
|
+
result2.inputs.add(
|
|
1137
1140
|
arg.startsWith(projectRoot) || arg.startsWith("/") ? arg : path5.join(process.cwd(), arg)
|
|
1138
1141
|
);
|
|
1139
|
-
return
|
|
1142
|
+
return result2;
|
|
1140
1143
|
},
|
|
1141
1144
|
{ inputs: /* @__PURE__ */ new Set([]) }
|
|
1142
1145
|
);
|
|
@@ -1150,12 +1153,15 @@ function parseCliFlags(projectRoot) {
|
|
|
1150
1153
|
}
|
|
1151
1154
|
providedFlags.browser = envBrowser;
|
|
1152
1155
|
}
|
|
1156
|
+
if (providedFlags.debug === void 0 && process.env.QUNITX_DEBUG) {
|
|
1157
|
+
providedFlags.debug = true;
|
|
1158
|
+
}
|
|
1153
1159
|
return { ...providedFlags, inputs: Array.from(providedFlags.inputs) };
|
|
1154
1160
|
}
|
|
1155
|
-
function parseBoolean(
|
|
1156
|
-
if (
|
|
1161
|
+
function parseBoolean(result2, defaultValue = true) {
|
|
1162
|
+
if (result2 === "true") {
|
|
1157
1163
|
return true;
|
|
1158
|
-
} else if (
|
|
1164
|
+
} else if (result2 === "false") {
|
|
1159
1165
|
return false;
|
|
1160
1166
|
}
|
|
1161
1167
|
return defaultValue;
|
|
@@ -1375,7 +1381,7 @@ var init_indent_string = __esm({
|
|
|
1375
1381
|
|
|
1376
1382
|
// lib/utils/source-map-decoder.ts
|
|
1377
1383
|
function decodeMappings(mappings) {
|
|
1378
|
-
const
|
|
1384
|
+
const result2 = [];
|
|
1379
1385
|
const cursor = { position: 0 };
|
|
1380
1386
|
const mappingsLength = mappings.length;
|
|
1381
1387
|
let segments = [];
|
|
@@ -1395,14 +1401,14 @@ function decodeMappings(mappings) {
|
|
|
1395
1401
|
} else if (charCode === COMMA) {
|
|
1396
1402
|
cursor.position++;
|
|
1397
1403
|
} else {
|
|
1398
|
-
|
|
1404
|
+
result2.push(segments);
|
|
1399
1405
|
segments = [];
|
|
1400
1406
|
generatedCol = 0;
|
|
1401
1407
|
cursor.position++;
|
|
1402
1408
|
}
|
|
1403
1409
|
}
|
|
1404
|
-
|
|
1405
|
-
return
|
|
1410
|
+
result2.push(segments);
|
|
1411
|
+
return result2;
|
|
1406
1412
|
}
|
|
1407
1413
|
function parseSourceMap(json, outDir) {
|
|
1408
1414
|
const map = JSON.parse(json);
|
|
@@ -2517,9 +2523,9 @@ function registerSharedStaticHandler(server, groupConfigs) {
|
|
|
2517
2523
|
function replaceAssetPaths(html, htmlPath, projectRoot) {
|
|
2518
2524
|
const assetPaths = findInternalAssetsFromHTML(html);
|
|
2519
2525
|
const htmlDirectory = htmlPath.split("/").slice(0, -1).join("/");
|
|
2520
|
-
return assetPaths.reduce((
|
|
2526
|
+
return assetPaths.reduce((result2, assetPath) => {
|
|
2521
2527
|
const normalizedFullAbsolutePath = path6.normalize(`${htmlDirectory}/${assetPath}`);
|
|
2522
|
-
return
|
|
2528
|
+
return result2.replace(assetPath, normalizedFullAbsolutePath.replace(projectRoot, "."));
|
|
2523
2529
|
}, html);
|
|
2524
2530
|
}
|
|
2525
2531
|
function testRuntimeToInject(config, groupId) {
|
|
@@ -3197,19 +3203,19 @@ async function buildAllGroupBundles(groupConfigs, groupCachedContents) {
|
|
|
3197
3203
|
jsx: "automatic",
|
|
3198
3204
|
footer: { js: 'window.dispatchEvent(new CustomEvent("qunitx:tests-ready"));' }
|
|
3199
3205
|
};
|
|
3200
|
-
const hasSmallOutput = (
|
|
3206
|
+
const hasSmallOutput = (result2) => (result2.outputFiles ?? []).some(
|
|
3201
3207
|
(outputFile) => GROUP_OUTPUT_REGEX.test(outputFile.path) && !outputFile.path.endsWith(".map") && outputFile.contents.length < EMPTY_BUNDLE_THRESHOLD
|
|
3202
3208
|
);
|
|
3203
3209
|
const buildWithRetry = async (retriesLeft) => {
|
|
3204
|
-
const
|
|
3205
|
-
if (!hasSmallOutput(
|
|
3210
|
+
const result2 = await esbuild.build(buildOptions);
|
|
3211
|
+
if (!hasSmallOutput(result2) || retriesLeft === 0) return result2;
|
|
3206
3212
|
await new Promise((resolve) => setTimeout(resolve, RETRY_DELAY_MS));
|
|
3207
3213
|
return buildWithRetry(retriesLeft - 1);
|
|
3208
3214
|
};
|
|
3209
3215
|
try {
|
|
3210
|
-
const
|
|
3216
|
+
const result2 = await buildWithRetry(MAX_RETRIES);
|
|
3211
3217
|
await Promise.all(
|
|
3212
|
-
(
|
|
3218
|
+
(result2.outputFiles ?? []).map((outputFile) => {
|
|
3213
3219
|
const match = GROUP_OUTPUT_REGEX.exec(outputFile.path);
|
|
3214
3220
|
if (!match) return Promise.resolve();
|
|
3215
3221
|
const slotIndex = parseInt(match[1]);
|
|
@@ -3271,12 +3277,12 @@ function buildFilteredTests(filteredTests, outputPath, config) {
|
|
|
3271
3277
|
);
|
|
3272
3278
|
}
|
|
3273
3279
|
async function runWithOverlayfsRetry(getContents, needsDisk) {
|
|
3274
|
-
let { result, js } = await getContents();
|
|
3280
|
+
let { result: result2, js } = await getContents();
|
|
3275
3281
|
const initialSize = js.length;
|
|
3276
3282
|
for (let retry = 1; retry <= MAX_RETRIES; retry++) {
|
|
3277
3283
|
if (js.length >= EMPTY_BUNDLE_THRESHOLD) break;
|
|
3278
3284
|
await new Promise((resolve) => setTimeout(resolve, RETRY_DELAY_MS));
|
|
3279
|
-
({ result, js } = await getContents());
|
|
3285
|
+
({ result: result2, js } = await getContents());
|
|
3280
3286
|
}
|
|
3281
3287
|
if (js.length < EMPTY_BUNDLE_THRESHOLD && js.length !== initialSize) {
|
|
3282
3288
|
console.log(
|
|
@@ -3285,7 +3291,7 @@ async function runWithOverlayfsRetry(getContents, needsDisk) {
|
|
|
3285
3291
|
}
|
|
3286
3292
|
if (needsDisk) {
|
|
3287
3293
|
await Promise.all(
|
|
3288
|
-
|
|
3294
|
+
result2.outputFiles.map((outputFile) => fs10.writeFile(outputFile.path, outputFile.contents))
|
|
3289
3295
|
);
|
|
3290
3296
|
}
|
|
3291
3297
|
return js;
|
|
@@ -3293,9 +3299,9 @@ async function runWithOverlayfsRetry(getContents, needsDisk) {
|
|
|
3293
3299
|
function buildWithOverlayfsRetry(options, needsDisk) {
|
|
3294
3300
|
const buildOpts = { ...options, write: false };
|
|
3295
3301
|
return runWithOverlayfsRetry(async () => {
|
|
3296
|
-
const
|
|
3297
|
-
const jsFile =
|
|
3298
|
-
return { result, js: Buffer.from(jsFile.contents) };
|
|
3302
|
+
const result2 = await esbuild.build(buildOpts);
|
|
3303
|
+
const jsFile = result2.outputFiles.find((f) => !f.path.endsWith(".map"));
|
|
3304
|
+
return { result: result2, js: Buffer.from(jsFile.contents) };
|
|
3299
3305
|
}, needsDisk);
|
|
3300
3306
|
}
|
|
3301
3307
|
async function buildIncrementally(options, fileKey, cache, needsDisk) {
|
|
@@ -3308,9 +3314,9 @@ async function buildIncrementally(options, fileKey, cache, needsDisk) {
|
|
|
3308
3314
|
}
|
|
3309
3315
|
const ctx = cache._esbuildContext;
|
|
3310
3316
|
return runWithOverlayfsRetry(async () => {
|
|
3311
|
-
const
|
|
3312
|
-
const jsFile =
|
|
3313
|
-
return { result, js: Buffer.from(jsFile.contents) };
|
|
3317
|
+
const result2 = await ctx.rebuild();
|
|
3318
|
+
const jsFile = result2.outputFiles.find((f) => !f.path.endsWith(".map"));
|
|
3319
|
+
return { result: result2, js: Buffer.from(jsFile.contents) };
|
|
3314
3320
|
}, needsDisk);
|
|
3315
3321
|
}
|
|
3316
3322
|
function esbuildTarget(browser) {
|
|
@@ -3513,6 +3519,11 @@ var init_open_output_in_browser = __esm({
|
|
|
3513
3519
|
import fs11 from "node:fs";
|
|
3514
3520
|
import { readdir, stat, lstat } from "node:fs/promises";
|
|
3515
3521
|
import path9 from "node:path";
|
|
3522
|
+
function recordJustAdded(config, filePath) {
|
|
3523
|
+
let map = justAddedAt.get(config);
|
|
3524
|
+
if (!map) justAddedAt.set(config, map = /* @__PURE__ */ new Map());
|
|
3525
|
+
map.set(filePath, Date.now());
|
|
3526
|
+
}
|
|
3516
3527
|
function setupFileWatchers(testFileLookupPaths, config, onEventFunc, onFinishFunc) {
|
|
3517
3528
|
const extensions = config.extensions || defaultProjectConfigValues.extensions;
|
|
3518
3529
|
config._lastBuildEndMs ??= Date.now();
|
|
@@ -3679,6 +3690,11 @@ function handleWatchEvent(config, extensions, event, filePath, onEventFunc, onFi
|
|
|
3679
3690
|
return Promise.resolve();
|
|
3680
3691
|
if (event === "change" && config._building && config._justAddedFiles?.has(filePath))
|
|
3681
3692
|
return Promise.resolve();
|
|
3693
|
+
if (event === "change") {
|
|
3694
|
+
const addedAt = justAddedAt.get(config)?.get(filePath);
|
|
3695
|
+
if (addedAt !== void 0 && Date.now() - addedAt < ADD_SUPPRESS_WINDOW_MS)
|
|
3696
|
+
return Promise.resolve();
|
|
3697
|
+
}
|
|
3682
3698
|
mutateFSTree(config.fsTree, event, filePath);
|
|
3683
3699
|
console.log(
|
|
3684
3700
|
"#",
|
|
@@ -3690,6 +3706,7 @@ function handleWatchEvent(config, extensions, event, filePath, onEventFunc, onFi
|
|
|
3690
3706
|
"#",
|
|
3691
3707
|
magenta().bold("==================================================================")
|
|
3692
3708
|
);
|
|
3709
|
+
if (event === "add") recordJustAdded(config, filePath);
|
|
3693
3710
|
if (config._building) {
|
|
3694
3711
|
if (event === "add") config._justAddedFiles?.add(filePath);
|
|
3695
3712
|
config._pendingBuildTrigger = () => handleWatchEvent(config, extensions, event, filePath, onEventFunc, onFinishFunc);
|
|
@@ -3697,12 +3714,12 @@ function handleWatchEvent(config, extensions, event, filePath, onEventFunc, onFi
|
|
|
3697
3714
|
}
|
|
3698
3715
|
config._building = true;
|
|
3699
3716
|
config._justAddedFiles = event === "add" ? /* @__PURE__ */ new Set([filePath]) : /* @__PURE__ */ new Set();
|
|
3700
|
-
const
|
|
3701
|
-
if (!(
|
|
3717
|
+
const result2 = onEventFunc(event, filePath);
|
|
3718
|
+
if (!(result2 instanceof Promise)) {
|
|
3702
3719
|
config._building = false;
|
|
3703
3720
|
return Promise.resolve();
|
|
3704
3721
|
}
|
|
3705
|
-
return
|
|
3722
|
+
return result2.then(() => onFinishFunc?.(filePath, event)).catch((error) => console.error("#", red("Build error:"), error.message || error)).finally(() => {
|
|
3706
3723
|
config._building = false;
|
|
3707
3724
|
config._lastBuildEndMs = Date.now();
|
|
3708
3725
|
if (config._pendingBuildTrigger) {
|
|
@@ -3798,7 +3815,7 @@ function colorEvent(event) {
|
|
|
3798
3815
|
if (event === "add" || event === "addDir") return green("ADDED:");
|
|
3799
3816
|
return red("REMOVED:");
|
|
3800
3817
|
}
|
|
3801
|
-
var CHANGE_DEDUPE_MS, SYMLINK_POLL_INTERVAL_MS, OVERLAYFS_RENAME_RETRY_MS, RESCAN_INTERVAL_MS;
|
|
3818
|
+
var CHANGE_DEDUPE_MS, SYMLINK_POLL_INTERVAL_MS, OVERLAYFS_RENAME_RETRY_MS, RESCAN_INTERVAL_MS, ADD_SUPPRESS_WINDOW_MS, justAddedAt;
|
|
3802
3819
|
var init_file_watcher = __esm({
|
|
3803
3820
|
"lib/setup/file-watcher.ts"() {
|
|
3804
3821
|
init_color();
|
|
@@ -3807,6 +3824,8 @@ var init_file_watcher = __esm({
|
|
|
3807
3824
|
SYMLINK_POLL_INTERVAL_MS = 500;
|
|
3808
3825
|
OVERLAYFS_RENAME_RETRY_MS = 50;
|
|
3809
3826
|
RESCAN_INTERVAL_MS = 1e3;
|
|
3827
|
+
ADD_SUPPRESS_WINDOW_MS = 1e3;
|
|
3828
|
+
justAddedAt = /* @__PURE__ */ new WeakMap();
|
|
3810
3829
|
}
|
|
3811
3830
|
});
|
|
3812
3831
|
|
|
@@ -4211,14 +4230,14 @@ async function buildCachedContent(config, htmlPaths) {
|
|
|
4211
4230
|
config.htmlPaths.map((htmlPath) => fs14.readFile(htmlPath).catch(() => null))
|
|
4212
4231
|
);
|
|
4213
4232
|
const cachedContent = htmlPaths.reduce(
|
|
4214
|
-
(
|
|
4233
|
+
(result2, _htmlPath, index) => {
|
|
4215
4234
|
const buffer = htmlBuffers[index];
|
|
4216
|
-
if (buffer === null) return
|
|
4235
|
+
if (buffer === null) return result2;
|
|
4217
4236
|
const filePath = config.htmlPaths[index];
|
|
4218
4237
|
const html = buffer.toString();
|
|
4219
4238
|
if (isCustomTemplate(html)) {
|
|
4220
|
-
|
|
4221
|
-
|
|
4239
|
+
result2.dynamicContentHTMLs[filePath] = html;
|
|
4240
|
+
result2.htmlPathsToRunTests.push(filePath.replace(config.projectRoot, ""));
|
|
4222
4241
|
} else {
|
|
4223
4242
|
console.log(
|
|
4224
4243
|
"#",
|
|
@@ -4226,12 +4245,12 @@ async function buildCachedContent(config, htmlPaths) {
|
|
|
4226
4245
|
`WARNING: Static html file with no {{qunitxScript}} or handlebars-style tokens detected. Therefore ignoring ${filePath}`
|
|
4227
4246
|
)
|
|
4228
4247
|
);
|
|
4229
|
-
|
|
4248
|
+
result2.staticHTMLs[filePath] = html;
|
|
4230
4249
|
}
|
|
4231
4250
|
findInternalAssetsFromHTML(html).forEach((key) => {
|
|
4232
|
-
|
|
4251
|
+
result2.assets.add(normalizeInternalAssetPathFromHTML(config.projectRoot, key, filePath));
|
|
4233
4252
|
});
|
|
4234
|
-
return
|
|
4253
|
+
return result2;
|
|
4235
4254
|
},
|
|
4236
4255
|
{
|
|
4237
4256
|
allTestCode: null,
|
|
@@ -4270,16 +4289,16 @@ async function readTimingCache(projectRoot) {
|
|
|
4270
4289
|
}
|
|
4271
4290
|
}
|
|
4272
4291
|
function computeFileTimes(groups, weights, wallTimes) {
|
|
4273
|
-
const
|
|
4292
|
+
const result2 = /* @__PURE__ */ new Map();
|
|
4274
4293
|
groups.forEach((group, i) => {
|
|
4275
4294
|
const wallMs = wallTimes.get(i);
|
|
4276
4295
|
if (wallMs === void 0) return;
|
|
4277
4296
|
const total = group.reduce((sum, f) => sum + (weights.get(f) ?? 0), 0);
|
|
4278
4297
|
group.forEach(
|
|
4279
|
-
(f) =>
|
|
4298
|
+
(f) => result2.set(f, total > 0 ? wallMs * ((weights.get(f) ?? 0) / total) : wallMs / group.length)
|
|
4280
4299
|
);
|
|
4281
4300
|
});
|
|
4282
|
-
return
|
|
4301
|
+
return result2;
|
|
4283
4302
|
}
|
|
4284
4303
|
async function persistTimings(fileTimes, projectRoot) {
|
|
4285
4304
|
await fs14.writeFile(
|
|
@@ -4744,9 +4763,9 @@ async function startDaemon() {
|
|
|
4744
4763
|
`);
|
|
4745
4764
|
return 0;
|
|
4746
4765
|
}
|
|
4747
|
-
const
|
|
4748
|
-
if (
|
|
4749
|
-
process.stdout.write(`Daemon started (pid ${
|
|
4766
|
+
const result2 = await spawnAndWaitForDaemon();
|
|
4767
|
+
if (result2) {
|
|
4768
|
+
process.stdout.write(`Daemon started (pid ${result2.pid})
|
|
4750
4769
|
`);
|
|
4751
4770
|
return 0;
|
|
4752
4771
|
}
|
|
@@ -4806,6 +4825,13 @@ ${highlight2("Tip:")} set ${color2("QUNITX_DAEMON=1")} to auto-spawn the daemon
|
|
|
4806
4825
|
}
|
|
4807
4826
|
});
|
|
4808
4827
|
|
|
4828
|
+
// lib/utils/enable-compile-cache.ts
|
|
4829
|
+
import module from "node:module";
|
|
4830
|
+
var result = module.enableCompileCache?.();
|
|
4831
|
+
if (result?.directory && !("NODE_COMPILE_CACHE" in process.env)) {
|
|
4832
|
+
process.env.NODE_COMPILE_CACHE = result.directory;
|
|
4833
|
+
}
|
|
4834
|
+
|
|
4809
4835
|
// cli.ts
|
|
4810
4836
|
init_chrome_prelaunch();
|
|
4811
4837
|
init_package();
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "qunitx-cli",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.23.
|
|
4
|
+
"version": "0.23.5",
|
|
5
5
|
"description": "Browser runner for QUnitx: run your qunitx tests in google-chrome",
|
|
6
6
|
"author": "Izel Nakri",
|
|
7
7
|
"license": "MIT",
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"prepublishOnly": "npm run build",
|
|
25
25
|
"format": "prettier --check \"lib/**/*.ts\" \"test/**/*.ts\" \"scripts/**/*.js\" \"bin/**/*.js\" \"*.ts\" \"package.json\" \".github/**/*.yml\"",
|
|
26
26
|
"format:fix": "prettier --write \"lib/**/*.ts\" \"test/**/*.ts\" \"scripts/**/*.js\" \"bin/**/*.js\" \"*.ts\" \"package.json\" \".github/**/*.yml\"",
|
|
27
|
-
"lint": "deno lint lib/ bin/ cli.ts",
|
|
27
|
+
"lint": "deno lint lib/ bin/ test/ scripts/ cli.ts",
|
|
28
28
|
"lint:docs": "node scripts/lint-docs.js",
|
|
29
29
|
"docs": "deno doc --html --name=\"qunitx-cli\" --output=docs/lib 'lib/**/*.ts' README.md",
|
|
30
30
|
"changelog:unreleased": "git-cliff --unreleased --strip all",
|