From harness-claude
Tests Next.js App Router components, Server Actions, and Route Handlers using Jest, Vitest, and MSW. Covers mocking next/navigation, next/headers, and direct handler invocation.
How this skill is triggered — by the user, by Claude, or both
Slash command
/harness-claude:next-testing-patternsThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
> Test App Router components, Server Actions, and Route Handlers with Jest, Vitest, and MSW
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
npx claudepluginhub intense-visions/harness-engineering --plugin harness-claudeTesting strategies for Next.js: Server Components, Client Components, Server Actions, Route Handlers, end-to-end with Playwright. Vitest/Jest configuration, React Testing Library patterns, msw for network mocks. Use this skill to: - Pick the right test layer for what you're testing. - Configure Vitest or Jest for Next.js. - Test Server Components without running them in isolation. - Test Server Actions and Route Handlers as pure functions. - Set up Playwright for e2e and integration of RSC. Do NOT use this skill for: - General Next.js conventions (see nextjs-conventions). - RSC vs Client model (see server-component-patterns). - Plain Node.js test patterns (see nodejs-plugin equivalents).
Detects React project structure (Next.js, Vite, CRA) and configures jest/vitest, @testing-library, MSW, customRender with provider context, and test scripts.
Provides testing patterns and examples for React components, hooks, and integrations using Vitest, React Testing Library, and Jest.