FN-6574: repair TaskDetailModal definition test lanes
Repair TaskDetailModal tests so Definition-surface assertions remain valid after Chat became the default tab. - Add regression coverage for explicitly opening the Definition tab while the default tab remains Chat. - Set definition-focused TaskDetailModal test renders to use initialTab="definition" across the split dashboard lanes. - Document why Definition-only assertions opt into the Definition tab after the Chat-default-tab change. Files changed: .../TaskDetailModal.attachments-and-tabs.test.tsx | 33 +++++++++ ...TaskDetailModal.github-tracking-header.test.tsx | 5 ++ .../TaskDetailModal.github-tracking-stale.test.tsx | 11 +++ ...lModal.inline-editing-and-integrations.test.tsx | 83 ++++++++++++++++++++++ ...skDetailModal.models-progress-workflow.test.tsx | 33 +++++++++ .../__tests__/TaskDetailModal.rendering.test.tsx | 73 +++++++++++++++++++ ...etailModal.responsive-and-dependencies.test.tsx | 37 ++++++++++ .../components/__tests__/TaskDetailModal.test.tsx | 17 +++++ 8 files changed, 292 insertions(+) Fusion-Task-Id: FN-6574 Fusion-Task-Lineage: f8d5e038-058a-4d12-8384-2ef603988e3a
This commit is contained in:
@@ -17,6 +17,10 @@ import {
|
||||
} from "./TaskDetailModal.test-helpers";
|
||||
import { TaskDetailModal, TaskDetailContent } from "../TaskDetailModal";
|
||||
|
||||
/*
|
||||
FNXC:TaskDetailTabs 2026-06-17-08:20:
|
||||
FN-6532 made Chat the default TaskDetailModal tab. Definition-tab regression coverage must prove both the no-`initialTab` Chat landing state and the explicit `initialTab="definition"` Definition surface for prompt, GitHub tracking, and dependency sections.
|
||||
*/
|
||||
setupTaskDetailModalHooks();
|
||||
|
||||
describe("TaskDetailModal", () => {
|
||||
@@ -988,6 +992,35 @@ describe("TaskDetailModal", () => {
|
||||
expect(container.querySelector(".detail-section--chat")).toBeNull();
|
||||
});
|
||||
|
||||
it("FN-6574 renders Definition-only content when initialTab requests definition", () => {
|
||||
const blocker = makeTask({ id: "FN-6574", title: "Definition task", prompt: "# Spec\n\nDefinition body unique text.", dependencies: ["FN-100"], githubTracking: { enabled: true } });
|
||||
const dependency = makeTask({ id: "FN-100", title: "Dependency task" });
|
||||
const dependent = makeTask({ id: "FN-200", title: "Dependent task", dependencies: ["FN-6574"] });
|
||||
const { container } = render(
|
||||
<TaskDetailModal
|
||||
task={blocker}
|
||||
tasks={[blocker, dependency, dependent]}
|
||||
initialTab="definition"
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
onDeleteTask={noopDelete}
|
||||
onMergeTask={noopMerge}
|
||||
onOpenDetail={noopOpenDetail}
|
||||
addToast={noop}
|
||||
/>,
|
||||
);
|
||||
|
||||
expect(screen.getByRole("button", { name: "Definition" })).toHaveClass("detail-tab-active");
|
||||
expect(screen.getByRole("button", { name: "Chat" })).not.toHaveClass("detail-tab-active");
|
||||
expect(container.querySelector(".detail-section--chat")).toBeNull();
|
||||
expect(screen.getByText("Definition body unique text.")).toBeInTheDocument();
|
||||
expect(screen.getByText("GitHub tracking")).toBeInTheDocument();
|
||||
expect(screen.getByText("Dependencies")).toBeInTheDocument();
|
||||
expect(screen.getByText("Blocking")).toBeInTheDocument();
|
||||
expect(container).toHaveTextContent("FN-100");
|
||||
expect(container).toHaveTextContent("FN-200");
|
||||
});
|
||||
|
||||
it("FN-6347 applies chat modifiers only while the Chat tab is active", () => {
|
||||
const { container } = render(
|
||||
<TaskDetailModal
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
/*
|
||||
FNXC:TaskDetailTabs 2026-06-17-08:20:
|
||||
FN-6532 made Chat the default TaskDetailModal tab. Tests that assert Definition-only sections must opt into `initialTab="definition"` so they verify the intended surface instead of the Chat landing state.
|
||||
*/
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { render, screen } from "@testing-library/react";
|
||||
import { loadAllAppCss } from "../../test/cssFixture";
|
||||
@@ -10,6 +14,7 @@ describe("FN-4224 GitHub tracking header layout", () => {
|
||||
it("keeps the summary, enable action, and disclosure toggle on one row across desktop and mobile CSS", () => {
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({
|
||||
column: "todo",
|
||||
githubTracking: { enabled: false },
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
/*
|
||||
FNXC:TaskDetailTabs 2026-06-17-08:20:
|
||||
FN-6532 made Chat the default TaskDetailModal tab. Tests that assert Definition-only sections must opt into `initialTab="definition"` so they verify the intended surface instead of the Chat landing state.
|
||||
*/
|
||||
import { describe, it, expect, vi } from "vitest";
|
||||
import { render, screen, waitFor } from "@testing-library/react";
|
||||
import userEvent from "@testing-library/user-event";
|
||||
@@ -25,6 +29,7 @@ describe("TaskDetailModal GitHub tracking stale await guards (FN-5148)", () => {
|
||||
|
||||
const { rerender } = render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={taskA}
|
||||
onClose={() => {}}
|
||||
onMoveTask={noopMove}
|
||||
@@ -39,6 +44,7 @@ describe("TaskDetailModal GitHub tracking stale await guards (FN-5148)", () => {
|
||||
await user.click(screen.getByRole("button", { name: "Enable GitHub tracking" }));
|
||||
rerender(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={taskB}
|
||||
onClose={() => {}}
|
||||
onMoveTask={noopMove}
|
||||
@@ -77,6 +83,7 @@ describe("TaskDetailModal GitHub tracking stale await guards (FN-5148)", () => {
|
||||
|
||||
const { rerender } = render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={taskA}
|
||||
onClose={() => {}}
|
||||
onMoveTask={noopMove}
|
||||
@@ -95,6 +102,7 @@ describe("TaskDetailModal GitHub tracking stale await guards (FN-5148)", () => {
|
||||
|
||||
rerender(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={taskB}
|
||||
onClose={() => {}}
|
||||
onMoveTask={noopMove}
|
||||
@@ -131,6 +139,7 @@ describe("TaskDetailModal GitHub tracking stale await guards (FN-5148)", () => {
|
||||
|
||||
const { rerender } = render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={taskA}
|
||||
onClose={() => {}}
|
||||
onMoveTask={noopMove}
|
||||
@@ -147,6 +156,7 @@ describe("TaskDetailModal GitHub tracking stale await guards (FN-5148)", () => {
|
||||
|
||||
rerender(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={taskB}
|
||||
onClose={() => {}}
|
||||
onMoveTask={noopMove}
|
||||
@@ -176,6 +186,7 @@ describe("TaskDetailModal GitHub tracking stale await guards (FN-5148)", () => {
|
||||
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={taskA}
|
||||
onClose={() => {}}
|
||||
onMoveTask={noopMove}
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
/*
|
||||
FNXC:TaskDetailTabs 2026-06-17-08:20:
|
||||
FN-6532 made Chat the default TaskDetailModal tab. Tests that assert Definition-only sections must opt into `initialTab="definition"` so they verify the intended surface instead of the Chat landing state.
|
||||
*/
|
||||
import { describe, it, expect, vi } from "vitest";
|
||||
import { useState } from "react";
|
||||
import { render, screen, fireEvent, act, waitFor } from "@testing-library/react";
|
||||
@@ -76,6 +80,7 @@ describe("TaskDetailModal", () => {
|
||||
const user = userEvent.setup();
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({
|
||||
sourceIssue: {
|
||||
provider: "github",
|
||||
@@ -138,6 +143,7 @@ describe("TaskDetailModal", () => {
|
||||
it("does not render GitHub badge for non-github providers", () => {
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({
|
||||
sourceIssue: {
|
||||
provider: "gitlab",
|
||||
@@ -163,6 +169,7 @@ describe("TaskDetailModal", () => {
|
||||
it("hides source issue read section when sourceIssue metadata is missing", () => {
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ sourceIssue: undefined })}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -180,6 +187,7 @@ describe("TaskDetailModal", () => {
|
||||
it("prefills source issue inputs in edit mode", async () => {
|
||||
const { container } = render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({
|
||||
id: "FN-001",
|
||||
column: "todo",
|
||||
@@ -214,6 +222,7 @@ describe("TaskDetailModal", () => {
|
||||
it("renders source issue block below Model Configuration in edit mode", async () => {
|
||||
const { container } = render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({
|
||||
id: "FN-001",
|
||||
column: "todo",
|
||||
@@ -255,6 +264,7 @@ describe("TaskDetailModal", () => {
|
||||
|
||||
const { container } = render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({
|
||||
id: "FN-001",
|
||||
column: "todo",
|
||||
@@ -304,6 +314,7 @@ describe("TaskDetailModal", () => {
|
||||
|
||||
const { container } = render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({
|
||||
id: "FN-001",
|
||||
column: "todo",
|
||||
@@ -346,6 +357,7 @@ describe("TaskDetailModal", () => {
|
||||
|
||||
const { container } = render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({
|
||||
id: "FN-001",
|
||||
column: "todo",
|
||||
@@ -385,6 +397,7 @@ describe("TaskDetailModal", () => {
|
||||
it("shows Edit button in header when task is in triage column", () => {
|
||||
const { container } = render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ id: "FN-001", column: "triage", title: "Test task" })}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -402,6 +415,7 @@ describe("TaskDetailModal", () => {
|
||||
it("shows Edit button in header when task is in todo column", () => {
|
||||
const { container } = render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ id: "FN-001", column: "todo", title: "Test task" })}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -419,6 +433,7 @@ describe("TaskDetailModal", () => {
|
||||
it("does not show Edit button when task is in in-progress column", () => {
|
||||
const { container } = render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ id: "FN-001", column: "in-progress", title: "Test task" })}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -436,6 +451,7 @@ describe("TaskDetailModal", () => {
|
||||
it("does not show Edit button when already in edit mode", () => {
|
||||
const { container } = render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ id: "FN-001", column: "triage", title: "Test task" })}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -460,6 +476,7 @@ describe("TaskDetailModal", () => {
|
||||
it("entering edit mode shows title input and description textarea", () => {
|
||||
const { container } = render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ id: "FN-001", column: "triage", title: "Test task", description: "Test description" })}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -486,6 +503,7 @@ describe("TaskDetailModal", () => {
|
||||
it("clicking Cancel exits edit mode without saving", () => {
|
||||
const { container } = render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ id: "FN-001", column: "triage", title: "Original title", description: "Original description" })}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -518,6 +536,7 @@ describe("TaskDetailModal", () => {
|
||||
|
||||
const { container } = render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ id: "FN-001", column: "triage", title: "Original title", description: "Original description" })}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -551,6 +570,7 @@ describe("TaskDetailModal", () => {
|
||||
it("Save button is enabled in edit mode", () => {
|
||||
const { container } = render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ id: "FN-001", column: "triage", title: "Test title", description: "Test description" })}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -576,6 +596,7 @@ describe("TaskDetailModal", () => {
|
||||
|
||||
const { container } = render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ id: "FN-001", column: "triage", title: "Original" })}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -608,6 +629,7 @@ describe("TaskDetailModal", () => {
|
||||
|
||||
const { container } = render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ id: "FN-001", column: "triage", title: "Original" })}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -644,6 +666,7 @@ describe("TaskDetailModal", () => {
|
||||
|
||||
const { container } = render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ id: "FN-001", column: "triage", title: "Original" })}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -674,6 +697,7 @@ describe("TaskDetailModal", () => {
|
||||
it("Escape key exits edit mode", async () => {
|
||||
const { container } = render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ id: "FN-001", column: "triage", title: "Test title" })}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -701,6 +725,7 @@ describe("TaskDetailModal", () => {
|
||||
it("edit mode shows both title and description fields", () => {
|
||||
const { container } = render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ id: "FN-001", column: "triage", title: "Test title", description: "Test description" })}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -722,6 +747,7 @@ describe("TaskDetailModal", () => {
|
||||
it("edit mode renders model configuration and workflow steps", () => {
|
||||
const { container } = render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ id: "FN-001", column: "triage", title: "Test task" })}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -749,6 +775,7 @@ describe("TaskDetailModal", () => {
|
||||
|
||||
const { container } = render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ id: "FN-001", column: "triage", title: "Test", description: "Desc", dependencies: ["FN-002"] })}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -782,6 +809,7 @@ describe("TaskDetailModal", () => {
|
||||
|
||||
const { container } = render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ id: "FN-001", column: "triage", title: "Test", description: "Desc", priority: "normal" })}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -817,6 +845,7 @@ describe("TaskDetailModal", () => {
|
||||
|
||||
const { container } = render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ id: "FN-001", column: "triage", title: "Test", description: "Desc", executionMode: "standard" })}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -843,6 +872,7 @@ describe("TaskDetailModal", () => {
|
||||
|
||||
const { container } = render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ id: "FN-001", column: "triage", title: "Test", description: "Desc", executionMode: "fast" })}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -869,6 +899,7 @@ describe("TaskDetailModal", () => {
|
||||
|
||||
const { container } = render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ id: "FN-001", column: "triage", title: "Test", description: "Desc", executionMode: "fast" })}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -890,6 +921,7 @@ describe("TaskDetailModal", () => {
|
||||
it("renders normalized priority in detail metadata", async () => {
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ id: "FN-001", column: "triage", description: "Priority metadata", priority: undefined })}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -913,6 +945,7 @@ describe("TaskDetailModal", () => {
|
||||
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ id: "FN-001", column: "todo", priority: "high", executionMode: "standard" })}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -956,6 +989,7 @@ describe("TaskDetailModal", () => {
|
||||
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({
|
||||
id: "FN-001",
|
||||
column: "triage",
|
||||
@@ -995,6 +1029,7 @@ describe("TaskDetailModal", () => {
|
||||
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ id: "FN-001", column: "triage", description: "Priority metadata", priority: "high" })}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -1022,6 +1057,7 @@ describe("TaskDetailModal", () => {
|
||||
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ id: "FN-001", column: "triage", description: "Priority metadata", priority: "low" })}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -1054,6 +1090,7 @@ describe("TaskDetailModal", () => {
|
||||
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ id: "FN-001", column: "todo", executionMode: "standard" })}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -1085,6 +1122,7 @@ describe("TaskDetailModal", () => {
|
||||
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ id: "FN-001", column: "todo", executionMode: "fast" })}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -1113,6 +1151,7 @@ describe("TaskDetailModal", () => {
|
||||
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ id: "FN-001", column: "todo", executionMode: "standard" })}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -1143,6 +1182,7 @@ describe("TaskDetailModal", () => {
|
||||
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ id: "FN-001", column: "todo", executionMode: "standard" })}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -1165,6 +1205,7 @@ describe("TaskDetailModal", () => {
|
||||
it("renders no-commits-expected toggle after plan and before attachments", () => {
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({
|
||||
id: "FN-001",
|
||||
column: "todo",
|
||||
@@ -1197,6 +1238,7 @@ describe("TaskDetailModal", () => {
|
||||
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ id: "FN-001", column: "todo", noCommitsExpected: false })}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -1217,6 +1259,7 @@ describe("TaskDetailModal", () => {
|
||||
it("pre-populates form with existing task values", () => {
|
||||
const { container } = render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ id: "FN-001", column: "todo", title: "My Task", description: "My Description" })}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -1243,6 +1286,7 @@ describe("TaskDetailModal", () => {
|
||||
|
||||
const { container } = render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ id: "FN-001", column: "todo", branch: "feature/fn-3422", baseBranch: "develop" })}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -1275,6 +1319,7 @@ describe("TaskDetailModal", () => {
|
||||
|
||||
const { container } = render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ id: "FN-001", column: "todo", branch: "feature/fn-3422", baseBranch: "develop" })}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -1301,6 +1346,7 @@ describe("TaskDetailModal", () => {
|
||||
|
||||
const { container } = render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ id: "FN-001", column: "todo", branch: "feature/fn-3422", baseBranch: "main" })}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -1345,6 +1391,7 @@ describe("TaskDetailModal", () => {
|
||||
|
||||
const { container } = render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={initialTask}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -1404,6 +1451,7 @@ describe("TaskDetailModal", () => {
|
||||
|
||||
return (
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={task}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -1462,6 +1510,7 @@ describe("TaskDetailModal", () => {
|
||||
it("renders Save and Cancel in the modal footer, not inside the edit form body", () => {
|
||||
const { container } = render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ id: "FN-001", column: "triage", title: "Test task" })}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -1496,6 +1545,7 @@ describe("TaskDetailModal", () => {
|
||||
it("renders keyboard hint in the modal footer when editing", () => {
|
||||
const { container } = render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ id: "FN-001", column: "triage", title: "Test task" })}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -1520,6 +1570,7 @@ describe("TaskDetailModal", () => {
|
||||
it("shows normal modal actions (not edit actions) when not editing", () => {
|
||||
const { container } = render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ id: "FN-001", column: "todo", title: "Test task" })}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -1556,6 +1607,7 @@ describe("TaskDetailModal", () => {
|
||||
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask()}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -1589,6 +1641,7 @@ describe("TaskDetailModal", () => {
|
||||
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask()}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -1618,6 +1671,7 @@ describe("TaskDetailModal", () => {
|
||||
it("shows Assign Agent button when task has no assigned agent", () => {
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ assignedAgentId: undefined })}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -1647,6 +1701,7 @@ describe("TaskDetailModal", () => {
|
||||
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ assignedAgentId: "agent-002" })}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -1680,6 +1735,7 @@ describe("TaskDetailModal", () => {
|
||||
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ assignedAgentId: undefined })}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -1715,6 +1771,7 @@ describe("TaskDetailModal", () => {
|
||||
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ assignedAgentId: "agent-005" })}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -1768,6 +1825,7 @@ describe("TaskDetailModal", () => {
|
||||
|
||||
const { container } = render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={task}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -1813,6 +1871,7 @@ describe("TaskDetailModal", () => {
|
||||
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={task}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -1847,6 +1906,7 @@ describe("TaskDetailModal", () => {
|
||||
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={detail}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -1886,6 +1946,7 @@ describe("TaskDetailModal", () => {
|
||||
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={task}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -1960,6 +2021,7 @@ describe("TaskDetailModal", () => {
|
||||
|
||||
const { container } = render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={task}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -2034,6 +2096,7 @@ describe("TaskDetailModal", () => {
|
||||
|
||||
const { container } = render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={strippedTask}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -2083,6 +2146,7 @@ describe("TaskDetailModal", () => {
|
||||
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={task}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -2122,6 +2186,7 @@ describe("TaskDetailModal", () => {
|
||||
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask()}
|
||||
onClose={noop}
|
||||
onOpenDetail={noop}
|
||||
@@ -2153,6 +2218,7 @@ describe("TaskDetailModal", () => {
|
||||
|
||||
const { container } = render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask()}
|
||||
onClose={noop}
|
||||
onOpenDetail={noop}
|
||||
@@ -2181,6 +2247,7 @@ describe("TaskDetailModal", () => {
|
||||
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask()}
|
||||
onClose={noop}
|
||||
onOpenDetail={noop}
|
||||
@@ -2208,6 +2275,7 @@ describe("TaskDetailModal", () => {
|
||||
it("renders after the prompt/spec section in read mode", () => {
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({
|
||||
id: "FN-001",
|
||||
column: "todo",
|
||||
@@ -2236,6 +2304,7 @@ describe("TaskDetailModal", () => {
|
||||
it("renders linked issue as link when url exists", async () => {
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({
|
||||
githubTracking: {
|
||||
enabled: true,
|
||||
@@ -2295,6 +2364,7 @@ describe("TaskDetailModal", () => {
|
||||
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={optimisticTask}
|
||||
onClose={noop}
|
||||
onOpenDetail={noopOpenDetail}
|
||||
@@ -2319,6 +2389,7 @@ describe("TaskDetailModal", () => {
|
||||
it("shows section when tracking is disabled and task is in an eligible column", () => {
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ column: "todo", githubTracking: { enabled: false } })}
|
||||
onClose={noop}
|
||||
onOpenDetail={noopOpenDetail}
|
||||
@@ -2351,6 +2422,7 @@ describe("TaskDetailModal", () => {
|
||||
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={optimisticTask}
|
||||
onClose={noop}
|
||||
onOpenDetail={noopOpenDetail}
|
||||
@@ -2390,6 +2462,7 @@ describe("TaskDetailModal", () => {
|
||||
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({
|
||||
id: "FN-001",
|
||||
column: "todo",
|
||||
@@ -2432,6 +2505,7 @@ describe("TaskDetailModal", () => {
|
||||
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({
|
||||
id: "FN-001",
|
||||
column: "todo",
|
||||
@@ -2476,6 +2550,7 @@ describe("TaskDetailModal", () => {
|
||||
it("hides the inline enable button when tracking is already enabled", () => {
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ column: "todo", githubTracking: { enabled: true } })}
|
||||
onClose={noop}
|
||||
onOpenDetail={noopOpenDetail}
|
||||
@@ -2493,6 +2568,7 @@ describe("TaskDetailModal", () => {
|
||||
it("hides the inline enable button when an issue is already linked", () => {
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({
|
||||
column: "todo",
|
||||
githubTracking: {
|
||||
@@ -2546,6 +2622,7 @@ describe("TaskDetailModal", () => {
|
||||
it("hides section when tracking is disabled and task is not in an eligible column", () => {
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ column: "done", githubTracking: { enabled: false } })}
|
||||
onClose={noop}
|
||||
onOpenDetail={noopOpenDetail}
|
||||
@@ -2582,6 +2659,7 @@ describe("TaskDetailModal", () => {
|
||||
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ id: "FN-001", column: "done", githubTracking: { enabled: true } })}
|
||||
onClose={noop}
|
||||
onOpenDetail={noopOpenDetail}
|
||||
@@ -2611,6 +2689,7 @@ describe("TaskDetailModal", () => {
|
||||
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({
|
||||
id: "FN-001",
|
||||
column: "todo",
|
||||
@@ -2654,6 +2733,7 @@ describe("TaskDetailModal", () => {
|
||||
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({
|
||||
id: "FN-001",
|
||||
column: "in-progress",
|
||||
@@ -2713,6 +2793,7 @@ describe("TaskDetailModal", () => {
|
||||
|
||||
return (
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={taskState}
|
||||
onClose={noop}
|
||||
onOpenDetail={noopOpenDetail}
|
||||
@@ -2759,6 +2840,7 @@ describe("TaskDetailModal", () => {
|
||||
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ id: "FN-001", column: "todo", githubTracking: { enabled: true, repoOverride: "runfusion/fusion" } })}
|
||||
onClose={noop}
|
||||
onOpenDetail={noopOpenDetail}
|
||||
@@ -2794,6 +2876,7 @@ describe("TaskDetailModal", () => {
|
||||
mockConfirm.mockResolvedValueOnce(false);
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({
|
||||
id: "FN-001",
|
||||
column: "todo",
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
/*
|
||||
FNXC:TaskDetailTabs 2026-06-17-08:20:
|
||||
FN-6532 made Chat the default TaskDetailModal tab. Tests that assert Definition-only sections must opt into `initialTab="definition"` so they verify the intended surface instead of the Chat landing state.
|
||||
*/
|
||||
import { describe, it, expect, vi } from "vitest";
|
||||
import { render, screen, fireEvent, act, waitFor } from "@testing-library/react";
|
||||
import userEvent from "@testing-library/user-event";
|
||||
@@ -47,6 +51,7 @@ describe("TaskDetailModal", () => {
|
||||
|
||||
return render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ prompt: "# Hello\n\nContent" })}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -81,6 +86,7 @@ describe("TaskDetailModal", () => {
|
||||
|
||||
return render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ prompt: "# Hello\n\nContent", ...taskOverrides })}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -220,6 +226,7 @@ describe("TaskDetailModal", () => {
|
||||
|
||||
const { container } = render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ prompt: "# Hello\n\nContent" })}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -288,6 +295,7 @@ describe("TaskDetailModal", () => {
|
||||
|
||||
const { container } = render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ prompt: "# Hello\n\nContent" })}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -333,6 +341,7 @@ describe("TaskDetailModal", () => {
|
||||
|
||||
const { container } = render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ prompt: "# Hello\n\nContent" })}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -408,6 +417,7 @@ describe("TaskDetailModal", () => {
|
||||
|
||||
const { container } = render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({
|
||||
prompt: "# Hello\n\nContent",
|
||||
planningModelProvider: "google",
|
||||
@@ -459,6 +469,7 @@ describe("TaskDetailModal", () => {
|
||||
|
||||
const { container } = render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ prompt: "# Hello\n\nContent" })}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -505,6 +516,7 @@ describe("TaskDetailModal", () => {
|
||||
|
||||
const { container } = render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ prompt: "# Hello\n\nContent" })}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -561,6 +573,7 @@ describe("TaskDetailModal", () => {
|
||||
|
||||
const { container } = render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ prompt: "# Hello\n\nContent", assignedAgentId: "agent-1", status: "executing", column: "in-progress" })}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -589,6 +602,7 @@ describe("TaskDetailModal", () => {
|
||||
it("renders step progress section when steps exist", () => {
|
||||
const { container } = render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({
|
||||
steps: [
|
||||
{ name: "Step 1", status: "done" },
|
||||
@@ -611,6 +625,7 @@ describe("TaskDetailModal", () => {
|
||||
it("shows '(no steps defined)' when steps array is empty", () => {
|
||||
const { container } = render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ steps: [] })}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -628,6 +643,7 @@ describe("TaskDetailModal", () => {
|
||||
it("renders correct number of segments matching step count", () => {
|
||||
const { container } = render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({
|
||||
steps: [
|
||||
{ name: "Step 1", status: "done" },
|
||||
@@ -651,6 +667,7 @@ describe("TaskDetailModal", () => {
|
||||
it("segments have correct status modifier classes", () => {
|
||||
const { container } = render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({
|
||||
steps: [
|
||||
{ name: "Step 1", status: "done" },
|
||||
@@ -678,6 +695,7 @@ describe("TaskDetailModal", () => {
|
||||
it("segments have correct inline background colors based on status", () => {
|
||||
const { container } = render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({
|
||||
steps: [
|
||||
{ name: "Step 1", status: "done" },
|
||||
@@ -707,6 +725,7 @@ describe("TaskDetailModal", () => {
|
||||
it("displays singular completion label for one-step tasks", () => {
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({
|
||||
steps: [{ name: "Step 1", status: "done" }],
|
||||
})}
|
||||
@@ -726,6 +745,7 @@ describe("TaskDetailModal", () => {
|
||||
it("displays correct completion count", () => {
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({
|
||||
steps: [
|
||||
{ name: "Step 1", status: "done" },
|
||||
@@ -750,6 +770,7 @@ describe("TaskDetailModal", () => {
|
||||
it("has data-tooltip attribute with step name and status on each segment", () => {
|
||||
const { container } = render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({
|
||||
steps: [
|
||||
{ name: "Initialize project", status: "done" },
|
||||
@@ -773,6 +794,7 @@ describe("TaskDetailModal", () => {
|
||||
it("step progress only renders in Definition tab, not in Agent Log subview", () => {
|
||||
const { container } = render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({
|
||||
prompt: "# Test",
|
||||
steps: [
|
||||
@@ -802,6 +824,7 @@ describe("TaskDetailModal", () => {
|
||||
it("step progress is hidden in Comments tab", () => {
|
||||
const { container } = render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({
|
||||
prompt: "# Test",
|
||||
steps: [
|
||||
@@ -834,6 +857,7 @@ describe("TaskDetailModal", () => {
|
||||
])("never shows a separate Commits tab for done tasks (%s) — changes are in the Changes tab", (_label, taskOverrides) => {
|
||||
const { container } = render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask(taskOverrides)}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -860,6 +884,7 @@ describe("TaskDetailModal", () => {
|
||||
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask()}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -893,6 +918,7 @@ describe("TaskDetailModal", () => {
|
||||
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask()}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -925,6 +951,7 @@ describe("TaskDetailModal", () => {
|
||||
])("Workflow tab is always rendered (%s)", (_label, taskOverrides) => {
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask(taskOverrides)}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -954,6 +981,7 @@ describe("TaskDetailModal", () => {
|
||||
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ enabledWorkflowSteps: ["WS-001"] })}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -982,6 +1010,7 @@ describe("TaskDetailModal", () => {
|
||||
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ enabledWorkflowSteps: ["WS-001"] })}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -1007,6 +1036,7 @@ describe("TaskDetailModal", () => {
|
||||
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ enabledWorkflowSteps: ["WS-001"] })}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -1034,6 +1064,7 @@ describe("TaskDetailModal", () => {
|
||||
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ enabledWorkflowSteps: ["WS-001"] })}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -1077,6 +1108,7 @@ describe("TaskDetailModal", () => {
|
||||
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ enabledWorkflowSteps: ["WS-001", "WS-002"] })}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -1100,6 +1132,7 @@ describe("TaskDetailModal", () => {
|
||||
it("hides Definition content when Workflow tab is active", async () => {
|
||||
const { container } = render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({
|
||||
enabledWorkflowSteps: ["WS-001"],
|
||||
prompt: "# Test prompt",
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
/*
|
||||
FNXC:TaskDetailTabs 2026-06-17-08:20:
|
||||
FN-6532 made Chat the default TaskDetailModal tab. Tests that assert Definition-only sections must opt into `initialTab="definition"` so they verify the intended surface instead of the Chat landing state.
|
||||
*/
|
||||
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
|
||||
import { render, screen, fireEvent, act, waitFor } from "@testing-library/react";
|
||||
import userEvent from "@testing-library/user-event";
|
||||
@@ -27,6 +31,7 @@ describe("TaskDetailModal", () => {
|
||||
render(
|
||||
<FileBrowserProvider openFile={openFile}>
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({
|
||||
column: "done",
|
||||
summary: "See `packages/dashboard/app/App.tsx:12` for context.",
|
||||
@@ -59,6 +64,7 @@ describe("TaskDetailModal", () => {
|
||||
] as const)("renders provenance text for %s", (sourceType, sourceAgentId, expectedText) => {
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ sourceType, sourceAgentId })}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -78,6 +84,7 @@ describe("TaskDetailModal", () => {
|
||||
it("renders parent task link for refinement provenance", async () => {
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ sourceType: "task_refine", sourceParentTaskId: "FN-001" })}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -100,6 +107,7 @@ describe("TaskDetailModal", () => {
|
||||
it("renders compact github issue link for github import provenance", () => {
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({
|
||||
sourceType: "github_import",
|
||||
sourceMetadata: { issueUrl: "https://github.com/owner/repo/issues/42" },
|
||||
@@ -128,6 +136,7 @@ describe("TaskDetailModal", () => {
|
||||
it("falls back to 'Open issue' label for unparseable github import URL", () => {
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({
|
||||
sourceType: "github_import",
|
||||
sourceMetadata: { issueUrl: "https://example.com/something" },
|
||||
@@ -151,6 +160,7 @@ describe("TaskDetailModal", () => {
|
||||
it("renders github import provenance with no issue URL as plain label", () => {
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({
|
||||
sourceType: "github_import",
|
||||
sourceMetadata: {},
|
||||
@@ -171,6 +181,7 @@ describe("TaskDetailModal", () => {
|
||||
it("renders finding label for research provenance", () => {
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({
|
||||
sourceType: "research",
|
||||
sourceMetadata: {
|
||||
@@ -195,6 +206,7 @@ describe("TaskDetailModal", () => {
|
||||
it("falls back to run id for research provenance context", () => {
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({
|
||||
sourceType: "research",
|
||||
sourceMetadata: { runId: "RR-456" },
|
||||
@@ -216,6 +228,7 @@ describe("TaskDetailModal", () => {
|
||||
it.each(["unknown", undefined] as const)("omits provenance for %s source", (sourceType) => {
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ sourceType })}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -232,6 +245,7 @@ describe("TaskDetailModal", () => {
|
||||
it("FN-3755 renders provenance before created-updated timestamps", () => {
|
||||
const { container } = render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ sourceType: "dashboard_ui" })}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -253,6 +267,7 @@ describe("TaskDetailModal", () => {
|
||||
it("keeps inline controls, provenance, and timestamps as direct detail-meta children", () => {
|
||||
const { container } = render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ sourceType: "task_refine", sourceParentTaskId: "FN-001" })}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -277,6 +292,7 @@ describe("TaskDetailModal", () => {
|
||||
it("keeps the optional PR link row in the same detail-meta row as provenance and timestamps", () => {
|
||||
const { container } = render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({
|
||||
sourceType: "dashboard_ui",
|
||||
prInfo: { number: 42, url: "https://github.com/owner/repo/pull/42" },
|
||||
@@ -316,6 +332,7 @@ describe("TaskDetailModal", () => {
|
||||
it("renders compact relative timestamps for recent tasks", () => {
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({
|
||||
sourceType: "dashboard_ui",
|
||||
createdAt: "2026-05-09T12:00:00.000Z",
|
||||
@@ -344,6 +361,7 @@ describe("TaskDetailModal", () => {
|
||||
it("renders short calendar date for older timestamps", () => {
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({
|
||||
sourceType: "dashboard_ui",
|
||||
createdAt: "2026-05-01T12:00:00.000Z",
|
||||
@@ -368,6 +386,7 @@ describe("TaskDetailModal", () => {
|
||||
it("shows active file scope overlap blocker in Dependencies section", () => {
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ id: "FN-T", column: "todo", overlapBlockedBy: "FN-OVER" })}
|
||||
tasks={[
|
||||
makeTask({ id: "FN-T", column: "todo", overlapBlockedBy: "FN-OVER" }),
|
||||
@@ -389,6 +408,7 @@ describe("TaskDetailModal", () => {
|
||||
it("renders clear overlap blocker button only when overlapBlockedBy is present", () => {
|
||||
const { rerender } = render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ id: "FN-T", column: "todo", overlapBlockedBy: "FN-OVER" })}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -403,6 +423,7 @@ describe("TaskDetailModal", () => {
|
||||
|
||||
rerender(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ id: "FN-T", column: "todo", overlapBlockedBy: undefined })}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -423,6 +444,7 @@ describe("TaskDetailModal", () => {
|
||||
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ id: "FN-T", column: "todo", overlapBlockedBy: "FN-OVER", status: "queued" })}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -451,6 +473,7 @@ describe("TaskDetailModal", () => {
|
||||
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ id: "FN-T", column: "todo", overlapBlockedBy: "FN-OVER", status: "planning" })}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -478,6 +501,7 @@ describe("TaskDetailModal", () => {
|
||||
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ id: "FN-T", column: "todo", overlapBlockedBy: "FN-OVER", status: "queued" })}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -499,6 +523,7 @@ describe("TaskDetailModal", () => {
|
||||
it("shows overlap blockedBy summary in Blocking section", () => {
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ id: "FN-B", column: "in-progress" })}
|
||||
tasks={[
|
||||
makeTask({ id: "FN-B", column: "in-progress" }),
|
||||
@@ -520,6 +545,7 @@ describe("TaskDetailModal", () => {
|
||||
it("renders modal wrapper structure and default close control", () => {
|
||||
const { container } = render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask()}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -539,6 +565,7 @@ describe("TaskDetailModal", () => {
|
||||
it("renders mobile back control variant when requested", () => {
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask()}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -597,6 +624,7 @@ describe("TaskDetailModal", () => {
|
||||
it("renders markdown-body without detail-prompt class when prompt exists", () => {
|
||||
const { container } = render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ prompt: "# Hello\n\nSome **bold** text" })}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -615,6 +643,7 @@ describe("TaskDetailModal", () => {
|
||||
it("strips the leading heading from prompt and renders remaining markdown", () => {
|
||||
const { container } = render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ prompt: "# Hello\n\nSome **bold** text" })}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -633,6 +662,7 @@ describe("TaskDetailModal", () => {
|
||||
it("renders (no prompt) with detail-prompt class when prompt is absent", () => {
|
||||
const { container } = render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ prompt: undefined })}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -652,6 +682,7 @@ describe("TaskDetailModal", () => {
|
||||
it("does not render a PROMPT.md heading", () => {
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ prompt: "# Some prompt content" })}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -668,6 +699,7 @@ describe("TaskDetailModal", () => {
|
||||
it("renders Review and Comments tabs", () => {
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask()}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -685,6 +717,7 @@ describe("TaskDetailModal", () => {
|
||||
it("shows non-PR review shell message in Review tab", async () => {
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ reviewState: { source: "reviewer-agent", items: [], addressing: [] } })}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -733,6 +766,7 @@ describe("TaskDetailModal", () => {
|
||||
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ reviewState: { source: "pull-request", summary: { reviewDecision: "REVIEW_REQUIRED", reviewers: [], blockingReasons: [], checks: [] }, items: [], addressing: [] } })}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -771,6 +805,7 @@ describe("TaskDetailModal", () => {
|
||||
});
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ reviewState: { source: "pull-request", summary: { reviewDecision: "CHANGES_REQUESTED", reviewers: [{ login: "octocat", state: "CHANGES_REQUESTED" }], blockingReasons: ["changes requested review is active"], checks: [] }, items: [], addressing: [] } })}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -790,6 +825,7 @@ describe("TaskDetailModal", () => {
|
||||
it("keeps inline priority and execution controls aligned with shared sizing and gap", () => {
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ column: "todo", priority: "high", executionMode: "fast" })}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -818,6 +854,7 @@ describe("TaskDetailModal", () => {
|
||||
it("renders standard mode as an unpressed toggle", () => {
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ column: "triage", executionMode: "standard" })}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -837,6 +874,7 @@ describe("TaskDetailModal", () => {
|
||||
it("renders fast mode as a pressed toggle", () => {
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ column: "todo", executionMode: "fast" })}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -870,6 +908,7 @@ describe("TaskDetailModal", () => {
|
||||
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({
|
||||
attachments: [
|
||||
{
|
||||
@@ -904,6 +943,7 @@ describe("TaskDetailModal", () => {
|
||||
it("leaves attachment href/src URLs unchanged when no daemon token is present", () => {
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({
|
||||
attachments: [
|
||||
{
|
||||
@@ -934,6 +974,7 @@ describe("TaskDetailModal", () => {
|
||||
it("renders Retry button when task status is 'failed' (in Actions dropdown)", () => {
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ status: "failed" })}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -955,6 +996,7 @@ describe("TaskDetailModal", () => {
|
||||
it("does NOT render Retry button when task status is not 'failed'", () => {
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ status: "executing" })}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -975,6 +1017,7 @@ describe("TaskDetailModal", () => {
|
||||
it("does NOT render Retry button when onRetryTask is not provided", () => {
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ status: "failed" })}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -992,6 +1035,7 @@ describe("TaskDetailModal", () => {
|
||||
it("shows exactly one Retry button when task is in-review AND failed (in Actions dropdown)", () => {
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ column: "in-review", status: "failed" })}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -1014,6 +1058,7 @@ describe("TaskDetailModal", () => {
|
||||
it("shows exactly one Retry button when task is in-review AND stuck-killed (in Actions dropdown)", () => {
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ column: "in-review", status: "stuck-killed" })}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -1036,6 +1081,7 @@ describe("TaskDetailModal", () => {
|
||||
it("shows Retry for a stranded planning triage task", () => {
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ column: "triage", status: "planning", stuckKillCount: 6 })}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -1060,6 +1106,7 @@ describe("TaskDetailModal", () => {
|
||||
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ column: "in-review", status: "failed" })}
|
||||
onClose={onClose}
|
||||
onMoveTask={noopMove}
|
||||
@@ -1095,6 +1142,7 @@ describe("TaskDetailModal", () => {
|
||||
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ column: "in-review", status: "failed" })}
|
||||
onClose={onClose}
|
||||
onMoveTask={noopMove}
|
||||
@@ -1134,6 +1182,7 @@ describe("TaskDetailModal", () => {
|
||||
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ column: "in-review", status: "failed" })}
|
||||
onClose={onClose}
|
||||
onMoveTask={noopMove}
|
||||
@@ -1167,6 +1216,7 @@ describe("TaskDetailModal", () => {
|
||||
it("shows in-review split button with primary action and secondary move option", () => {
|
||||
const { container } = render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ column: "in-review" })}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -1194,6 +1244,7 @@ describe("TaskDetailModal", () => {
|
||||
it("in-review failed task shows both Retry action and secondary move option", async () => {
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ column: "in-review", status: "failed" })}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -1223,6 +1274,7 @@ describe("TaskDetailModal", () => {
|
||||
it("split-button renders with chevron when multiple transitions exist", async () => {
|
||||
const { container } = render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ column: "in-progress" })}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -1258,6 +1310,7 @@ describe("TaskDetailModal", () => {
|
||||
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ column: "in-progress" })}
|
||||
onClose={noop}
|
||||
onMoveTask={onMoveTask}
|
||||
@@ -1279,6 +1332,7 @@ describe("TaskDetailModal", () => {
|
||||
it("chevron dropdown includes only secondary transitions", async () => {
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ column: "in-progress" })}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -1306,6 +1360,7 @@ describe("TaskDetailModal", () => {
|
||||
it("shows description exactly once for a task without title", () => {
|
||||
const { container } = render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({
|
||||
title: undefined,
|
||||
description: "Fix the login bug",
|
||||
@@ -1335,6 +1390,7 @@ describe("TaskDetailModal", () => {
|
||||
it("shows the title in <h2> when task.title is set", () => {
|
||||
const { container } = render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({
|
||||
title: "Implement dark mode",
|
||||
description: "Add dark mode toggle to the settings page",
|
||||
@@ -1365,6 +1421,7 @@ describe("TaskDetailModal", () => {
|
||||
|
||||
const renderDetail = (taskOverrides: Parameters<typeof makeTask>[0] = {}) => render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask(taskOverrides)}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -1519,6 +1576,7 @@ describe("TaskDetailModal", () => {
|
||||
const triageDescription = "H".repeat(250);
|
||||
const { container, rerender } = render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({
|
||||
id: "FN-TODO",
|
||||
column: "todo",
|
||||
@@ -1539,6 +1597,7 @@ describe("TaskDetailModal", () => {
|
||||
|
||||
rerender(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({
|
||||
id: "FN-TRIAGE",
|
||||
column: "triage",
|
||||
@@ -1627,6 +1686,7 @@ describe("TaskDetailModal", () => {
|
||||
// With title
|
||||
const { container: withTitle } = render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ title: "Some title" })}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -1641,6 +1701,7 @@ describe("TaskDetailModal", () => {
|
||||
// Without title
|
||||
const { container: withoutTitle } = render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ title: undefined, description: "A description" })}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -1688,6 +1749,7 @@ describe("TaskDetailModal", () => {
|
||||
|
||||
const { container } = render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={task}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -1733,6 +1795,7 @@ describe("TaskDetailModal", () => {
|
||||
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={task}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -1767,6 +1830,7 @@ describe("TaskDetailModal", () => {
|
||||
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={detail}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -1806,6 +1870,7 @@ describe("TaskDetailModal", () => {
|
||||
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={task}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -1881,6 +1946,7 @@ describe("TaskDetailModal", () => {
|
||||
|
||||
const { container } = render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={task}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -1955,6 +2021,7 @@ describe("TaskDetailModal", () => {
|
||||
|
||||
const { container } = render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={strippedTask}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -2004,6 +2071,7 @@ describe("TaskDetailModal", () => {
|
||||
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={task}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -2036,6 +2104,7 @@ describe("TaskDetailModal", () => {
|
||||
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ sourceMetadata: { nearDuplicateOf: "FN-1234" } })}
|
||||
tasks={[makeTask({ id: "FN-1234" })]}
|
||||
onClose={noop}
|
||||
@@ -2058,6 +2127,7 @@ describe("TaskDetailModal", () => {
|
||||
it("hides near-duplicate banner once dismissed", () => {
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ sourceMetadata: { nearDuplicateOf: "FN-1234", nearDuplicateDismissed: true } })}
|
||||
tasks={[makeTask({ id: "FN-1234" })]}
|
||||
onClose={noop}
|
||||
@@ -2079,6 +2149,7 @@ describe("TaskDetailModal", () => {
|
||||
])("hides near-duplicate decision banner when canonical is %s", (_label, canonical) => {
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ sourceMetadata: { nearDuplicateOf: "FN-1234" } })}
|
||||
tasks={canonical ? [canonical] : []}
|
||||
onClose={noop}
|
||||
@@ -2101,6 +2172,7 @@ describe("TaskDetailModal", () => {
|
||||
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ sourceMetadata: { nearDuplicateOf: "FN-1234" } })}
|
||||
tasks={[makeTask({ id: "FN-1234" })]}
|
||||
onClose={noop}
|
||||
@@ -2155,6 +2227,7 @@ describe("TaskDetailModal", () => {
|
||||
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={task}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
/*
|
||||
FNXC:TaskDetailTabs 2026-06-17-08:20:
|
||||
FN-6532 made Chat the default TaskDetailModal tab. Tests that assert Definition-only sections must opt into `initialTab="definition"` so they verify the intended surface instead of the Chat landing state.
|
||||
*/
|
||||
import { describe, it, expect, vi } from "vitest";
|
||||
import { render, screen, fireEvent, act, waitFor } from "@testing-library/react";
|
||||
import userEvent from "@testing-library/user-event";
|
||||
@@ -147,6 +151,7 @@ describe("TaskDetailModal", () => {
|
||||
it("modal-actions contains Delete and Pause buttons for non-done tasks (via Actions dropdown)", () => {
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ column: "in-progress" as Column })}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -175,6 +180,7 @@ describe("TaskDetailModal", () => {
|
||||
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({
|
||||
githubTracking: {
|
||||
enabled: true,
|
||||
@@ -212,6 +218,7 @@ describe("TaskDetailModal", () => {
|
||||
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
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}
|
||||
@@ -238,6 +245,7 @@ describe("TaskDetailModal", () => {
|
||||
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
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}
|
||||
@@ -262,6 +270,7 @@ describe("TaskDetailModal", () => {
|
||||
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask()}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -300,6 +309,7 @@ describe("TaskDetailModal", () => {
|
||||
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
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}
|
||||
@@ -361,6 +371,7 @@ describe("TaskDetailModal", () => {
|
||||
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask()}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -397,6 +408,7 @@ describe("TaskDetailModal", () => {
|
||||
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
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}
|
||||
@@ -433,6 +445,7 @@ describe("TaskDetailModal", () => {
|
||||
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask()}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -475,6 +488,7 @@ describe("TaskDetailModal", () => {
|
||||
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
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}
|
||||
@@ -504,6 +518,7 @@ describe("TaskDetailModal", () => {
|
||||
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ column: "todo" as any })}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -540,6 +555,7 @@ describe("TaskDetailModal", () => {
|
||||
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ column: "done" as any })}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -573,6 +589,7 @@ describe("TaskDetailModal", () => {
|
||||
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ column: "done" as any })}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -596,6 +613,7 @@ describe("TaskDetailModal", () => {
|
||||
it("in-review modal-actions contains Merge & Close and Back to In Progress buttons", () => {
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ column: "in-review" as Column })}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -625,6 +643,7 @@ describe("TaskDetailModal", () => {
|
||||
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ column: "in-review" as Column })}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -654,6 +673,7 @@ describe("TaskDetailModal", () => {
|
||||
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ column: "in-review" as Column })}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -700,6 +720,7 @@ describe("TaskDetailModal", () => {
|
||||
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({
|
||||
column: "in-review" as Column,
|
||||
prInfo: {
|
||||
@@ -749,6 +770,7 @@ describe("TaskDetailModal", () => {
|
||||
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({
|
||||
column: "in-review" as Column,
|
||||
prInfo: {
|
||||
@@ -795,6 +817,7 @@ describe("TaskDetailModal", () => {
|
||||
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({
|
||||
column: "in-review" as Column,
|
||||
prInfo: {
|
||||
@@ -823,6 +846,7 @@ describe("TaskDetailModal", () => {
|
||||
it("shows linked PR number in detail metadata for in-review tasks", () => {
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ column: "in-review" as Column, prInfo: {
|
||||
url: "https://github.com/owner/repo/pull/42",
|
||||
number: 42,
|
||||
@@ -847,6 +871,7 @@ describe("TaskDetailModal", () => {
|
||||
it("shows linked PR number in merge details for done tasks", () => {
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({
|
||||
column: "done" as Column,
|
||||
prInfo: {
|
||||
@@ -877,6 +902,7 @@ describe("TaskDetailModal", () => {
|
||||
it("shows PR automation waiting label instead of Merge & Close when awaiting PR checks", () => {
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ column: "in-review" as Column, status: "awaiting-pr-checks", prInfo: {
|
||||
url: "https://github.com/owner/repo/pull/42",
|
||||
number: 42,
|
||||
@@ -903,6 +929,7 @@ describe("TaskDetailModal", () => {
|
||||
it("shows Creating PR label while PR-first automation is creating a PR", () => {
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ column: "in-review" as Column, status: "creating-pr" })}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -930,6 +957,7 @@ describe("TaskDetailModal", () => {
|
||||
function renderWithSearch(taskOverrides: Partial<TaskDetail> = {}) {
|
||||
return render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask(taskOverrides)}
|
||||
tasks={searchTasks}
|
||||
onClose={noop}
|
||||
@@ -1024,6 +1052,7 @@ describe("TaskDetailModal", () => {
|
||||
|
||||
const { container } = render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ dependencies: ["FN-001", "FN-002"] })}
|
||||
tasks={allTasks}
|
||||
onClose={noop}
|
||||
@@ -1058,6 +1087,7 @@ describe("TaskDetailModal", () => {
|
||||
|
||||
const { container } = render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ dependencies: ["FN-001"] })}
|
||||
tasks={allTasks}
|
||||
onClose={noop}
|
||||
@@ -1077,6 +1107,7 @@ describe("TaskDetailModal", () => {
|
||||
it("renders dependency ID as label when no title or description available", () => {
|
||||
const { container } = render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ dependencies: ["FN-001"] })}
|
||||
// No tasks prop - dependency not found
|
||||
onClose={noop}
|
||||
@@ -1103,6 +1134,7 @@ describe("TaskDetailModal", () => {
|
||||
|
||||
const { container } = render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ dependencies: ["FN-001"] })}
|
||||
tasks={allTasks}
|
||||
onClose={noop}
|
||||
@@ -1129,6 +1161,7 @@ describe("TaskDetailModal", () => {
|
||||
|
||||
const { container } = render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ dependencies: ["FN-001"] })}
|
||||
tasks={allTasks}
|
||||
onClose={noop}
|
||||
@@ -1158,6 +1191,7 @@ describe("TaskDetailModal", () => {
|
||||
|
||||
const { container } = render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ dependencies: ["FN-001"] })}
|
||||
onOpenDetail={onOpenDetail}
|
||||
onClose={noop}
|
||||
@@ -1186,6 +1220,7 @@ describe("TaskDetailModal", () => {
|
||||
|
||||
const { container } = render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ dependencies: ["FN-001"] })}
|
||||
onOpenDetail={onOpenDetail}
|
||||
onClose={noop}
|
||||
@@ -1214,6 +1249,7 @@ describe("TaskDetailModal", () => {
|
||||
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ dependencies: ["FN-001"] })}
|
||||
onOpenDetail={onOpenDetail}
|
||||
onClose={noop}
|
||||
@@ -1246,6 +1282,7 @@ describe("TaskDetailModal", () => {
|
||||
|
||||
const { container } = render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={tasks[0]}
|
||||
tasks={tasks}
|
||||
onOpenDetail={noopOpenDetail}
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
/*
|
||||
FNXC:TaskDetailTabs 2026-06-17-08:20:
|
||||
FN-6532 made Chat the default TaskDetailModal tab. Tests that assert Definition-only sections must opt into `initialTab="definition"` so they verify the intended surface instead of the Chat landing state.
|
||||
*/
|
||||
import { describe, it, expect, vi } from "vitest";
|
||||
import { render, screen, waitFor } from "@testing-library/react";
|
||||
import type { ComponentProps } from "react";
|
||||
@@ -34,6 +38,7 @@ function renderSummarizeTitleModal(overrides: Parameters<typeof makeTask>[0] = {
|
||||
|
||||
const result = render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={task}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -169,6 +174,7 @@ describe("TaskDetailModal GitHub tracking CTA", () => {
|
||||
const user = userEvent.setup();
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({
|
||||
githubTracking: { enabled: true },
|
||||
title: "",
|
||||
@@ -194,6 +200,7 @@ describe("TaskDetailModal GitHub tracking CTA", () => {
|
||||
const user = userEvent.setup();
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({
|
||||
githubTracking: { enabled: true },
|
||||
title: "Real title",
|
||||
@@ -217,6 +224,7 @@ describe("TaskDetailModal GitHub tracking CTA", () => {
|
||||
const user = userEvent.setup();
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({
|
||||
githubTracking: { enabled: true },
|
||||
title: "",
|
||||
@@ -281,6 +289,7 @@ describe("TaskDetailModal Logs activity loading", () => {
|
||||
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeSlimTask() as any}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -418,6 +427,7 @@ describe("TaskDetailModal Logs agent loading", () => {
|
||||
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ prompt: "# Loaded" })}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -442,6 +452,7 @@ describe("TaskDetailModal branch group surfacing", () => {
|
||||
it("renders branch group card when task has group context", () => {
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ branchContext: { groupId: "BG-1", source: "planning", assignmentMode: "shared" } })}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
@@ -466,6 +477,7 @@ describe("TaskDetailModal delete affordance", () => {
|
||||
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({ column: "done" })}
|
||||
onClose={onClose}
|
||||
onMoveTask={noopMove}
|
||||
@@ -494,6 +506,7 @@ describe("TaskDetailModal in-review stall diagnostics", () => {
|
||||
const user = userEvent.setup();
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({
|
||||
column: "in-review",
|
||||
inReviewStall: {
|
||||
@@ -531,6 +544,7 @@ describe("TaskDetailModal in-review stall diagnostics", () => {
|
||||
const user = userEvent.setup();
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({
|
||||
column: "in-review",
|
||||
mergeRetries: 3,
|
||||
@@ -557,6 +571,7 @@ describe("TaskDetailModal in-review stall diagnostics", () => {
|
||||
const user = userEvent.setup();
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({
|
||||
column: "in-review",
|
||||
inReviewStall: {
|
||||
@@ -583,6 +598,7 @@ describe("TaskDetailModal in-review stall diagnostics", () => {
|
||||
it("FN-4570: hides merge-blocker diagnostic while task is actively merging", () => {
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={makeTask({
|
||||
column: "in-review",
|
||||
status: "merging-fix",
|
||||
@@ -631,6 +647,7 @@ describe("TaskDetailModal in-review stall diagnostics", () => {
|
||||
])("does not render diagnostic row for $label", ({ task }) => {
|
||||
render(
|
||||
<TaskDetailModal
|
||||
initialTab="definition"
|
||||
task={task}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
|
||||
Reference in New Issue
Block a user