WeniVooks

검색

JavaScript 에센셜

Jest

1. Jest란?

Jest는 Meta(구 Facebook)에서 개발한 자바스크립트 테스트 프레임워크입니다. 테스트 코드를 찾고, 테스트를 실행하고, 결과를 판단하는 테스트 러너의 역할을 합니다.

Jest

2. Jest의 특징

Jest의 주요 특징 중 하나는 접근성을 고려한 테스트 방식입니다. Jest는 WAI-ARIA를 사용하여 HTML 요소를 탐색합니다. 이는 테스트 주도 개발(TDD)를 통해 접근성을 향상시키는 장점이 있습니다. Jest가 WAI-ARIA를 통해 요소를 찾을 수 있다면, 스크린 리더들 또한 WAI-ARIA를 이용하여 해당 요소를 찾을 수 있다는 것을 의미합니다.

WAI-ARIA란?
Web Accessibility Initiative - Accessible Rich Internet Applications의 약자로 HTML태그에 속성을 통한 추가 시맨틱을 제공하여 부족한 접근성을 개선합니다.

WAI-ARIA | W3CWAI-ARIA | MDN

3. Jest 기본 사용법

3.1. Jest 설치 및 실행

React 프로젝트에서 Jest를 사용하려면 다음 단계를 따릅니다.

  1. npx 명령어를 통해 리엑트 앱을 생성합니다.

    npx create-react-app my-app
    cd my-app
    npx create-react-app my-app
    cd my-app
  2. Jest는 create-react-app에 기본적으로 포함되어 있습니다. 따라서 별도의 설치가 필요하지 않습니다. 다음 명령어를 통해 테스트를 실행하면, watch 모드로 실행됩니다. watch 모드는 파일에 수정 사항이 감지될 경우 자동으로 테스트를 실행해줍니다.

    npm test
    npm test

노드 버전 이슈
만약 제스트 실행 시 노드 버전 때문에 다음과 같은 에러가 발생한다면 제스트와 관련된 패키지를 설치 해주셔야 합니다.

스크린샷 2022-01-26 오전 10.22.08.png

npm i -D --exact jest-watch-typeahead@0.6.5
npm i -D --exact jest-watch-typeahead@0.6.5
3.2. 기본 테스트 구조

Jest 테스트 파일의 기본 구조는 다음과 같습니다. Jest가 실행한 코드는 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();
});
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 함수: 개별 테스트를 정의합니다. 첫 번째 인자는 테스트 설명, 두 번째 인자는 테스트 로직을 나타냅니다.
  • render 함수: JSX의 가상돔을 생성합니다. 위 코드에서는 app 컴포넌트를 전달받습니다.
  • screen 객체: 생성된 가상돔에 접근하기 위한 전역 객체입니다.
    • getByText 함수: 인자로 전달된 텍스트를 가지는 돔 안의 요소를 찾습니다. 여기서는 정규표현식을 사용했습니다. /learn react/i 뒤에 붙은 i는 대소문자를 구분하지 않겠다는 의미입니다.
  • expect 함수: 테스트 결과를 검증합니다. 기대한 결과가 성공인지 실패인지를 판단합니다.
    • toBeInTheDocument: matcher 함수로, Jest의 .toBe() 함수와 같은 역할을 합니다.

React Testing Library
render와 screen은 모두 import { render, screen } from '@testing-library/react'; 에서 왔습니다. React Testing Library는 테스트를 위한 virtual DOM을 제공합니다. Jest는 바로 그 테스트 코드를 찾아서 실행합니다.

3.3. 요소 선택 및 이벤트 시뮬레이션

기본적인 문법과 내용에 대해 살펴봤습니다. 이제 간단한 기능을 테스트 해보겠습니다. Jest와 React Testing Library를 사용하여 요소를 선택하고 이벤트를 시뮬레이션하는 방법을 알아보겠습니다. 클릭 했을 때 색이 바뀌는 버튼을 만들고 테스트 해보겠습니다.

import { render, screen, fireEvent } from '@testing-library/react';
 
test('버튼 클릭 테스트', () => {
  render(<App />);
 
  const button = screen.getByRole('button', { name: 'Change to blue!' });
 
  expect(button).toHaveStyle({ backgroundColor: 'red' });
  fireEvent.click(button);
  expect(button).toHaveStyle({ backgroundColor: 'blue' });
});
import { render, screen, fireEvent } from '@testing-library/react';
 
test('버튼 클릭 테스트', () => {
  render(<App />);
 
  const button = screen.getByRole('button', { name: 'Change to blue!' });
 
  expect(button).toHaveStyle({ backgroundColor: 'red' });
  fireEvent.click(button);
  expect(button).toHaveStyle({ backgroundColor: 'blue' });
});
  • getByRole 함수: 접근성을 고려한 요소 선택 방법으로, 두 번째 인자로 찾아야 할 요소 안의 텍스트를 전달합니다.
  • toHaveStyle 함수: 요소가 특정한 CSS 스타일을 가지고 있는지 체크합니다.
  • fireEvent 객체: 가상돔과의 상호작용이 가능하도록 하는 객체입니다. 사용자 이벤트를 시뮬레이션할 수 있습니다.

코드에서 요소를 찾을 떄 getByRole 메서드를 사용합니다. role은 aria에서 사용하는 요소의 역할을 의미하는 속성으로, 특정 요소는 role을 명시하지 않아도 암묵적으로 가지고 있는 경우도 있습니다. role 값이 틀렸을 경우 제스트에서 제안을 해주기도 합니다. 암묵적인 role이 없는 요소의 경우 role 속성을 직접 명시해줍니다.

암무적 role

role의 종류
role의 종류에 대해 궁금하다면 다음 링크를 참고해보세요.

role의 종류

matcher 함수

이런 matcher 함수들의 종류가 궁금하다면 여기를 참고해 보세요.

matcher 함수

App.js에 다음 코드를 추가하여 테스트를 진행해보세요.

<div>
  <button style={{ backgroundColor: 'red' }}>Change to blue!</button>
</div>
<div>
  <button style={{ backgroundColor: 'red' }}>Change to blue!</button>
</div>

JSX에서 마크업에 표현식을 넣고싶다면 중괄호를 사용해야합니다.

버튼을 클릭했을 때 색이 바뀌는 기능을 추가해보겠습니다. App.js 상단에 import 구문을 추가합니다.

useState
useState 함수는 두 가지 요소를 가지는 배열을 반환합니다. 첫번째 요소는 state의 값, 두번째는 state의 값을 설정하는 함수입니다.

const [buttonColor, setColor] = useState('red');
const [buttonColor, setColor] = useState('red');

'red'는 초기값으로 설정되어 있습니다. setColor 함수는 buttonColor의 값을 바꿀 수 있는 함수를 참조합니다.

import { useState } from 'react';
 
const App = () => {
  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>
  );
};
import { useState } from 'react';
 
const App = () => {
  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>
  );
};
import { render, screen, fireEvent } from '@testing-library/react';
 
fireEvent.click(button);
expect(button).toHaveStyle({ backgroundColor: 'blue' });
expect(button.textContent).toBe('Change to red!');
import { render, screen, fireEvent } from '@testing-library/react';
 
fireEvent.click(button);
expect(button).toHaveStyle({ backgroundColor: 'blue' });
expect(button.textContent).toBe('Change to red!');

테스트를 돌려 결과를 확인합니다. 이제 npm start로 실제로 잘 동작하는지 확인해볼 단계입니다.

15.1 TDD