Next.js Jest Configuration
Testing is a crucial part of application development, and Next.js applications are no exception. Jest is one of the most popular testing frameworks for JavaScript applications, and it works great with Next.js when properly configured. In this guide, we'll learn how to set up Jest for testing your Next.js applications.
Introduction to Jest in Next.js
Jest is a delightful JavaScript testing framework with a focus on simplicity. It works with projects using Babel, TypeScript, Node.js, React, Angular, and more. While Next.js doesn't come with Jest pre-configured, setting it up is straightforward and provides significant benefits for testing your application.
Why Configure Jest for Next.js?
- Component Testing: Test React components in your Next.js application
- API Route Testing: Verify the functionality of your Next.js API routes
- Integration Testing: Ensure different parts of your application work together
- Special Handling: Properly manage Next.js-specific features like routing and Image components
Basic Jest Configuration for Next.js
Let's start with the installation and basic configuration to get Jest working with Next.js.
Step 1: Install Required Dependencies
npm install --save-dev jest @testing-library/react @testing-library/jest-dom jest-environment-jsdom
or if you use Yarn:
yarn add --dev jest @testing-library/react @testing-library/jest-dom jest-environment-jsdom
Step 2: Create Jest Configuration File
Create a jest.config.js
file in the root of your project:
// jest.config.js
const nextJest = require('next/jest')
// Providing the path to your Next.js app which will enable loading next.config.js and .env files
const createJestConfig = nextJest({
dir: './',
})
// Any custom config you want to pass to Jest
const customJestConfig = {
setupFilesAfterEnv: ['<rootDir>/jest.setup.js'],
testEnvironment: 'jest-environment-jsdom',
moduleNameMapper: {
// Handle module aliases (this will be automatically configured for you soon)
'^@/components/(.*)$': '<rootDir>/components/$1',
'^@/pages/(.*)$': '<rootDir>/pages/$1',
},
}
// createJestConfig is exported this way to ensure that next/jest can load the Next.js config
module.exports = createJestConfig(customJestConfig)
Step 3: Create Jest Setup File
Create a jest.setup.js
file to extend Jest with additional functionality:
// jest.setup.js
import '@testing-library/jest-dom'
Step 4: Update package.json
Add testing scripts to your package.json
:
{
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"test": "jest",
"test:watch": "jest --watch"
}
}
Advanced Configuration Options
Let's explore more advanced options to handle Next.js-specific features.
Handling CSS and Style Imports
Next.js allows importing CSS files directly into components. To handle these in your tests, add this to your Jest configuration:
// In jest.config.js under customJestConfig
moduleNameMapper: {
// Handle CSS imports (with CSS modules)
'^.+\\.module\\.(css|sass|scss)$': 'identity-obj-proxy',
// Handle CSS imports (without CSS modules)
'^.+\\.(css|sass|scss)$': '<rootDir>/__mocks__/styleMock.js',
// Handle image imports
'^.+\\.(jpg|jpeg|png|gif|webp|avif|svg)$': '<rootDir>/__mocks__/fileMock.js',
}
Create the mock files:
// __mocks__/styleMock.js
module.exports = {};
// __mocks__/fileMock.js
module.exports = 'test-file-stub';
Mocking Next.js Components and Hooks
Next.js provides components like Image
, Link
, and hooks like useRouter
that need special handling in tests.
Create a __mocks__
directory at the root of your project:
// __mocks__/next/router.js
module.exports = {
useRouter() {
return {
route: '/',
pathname: '',
query: {},
asPath: '',
push: jest.fn(),
replace: jest.fn(),
reload: jest.fn(),
back: jest.fn(),
prefetch: jest.fn(),
beforePopState: jest.fn(),
events: {
on: jest.fn(),
off: jest.fn(),
emit: jest.fn(),
},
isFallback: false,
};
},
};
// __mocks__/next/image.js
const nextImage = ({ src, alt, ...props }) => {
return <img src={src} alt={alt} {...props} />;
};
module.exports = nextImage;
Testing Environment Variables
To handle environment variables in your tests:
// jest.config.js
const customJestConfig = {
// ... other config
testEnvironment: 'jest-environment-jsdom',
testEnvironmentOptions: {
// Set environment variables for tests
env: {
API_URL: 'http://test-api.example.com',
},
},
}
Real-World Example: Testing a Next.js Component
Let's look at a complete example of testing a component in a Next.js application:
Component to Test:
// components/Greeting.js
import { useState } from 'react';
export default function Greeting({ initialName = 'friend' }) {
const [name, setName] = useState(initialName);
return (
<div>
<h1>Hello, {name}!</h1>
<input
aria-label="Name"
value={name}
onChange={(e) => setName(e.target.value)}
/>
</div>
);
}
Test File:
// __tests__/Greeting.test.js
import { render, screen, fireEvent } from '@testing-library/react';
import Greeting from '../components/Greeting';
describe('Greeting component', () => {
it('renders with default greeting', () => {
render(<Greeting />);
expect(screen.getByText('Hello, friend!')).toBeInTheDocument();
});
it('renders with custom name', () => {
render(<Greeting initialName="Sarah" />);
expect(screen.getByText('Hello, Sarah!')).toBeInTheDocument();
});
it('updates greeting when name is changed', () => {
render(<Greeting />);
const input = screen.getByLabelText('Name');
fireEvent.change(input, { target: { value: 'John' } });
expect(screen.getByText('Hello, John!')).toBeInTheDocument();
});
});
Testing API Routes in Next.js
Testing API routes requires a different approach since they are server-side code:
API Route to Test:
// pages/api/hello.js
export default function handler(req, res) {
const { name = 'World' } = req.query;
res.status(200).json({ message: `Hello ${name}!` });
}
Test File for API Route:
// __tests__/api/hello.test.js
import { createMocks } from 'node-mocks-http';
import helloHandler from '../../pages/api/hello';
describe('/api/hello API endpoint', () => {
test('returns default greeting', async () => {
const { req, res } = createMocks({
method: 'GET',
query: {},
});
await helloHandler(req, res);
expect(res._getStatusCode()).toBe(200);
expect(JSON.parse(res._getData())).toEqual({ message: 'Hello World!' });
});
test('returns personalized greeting', async () => {
const { req, res } = createMocks({
method: 'GET',
query: { name: 'John' },
});
await helloHandler(req, res);
expect(res._getStatusCode()).toBe(200);
expect(JSON.parse(res._getData())).toEqual({ message: 'Hello John!' });
});
});
For this example, you'll need to install the node-mocks-http
package:
npm install --save-dev node-mocks-http
Common Issues and Solutions
1. SyntaxError: Unexpected token 'export'
If you see this error, make sure your Jest config is properly handling ES modules:
// jest.config.js
const customJestConfig = {
// ...
transform: {
'^.+\\.(js|jsx|ts|tsx)$': ['babel-jest', { presets: ['next/babel'] }],
},
}
2. Cannot find module 'next/image'
Make sure you've mocked Next.js components as shown earlier or add this to your Jest config:
// jest.config.js
moduleNameMapper: {
// Handle Next.js specific components
'^next/(.*)$': '<rootDir>/__mocks__/next/$1',
}
3. Problems with CSS Modules
If you're having issues with CSS modules, ensure you've installed and configured identity-obj-proxy
:
npm install --save-dev identity-obj-proxy
Summary
Setting up Jest with Next.js requires some configuration but provides powerful testing capabilities for your application. We've covered:
- Basic Jest setup for Next.js applications
- Advanced configuration options
- Handling Next.js-specific features like routing and components
- Testing React components and API routes with practical examples
- Solutions for common testing issues
With this configuration in place, you can write comprehensive tests for your Next.js application, ensuring that your code works as expected and catches regressions before they affect users.
Additional Resources
- Jest Official Documentation
- React Testing Library Documentation
- Next.js Testing Documentation
- Testing Next.js API Routes
Practice Exercises
- Set up Jest in a new Next.js project following the steps in this guide
- Write tests for a simple counter component that increments and decrements a value
- Create and test an API route that accepts POST requests with user data and returns a formatted response
- Configure Jest to generate coverage reports and aim for over 80% coverage in your tests
By following this guide and practicing with the exercises, you'll be well-equipped to implement effective testing in your Next.js applications!
If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)