





















@@ -54,6 +54,14 @@ function collectedTexts() {
5454return enqueueSystemEventMock.mock.calls.map((call) => String(call[0] ?? ""));
5555}
565657+function expectTextWithFragment(texts: string[], fragment: string): void {
58+expect(texts.some((text) => text.includes(fragment))).toBe(true);
59+}
60+61+function expectNoTextWithFragment(texts: string[], fragment: string): void {
62+expect(texts.every((text) => !text.includes(fragment))).toBe(true);
63+}
64+5765describe("startAcpSpawnParentStreamRelay", () => {
5866beforeAll(async () => {
5967({ emitAgentEvent } = await import("../infra/agent-events.js"));
@@ -113,34 +121,34 @@ describe("startAcpSpawnParentStreamRelay", () => {
113121});
114122115123const texts = collectedTexts();
116-expect(texts).toEqual(
117-expect.arrayContaining([expect.stringContaining("Started codex session")]),
118-);
119-expect(texts).toEqual(
120-expect.arrayContaining([expect.stringContaining("codex: hello from child")]),
121-);
122-expect(texts).toEqual(
123-expect.arrayContaining([expect.stringContaining("codex run completed in 2s")]),
124-);
124+expectTextWithFragment(texts, "Started codex session");
125+expectTextWithFragment(texts, "codex: hello from child");
126+expectTextWithFragment(texts, "codex run completed in 2s");
125127expect(
126128enqueueSystemEventMock.mock.calls.every(
127129(call) => (call[1] as { trusted?: boolean } | undefined)?.trusted === false,
128130),
129131).toBe(true);
130-expect(enqueueSystemEventMock).toHaveBeenCalledWith(
131-expect.any(String),
132-expect.objectContaining({
133-sessionKey: "agent:main:main",
134- deliveryContext,
135-trusted: false,
136-}),
137-);
138-expect(requestHeartbeatMock).toHaveBeenCalledWith(
139-expect.objectContaining({
140-reason: "acp:spawn:stream",
141-sessionKey: "agent:main:main",
142-}),
143-);
132+const systemEventCalls = enqueueSystemEventMock.mock.calls as Array<
133+[string, { sessionKey?: string; deliveryContext?: unknown; trusted?: boolean }]
134+>;
135+expect(
136+systemEventCalls.some(
137+([, options]) =>
138+options.sessionKey === "agent:main:main" &&
139+options.deliveryContext === deliveryContext &&
140+options.trusted === false,
141+),
142+).toBe(true);
143+const heartbeatCalls = requestHeartbeatMock.mock.calls as Array<
144+[{ reason?: string; sessionKey?: string }]
145+>;
146+expect(
147+heartbeatCalls.some(
148+([options]) =>
149+options.reason === "acp:spawn:stream" && options.sessionKey === "agent:main:main",
150+),
151+).toBe(true);
144152relay.dispose();
145153});
146154@@ -156,9 +164,7 @@ describe("startAcpSpawnParentStreamRelay", () => {
156164});
157165158166vi.advanceTimersByTime(1_500);
159-expect(collectedTexts()).toEqual(
160-expect.arrayContaining([expect.stringContaining("has produced no output for 1s")]),
161-);
167+expectTextWithFragment(collectedTexts(), "has produced no output for 1s");
162168163169emitAgentEvent({
164170runId: "run-2",
@@ -170,10 +176,8 @@ describe("startAcpSpawnParentStreamRelay", () => {
170176vi.advanceTimersByTime(5);
171177172178const texts = collectedTexts();
173-expect(texts).toEqual(expect.arrayContaining([expect.stringContaining("resumed output.")]));
174-expect(texts).toEqual(
175-expect.arrayContaining([expect.stringContaining("codex: resumed output")]),
176-);
179+expectTextWithFragment(texts, "resumed output.");
180+expectTextWithFragment(texts, "codex: resumed output");
177181178182emitAgentEvent({
179183runId: "run-2",
@@ -183,9 +187,7 @@ describe("startAcpSpawnParentStreamRelay", () => {
183187error: "boom",
184188},
185189});
186-expect(collectedTexts()).toEqual(
187-expect.arrayContaining([expect.stringContaining("run failed: boom")]),
188-);
190+expectTextWithFragment(collectedTexts(), "run failed: boom");
189191relay.dispose();
190192});
191193@@ -201,9 +203,7 @@ describe("startAcpSpawnParentStreamRelay", () => {
201203});
202204203205vi.advanceTimersByTime(1_001);
204-expect(collectedTexts()).toEqual(
205-expect.arrayContaining([expect.stringContaining("stream relay timed out after 1s")]),
206-);
206+expectTextWithFragment(collectedTexts(), "stream relay timed out after 1s");
207207208208const before = enqueueSystemEventMock.mock.calls.length;
209209emitAgentEvent({
@@ -228,15 +228,11 @@ describe("startAcpSpawnParentStreamRelay", () => {
228228emitStartNotice: false,
229229});
230230231-expect(collectedTexts()).not.toEqual(
232-expect.arrayContaining([expect.stringContaining("Started codex session")]),
233-);
231+expectNoTextWithFragment(collectedTexts(), "Started codex session");
234232235233relay.notifyStarted();
236234237-expect(collectedTexts()).toEqual(
238-expect.arrayContaining([expect.stringContaining("Started codex session")]),
239-);
235+expectTextWithFragment(collectedTexts(), "Started codex session");
240236relay.dispose();
241237});
242238@@ -300,7 +296,7 @@ describe("startAcpSpawnParentStreamRelay", () => {
300296vi.advanceTimersByTime(15);
301297302298const texts = collectedTexts();
303-expect(texts).toEqual(expect.arrayContaining([expect.stringContaining("codex: hello world")]));
299+expectTextWithFragment(texts, "codex: hello world");
304300relay.dispose();
305301});
306302@@ -325,12 +321,8 @@ describe("startAcpSpawnParentStreamRelay", () => {
325321vi.advanceTimersByTime(15);
326322327323const texts = collectedTexts();
328-expect(texts).not.toEqual(
329-expect.arrayContaining([expect.stringContaining("checking thread context")]),
330-);
331-expect(texts).not.toEqual(
332-expect.arrayContaining([expect.stringContaining("post a tight progress reply here")]),
333-);
324+expectNoTextWithFragment(texts, "checking thread context");
325+expectNoTextWithFragment(texts, "post a tight progress reply here");
334326relay.dispose();
335327});
336328@@ -363,12 +355,8 @@ describe("startAcpSpawnParentStreamRelay", () => {
363355vi.advanceTimersByTime(15);
364356365357const texts = collectedTexts();
366-expect(texts).not.toEqual(
367-expect.arrayContaining([expect.stringContaining("checking thread context")]),
368-);
369-expect(texts).toEqual(
370-expect.arrayContaining([expect.stringContaining("codex: final answer ready")]),
371-);
358+expectNoTextWithFragment(texts, "checking thread context");
359+expectTextWithFragment(texts, "codex: final answer ready");
372360relay.dispose();
373361});
374362@@ -392,14 +380,14 @@ describe("startAcpSpawnParentStreamRelay", () => {
392380expect(readAcpSessionEntryMock).toHaveBeenCalledWith({
393381sessionKey: "agent:codex:acp:child-1",
394382});
395-expect(resolveSessionFilePathMock).toHaveBeenCalledWith(
396- "sess-123",
397-expect.objectContaining({
398- sessionId: "sess-123",
399-}),
400- expect.objectContaining({
401- storePath: "/tmp/openclaw/agents/codex/sessions/sessions.json",
402- }),
403-);
383+expect(resolveSessionFilePathMock).toHaveBeenCalledTimes(1);
384+const [sessionId, entry, options] = resolveSessionFilePathMock.mock.calls[0] as [
385+string,
386+{ sessionId?: unknown },
387+{ storePath?: unknown },
388+];
389+expect(sessionId).toBe("sess-123");
390+expect(entry.sessionId).toBe("sess-123");
391+expect(options.storePath).toBe("/tmp/openclaw/agents/codex/sessions/sessions.json");
404392});
405393});
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。