
























@@ -17,6 +17,26 @@ const createOutput = () => {
1717};
1818};
191920+function requireRecord(value: unknown, label: string): Record<string, unknown> {
21+expect(value, label).toBeTypeOf("object");
22+expect(value, label).not.toBeNull();
23+return value as Record<string, unknown>;
24+}
25+26+function spawnCall(mock: unknown, callIndex: number) {
27+const calls = (mock as { mock?: { calls?: Array<Array<unknown>> } }).mock?.calls ?? [];
28+const call = calls.at(callIndex);
29+expect(call, `spawn call ${callIndex + 1}`).toBeDefined();
30+return call as Array<unknown>;
31+}
32+33+function expectSpawn(mock: unknown, callIndex: number, command: string, args: Array<unknown>) {
34+const call = spawnCall(mock, callIndex);
35+expect(call[0]).toBe(command);
36+expect(call[1]).toEqual(args);
37+return requireRecord(call[2], "spawn options");
38+}
39+2040describe("gateway-watch tmux wrapper", () => {
2141it("derives stable session names from profile and port", () => {
2242expect(resolveGatewayWatchTmuxSessionName({ args: ["gateway", "--force"], env: {} })).toBe(
@@ -198,51 +218,42 @@ describe("gateway-watch tmux wrapper", () => {
198218});
199219200220expect(code).toBe(0);
201-expect(spawnSync).toHaveBeenNthCalledWith(
202-1,
203-"tmux",
204-["has-session", "-t", "openclaw-gateway-watch-main"],
205-expect.objectContaining({ encoding: "utf8" }),
206-);
207-expect(spawnSync).toHaveBeenNthCalledWith(
208-2,
209-"tmux",
210-[
211-"new-session",
212-"-d",
213-"-s",
214-"openclaw-gateway-watch-main",
215-"-c",
216-"/repo",
217-expect.stringContaining("scripts/watch-node.mjs"),
218-],
219-expect.objectContaining({ encoding: "utf8" }),
220-);
221-expect(spawnSync).toHaveBeenNthCalledWith(
222-3,
223-"tmux",
224-[
221+expect(
222+expectSpawn(spawnSync, 0, "tmux", ["has-session", "-t", "openclaw-gateway-watch-main"])
223+.encoding,
224+).toBe("utf8");
225+const newSessionCall = spawnCall(spawnSync, 1);
226+expect(newSessionCall[0]).toBe("tmux");
227+const newSessionArgs = newSessionCall[1] as Array<unknown>;
228+expect(newSessionArgs.slice(0, 6)).toEqual([
229+"new-session",
230+"-d",
231+"-s",
232+"openclaw-gateway-watch-main",
233+"-c",
234+"/repo",
235+]);
236+expect(String(newSessionArgs[6])).toContain("scripts/watch-node.mjs");
237+expect(requireRecord(newSessionCall[2], "spawn options").encoding).toBe("utf8");
238+expect(
239+expectSpawn(spawnSync, 2, "tmux", [
225240"set-option",
226241"-q",
227242"-t",
228243"openclaw-gateway-watch-main",
229244"@openclaw.gateway_watch.cwd",
230245"/repo",
231-],
232-expect.objectContaining({ encoding: "utf8" }),
233-);
234-expect(spawnSync).toHaveBeenNthCalledWith(
235-4,
236-"tmux",
237-[
246+]).encoding,
247+).toBe("utf8");
248+expect(
249+expectSpawn(spawnSync, 3, "tmux", [
238250"set-environment",
239251"-t",
240252"openclaw-gateway-watch-main",
241253"OPENCLAW_GATEWAY_WATCH_CWD",
242254"/repo",
243-],
244-expect.objectContaining({ encoding: "utf8" }),
245-);
255+]).encoding,
256+).toBe("utf8");
246257expect(stderr.chunks.join("")).toContain(
247258"gateway:watch started in tmux session openclaw-gateway-watch-main",
248259);
@@ -276,12 +287,10 @@ describe("gateway-watch tmux wrapper", () => {
276287});
277288278289expect(code).toBe(0);
279-expect(spawnSync).toHaveBeenNthCalledWith(
280-5,
281-"tmux",
282-["attach-session", "-t", "openclaw-gateway-watch-main"],
283-expect.objectContaining({ stdio: "inherit" }),
284-);
290+expect(
291+expectSpawn(spawnSync, 4, "tmux", ["attach-session", "-t", "openclaw-gateway-watch-main"])
292+.stdio,
293+).toBe("inherit");
285294expect(stdout.chunks.join("")).not.toContain("tmux attach -t");
286295});
287296@@ -309,12 +318,10 @@ describe("gateway-watch tmux wrapper", () => {
309318});
310319311320expect(code).toBe(0);
312-expect(spawnSync).toHaveBeenNthCalledWith(
313-5,
314-"tmux",
315-["switch-client", "-t", "openclaw-gateway-watch-main"],
316-expect.objectContaining({ stdio: "inherit" }),
317-);
321+expect(
322+expectSpawn(spawnSync, 4, "tmux", ["switch-client", "-t", "openclaw-gateway-watch-main"])
323+.stdio,
324+).toBe("inherit");
318325});
319326320327it("keeps detached output in CI unless attach is forced", () => {
@@ -365,20 +372,19 @@ describe("gateway-watch tmux wrapper", () => {
365372});
366373367374expect(code).toBe(0);
368-expect(spawnSync).toHaveBeenNthCalledWith(
369-2,
370-"tmux",
371-[
372-"respawn-pane",
373-"-k",
374-"-t",
375-"openclaw-gateway-watch-dev-19001",
376-"-c",
377-"/repo",
378-expect.stringContaining("scripts/watch-node.mjs"),
379-],
380-expect.objectContaining({ encoding: "utf8" }),
381-);
375+const respawnCall = spawnCall(spawnSync, 1);
376+expect(respawnCall[0]).toBe("tmux");
377+const respawnArgs = respawnCall[1] as Array<unknown>;
378+expect(respawnArgs.slice(0, 6)).toEqual([
379+"respawn-pane",
380+"-k",
381+"-t",
382+"openclaw-gateway-watch-dev-19001",
383+"-c",
384+"/repo",
385+]);
386+expect(String(respawnArgs[6])).toContain("scripts/watch-node.mjs");
387+expect(requireRecord(respawnCall[2], "spawn options").encoding).toBe("utf8");
382388expect(stderr.chunks.join("")).toContain(
383389"gateway:watch restarted in tmux session openclaw-gateway-watch-dev-19001",
384390);
@@ -407,40 +413,36 @@ describe("gateway-watch tmux wrapper", () => {
407413});
408414409415expect(code).toBe(0);
410-expect(spawnSync).toHaveBeenNthCalledWith(
411-2,
412-"tmux",
413-[
414-"respawn-pane",
415-"-k",
416-"-t",
417-"openclaw-gateway-watch-main",
418-"-c",
419-"/repo",
420-expect.stringContaining("scripts/watch-node.mjs"),
421-],
422-expect.objectContaining({ encoding: "utf8" }),
423-);
424-expect(spawnSync).toHaveBeenNthCalledWith(
425-3,
426-"tmux",
427-["kill-session", "-t", "openclaw-gateway-watch-main"],
428-expect.objectContaining({ encoding: "utf8" }),
429-);
430-expect(spawnSync).toHaveBeenNthCalledWith(
431-4,
432-"tmux",
433-[
434-"new-session",
435-"-d",
436-"-s",
437-"openclaw-gateway-watch-main",
438-"-c",
439-"/repo",
440-expect.stringContaining("scripts/watch-node.mjs"),
441-],
442-expect.objectContaining({ encoding: "utf8" }),
443-);
416+const staleRespawnCall = spawnCall(spawnSync, 1);
417+expect(staleRespawnCall[0]).toBe("tmux");
418+const staleRespawnArgs = staleRespawnCall[1] as Array<unknown>;
419+expect(staleRespawnArgs.slice(0, 6)).toEqual([
420+"respawn-pane",
421+"-k",
422+"-t",
423+"openclaw-gateway-watch-main",
424+"-c",
425+"/repo",
426+]);
427+expect(String(staleRespawnArgs[6])).toContain("scripts/watch-node.mjs");
428+expect(requireRecord(staleRespawnCall[2], "spawn options").encoding).toBe("utf8");
429+expect(
430+expectSpawn(spawnSync, 2, "tmux", ["kill-session", "-t", "openclaw-gateway-watch-main"])
431+.encoding,
432+).toBe("utf8");
433+const recreatedCall = spawnCall(spawnSync, 3);
434+expect(recreatedCall[0]).toBe("tmux");
435+const recreatedArgs = recreatedCall[1] as Array<unknown>;
436+expect(recreatedArgs.slice(0, 6)).toEqual([
437+"new-session",
438+"-d",
439+"-s",
440+"openclaw-gateway-watch-main",
441+"-c",
442+"/repo",
443+]);
444+expect(String(recreatedArgs[6])).toContain("scripts/watch-node.mjs");
445+expect(requireRecord(recreatedCall[2], "spawn options").encoding).toBe("utf8");
444446});
445447446448it("runs the raw foreground watcher when tmux mode is disabled", () => {
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。