import { cleanup, fireEvent, render, screen, waitFor } from "@testing-library/react";
import { afterEach, describe, expect, it, vi } from "vitest";
import type { TaskPlan, TaskPlanRevision } from "@/lib/types/http";
const implementPlanMock = vi.fn().mockResolvedValue(undefined);
vi.mock("@/hooks/domains/kanban/use-plan-actions", () => ({
useImplementPlanRunner: () => implementPlanMock,
}));
vi.mock("./task-plan-revisions", () => ({
TaskPlanRevisions: () => null,
}));
vi.mock("./chat/implement-plan-button", () => ({
ImplementPlanButton: ({
onClick,
disabled,
}: {
onClick: (fresh: boolean) => void;
disabled?: boolean;
}) => (
),
}));
import { PlanPanelHeader } from "./task-plan-panel-header";
const TASK_1 = "task-1";
const REVISIONS: TaskPlanRevision[] = [];
function renderHeader(attemptSave: (content: string, title?: string) => Promise) {
return render(
{}}
onRevert={async () => null}
loadRevisionContent={async () => ""}
previewRevisionId={null}
setPreviewRevision={() => {}}
comparePair={[null, null]}
toggleCompareSelection={() => {}}
clearComparePair={() => {}}
/>,
);
}
describe("PlanPanelHeader Implement routes through the guarded save entry point", () => {
afterEach(() => {
cleanup();
implementPlanMock.mockClear();
});
it("calls the attemptSave prop, not a separate raw save path, before implementing", async () => {
// Regression test: handleImplement used to call a raw savePlan prop that
// bypassed usePlanDraft's attemptSave wrapper, so an oversized draft
// rejected via the Implement button was never recorded in the autosave
// suppression ref — the very next autosave tick resubmitted the same
// rejected content. Routing through attemptSave (whatever the caller
// passes as this prop) closes that gap; this test pins that the panel's
// wiring passes the guarded callback and that a rejection here does not
// proceed to implement.
const attemptSave = vi.fn().mockResolvedValue(null); // simulates a size rejection
renderHeader(attemptSave);
fireEvent.click(screen.getByTestId("implement-button"));
await waitFor(() =>
expect(attemptSave).toHaveBeenCalledWith("draft that will be sent", undefined),
);
expect(implementPlanMock).not.toHaveBeenCalled();
});
it("proceeds to implement once the guarded save succeeds", async () => {
const savedPlan: TaskPlan = {
task_id: TASK_1,
content: "draft that will be sent",
title: "Plan",
} as TaskPlan;
const attemptSave = vi.fn().mockResolvedValue(savedPlan);
renderHeader(attemptSave);
fireEvent.click(screen.getByTestId("implement-button"));
await waitFor(() => expect(implementPlanMock).toHaveBeenCalledWith(false));
expect(attemptSave).toHaveBeenCalledWith("draft that will be sent", undefined);
});
});