test: add comprehensive frontend tests for components, stores, and utils
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>
This commit is contained in:
104
tests/components/AppShell.test.tsx
Normal file
104
tests/components/AppShell.test.tsx
Normal file
@@ -0,0 +1,104 @@
|
||||
import { describe, it, expect, vi, beforeEach } from "vitest";
|
||||
import { render, screen, act } from "@testing-library/react";
|
||||
import userEvent from "@testing-library/user-event";
|
||||
import { AppShell } from "@/components/AppShell";
|
||||
import { useNavStore } from "@/stores/nav-store";
|
||||
import { useFocusStore } from "@/stores/focus-store";
|
||||
import { useCaptureStore } from "@/stores/capture-store";
|
||||
import { simulateEvent, resetMocks } from "../mocks/tauri-api";
|
||||
import { makeFocusItem } from "../helpers/fixtures";
|
||||
|
||||
describe("AppShell", () => {
|
||||
beforeEach(() => {
|
||||
useNavStore.setState({ activeView: "focus" });
|
||||
useFocusStore.setState({
|
||||
current: null,
|
||||
queue: [],
|
||||
isLoading: false,
|
||||
error: null,
|
||||
});
|
||||
useCaptureStore.setState({
|
||||
isOpen: false,
|
||||
isSubmitting: false,
|
||||
lastCapturedId: null,
|
||||
error: null,
|
||||
});
|
||||
resetMocks();
|
||||
});
|
||||
|
||||
it("renders navigation tabs", () => {
|
||||
render(<AppShell />);
|
||||
expect(screen.getByText("Focus")).toBeInTheDocument();
|
||||
expect(screen.getByText("Queue")).toBeInTheDocument();
|
||||
expect(screen.getByText("Inbox")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("shows Focus view by default", () => {
|
||||
render(<AppShell />);
|
||||
expect(screen.getByText(/all clear/i)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("switches to Queue view when Queue tab is clicked", async () => {
|
||||
const user = userEvent.setup();
|
||||
render(<AppShell />);
|
||||
|
||||
await user.click(screen.getByText("Queue"));
|
||||
expect(await screen.findByText(/no items/i)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("switches to Inbox placeholder", async () => {
|
||||
const user = userEvent.setup();
|
||||
render(<AppShell />);
|
||||
|
||||
await user.click(screen.getByText("Inbox"));
|
||||
expect(await screen.findByText(/coming in Phase 4b/i)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("shows queue count badge when items exist", () => {
|
||||
useFocusStore.setState({
|
||||
current: makeFocusItem({ id: "a" }),
|
||||
queue: [makeFocusItem({ id: "b" }), makeFocusItem({ id: "c" })],
|
||||
});
|
||||
|
||||
render(<AppShell />);
|
||||
expect(screen.getByText("3")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("opens quick capture overlay on global shortcut event", async () => {
|
||||
render(<AppShell />);
|
||||
|
||||
act(() => {
|
||||
simulateEvent("global-shortcut-triggered", "quick-capture");
|
||||
});
|
||||
|
||||
expect(useCaptureStore.getState().isOpen).toBe(true);
|
||||
expect(screen.getByPlaceholderText("Capture a thought...")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("clicking queue item sets focus and switches to focus view", async () => {
|
||||
const user = userEvent.setup();
|
||||
|
||||
useFocusStore.setState({
|
||||
current: makeFocusItem({ id: "current", title: "Current" }),
|
||||
queue: [
|
||||
makeFocusItem({
|
||||
id: "target",
|
||||
type: "issue",
|
||||
title: "Target item",
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
render(<AppShell />);
|
||||
|
||||
// Navigate to queue and wait for transition
|
||||
await user.click(screen.getByText("Queue"));
|
||||
const targetItem = await screen.findByText("Target item");
|
||||
// Click on the target item
|
||||
await user.click(targetItem);
|
||||
|
||||
// Should switch back to focus view with the target as current
|
||||
expect(useFocusStore.getState().current?.id).toBe("target");
|
||||
expect(useNavStore.getState().activeView).toBe("focus");
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user