예시:
이 문서에서는 Cypress
, Playwright
, Jest
와 React Testing Library
와 같은 대표적인 테스팅 툴을 사용하여 Next.js
를 어떻게 설정하는지 배울 수 있습니다.
Cypress
는 End-to-End (E2E) 및 Component Testing에 사용되는 테스트 러너입니다.
with-cypress
예제를 사용하여 create-next-app
을 실행하여 빠르게 시작할 수 있습니다.
npx create-next-app@latest --example with-cypress with-cypress-app
Cypress를 시작하려면 cypress 패키지를 설치합니다.
npm install --save-dev cypress
Cypress
를 package.json
의 스크립트 필드에 추가합니다.
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"cypress": "cypress open",
}
Cypress
를 처음 실행하여 권장되는 폴더 구조를 사용하는 예제를 생성합니다.
npm run cypress
생성된 예제와 Cypress
문서의 Writing Your First Test 섹션을 확인하여 Cypress
에 익숙해질 수 있습니다.
Cypress 문서에는 이 두 가지 유형의 테스트의 차이점과 언제 어떤 것을 사용하는 것이 적절한지에 대한 가이드가 포함되어 있습니다.
다음과 같은 두 개의 Next.js 페이지가 있다고 가정해보겠습니다:
// pages/index.js
import Link from 'next/link'
export default function Home() {
return (
<nav>
<h1>Homepage</h1>
<Link href="/about">About</Link>
</nav>
)
}
// pages/about.js
export default function About() {
return (
<div>
<h1>About Page</h1>
<Link href="/">Homepage</Link>
</div>
)
}
다음 테스트를 추가하여 내비게이션이 올바르게 작동하는지 확인할 수 있습니다:
// cypress/e2e/app.cy.js
describe('Navigation', () => {
it('should navigate to the about page', () => {
// 인덱스 페이지에서 시작
cy.visit('http://localhost:3000/')
// "about"을 포함하는 href 속성을 가진 링크를 찾아 클릭
cy.get('a[href*="about"]').click()
// 새로운 URL은 "/about"을 포함해야 합니다.
cy.url().should('include', '/about')
// 새 페이지에 "About page"를 포함하는 h1이 있어야 합니다.
cy.get('h1').contains('About Page')
})
})
cypress.config.js
구성 파일에 baseUrl: 'http://localhost:3000'
을 추가하면 cy.visit("http://localhost:3000/")
대신 cy.visit("/")
을 사용할 수 있습니다.
컴포넌트 테스트는 전체 애플리케이션을 번들링하거나 서버를 시작하지 않고 특정 컴포넌트를 빌드하고 마운트합니다. 이를 통해 더 빠르고 성능적으로 효율적인 테스트를 수행할 수 있습니다. 이러한 컴포넌트 테스트는 시각적 피드백과 Cypress E2E
테스트에 사용되는 동일한 API를 제공합니다.
참고: 컴포넌트 테스트는 Next.js 서버를 시작하지 않으므로, 서버가 필요한
<Image />
및getServerSideProps
와 같은 기능은 기본적으로 작동하지 않습니다. 이러한 기능을 컴포넌트 테스트에서 사용하는 방법에 대한 예는 Cypress Next.js 문서를 참조하십시오.
이전 섹션과 동일한 컴포넌트를 가정하고, 예상된 출력이 렌더링되는지 확인하는 테스트를 추가해 보겠습니다:
// pages/about.cy.js
import AboutPage from './about.js'
describe('<AboutPage />', () => {
it('should render and display expected content', () => {
// About 페이지의 React 컴포넌트를 마운트합니다.
cy.mount(<AboutPage />)
// 새 페이지에 "About page"를 포함하는 h1이 있어야 합니다.
cy.get('h1').contains('About Page')
// 예상된 URL을 가진 링크가 존재하는지 확인합니다.
// *링크를 따라가는* 것은 E2E 테스트에 더 적합합니다.
cy.get('a[href="/"]').should('be.visible')
})
})
Cypress E2E
테스트는 실제 Next.js
애플리케이션을 테스트하기 때문에 Cypress
를 시작하기 전에 Next.js
서버가 실행되어야 합니다. 애플리케이션이 어떻게 작동할지 더욱 가까이 모사하기 위해 프로덕션 코드를 대상으로 테스트하는 것을 권장합니다.
npm run build
와 npm run start
를 실행한 다음에 다른 터미널 창에서 npm run cypress -- --e2e
를 실행하여 Cypress
를 시작하고 E2E 테스트 스위트를 실행하세요.
참고: start-server-and-test
패키지를 설치하고 package.json
스크립트 필드에 추가할 수도 있습니다. "test": "start-server-and-test start http://localhost:3000 cypress"
는 Cypress
와 함께 Next.js
프로덕션 서버를 시작하는 데 사용됩니다. 새로운 변경 후에 애플리케이션을 다시 빌드해야 합니다.
npm run cypress -- --component
를 실행하여 Cypress를 시작하고 컴포넌트 테스트 스위트를 실행하세요.
Cypress
를 실행하면 대화형 브라우저가 열리기 때문에 CI
환경에서는 이상적이지 않습니다. cypress run
명령어를 사용하여 Cypress
를 headless
모드로 실행할 수도 있습니다:
// package.json
"scripts": {
//...
"e2e": "start-server-and-test dev http://localhost:3000 \"cypress open --e2e\"",
"e2e:headless": "start-server-and-test dev http://localhost:3000 \"cypress run --e2e\"",
"component": "cypress open --component",
"component:headless": "cypress run --component"
}
Cypress
와 지속적인 통합에 관한 자세한 내용은 다음 자료를 참고하세요.
Playwright
는 하나의 API로 Chromium
, Firefox
, WebKit
을 자동화할 수 있는 테스트 프레임워크입니다. 이를 사용하여 모든 플랫폼에서 End-to-End
(E2E
) 및 통합 테스트를 작성할 수 있습니다.
가장 빠르게 시작하는 방법은 with-playwright
예제를 사용하여 create-next-app
을 사용하는 것입니다. 이렇게 하면 Playwright
가 설정된 Next.js
프로젝트가 생성됩니다.
npx create-next-app@latest --example with-playwright with-playwright-app
기존 NPM
프로젝트에 Playwright
를 추가하려면 npm init playwright
을 사용할 수도 있습니다.
Playwright
를 수동으로 시작하려면 @playwright/test
패키지를 설치하세요.
npm install --save-dev @playwright/test
Playwright
를 package.json
스크립트 필드에 추가하세요.
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"test:e2e": "playwright test",
}
첫 번째 Playwright End-to-End
테스트 작성하기
다음과 같은 두 개의 Next.js
페이지를 가정합니다.
// pages/index.js
import Link from 'next/link'
export default function Home() {
return (
<nav>
<Link href="/about">About</Link>
</nav>
)
}
// pages/about.js
export default function About() {
return (
<div>
<h1>About Page</h1>
</div>
)
}
다음 내용을 검증하는 테스트를 추가하세요: 네비게이션 기능이 제대로 작동하는지 검증합니다.
// e2e/example.spec.ts
import { test, expect } from '@playwright/test'
test('should navigate to the about page', async ({ page }) => {
// index 페이지에서 시작합니다. (playwright.config.ts에서 webServer를 통해 baseURL을 설정합니다.)
await page.goto('http://localhost:3000/')
// 'About Page' 텍스트가 포함된 요소를 찾고 클릭합니다.
await page.click('text=About')
// 새 URL은 "/about" 이어야 합니다. (baseURL이 사용됩니다.)
await expect(page).toHaveURL('http://localhost:3000/about')
// 새 페이지에는 "About Page" h1이 있어야 합니다.
await expect(page.locator('h1')).toContainText('About Page')
})
playwright.config.ts
구성 파일에 "baseURL": "http://localhost:3000"
을 추가하면 page.goto("/")
대신 page.goto("http://localhost:3000/")
을 사용할 수 있습니다.
Playwright
는 실제 Next.js
애플리케이션을 테스트하기 때문에, Playwright
를 시작하기 전에 Next.js
서버가 실행 중이어야합니다. 애플리케이션이 동작하는 방식과 더욱 유사하게 테스트하기 위해 프로덕션 코드에 대해 테스트하는 것이 좋습니다.
터미널에서 npm run build
및 npm run start
를 실행한 다음, 다른 터미널 창에서 npm run test:e2e
를 실행하여 Playwright
테스트를 실행할 수 있습니다.
참고: 대안으로, Playwright
가 개발 서버를 시작하고 사용 가능할 때까지 대기하도록 webServer
기능을 사용할 수 있습니다.
Continuous Integration(CI)
에서 Playwright
실행하기
Playwright
는 기본적으로 헤드리스 모드(headless mode)에서 테스트를 실행합니다. 모든 Playwright
종속성을 설치하려면 npx playwright install-deps
를 실행하세요.
다음 리소스에서 Playwright
및 CI에 대해 더 알아볼 수 있습니다.
Jest와 React Testing Library
는 유닛 테스트를 위해 자주 함께 사용됩니다. Next.js
애플리케이션에서 Jest
를 사용하는 방법에는 다음과 같은 세 가지가 있습니다:
Jest
를 설정하는 방법을 알아보겠습니다:with-jest
예제를 사용하여 create-next-app
을 실행하면 쉽게 Jest
와 React Testing Library
를 시작할 수 있습니다:
npx create-next-app@latest --example with-jest with-jest-app
Next.js 12
부터 Jest
를 위한 내장 구성이 추가되었습니다.
Jest
를 설정하려면 jest
, jest-environment-jsdom
, @testing-library/react
, @testing-library/jest-dom
을 설치하세요:
npm install --save-dev jest jest-environment-jsdom @testing-library/react @testing-library/jest-dom
프로젝트 루트 디렉토리에 jest.config.js
파일을 만들고 다음과 같이 추가하세요:
// jest.config.js
const nextJest = require('next/jest')
const createJestConfig = nextJest({
// 테스트 환경에서 next.config.js 및 .env 파일을 로드하기 위해 Next.js 앱의 경로를 제공합니다
dir: './',
})
// Jest에 전달할 사용자 정의 구성 추가
/** @type {import('jest').Config} */
const customJestConfig = {
// 각 테스트가 실행되기 전에 추가 설정 옵션을 더할 수 있습니다
// setupFilesAfterEnv: ['<rootDir>/jest.setup.js'],
testEnvironment: 'jest-environment-jsdom',
}
// createJestConfig은 next/jest에서 Next.js 구성을 비동기적으로 로드할 수 있도록 이렇게 내보내집니다
module.exports = createJestConfig(customJestConfig)
내부적으로, next/jest
는 자동으로 다음과 같은 작업을 수행하여 Jest
를 구성합니다:
SWC
를 사용하여 변환 설정.css
, .module.css
, scss
변형) 자동 모킹, 이미지 가져오기 및 next/font
.env
(및 모든 변형)를 process.env
에 로드node_modules
를 테스트 해결 및 변환에서 제외.next
를 테스트에서 제외SWC
변환을 활성화하는 플래그가 포함된 next.config.js
를 로드합니다.참고: 환경 변수를 직접 테스트하려면 별도의 설정 스크립트나
jest.config.js
파일에서 수동으로 로드해야 합니다. 자세한 정보는Test Environment Variables
을 참조하세요.
Rust
컴파일러를 사용하지 않을 경우, Jest
를 수동으로 구성하고 babel-jest
와 identity-obj-proxy
를 설치해야 합니다. 다음은 Next.js
에서 Jest
를 구성하는 권장 옵션입니다.
// jest.config.js
module.exports = {
collectCoverage: true,
// node 14.x에서 커버리지 제공자 v8은 속도가 좋고 보고서도 거의 좋음
coverageProvider: 'v8',
collectCoverageFrom: [
'**/*.{js,jsx,ts,tsx}',
'!**/*.d.ts',
'!**/node_modules/**',
'!<rootDir>/out/**',
'!<rootDir>/.next/**',
'!<rootDir>/*.config.js',
'!<rootDir>/coverage/**',
],
moduleNameMapper: {
// CSS import 처리(CSS 모듈 포함)
// https://jestjs.io/docs/webpack#mocking-css-modules
'^.+\\.module\\.(css|sass|scss)$': 'identity-obj-proxy',
// CSS import 처리(CSS 모듈 미포함)
'^.+\\.(css|sass|scss)$': '<rootDir>/__mocks__/styleMock.js',
// 이미지 import 처리
// https://jestjs.io/docs/webpack#handling-static-assets
'^.+\\.(png|jpg|jpeg|gif|webp|avif|ico|bmp|svg)$/i': `<rootDir>/__mocks__/fileMock.js`,
// 모듈 별칭 처리
'^@/components/(.*)$': '<rootDir>/components/$1',
},
// 테스트가 실행되기 전에 추가적인 설정 옵션을 추가
// setupFilesAfterEnv: ['<rootDir>/jest.setup.js'],
testPathIgnorePatterns: ['<rootDir>/node_modules/', '<rootDir>/.next/'],
testEnvironment: 'jsdom',
transform: {
// next/babel 프리셋을 사용하여 babel-jest를 이용하여 테스트를 트랜스파일
// https://jestjs.io/docs/configuration#transform-objectstring-pathtotransformer--pathtotransformer-object
'^.+\\.(js|jsx|ts|tsx)$': ['babel-jest', { presets: ['next/babel'] }],
},
transformIgnorePatterns: [
'/node_modules/',
'^.+\\.module\\.(css|sass|scss)$',
],
}
Jest
설정 옵션에 대해 자세히 알아보려면 Jest
문서를 참조하세요.
테스트에서는 스타일시트와 이미지가 사용되지 않지만, 이를 가져오는 것이 오류를 유발할 수 있으므로 모킹해야 합니다.
위에서 구성에 참조된 파일
fileMock.js
와 styleMock.js
를 __mocks__
디렉토리 내에 생성하세요.// __mocks__/fileMock.js
module.exports = {
src: '/img.jpg',
height: 24,
width: 24,
blurDataURL: 'data:image/png;base64,imagedata',
}
// __mocks__/styleMock.js
module.exports = {}
정적 자산 처리에 대한 자세한 정보는 Jest 문서를 참조하세요.
@testing-library/jest-dom
은 .toBeInTheDocument()
와 같은 편리한 사용자 정의 매처 세트를 제공하여 테스트 작성을 용이하게 해줍니다. Jest
구성 파일에 다음 옵션을 추가하여 모든 테스트에서 사용자 정의 매처를 가져올 수 있습니다.
// jest.config.js
setupFilesAfterEnv: ['<rootDir>/jest.setup.js']
그런 다음 jest.setup.js
내에 다음 import
를 추가하세요.
// jest.setup.js
import '@testing-library/jest-dom/extend-expect'
각 테스트가 실행되기 전에 추가 설정 옵션을 추가해야하는 경우, 보통 jest.setup.js 파일에 추가합니다.
모듈 별칭을 사용하는 경우, Jest
를 구성하여 jsconfig.json
파일의 paths
옵션과 jest.config.js
파일의 moduleNameMapper
옵션을 일치시켜 가져올 수 있도록 해야합니다. 예를 들어:
// tsconfig.json 또는 jsconfig.json
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/components/*": ["components/*"]
}
}
}
// jest.config.js
moduleNameMapper: {
'^@/components/(.*)$': '<rootDir>/components/$1',
}
package.json
에 테스트 스크립트 추가
Jest 실행 파일을 package.json
스크립트에 추가하여 watch
모드로 실행합니다:
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"test": "jest --watch"
}
jest --watch
는 파일이 변경될 때마다 테스트를 다시 실행합니다. 더 많은 Jest CLI
옵션에 대해서는 Jest 문서를 참조하세요.
이제 테스트를 작성해 볼까요? 테스트를 작성하기 전에, npm run dev
명령어를 사용하여 Next.js
앱을 실행하고, 앱이 응답하는지 확인해야 합니다. 이것은 앱이 정상적으로 실행 중이며, 테스트 작성이 가능함을 나타냅니다.
테스트 파일은 __tests__
디렉토리에 저장하는 것이 좋습니다. 이것은 Jest
가 자동으로 인식하고 실행할 수 있는 디렉토리입니다. 예를 들어, 다음과 같은 파일 구조를 가진 pages/index.js
파일이 있다고 가정해 봅시다.
import styles from '../styles/Home.module.css'
export default function Home() {
return (
<div className={styles.container}>
<main className={styles.main}>
<h1 className={styles.title}>
Welcome to <a href="https://nextjs.org">Next.js!</a>
</h1>
<p className={styles.description}>
Get started by editing <code className={styles.code}>pages/index.js</code>
</p>
</main>
</div>
)
}
이제 __tests__
디렉토리에 index.test.js
파일을 만들어 보겠습니다.
import { render, screen } from '@testing-library/react'
import Home from '../pages/index'
describe('Home', () => {
it('renders a heading', () => {
render(<Home />)
const heading = screen.getByRole('heading', { name: /welcome to next\.js!/i })
expect(heading).toBeInTheDocument()
})
})
이 코드는 Home
컴포넌트가 <h1>
요소를 렌더링하는지 확인하는 단순한 테스트를 수행합니다. render
함수를 사용하여 Home
컴포넌트를 렌더링하고, screen
객체를 사용하여 DOM
요소를 가져옵니다. 마지막으로 expect
함수를 사용하여 DOM
요소가 실제로 존재하는지 확인합니다.
테스트를 실행하려면, npm run test
명령어를 실행하면 됩니다. 테스트 결과가 출력됩니다. 이제 Welcome to Next.js!
텍스트가 표시되는지 확인하는 테스트가 통과했음을 확인할 수 있습니다.
예상치 못한 변경사항이 있는지 추적하기 위해 <Home />
컴포넌트의 스냅샷 테스트를 추가할 수도 있습니다.
// __tests__/snapshot.js
import { render } from '@testing-library/react'
import Home from '../pages/index'
it('renders homepage unchanged', () => {
const { container } = render(<Home />)
expect(container).toMatchSnapshot()
})
참고: 테스트 파일은
pages
디렉터리 내에 포함되어서는 안됩니다.pages
디렉터리 내의 모든 파일은 라우트로 간주되기 때문입니다.
npm run test
명령어를 실행하여 테스트 스위트를 실행할 수 있습니다. 테스트가 통과하거나 실패한 후에는 더 많은 테스트를 추가하는 데 도움이 될 인터랙티브한 Jest 명령어 목록이 표시됩니다.
더 많은 자료를 원한다면, 아래 자료를 참고해보세요.
Next.js
커뮤니티에서는 유용한 패키지와 문서를 만들어 두었습니다.
Storybook
을 위한 next-router-mockGleb Bahmutov
에 의한 Cypress와 함께하는 테스트 미리보기 Vercel 배포