YSNHatenaBlog

主にアプリやWebサービス開発について

algoliasearchをモックする

algoliasearch がmockできない。

i  Running script: jest
 FAIL  src/functions/__tests__/index.test.ts
  ● Test suite failed to run

    TypeError: algoliasearch_1.default is not a function

      2 | import * as functions from 'firebase-functions'
      3 | 
    > 4 | const client = algoliasearch(
        |                             ^
      5 |   functions.config().algolia.app_id,
      6 |   functions.config().algolia.admin_key
      7 | )

      at Object.<anonymous> (src/functions/firestore/index.ts:4:29)
      at Object.<anonymous> (src/functions/__tests__/index.test.ts:13:1)

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

algoliaのclientはリクエストとレスポンスを上書きできるらしい。 https://discourse.algolia.com/t/mock-js-client-for-instantsearch-ui-intergration-testing/9751 https://www.algolia.com/doc/api-client/advanced/configure-the-client/javascript/?language=javascript&client=javascript#requester

これならいけそう。 https://stackoverflow.com/questions/47056694/jest-mocking-default-exports-require-vs-import/47058957 でもrequire使っていなはずなのだけど...。

jest.mock('algoliasearch', () => {
  return {
    default: jest.fn()
  }
})

jest.fn().mockReturnValue({})を事前に定義するとモックされない ↓ダメパターン

const mockSaveObject = jest.fn().mockReturnValue({})
jest.mock('algoliasearch', () => ({
  default: () => ({
    initIndex: () => ({
      saveObject: mockSaveObject,
    }),
  }),
}))

でもmockSaveObjectにアクセスできないと、この関数が呼ばれたかの判断ができない。

なにやらmockの初期化関数内でjest.fn()呼ばないとだめそう。 これならOK。

let mockSaveObject: ReturnType<typeof jest.fn>
jest.mock('algoliasearch', () => {
  mockSaveObject = jest.fn().mockReturnValue({})
  return {
    default: () => ({
      initIndex: () => ({
        saveObject: mockSaveObject,
      }),
    }),
  }
})

その他知ったこと

ややこしいリセット系
  • clearAllMocks - モックに格納された値だけリセット。
  • resetAllMocks - 上記に加えて実装もリセット。
  • restoreAllMocks - すべての振る舞いをオリジナルに戻す。ただしspyOnで作ったものだけ。
jestのオブジェクトの比較
toStrictEqual
jest中のconsoleログはsilentオプションで消せる
jest --silent