Testing
Best practices for testing React components using Vitest and 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
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",
},
})
Setting globals: true
will automatically import the Vitest globals and removes
the need to import expect
, test
, describe
, etc.
Setup Test File
Create the setup-test.ts
file to configure the testing environment and mock
unimplemented APIs.
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
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
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()
})