# Jest Snapshot Test

# 개요

Jest Snapshot Test는 UI가 예상치못하게 변경되지않도록 도와줍니다.

코드의 일부분을 수정했을때, 해당 코드에 의존하고 있는 여러 컴포넌트가 변화될 수 있는데 그 변화를 정확하게 예측하긴 어렵습니다.

스냅샷 테스트 코드를 작성하여컴포넌트의 변화를 알기 쉽게 합니다.

# 활용

먼저 스냅샷 테스트 코드를 작성합니다.

// button.react.test.js
import React from "react";
import renderer from "react-test-renderer";

it("button renders correctly", () => {
  const tree = renderer
    .create(
      <button type="button" onClick={() => {}}>
        OK
      </button>
    )
    .toJSON();
  expect(tree).toMatchSnapshot();
});

테스트코드를 실행시키면 아래와같이 __snapshot__ 디렉토리에 snap이라는 확장자로 된 파일이 하나 생성됩니다.

(정확히는 toMatchSnapshot 메소드를 실행시키면 파일이 생성됩니다.)

// __snapshot__/button.react.test.js.snap
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`button renders correctly 1`] = `
<button
  onClick={[Function]}
  type="button"
>
  OK
</button>
`;

template literal을 보시면 react component가 string형태로 생성되어 있습니다.

여기서 의도적으로 button의 type을 submit으로 바꿔보겠습니다.

// button.react.test.js
import React from "react";
import renderer from "react-test-renderer";

it("button renders correctly", () => {
  const tree = renderer
    .create(
      <button type="submit" onClick={() => {}}>
        OK
      </button>
    )
    .toJSON();
  expect(tree).toMatchSnapshot();
});

변경하면 아래와 같은 긴 테스트 실패 메시지가 콘솔에 출력됩니다

 FAIL  src/components/common/__tests__/Button.react.test.tsx
  ● button renders correctly

    expect(received).toMatchSnapshot()

    Snapshot name: `button renders correctly 1`

    - Snapshot
    + Received

      <button
        onClick={[Function]}
    -   type="button"
    +   type="submit"
      >
        OK
      </button>

      10 |     )
      11 |     .toJSON();
    > 12 |   expect(tree).toMatchSnapshot();
         |                ^
      13 | });
      14 |

      at Object.<anonymous> (src/components/common/__tests__/Button.react.test.tsx:12:16)

 › 1 snapshot failed.
Snapshot Summary
 › 1 snapshot failed from 1 test suite. Inspect your code changes or press `u` to update them.

+로 표시된 부분과 -로 표시된 부분을 보시면, 스냅샷과 현재상태를 비교해서 보여줍니다.

어떤 부분이 변경됐는지 명확하게 파악할 수 있습니다.

의도하지않은 변경이라면 코드를 수정하면 될 것이고

의도한 변경이라면 스냅샷을 변경(업데이트)해주면 됩니다.

콘솔에서(watch모드인 경우) 'u'를 누르면 자동으로 업데이트됩니다.

혹은 테스트 커맨드에 jest라면 --updateSnapshot 옵션을, react-scripts test라면 -u 옵션을 주면 됩니다.

# 인라인 스냅샷

__snapshot__/button.react.test.js.snap

이런식으로 파일과 디렉토리가 늘어나는게 별로 반갑지않다면 인라인 스냅샷을 하는 방법도 있습니다.

toMatchInlineSnapshot 을 사용하세요.

테스트를 실행하고나면 해당 메소드 파라미터에 template literal이 자동으로 생성되어 추가됩니다.

import React from "react";
import renderer from "react-test-renderer";

it("button renders correctly", () => {
  const tree = renderer
    .create(
      <button type="button" onClick={() => {}}>
        OK
      </button>
    )
    .toJSON();
  expect(tree).toMatchInlineSnapshot(`
    <button
      onClick={[Function]}
      type="button"
    >
      OK
    </button>
  `);
});

# 마무리

스냅샷 테스트가 오류를 뱉어낼때, 컴포넌트의 변경을 알기 쉽지만

반대로 컴포넌트가 의도적으로 변경된 것 인지 판단할 수 있는 개발자의 역량이 필요합니다.

만약 의도치않은 컴포넌트 에러가 났는데도 실수로 스냅샷 테스트를 업데이트하면 의도하지 않은 변경이라도 테스트에서 통과됩니다.

복잡한 컴포넌트에는 적용하기가 귀찮다.

공통으로 활용되는 컴포넌트들에 적용해놓으면 마음이 조금 더 편해질것같다.

인라인 스냅샷의 경우 pr로 코드리뷰를 한다면, 스냅샷 업데이트를 pr에 올리지않게 하기위해.. 조금 더 손이 간다. 그래서 개인적으로 추천하진않는다.

ref: https://jestjs.io/docs/en/snapshot-testing