From harness-claude
Tests Next.js App Router Server Components, Client Components, Server Actions, and Route Handlers using Jest, Vitest, MSW, and next-router-mock.
npx claudepluginhub intense-visions/harness-engineering --plugin harness-claudeThis skill uses the workspace's default tool permissions.
> Test App Router components, Server Actions, and Route Handlers with Jest, Vitest, and MSW
Provides testing patterns and examples for React components, hooks, and integrations using Vitest, React Testing Library, and Jest.
Guides writing, running, debugging, and organizing Vitest v4 tests for TypeScript React/Next.js projects including mocks, cleanup, and coverage.
Guides Vitest unit and integration testing for JavaScript/TypeScript apps using Jest-compatible API, Vite integration, MSW v2 HTTP mocking, vi.mock hoisting, fake timers, snapshots, and test isolation.
Share bugs, ideas, or general feedback.
Test App Router components, Server Actions, and Route Handlers with Jest, Vitest, and MSW
@testing-library/react for rendering Client Components — import from @testing-library/react as usual.next/navigation (useRouter, usePathname, useSearchParams) with jest.mock() or vi.mock() — these hooks are not available in tests.next/headers (cookies, headers) for Server Components that read request headers or cookies.msw) to intercept fetch() calls in integration tests — set up a server with setupServer() and start/stop per test suite.NextRequest and calling the handler directly — no HTTP server needed.next-router-mock as a drop-in useRouter mock that supports assertions on navigation calls.// __tests__/server-component.test.tsx — testing a Server Component
import { render, screen } from '@testing-library/react';
import { PostList } from '@/components/post-list'; // Server Component
// Mock data access module
vi.mock('@/lib/posts', () => ({
getPosts: vi.fn().mockResolvedValue([
{ id: '1', title: 'Hello World', slug: 'hello-world' },
]),
}));
test('renders post titles', async () => {
const component = await PostList(); // call as async function
render(component);
expect(screen.getByText('Hello World')).toBeInTheDocument();
});
// __tests__/client-component.test.tsx — Client Component with router mock
import { render, screen, fireEvent } from '@testing-library/react';
import { useRouter } from 'next/navigation';
import { NavButton } from '@/components/nav-button';
vi.mock('next/navigation', () => ({ useRouter: vi.fn() }));
test('navigates on click', () => {
const push = vi.fn();
vi.mocked(useRouter).mockReturnValue({ push } as any);
render(<NavButton href="/dashboard">Go to Dashboard</NavButton>);
fireEvent.click(screen.getByText('Go to Dashboard'));
expect(push).toHaveBeenCalledWith('/dashboard');
});
// __tests__/route-handler.test.ts — Route Handler unit test
import { GET } from '@/app/api/posts/route';
import { NextRequest } from 'next/server';
test('returns posts as JSON', async () => {
const request = new NextRequest('http://localhost/api/posts');
const response = await GET(request);
expect(response.status).toBe(200);
const data = await response.json();
expect(Array.isArray(data)).toBe(true);
});
Testing Next.js App Router applications requires different strategies for Server Components, Client Components, and server-side functions — they run in different environments.
Server Component testing: Server Components are async functions — call them directly and render the result. The key is mocking their dependencies (database calls, fetch, next/headers) rather than trying to render them in a browser environment.
next/navigation mocking: useRouter, usePathname, useSearchParams, and redirect are not available in the test environment. Always mock next/navigation. For complex navigation testing, use the next-router-mock package which provides a mock router with state tracking.
MSW integration: MSW intercepts fetch() at the network layer — no need to mock fetch globally. Set up server.listen() in beforeAll, server.resetHandlers() in afterEach, and server.close() in afterAll. Use server.use() within a test to override handlers for specific scenarios.
Vitest vs Jest: Vitest is faster and has native ESM support — preferred for new Next.js projects. Configure vitest.config.ts with @vitejs/plugin-react and alias next/navigation to a mock. Jest requires next/jest transform configuration for App Router compatibility.
next/cache in tests: revalidatePath and revalidateTag throw errors in test environments. Mock next/cache module entirely: vi.mock('next/cache', () => ({ revalidatePath: vi.fn(), revalidateTag: vi.fn() })).
E2E testing: For full integration tests including navigation and streaming, use Playwright with next dev or next start. Playwright can test App Router features (streaming, client navigation) that JSDOM-based unit tests cannot.
https://nextjs.org/docs/app/building-your-application/testing