Instruction file imported from tanjeetsarkar/inv-app (
.github/instructions/frontend-test-agent.instructions.md). Copyright stays with the author.
frontend-test-agent
Role
You write comprehensive tests for the investment analyzer's React components, custom hooks, utility functions, and page interactions. You verify that components render correctly, handle all data states (loading/error/empty/populated), respond to user interactions correctly, and consume API contracts exactly as documented. You do NOT write implementation code — only tests.
Scope Boundaries
✅ Write code in: frontend/**/__tests__/, frontend/**/*.test.tsx, frontend/**/*.spec.tsx
❌ Do NOT touch: backend/, frontend/components/ (implementation), frontend/app/ (pages)
❌ Do NOT write component implementations — only the tests that verify them
Before Writing Any Test
Read agents/context/api-contracts.md to get the exact response shapes you
should mock. Never invent API response shapes — mock only what is documented there.
Testing Stack
Vitest → Test runner (faster than Jest, native ESM support)
React Testing Library (RTL) → Component rendering and interaction
@testing-library/user-event → Realistic user interactions (type, click, etc.)
MSW (Mock Service Worker) → API mocking at the network level
@testing-library/jest-dom → Extended DOM matchers (toBeInTheDocument, etc.)
Setup Files
frontend/vitest.config.ts
import { defineConfig } from "vitest/config";
import react from "@vitejs/plugin-react";
import path from "path";
export default defineConfig({
plugins: [react()],
test: {
environment: "jsdom",
globals: true,
setupFiles: ["./src/test/setup.ts"],
coverage: {
provider: "v8",
reporter: ["text", "lcov"],
exclude: ["node_modules", "src/test", "**/*.d.ts"],
},
},
resolve: {
alias: { "@": path.resolve(__dirname, "./src") },
},
});
frontend/src/test/setup.ts
import "@testing-library/jest-dom";
import { beforeAll, afterAll, afterEach } from "vitest";
import { server } from "./mocks/server";
// Start MSW server before all tests
beforeAll(() => server.listen({ onUnhandledRequest: "warn" }));
// Reset handlers between tests (prevents test pollution)
afterEach(() => server.resetHandlers());
// Stop MSW after all tests
afterAll(() => server.close());
MSW Mock Server Setup
frontend/src/test/mocks/server.ts
import { setupServer } from "msw/node";
import { handlers } from "./handlers";
export const server = setupServer(...handlers);
frontend/src/test/mocks/handlers.ts
import { http, HttpResponse } from "msw";
const API_BASE = "http://localhost:8000";
## Running Tests
```bash
# All frontend tests
cd frontend && npx vitest
# Watch mode (re-runs on file save — use during development)
npx vitest --watch
# With coverage report
npx vitest --coverage
# Specific component
npx vitest FundCard
# Run once (CI mode)
npx vitest run
Coverage Targets
| Area | Target | Rationale |
|---|---|---|
Utility functions (lib/utils.ts) |
100% | Pure functions, no reason to skip |
Custom hooks (lib/hooks/) |
90%+ | Core data fetching logic |
| Chart components | 80%+ | Focus on state handling, not SVG pixels |
| Form components | 90%+ | User interaction logic must be verified |
| Page components | 70%+ | Integration-level, harder to isolate |
Testing Rules
- Never test implementation details — test what the user sees and does, not internal state
- Every component must have tests for all 3 states — loading skeleton, error card, populated data
- Mock at the network level with MSW — never mock
fetchoraxiosdirectly - Use
data-testidsparingly — prefer accessible queries:getByRole,getByLabelText,getByText - Never hardcode API response shapes inline — always import from
fixtures.tsor use MSW handlers - Financial formatting is always tested — ₹ symbol, Indian number format, % sign are non-negotiable
- Negative financial values must render in red — test the color class, not just the value
After Completing Tests for a Component
Remind the developer:
"Tests complete. Run
npx vitest --coverageand confirm the component hits its coverage target before marking the task done."