






















@@ -133,6 +133,77 @@ describe("runQaDockerUp", () => {
133133}
134134});
135135136+it("falls back to Corepack for the QA UI build when pnpm is unavailable", async () => {
137+const calls: string[] = [];
138+const outputDir = await mkdtemp(path.join(os.tmpdir(), "qa-docker-up-"));
139+const repoRoot = path.resolve("/repo/openclaw");
140+const composeFile = path.join(outputDir, "docker-compose.qa.yml");
141+142+try {
143+await runQaDockerUp(
144+{
145+ repoRoot,
146+ outputDir,
147+usePrebuiltImage: true,
148+},
149+{
150+async runCommand(command, args, cwd) {
151+calls.push([command, ...args, `@${cwd}`].join(" "));
152+if (command === "pnpm") {
153+throw Object.assign(new Error("spawn pnpm ENOENT"), { code: "ENOENT" });
154+}
155+if (args.join(" ").includes("ps --format json openclaw-qa-gateway")) {
156+return { stdout: '{"Health":"healthy","State":"running"}\n', stderr: "" };
157+}
158+return { stdout: "", stderr: "" };
159+},
160+fetchImpl: vi.fn(async () => ({ ok: true })),
161+sleepImpl: vi.fn(async () => {}),
162+},
163+);
164+165+expect(calls).toEqual([
166+`pnpm qa:lab:build @${repoRoot}`,
167+`corepack pnpm qa:lab:build @${repoRoot}`,
168+`docker compose -f ${composeFile} down --remove-orphans @${repoRoot}`,
169+`docker compose -f ${composeFile} up -d @${repoRoot}`,
170+`docker compose -f ${composeFile} ps --format json openclaw-qa-gateway @${repoRoot}`,
171+]);
172+} finally {
173+await rm(outputDir, { recursive: true, force: true });
174+}
175+});
176+177+it("does not hide real QA UI build failures behind the Corepack fallback", async () => {
178+const calls: string[] = [];
179+const outputDir = await mkdtemp(path.join(os.tmpdir(), "qa-docker-up-"));
180+const repoRoot = path.resolve("/repo/openclaw");
181+182+try {
183+await expect(
184+runQaDockerUp(
185+{
186+ repoRoot,
187+ outputDir,
188+usePrebuiltImage: true,
189+},
190+{
191+async runCommand(command, args, cwd) {
192+calls.push([command, ...args, `@${cwd}`].join(" "));
193+throw Object.assign(new Error("qa lab build failed"), { code: 1 });
194+},
195+fetchImpl: vi.fn(async () => ({ ok: true })),
196+sleepImpl: vi.fn(async () => {}),
197+},
198+),
199+).rejects.toThrow("qa lab build failed");
200+201+expect(calls).toEqual([`pnpm qa:lab:build @${repoRoot}`]);
202+} finally {
203+await rm(outputDir, { recursive: true, force: true });
204+}
205+});
206+136207it("uses a repo-root-relative default output dir when none is provided", async () => {
137208const calls: string[] = [];
138209const repoRoot = await mkdtemp(path.join(os.tmpdir(), "qa-docker-root-"));
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。