


















@@ -450,6 +450,14 @@ describe("qa cli runtime", () => {
450450it("keeps telegram exit code clear when --allow-failures is set", async () => {
451451const priorExitCode = process.exitCode;
452452process.exitCode = undefined;
453+await fs.writeFile(
454+telegramSummaryPath,
455+JSON.stringify({
456+counts: { total: 1, passed: 0, failed: 1 },
457+scenarios: [{ status: "fail" }],
458+}),
459+"utf8",
460+);
453461runTelegramQaLive.mockResolvedValueOnce({
454462outputDir: telegramArtifactsDir,
455463reportPath: path.join(telegramArtifactsDir, "report.md"),
@@ -534,6 +542,39 @@ describe("qa cli runtime", () => {
534542}
535543});
536544545+it("sets a failing exit code when host suite scenarios are skipped", async () => {
546+const priorExitCode = process.exitCode;
547+process.exitCode = undefined;
548+await fs.writeFile(
549+suiteSummaryPath,
550+JSON.stringify({
551+counts: {
552+total: 1,
553+passed: 0,
554+failed: 0,
555+skipped: 1,
556+},
557+scenarios: [{ name: "channel chat baseline", status: "skip" }],
558+}),
559+"utf8",
560+);
561+runQaSuiteFromRuntime.mockResolvedValueOnce({
562+watchUrl: "http://127.0.0.1:43124",
563+reportPath: suiteReportPath,
564+summaryPath: suiteSummaryPath,
565+scenarios: [],
566+});
567+568+try {
569+await runQaSuiteCommand({
570+repoRoot: "/tmp/openclaw-repo",
571+});
572+expect(process.exitCode).toBe(1);
573+} finally {
574+process.exitCode = priorExitCode;
575+}
576+});
577+537578it("keeps host suite exit code clear when --allow-failures is set", async () => {
538579const priorExitCode = process.exitCode;
539580process.exitCode = undefined;
@@ -720,7 +761,7 @@ describe("qa cli runtime", () => {
720761repoRoot: "/tmp/openclaw-repo",
721762preflight: true,
722763}),
723-).rejects.toThrow("QA parity preflight failed with 1 failing scenario.");
764+).rejects.toThrow("QA parity preflight failed with 1 failing or skipped scenario.");
724765});
725766726767it("keeps parity preflight exit code clear when --allow-failures is set", async () => {
@@ -1503,6 +1544,46 @@ describe("qa cli runtime", () => {
15031544}
15041545});
150515461547+it("sets a failing exit code when multipass summary reports skipped scenarios", async () => {
1548+const repoRoot = await fs.mkdtemp(path.join(os.tmpdir(), "qa-multipass-summary-"));
1549+const summaryPath = path.join(repoRoot, "qa-suite-summary.json");
1550+await fs.writeFile(
1551+summaryPath,
1552+JSON.stringify({
1553+counts: {
1554+total: 2,
1555+passed: 1,
1556+failed: 0,
1557+skipped: 1,
1558+},
1559+}),
1560+"utf8",
1561+);
1562+runQaMultipass.mockResolvedValueOnce({
1563+outputDir: repoRoot,
1564+reportPath: path.join(repoRoot, "qa-suite-report.md"),
1565+ summaryPath,
1566+hostLogPath: path.join(repoRoot, "multipass-host.log"),
1567+bootstrapLogPath: path.join(repoRoot, "multipass-guest-bootstrap.log"),
1568+guestScriptPath: path.join(repoRoot, "multipass-guest-run.sh"),
1569+vmName: "openclaw-qa-test",
1570+scenarioIds: ["channel-chat-baseline"],
1571+});
1572+const priorExitCode = process.exitCode;
1573+process.exitCode = undefined;
1574+1575+try {
1576+await runQaSuiteCommand({
1577+repoRoot: "/tmp/openclaw-repo",
1578+runner: "multipass",
1579+});
1580+expect(process.exitCode).toBe(1);
1581+} finally {
1582+process.exitCode = priorExitCode;
1583+await fs.rm(repoRoot, { recursive: true, force: true });
1584+}
1585+});
1586+15061587it("rejects malformed multipass summary JSON", async () => {
15071588const repoRoot = await fs.mkdtemp(path.join(os.tmpdir(), "qa-multipass-summary-"));
15081589const summaryPath = path.join(repoRoot, "qa-suite-summary.json");
@@ -1577,7 +1658,7 @@ describe("qa cli runtime", () => {
15771658repoRoot: "/tmp/openclaw-repo",
15781659runner: "multipass",
15791660}),
1580-).rejects.toThrow("did not include counts.failed or scenarios[].status");
1661+).rejects.toThrow("did not include counts.failed, counts.skipped, or scenarios[].status");
15811662} finally {
15821663await fs.rm(repoRoot, { recursive: true, force: true });
15831664}
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。