qat-cli 0.2.6 → 0.2.8

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 CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  **Quick Auto Testing — 面向 Vue 项目,集成 Vitest & Playwright,AI 驱动覆盖测试全流程**
6
6
 
7
- [![npm version](https://img.shields.io/badge/version-0.2.6-blue.svg)](https://www.npmjs.com/package/qat-cli)
7
+ [![npm version](https://img.shields.io/badge/version-0.2.8-blue.svg)](https://www.npmjs.com/package/qat-cli)
8
8
  [![Node.js](https://img.shields.io/badge/node-%3E%3D18.0.0-green.svg)](https://nodejs.org/)
9
9
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
10
10
  [![TypeScript](https://img.shields.io/badge/TypeScript-5.6-blue.svg)](https://www.typescriptlang.org/)
package/dist/cli.js CHANGED
@@ -467,17 +467,20 @@ async function loadConfig(configPath, forceReload = false) {
467
467
  }
468
468
  async function importConfig(filePath) {
469
469
  const { resolve } = await import("path");
470
+ const { pathToFileURL } = await import("url");
470
471
  const absolutePath = resolve(process.cwd(), filePath);
471
472
  if (!fs2.existsSync(absolutePath)) {
472
473
  throw new Error(`Cannot find module '${absolutePath}'`);
473
474
  }
475
+ const fileUrl = pathToFileURL(absolutePath).href;
474
476
  try {
475
- const module = await import(absolutePath);
477
+ const module = await import(fileUrl);
476
478
  return module.default || module;
477
479
  } catch {
478
480
  const jsPath = absolutePath.replace(/\.ts$/, ".js");
479
- if (fs2.existsSync(jsPath)) {
480
- const module = await import(jsPath);
481
+ if (jsPath !== absolutePath && fs2.existsSync(jsPath)) {
482
+ const jsUrl = pathToFileURL(jsPath).href;
483
+ const module = await import(jsUrl);
481
484
  return module.default || module;
482
485
  }
483
486
  throw new Error(`\u65E0\u6CD5\u52A0\u8F7D\u914D\u7F6E\u6587\u4EF6: ${absolutePath}`);
@@ -3166,6 +3169,8 @@ function displayCreateResult(createdFiles, skippedCount, usedAI) {
3166
3169
  import chalk5 from "chalk";
3167
3170
  import inquirer3 from "inquirer";
3168
3171
  import ora4 from "ora";
3172
+ import fs9 from "fs";
3173
+ import path11 from "path";
3169
3174
 
3170
3175
  // src/runners/vitest-runner.ts
3171
3176
  import { execFile } from "child_process";
@@ -3831,6 +3836,8 @@ function calculateAverageMetrics(results) {
3831
3836
  }
3832
3837
 
3833
3838
  // src/commands/run.ts
3839
+ var RESULTS_DIR = ".qat-results";
3840
+ var SERVER_REQUIRED_TYPES = ["e2e", "visual", "performance"];
3834
3841
  var TYPE_RUNNERS = {
3835
3842
  unit: "Vitest",
3836
3843
  component: "Vitest",
@@ -3875,6 +3882,62 @@ async function executeRun(options) {
3875
3882
  console.log(chalk5.yellow("\n \u6CA1\u6709\u53EF\u8FD0\u884C\u7684\u6D4B\u8BD5\u7C7B\u578B\uFF08\u8BF7\u5728 qat.config.ts \u4E2D\u542F\u7528\uFF09\n"));
3876
3883
  return;
3877
3884
  }
3885
+ const serverNeededTypes = typesToRun.filter((t) => SERVER_REQUIRED_TYPES.includes(t));
3886
+ if (serverNeededTypes.length > 0) {
3887
+ const serverOk = await checkDevServer(config);
3888
+ if (!serverOk) {
3889
+ const { action } = await inquirer3.prompt([
3890
+ {
3891
+ type: "list",
3892
+ name: "action",
3893
+ message: `\u8FD0\u884C ${serverNeededTypes.map((t) => TYPE_LABELS[t]).join("\u3001")} \u9700\u8981\u9879\u76EE\u670D\u52A1\u8FD0\u884C\uFF0C\u5982\u4F55\u5904\u7406\uFF1F`,
3894
+ choices: [
3895
+ { name: "\u81EA\u52A8\u542F\u52A8 dev server \u5E76\u8FD0\u884C", value: "start" },
3896
+ { name: "\u8DF3\u8FC7\u8FD9\u4E9B\u6D4B\u8BD5\u7C7B\u578B\uFF0C\u4EC5\u8FD0\u884C\u5176\u4ED6\u6D4B\u8BD5", value: "skip" },
3897
+ { name: "\u53D6\u6D88\u8FD0\u884C", value: "cancel" }
3898
+ ],
3899
+ default: "start"
3900
+ }
3901
+ ]);
3902
+ if (action === "cancel") {
3903
+ console.log(chalk5.gray("\n \u5DF2\u53D6\u6D88\u8FD0\u884C\n"));
3904
+ return;
3905
+ }
3906
+ if (action === "skip") {
3907
+ typesToRun = typesToRun.filter((t) => !SERVER_REQUIRED_TYPES.includes(t));
3908
+ if (typesToRun.length === 0) {
3909
+ console.log(chalk5.yellow("\n \u6CA1\u6709\u53EF\u8FD0\u884C\u7684\u6D4B\u8BD5\u7C7B\u578B\n"));
3910
+ return;
3911
+ }
3912
+ }
3913
+ if (action === "start") {
3914
+ const started = await startDevServer(config);
3915
+ if (!started) {
3916
+ const { fallback } = await inquirer3.prompt([
3917
+ {
3918
+ type: "list",
3919
+ name: "fallback",
3920
+ message: "dev server \u542F\u52A8\u5931\u8D25\uFF0C\u5982\u4F55\u5904\u7406\uFF1F",
3921
+ choices: [
3922
+ { name: "\u8DF3\u8FC7\u9700\u8981\u670D\u52A1\u7684\u6D4B\u8BD5\uFF0C\u4EC5\u8FD0\u884C\u5176\u4ED6\u6D4B\u8BD5", value: "skip" },
3923
+ { name: "\u53D6\u6D88\u8FD0\u884C", value: "cancel" }
3924
+ ],
3925
+ default: "skip"
3926
+ }
3927
+ ]);
3928
+ if (fallback === "cancel") {
3929
+ console.log(chalk5.gray("\n \u5DF2\u53D6\u6D88\u8FD0\u884C\n"));
3930
+ return;
3931
+ }
3932
+ typesToRun = typesToRun.filter((t) => !SERVER_REQUIRED_TYPES.includes(t));
3933
+ if (typesToRun.length === 0) {
3934
+ console.log(chalk5.yellow("\n \u6CA1\u6709\u53EF\u8FD0\u884C\u7684\u6D4B\u8BD5\u7C7B\u578B\n"));
3935
+ return;
3936
+ }
3937
+ }
3938
+ }
3939
+ }
3940
+ }
3878
3941
  if (!type && !file) {
3879
3942
  const { runMode } = await inquirer3.prompt([
3880
3943
  {
@@ -3921,6 +3984,7 @@ async function executeRun(options) {
3921
3984
  }
3922
3985
  }
3923
3986
  displaySummary(results, config);
3987
+ saveRunResults(results);
3924
3988
  }
3925
3989
  function printDryRunCommands(types, options, config) {
3926
3990
  console.log();
@@ -4248,6 +4312,71 @@ function scoreColor(score) {
4248
4312
  if (score >= 50) return chalk5.yellow("\u25CF");
4249
4313
  return chalk5.red("\u25CF");
4250
4314
  }
4315
+ async function checkDevServer(config) {
4316
+ const baseUrl = config.playwright.baseURL || "http://localhost:5173";
4317
+ try {
4318
+ const controller = new AbortController();
4319
+ const timer = setTimeout(() => controller.abort(), 3e3);
4320
+ const response = await fetch(baseUrl, { signal: controller.signal, method: "HEAD" });
4321
+ clearTimeout(timer);
4322
+ return response.status > 0;
4323
+ } catch {
4324
+ return false;
4325
+ }
4326
+ }
4327
+ async function startDevServer(config) {
4328
+ const { spawn } = await import("child_process");
4329
+ const hasPnpm = fs9.existsSync(path11.join(process.cwd(), "pnpm-lock.yaml"));
4330
+ const hasYarn = fs9.existsSync(path11.join(process.cwd(), "yarn.lock"));
4331
+ const pkgCmd = hasPnpm ? "pnpm" : hasYarn ? "yarn" : "npm";
4332
+ console.log(chalk5.cyan(` \u6B63\u5728\u542F\u52A8 dev server (${pkgCmd} run dev) ...`));
4333
+ const child = spawn(pkgCmd, ["run", "dev"], {
4334
+ cwd: process.cwd(),
4335
+ stdio: "pipe",
4336
+ shell: true,
4337
+ detached: true
4338
+ });
4339
+ const baseUrl = config.playwright.baseURL || "http://localhost:5173";
4340
+ const maxWait = 3e4;
4341
+ const interval = 1e3;
4342
+ let waited = 0;
4343
+ while (waited < maxWait) {
4344
+ await new Promise((r) => setTimeout(r, interval));
4345
+ waited += interval;
4346
+ const isUp = await checkDevServer(config);
4347
+ if (isUp) {
4348
+ console.log(chalk5.green(` \u2713 dev server \u5DF2\u542F\u52A8 (${baseUrl})`));
4349
+ child.unref();
4350
+ return true;
4351
+ }
4352
+ }
4353
+ child.kill();
4354
+ console.log(chalk5.red(" \u2717 dev server \u542F\u52A8\u8D85\u65F6"));
4355
+ return false;
4356
+ }
4357
+ function saveRunResults(results) {
4358
+ if (results.length === 0) return;
4359
+ const resultsPath = path11.join(process.cwd(), RESULTS_DIR);
4360
+ if (!fs9.existsSync(resultsPath)) {
4361
+ fs9.mkdirSync(resultsPath, { recursive: true });
4362
+ }
4363
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
4364
+ const fileName = `result-${timestamp}.json`;
4365
+ const filePath = path11.join(resultsPath, fileName);
4366
+ const data = {
4367
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
4368
+ results
4369
+ };
4370
+ fs9.writeFileSync(filePath, JSON.stringify(data, null, 2), "utf-8");
4371
+ try {
4372
+ const files = fs9.readdirSync(resultsPath).filter((f) => f.startsWith("result-") && f.endsWith(".json")).sort();
4373
+ while (files.length > 20) {
4374
+ const oldest = files.shift();
4375
+ fs9.unlinkSync(path11.join(resultsPath, oldest));
4376
+ }
4377
+ } catch {
4378
+ }
4379
+ }
4251
4380
 
4252
4381
  // src/commands/mock.ts
4253
4382
  import chalk6 from "chalk";
@@ -4371,12 +4500,12 @@ function showStatus() {
4371
4500
  // src/commands/report.ts
4372
4501
  import chalk7 from "chalk";
4373
4502
  import ora6 from "ora";
4374
- import fs10 from "fs";
4375
- import path12 from "path";
4503
+ import fs11 from "fs";
4504
+ import path13 from "path";
4376
4505
 
4377
4506
  // src/services/reporter.ts
4378
- import fs9 from "fs";
4379
- import path11 from "path";
4507
+ import fs10 from "fs";
4508
+ import path12 from "path";
4380
4509
  function aggregateResults(results) {
4381
4510
  const summary = {
4382
4511
  total: 0,
@@ -4631,17 +4760,17 @@ function generateHTMLReport(data) {
4631
4760
  }
4632
4761
  function writeReportToDisk(data, outputDir) {
4633
4762
  const html = generateHTMLReport(data);
4634
- const dir = path11.resolve(outputDir);
4635
- if (!fs9.existsSync(dir)) {
4636
- fs9.mkdirSync(dir, { recursive: true });
4763
+ const dir = path12.resolve(outputDir);
4764
+ if (!fs10.existsSync(dir)) {
4765
+ fs10.mkdirSync(dir, { recursive: true });
4637
4766
  }
4638
- const indexPath = path11.join(dir, "index.html");
4639
- fs9.writeFileSync(indexPath, html, "utf-8");
4767
+ const indexPath = path12.join(dir, "index.html");
4768
+ fs10.writeFileSync(indexPath, html, "utf-8");
4640
4769
  return indexPath;
4641
4770
  }
4642
4771
 
4643
4772
  // src/commands/report.ts
4644
- var RESULTS_DIR = ".qat-results";
4773
+ var RESULTS_DIR2 = ".qat-results";
4645
4774
  function registerReportCommand(program2) {
4646
4775
  program2.command("report").description("\u751F\u6210\u6D4B\u8BD5\u62A5\u544A - \u805A\u5408\u6240\u6709\u6D4B\u8BD5\u7ED3\u679C\u5E76\u8F93\u51FAHTML").option("-o, --output <dir>", "\u62A5\u544A\u8F93\u51FA\u76EE\u5F55").option("--open", "\u751F\u6210\u540E\u81EA\u52A8\u6253\u5F00\u62A5\u544A", false).action(async (options) => {
4647
4776
  try {
@@ -4676,15 +4805,15 @@ async function executeReport(options) {
4676
4805
  }
4677
4806
  function collectResults() {
4678
4807
  const results = [];
4679
- const resultsPath = path12.join(process.cwd(), RESULTS_DIR);
4680
- if (!fs10.existsSync(resultsPath)) {
4808
+ const resultsPath = path13.join(process.cwd(), RESULTS_DIR2);
4809
+ if (!fs11.existsSync(resultsPath)) {
4681
4810
  return results;
4682
4811
  }
4683
- const files = fs10.readdirSync(resultsPath).filter((f) => f.endsWith(".json")).sort().reverse();
4812
+ const files = fs11.readdirSync(resultsPath).filter((f) => f.endsWith(".json")).sort().reverse();
4684
4813
  if (files.length > 0) {
4685
- const latestFile = path12.join(resultsPath, files[0]);
4814
+ const latestFile = path13.join(resultsPath, files[0]);
4686
4815
  try {
4687
- const data = JSON.parse(fs10.readFileSync(latestFile, "utf-8"));
4816
+ const data = JSON.parse(fs11.readFileSync(latestFile, "utf-8"));
4688
4817
  if (Array.isArray(data)) {
4689
4818
  results.push(...data);
4690
4819
  } else if (data.results) {
@@ -4696,22 +4825,22 @@ function collectResults() {
4696
4825
  return results;
4697
4826
  }
4698
4827
  function saveResultToHistory(reportData) {
4699
- const resultsPath = path12.join(process.cwd(), RESULTS_DIR);
4700
- if (!fs10.existsSync(resultsPath)) {
4701
- fs10.mkdirSync(resultsPath, { recursive: true });
4828
+ const resultsPath = path13.join(process.cwd(), RESULTS_DIR2);
4829
+ if (!fs11.existsSync(resultsPath)) {
4830
+ fs11.mkdirSync(resultsPath, { recursive: true });
4702
4831
  }
4703
4832
  const timestamp = new Date(reportData.timestamp).toISOString().replace(/[:.]/g, "-");
4704
4833
  const fileName = `result-${timestamp}.json`;
4705
- const filePath = path12.join(resultsPath, fileName);
4706
- fs10.writeFileSync(filePath, JSON.stringify(reportData, null, 2), "utf-8");
4707
- const files = fs10.readdirSync(resultsPath).filter((f) => f.startsWith("result-") && f.endsWith(".json")).sort();
4834
+ const filePath = path13.join(resultsPath, fileName);
4835
+ fs11.writeFileSync(filePath, JSON.stringify(reportData, null, 2), "utf-8");
4836
+ const files = fs11.readdirSync(resultsPath).filter((f) => f.startsWith("result-") && f.endsWith(".json")).sort();
4708
4837
  while (files.length > 20) {
4709
4838
  const oldest = files.shift();
4710
- fs10.unlinkSync(path12.join(resultsPath, oldest));
4839
+ fs11.unlinkSync(path13.join(resultsPath, oldest));
4711
4840
  }
4712
4841
  }
4713
4842
  function displayReportResult(reportPath, data) {
4714
- const relativePath = path12.relative(process.cwd(), reportPath);
4843
+ const relativePath = path13.relative(process.cwd(), reportPath);
4715
4844
  console.log();
4716
4845
  console.log(chalk7.green(" \u2713 \u6D4B\u8BD5\u62A5\u544A\u5DF2\u751F\u6210"));
4717
4846
  console.log();
@@ -4758,19 +4887,19 @@ import chalk8 from "chalk";
4758
4887
  import ora7 from "ora";
4759
4888
 
4760
4889
  // src/services/visual.ts
4761
- import fs11 from "fs";
4762
- import path13 from "path";
4890
+ import fs12 from "fs";
4891
+ import path14 from "path";
4763
4892
  import pixelmatch from "pixelmatch";
4764
4893
  import { PNG } from "pngjs";
4765
4894
  function compareImages(baselinePath, currentPath, diffOutputPath, threshold = 0.1) {
4766
- if (!fs11.existsSync(baselinePath)) {
4895
+ if (!fs12.existsSync(baselinePath)) {
4767
4896
  throw new Error(`\u57FA\u7EBF\u56FE\u7247\u4E0D\u5B58\u5728: ${baselinePath}`);
4768
4897
  }
4769
- if (!fs11.existsSync(currentPath)) {
4898
+ if (!fs12.existsSync(currentPath)) {
4770
4899
  throw new Error(`\u5F53\u524D\u56FE\u7247\u4E0D\u5B58\u5728: ${currentPath}`);
4771
4900
  }
4772
- const baseline = PNG.sync.read(fs11.readFileSync(baselinePath));
4773
- const current = PNG.sync.read(fs11.readFileSync(currentPath));
4901
+ const baseline = PNG.sync.read(fs12.readFileSync(baselinePath));
4902
+ const current = PNG.sync.read(fs12.readFileSync(currentPath));
4774
4903
  if (baseline.width !== current.width || baseline.height !== current.height) {
4775
4904
  return {
4776
4905
  passed: false,
@@ -4798,11 +4927,11 @@ function compareImages(baselinePath, currentPath, diffOutputPath, threshold = 0.
4798
4927
  const passed = diffRatio <= threshold;
4799
4928
  let diffPath;
4800
4929
  if (diffPixels > 0) {
4801
- const diffDir = path13.dirname(diffOutputPath);
4802
- if (!fs11.existsSync(diffDir)) {
4803
- fs11.mkdirSync(diffDir, { recursive: true });
4930
+ const diffDir = path14.dirname(diffOutputPath);
4931
+ if (!fs12.existsSync(diffDir)) {
4932
+ fs12.mkdirSync(diffDir, { recursive: true });
4804
4933
  }
4805
- fs11.writeFileSync(diffOutputPath, PNG.sync.write(diff));
4934
+ fs12.writeFileSync(diffOutputPath, PNG.sync.write(diff));
4806
4935
  diffPath = diffOutputPath;
4807
4936
  }
4808
4937
  return {
@@ -4816,69 +4945,69 @@ function compareImages(baselinePath, currentPath, diffOutputPath, threshold = 0.
4816
4945
  };
4817
4946
  }
4818
4947
  function createBaseline(currentPath, baselinePath) {
4819
- if (!fs11.existsSync(currentPath)) {
4948
+ if (!fs12.existsSync(currentPath)) {
4820
4949
  throw new Error(`\u5F53\u524D\u622A\u56FE\u4E0D\u5B58\u5728: ${currentPath}`);
4821
4950
  }
4822
- const baselineDir = path13.dirname(baselinePath);
4823
- if (!fs11.existsSync(baselineDir)) {
4824
- fs11.mkdirSync(baselineDir, { recursive: true });
4951
+ const baselineDir = path14.dirname(baselinePath);
4952
+ if (!fs12.existsSync(baselineDir)) {
4953
+ fs12.mkdirSync(baselineDir, { recursive: true });
4825
4954
  }
4826
- fs11.copyFileSync(currentPath, baselinePath);
4955
+ fs12.copyFileSync(currentPath, baselinePath);
4827
4956
  return baselinePath;
4828
4957
  }
4829
4958
  function updateAllBaselines(currentDir, baselineDir) {
4830
4959
  const updated = [];
4831
- if (!fs11.existsSync(currentDir)) {
4960
+ if (!fs12.existsSync(currentDir)) {
4832
4961
  return updated;
4833
4962
  }
4834
- const files = fs11.readdirSync(currentDir).filter((f) => f.endsWith(".png"));
4963
+ const files = fs12.readdirSync(currentDir).filter((f) => f.endsWith(".png"));
4835
4964
  for (const file of files) {
4836
- const currentPath = path13.join(currentDir, file);
4837
- const baselinePath = path13.join(baselineDir, file);
4838
- const baselineDirAbs = path13.dirname(baselinePath);
4839
- if (!fs11.existsSync(baselineDirAbs)) {
4840
- fs11.mkdirSync(baselineDirAbs, { recursive: true });
4965
+ const currentPath = path14.join(currentDir, file);
4966
+ const baselinePath = path14.join(baselineDir, file);
4967
+ const baselineDirAbs = path14.dirname(baselinePath);
4968
+ if (!fs12.existsSync(baselineDirAbs)) {
4969
+ fs12.mkdirSync(baselineDirAbs, { recursive: true });
4841
4970
  }
4842
- fs11.copyFileSync(currentPath, baselinePath);
4971
+ fs12.copyFileSync(currentPath, baselinePath);
4843
4972
  updated.push(file);
4844
4973
  }
4845
4974
  return updated;
4846
4975
  }
4847
4976
  function cleanBaselines(baselineDir) {
4848
- if (!fs11.existsSync(baselineDir)) {
4977
+ if (!fs12.existsSync(baselineDir)) {
4849
4978
  return 0;
4850
4979
  }
4851
- const files = fs11.readdirSync(baselineDir).filter((f) => f.endsWith(".png"));
4980
+ const files = fs12.readdirSync(baselineDir).filter((f) => f.endsWith(".png"));
4852
4981
  let count = 0;
4853
4982
  for (const file of files) {
4854
- fs11.unlinkSync(path13.join(baselineDir, file));
4983
+ fs12.unlinkSync(path14.join(baselineDir, file));
4855
4984
  count++;
4856
4985
  }
4857
4986
  return count;
4858
4987
  }
4859
4988
  function cleanDiffs(diffDir) {
4860
- if (!fs11.existsSync(diffDir)) {
4989
+ if (!fs12.existsSync(diffDir)) {
4861
4990
  return 0;
4862
4991
  }
4863
- const files = fs11.readdirSync(diffDir).filter((f) => f.endsWith(".png"));
4992
+ const files = fs12.readdirSync(diffDir).filter((f) => f.endsWith(".png"));
4864
4993
  let count = 0;
4865
4994
  for (const file of files) {
4866
- fs11.unlinkSync(path13.join(diffDir, file));
4995
+ fs12.unlinkSync(path14.join(diffDir, file));
4867
4996
  count++;
4868
4997
  }
4869
4998
  return count;
4870
4999
  }
4871
5000
  function compareDirectories(baselineDir, currentDir, diffDir, threshold = 0.1) {
4872
5001
  const results = [];
4873
- if (!fs11.existsSync(currentDir)) {
5002
+ if (!fs12.existsSync(currentDir)) {
4874
5003
  return results;
4875
5004
  }
4876
- const currentFiles = fs11.readdirSync(currentDir).filter((f) => f.endsWith(".png"));
5005
+ const currentFiles = fs12.readdirSync(currentDir).filter((f) => f.endsWith(".png"));
4877
5006
  for (const file of currentFiles) {
4878
- const currentPath = path13.join(currentDir, file);
4879
- const baselinePath = path13.join(baselineDir, file);
4880
- const diffPath = path13.join(diffDir, file);
4881
- if (!fs11.existsSync(baselinePath)) {
5007
+ const currentPath = path14.join(currentDir, file);
5008
+ const baselinePath = path14.join(baselineDir, file);
5009
+ const diffPath = path14.join(diffDir, file);
5010
+ if (!fs12.existsSync(baselinePath)) {
4882
5011
  createBaseline(currentPath, baselinePath);
4883
5012
  results.push({
4884
5013
  passed: true,
@@ -4910,8 +5039,8 @@ function compareDirectories(baselineDir, currentDir, diffDir, threshold = 0.1) {
4910
5039
  }
4911
5040
 
4912
5041
  // src/commands/visual.ts
4913
- import fs12 from "fs";
4914
- import path14 from "path";
5042
+ import fs13 from "fs";
5043
+ import path15 from "path";
4915
5044
  function registerVisualCommand(program2) {
4916
5045
  program2.command("visual").description("\u89C6\u89C9\u56DE\u5F52\u6D4B\u8BD5 - \u622A\u56FE\u6BD4\u5BF9\u4E0E\u57FA\u7EBF\u7BA1\u7406").argument("<action>", "\u64CD\u4F5C\u7C7B\u578B (test|approve|clean)").option("--threshold <number>", "\u50CF\u7D20\u5DEE\u5F02\u9608\u503C (0-1)", "0.1").action(async (action, options) => {
4917
5046
  try {
@@ -4986,12 +5115,12 @@ async function runVisualTest(threshold, baselineDir, diffDir, config) {
4986
5115
  }
4987
5116
  function findCurrentScreenshotsDir(baselineDir) {
4988
5117
  const possibleDirs = [
4989
- path14.join(process.cwd(), "test-results"),
4990
- path14.join(process.cwd(), "tests", "visual", "current"),
4991
- path14.join(process.cwd(), baselineDir, "..", "current")
5118
+ path15.join(process.cwd(), "test-results"),
5119
+ path15.join(process.cwd(), "tests", "visual", "current"),
5120
+ path15.join(process.cwd(), baselineDir, "..", "current")
4992
5121
  ];
4993
5122
  for (const dir of possibleDirs) {
4994
- if (fs12.existsSync(dir)) {
5123
+ if (fs13.existsSync(dir)) {
4995
5124
  const pngs = findPngFiles(dir);
4996
5125
  if (pngs.length > 0) return dir;
4997
5126
  }
@@ -5001,10 +5130,10 @@ function findCurrentScreenshotsDir(baselineDir) {
5001
5130
  function findPngFiles(dir) {
5002
5131
  const files = [];
5003
5132
  function walk(d) {
5004
- if (!fs12.existsSync(d)) return;
5005
- const entries = fs12.readdirSync(d, { withFileTypes: true });
5133
+ if (!fs13.existsSync(d)) return;
5134
+ const entries = fs13.readdirSync(d, { withFileTypes: true });
5006
5135
  for (const entry of entries) {
5007
- const fullPath = path14.join(d, entry.name);
5136
+ const fullPath = path15.join(d, entry.name);
5008
5137
  if (entry.isDirectory() && entry.name !== "node_modules") {
5009
5138
  walk(fullPath);
5010
5139
  } else if (entry.name.endsWith(".png")) {
@@ -5033,7 +5162,7 @@ function displayVisualResults(results, threshold) {
5033
5162
  console.log();
5034
5163
  console.log(chalk8.green(" \u901A\u8FC7\u7684\u622A\u56FE:"));
5035
5164
  for (const result of passed) {
5036
- const name = path14.basename(result.baselinePath);
5165
+ const name = path15.basename(result.baselinePath);
5037
5166
  if (result.totalPixels > 0) {
5038
5167
  const diffPct = (result.diffRatio * 100).toFixed(2);
5039
5168
  console.log(chalk8.green(` \u2713 ${name} (\u5DEE\u5F02: ${diffPct}%)`));
@@ -5046,7 +5175,7 @@ function displayVisualResults(results, threshold) {
5046
5175
  console.log();
5047
5176
  console.log(chalk8.red(" \u5931\u8D25\u7684\u622A\u56FE:"));
5048
5177
  for (const result of failed) {
5049
- const name = path14.basename(result.baselinePath);
5178
+ const name = path15.basename(result.baselinePath);
5050
5179
  if (result.diffPixels === -1) {
5051
5180
  console.log(chalk8.red(` \u2717 ${name} (\u5C3A\u5BF8\u4E0D\u5339\u914D)`));
5052
5181
  } else {
@@ -5054,7 +5183,7 @@ function displayVisualResults(results, threshold) {
5054
5183
  console.log(chalk8.red(` \u2717 ${name} (\u5DEE\u5F02: ${diffPct}%)`));
5055
5184
  }
5056
5185
  if (result.diffPath) {
5057
- console.log(chalk8.gray(` \u5DEE\u5F02\u56FE: ${path14.relative(process.cwd(), result.diffPath)}`));
5186
+ console.log(chalk8.gray(` \u5DEE\u5F02\u56FE: ${path15.relative(process.cwd(), result.diffPath)}`));
5058
5187
  }
5059
5188
  }
5060
5189
  console.log();
@@ -5100,8 +5229,8 @@ import chalk9 from "chalk";
5100
5229
  import inquirer4 from "inquirer";
5101
5230
  import ora8 from "ora";
5102
5231
  import { execFile as execFile4 } from "child_process";
5103
- import fs13 from "fs";
5104
- import path15 from "path";
5232
+ import fs14 from "fs";
5233
+ import path16 from "path";
5105
5234
  var DEPENDENCY_GROUPS = [
5106
5235
  {
5107
5236
  name: "Vitest (\u5355\u5143/\u7EC4\u4EF6/API\u6D4B\u8BD5)",
@@ -5135,7 +5264,7 @@ function registerSetupCommand(program2) {
5135
5264
  async function executeSetup(options) {
5136
5265
  console.log(chalk9.cyan("\n QAT \u4F9D\u8D56\u5B89\u88C5\u5668\n"));
5137
5266
  const projectInfo = detectProject();
5138
- if (!fs13.existsSync(path15.join(process.cwd(), "package.json"))) {
5267
+ if (!fs14.existsSync(path16.join(process.cwd(), "package.json"))) {
5139
5268
  throw new Error("\u672A\u627E\u5230 package.json\uFF0C\u8BF7\u5728\u9879\u76EE\u6839\u76EE\u5F55\u6267\u884C\u6B64\u547D\u4EE4");
5140
5269
  }
5141
5270
  if (projectInfo.frameworkConfidence > 0) {
@@ -5169,8 +5298,8 @@ async function executeSetup(options) {
5169
5298
  }
5170
5299
  ]);
5171
5300
  if (chooseDir !== "root") {
5172
- installDir = path15.join(process.cwd(), chooseDir);
5173
- if (!fs13.existsSync(path15.join(installDir, "package.json"))) {
5301
+ installDir = path16.join(process.cwd(), chooseDir);
5302
+ if (!fs14.existsSync(path16.join(installDir, "package.json"))) {
5174
5303
  throw new Error(`${chooseDir} \u4E0B\u6CA1\u6709 package.json`);
5175
5304
  }
5176
5305
  }
@@ -5209,7 +5338,7 @@ ${allPackages.map((p) => ` - ${p}`).join("\n")}`,
5209
5338
  const pm = getPackageManager(projectInfo.packageManager);
5210
5339
  const installCmd = pm === "npm" ? "npm install -D" : pm === "yarn" ? "yarn add -D" : pm === "pnpm" ? "pnpm add -D" : "bun add -D";
5211
5340
  for (const group of selectedGroups) {
5212
- const dirHint = installDir !== process.cwd() ? ` (\u5728 ${path15.relative(process.cwd(), installDir) || installDir})` : "";
5341
+ const dirHint = installDir !== process.cwd() ? ` (\u5728 ${path16.relative(process.cwd(), installDir) || installDir})` : "";
5213
5342
  console.log(chalk9.white(` ${installCmd} ${group.packages.join(" ")}${dirHint}`));
5214
5343
  if (group.postInstall) {
5215
5344
  for (const cmd of group.postInstall) {
@@ -5490,7 +5619,7 @@ async function executeChange(_options) {
5490
5619
  }
5491
5620
 
5492
5621
  // src/cli.ts
5493
- var VERSION = "0.2.6";
5622
+ var VERSION = "0.2.8";
5494
5623
  function printLogo() {
5495
5624
  const logo = `
5496
5625
  ${chalk12.bold.cyan(" ___ _ _ _ _ _____ _ _ ")}