Skip to content

Next.js 测试 🧪

🎯 概述

测试是保证代码质量的关键。Next.js 支持多种测试方案,包括单元测试、集成测试和端到端测试。

📦 Jest + React Testing Library

安装

bash
npm install -D jest @testing-library/react @testing-library/jest-dom jest-environment-jsdom

配置

js
// jest.config.js
const nextJest = require('next/jest')

const createJestConfig = nextJest({
  dir: './',
})

const customJestConfig = {
  setupFilesAfterEnv: ['<rootDir>/jest.setup.js'],
  testEnvironment: 'jest-environment-jsdom',
  moduleNameMapper: {
    '^@/(.*)$': '<rootDir>/$1',
  },
}

module.exports = createJestConfig(customJestConfig)

// jest.setup.js
import '@testing-library/jest-dom'

组件测试

tsx
// components/Button.test.tsx
import { render, screen, fireEvent } from '@testing-library/react'
import Button from './Button'

describe('Button', () => {
  it('renders button text', () => {
    render(<Button>Click me</Button>)
    expect(screen.getByText('Click me')).toBeInTheDocument()
  })
  
  it('calls onClick when clicked', () => {
    const handleClick = jest.fn()
    render(<Button onClick={handleClick}>Click me</Button>)
    fireEvent.click(screen.getByText('Click me'))
    expect(handleClick).toHaveBeenCalledTimes(1)
  })
})

🚀 Playwright (E2E)

安装

bash
npm install -D @playwright/test
npx playwright install

配置

ts
// playwright.config.ts
import { defineConfig } from '@playwright/test'

export default defineConfig({
  testDir: './e2e',
  use: {
    baseURL: 'http://localhost:3000',
  },
  webServer: {
    command: 'npm run dev',
    port: 3000,
  },
})

E2E 测试

ts
// e2e/home.spec.ts
import { test, expect } from '@playwright/test'

test('home page', async ({ page }) => {
  await page.goto('/')
  await expect(page.getByRole('heading', { name: '欢迎' })).toBeVisible()
})

test('navigation', async ({ page }) => {
  await page.goto('/')
  await page.click('text=关于')
  await expect(page).toHaveURL('/about')
})

📝 API 测试

tsx
// app/api/users/route.test.ts
import { GET, POST } from './route'

describe('/api/users', () => {
  it('GET returns users', async () => {
    const response = await GET()
    const data = await response.json()
    expect(Array.isArray(data)).toBe(true)
  })
  
  it('POST creates user', async () => {
    const request = new Request('http://localhost:3000/api/users', {
      method: 'POST',
      body: JSON.stringify({ name: '张三', email: 'zhang@example.com' })
    })
    
    const response = await POST(request)
    const data = await response.json()
    expect(data.name).toBe('张三')
  })
})

📚 最佳实践

1. 测试覆盖率

json
// package.json
{
  "scripts": {
    "test": "jest",
    "test:watch": "jest --watch",
    "test:coverage": "jest --coverage"
  }
}

2. Mock 数据

tsx
// __mocks__/api.ts
export const mockUser = {
  id: '1',
  name: '张三',
  email: 'zhang@example.com'
}

// components/UserProfile.test.tsx
jest.mock('@/lib/api')
import { mockUser } from '@/__mocks__/api'

test('displays user info', async () => {
  render(<UserProfile userId="1" />)
  expect(await screen.findByText(mockUser.name)).toBeInTheDocument()
})

3. 快照测试

tsx
import { render } from '@testing-library/react'
import Component from './Component'

test('matches snapshot', () => {
  const { container } = render(<Component />)
  expect(container).toMatchSnapshot()
})

🔗 相关资源


下一步:学习 Next.js 性能优化