feat(KB-651): add changed files diff viewer for tasks
- Add backend API endpoint to get changed files and diffs for a task worktree - Add useChangedFiles hook for fetching and managing diff data - Create ChangedFilesModal component with file list and diff viewer - Integrate modal into TaskCard with click handler to view changes - Add frontend API integration and type definitions - Include unit tests for hook and modal components - Add changeset for the new feature - Remove deprecated mission-related test files
This commit is contained in:
@@ -0,0 +1,102 @@
|
||||
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
|
||||
import { render, screen, fireEvent } from "@testing-library/react";
|
||||
import { ChangedFilesModal } from "../ChangedFilesModal";
|
||||
import * as changedFilesHook from "../../hooks/useChangedFiles";
|
||||
|
||||
vi.mock("../../hooks/useChangedFiles");
|
||||
|
||||
const mockUseChangedFiles = vi.mocked(changedFilesHook.useChangedFiles);
|
||||
|
||||
describe("ChangedFilesModal", () => {
|
||||
const mockOnClose = vi.fn();
|
||||
const mockSetSelectedFile = vi.fn();
|
||||
|
||||
beforeEach(() => {
|
||||
vi.resetAllMocks();
|
||||
mockUseChangedFiles.mockReturnValue({
|
||||
files: [
|
||||
{ path: "src/a.ts", status: "modified", diff: "diff --git a/src/a.ts b/src/a.ts\n--- a/src/a.ts\n+++ b/src/a.ts\n+hello" },
|
||||
{ path: "src/b.ts", status: "added", diff: "diff --git a/src/b.ts b/src/b.ts" },
|
||||
],
|
||||
loading: false,
|
||||
error: null,
|
||||
selectedFile: { path: "src/a.ts", status: "modified", diff: "diff --git a/src/a.ts b/src/a.ts\n--- a/src/a.ts\n+++ b/src/a.ts\n+hello" },
|
||||
setSelectedFile: mockSetSelectedFile,
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
vi.restoreAllMocks();
|
||||
});
|
||||
|
||||
it("renders changed files and selected diff", () => {
|
||||
render(
|
||||
<ChangedFilesModal
|
||||
taskId="KB-651"
|
||||
worktree="/repo/.worktrees/kb-651"
|
||||
column="in-progress"
|
||||
isOpen={true}
|
||||
onClose={mockOnClose}
|
||||
/>,
|
||||
);
|
||||
|
||||
expect(screen.getByText("Changed Files — KB-651")).toBeInTheDocument();
|
||||
expect(screen.getByText("src/a.ts")).toBeInTheDocument();
|
||||
expect(screen.getByLabelText("Diff for src/a.ts")).toBeInTheDocument();
|
||||
expect(screen.getByText(/\+hello/)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("allows selecting another file from the sidebar", () => {
|
||||
render(
|
||||
<ChangedFilesModal
|
||||
taskId="KB-651"
|
||||
worktree="/repo/.worktrees/kb-651"
|
||||
column="in-progress"
|
||||
isOpen={true}
|
||||
onClose={mockOnClose}
|
||||
/>,
|
||||
);
|
||||
|
||||
fireEvent.click(screen.getByRole("button", { name: /src\/b.ts/i }));
|
||||
|
||||
expect(mockSetSelectedFile).toHaveBeenCalledWith({ path: "src/b.ts", status: "added", diff: "diff --git a/src/b.ts b/src/b.ts" });
|
||||
});
|
||||
|
||||
it("shows an empty state when there are no changed files", () => {
|
||||
mockUseChangedFiles.mockReturnValue({
|
||||
files: [],
|
||||
loading: false,
|
||||
error: null,
|
||||
selectedFile: null,
|
||||
setSelectedFile: mockSetSelectedFile,
|
||||
});
|
||||
|
||||
render(
|
||||
<ChangedFilesModal
|
||||
taskId="KB-651"
|
||||
worktree="/repo/.worktrees/kb-651"
|
||||
column="in-progress"
|
||||
isOpen={true}
|
||||
onClose={mockOnClose}
|
||||
/>,
|
||||
);
|
||||
|
||||
expect(screen.getByText("No files changed")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("closes on Escape", () => {
|
||||
render(
|
||||
<ChangedFilesModal
|
||||
taskId="KB-651"
|
||||
worktree="/repo/.worktrees/kb-651"
|
||||
column="in-progress"
|
||||
isOpen={true}
|
||||
onClose={mockOnClose}
|
||||
/>,
|
||||
);
|
||||
|
||||
fireEvent.keyDown(document, { key: "Escape" });
|
||||
|
||||
expect(mockOnClose).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user