fix(cli): z-order Cancel #151 + projection live événements avant Final #167 (+ alignement fixture plugin #165/#166) — QA verte

This commit is contained in:
2026-08-06 19:09:07 +02:00
parent 3d4ea6859e
commit b45deabe6d
4 changed files with 133 additions and 24 deletions

View File

@ -37,7 +37,17 @@ function addPluginCommand(
pluginId,
displayName: "Acme Plugin",
contributes: {
commands: [{ id: commandId, title: "Explain", shortDescription: "Explain selection" }],
menus: [],
menuItems: [],
slashCommands: [
{
name: "/explain",
shortDescription: "Explain selection",
command: commandId,
},
],
layouts: [],
mcpServers: [],
},
commands,
layouts: new PluginLayoutRegistry(pluginId, new Set()),
@ -408,6 +418,83 @@ describe("CustomAgentChatView", () => {
expect(screen.getByText("Progress").parentElement?.textContent).toContain("done");
});
it("does not append late progress chunks after the final answer", async () => {
let emitChunk: ((chunk: unknown) => void) | null = null;
const agent = {
launchAgentChat: vi.fn(),
reattachAgentChat: vi.fn(async (sessionId: string) => ({
sessionId,
scrollback: [],
})),
sendAgentChat: vi.fn(
(_sessionId: string, _prompt: string, onChunk: (chunk: unknown) => void) =>
new Promise<void>((resolve) => {
emitChunk = (chunk: unknown) => {
onChunk(chunk);
if ((chunk as { kind?: string }).kind === "final") resolve();
};
}),
),
cancelAgentChat: vi.fn(async () => {}),
closeAgentChat: vi.fn(async () => {}),
};
render(
<DIProvider
gateways={{
agent,
system: { pickFile: vi.fn(async () => null) },
} as unknown as Gateways}
>
<CustomAgentChatView
projectId="project-1"
agentId="agent-1"
agentName="Worker"
profile={profile}
cwd="/repo"
nodeId="node-1"
sessionId="chat-session-1"
conversationId="conversation-1"
onSessionId={vi.fn()}
onConversationId={vi.fn()}
/>
</DIProvider>,
);
await waitFor(() =>
expect(agent.reattachAgentChat).toHaveBeenCalledWith(
"chat-session-1",
expect.any(Function),
),
);
fireEvent.change(screen.getByLabelText(/message CLI custom/), {
target: { value: "ship ordered stream" },
});
fireEvent.click(screen.getByRole("button", { name: "Envoyer" }));
await waitFor(() => expect(emitChunk).not.toBeNull());
act(() => {
emitChunk?.({ kind: "final", content: "done" });
});
await screen.findByText("done");
act(() => {
emitChunk?.({
kind: "progress",
progress: {
source: "ideaLocal",
kind: "mcp",
stage: "started",
label: "idea_ticket_read",
toolName: "idea_ticket_read",
},
});
});
expect(screen.queryByText("idea_ticket_read")).toBeNull();
});
it("shows slash-command suggestions from the gateway, filters by prefix, and inserts the selected command", async () => {
const agent = {
launchAgentChat: vi.fn(),
@ -1040,6 +1127,7 @@ describe("CustomAgentChatView", () => {
expect(shell.className).toContain("overflow-hidden");
expect(toolbar.className).toContain("overflow-hidden");
expect(cancel.className).toContain("shrink-0");
expect(cancel.className).toContain("z-30");
expect(scroll.className).toContain("flex-1");
expect(scroll.className).toContain("basis-0");
expect(scroll.className).toContain("overflow-y-auto");