Full test coverage for the frontend implementation using Vitest and Testing Library. Tests are organized by concern with shared fixtures. Component tests: - AppShell.test.tsx: Navigation tabs, view switching, batch mode overlay - FocusCard.test.tsx: Rendering, action buttons, keyboard shortcuts, empty state - QueueView.test.tsx: Item display, focus promotion, empty state - QueueItem.test.tsx: Type badges, click handling - QueueSummary.test.tsx: Count display by type - QuickCapture.test.tsx: Modal behavior, form submission, error states - BatchMode.test.tsx: Progress tracking, item advancement, completion - App.test.tsx: Updated for AppShell integration Store tests: - focus-store.test.ts: Item management, act(), setFocus(), reorderQueue() - nav-store.test.ts: View switching - capture-store.test.ts: Open/close, submission states - batch-store.test.ts: Batch lifecycle, status tracking, derived counts Library tests: - types.test.ts: Type guards, staleness computation - transform.test.ts: Lore data transformation, priority ordering - format.test.ts: IID formatting for MRs vs issues E2E tests (app.spec.ts): - Navigation flow - Focus card interactions - Queue management - Quick capture flow Test infrastructure: - fixtures.ts: makeFocusItem() factory - tauri-plugin-shell.ts: Mock for @tauri-apps/plugin-shell - Updated tauri-api.ts mock with new commands - vitest.config.ts: Path aliases, jsdom environment - playwright.config.ts: Removed webServer (run separately) - package.json: Added @tauri-apps/plugin-shell dependency Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
101 lines
3.3 KiB
TypeScript
101 lines
3.3 KiB
TypeScript
import { describe, it, expect, vi } from "vitest";
|
|
import { render, screen } from "@testing-library/react";
|
|
import userEvent from "@testing-library/user-event";
|
|
import { QueueItem } from "@/components/QueueItem";
|
|
import { makeFocusItem } from "../helpers/fixtures";
|
|
|
|
describe("QueueItem", () => {
|
|
it("renders the item title", () => {
|
|
render(<QueueItem item={makeFocusItem()} onClick={vi.fn()} />);
|
|
expect(
|
|
screen.getByText("Fix authentication token refresh logic")
|
|
).toBeInTheDocument();
|
|
});
|
|
|
|
it("renders the type badge", () => {
|
|
render(<QueueItem item={makeFocusItem()} onClick={vi.fn()} />);
|
|
expect(screen.getByText(/MR REVIEW/i)).toBeInTheDocument();
|
|
});
|
|
|
|
it("renders the IID with correct prefix for MRs", () => {
|
|
render(<QueueItem item={makeFocusItem()} onClick={vi.fn()} />);
|
|
expect(screen.getByText(/!847/)).toBeInTheDocument();
|
|
});
|
|
|
|
it("renders the IID with # prefix for issues", () => {
|
|
render(
|
|
<QueueItem
|
|
item={makeFocusItem({ type: "issue", iid: 42 })}
|
|
onClick={vi.fn()}
|
|
/>
|
|
);
|
|
expect(screen.getByText(/#42/)).toBeInTheDocument();
|
|
});
|
|
|
|
it("renders the project name", () => {
|
|
render(<QueueItem item={makeFocusItem()} onClick={vi.fn()} />);
|
|
expect(screen.getByText(/platform\/core/)).toBeInTheDocument();
|
|
});
|
|
|
|
it("calls onClick when clicked", async () => {
|
|
const onClick = vi.fn();
|
|
const user = userEvent.setup();
|
|
const item = makeFocusItem({ id: "test-click" });
|
|
|
|
render(<QueueItem item={item} onClick={onClick} />);
|
|
await user.click(screen.getByRole("button"));
|
|
|
|
expect(onClick).toHaveBeenCalledOnce();
|
|
expect(onClick).toHaveBeenCalledWith("test-click");
|
|
});
|
|
|
|
it("shows staleness color for fresh items", () => {
|
|
const freshItem = makeFocusItem({
|
|
updatedAt: new Date().toISOString(),
|
|
});
|
|
const { container } = render(
|
|
<QueueItem item={freshItem} onClick={vi.fn()} />
|
|
);
|
|
// Fresh items should have green indicator
|
|
expect(container.querySelector("[data-staleness='fresh']")).toBeTruthy();
|
|
});
|
|
|
|
it("shows staleness color for urgent items", () => {
|
|
const oldItem = makeFocusItem({
|
|
updatedAt: new Date(
|
|
Date.now() - 10 * 24 * 60 * 60 * 1000
|
|
).toISOString(),
|
|
});
|
|
const { container } = render(
|
|
<QueueItem item={oldItem} onClick={vi.fn()} />
|
|
);
|
|
expect(container.querySelector("[data-staleness='urgent']")).toBeTruthy();
|
|
});
|
|
|
|
it("shows requestedBy when present", () => {
|
|
render(
|
|
<QueueItem
|
|
item={makeFocusItem({ requestedBy: "alice" })}
|
|
onClick={vi.fn()}
|
|
/>
|
|
);
|
|
expect(screen.getByText(/@alice/)).toBeInTheDocument();
|
|
});
|
|
|
|
it("staleness indicator has accessible label for fresh items", () => {
|
|
const freshItem = makeFocusItem({
|
|
updatedAt: new Date().toISOString(),
|
|
});
|
|
render(<QueueItem item={freshItem} onClick={vi.fn()} />);
|
|
expect(screen.getByRole("img", { name: /updated recently/i })).toBeInTheDocument();
|
|
});
|
|
|
|
it("staleness indicator has accessible label for urgent items", () => {
|
|
const oldItem = makeFocusItem({
|
|
updatedAt: new Date(Date.now() - 10 * 24 * 60 * 60 * 1000).toISOString(),
|
|
});
|
|
render(<QueueItem item={oldItem} onClick={vi.fn()} />);
|
|
expect(screen.getByRole("img", { name: /needs attention/i })).toBeInTheDocument();
|
|
});
|
|
});
|