created: 2021-08-27T08:22:46.000Z

jest でパッケージをモックしながら react-test-utils でクリックイベントをテストする

こんな実装になった。

import React from "react";
import ReactDOM from "react-dom";
import { act, Simulate } from "react-dom/test-utils";
import { Button } from "./Button";

const fn = jest.fn();
jest.mock("mocked-packagejs", () => (...args: any) => {
  fn(...args);
});

test("basic", async () => {
  const container = document.createElement("div");
  document.body.appendChild(container);
  act(() => ReactDOM.render(<Button />, container));
  const button = container.querySelector("button")!;
  await act(async () => Simulate.click(button));
  const args = fn.mock.calls[0];
  expect(!args).toBe(true);
});

jest.mock

jest.mock は import などと同じ scope に置かなくてはならない。

jest.mock("mocked-packagejs", () => (...args: any) => {
  fn(...args);
});

Note: In order to mock properly, Jest needs jest.mock('moduleName') to be in the same scope as the require/import statement.

この制約があって mocked-packagejs が返す値をテストにて変更しながらテストを回すことができなかった。やろうとするとなんらかのオブジェクトにラップして mockFn.mockReturnValue とかでやる必要があるのだろう。

Simulate.click

Clickイベントなので当然のことながら処理が非同期になる。 await してあげないと処理がタスクキューにのってるうちにテストのassertが呼ばれてしまう。

ただし、単純に await をつけるだけだと以下の warn がでる。

Warning: Do not await the result of calling act(...) with sync logic, it is not a Promise.

なので async もつけておく。

await act(async () => Simulate.click(button));