How to set up Vitest with Next.js

김동현·2026년 3월 4일

next.js 공식문서 번역

목록 보기
38/79

Vitest와 React Testing Library는 단위 테스트(Unit Testing)를 위해 프론트엔드 씬에서 정말 자주, 그리고 함께 사용되는 단짝 친구랍니다. 이 가이드에서는 여러분의 Next.js 프로젝트에 Vitest를 어떻게 세팅하는지, 그리고 대망의 첫 번째 테스트 코드를 어떻게 작성하는지 차근차근 알려드릴게요!

💡 강사의 팁: 예전에는 React 테스트를 할 때 Jest를 기본으로 많이 사용했지만, 요즘은 Vite의 엄청난 속도를 등에 업은 Vitest가 정말 대세로 자리 잡고 있어요. Next.js 환경에서도 무겁지 않고 빠르게 테스트를 돌릴 수 있어서 꼭 익혀두시면 현업에서 큰 무기가 될 겁니다!

알아두면 좋은 점: async 서버 컴포넌트(Server Components)는 React 생태계에 등장한 지 얼마 안 된 새로운 개념이에요. 그래서 아쉽게도 현재 Vitest가 이를 완벽하게 지원하지는 않습니다. 동기(synchronous) 서버 컴포넌트나 클라이언트 컴포넌트의 경우는 지금처럼 단위 테스트를 작성하시면 되지만, async 컴포넌트의 경우에는 단위 테스트보다는 Playwright나 Cypress 같은 E2E(End-to-End) 테스트를 사용하시는 것을 적극 권장합니다.

빠른 시작 (Quickstart)

복잡한 설정 없이 바로 시작해보고 싶으신가요? create-next-app 명령어와 Next.js에서 공식적으로 제공하는 with-vitest 예제 템플릿을 결합하면 아주 빠르게 보일러플레이트를 생성할 수 있어요.

pnpm create next-app --example with-vitest with-vitest-app
npx create-next-app@latest --example with-vitest with-vitest-app
yarn create next-app --example with-vitest with-vitest-app
bun create next-app --example with-vitest with-vitest-app

수동 설정 (Manual Setup)

이미 작업 중인 프로젝트가 있고, 거기에 테스트 환경만 얹고 싶으시다면 수동으로 세팅을 해주셔야 해요. 당황하지 마시고 터미널을 열어 vitest와 다음 패키지들을 개발 의존성(dev dependencies)으로 설치해주세요.

👨‍🏫 강사의 보충 설명: 여기서 jsdom은 실제 브라우저가 없는 터미널(Node.js) 환경에서 가상의 브라우저 DOM을 만들어주는 아주 중요한 역할을 해요! 그리고 @testing-library/react는 그 가짜 DOM 위에서 우리의 리액트 컴포넌트를 렌더링하고, 버튼을 클릭하는 등의 행동을 흉내 낼 수 있게 해주는 도구랍니다. 만약 TypeScript를 쓰신다면 vite-tsconfig-paths 패키지를 꼭 설치하셔야 tsconfig.json에 설정해둔 절대 경로(예: @/components/Button)를 Vitest가 똑똑하게 알아먹을 수 있어요!

# Using TypeScript (타입스크립트 사용 시)
pnpm add -D vitest @vitejs/plugin-react jsdom @testing-library/react @testing-library/dom vite-tsconfig-paths
# Using JavaScript (자바스크립트 사용 시)
pnpm add -D vitest @vitejs/plugin-react jsdom @testing-library/react @testing-library/dom
# Using TypeScript (타입스크립트 사용 시)
npm install -D vitest @vitejs/plugin-react jsdom @testing-library/react @testing-library/dom vite-tsconfig-paths
# Using JavaScript (자바스크립트 사용 시)
npm install -D vitest @vitejs/plugin-react jsdom @testing-library/react @testing-library/dom
# Using TypeScript (타입스크립트 사용 시)
yarn add -D vitest @vitejs/plugin-react jsdom @testing-library/react @testing-library/dom vite-tsconfig-paths
# Using JavaScript (자바스크립트 사용 시)
yarn add -D vitest @vitejs/plugin-react jsdom @testing-library/react @testing-library/dom
# Using TypeScript (타입스크립트 사용 시)
bun add -D vitest @vitejs/plugin-react jsdom @testing-library/react @testing-library/dom vite-tsconfig-paths
# Using JavaScript (자바스크립트 사용 시)
bun add -D vitest @vitejs/plugin-react jsdom @testing-library/react @testing-library/dom

설치가 끝났다면, 프로젝트의 가장 최상단 경로(루트 디렉토리)에 vitest.config.mts (또는 .js) 파일을 만들어주세요. 그리고 아래와 같이 설정 코드를 작성합니다.

//filename="vitest.config.mts" switcher
import { defineConfig } from 'vitest/config'
import react from '@vitejs/plugin-react'
import tsconfigPaths from 'vite-tsconfig-paths'

