create next app(CNA)에 typescript 옵션을 붙여 프로젝트를 생성한 후 Jest를 설정하는 방법입니다. CNA 을 사용할 경우 Jest 세팅이 되어 있지 않기 때문에 별도로 세팅을 해 주어야 합니다. 공식 문서 링크
1. 필요 패키지 설치
테스트에 필요한 파일들을 설치합니다.
$ yarn add -D @testing-library/dom @testing-library/jest-dom @testing-library/react @testing-library/user-event babel-jest jest jest-dom node-mocks-http ts-jest ts-loader
각 패키지의 기능은 다음과 같습니다.
- @testing-library 패키지들, babel-jest : @testing-libaray는 리액트 컴포넌트를 가상 브라우저에서 테스트하기 위한 기능들을 제공합니다. babel-jest는 테스트 코드를 변환하고 컴파일합니다.
- ts-jest, ts-loader : Jest에서 타입스크립트 기반의 코드를 테스트할 수 있게 해 줍니다.
- node-mocks-http : Next API routes를 테스트할 때 필요한 request, response 객체의 mock을 생성해 줍니다.
2. 설정 파일 구성
1) tsconfig 파일에 설정을 추가해 줍니다.
CNA에 타입스크립트 플래그를 사용했다면 tsconfig 파일이 이미 생성되어 있습니다(없을 경우 yarn dev를 한 번 실행하면 생성된다고 합니다). 따로 설정을 만질 것은 없습니다. 그냥 코드 작성 시 편의를 위해 Path alias만 추가해 줍니다. 아래와 같은 설정을 추가하면 relative path를 일일히 적을 필요 없이 @component 식으로 import 할 수 있어 편리합니다.
// tsconfig.json
{
"compilerOptions": {
{...}
"baseUrl": ".",
"paths": {
"@components/*": ["components/*"],
"@styles/*": ["styles/*"],
"@pages/*": ["pages/*"],
"@hooks/*": ["hooks/*"]
}
{...}
}
2) babelrc 파일에 프리셋을 설정해 줍니다.
// .babelrc.json
{
"presets": ["next/babel"]
}
3) jest.config.json 파일을 설정해 줍니다.
root path에 jest.config.json 파일을 생성 후 설정들을 넣어줍니다. 아래 설정은 공식 문서에서 추천하는 설정입니다.
// jest.config.json
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>/styles/__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
"^@pages/(.*)$": "<rootDir>/pages/$1",
"^@components/(.*)$": "<rootDir>/components/$1"
},
setupFilesAfterEnv: ["<rootDir>/jest.setup.js"],
testPathIgnorePatterns: ["<rootDir>/node_modules/", "<rootDir>/.next/"],
testEnvironment: "jsdom",
transform: {
// Use babel-jest to transpile tests with the next/babel preset
// 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)$"]
};
- setupFilesAfterEnv
테스트 실행 전에 셋업해야 할 내용들을 담은 파일입니다. 예시에서는 jest.setup.js 이라는 파일을 사용했습니다. 이 파일은 자동 생성되지 않기 때문에 반드시 root에 jest.setup.js 파일을 생성해 주셔야 합니다. 공식 문서에서는 간단하게 다음 코드만 사용하고 있습니다.
// jest.setup.js
import '@testing-library/jest-dom/extend-expect'
@testing-library/jest-dom 에 있는 custom matcher를 사용하기 위한 구문입니다.
- Path alias 설정(moduleNameMapper)
절대 경로를 쓰지 않고 alias를 사용하기 위한 설정입니다. 타입스크립트의 경우 먼저 tsconfig 에 baseUrl과 paths를 설정해 주어야 합니다. 그 후, moduleNameMapper에 설정을 추가해 주면 됩니다. 저는 @component/* 같은 형태로 path alias를 사용하고 싶어서 아래와 같이 설정을 추가했습니다.
moduleNameMapper: {
...
// Handle module aliases
"^@pages/(.*)$": "<rootDir>/pages/$1",
"^@components/(.*)$": "<rootDir>/components/$1"
},
위와 같이 설정해 두면 테스트 파일에서 import 할 때 매번 절대 경로를 적을 필요 없이 @components/... 를 사용해 components 폴더의 파일들을 가져올 수 있습니다.
3. 컴포넌트 테스트
컴포넌트 테스트를 위해 먼저 테스트 폴더들을 생성해 줍니다. root에 __test__ 폴더를 만들고 하위 폴더들을 생성해 줍니다. 마지막으로 page의 index를 테스트하기 위한 index.test.jsx를 생성합니다.
그 후, 테스트 코드를 작성합니다.
// __test__/page/index.test.tsx
import React from "react";
import { render, screen } from "@testing-library/react";
import Home from "@pages/index"; // 위에서 path alias를 미리 설정해 두어서 편리하게 사용!
describe("Home", () => {
it("renders a heading", () => {
render(<Home />);
const heading = screen.getByRole("heading", {
name: /welcome to next\.js!/i
});
expect(heading).toBeInTheDocument();
});
});
# document is not defined 에러 처리
● App › renders without crashing
The error below may be caused by using the wrong test environment, see https://jestjs.io/docs/configuration#testenvironment-string.
Consider using the "jsdom" test environment.
ReferenceError: document is not defined
테스트 코드 실행 시, 위와 같은 에러가 발생할 수 있습니다. 이는 Jest의 기본 테스트 환경이 node로 설정되어 있기 때문입니다. node에는 DOM 객체가 없기 때문에 react test liblary가 제대로 작동할 수 없습니다. 컴포넌트 테스트를 위해서는 테스트 환경을 jsdom으로 변경해 주어야 합니다. 해결책은 크게 두 가지가 있습니다.
1. jest.config.js에 설정을 추가하는 방법
jest.config.js에 "testEnvironment": "jsdom" 을 추가합니다. 설정을 추가하면 전역적으로 테스트 환경이 jsdom이 됩니다.
2. 각 테스트 파일에 @jest-environment jsdom 주석 추가
/**
* @jest-environment jsdom
*/
각 테스트 파일 상단에 위와 같은 주석을 추가합니다. 이 방법은 해당 파일만 jsdom 환경에서 실행되도록 합니다.
4. API route 테스트
API route 테스트를 위해서는 http request 와 response를 mock 해야 합니다. node-mock-http 모듈을 사용해 간단하게 이 기능을 mock 할 수 있습니다.
테스트를 위해 아래와 같이 코드를 작성하고 실행합니다. CNA 사용 시 기본적으로 page/api 에 hello.ts 라는 api가 작성되어 있습니다. 이 api를 node-mock-http 에서 제공하는 createMocks 함수로 간단하게 mocking 하여 테스트하는 코드입니다.
import { createMocks } from 'node-mocks-http';
import handler from '@pages/api/hello';
describe('/api/hello', () => {
test('returns a message with the specified name', async () => {
const { req, res } = createMocks({
method: 'GET',
});
await handler(req, res);
expect(res._getStatusCode()).toBe(200);
expect(JSON.parse(res._getData())).toEqual(
expect.objectContaining({
name: 'John Doe',
})
);
});
});
참조
Setting up a Next.js Application with TypeScript, JIT Tailwind CSS and Jest/react-testing-library
'dev > React' 카테고리의 다른 글
react 자식 컴포넌트의 함수를 부모 컴포넌트에 내보내기 (0) | 2022.08.18 |
---|---|
redux를 이용해 react modal을 효율적으로 관리하는 방법 (0) | 2022.01.07 |
Redux 개념 이해하기 (0) | 2021.03.08 |
[번역글] react functional component에서 setState를 동기식으로 사용하기 (1) | 2021.03.08 |
React Hooks (0) | 2020.08.31 |