qat-cli 0.3.1 → 0.3.2
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 +1 -1
- package/dist/cli.js +1257 -1244
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +228 -122
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +227 -121
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1715,12 +1715,23 @@ function generateHTMLReport(data) {
|
|
|
1715
1715
|
// src/runners/vitest-runner.ts
|
|
1716
1716
|
var import_node_child_process = require("child_process");
|
|
1717
1717
|
var import_node_path6 = __toESM(require("path"), 1);
|
|
1718
|
+
var import_node_fs6 = __toESM(require("fs"), 1);
|
|
1719
|
+
var import_node_os = __toESM(require("os"), 1);
|
|
1720
|
+
var isVerbose = () => process.env.QAT_VERBOSE === "true";
|
|
1721
|
+
function debug(label, ...args) {
|
|
1722
|
+
if (isVerbose()) {
|
|
1723
|
+
console.log(`\x1B[90m [debug:${label}]\x1B[0m`, ...args);
|
|
1724
|
+
}
|
|
1725
|
+
}
|
|
1718
1726
|
async function runVitest(options) {
|
|
1719
1727
|
const startTime = Date.now();
|
|
1720
1728
|
const args = buildVitestArgs(options);
|
|
1729
|
+
debug("vitest", "\u547D\u4EE4\u53C2\u6570:", args.join(" "));
|
|
1721
1730
|
try {
|
|
1722
1731
|
const result = await execVitest(args);
|
|
1723
1732
|
const endTime = Date.now();
|
|
1733
|
+
debug("vitest", `\u89E3\u6790\u7ED3\u679C: ${result.suites.length} \u4E2A\u5957\u4EF6, ${result.suites.reduce((s, su) => s + su.tests.length, 0)} \u4E2A\u7528\u4F8B`);
|
|
1734
|
+
debug("vitest", "\u89E3\u6790\u65B9\u5F0F:", result.parseMethod);
|
|
1724
1735
|
return {
|
|
1725
1736
|
type: options.type,
|
|
1726
1737
|
status: result.success ? "passed" : "failed",
|
|
@@ -1785,12 +1796,11 @@ function buildVitestArgs(options) {
|
|
|
1785
1796
|
return args;
|
|
1786
1797
|
}
|
|
1787
1798
|
async function execVitest(args) {
|
|
1788
|
-
const
|
|
1789
|
-
const fs9 = await import("fs");
|
|
1790
|
-
const tmpFile = import_node_path6.default.join(os.tmpdir(), `qat-vitest-result-${Date.now()}.json`);
|
|
1799
|
+
const tmpFile = import_node_path6.default.join(import_node_os.default.tmpdir(), `qat-vitest-result-${Date.now()}.json`);
|
|
1791
1800
|
const argsWithOutput = [...args, "--outputFile", tmpFile];
|
|
1792
1801
|
return new Promise((resolve, reject) => {
|
|
1793
1802
|
const npx = process.platform === "win32" ? "npx.cmd" : "npx";
|
|
1803
|
+
debug("vitest", "\u6267\u884C\u547D\u4EE4:", npx, argsWithOutput.join(" "));
|
|
1794
1804
|
const child = (0, import_node_child_process.execFile)(npx, argsWithOutput, {
|
|
1795
1805
|
cwd: process.cwd(),
|
|
1796
1806
|
env: { ...process.env, FORCE_COLOR: "0", NO_COLOR: "1" },
|
|
@@ -1798,85 +1808,113 @@ async function execVitest(args) {
|
|
|
1798
1808
|
shell: true
|
|
1799
1809
|
}, (error, stdout, stderr) => {
|
|
1800
1810
|
const rawOutput = stdout || stderr || "";
|
|
1811
|
+
const exitCode = error && "code" in error ? error.code : 0;
|
|
1812
|
+
debug("vitest", `\u9000\u51FA\u7801: ${exitCode}`);
|
|
1813
|
+
debug("vitest", `stdout \u957F\u5EA6: ${stdout?.length || 0}, stderr \u957F\u5EA6: ${stderr?.length || 0}`);
|
|
1801
1814
|
let jsonResult = null;
|
|
1802
1815
|
try {
|
|
1803
|
-
if (
|
|
1804
|
-
jsonResult =
|
|
1805
|
-
|
|
1816
|
+
if (import_node_fs6.default.existsSync(tmpFile)) {
|
|
1817
|
+
jsonResult = import_node_fs6.default.readFileSync(tmpFile, "utf-8");
|
|
1818
|
+
debug("vitest", `\u4ECE\u4E34\u65F6\u6587\u4EF6\u8BFB\u53D6\u5230 JSON (${jsonResult.length} \u5B57\u7B26)`);
|
|
1819
|
+
debug("vitest", "JSON \u524D 500 \u5B57\u7B26:", jsonResult.substring(0, 500));
|
|
1820
|
+
import_node_fs6.default.unlinkSync(tmpFile);
|
|
1821
|
+
} else {
|
|
1822
|
+
debug("vitest", "\u4E34\u65F6\u6587\u4EF6\u4E0D\u5B58\u5728:", tmpFile);
|
|
1806
1823
|
}
|
|
1807
|
-
} catch {
|
|
1824
|
+
} catch (e) {
|
|
1825
|
+
debug("vitest", "\u4E34\u65F6\u6587\u4EF6\u8BFB\u53D6\u5931\u8D25:", e instanceof Error ? e.message : String(e));
|
|
1808
1826
|
}
|
|
1809
1827
|
if (jsonResult) {
|
|
1810
1828
|
try {
|
|
1811
|
-
const parsed =
|
|
1812
|
-
|
|
1829
|
+
const parsed = parseVitestJSON(jsonResult);
|
|
1830
|
+
debug("vitest", "\u4ECE\u4E34\u65F6\u6587\u4EF6\u89E3\u6790\u6210\u529F:", parsed.suites.length, "\u4E2A\u5957\u4EF6");
|
|
1831
|
+
resolve({ ...parsed, rawOutput, parseMethod: "outputFile-JSON" });
|
|
1813
1832
|
return;
|
|
1814
|
-
} catch {
|
|
1833
|
+
} catch (e) {
|
|
1834
|
+
debug("vitest", "\u4E34\u65F6\u6587\u4EF6 JSON \u89E3\u6790\u5931\u8D25:", e instanceof Error ? e.message : String(e));
|
|
1815
1835
|
}
|
|
1816
1836
|
}
|
|
1837
|
+
debug("vitest", "\u5C1D\u8BD5\u4ECE stdout \u63D0\u53D6 JSON...");
|
|
1817
1838
|
try {
|
|
1818
|
-
const parsed =
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1839
|
+
const parsed = parseFromStdout(rawOutput);
|
|
1840
|
+
debug("vitest", "\u4ECE stdout \u89E3\u6790\u6210\u529F:", parsed.suites.length, "\u4E2A\u5957\u4EF6");
|
|
1841
|
+
resolve({ ...parsed, rawOutput, parseMethod: "stdout-JSON" });
|
|
1842
|
+
return;
|
|
1843
|
+
} catch (e) {
|
|
1844
|
+
debug("vitest", "stdout JSON \u89E3\u6790\u5931\u8D25:", e instanceof Error ? e.message : String(e));
|
|
1845
|
+
}
|
|
1846
|
+
debug("vitest", "\u5C1D\u8BD5\u4ECE\u6587\u672C\u8F93\u51FA\u89E3\u6790...");
|
|
1847
|
+
if (rawOutput) {
|
|
1848
|
+
const parsed = parseVitestTextOutput(rawOutput, !!error);
|
|
1849
|
+
debug("vitest", "\u6587\u672C\u89E3\u6790\u7ED3\u679C:", parsed.suites.length, "\u4E2A\u5957\u4EF6");
|
|
1850
|
+
resolve({ ...parsed, rawOutput, parseMethod: "text-fallback" });
|
|
1851
|
+
return;
|
|
1828
1852
|
}
|
|
1853
|
+
if (error && error.message.includes("ENOENT")) {
|
|
1854
|
+
reject(new Error("\u672A\u627E\u5230 vitest\uFF0C\u8BF7\u786E\u4FDD\u5DF2\u5B89\u88C5: npm install -D vitest"));
|
|
1855
|
+
return;
|
|
1856
|
+
}
|
|
1857
|
+
debug("vitest", "\u6240\u6709\u89E3\u6790\u65B9\u5F0F\u5747\u5931\u8D25\uFF0C\u8FD4\u56DE\u7A7A\u7ED3\u679C");
|
|
1858
|
+
resolve({ success: !error, suites: [], rawOutput, parseMethod: "none" });
|
|
1829
1859
|
});
|
|
1830
1860
|
child.on("error", (err) => {
|
|
1831
1861
|
try {
|
|
1832
|
-
|
|
1862
|
+
import_node_fs6.default.unlinkSync(tmpFile);
|
|
1833
1863
|
} catch {
|
|
1834
1864
|
}
|
|
1835
1865
|
reject(new Error(`Vitest \u6267\u884C\u5931\u8D25: ${err.message}`));
|
|
1836
1866
|
});
|
|
1837
1867
|
});
|
|
1838
1868
|
}
|
|
1839
|
-
function
|
|
1869
|
+
function parseVitestJSON(jsonStr) {
|
|
1840
1870
|
const data = JSON.parse(jsonStr);
|
|
1841
1871
|
const suites = [];
|
|
1872
|
+
debug("vitest-json", "JSON \u9876\u5C42\u5B57\u6BB5:", Object.keys(data).join(", "));
|
|
1842
1873
|
if (data.testResults && Array.isArray(data.testResults)) {
|
|
1874
|
+
debug("vitest-json", `testResults \u6570\u91CF: ${data.testResults.length}`);
|
|
1843
1875
|
for (const fileResult of data.testResults) {
|
|
1876
|
+
const suiteTests = parseTestResults(fileResult);
|
|
1877
|
+
suites.push({
|
|
1878
|
+
name: import_node_path6.default.basename(fileResult.name || "unknown"),
|
|
1879
|
+
file: fileResult.name || "unknown",
|
|
1880
|
+
type: "unit",
|
|
1881
|
+
status: mapVitestStatus(fileResult.status),
|
|
1882
|
+
duration: fileResult.duration || 0,
|
|
1883
|
+
tests: suiteTests
|
|
1884
|
+
});
|
|
1885
|
+
}
|
|
1886
|
+
}
|
|
1887
|
+
if (suites.length === 0 && data.numTotalTests !== void 0) {
|
|
1888
|
+
debug("vitest-json", `\u4F7F\u7528\u6C47\u603B\u683C\u5F0F: total=${data.numTotalTests}, passed=${data.numPassedTests}`);
|
|
1889
|
+
suites.push({
|
|
1890
|
+
name: "Vitest Results",
|
|
1891
|
+
file: "unknown",
|
|
1892
|
+
type: "unit",
|
|
1893
|
+
status: data.numFailedTests > 0 ? "failed" : "passed",
|
|
1894
|
+
duration: 0,
|
|
1895
|
+
tests: buildTestsFromSummary(data)
|
|
1896
|
+
});
|
|
1897
|
+
}
|
|
1898
|
+
if (suites.length === 0 && data.suites && Array.isArray(data.suites)) {
|
|
1899
|
+
debug("vitest-json", `suites \u6570\u91CF: ${data.suites.length}`);
|
|
1900
|
+
for (const suiteData of data.suites) {
|
|
1844
1901
|
const suiteTests = [];
|
|
1845
|
-
const
|
|
1846
|
-
for (const assertion of assertions) {
|
|
1902
|
+
for (const test of suiteData.tests || []) {
|
|
1847
1903
|
suiteTests.push({
|
|
1848
|
-
name:
|
|
1849
|
-
file:
|
|
1850
|
-
status: mapVitestStatus(
|
|
1851
|
-
duration:
|
|
1852
|
-
error:
|
|
1904
|
+
name: test.name || test.title || "unknown",
|
|
1905
|
+
file: test.file || suiteData.file || "unknown",
|
|
1906
|
+
status: mapVitestStatus(test.status || test.result?.status),
|
|
1907
|
+
duration: test.duration || test.result?.duration || 0,
|
|
1908
|
+
error: test.result?.errors?.[0] ? { message: test.result.errors[0].message || String(test.result.errors[0]) } : void 0,
|
|
1853
1909
|
retries: 0
|
|
1854
1910
|
});
|
|
1855
1911
|
}
|
|
1856
|
-
if (suiteTests.length === 0 && fileResult.numPassingTests !== void 0) {
|
|
1857
|
-
const counts = [
|
|
1858
|
-
{ n: fileResult.numPassingTests || 0, s: "passed" },
|
|
1859
|
-
{ n: fileResult.numFailingTests || 0, s: "failed" },
|
|
1860
|
-
{ n: fileResult.numPendingTests || 0, s: "skipped" }
|
|
1861
|
-
];
|
|
1862
|
-
for (const { n, s } of counts) {
|
|
1863
|
-
for (let i = 0; i < n; i++) {
|
|
1864
|
-
suiteTests.push({
|
|
1865
|
-
name: `${s} test ${i + 1}`,
|
|
1866
|
-
file: fileResult.name || "unknown",
|
|
1867
|
-
status: s,
|
|
1868
|
-
duration: 0,
|
|
1869
|
-
retries: 0
|
|
1870
|
-
});
|
|
1871
|
-
}
|
|
1872
|
-
}
|
|
1873
|
-
}
|
|
1874
1912
|
suites.push({
|
|
1875
|
-
name:
|
|
1876
|
-
file:
|
|
1913
|
+
name: suiteData.name || "unknown",
|
|
1914
|
+
file: suiteData.file || "unknown",
|
|
1877
1915
|
type: "unit",
|
|
1878
|
-
status:
|
|
1879
|
-
duration:
|
|
1916
|
+
status: suiteTests.some((t) => t.status === "failed") ? "failed" : "passed",
|
|
1917
|
+
duration: 0,
|
|
1880
1918
|
tests: suiteTests
|
|
1881
1919
|
});
|
|
1882
1920
|
}
|
|
@@ -1885,58 +1923,101 @@ function parseVitestJSONResult(jsonStr) {
|
|
|
1885
1923
|
if (data.coverageMap) {
|
|
1886
1924
|
coverage = extractCoverage(data.coverageMap);
|
|
1887
1925
|
}
|
|
1888
|
-
|
|
1926
|
+
if (!coverage && data.coverage && typeof data.coverage === "object") {
|
|
1927
|
+
const cov = data.coverage;
|
|
1928
|
+
const totals = cov.totals || cov;
|
|
1929
|
+
const getVal = (key) => {
|
|
1930
|
+
const v = totals[key];
|
|
1931
|
+
return typeof v === "number" ? v : typeof v === "object" && v !== null && "pct" in v ? v.pct / 100 : 0;
|
|
1932
|
+
};
|
|
1933
|
+
coverage = {
|
|
1934
|
+
lines: getVal("lines"),
|
|
1935
|
+
statements: getVal("statements"),
|
|
1936
|
+
functions: getVal("functions"),
|
|
1937
|
+
branches: getVal("branches")
|
|
1938
|
+
};
|
|
1939
|
+
}
|
|
1940
|
+
const success = data.success !== false ? data.numFailedTests !== void 0 ? data.numFailedTests === 0 : suites.every((s) => s.status !== "failed") : false;
|
|
1889
1941
|
return { success, suites, coverage };
|
|
1890
1942
|
}
|
|
1891
|
-
function
|
|
1892
|
-
const
|
|
1893
|
-
|
|
1894
|
-
|
|
1943
|
+
function parseTestResults(fileResult) {
|
|
1944
|
+
const tests = [];
|
|
1945
|
+
const assertions = fileResult.assertionResults || fileResult.tests || [];
|
|
1946
|
+
for (const assertion of assertions) {
|
|
1947
|
+
tests.push({
|
|
1948
|
+
name: assertion.title || assertion.fullName || assertion.name || "unknown",
|
|
1949
|
+
file: fileResult.name || "unknown",
|
|
1950
|
+
status: mapVitestStatus(assertion.status),
|
|
1951
|
+
duration: assertion.duration || 0,
|
|
1952
|
+
error: assertion.failureMessages?.length ? { message: assertion.failureMessages[0] } : assertion.failureMessage ? { message: assertion.failureMessage } : void 0,
|
|
1953
|
+
retries: 0
|
|
1954
|
+
});
|
|
1895
1955
|
}
|
|
1896
|
-
|
|
1956
|
+
if (tests.length === 0 && fileResult.numPassingTests !== void 0) {
|
|
1957
|
+
tests.push(...buildTestsFromSummary(fileResult));
|
|
1958
|
+
}
|
|
1959
|
+
return tests;
|
|
1960
|
+
}
|
|
1961
|
+
function buildTestsFromSummary(data) {
|
|
1962
|
+
const tests = [];
|
|
1963
|
+
const counts = [
|
|
1964
|
+
[data.numPassedTests || 0, "passed"],
|
|
1965
|
+
[data.numFailedTests || 0, "failed"],
|
|
1966
|
+
[data.numPendingTests || 0, "skipped"]
|
|
1967
|
+
];
|
|
1968
|
+
for (const [n, s] of counts) {
|
|
1969
|
+
for (let i = 0; i < n; i++) {
|
|
1970
|
+
tests.push({
|
|
1971
|
+
name: `${s} test ${i + 1}`,
|
|
1972
|
+
file: data.name || "unknown",
|
|
1973
|
+
status: s,
|
|
1974
|
+
duration: 0,
|
|
1975
|
+
retries: 0
|
|
1976
|
+
});
|
|
1977
|
+
}
|
|
1978
|
+
}
|
|
1979
|
+
return tests;
|
|
1980
|
+
}
|
|
1981
|
+
function parseFromStdout(output) {
|
|
1982
|
+
const jsonMatch = output.match(/\{[\s\S]*"testResults"[\s\S]*\}/);
|
|
1983
|
+
if (jsonMatch) {
|
|
1897
1984
|
const data = JSON.parse(jsonMatch[0]);
|
|
1898
1985
|
const suites = [];
|
|
1899
1986
|
if (data.testResults && Array.isArray(data.testResults)) {
|
|
1900
1987
|
for (const fileResult of data.testResults) {
|
|
1901
|
-
|
|
1902
|
-
name: import_node_path6.default.basename(fileResult.name ||
|
|
1988
|
+
suites.push({
|
|
1989
|
+
name: import_node_path6.default.basename(fileResult.name || "unknown"),
|
|
1903
1990
|
file: fileResult.name || "unknown",
|
|
1904
1991
|
type: "unit",
|
|
1905
1992
|
status: mapVitestStatus(fileResult.status),
|
|
1906
1993
|
duration: fileResult.duration || 0,
|
|
1907
|
-
tests: (fileResult
|
|
1908
|
-
|
|
1909
|
-
file: fileResult.name || "unknown",
|
|
1910
|
-
status: mapVitestStatus(assertion.status),
|
|
1911
|
-
duration: assertion.duration || 0,
|
|
1912
|
-
error: assertion.failureMessages?.length ? { message: assertion.failureMessages[0] } : void 0,
|
|
1913
|
-
retries: 0
|
|
1914
|
-
}))
|
|
1915
|
-
};
|
|
1916
|
-
suites.push(suite);
|
|
1994
|
+
tests: parseTestResults(fileResult)
|
|
1995
|
+
});
|
|
1917
1996
|
}
|
|
1918
1997
|
}
|
|
1919
|
-
let coverage;
|
|
1920
|
-
if (data.coverageMap) {
|
|
1921
|
-
coverage = extractCoverage(data.coverageMap);
|
|
1922
|
-
}
|
|
1923
1998
|
const success = data.success !== false && suites.every((s) => s.status !== "failed");
|
|
1999
|
+
let coverage;
|
|
2000
|
+
if (data.coverageMap) coverage = extractCoverage(data.coverageMap);
|
|
1924
2001
|
return { success, suites, coverage };
|
|
1925
|
-
} catch {
|
|
1926
|
-
return parseVitestTextOutput(output, false);
|
|
1927
2002
|
}
|
|
2003
|
+
const anyJsonMatch = output.match(/\{[\s\S]*"numTotalTests"[\s\S]*\}/);
|
|
2004
|
+
if (anyJsonMatch) {
|
|
2005
|
+
return parseVitestJSON(anyJsonMatch[0]);
|
|
2006
|
+
}
|
|
2007
|
+
throw new Error("stdout \u4E2D\u672A\u627E\u5230\u6709\u6548 JSON");
|
|
1928
2008
|
}
|
|
1929
2009
|
function parseVitestTextOutput(output, hasError) {
|
|
1930
2010
|
const suites = [];
|
|
2011
|
+
debug("vitest-text", "\u6587\u672C\u8F93\u51FA\u524D 1000 \u5B57\u7B26:", output.substring(0, 1e3));
|
|
2012
|
+
const suiteRegex = /[✓✗×✕]\s+(.+\.test\.(ts|js)|.+\.spec\.(ts|js))\s*\((\d+)[^)]*\)/i;
|
|
2013
|
+
const lines = output.split("\n");
|
|
1931
2014
|
let totalPassed = 0;
|
|
1932
2015
|
let totalFailed = 0;
|
|
1933
|
-
const suiteRegex = /[✓✗×]\s+(.+\.test\.ts|.+\.spec\.ts)\s*\((\d+)\s+test/i;
|
|
1934
|
-
const lines = output.split("\n");
|
|
1935
2016
|
for (const line of lines) {
|
|
1936
2017
|
const match = line.match(suiteRegex);
|
|
1937
2018
|
if (match) {
|
|
1938
2019
|
const file = match[1];
|
|
1939
|
-
const testCount = parseInt(match[
|
|
2020
|
+
const testCount = parseInt(match[4], 10);
|
|
1940
2021
|
const isPassed = line.includes("\u2713");
|
|
1941
2022
|
if (isPassed) totalPassed += testCount;
|
|
1942
2023
|
else totalFailed += testCount;
|
|
@@ -1956,15 +2037,39 @@ function parseVitestTextOutput(output, hasError) {
|
|
|
1956
2037
|
});
|
|
1957
2038
|
}
|
|
1958
2039
|
}
|
|
2040
|
+
if (suites.length === 0) {
|
|
2041
|
+
const summaryMatch = output.match(/Tests\s+(\d+)\s+(passed|failed)/i);
|
|
2042
|
+
if (summaryMatch) {
|
|
2043
|
+
const count = parseInt(summaryMatch[1], 10);
|
|
2044
|
+
const status = summaryMatch[2].toLowerCase() === "passed" ? "passed" : "failed";
|
|
2045
|
+
suites.push({
|
|
2046
|
+
name: "Vitest Summary",
|
|
2047
|
+
file: "unknown",
|
|
2048
|
+
type: "unit",
|
|
2049
|
+
status,
|
|
2050
|
+
duration: 0,
|
|
2051
|
+
tests: Array.from({ length: count }, (_, i) => ({
|
|
2052
|
+
name: `test ${i + 1}`,
|
|
2053
|
+
file: "unknown",
|
|
2054
|
+
status,
|
|
2055
|
+
duration: 0,
|
|
2056
|
+
retries: 0
|
|
2057
|
+
}))
|
|
2058
|
+
});
|
|
2059
|
+
}
|
|
2060
|
+
}
|
|
2061
|
+
debug("vitest-text", `\u89E3\u6790\u5230 ${suites.length} \u4E2A\u5957\u4EF6, ${totalPassed} \u901A\u8FC7, ${totalFailed} \u5931\u8D25`);
|
|
1959
2062
|
return {
|
|
1960
2063
|
success: !hasError || totalFailed === 0,
|
|
1961
2064
|
suites
|
|
1962
2065
|
};
|
|
1963
2066
|
}
|
|
1964
2067
|
function mapVitestStatus(status) {
|
|
2068
|
+
if (!status) return "pending";
|
|
1965
2069
|
switch (status) {
|
|
1966
2070
|
case "passed":
|
|
1967
2071
|
case "pass":
|
|
2072
|
+
case "done":
|
|
1968
2073
|
return "passed";
|
|
1969
2074
|
case "failed":
|
|
1970
2075
|
case "fail":
|
|
@@ -1972,6 +2077,7 @@ function mapVitestStatus(status) {
|
|
|
1972
2077
|
case "skipped":
|
|
1973
2078
|
case "skip":
|
|
1974
2079
|
case "pending":
|
|
2080
|
+
case "todo":
|
|
1975
2081
|
return "skipped";
|
|
1976
2082
|
default:
|
|
1977
2083
|
return "pending";
|
|
@@ -2908,7 +3014,7 @@ async function testAIConnection(config) {
|
|
|
2908
3014
|
}
|
|
2909
3015
|
|
|
2910
3016
|
// src/services/mock-server.ts
|
|
2911
|
-
var
|
|
3017
|
+
var import_node_fs7 = __toESM(require("fs"), 1);
|
|
2912
3018
|
var import_node_path8 = __toESM(require("path"), 1);
|
|
2913
3019
|
var serverState = {
|
|
2914
3020
|
running: false,
|
|
@@ -2921,18 +3027,18 @@ function getMockServerState() {
|
|
|
2921
3027
|
}
|
|
2922
3028
|
async function loadMockRoutes(routesDir) {
|
|
2923
3029
|
const absDir = import_node_path8.default.resolve(process.cwd(), routesDir);
|
|
2924
|
-
if (!
|
|
3030
|
+
if (!import_node_fs7.default.existsSync(absDir)) {
|
|
2925
3031
|
return [];
|
|
2926
3032
|
}
|
|
2927
3033
|
const routes = [];
|
|
2928
|
-
const entries =
|
|
3034
|
+
const entries = import_node_fs7.default.readdirSync(absDir, { withFileTypes: true });
|
|
2929
3035
|
for (const entry of entries) {
|
|
2930
3036
|
if (!entry.isFile()) continue;
|
|
2931
3037
|
const filePath = import_node_path8.default.join(absDir, entry.name);
|
|
2932
3038
|
const ext = import_node_path8.default.extname(entry.name);
|
|
2933
3039
|
try {
|
|
2934
3040
|
if (ext === ".json") {
|
|
2935
|
-
const content =
|
|
3041
|
+
const content = import_node_fs7.default.readFileSync(filePath, "utf-8");
|
|
2936
3042
|
const parsed = JSON.parse(content);
|
|
2937
3043
|
if (Array.isArray(parsed)) {
|
|
2938
3044
|
routes.push(...parsed);
|
|
@@ -3124,11 +3230,11 @@ function generateMockRouteTemplate(name) {
|
|
|
3124
3230
|
}
|
|
3125
3231
|
function initMockRoutesDir(routesDir) {
|
|
3126
3232
|
const absDir = import_node_path8.default.resolve(process.cwd(), routesDir);
|
|
3127
|
-
if (!
|
|
3128
|
-
|
|
3233
|
+
if (!import_node_fs7.default.existsSync(absDir)) {
|
|
3234
|
+
import_node_fs7.default.mkdirSync(absDir, { recursive: true });
|
|
3129
3235
|
}
|
|
3130
3236
|
const examplePath = import_node_path8.default.join(absDir, "example.json");
|
|
3131
|
-
if (!
|
|
3237
|
+
if (!import_node_fs7.default.existsSync(examplePath)) {
|
|
3132
3238
|
const exampleRoutes = [
|
|
3133
3239
|
{
|
|
3134
3240
|
method: "GET",
|
|
@@ -3152,24 +3258,24 @@ function initMockRoutesDir(routesDir) {
|
|
|
3152
3258
|
}
|
|
3153
3259
|
}
|
|
3154
3260
|
];
|
|
3155
|
-
|
|
3261
|
+
import_node_fs7.default.writeFileSync(examplePath, JSON.stringify(exampleRoutes, null, 2), "utf-8");
|
|
3156
3262
|
}
|
|
3157
3263
|
}
|
|
3158
3264
|
|
|
3159
3265
|
// src/services/visual.ts
|
|
3160
|
-
var
|
|
3266
|
+
var import_node_fs8 = __toESM(require("fs"), 1);
|
|
3161
3267
|
var import_node_path9 = __toESM(require("path"), 1);
|
|
3162
3268
|
var import_pixelmatch = __toESM(require("pixelmatch"), 1);
|
|
3163
3269
|
var import_pngjs = require("pngjs");
|
|
3164
3270
|
function compareImages(baselinePath, currentPath, diffOutputPath, threshold = 0.1) {
|
|
3165
|
-
if (!
|
|
3271
|
+
if (!import_node_fs8.default.existsSync(baselinePath)) {
|
|
3166
3272
|
throw new Error(`\u57FA\u7EBF\u56FE\u7247\u4E0D\u5B58\u5728: ${baselinePath}`);
|
|
3167
3273
|
}
|
|
3168
|
-
if (!
|
|
3274
|
+
if (!import_node_fs8.default.existsSync(currentPath)) {
|
|
3169
3275
|
throw new Error(`\u5F53\u524D\u56FE\u7247\u4E0D\u5B58\u5728: ${currentPath}`);
|
|
3170
3276
|
}
|
|
3171
|
-
const baseline = import_pngjs.PNG.sync.read(
|
|
3172
|
-
const current = import_pngjs.PNG.sync.read(
|
|
3277
|
+
const baseline = import_pngjs.PNG.sync.read(import_node_fs8.default.readFileSync(baselinePath));
|
|
3278
|
+
const current = import_pngjs.PNG.sync.read(import_node_fs8.default.readFileSync(currentPath));
|
|
3173
3279
|
if (baseline.width !== current.width || baseline.height !== current.height) {
|
|
3174
3280
|
return {
|
|
3175
3281
|
passed: false,
|
|
@@ -3198,10 +3304,10 @@ function compareImages(baselinePath, currentPath, diffOutputPath, threshold = 0.
|
|
|
3198
3304
|
let diffPath;
|
|
3199
3305
|
if (diffPixels > 0) {
|
|
3200
3306
|
const diffDir = import_node_path9.default.dirname(diffOutputPath);
|
|
3201
|
-
if (!
|
|
3202
|
-
|
|
3307
|
+
if (!import_node_fs8.default.existsSync(diffDir)) {
|
|
3308
|
+
import_node_fs8.default.mkdirSync(diffDir, { recursive: true });
|
|
3203
3309
|
}
|
|
3204
|
-
|
|
3310
|
+
import_node_fs8.default.writeFileSync(diffOutputPath, import_pngjs.PNG.sync.write(diff));
|
|
3205
3311
|
diffPath = diffOutputPath;
|
|
3206
3312
|
}
|
|
3207
3313
|
return {
|
|
@@ -3215,14 +3321,14 @@ function compareImages(baselinePath, currentPath, diffOutputPath, threshold = 0.
|
|
|
3215
3321
|
};
|
|
3216
3322
|
}
|
|
3217
3323
|
function createBaseline(currentPath, baselinePath) {
|
|
3218
|
-
if (!
|
|
3324
|
+
if (!import_node_fs8.default.existsSync(currentPath)) {
|
|
3219
3325
|
throw new Error(`\u5F53\u524D\u622A\u56FE\u4E0D\u5B58\u5728: ${currentPath}`);
|
|
3220
3326
|
}
|
|
3221
3327
|
const baselineDir = import_node_path9.default.dirname(baselinePath);
|
|
3222
|
-
if (!
|
|
3223
|
-
|
|
3328
|
+
if (!import_node_fs8.default.existsSync(baselineDir)) {
|
|
3329
|
+
import_node_fs8.default.mkdirSync(baselineDir, { recursive: true });
|
|
3224
3330
|
}
|
|
3225
|
-
|
|
3331
|
+
import_node_fs8.default.copyFileSync(currentPath, baselinePath);
|
|
3226
3332
|
return baselinePath;
|
|
3227
3333
|
}
|
|
3228
3334
|
function updateBaseline(currentPath, baselinePath) {
|
|
@@ -3230,69 +3336,69 @@ function updateBaseline(currentPath, baselinePath) {
|
|
|
3230
3336
|
}
|
|
3231
3337
|
function updateAllBaselines(currentDir, baselineDir) {
|
|
3232
3338
|
const updated = [];
|
|
3233
|
-
if (!
|
|
3339
|
+
if (!import_node_fs8.default.existsSync(currentDir)) {
|
|
3234
3340
|
return updated;
|
|
3235
3341
|
}
|
|
3236
|
-
const files =
|
|
3342
|
+
const files = import_node_fs8.default.readdirSync(currentDir).filter((f) => f.endsWith(".png"));
|
|
3237
3343
|
for (const file of files) {
|
|
3238
3344
|
const currentPath = import_node_path9.default.join(currentDir, file);
|
|
3239
3345
|
const baselinePath = import_node_path9.default.join(baselineDir, file);
|
|
3240
3346
|
const baselineDirAbs = import_node_path9.default.dirname(baselinePath);
|
|
3241
|
-
if (!
|
|
3242
|
-
|
|
3347
|
+
if (!import_node_fs8.default.existsSync(baselineDirAbs)) {
|
|
3348
|
+
import_node_fs8.default.mkdirSync(baselineDirAbs, { recursive: true });
|
|
3243
3349
|
}
|
|
3244
|
-
|
|
3350
|
+
import_node_fs8.default.copyFileSync(currentPath, baselinePath);
|
|
3245
3351
|
updated.push(file);
|
|
3246
3352
|
}
|
|
3247
3353
|
return updated;
|
|
3248
3354
|
}
|
|
3249
3355
|
function cleanBaselines(baselineDir) {
|
|
3250
|
-
if (!
|
|
3356
|
+
if (!import_node_fs8.default.existsSync(baselineDir)) {
|
|
3251
3357
|
return 0;
|
|
3252
3358
|
}
|
|
3253
|
-
const files =
|
|
3359
|
+
const files = import_node_fs8.default.readdirSync(baselineDir).filter((f) => f.endsWith(".png"));
|
|
3254
3360
|
let count = 0;
|
|
3255
3361
|
for (const file of files) {
|
|
3256
|
-
|
|
3362
|
+
import_node_fs8.default.unlinkSync(import_node_path9.default.join(baselineDir, file));
|
|
3257
3363
|
count++;
|
|
3258
3364
|
}
|
|
3259
3365
|
return count;
|
|
3260
3366
|
}
|
|
3261
3367
|
function cleanDiffs(diffDir) {
|
|
3262
|
-
if (!
|
|
3368
|
+
if (!import_node_fs8.default.existsSync(diffDir)) {
|
|
3263
3369
|
return 0;
|
|
3264
3370
|
}
|
|
3265
|
-
const files =
|
|
3371
|
+
const files = import_node_fs8.default.readdirSync(diffDir).filter((f) => f.endsWith(".png"));
|
|
3266
3372
|
let count = 0;
|
|
3267
3373
|
for (const file of files) {
|
|
3268
|
-
|
|
3374
|
+
import_node_fs8.default.unlinkSync(import_node_path9.default.join(diffDir, file));
|
|
3269
3375
|
count++;
|
|
3270
3376
|
}
|
|
3271
3377
|
return count;
|
|
3272
3378
|
}
|
|
3273
3379
|
function listBaselines(baselineDir) {
|
|
3274
|
-
if (!
|
|
3380
|
+
if (!import_node_fs8.default.existsSync(baselineDir)) {
|
|
3275
3381
|
return [];
|
|
3276
3382
|
}
|
|
3277
|
-
return
|
|
3383
|
+
return import_node_fs8.default.readdirSync(baselineDir).filter((f) => f.endsWith(".png")).sort();
|
|
3278
3384
|
}
|
|
3279
3385
|
function listDiffs(diffDir) {
|
|
3280
|
-
if (!
|
|
3386
|
+
if (!import_node_fs8.default.existsSync(diffDir)) {
|
|
3281
3387
|
return [];
|
|
3282
3388
|
}
|
|
3283
|
-
return
|
|
3389
|
+
return import_node_fs8.default.readdirSync(diffDir).filter((f) => f.endsWith(".png")).sort();
|
|
3284
3390
|
}
|
|
3285
3391
|
function compareDirectories(baselineDir, currentDir, diffDir, threshold = 0.1) {
|
|
3286
3392
|
const results = [];
|
|
3287
|
-
if (!
|
|
3393
|
+
if (!import_node_fs8.default.existsSync(currentDir)) {
|
|
3288
3394
|
return results;
|
|
3289
3395
|
}
|
|
3290
|
-
const currentFiles =
|
|
3396
|
+
const currentFiles = import_node_fs8.default.readdirSync(currentDir).filter((f) => f.endsWith(".png"));
|
|
3291
3397
|
for (const file of currentFiles) {
|
|
3292
3398
|
const currentPath = import_node_path9.default.join(currentDir, file);
|
|
3293
3399
|
const baselinePath = import_node_path9.default.join(baselineDir, file);
|
|
3294
3400
|
const diffPath = import_node_path9.default.join(diffDir, file);
|
|
3295
|
-
if (!
|
|
3401
|
+
if (!import_node_fs8.default.existsSync(baselinePath)) {
|
|
3296
3402
|
createBaseline(currentPath, baselinePath);
|
|
3297
3403
|
results.push({
|
|
3298
3404
|
passed: true,
|
|
@@ -3324,14 +3430,14 @@ function compareDirectories(baselineDir, currentDir, diffDir, threshold = 0.1) {
|
|
|
3324
3430
|
}
|
|
3325
3431
|
|
|
3326
3432
|
// src/services/source-analyzer.ts
|
|
3327
|
-
var
|
|
3433
|
+
var import_node_fs9 = __toESM(require("fs"), 1);
|
|
3328
3434
|
var import_node_path10 = __toESM(require("path"), 1);
|
|
3329
3435
|
function analyzeFile(filePath) {
|
|
3330
3436
|
const absolutePath = import_node_path10.default.resolve(process.cwd(), filePath);
|
|
3331
|
-
if (!
|
|
3437
|
+
if (!import_node_fs9.default.existsSync(absolutePath)) {
|
|
3332
3438
|
return { filePath, exports: [], apiCalls: [] };
|
|
3333
3439
|
}
|
|
3334
|
-
const content =
|
|
3440
|
+
const content = import_node_fs9.default.readFileSync(absolutePath, "utf-8");
|
|
3335
3441
|
const ext = import_node_path10.default.extname(filePath);
|
|
3336
3442
|
const result = {
|
|
3337
3443
|
filePath,
|
|
@@ -3686,13 +3792,13 @@ function cleanTemplateUrl(url) {
|
|
|
3686
3792
|
}
|
|
3687
3793
|
function scanAPICalls(srcDir) {
|
|
3688
3794
|
const absDir = import_node_path10.default.resolve(process.cwd(), srcDir);
|
|
3689
|
-
if (!
|
|
3795
|
+
if (!import_node_fs9.default.existsSync(absDir)) {
|
|
3690
3796
|
return [];
|
|
3691
3797
|
}
|
|
3692
3798
|
const allCalls = [];
|
|
3693
3799
|
const seen = /* @__PURE__ */ new Set();
|
|
3694
3800
|
function walk(dir) {
|
|
3695
|
-
const entries =
|
|
3801
|
+
const entries = import_node_fs9.default.readdirSync(dir, { withFileTypes: true });
|
|
3696
3802
|
for (const entry of entries) {
|
|
3697
3803
|
if (entry.name.startsWith(".") || entry.name === "node_modules" || entry.name === "dist") continue;
|
|
3698
3804
|
const fullPath = import_node_path10.default.join(dir, entry.name);
|
|
@@ -3700,7 +3806,7 @@ function scanAPICalls(srcDir) {
|
|
|
3700
3806
|
walk(fullPath);
|
|
3701
3807
|
} else if (entry.isFile() && /\.(ts|js|vue|mjs)$/.test(entry.name)) {
|
|
3702
3808
|
try {
|
|
3703
|
-
const content =
|
|
3809
|
+
const content = import_node_fs9.default.readFileSync(fullPath, "utf-8");
|
|
3704
3810
|
const calls = extractAPICalls(content, import_node_path10.default.relative(process.cwd(), fullPath));
|
|
3705
3811
|
for (const call of calls) {
|
|
3706
3812
|
const key = `${call.method}:${call.url}`;
|