LoginSignup
3
2

More than 1 year has passed since last update.

jestでmock系のtips集

Posted at

はじめに

jestネタです。
何番煎じかわからないtipsもありますが、自分が引っかかったところをまとめたものです。
jest+typescript+reactを想定してます

moment.jsのモック化

moment_mock.test.ts
const mockDate = jest.spyOn(Date, 'now');

beforeEach(() => {
  // 当日日付の固定化
  mockDate.mockImplementation(() => {
    return new Date(2022, 2, 16, 0, 0, 0).getTime();
  });
});

外部ファイルのモック化

external_library.test.ts
import * as HogeApi from '../external/HogeApi';

const mockHogeApi = jest.spyOn(HogeApi, 'default');
beforeEach(() => {
    mockHogeApi.mockReset();
});

window.locationのモック化

location_mock.test.ts
beforeEach(() => {
  window.history.pushState({}, 'Page Title:test', '/route/path');
});

new Audio().play()のモック化

audio_mock.test.ts
const mockPlay = jest.spyOn(window.HTMLMediaElement.prototype, 'play');
beforeEach(() => {
    mockPlay.mockReset();
});

非同期のテスト

async.test.ts
it('snapshot', (done) => {
  execAsyncFunction();
  setTimeout(() => {
    try {
      expect(mockAsyncApi).toBeCalled();
      done();
    } catch (e) {
      done(e);
    }
  }, 300);
});

繰り返しテスト

each.test.ts
it.each`
  input | expected
  ${0}  | ${'firstActual'}
  ${1}  | ${'secondActual'}
`('each test input=$input',
  ({ input, expected }) => {
    const actual = eachFunction();
    expect(actual).toEqual(expected);
  }
);

繰り返し+非同期のテスト

each_async.test.ts
it.each`
  input | expected
  ${0}  | ${'firstActual'}
  ${1}  | ${'secondActual'}
`('each async test input=$input',
  ({ input, expected }, done: jest.DoneCallback) => {
    eachAsyncFunction();
    setTimeout(() => {
      try {
        expect(mockAsyncApi).toBeCalled();
        expect(mockAsyncApi.mock.calls[0][0]).toEqual(expected);
        done();
      } catch (error) {
        done(error);
      }
    }, 300);
  }
);

jqueryのモック化

  • プロダクトコード中のjquery関数をモック化したい場合
product.ts
const $ = require('jquery');

const parent = $(e).parents('tr');
jquery_mock.test.ts
jest.mock('jquery', () => {
  const m$ = {
    // jQuery関数のモック化
    parents: jest.fn().mockReturnValue({}),
  };
  return jest.fn(() => m$);
});

it('test',() => {
  // parentsモックの返却値を変更する
  const mockAdd = jest.fn();
  const $ = require('jquery');
  ($('').parents as jest.Mock).mockReturnValue([
    { classList: { add: mockAdd } },
  ]);

  callFunction();

  expect(mockAdd).toBeCalled();
  // parentsモックそのものがcallされたかの検証
  expect($().parents).toBeCalled();
});

afterEach(()=>{
  // 初期化したいなら
  ($('').parents as jest.Mock).mockReset();
})

Math.randomのモック化

random_mock.test.ts
beforeEach(() => {
    jest.spyOn(global.Math, 'random').mockReturnValue(0.123456789);
});

Modal(react-modal)の描画元を固定化

  • react-modalに関するwarningを解消する
console.error
  Warning: react-modal: App element is not defined. Please use `Modal.setAppElement(el)` or set `appElement={el}`. This is needed so screen readers don't see main content when modal is opened. It is not recommended, but you can opt-out by setting `ariaHideApp={false}`.
react-modal_mock.test.ts
beforeEach(() => {
    Modal.setAppElement(document.createElement('div'));
});

Link(react-router)のモック化

  • Linkが含まれるコンポーネントをshallowする時のエラー回避
The above error occurred in the <Link> component:
 ...
Error: Uncaught [Error: useHref() may be used only in the context of a <Router> component.]
 ...
link_mock.test.ts
import { MemoryRouter } from 'react-router-dom';

shallow(
<MemoryRouter>
    <Component />
</MemoryRouter>
);

参考

3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2