페이스북에서 만들어서 React와 더불어 많은 자바스크립트 개발자들로 부터 좋은 반응을 얻고 있는 테스팅 라이브러리이다.
Jest 이전에는 자바스크립트 코드를 테스트하라면 여러가지 테스팅 라이브러리를 조합해서 사용했다!
예를 들어, Mocha나 Jasmin을 Test Runner로 사용하고, Chai나 Expect와 같은 Test Mathcher를 사용했으며, 또한 Sinon과 Testdouble 같은 Test Mock 라이브러리도 필요했었다.
이 라이브러리들은 굉장히 유사하지만 살짝씩 다른 API를 가지고 있었기 때문에, 여러 프로젝트에 걸쳐서 일하는 자바스크립트 개발자들에게 혼란을 주기도 했었다.
하지만 Jest는 라이브러리 하나만 설치하면, Test Runner와 Test Mathcher 그리고 Test Mock 프레임워크까지 제공해주기 때문에 현재 대세라고 말할 수 있다.
yarn add --dev jest
npm install --save-dev jest
설치가 끝나면 package.json에 아래 코드를 추가한다.
"scripts": {
"test": "jest",
},
yarb test
로 스크립트를 실행한다.
test할 파일을 만들때에는
테스트 함수파일명.test.js
function sum(a, b) {
return a + b;
}
module.exports = sum;
const sum = require("./sum");
test("adds 1 + 2 to equal 3", () => {
expect(sum(1, 2)).toBe(3);
});
npm test를 실행시키면 아래와 같은 결과가 나온다.
toBe(8)을 넣고 다시 테스트를 진행해보면, 어디에서 실패되었는지 정확하게 알려준다.
function sum(a, b) {
return a + b;
}
export default sum;
import sum from "./sum";
test("adds 1 + 2 to equal 3", () => {
expect(sum(1, 2)).toBe(8);
});
이후 npm test를 진행해보자.
jest는 CommonJS 모듈 시스템을 사용하기 때문에 ES6 문법을 사용하면 에러가 나타난다!
따라서 우리는 Babel 설정을 진행해주어야 한다.
npm install -D jest @types/jest @babel/core @babel/preset-env
yarn add --dev babel-jest @babel/core @babel/preset-env
프로젝트 루트에 babel.config.js을 생성하여 현재 노드 버전에 맞는 Babel을 설정한다.
{
"presets": ["@babel/preset-env"]
}
{
"collectCoverage": true,
"moduleFileExtensions": ["js", "mjs"],
"transform": {
"^.+\\.js$": "babel-jest",
"^.+\\.mjs$": "babel-jest"
},
"testRegex": "((\\.|/*.)(test))\\.js?$"
}
이후 npm test를 진행하면 ES6 문법을 사용할 수 있다.
function sum(a: number, b: number): number {
return a + b;
}
export default sum;
타입스크립트로 변환 후 npm test를 해주면 어마어마한 에러가 발생하게 된다😭
❗️ 하지만 이것도 패키지를 다운받아 해결할 수 있다 ❗️
npm install --dev @babel/preset-typescript
yarn add --dev @babel/preset-typescript
{
presets: [
[
'@babel/preset-env',
{targets: {node: 'current'}}
],
'@babel/preset-typescript', // 👈 여기 !!
],
};
{
"preset": "ts-jest", // 👈 여기
"collectCoverage": true,
"moduleFileExtensions": ["js", "mjs", "ts"], // 👈 여기
"transform": {
"^.+\\.js$": "babel-jest",
"^.+\\.mjs$": "babel-jest"
},
"testRegex": "((\\.|/*.)(test))\\.js?$"
}
이후 npm test를 진행하면 타입스크립트를 사용할 수 있다.
import sum from "./sum";
test("sum 1 + 2 to equal 3", () => {
expect(sum(1, 2)).toBe("3");
});
그렇다면 리액트는 어떻게 사용할까?
리액트 공식문서에서 사용을 권장하는 라이브러리는 react-testing-library이며 대체방안으로 Enzyme 이 있다.
react-testing-library vs Enzyme
react-testing-library
- 실제 DOM 에 대해서 신경을 더 많이 쓰고 컴포넌트의 인스턴스에 대해서 신경쓰지 않는다.
- 실제 화면에 무엇이 보여지는지, 어떠한 이벤트가 발생했을때 화면에 원하는 변화가 생겼는지 확인하기에 조금 더 최적화되어있다.
Enzyme
- 테스트 코드를 작성 할 때에는 컴포넌트의 내부 기능을 자주 접근한다.
- props, state 를 확인하고, 컴포넌트의 내장 메서드를 직접 호출하기도 한다.
1️⃣ react-testing-library 설치
// CRA
npx create-react-app jest-react
yarn create jest-react
// 설치
npm i -D @testing-library/react @testing-library/jest-dom
yarn add --dev @testing-library/react @testing-library/jest-dom
import "@testing-library/jest-dom";
2️⃣ 컴포넌트 및 테스트 작성
import React from "react";
const Profile = ({ username, name }) => {
return (
<div>
<b>{username}</b>
<span>({name})</span>
</div>
);
};
export default Profile;
import React from "react";
import { render, screen } from "@testing-library/react";
import Profile from "./Profile";
describe("<Profile />", () => {
it("matches snapshot", () => {
const utils = render(<Profile username="Happhee" name="서히" />);
expect(utils.container).toMatchSnapshot();
});
it("shows the props correctly", () => {
const utils = render(<Profile username="Happhee" name="서히" />);
screen.getByText("Happhee"); // Happhee 라는 텍스트를 가진 엘리먼트가 있는지 확인
screen.getByText("(서히)"); // (서히) 이라는 텍스트를 가진 엘리먼트가 있는지 확인
screen.getByText(/서/); // 정규식 /서/ 을 통과하는 엘리먼트가 있는지 확인
});
});
toMatchSnapshot
을 실행 👉 __snapshots__/Profile.test.js.snap
이 생성
이 칭구는 컴포넌트를 수정했을 때 원하는 방식으로 렌더되는지 비교하기 위해 생성된다!
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`<Profile /> matches snapshot 1`] = `
<div>
<div>
<b>
Happhee
</b>
<span>
(
서히
)
</span>
</div>
</div>
`;
"Happ"에 대한 검사를 진행하도록 변경하면
it("shows the props correctly", () => {
const utils = render(<Profile username="Happhee" name="서히" />);
screen.getByText("Happ");
screen.getByText("(서히)");
screen.getByText(/서/);
});
아래와 같이 에러가 뜨게 된다!
describe
test들을 블록으로 묶어준다.
it
각 test들을 의미한다.
render
리액트 컴포넌트를 렌더링 시켜준다.
- matcher
위의 코드에서 toMatchSnapshot(), toBe와 같은 것
이외에도 다양한 matcher들이있다.