Next.js Testing(테스팅)
[공지사항] 푸샤 깃허브 블로그 업데이트 사항
Cypress
Cypress는 E2E(End-to-End) 및 통합 테스트에 사용되는 테스트 러너입니다.
빠른 시작
with-cypress 예제와 함께 create-next-app
사용하여 빠르게 시작할 수 있습니다.
npx create-next-app@latest --example with-cypress with-cypress-app
수동 설정
Cypress
를 시작하려면 cypress 패키지를 설치하십시오:
npm install --save-dev cypress
package.json
스크립트 필드에 Cypress를 추가합니다:
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"cypress": "cypress open",
}
Cypress를 처음 실행하여 권장 폴더 구조를 사용하는 예제를 생성합니다:
npm run cypress
생성된 예제와 Cypress 문서의 첫 번째 테스트 작성 섹션을 살펴보고 Cypress에 익숙해지는 데 도움을 받을 수 있습니다.
첫 번째 Cypress 통합 테스트 만들기
다음 두 개의 Next.js 페이지를 가정합니다:
// pages/index.js
// pages/index.js
import Link from "next/link";
export default function Home() {
return (
<nav>
<Link href="/about">
<a>About</a>
</Link>
</nav>
);
}
// pages/about.js
export default function About() {
return (
<div>
<h1>About Page</h1>
</div>
);
}
탐색이 올바르게 작동하는지 확인하는 테스트를 추가합니다:
// cypress/integration/app.spec.js
describe("Navigation", () => {
it("should navigate to the about page", () => {
// index 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.json 파일에 "baseUrl": "http://localhost:3000"
을 추가하면 cy.visit("http://localhost:3000/")
대신 cy.visit("/")
를 사용할 수 있습니다.
Cypress 테스트 실행
Cypress는 실제 Next.js 애플리케이션을 테스트하고 있으므로 Cypress를 시작하기 전에 Next.js 서버가 실행 중이어야 합니다. 애플리케이션이 작동하는 방식과 더 유사하도록 프로덕션 코드에 대해 테스트를 실행하는 것이 좋습니다.
npm run build
및 npm run start
를 실행한 다음 다른 터미널 창에서 npm run cypress
를 실행하여 Cypress를 시작합니다.
참고: 또는 start-server-and-test
패키지를 설치하고 package.json
스크립트 필드에 추가할 수 있습니다. "test": "start-server-and-test start http://localhost:3000 cypress"
Cypress와 함께 Next.js 프로덕션 서버를 시작합니다. 새로운 변경 사항 후에는 애플리케이션을 다시 빌드해야 합니다.
지속적인 통합(Continuous Integration)을 위한 준비 (CI)
지금까지 Cypress를 실행하면 CI 환경에 적합하지 않은 상호적인(interactive) 브라우저가 열렸습니다. cypress run
명령을 사용하여 헤드리스로 Cypress를 실행할 수도 있습니다.
// package.json
"scripts": {
//...
"cypress": "cypress open",
"cypress:headless": "cypress run",
"e2e": "start-server-and-test start http://localhost:3000 cypress",
"e2e:headless": "start-server-and-test start http://localhost:3000 cypress:headless"
}
다음 리소스에서 Cypress 및 지속적 통합에 대해 자세히 알아볼 수 있습니다.
Playwright
Playwright는 단일 API로 Chromium, Firefox 및 WebKit을 자동화할 수 있는 테스트 프레임워크입니다. Playwright를 사용하여 모든 플랫폼에서 E2E(End-to-End) 및 통합 테스트를 작성할 수 있습니다. .
빠르게 시작하기
가장 빠르게 시작하는 방법은 with-playwright 예제와 create-next-app
함께 사용하는 것입니다. 그러면 Playwright가 모두 설정된 Next.js 프로젝트가 생성됩니다.
npx create-next-app@latest --example with-playwright with-playwright-app
수동 설정
npm init playwright
사용하여 기존 NPM
프로젝트에 Playwright를 추가할 수도 있습니다.
Playwright 수동으로 시작하려면 @playwright/test
패캐지를 설치하세요.
npm install --save-dev @playwright/test
package.json
스크립트에 Playwright 추가해주세요:
"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">
<a>About</a>
</Link>
</nav>
);
}
// pages/about.js
export default function About() {
return (
<div>
<h1>About Page</h1>
</div>
);
}
네비게이션(navigation)이 올바르게 작동하는지 확인하는 테스트를 추가합니다:
// e2e/example.spec.ts
import { test, expect } from "@playwright/test";
test("should navigate to the about page", async ({ page }) => {
// index 페이지에서 시작합니다(baseURL은 playwright.config.ts에 webServer 설정을 통하여 작동됩니다)
await page.goto("http://localhost:3000/");
//'About Page' 텍스트로 된 엘리먼트(element)를 찾고 클릭합니다
await page.click("text=About Page");
// 새로운 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"](https://playwright.dev/docs/api/class-testoptions#test-options-base-url)
를 추가를 해준다면 page.goto("http://localhost:3000/")
대신하여 page.goto("/")
사용할 수 있습니다.
Playwright 테스트 실행
Playwright는 실제 Next.js 애플리케이션을 테스트 중이므로 Playwright를 시작하기 전에 Next.js 서버가 실행 중이어야 합니다. 애플리케이션이 작동하는 방식과 더 유사하도록 프로덕션 코드에 대해 테스트를 실행하는 것이 좋습니다..
npm run build
와 npm run start
실행하고, 그리고 다른 윈도우 터미널에서 npm run test:e2e
실행하여 Playwright 테스트를 실행해줍니다.
참고: webServer
기능을 사용하여 Playwright가 개발 서버를 시작하고 완전히 사용히 다 사용할 수 있을 때까지 기다릴 수 있습니다.
지속적 통합(Continuous Integration, CI)으로 Playwright 실행
Playwright는 기본적으로 headed mode 실행합니다. Playwright 모든 dependencies 설치하기 위해서는 npx playwright install-deps
실행해주세요.
다음 리소스에서 Playwright 지속적 통합(Continuous Integration)에 대해 자세히 알아볼 수 있습니다:
Jest와 React Testing Library
Jest와 React Testing Library는 Unit Testing에 자주 함께 사용됩니다. Next.js 애플리케이션 내에서 Jest 사용을 시작할 수 있는 세 가지 방법이 있습니다:
- 빠른 시작 예시 참조하기
- Next.js Rust Compiler와 함께
- Babel과 함깨
다음 섹션에서는 이러한 각 옵션으로 Jest를 설정하는 방법을 설명합니다:
빠른 시작
create-next-app
을 사용하여 with-jest 예제와 함께 Jest 와 React Testing Library를 빠르게 시작할 수 있습니다:
npx create-next-app@latest --example with-jest with-jest-app
Jest 설정하기 (Rust Compiler와 함께)
Next.js 12 버전 릴리스 이후, Next.js에는 이제 Jest에 대한 기본 제공 구성이 있습니다.
Jest 설정하려면, jest
, @testing-library/react
, @testing-library/jest-dom
설치해주세요:
npm install --save-dev jest @testing-library/react @testing-library/jest-dom
jest.config.js
파일을 당신의 root 디렉토리에 만든 다음, 아래와 같이 추가해주세요.:
// jest.config.js
const nextJest = require('next/jest')
const createJestConfig = nextJest({
// 테스트 환경에서 next.config.js 및 .env 파일을 로드하려면 Next.js 앱의 경로를 제공하세요.
dir: './',
})
// Jest에 전달할 사용자 정의 구성 추가
const customJestConfig = {
setupFilesAfterEnv: ['<rootDir>/jest.setup.js'],
// baseUrl이 루트 디렉토리로 설정된 TypeScript를 사용하는 경우 별칭(alias')이 작동하려면 아래가 필요합니다.
moduleDirectories: ['node_modules', '<rootDir>/'],
testEnvironment: 'jest-environment-jsdom',
}
// createJestConfig는 next/jest가 비동기식인 Next.js 구성을 로드할 수 있도록 이 방법으로 내보내집니다.
module.exports = createJestConfig(customJestConfig)
내부에서, next/jest
는 다음을 포함여 자동으로 Jest를 구성합니다:
- [SWC]를 사용하여
transform
설정합니다(https://nextjs.org/docs/advanced-features/compiler) - 자동 모킹(mocking) 스타일 시트 (
.css
,.module.css
, 그리고 scss 변수들) 그리고 이미지 imports process.env
안에 있는.env
(그리고 모든 변수들) 로딩- 테스트 해결 및 변환에서
node_modules
무시 - 테스트 해결에서
.next
무시 - SWC 변환을 활성화하는 플래그에 대해
next.config.js
로딩
Jest 설정(Babel과 함께)
Rust Compiler를 옵트아웃하면 위의 패키지 외에 Jest를 수동으로 구성하고 babel-jest
및 identity-obj-proxy
를 설치해야 합니다.
다음은 Next.js용 Jest를 구성하는 데 권장되는 옵션입니다:
// jest.config.js
module.exports = {
collectCoverageFrom: [
"**/*.{js,jsx,ts,tsx}",
"!**/*.d.ts",
"!**/node_modules/**",
],
moduleNameMapper: {
// Handle CSS imports (with CSS modules)
// https://jestjs.io/docs/webpack#mocking-css-modules
"^.+\\.module\\.(css|sass|scss)$": "identity-obj-proxy",
// Handle CSS imports (without CSS modules)
"^.+\\.(css|sass|scss)$": "<rootDir>/__mocks__/styleMock.js",
// Handle image imports
// https://jestjs.io/docs/webpack#handling-static-assets
"^.+\\.(jpg|jpeg|png|gif|webp|avif|svg)$": `<rootDir>/__mocks__/fileMock.js`,
// Handle module aliases
"^@/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 문서에서 각 구성 옵션에 대해 자세히 알아볼 수 있습니다.
핸들링 스타일시트 그리고 이미지 불러오기(imports)
Styleheets and images aren’t used in the tests but importing them may cause errors, so they will need to be mocked. Create the mock files referenced in the configuration above - fileMock.js and styleMock.js - inside a mocks directory:
// **mocks**/fileMock.js
module.exports = "test-file-stub";
// **mocks**/styleMock.js
module.exports = {};
"Failed to parse src "test-file-stub" on 'next/image'"
문제가 발생할 경우, fileMock에 ‘/’ 추가하세요.
// **mocks**/fileMock.js
module.exports = "/test-file-stub";
정적 자산(assets) 처리에 대한 자세한 내용은 Jest 문서를 참조하세요.
선택 사항: 사용자 지정 매처로 Jest 확장
@testing-library/jest-dom
에는 .toBeInTheDocument()
와 같은 편리한 custom matchers 세트가 포함되어 있어 테스트를 더 쉽게 작성할 수 있습니다. Jest 구성 파일에 다음 옵션을 추가하여 모든 테스트에 대한 사용자 지정 매처를 가져올 수 있습니다
// jest.config.js
setupFilesAfterEnv: ["<rootDir>/jest.setup.js"];
그런 다음 jest.setup.js
내부에 다음 가져오기를 추가합니다:
// jest.setup.js
import "@testing-library/jest-dom/extend-expect";
각 테스트 전에 더 많은 설정 옵션을 추가해야 하는 경우 위의 jest.setup.js
파일에 추가하는 것이 일반적입니다.
선택 사항: 절대 가져오기(Imports) 및 모듈 경로 별칭(Aliases)
프로젝트에서 Module Path Aliases를 사용하는 경우 jsconfig.json
파일의 경로 옵션을 jest.config.js
파일의 moduleNameMapper
옵션과 일치시켜 가져오기를 해결하도록 Jest를 구성해야 합니다. 예를 들어:
// tsconfig.json or jsconfig.json
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/components/*": ["components/*"]
}
}
}
// jest.config.js
moduleNameMapper: {
'^@/components/(.*)$': '<rootDir>/components/$1',
}
테스트 만들기:
package.json에 테스트 스크립트 추가
watch 모드의 Jest 실행 파일을 package.json
스크립트에 추가합니다:
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"test": "jest --watch"
}
jest --watch
는 파일이 변경되면 테스트를 다시 실행합니다. 더 많은 Jest CLI 옵션은 Jest Docs를 참조하세요.
첫 번째 테스트 만들기
이제 프로젝트에서 테스트를 실행할 준비가 되었습니다. 프로젝트의 루트 디렉토리에 있는 __tests__
폴더에 테스트를 추가하여 Jests 규칙을 따르세요.
예를 들어 <Home />
구성 요소가 제목을 성공적으로 렌더링하는지 확인하는 테스트를 추가할 수 있습니다.
// __tests__/index.test.jsx
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 />
구성요소에 대한 예기치 않은 변경 사항을 추적하기 위해 스냅샷 테스트를 추가합니다.
// __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();
});
참고: 페이지 디렉토리 내부의 모든 파일은 경로로 간주되기 때문에 테스트 파일은 페이지 디렉토리 내부에 포함되어서는 안 됩니다.
테스트 suite 실행
npm run test
를 실행하여 테스트 스위트를 실행합니다. 테스트가 통과하거나 실패하면 더 많은 테스트를 추가할 때 도움이 될 대화식 Jest 명령 목록이 표시됩니다.
더 많은 정보를 얻으려면 다음 리소스가 도움이 될 수 있습니다.
- Jest Docs
- React Testing Library Docs
- Testing Playground - 요소(elements)를 일치시키기 위해 좋은 테스트 방법을 사용하십시오.
커뮤니티 패키지 및 예제
Next.js 커뮤니티는 도움이 될 만한 패키지와 기사를 만들었습니다:
- next-page-tester DOM 통합 테스팅을 위해서.
- next-router-mock 스토리북을 위해서.
- Test Preview Vercel Deploys with Cypress by Gleb Bahmutov.
Cypress 장점
- 관련 커뮤니티 및 자료(stackoverflow ...) 등이 많다
- 배우기 굉장히 쉽고 사용하기도 간편한다(dashboard)
- cypress open 실행 후, 테스트 코드 수정 후 저장하면 자동으로 테스트 재실행된다.
- 에러 메세지에 대한 설명이 비교적 잘되어있다.
Playwright 장점
- Playwright는 한 번의 command(명령어) 실행으로 여러 브라우저 및 디바이스 동시에 테스트 가능하다
- 보통 url 변경되는 테스트 코드 에러가 많이 발생하는데 Playwright async/await을 지원해서 간편하다
- 테스트 코드를 여러가지 언어로 실행 가능하다.
참고 영상
참조 문서 및 사이트
댓글남기기