[Jest][유닛테스트] (1) 테스트 코드 작성전 설정하기, 에러 해결하기 ( jsx, unhandledPromiseRejection, TestingLibraryElementError)

프로젝트에서 중요한 부분인 예약 기간 선택 기능에 오류가 있는 것을 발견했다.
의도한 대로 동작하지 않는 부분이 있었는데,이것을 하나하나 브라우저에서 실행해 테스트하는 대신 테스트 코드를 작성해두고 사용해보기로 했다.

TDD를 제대로 진행해보고 싶었다.

그냥 새로운 프로젝트부터 TDD를 하기에는 시간도 부족했지만 기능 명세가 부족해 오히려 유연하게 대처하지 못할 위험이 있었다. 모든 기능이 구현 된 이후 리팩토링 단계에서 진행하면 테스트 범위와 내용이 명확해질 뿐더러 에러 해결에도 큰 도움을 받을 수 있을 것이라고 생각했다.

테스트 내용

테스트할 내용은 상세 페이지의 날짜 예약 컴포넌트의 함수들이다.

  • 날짜를 선택하세요 버튼 클릭 시 달력 창 열기
  • 달력 창이 렌더링 된 후 예약 불가능한 날짜 받아오기
  • 예약 불가능한 날짜로 달력에 선택 불가하도록 표시 (disableDates())
  • 체크인 날짜를 선택하면, checkFirstUnavailableDates()가 실행된다. 이 함수는 예약 불가능 한 날짜들을 순회하며 선택한 체크인 날짜 이후의 가장 첫번째 예약 불가 날짜를 리턴한다.
  • 이 첫번째 예약 불가날짜 이후의 모든 날짜들은 블락처리될 수 있도록 true를 반환한다.

그런데... 테스트 코드를 작성하기 이전 설정부터 여러 오류를 만났기 때문에, 이 부분부터 정리해보았다.

💪 마주한 에러들, 차근차근 해결해나가자!

자자... 그런데, 처음부터 순탄치가 않았다.
테스트 코드도 어떻게 작성해야할지 잘 모르겠는데, 설정부터가 난관이었다.

마주한 에러를 차근차근 정리해보자.

에러 1. jsx 문법 트랜스파일링

Support for the experimental syntax 'jsx' isn't currently enabled

jsx 문법을 jest가 이해할 수 없기 때문에 발생한 에러로, 바벨을 설치 한 뒤 설정을 따로 해주어야 한다.
preset-evn와 react 외에도 한 개가 더 있어야 하는데, 플러그인으로 jsx 문법을 변환할 수 있도록 설정해준다.

module.exports = {
  presets: [
    ['@babel/preset-env', { targets: { node: 'current' } }],
    '@babel/preset-react',
  ],
  plugins: ['@babel/plugin-transform-react-jsx'],
};

참고 문서:
참고한 스택오버플로우 답변
참고한 깃허브 babel-jest 관련 이슈
Jest 공식문서 - configuration
Jest 공식문서 - code-transformation


에러 2. 비동기 처리

[UnhandledPromiseRejection: This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). The promise rejected with the reason "ReferenceError: fetch is not defined".] {code: 'ERR_UNHANDLED_REJECTION'

fetch 함수가 에러를 캐치하는 구문없이 실행되기 때문에 발생한 에러로, 테스트할 컴포넌트 코드 중 fetch 함수 구분에 catch문을 넣어 예외처리를 해주면 된다.


  async function getUnavaliableDate() {
    try {
      const res = await fetch(unAvailableDatesUrl(stayIdParams, today));
      const resJson = await res.json();
      const undates = resJson.data.date;
      setUnavailableDates(undates);
    } catch (err) {
    ...

에러 3. 테스트 환경 설정 (jsdom)

공식문서를 보니 Jest로 테스트가 실행되는 환경은 기본적으로 노드인데, 웹앱을 개발할 경우 브라우저와 유사한 환경인 jsdom을 대신 사용하라고 한다.
@jest-environment 문서 블록을 파일 위에 추가하면 해당 파일에서 테스트에 사용할 환경을 명시할 수 있다.

아래와 같이 가장 위에 작성해주었다.

/**
 * @jest-environment jsdom
 */

import React from 'react';
import ReservationDate from './ReservationDate';
import { screen, render } from '@testing-library/react';
import userEvent from '@testing-library/user-event';

describe('ReservationDate', () => {
  let getUnavaliableDate;
  let startDate;
  ...

참고 문서:
Jest 공식문서 - test environment


😃 에러 해결! 테스트를 본격적으로 시작해보자.

이제 테스트 코드 작성에만 전념할 수 있는지 확인해보기 위해, 간단한 테스트를 작성 후 실행해보자.

테스트를 진행할 부분은 이곳, 상세페이지의 ReservationDate 컴포넌트이다. 날짜를 선택해주세요 버튼을 클릭하면 달력이 표시되고, 여기서 원하는 기간을 선택할 수 있다.

우선 설정을 마친 뒤 테스트를 정상적으로 실행할 수 있는 환경인지 확인해보기 위해, 간단한 테스트 코드까지만 작성 후 실행해보았다.

아래는 컴포넌트 렌더링 후 '날짜를 선택해주세요' 버튼을 찾아 클릭하는 것까지의 테스트 코드이다.

/**
 * @jest-environment jsdom
 */

import React from 'react';
import ReservationDate from './ReservationDate';
import { screen, render } from '@testing-library/react';
import userEvent from '@testing-library/user-event';

describe('ReservationDate', () => {
  let getUnavaliableDate;
  let startDate;
  let endDate;
  let setStartDate;
  let setEndDate;
  beforeEach(() => {
    getUnavaliableDate = jest.fn();
    setStartDate = jest.fn();
    setEndDate = jest.fn();
  });
  it('날짜선택 버튼 클릭 시 달력 창 띄우기', async () => {
    await render(
      <ReservationDate
        startDate={startDate}
        endDate={endDate}
        setStartDate={setStartDate}
        setEndDate={setEndDate}
      />
    );
    const selectDateButton = screen.getByText('날짜를 선택해주세요');
    userEvent.click(selectDateButton);
  });
});
  • 함수들은 jest.fn() 목함수를 사용했다.
  • userEvent를 사용해 이벤트를 처리했다.

휴, 성공했다!

테스트도 정상적으로 작동하고, 지금까지 작성한 테스트 코드도 통과했다.

이제, 본격적으로 자세한 테스트 코드를 작성해보자!

좋은 웹페이지 즐겨찾기