FFFT

主にwebプロダクト開発に関連する話をつらつらと

【create-react-app】jestでuuidを利用するコンポーネントのテストをする

create-react-appではテストランナーにjestが利用されています。

create-react-app.dev

今回、uuidを利用するコンポーネントでスナップショットテストを書く際に少し調べたのでまとめます。

jestjs.io

こちらのissueでいろいろ話されていますが、jest.mockを使うやり方が良さそう。

github.com

サンプルのアプリケーションを作成してまとめます。
プロジェクトを作成して、uuidのパッケージを追加。App.jsx(App.js)を下記のように修正します。

import React from 'react';
import './App.css';
import { v4 as uuid } from 'uuid';

function App() {
  return (
    <div className="App">
      <p>{uuid()}</p>
    </div>
  );
}

export default App;

App.test.jsxを下記のように修正。

import React from 'react';
import { render } from '@testing-library/react';
import App from './App';

test('renders currently', () => {
  const {container} = render(<App />);
  expect(container).toMatchSnapshot();
});

一度、testを実行します。

$ yarn run test

こんな感じで通るかと思います。

 PASS  src/App.test.jsx
  ✓ renders currently (18ms)

 › 1 snapshot written.
Snapshot Summary
 › 1 snapshot written from 1 test suite.

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   1 written, 1 total
Time:        1.409s
Ran all test suites related to changed files.

Watch Usage
 › Press a to run all tests.
 › Press f to run only failed tests.
 › Press q to quit watch mode.
 › Press p to filter by a filename regex pattern.
 › Press t to filter by a test name regex pattern.
 › Press Enter to trigger a test run.

ただ、uuidを利用したコンポーネントのため、都度値が変わります。そのため、再度testを実行すると当然ですが失敗します。

 FAIL  src/App.test.jsx
  ✕ renders currently (6ms)

  ● renders currently

    expect(received).toMatchSnapshot()

    Snapshot name: `renders currently 1`

    - Snapshot
    + Received

      <div>
        <div
          class="App"
        >
          <p>
    -       12fa6ae8-75d3-40b3-97af-172d0a304d37
    +       19c42b95-7fcc-4848-9616-4396f6c768e5
          </p>
        </div>
      </div>

      5 | test('renders currently', () => {
      6 |   const {container} = render(<App />);
    > 7 |   expect(container).toMatchSnapshot();
        |                     ^
      8 | });
      9 |

      at Object.<anonymous> (src/App.test.jsx:7:21)

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

Test Suites: 1 failed, 1 total
Tests:       1 failed, 1 total
Snapshots:   1 failed, 1 total
Time:        0.182s, estimated 1s
Ran all test suites.

toMatchSnapshot()を使ったtestがはじめて実行された場合、src配下の__snapshots__にスナップショットファイルが生成されます。
中身を見ると、初回実行時に対象のコンポーネントレンダリングされたDOMが書かれています。

// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`renders currently 1`] = `
<div>
  <div
    class="App"
  >
    <p>
      12fa6ae8-75d3-40b3-97af-172d0a304d37
    </p>
  </div>
</div>
`;

二度目以降は、こいつと差分がある場合は落ちるという感じ。
対応は、テスト実行時に利用されるuuid生成の関数をモックにして、スナップショットと同じ固定値を返すようにしてあげます。

App.test.jsxを下記のように修正します。

import React from 'react';
import { render } from '@testing-library/react';
import App from './App';

jest.mock('uuid',() => ({
  v4: () => '12fa6ae8-75d3-40b3-97af-172d0a304d37',
}));

test('renders currently', () => {
  const {container} = render(<App />);
  expect(container).toMatchSnapshot();
});

これでtestが通ります。 サンプルのプロジェクトは下記にあげました。

github.com