跳转到内容

Next.js React Testing Library

来自代码酷
Admin留言 | 贡献2025年5月1日 (四) 23:18的版本 (Page creation by admin bot)

(差异) ←上一版本 | 已核准修订 (差异) | 最后版本 (差异) | 下一版本→ (差异)

Next.js React Testing Library[编辑 | 编辑源代码]

介绍[编辑 | 编辑源代码]

Next.js React Testing Library 是一个基于 React Testing Library 的测试工具集,专门用于测试 Next.js 应用程序中的组件和页面。它提供了一套简单、直观的 API,帮助开发者编写可维护、可读性强的测试代码,同时鼓励最佳实践,如避免测试实现细节,而是专注于用户行为。

React Testing Library 的核心思想是:

  • 测试组件的行为,而非内部实现。
  • 模拟用户交互(点击、输入等)。
  • 提供查询方法(如 `getByText`、`getByRole`)来定位 DOM 元素。
  • 支持异步操作(如 `waitFor`、`findBy`)。

在 Next.js 中,由于框架的特殊性(如路由、数据获取等),React Testing Library 需要结合 Jest 或其他测试运行器使用,并可能需要额外的配置。

安装与配置[编辑 | 编辑源代码]

首先,确保你的 Next.js 项目已安装必要的依赖:

npm install --save-dev @testing-library/react @testing-library/jest-dom @testing-library/user-event jest @types/jest

然后,在项目根目录创建或修改 `jest.config.js`:

module.exports = {
  testEnvironment: 'jsdom',
  setupFilesAfterEnv: ['<rootDir>/jest.setup.js'],
};

创建 `jest.setup.js` 文件以引入 `@testing-library/jest-dom` 的扩展断言:

import '@testing-library/jest-dom/extend-expect';

基本用法[编辑 | 编辑源代码]

以下是一个简单的测试示例,测试一个 Next.js 页面组件:

示例组件[编辑 | 编辑源代码]

假设有一个 `Home` 组件 (`pages/index.js`):

export default function Home() {
  return (
    <div>
      <h1>Welcome to Next.js</h1>
      <button onClick={() => alert('Button clicked!')}>Click Me</button>
    </div>
  );
}

测试文件[编辑 | 编辑源代码]

创建 `__tests__/index.test.js`:

import { render, screen, fireEvent } from '@testing-library/react';
import Home from '../pages/index';

describe('Home Page', () => {
  it('renders a heading', () => {
    render(<Home />);
    const heading = screen.getByRole('heading', { name: /Welcome to Next.js/i });
    expect(heading).toBeInTheDocument();
  });

  it('shows alert when button is clicked', () => {
    window.alert = jest.fn();
    render(<Home />);
    const button = screen.getByRole('button', { name: /Click Me/i });
    fireEvent.click(button);
    expect(window.alert).toHaveBeenCalledWith('Button clicked!');
  });
});

解释[编辑 | 编辑源代码]

1. `render` 函数渲染组件。 2. `screen.getByRole` 查询 DOM 元素(`heading` 和 `button`)。 3. `fireEvent.click` 模拟用户点击。 4. `expect` 断言验证结果。

高级用法[编辑 | 编辑源代码]

测试异步操作[编辑 | 编辑源代码]

Next.js 中常见的数据获取(如 `getServerSideProps`)可以通过模拟 API 测试:

import { render, screen, waitFor } from '@testing-library/react';
import Home from '../pages/index';

jest.mock('../lib/api', () => ({
  fetchData: jest.fn(() => Promise.resolve({ data: 'Mock Data' })),
}));

describe('Home Page with Data', () => {
  it('displays fetched data', async () => {
    render(<Home data={{ message: 'Hello' }} />);
    await waitFor(() => {
      expect(screen.getByText('Hello')).toBeInTheDocument();
    });
  });
});

测试路由[编辑 | 编辑源代码]

使用 `next-router-mock` 测试路由行为:

npm install --save-dev next-router-mock

测试示例:

import { render, screen } from '@testing-library/react';
import Home from '../pages/index';
import mockRouter from 'next-router-mock';

jest.mock('next/router', () => require('next-router-mock'));

describe('Routing', () => {
  it('navigates on button click', () => {
    mockRouter.push('/initial-route');
    render(<Home />);
    fireEvent.click(screen.getByText('Navigate'));
    expect(mockRouter.pathname).toBe('/new-route');
  });
});

实际案例[编辑 | 编辑源代码]

测试登录表单[编辑 | 编辑源代码]

假设有一个登录组件:

function LoginForm({ onSubmit }) {
  const [email, setEmail] = useState('');
  return (
    <form onSubmit={(e) => { e.preventDefault(); onSubmit(email); }}>
      <input 
        type="email" 
        value={email} 
        onChange={(e) => setEmail(e.target.value)} 
        placeholder="Email" 
      />
      <button type="submit">Login</button>
    </form>
  );
}

测试文件:

import { render, screen, fireEvent } from '@testing-library/react';
import LoginForm from '../components/LoginForm';

describe('LoginForm', () => {
  it('submits email', () => {
    const mockSubmit = jest.fn();
    render(<LoginForm onSubmit={mockSubmit} />);
    
    fireEvent.change(
      screen.getByPlaceholderText('Email'),
      { target: { value: 'test@example.com' } }
    );
    fireEvent.click(screen.getByText('Login'));
    
    expect(mockSubmit).toHaveBeenCalledWith('test@example.com');
  });
});

最佳实践[编辑 | 编辑源代码]

  • 使用 `getByRole` 优先于其他查询方法。
  • 避免使用 `container.querySelector` 直接访问 DOM。
  • 对异步操作使用 `await waitFor` 或 `findBy*`。
  • 模拟外部依赖(如 API、路由)。

常见问题[编辑 | 编辑源代码]

问题 解决方案
使用 `await` 或 `waitFor` 处理异步更新
确保正确模拟 `next/router`
在 Jest 配置中添加 `identity-obj-proxy`

总结[编辑 | 编辑源代码]

Next.js React Testing Library 是测试 Next.js 应用的强大工具,它强调以用户为中心的方式验证组件行为。通过结合 Jest 和适当的模拟,可以覆盖从简单渲染测试到复杂异步场景的全方位测试需求。