test(FN-4378): cover tracked delete action prompts in task surfaces
Fusion-Task-Id: FN-4378 Fusion-Task-Lineage: d3867ba8-f852-41e3-9db0-584c0ffc23b1
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
import { afterEach, describe, it, expect, vi } from "vitest";
|
import { afterEach, describe, it, expect, vi } from "vitest";
|
||||||
import { render, screen, fireEvent, waitFor, act } from "@testing-library/react";
|
import { render, screen, fireEvent, waitFor, act } from "@testing-library/react";
|
||||||
import { TaskCard, formatElapsedDurationDone, __test_areTaskCardPropsEqual } from "../TaskCard";
|
import { TaskCard, formatElapsedDurationDone, __test_areTaskCardPropsEqual } from "../TaskCard";
|
||||||
|
import type { ConfirmOptions } from "../../hooks/useConfirm";
|
||||||
import type { Task } from "@fusion/core";
|
import type { Task } from "@fusion/core";
|
||||||
|
|
||||||
// Mock lucide-react to avoid SVG rendering issues in test env
|
// Mock lucide-react to avoid SVG rendering issues in test env
|
||||||
@@ -38,6 +39,11 @@ vi.mock("../../api", () => ({
|
|||||||
fetchAgent: vi.fn(),
|
fetchAgent: vi.fn(),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
const mockConfirm = vi.fn<(options: ConfirmOptions) => Promise<boolean>>();
|
||||||
|
vi.mock("../../hooks/useConfirm", () => ({
|
||||||
|
useConfirm: () => ({ confirm: mockConfirm }),
|
||||||
|
}));
|
||||||
|
|
||||||
import { uploadAttachment, fetchMission, fetchAgent } from "../../api";
|
import { uploadAttachment, fetchMission, fetchAgent } from "../../api";
|
||||||
import { loadAllAppCss, loadAllAppCssBaseOnly } from "../../test/cssFixture";
|
import { loadAllAppCss, loadAllAppCssBaseOnly } from "../../test/cssFixture";
|
||||||
|
|
||||||
@@ -87,6 +93,50 @@ afterEach(() => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe("TaskCard", () => {
|
describe("TaskCard", () => {
|
||||||
|
it("uses githubIssueAction for tracked task delete", async () => {
|
||||||
|
const onDeleteTask = vi.fn(async () => makeTask());
|
||||||
|
mockConfirm
|
||||||
|
.mockResolvedValueOnce(true)
|
||||||
|
.mockResolvedValueOnce(true);
|
||||||
|
|
||||||
|
render(
|
||||||
|
<TaskCard
|
||||||
|
task={makeTask({
|
||||||
|
column: "triage",
|
||||||
|
githubTracking: {
|
||||||
|
enabled: true,
|
||||||
|
issue: { owner: "owner", repo: "repo", number: 42, url: "https://github.com/owner/repo/issues/42", createdAt: "2026-01-01T00:00:00Z" },
|
||||||
|
},
|
||||||
|
} as any)}
|
||||||
|
onOpenDetail={noop}
|
||||||
|
addToast={noop}
|
||||||
|
onDeleteTask={onDeleteTask}
|
||||||
|
/>,
|
||||||
|
);
|
||||||
|
|
||||||
|
await act(async () => {
|
||||||
|
fireEvent.click(screen.getByLabelText("Delete task"));
|
||||||
|
});
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(onDeleteTask).toHaveBeenCalledWith("FN-001", { githubIssueAction: "close" });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("keeps legacy delete options for untracked task", async () => {
|
||||||
|
const onDeleteTask = vi.fn(async () => makeTask());
|
||||||
|
mockConfirm.mockResolvedValueOnce(true);
|
||||||
|
|
||||||
|
render(<TaskCard task={makeTask({ column: "triage" })} onOpenDetail={noop} addToast={noop} onDeleteTask={onDeleteTask} />);
|
||||||
|
|
||||||
|
await act(async () => {
|
||||||
|
fireEvent.click(screen.getByLabelText("Delete task"));
|
||||||
|
});
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(onDeleteTask).toHaveBeenCalledWith("FN-001");
|
||||||
|
});
|
||||||
|
});
|
||||||
it("renders the card ID text", () => {
|
it("renders the card ID text", () => {
|
||||||
render(<TaskCard task={makeTask()} onOpenDetail={noop} addToast={noop} />);
|
render(<TaskCard task={makeTask()} onOpenDetail={noop} addToast={noop} />);
|
||||||
expect(screen.getByText("FN-001")).toBeDefined();
|
expect(screen.getByText("FN-001")).toBeDefined();
|
||||||
|
|||||||
@@ -90,6 +90,68 @@ describe("TaskDetailModal", () => {
|
|||||||
expect(screen.getByRole("menuitem", { name: "Pause" })).toBeTruthy();
|
expect(screen.getByRole("menuitem", { name: "Pause" })).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("passes githubIssueAction for tracked tasks", async () => {
|
||||||
|
const onDeleteTask = vi.fn().mockResolvedValue({} as Task);
|
||||||
|
|
||||||
|
mockConfirm
|
||||||
|
.mockResolvedValueOnce(true)
|
||||||
|
.mockResolvedValueOnce(true);
|
||||||
|
|
||||||
|
render(
|
||||||
|
<TaskDetailModal
|
||||||
|
task={makeTask({
|
||||||
|
githubTracking: {
|
||||||
|
enabled: true,
|
||||||
|
issue: {
|
||||||
|
owner: "owner",
|
||||||
|
repo: "repo",
|
||||||
|
number: 42,
|
||||||
|
url: "https://github.com/owner/repo/issues/42",
|
||||||
|
createdAt: "2026-01-01T00:00:00.000Z",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})}
|
||||||
|
onClose={noop}
|
||||||
|
onMoveTask={noopMove}
|
||||||
|
onDeleteTask={onDeleteTask}
|
||||||
|
onMergeTask={noopMerge}
|
||||||
|
onOpenDetail={noopOpenDetail}
|
||||||
|
addToast={noop}
|
||||||
|
/>,
|
||||||
|
);
|
||||||
|
|
||||||
|
fireEvent.click(screen.getByRole("button", { name: /actions/i }));
|
||||||
|
fireEvent.click(screen.getByRole("menuitem", { name: "Delete" }));
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(onDeleteTask).toHaveBeenCalledWith("FN-099", { githubIssueAction: "close" });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("keeps legacy delete payload for untracked tasks", async () => {
|
||||||
|
const onDeleteTask = vi.fn().mockResolvedValue({} as Task);
|
||||||
|
mockConfirm.mockResolvedValueOnce(true);
|
||||||
|
|
||||||
|
render(
|
||||||
|
<TaskDetailModal
|
||||||
|
task={makeTask()}
|
||||||
|
onClose={noop}
|
||||||
|
onMoveTask={noopMove}
|
||||||
|
onDeleteTask={onDeleteTask}
|
||||||
|
onMergeTask={noopMerge}
|
||||||
|
onOpenDetail={noopOpenDetail}
|
||||||
|
addToast={noop}
|
||||||
|
/>,
|
||||||
|
);
|
||||||
|
|
||||||
|
fireEvent.click(screen.getByRole("button", { name: /actions/i }));
|
||||||
|
fireEvent.click(screen.getByRole("menuitem", { name: "Delete" }));
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(onDeleteTask).toHaveBeenCalledWith("FN-099");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it("prompts for dependency-removal confirmation and retries delete with explicit flag", async () => {
|
it("prompts for dependency-removal confirmation and retries delete with explicit flag", async () => {
|
||||||
const onDeleteTask = vi.fn();
|
const onDeleteTask = vi.fn();
|
||||||
const conflict = new Error("Cannot delete task FN-099: still referenced as a dependency by FN-100, FN-101.") as Error & {
|
const conflict = new Error("Cannot delete task FN-099: still referenced as a dependency by FN-100, FN-101.") as Error & {
|
||||||
|
|||||||
Reference in New Issue
Block a user