Skip to content

Commit 60a5f1f

Browse files
kangjinghangclaude
andcommitted
test(ui): harden stream:item toolprogress test coverage
- Add afterAll to clean up the window installed by beforeAll (only when we installed it, so we don't disturb sibling describe blocks that may rely on a pre-existing window). - Add two guard tests for the stream:"item" branch in handleAgentEvent: events whose kind is not "tool" or whose phase is not "update" are ignored, leaving the entry's progressText untouched. In-scope suite: 124 pass (was 122). No regressions. Co-Authored-By: Claude Opus 4.6 <[email protected]>
1 parent 3554302 commit 60a5f1f

1 file changed

Lines changed: 66 additions & 1 deletion

File tree

ui/src/ui/app-tool-stream.node.test.ts

Lines changed: 66 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// @vitest-environment node
2-
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
2+
import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
33
import { ACTIVITY_ENTRY_LIMIT, ACTIVITY_OUTPUT_PREVIEW_LIMIT } from "./activity-model.ts";
44
import {
55
handleAgentEvent,
@@ -833,12 +833,25 @@ describe("app-tool-stream fallback lifecycle handling", () => {
833833
});
834834

835835
describe("stream:item toolprogress events", () => {
836+
let weSetWindow = false;
836837
beforeAll(() => {
837838
const globalWithWindow = globalThis as typeof globalThis & {
838839
window?: Window & typeof globalThis;
839840
};
840841
if (!globalWithWindow.window) {
841842
globalWithWindow.window = globalThis as unknown as Window & typeof globalThis;
843+
weSetWindow = true;
844+
}
845+
});
846+
afterAll(() => {
847+
// Only clean up the window we installed; leave any pre-existing one
848+
// intact so we don't disturb sibling describe blocks that may rely on it.
849+
if (weSetWindow) {
850+
const globalWithWindow = globalThis as typeof globalThis & {
851+
window?: Window & typeof globalThis;
852+
};
853+
delete globalWithWindow.window;
854+
weSetWindow = false;
842855
}
843856
});
844857

@@ -910,6 +923,58 @@ describe("stream:item toolprogress events", () => {
910923
expect(host.toolStreamOrder).toHaveLength(0);
911924
});
912925

926+
it("ignores stream:item events whose kind is not 'tool'", () => {
927+
const host = createHost();
928+
handleAgentEvent(
929+
host,
930+
agentEvent("run-1", 1, "tool", {
931+
phase: "start",
932+
toolCallId: "id-1",
933+
name: "trading_quick",
934+
}),
935+
);
936+
handleAgentEvent(
937+
host,
938+
agentEvent("run-1", 2, "item", {
939+
kind: "text",
940+
phase: "update",
941+
toolCallId: "id-1",
942+
progressText: "should be ignored",
943+
}),
944+
);
945+
const entry = host.toolStreamById.get("id-1");
946+
expect(entry?.progressText).toBeUndefined();
947+
expect(entry?.message.content).not.toContainEqual(
948+
expect.objectContaining({ type: "toolprogress" }),
949+
);
950+
});
951+
952+
it("ignores stream:item tool events whose phase is not 'update'", () => {
953+
const host = createHost();
954+
handleAgentEvent(
955+
host,
956+
agentEvent("run-1", 1, "tool", {
957+
phase: "start",
958+
toolCallId: "id-1",
959+
name: "trading_quick",
960+
}),
961+
);
962+
handleAgentEvent(
963+
host,
964+
agentEvent("run-1", 2, "item", {
965+
kind: "tool",
966+
phase: "start",
967+
toolCallId: "id-1",
968+
progressText: "should be ignored",
969+
}),
970+
);
971+
const entry = host.toolStreamById.get("id-1");
972+
expect(entry?.progressText).toBeUndefined();
973+
expect(entry?.message.content).not.toContainEqual(
974+
expect.objectContaining({ type: "toolprogress" }),
975+
);
976+
});
977+
913978
it("clears progressText when the final result arrives", () => {
914979
const host = createHost();
915980
handleAgentEvent(

0 commit comments

Comments
 (0)