Skip to Content
文档

测试

使用 Vitest 和 Jest 测试 React 组件的最佳实践。

使用 Vitest 或 Jest 编写测试时,请遵循以下做法以获得最佳效果。

¥When writing tests with Vitest or Jest, use the following practices to get the best results.

note

通常,我们建议使用 Vitest 而不是 Jest,但设置类似。

¥In general, we recommend using Vitest over Jest but the setup are similar.

设置

¥Setup

在编写测试之前,请确保你的项目具有必要的依赖:

¥Before writing tests, ensure your project has the necessary dependencies:

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

配置

¥Configuration

创建 vite.config.ts 文件以配置 Vitest。

¥Create the vite.config.ts file to configure Vitest.

import { defineConfig } from "vitest/config"

export default defineConfig({
  // ...
  test: {
    globals: true,
    environment: "jsdom",
    setupFiles: "./setup-test.ts",
  },
})

设置 globals: true 将自动导入 Vitest 全局变量,无需导入 expecttestdescribe 等。

¥Setting globals: true will automatically import the Vitest globals and removes the need to import expect, test, describe, etc.

设置测试文件

¥Setup Test File

创建 setup-test.ts 文件以配置测试环境并模拟未实现的 API。

¥Create the setup-test.ts file to configure the testing environment and mock unimplemented APIs.

以下是 Chakra v3 项目的一个常见示例:

¥Here's a common example for Chakra v3 projects:

import "@testing-library/jest-dom/vitest"
import { JSDOM } from "jsdom"
import ResizeObserver from "resize-observer-polyfill"
import { vi } from "vitest"
import "vitest-axe/extend-expect"

const { window } = new JSDOM()

// ResizeObserver mock
vi.stubGlobal("ResizeObserver", ResizeObserver)
window["ResizeObserver"] = ResizeObserver

// IntersectionObserver mock
const IntersectionObserverMock = vi.fn(() => ({
  disconnect: vi.fn(),
  observe: vi.fn(),
  takeRecords: vi.fn(),
  unobserve: vi.fn(),
}))
vi.stubGlobal("IntersectionObserver", IntersectionObserverMock)
window["IntersectionObserver"] = IntersectionObserverMock

// Scroll Methods mock
window.Element.prototype.scrollTo = () => {}
window.Element.prototype.scrollIntoView = () => {}

// requestAnimationFrame mock
window.requestAnimationFrame = (cb) => setTimeout(cb, 1000 / 60)

// URL object mock
window.URL.createObjectURL = () => "https://i.pravatar.cc/300"
window.URL.revokeObjectURL = () => {}

// navigator mock
Object.defineProperty(window, "navigator", {
  value: {
    clipboard: {
      writeText: vi.fn(),
    },
  },
})

// Override globalThis
Object.assign(global, { window, document: window.document })

自定义渲染

¥Custom Render

首先,你需要创建一个自定义渲染函数,将你的组件封装在 ChakraProvider 中。

¥First, you need to create a custom render function to wrap your component in the ChakraProvider.

test-utils/render.tsx

// ./testing/render.tsx
import { Provider } from "@/components/ui/provider"
import { render as rtlRender } from "@testing-library/react"

export function render(ui: React.ReactNode) {
  return rtlRender(<>{ui}</>, {
    wrapper: (props: React.PropsWithChildren) => (
      <Provider>{props.children}</Provider>
    ),
  })
}

测试组件

¥Testing Components

现在,你可以使用 render 函数测试你的组件。

¥Now, you can use the render function to test your components.

testing/render.tsx

import { Button } from "@chakra-ui/react"
import { render } from "./testing/render"

test("renders a button", () => {
  render(<Button>Click me</Button>)
  expect(screen.getByText("Click me")).toBeInTheDocument()
})

Previous

服务器组件

Next

宽高比