본문 바로가기

Jest

[Jest] React-Testing-Library로 unmount 테스트 하기

개요

  • unmount 시 어떤 함수를 실행해주는지 React-Testing-Library와 Jest로 테스트해보려고 한다.

접근

  • 기본적으로 React-Testing-Library의 render 함수는 해당 컴포넌트를 렌더링한다.
  • 그럼 unmount 테스트를 위해서는 render 함수를 반환하는 함수를 호출해주면 된다.

코드

// Receipt.tst
import { useEffect } from 'react';
import useCartStore from '../../hook/useCartStore';
import convertKRW from '../../utils/convertKRW';
import getTotalPrice from '../../utils/getTotalPrice';

type ReceiptProps = {
  goToIntro:() => void
}

function Receipt({ goToIntro }:ReceiptProps) {
  const [{ menu }, cartStore] = useCartStore();
  const totalPrice = getTotalPrice(menu);

  useEffect(() => () => {
    cartStore.clearCart();
  }, []);
  return (
    <div>
      <p>
        주문내역
        {menu.length}
        개
      </p>

      <ul>
        {menu.map((food) => (
          <li key={food.id}>
            <span>{`${food.name} ${convertKRW(food.price)}`}</span>
            <button type="button" onClick={() => cartStore.removeCart(food.id)}>X</button>
          </li>
        ))}
      </ul>

      <p>
        총 결제 예상금액
        {convertKRW(totalPrice)}
      </p>

      <button type="button" onClick={goToIntro}>취소</button>
      <button type="button">주문하기</button>
    </div>
  );
}

export default Receipt;
  • unmount 시 cartStore의 clearCart() 로직을 실행해준다.
import { fireEvent, render, screen } from '@testing-library/react';
import Receipt from '.';
import fixture from '../../fixture';

let menu = fixture.food;

const clearCart = jest.fn();

jest.mock('../../hook/useCartStore', () => () => [
  { menu },
  { clearCart },
]);

const goToIntro = jest.fn();

const context = describe;
describe('Receipt 컴포넌트', () => {
  function renderReceipt() {
    console.log('renderReceipt');
    return render(<Receipt goToIntro={goToIntro} />);
  }

  beforeEach(() => {
    jest.clearAllMocks();
  });

  it('올바르게 렌더링 된다.', () => {
    render(<Receipt goToIntro={goToIntro} />);
    screen.getByText('취소');
    screen.getByText('주문하기');
  });

  context('취소버튼을 클릭하면', () => {
    it('인트로 페이지로 이동한다.', () => {
      render(<Receipt goToIntro={goToIntro} />);
      fireEvent.click(screen.getByText('취소'));
      expect(goToIntro).toHaveBeenCalledTimes(1);
    });

    it('주문내역을 초기화한다.', () => {
      const { unmount } = renderReceipt();
      unmount();
      expect(clearCart).toHaveBeenCalledTimes(1);
    });
  });
  ...
});
  • render 함수를 호출하면 그 반환값으로 RenderResult를 반환한다.
  • RenderResult에는 아래와 같은 속성들이 있고 그 중 unmount를 사용하면 된다.
// @testing/library > react > types > index.d.ts
export type RenderResult<
  Q extends Queries = typeof queries,
  Container extends Element | DocumentFragment = HTMLElement,
  BaseElement extends Element | DocumentFragment = Container,
> = {
  container: Container
  baseElement: BaseElement
  debug: (
    baseElement?:
      | Element
      | DocumentFragment
      | Array<Element | DocumentFragment>,
    maxLength?: number,
    options?: prettyFormat.OptionsReceived,
  ) => void
  rerender: (ui: React.ReactElement) => void
  unmount: () => void
  asFragment: () => DocumentFragment
} & {[P in keyof Q]: BoundFunction<Q[P]>}