qunitx-cli 0.23.4 → 0.23.6

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 (2) hide show
  1. package/dist/cli.js +42 -8
  2. package/package.json +2 -2
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.4",
377
+ version: "0.23.6",
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;
@@ -1150,6 +1153,9 @@ 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
1161
  function parseBoolean(result2, defaultValue = true) {
@@ -3323,15 +3329,16 @@ async function runTestInsideHTMLFile(filePath, { page, server, browser }, config
3323
3329
  let targetError;
3324
3330
  let timeoutHandle;
3325
3331
  let wsConnected = false;
3332
+ let resolveTestRace;
3333
+ const testRaceResult = new Promise((resolve) => {
3334
+ resolveTestRace = resolve;
3335
+ });
3336
+ page.on("close", resolveTestRace);
3326
3337
  try {
3327
3338
  console.log("#", blue(`QUnitX running: http://localhost:${config.port}${filePath}`));
3328
3339
  const navMs = Math.max(config.timeout + NAV_GRACE_MS, MIN_NAV_MS);
3329
3340
  const startupMs = Math.max(config.timeout * STARTUP_TIMEOUT_FACTOR, navMs);
3330
3341
  const testsJsMs = Math.max(config.timeout * TESTS_JS_TIMEOUT_FACTOR, navMs);
3331
- let resolveTestRace;
3332
- const testRaceResult = new Promise((resolve) => {
3333
- resolveTestRace = resolve;
3334
- });
3335
3342
  config._testRunDone = resolveTestRace;
3336
3343
  config._onWsOpen = () => {
3337
3344
  wsConnected = true;
@@ -3364,6 +3371,7 @@ async function runTestInsideHTMLFile(filePath, { page, server, browser }, config
3364
3371
  console.error(error);
3365
3372
  } finally {
3366
3373
  clearTimeout(timeoutHandle);
3374
+ page.off("close", resolveTestRace);
3367
3375
  config._onWsOpen = null;
3368
3376
  config._onTestsJsServed = null;
3369
3377
  config._resetTestTimeout = null;
@@ -3513,6 +3521,11 @@ var init_open_output_in_browser = __esm({
3513
3521
  import fs11 from "node:fs";
3514
3522
  import { readdir, stat, lstat } from "node:fs/promises";
3515
3523
  import path9 from "node:path";
3524
+ function recordJustAdded(config, filePath) {
3525
+ let map = justAddedAt.get(config);
3526
+ if (!map) justAddedAt.set(config, map = /* @__PURE__ */ new Map());
3527
+ map.set(filePath, Date.now());
3528
+ }
3516
3529
  function setupFileWatchers(testFileLookupPaths, config, onEventFunc, onFinishFunc) {
3517
3530
  const extensions = config.extensions || defaultProjectConfigValues.extensions;
3518
3531
  config._lastBuildEndMs ??= Date.now();
@@ -3521,6 +3534,7 @@ function setupFileWatchers(testFileLookupPaths, config, onEventFunc, onFinishFun
3521
3534
  const rescanTimers = [];
3522
3535
  const fileWatchers = {};
3523
3536
  const symlinkPollers = /* @__PURE__ */ new Map();
3537
+ const pendingChangeTimers = /* @__PURE__ */ new Map();
3524
3538
  function trackSymlink(filePath) {
3525
3539
  if (symlinkPollers.has(filePath)) return;
3526
3540
  const handler = (curr, prev) => {
@@ -3580,7 +3594,16 @@ function setupFileWatchers(testFileLookupPaths, config, onEventFunc, onFinishFun
3580
3594
  return;
3581
3595
  } catch {
3582
3596
  }
3583
- return handleWatchEvent(config, extensions, "change", fullPath, onEventFunc, onFinishFunc);
3597
+ const existing = pendingChangeTimers.get(fullPath);
3598
+ if (existing) clearTimeout(existing);
3599
+ pendingChangeTimers.set(
3600
+ fullPath,
3601
+ setTimeout(() => {
3602
+ pendingChangeTimers.delete(fullPath);
3603
+ handleWatchEvent(config, extensions, "change", fullPath, onEventFunc, onFinishFunc);
3604
+ }, CHANGE_COALESCE_MS)
3605
+ );
3606
+ return;
3584
3607
  }
3585
3608
  const event = await classifyRenameEvent(fullPath, config.fsTree);
3586
3609
  if (!event) return;
@@ -3670,6 +3693,8 @@ function setupFileWatchers(testFileLookupPaths, config, onEventFunc, onFinishFun
3670
3693
  rescanTimers.forEach((t) => clearInterval(t));
3671
3694
  symlinkPollers.forEach((cancel) => cancel());
3672
3695
  symlinkPollers.clear();
3696
+ pendingChangeTimers.forEach((t) => clearTimeout(t));
3697
+ pendingChangeTimers.clear();
3673
3698
  return fileWatchers;
3674
3699
  }
3675
3700
  };
@@ -3679,6 +3704,11 @@ function handleWatchEvent(config, extensions, event, filePath, onEventFunc, onFi
3679
3704
  return Promise.resolve();
3680
3705
  if (event === "change" && config._building && config._justAddedFiles?.has(filePath))
3681
3706
  return Promise.resolve();
3707
+ if (event === "change") {
3708
+ const addedAt = justAddedAt.get(config)?.get(filePath);
3709
+ if (addedAt !== void 0 && Date.now() - addedAt < ADD_SUPPRESS_WINDOW_MS)
3710
+ return Promise.resolve();
3711
+ }
3682
3712
  mutateFSTree(config.fsTree, event, filePath);
3683
3713
  console.log(
3684
3714
  "#",
@@ -3690,6 +3720,7 @@ function handleWatchEvent(config, extensions, event, filePath, onEventFunc, onFi
3690
3720
  "#",
3691
3721
  magenta().bold("==================================================================")
3692
3722
  );
3723
+ if (event === "add") recordJustAdded(config, filePath);
3693
3724
  if (config._building) {
3694
3725
  if (event === "add") config._justAddedFiles?.add(filePath);
3695
3726
  config._pendingBuildTrigger = () => handleWatchEvent(config, extensions, event, filePath, onEventFunc, onFinishFunc);
@@ -3798,7 +3829,7 @@ function colorEvent(event) {
3798
3829
  if (event === "add" || event === "addDir") return green("ADDED:");
3799
3830
  return red("REMOVED:");
3800
3831
  }
3801
- var CHANGE_DEDUPE_MS, SYMLINK_POLL_INTERVAL_MS, OVERLAYFS_RENAME_RETRY_MS, RESCAN_INTERVAL_MS;
3832
+ var CHANGE_DEDUPE_MS, SYMLINK_POLL_INTERVAL_MS, OVERLAYFS_RENAME_RETRY_MS, RESCAN_INTERVAL_MS, CHANGE_COALESCE_MS, ADD_SUPPRESS_WINDOW_MS, justAddedAt;
3802
3833
  var init_file_watcher = __esm({
3803
3834
  "lib/setup/file-watcher.ts"() {
3804
3835
  init_color();
@@ -3807,6 +3838,9 @@ var init_file_watcher = __esm({
3807
3838
  SYMLINK_POLL_INTERVAL_MS = 500;
3808
3839
  OVERLAYFS_RENAME_RETRY_MS = 50;
3809
3840
  RESCAN_INTERVAL_MS = 1e3;
3841
+ CHANGE_COALESCE_MS = 50;
3842
+ ADD_SUPPRESS_WINDOW_MS = 1e3;
3843
+ justAddedAt = /* @__PURE__ */ new WeakMap();
3810
3844
  }
3811
3845
  });
3812
3846
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "qunitx-cli",
3
3
  "type": "module",
4
- "version": "0.23.4",
4
+ "version": "0.23.6",
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",