Jest란?
제스트는 테스트 코드를 찾고, 테스트를 실행하고, 실패인지 성공인지를 판단하는 테스트 러너입니다.
facebook 에서 개발하고 관리하고 있습니다. (https://jestjs.io/)
제스트만의 특징은
Html 요소를 탐색하는데 접근성 마커 즉, aria를 이용합니다. TDD 를 작성함으로서 자연스럽게 접근성을 향상시키는 장점이 있습니다. 제스트가 요소를 aria를 통해 찾을 수 있다는것은 스크린 리더들도 찾을 수 있다는 얘기입니다.
1. 제스트를 사용해보겠습니다.
- npx 명령어를 통해 리엑트 앱을 생성해봅시다.
npx create-react-app color-button
- react 설치가 완료되고 프로젝트가 생성되었습니다. 터미널을 통해 제안을 해주는군요 🙂

- 설치가 완료되었으면 npm test를 해봅시다.
제스트가 와치모드로 실행되는것을 확인 할 수 있습니다.
와치모드는 파일에 수정 사항이 감지될 경우 자동으로 테스트를 실행해주는 상태를 의미합니다.
만약 제스트 실행 시 노드 버전 이슈로

이런 에러가 발생한다면 제스트와 관련된 패키지를 설치 해주셔야 합니다.
npm i -D --exact jest-watch-typeahead@0.6.5
- a 를 눌러 테스트를 실행해봅니다.
아무런 테스트 코드를 작성하지 않았지만 뭔가 성공했습니다! ㅎㅎ
일단 q를 눌러 test 상태에서 빠져나갑니다.
2. 자 이제 내부적으로 어떻게 테스트가 실행되었는지 살펴보겠습니다.
- 제스트가 실행 코드는 App.test.js 에 있습니다.
import { render, screen } from '@testing-library/react'; import App from './App'; test('renders learn react link', () => { render(<App />); const linkElement = screen.getByText(/learn react/i); expect(linkElement).toBeInTheDocument(); });
- Test 함수 : 글로벌 함수. 두 가지 인자를 가집니다. 첫번째 인자는 문자열로 테스트의 설명입니다. 자스민에서는 describe 입니다. 두번째 인자는 테스트를 실행하는 테스트 함수입니다.
- Render 함수 : 인자로 받는 JSX의 가상돔을 생성합니다. 여기서는 app 컴포넌트를 전달받습니다.
- Screen : 생성된 가상돔에 접근하기 위한 전역 객체입니다.
render와 screen은 모두 import { render, screen } from '@testing-library/react'; 에서 왔습니다.
- getByText 함수 : 인자로 전달된 텍스트를 가지는 돔 안의 요소를 찾습니다. 여기서는 정규표현식을 사용했군요. /learn react/i 뒤에 붙은 i는 대소문자를 구분하지 않겠다는 의미입니다.
- expect 함수 : 익숙하죠? 제스민에도 있었습니다. 기대한 결과가 성공인지 실패인지 판단하는 함수입니다.
- .toBeInTheDocument : matcher 함수입니다. 제스민의 .toBe() 함수가 기억나시나요? 제스트에도 존재합니다.
- 이번에는 테스트를 실패 해봅시다. App.js 의 텍스트를 ‘Learn View’ 로 변경해보고 npm test를 실행 해봅니다.
- 수정 했던 코드를 원상 복구해서 와치 모드가 잘 작동하는지도 확인해 봅시다. 🙂
3.간단한 기능테스트를 직접 해봅시다.
기본적인 문법과 내용에 대해 살펴봤습니다. 이제 간단한 기능을 테스트 해보겠습니다!
- App.js 안의 return 키워드 안의 내용들과 App.test.js 안의 테스트 함수 안의 내용을 모두 지웁니다.
- 누르면 색이 바뀌는 버튼을 만들고 테스트 해보겠습니다. App.test.js 파일에 테스트 코드를 추가합니다.
test('버튼이 제대로 잘 작동하고 있습니까?', () => { render(<App />); const button = screen.getByRole('button', { name: 'change to blue!' }); expect(button).toHaveStyle({ backgroundColor: 'red' }); });
- 코드에서 요소를 찾을 때 getByRole 로 찾는 것이 보입니다. role은 aria에서 사용하는 요소의 역할을 의미하는 속성입니다. 특정 요소는 role 을 명시하지 않아도 암묵적으로 가지고 있는 경우도 있습니다.(https://www.w3.org/TR/html-aria/#docconformance)
- role 값이 틀렸을 경우 친절하게 제스트에서 제안을 해주기도 합니다.
- 암묵적인 role이 없는 요소의 경우 role 속성을 직접 명시해줍니다.
role의 종류에 대해 궁금하다면 여기를 참고해보세요. https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles
- getByRole함수는 두번째 인자로, 찾아야할 요소 안의 텍스트를 지정할 수 있습니다.
- toHaveStyle 함수 : 요소가 특정한 CSS 스타일을 가지고 있는지 체크합니다.
이런 matcher 함수들의 종류가 궁금하다면 여기를 참고해 보세요.
- 이제 테스트를 진행해 보겠습니다. 어떤 결과가 보이시나요?
- 이제 App.js를 수정해보겠습니다. 아래 코드를 추가해 봅시다.
<div> <button style={{ backgroundColor: 'red' }}>change to blue!</button> </div>
Jsx 에서 마크업에 표현식을 넣고싶다면 중괄호를 사용해야합니다.
- 다시 테스트를 돌려봅시다.
- 이제 기능을 추가해봅시다. 버튼을 클릭했을 때 색이 변하는지 확인하는 테스트입니다.
import { render, screen, fireEvent } from '@testing-library/react';
- import 구문에 fireEvent를 추가했습니다. 가상돔과의 상호작용이 가능하도록 하는 객체입니다. 계속해서 아래 코드를 추가합니다.
fireEvent.click(button); expect(button).toHaveStyle({ backgroundColor: 'blue' }); expect(button.textContent).toBe('change to red!');
- 테스트에 실패합니다.
- 아직 버튼을 클릭했을 때의 기능을 추가하지 않았기 때문입니다. useState 함수를 통해 현재의 버튼 색을 저장하도록 하겠습니다. App.js 상단에 import 구문을 추가합니다.
import { useState } from 'react';
- useState 함수는 두 가지 요소를 가지는 배열을 반환합니다. 첫번째 요소는 state의 값, 두번째는 state의 값을 설정하는 함수입니다.
const [buttonColor, setColor] = useState('red');
- ‘red’ 문자열이 buttonColor 상수의 값이 됩니다. setColor 는 buttonColor 상수의 값을 바꿀 수 있는 함수를 참조합니다.
- 이제 이벤트를 달아보겠습니다.
const [buttonColor, setColor] = useState('red'); const newColor = buttonColor === 'red' ? 'blue' : 'red'; return ( <div> <button style={{ backgroundColor: buttonColor }} onClick={() => setColor(newColor)}>change to {newColor}!</button> </div> );
- 테스트를 돌려보고 결과를 확인합니다.
- 이제 npm start로 실제로 잘 동작하는지 확인해볼 단계입니다.