Files
fusion/packages/dashboard/app/components/__tests__/DuplicateWarningModal.test.tsx
gsxdsm a6685b7f03 FN-6930: add New Task duplicate preflight
Add duplicate detection parity to full-dialog task creation and improve duplicate warnings.\n\n- Run duplicate checks before New Task dialog creation and require explicit acknowledgement to create anyway.\n- Show duplicate task descriptions with title and empty-state fallbacks in the warning modal.\n- Cover duplicate warning and New Task duplicate flows with dashboard tests.\n- Document duplicate handling parity and add a published CLI changeset.\n\nFiles changed:\n .changeset/new-task-duplicates.md                  |   5 +\n docs/dashboard-guide.md                            |   4 +\n .../app/components/DuplicateWarningModal.css       |   6 +-\n .../app/components/DuplicateWarningModal.tsx       |   6 +-\n packages/dashboard/app/components/NewTaskModal.tsx | 324 ++++++++++++---------\n .../__tests__/DuplicateWarningModal.test.tsx       |  28 +-\n .../app/components/__tests__/NewTaskModal.test.tsx | 104 +++++++\n 7 files changed, 331 insertions(+), 146 deletions(-)

Fusion-Task-Id: FN-6930

Fusion-Task-Lineage: 06d75ec5-e7e8-4124-9b08-47a7adad4fad
2026-06-22 23:42:45 -07:00

65 lines
2.7 KiB
TypeScript

import { describe, it, expect, vi } from "vitest";
import { fireEvent, render, screen } from "@testing-library/react";
import { DuplicateWarningModal } from "../DuplicateWarningModal";
import type { DuplicateMatch } from "../../api";
const matches: DuplicateMatch[] = [
{ id: "FN-101", title: "Fix duplicate task flow", description: "Prevent duplicate tasks from the quick entry surface", column: "todo", score: 0.81 },
{ id: "FN-102", title: "Another duplicate", description: "Detect duplicates before saving full dialog tasks", column: "in-progress", score: 0.67 },
];
describe("DuplicateWarningModal", () => {
it("renders one row per match with id and description", () => {
render(<DuplicateWarningModal matches={matches} onOpen={vi.fn()} onProceed={vi.fn()} onCancel={vi.fn()} />);
expect(screen.getByText("FN-101")).toBeInTheDocument();
expect(screen.getByText("FN-102")).toBeInTheDocument();
expect(screen.getByText("Prevent duplicate tasks from the quick entry surface")).toBeInTheDocument();
expect(screen.getByText("Detect duplicates before saving full dialog tasks")).toBeInTheDocument();
expect(screen.queryByText("Fix duplicate task flow")).not.toBeInTheDocument();
});
it("falls back from empty description to title then No description", () => {
render(
<DuplicateWarningModal
matches={[
{ id: "FN-201", title: "Title fallback", description: "", column: "todo", score: 0.71 },
{ id: "FN-202", title: "", description: "", column: "todo", score: 0.62 },
]}
onOpen={vi.fn()}
onProceed={vi.fn()}
onCancel={vi.fn()}
/>,
);
expect(screen.getByText("Title fallback")).toBeInTheDocument();
expect(screen.getByText("No description")).toBeInTheDocument();
});
it("calls onOpen with the selected id", () => {
const onOpen = vi.fn();
render(<DuplicateWarningModal matches={matches} onOpen={onOpen} onProceed={vi.fn()} onCancel={vi.fn()} />);
fireEvent.click(screen.getAllByRole("button", { name: "Open" })[1]);
expect(onOpen).toHaveBeenCalledWith("FN-102");
});
it("calls onProceed", () => {
const onProceed = vi.fn();
render(<DuplicateWarningModal matches={matches} onOpen={vi.fn()} onProceed={onProceed} onCancel={vi.fn()} />);
fireEvent.click(screen.getByRole("button", { name: "Create anyway" }));
expect(onProceed).toHaveBeenCalledTimes(1);
});
it("calls onCancel for cancel click and Escape", () => {
const onCancel = vi.fn();
render(<DuplicateWarningModal matches={matches} onOpen={vi.fn()} onProceed={vi.fn()} onCancel={onCancel} />);
fireEvent.click(screen.getByRole("button", { name: "Cancel" }));
fireEvent.keyDown(document, { key: "Escape" });
expect(onCancel).toHaveBeenCalledTimes(2);
});
});