Jest: ノードモジュールを正しくモックするにはどうすればいいですか? 質問する

Jest: ノードモジュールを正しくモックするにはどうすればいいですか? 質問する

Jest を使用して React Native の node_module 'React Native Keychain' をモックしたいと思います。

続いてドキュメントというフォルダを作成し__mocks__、その中に というファイルを作成しましたreact-native-keychain.js

ファイル内のコードは次のとおりです。

export default jest.mock("react-native-keychain", () => {
  const token = "abcdefghijklmnopqrstuvwxyz0123456789";
  const credentials = {
    username: "session",
    password: token
  };
  return {
    setGenericPassword: jest.fn(
      (username, password) => new Promise((resolve, reject) => resolve(true)) // eslint-disable-line no-unused-vars
    ),
    getGenericPassword: jest.fn(() => new Promise((resolve, reject) => resolve(credentials))), // eslint-disable-line no-unused-vars
    resetGenericPassword: jest.fn(() => new Promise((resolve, reject) => resolve(true))) // eslint-disable-line no-unused-vars
  };
});

次に、このライブラリを使用する関数のテストを記述しました。

import * as keyChainFunctions from "react-native-keychain";
import { setToken, getToken, clearToken } from "./secureStorage";

const token = "abcdefghijklmnopqrstuvwxyz0123456789";

    describe("set token", () => {
      it("saves the token in the keychain", () => {
        expect.assertions(1);
        return setToken(token).then(res => {
          console.log(res);
          console.log(keyChainFunctions);
          expect(keyChainFunctions.setGenericPassword).toHaveBeenCalledWith("session", token);
        });
      });
    });

問題は、テストが失敗することです。次のエラー メッセージが表示されます:

 FAIL  app/api/secureStorage/secureStorage.test.js
  set token
    ✕ saves the token in the keychain (42ms)

  ● set token › saves the token in the keychain

    expect(jest.fn())[.not].toHaveBeenCalledWith()

    jest.fn() value must be a mock function or spy.
    Received: undefined

      10 |       console.log(res);
      11 |       console.log(keyChainFunctions);
    > 12 |       expect(keyChainFunctions.setGenericPassword).toHaveBeenCalledWith("session", token);
         |                                                    ^
      13 |     });
      14 |   });
      15 | });

      at app/api/secureStorage/secureStorage.test.js:12:52
      at tryCallOne (node_modules/promise/lib/core.js:37:12)
      at node_modules/promise/lib/core.js:123:15
      at flush (node_modules/asap/raw.js:50:29)
 ● set token › saves the token in the keychain

    expect.assertions(1)

    Expected one assertion to be called but received zero assertion calls.

       6 | describe("set token", () => {
       7 |   it("saves the token in the keychain", () => {
    >  8 |     expect.assertions(1);
         |            ^
       9 |     return setToken(token).then(res => {
      10 |       console.log(res);
      11 |       console.log(keyChainFunctions);

      at Object.<anonymous> (app/api/secureStorage/secureStorage.test.js:8:12)

そしてconsole.log()収穫量:

console.log app/api/secureStorage/secureStorage.test.js:10
    true

  console.log app/api/secureStorage/secureStorage.test.js:11
    { default:
       { addMatchers: [Function: addMatchers],

         advanceTimersByTime: [Function: advanceTimersByTime],
         autoMockOff: [Function: disableAutomock],
         autoMockOn: [Function: enableAutomock],
         clearAllMocks: [Function: clearAllMocks],
         clearAllTimers: [Function: clearAllTimers],
         deepUnmock: [Function: deepUnmock],
         disableAutomock: [Function: disableAutomock],
         doMock: [Function: mock],
         dontMock: [Function: unmock],
         enableAutomock: [Function: enableAutomock],
         fn: [Function: bound fn],
         genMockFromModule: [Function: genMockFromModule],
         isMockFunction: [Function: isMockFunction],
         mock: [Function: mock],
         requireActual: [Function: bound requireModule],
         requireMock: [Function: bound requireMock],
         resetAllMocks: [Function: resetAllMocks],
         resetModuleRegistry: [Function: resetModules],
         resetModules: [Function: resetModules],
         restoreAllMocks: [Function: restoreAllMocks],
         retryTimes: [Function: retryTimes],
         runAllImmediates: [Function: runAllImmediates],
         runAllTicks: [Function: runAllTicks],
         runAllTimers: [Function: runAllTimers],
         runOnlyPendingTimers: [Function: runOnlyPendingTimers],
         runTimersToTime: [Function: runTimersToTime],
         setMock: [Function: setMock],
         setTimeout: [Function: setTimeout],
         spyOn: [Function: bound spyOn],
         unmock: [Function: unmock],
         useFakeTimers: [Function: useFakeTimers],
         useRealTimers: [Function: useRealTimers] } }

このことからわかること: 1. モックが機能しているか (true が正しく返されるため)、setGenericPasswordReact Native Keychain から実際の関数が呼び出されているかのいずれかです。2. 何らかの理由で、3 つのモック関数ではなくオブジェクトkeychainfunctionsとして定義されています。jest.mock

モックが機能する場合、1 と 2 は互いに矛盾しているように感じます。何が間違っているのでしょうか? このモックが機能しないのはなぜですか? これらの奇妙なconsole.log()s と失敗したテストはどのように説明できますか?

バンセコメントでは、オブジェクトをエクスポートするだけと提案されています。この回避策は機能します。これを正しく行う方法や、何を間違えたのか、まだ興味があります。

const token = "abcdefghijklmnopqrstuvwxyz0123456789";
const credentials = {
  username: "session",
  password: token
};

export const setGenericPassword = jest.fn(
  (username, password) => new Promise((resolve, reject) => resolve(true)) // eslint-disable-line no-unused-vars
);

export const getGenericPassword = jest.fn(
  () => new Promise((resolve, reject) => resolve(credentials)) // eslint-disable-line no-unused-vars
);

export const resetGenericPassword = jest.fn(() => new Promise((resolve, reject) => resolve(true))); // eslint-disable-line no-unused-vars

ベストアンサー1

使ってみるのもいいでしょうjest.createMockFromModuleテストで必要なメソッドのみをモックします。(Jest バージョン 26 より前では genMockFromModule と呼ばれていました)

それが役に立てば幸い

おすすめ記事