测试
使用 Vitest 和 Jest 测试 React 组件的最佳实践。
使用 Vitest 或 Jest 编写测试时,请遵循以下做法以获得最佳效果。
¥When writing tests with Vitest or Jest, use the following practices to get the best results.
设置
¥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 全局变量,无需导入 expect
、test
、describe
等。
¥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()
})