export default defineConfig({
  plugins: [tsconfigPaths(), react()],
  test: {
    environment: 'jsdom', // 테스트 환경을 jsdom으로 지정해줍니다!
  },
})
//filename="vitest.config.js" switcher
import { defineConfig } from 'vitest/config'
import react from '@vitejs/plugin-react'

export default defineConfig({
  plugins: [react()],
  test: {
    environment: 'jsdom',
  },
})

Vitest의 설정 옵션들에 대해 더 깊이 파보고 싶으시다면, Vitest 설정 공식 문서(Vitest Configuration)를 읽어보시는 것을 추천해요. 개발자는 결국 공식 문서와 친해져야 성장하거든요!

세팅의 마지막 단계입니다! package.json 파일을 열어서 scripts 부분에 test 명령어를 쏙 추가해주세요.

{
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "test": "vitest"
  }
}

이렇게 세팅해두고 터미널에서 npm run test를 실행하면, Vitest가 기본적으로 프로젝트 폴더 내의 파일 변경 사항을 감시(watch) 하게 돼요. 코드를 수정하고 저장할 때마다 자동으로 테스트가 다시 돌아가니까, 개발 속도도 올라가고 버그도 즉각적으로 잡을 수 있어서 무척 편리하답니다!

첫 번째 Vitest 단위 테스트 만들어보기 (Creating your first Vitest Unit Test)

자, 그럼 우리가 힘들게 설정한 환경이 잘 동작하는지 확인해봐야겠죠? <Page /> 컴포넌트가 화면에 'Home'이라는 제목(heading)을 성공적으로 렌더링하는지 검증하는 테스트 코드를 한 번 짜봅시다.

먼저 대상이 될 간단한 페이지 컴포넌트입니다.

//filename="app/page.tsx" switcher
import Link from 'next/link'

export default function Page() {
  return (
    <div>
      <h1>Home</h1>
      <Link href="/about">About</Link>
    </div>
  )
}
//filename="app/page.jsx" switcher
import Link from 'next/link'

export default function Page() {
  return (
    <div>
      <h1>Home</h1>
      <Link href="/about">About</Link>
    </div>
  )
}

이제 이 컴포넌트를 테스트할 코드를 작성해볼게요!

//filename="__tests__/page.test.tsx" switcher
import { expect, test } from 'vitest'
import { render, screen } from '@testing-library/react'
import Page from '../app/page'

test('Page', () => {
  render(<Page />)
  expect(screen.getByRole('heading', { level: 1, name: 'Home' })).toBeDefined()
})
//filename="__tests__/page.test.jsx" switcher
import { expect, test } from 'vitest'
import { render, screen } from '@testing-library/react'
import Page from '../app/page'

test('Page', () => {
  render(<Page />)
  expect(screen.getByRole('heading', { level: 1, name: 'Home' })).toBeDefined()
})

👨‍🏫 강사의 보충 설명: 위 코드에서 render(<Page />)는 아까 우리가 말했던 가짜 브라우저(jsdom) 위에 컴포넌트를 그리는 행위예요. 그리고 screen.getByRole을 써서 화면에 렌더링된 요소 중 heading 요소(즉, <h1>, <h2> 등)이면서, level: 1 (<h1>)이고 텍스트가 'Home'인 요소를 찾습니다.
"이 요소가 정의되어 있어야 한다(.toBeDefined())"라고 기대(expect)하는 것이죠! Testing Library는 이렇게 '개발자의 구현 방식'이 아닌 '사용자가 화면에서 무엇을 보는가'를 기준으로 테스트를 작성하도록 유도합니다.

알아두면 좋은 점: 위 예제에서는 프론트엔드 관례에 따라 폴더 이름을 __tests__로 묶어서 분리했어요. 하지만 Next.js App Router 환경에서는 굳이 폴더를 따로 빼지 않고 app 라우터 폴더 안에 여러분이 만든 컴포넌트 파일 바로 옆에 나란히(colocated) 테스트 파일을 두셔도 아무 문제가 없습니다. 실무에서도 팀의 취향이나 규칙에 따라 이 방식을 꽤 많이 사용해요!

테스트 실행하기 (Running your tests)

준비가 다 끝났다면, 아래 명령어 중 여러분이 사용하시는 패키지 매니저에 맞춰서 터미널에 입력하고 테스트를 돌려보세요! "Pass"라는 초록색 글자가 뜨면 성공입니다. 🎉

pnpm test
npm run test
yarn test
bun run test

추가 학습 자료 (Additional Resources)

공부하시다가 막히는 부분이 있거나 더 자세한 정보가 필요할 때, 다음 자료들이 좋은 길잡이가 될 거예요:


전체 문서의 구조(의미론적 개요)가 궁금하시다면 https://nextjs.org/docs/sitemap.md를 참고해주세요.

이용 가능한 전체 문서의 인덱스 목록을 보시려면 https://nextjs.org/docs/llms.txt를 확인해주시면 됩니다.

profile
프론트에_가까운_풀스택_개발자

0개의 댓글