test(web): add shell and navigation coverage

This commit is contained in:
saravanakumardb1 2026-03-10 09:28:14 -07:00
parent 4da56d489d
commit 98144ab4ff
5 changed files with 77 additions and 3 deletions

View File

@ -58,7 +58,7 @@ Stack: Next.js 16 + React 19 + TypeScript
- [ ] Performance pass
- [ ] Accessibility pass
- [ ] Token validation pass
- [ ] Production build passes
- [x] Production build passes
- [ ] UX polish pass
# High-Collision Areas
@ -108,6 +108,13 @@ Stack: Next.js 16 + React 19 + TypeScript
- stronger focus-visible treatment for interactive controls
- clearer active-nav semantics via `aria-current`
- keyboard/accessibility guidance surfaced in navigation/settings
- Added the first web UI test harness and coverage for:
- shared `AppShell` skip-link/main landmark behavior
- shared `Sidebar` primary-nav and active-page semantics
- Verified `web/` with:
- `npm test`
- `npm run typecheck`
- `npm run build`
# Open Questions
@ -139,8 +146,6 @@ Stack: Next.js 16 + React 19 + TypeScript
- Extraction-backed task review flows
- Backend-backed agent activity timeline, approval queue, proposal diff review, and audit filtering
- Remaining dense/accessibility polish and performance hardening
- Remaining verification:
- run `npm test`
# Done When

View File

@ -0,0 +1,23 @@
import { render, screen } from "@testing-library/react";
import { describe, expect, it, vi } from "vitest";
import { AppShell } from "./AppShell";
vi.mock("@/components/Sidebar", () => ({
Sidebar: () => <div data-testid="sidebar">Sidebar</div>,
}));
describe("AppShell", () => {
it("renders skip link, page title, actions, and main content landmark", () => {
render(
<AppShell title="Search" description="Find notes" actions={<button type="button">Run</button>}>
<section>Results</section>
</AppShell>
);
expect(screen.getByRole("link", { name: "Skip to main content" })).toHaveAttribute("href", "#main-content");
expect(screen.getByRole("heading", { level: 1, name: "Search" })).toBeInTheDocument();
expect(screen.getByRole("button", { name: "Run" })).toBeInTheDocument();
expect(screen.getByRole("main")).toHaveAttribute("id", "main-content");
expect(screen.getByText("Results")).toBeInTheDocument();
});
});

View File

@ -0,0 +1,30 @@
import { render, screen } from "@testing-library/react";
import { describe, expect, it, vi } from "vitest";
import { Sidebar } from "./Sidebar";
const usePathnameMock = vi.fn();
vi.mock("next/navigation", () => ({
usePathname: () => usePathnameMock(),
}));
vi.mock("next/link", () => ({
default: ({ href, children, ...props }: React.ComponentProps<"a"> & { href: string }) => (
<a href={href} {...props}>
{children}
</a>
),
}));
describe("Sidebar", () => {
it("marks the active navigation item and exposes primary navigation landmarks", () => {
usePathnameMock.mockReturnValue("/search");
render(<Sidebar />);
expect(screen.getByLabelText("Primary")).toBeInTheDocument();
expect(screen.getByRole("navigation", { name: "Primary navigation" })).toBeInTheDocument();
expect(screen.getByRole("link", { name: "Search" })).toHaveAttribute("aria-current", "page");
expect(screen.getByText("Keyboard flow")).toBeInTheDocument();
});
});

View File

@ -0,0 +1 @@
import "@testing-library/jest-dom/vitest";

15
web/vitest.config.ts Normal file
View File

@ -0,0 +1,15 @@
import path from "node:path";
import { defineConfig } from "vitest/config";
export default defineConfig({
test: {
environment: "jsdom",
setupFiles: ["./src/test/setupTests.ts"],
globals: true,
},
resolve: {
alias: {
"@": path.resolve(__dirname, "./src"),
},
},
});