File size: 8,022 Bytes
fd2c364 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 | import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { describe, it, expect, vi, beforeEach } from "vitest";
import {
FileDiffViewer,
MAX_DIFF_EDITOR_HEIGHT_PX,
} from "#/components/features/diff-viewer/file-diff-viewer";
const MOCK_DIFF = { original: "old content", modified: "new content" };
const MOCK_MD_DIFF = {
original: "# Old Heading",
modified: "# New Heading\n\nSome **bold** text",
};
let mockDiff = MOCK_DIFF;
let mockIsSuccess = true;
let mockIsLoading = false;
vi.mock("#/hooks/query/use-unified-git-diff", () => ({
useUnifiedGitDiff: () => ({
data: mockDiff,
isLoading: mockIsLoading,
isSuccess: mockIsSuccess,
isRefetching: false,
}),
}));
vi.mock("@monaco-editor/react", () => ({
DiffEditor: (props: Record<string, unknown>) => (
<div data-testid="file-diff-viewer" data-original={props.original} data-modified={props.modified} />
),
Editor: (props: Record<string, unknown>) => (
<div data-testid="file-single-viewer" data-value={props.value} />
),
}));
vi.mock("#/components/features/markdown/markdown-renderer", () => ({
MarkdownRenderer: ({ content }: { content: string }) => (
<div data-testid="markdown-renderer">{content}</div>
),
}));
const expand = async (user: ReturnType<typeof userEvent.setup>) => {
await user.click(screen.getByTestId("collapse"));
};
describe("FileDiffViewer", () => {
beforeEach(() => {
mockDiff = MOCK_DIFF;
mockIsSuccess = true;
mockIsLoading = false;
});
it("caps opened editor panes at 600px", () => {
expect(MAX_DIFF_EDITOR_HEIGHT_PX).toBe(600);
});
it("keeps view mode controls reserved but inert while collapsed", () => {
render(<FileDiffViewer path="src/index.ts" type="M" />);
const viewModeGroup = screen.getByTestId("view-mode-diff").parentElement;
expect(viewModeGroup).toHaveClass("invisible");
expect(screen.getByTestId("view-mode-old")).toHaveAttribute(
"tabIndex",
"-1",
);
});
it("reveals view mode buttons when expanded", async () => {
const user = userEvent.setup();
render(<FileDiffViewer path="src/index.ts" type="M" />);
await expand(user);
const viewModeGroup = screen.getByTestId("view-mode-diff").parentElement;
expect(viewModeGroup).not.toHaveClass("invisible");
expect(screen.getByTestId("view-mode-old")).toBeInTheDocument();
expect(screen.getByTestId("view-mode-diff")).toBeInTheDocument();
expect(screen.getByTestId("view-mode-new")).toBeInTheDocument();
});
it("shows diff editor by default when expanded", async () => {
const user = userEvent.setup();
render(<FileDiffViewer path="src/index.ts" type="M" />);
await expand(user);
expect(screen.getByTestId("file-diff-viewer")).toBeInTheDocument();
expect(screen.queryByTestId("file-single-viewer")).not.toBeInTheDocument();
});
it("switches to single editor on 'new' mode", async () => {
const user = userEvent.setup();
render(<FileDiffViewer path="src/index.ts" type="M" />);
await expand(user);
await user.click(screen.getByTestId("view-mode-new"));
expect(screen.getByTestId("file-single-viewer")).toBeInTheDocument();
expect(screen.getByTestId("file-single-viewer")).toHaveAttribute("data-value", "new content");
expect(screen.queryByTestId("file-diff-viewer")).not.toBeInTheDocument();
});
it("switches to single editor on 'old' mode", async () => {
const user = userEvent.setup();
render(<FileDiffViewer path="src/index.ts" type="M" />);
await expand(user);
await user.click(screen.getByTestId("view-mode-old"));
expect(screen.getByTestId("file-single-viewer")).toBeInTheDocument();
expect(screen.getByTestId("file-single-viewer")).toHaveAttribute("data-value", "old content");
});
it("returns to diff editor when switching back to 'diff' mode", async () => {
const user = userEvent.setup();
render(<FileDiffViewer path="src/index.ts" type="M" />);
await expand(user);
await user.click(screen.getByTestId("view-mode-new"));
await user.click(screen.getByTestId("view-mode-diff"));
expect(screen.getByTestId("file-diff-viewer")).toBeInTheDocument();
expect(screen.queryByTestId("file-single-viewer")).not.toBeInTheDocument();
});
it("renders markdown preview for .md files in 'new' mode", async () => {
mockDiff = MOCK_MD_DIFF;
const user = userEvent.setup();
render(<FileDiffViewer path="README.md" type="M" />);
await expand(user);
await user.click(screen.getByTestId("view-mode-new"));
expect(screen.getByTestId("markdown-preview")).toBeInTheDocument();
expect(screen.getByTestId("markdown-renderer")).toHaveTextContent(/New Heading/);
expect(screen.getByTestId("markdown-renderer")).toHaveTextContent(/bold/);
expect(screen.queryByTestId("file-single-viewer")).not.toBeInTheDocument();
});
it("renders markdown preview for .md files in 'old' mode", async () => {
mockDiff = MOCK_MD_DIFF;
const user = userEvent.setup();
render(<FileDiffViewer path="README.md" type="M" />);
await expand(user);
await user.click(screen.getByTestId("view-mode-old"));
expect(screen.getByTestId("markdown-renderer")).toHaveTextContent(MOCK_MD_DIFF.original);
});
it("shows diff editor for .md files in 'diff' mode", async () => {
mockDiff = MOCK_MD_DIFF;
const user = userEvent.setup();
render(<FileDiffViewer path="README.md" type="M" />);
await expand(user);
expect(screen.getByTestId("file-diff-viewer")).toBeInTheDocument();
expect(screen.queryByTestId("markdown-preview")).not.toBeInTheDocument();
});
it("renders a 'file deleted' placeholder when expanded for a deleted file", async () => {
// Simulate the hook short-circuiting the API call for deleted files.
mockDiff = undefined as unknown as typeof MOCK_DIFF;
mockIsSuccess = false;
const user = userEvent.setup();
render(<FileDiffViewer path="src/removed.ts" type="D" />);
await expand(user);
expect(screen.getByTestId("file-deleted-message")).toBeInTheDocument();
expect(screen.queryByTestId("file-diff-viewer")).not.toBeInTheDocument();
expect(screen.queryByTestId("file-single-viewer")).not.toBeInTheDocument();
// View-mode toolbar should not render for deleted files since there is
// nothing to switch between.
expect(screen.queryByTestId("view-mode-old")).not.toBeInTheDocument();
expect(screen.queryByTestId("view-mode-diff")).not.toBeInTheDocument();
expect(screen.queryByTestId("view-mode-new")).not.toBeInTheDocument();
});
it("renders a deleted file's diff content in commit mode instead of the placeholder", async () => {
// Arrange — in per-commit mode both sides come from git objects, so a
// deleted file has real content to show (original vs empty).
mockDiff = { original: "old content", modified: "" };
const user = userEvent.setup();
render(
<FileDiffViewer path="src/removed.ts" type="D" commit={"a".repeat(40)} />,
);
// Act
await expand(user);
// Assert
expect(
screen.queryByTestId("file-deleted-message"),
).not.toBeInTheDocument();
expect(screen.getByTestId("file-diff-viewer")).toBeInTheDocument();
});
it("reflects the active view mode via aria-pressed on the toggle buttons", async () => {
const user = userEvent.setup();
render(<FileDiffViewer path="src/index.ts" type="M" />);
await expand(user);
expect(screen.getByTestId("view-mode-diff")).toHaveAttribute(
"aria-pressed",
"true",
);
expect(screen.getByTestId("view-mode-old")).toHaveAttribute(
"aria-pressed",
"false",
);
await user.click(screen.getByTestId("view-mode-old"));
expect(screen.getByTestId("view-mode-old")).toHaveAttribute(
"aria-pressed",
"true",
);
expect(screen.getByTestId("view-mode-diff")).toHaveAttribute(
"aria-pressed",
"false",
);
});
});
|