Testing

Testing

Vitest와 Jest를 사용해 React 컴포넌트를 테스트하는 모범 사례를 다루는 개념 문서예요.

출처: 문서

본문

Vitest 또는 Jest로 테스트를 작성할 때는 다음 관행을 사용해 최상의 결과를 얻어 보세요.

:::note

일반적으로 Jest보다 Vitest를 권장하지만, 설정은 비슷해요.

:::

설정 (Setup)

테스트를 작성하기 전에 프로젝트에 필요한 의존성이 있는지 확인해 주세요:

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

구성 (Configuration)

Vitest를 구성하려면 vite.config.ts 파일을 만들어 주세요.

import { defineConfig } from "vitest/config"

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

globals: true로 설정하면 Vitest globals가 자동으로 import되어 expect, test, describe 등을 별도로 import할 필요가 없어져요.

테스트 파일 설정 (Setup Test File)

테스트 환경을 구성하고 미구현 API를 mock하려면 setup-test.ts 파일을 만들어 주세요.

다음은 Chakra v3 프로젝트의 일반적인 예시예요:

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

// matchMedia mock
Object.defineProperty(window, "matchMedia", {
  writable: true,
  value: vi.fn().mockImplementation((query) => ({
    matches: false,
    media: query,
    onchange: null,
    addListener: vi.fn(), // deprecated
    removeListener: vi.fn(), // deprecated
    addEventListener: vi.fn(),
    removeEventListener: vi.fn(),
    dispatchEvent: vi.fn(),
  })),
})

// 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로 감싸는 커스텀 렌더 함수를 만들어야 해요.

// ./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 함수를 사용해 컴포넌트를 테스트할 수 있어요.

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()
})

더 알아보기 (Learn more)

Chakra UI 컴포넌트를 테스트하는 더 자세한 내용은 공식 문서를 확인해 보세요.