web-dev-qa-db-ja.com

JESTエラーTypeError:specificMockImpl.applyは関数ではありません

APIからのコールバックを使用して関数の1つをモックしようとすると、TypeError: specificMockImpl.apply is not a functionとしてエラーが発生します

import { IEnvironmentMap, load } from 'dotenv-extended';
import { getTokensWithAuthCode, sdk } from '../src/connection-manager';

describe('getTokensWithAuthCode function Tests', () => {

    jest.useFakeTimers();
    let boxConfig: IEnvironmentMap;

    beforeAll(() => {
        boxConfig = load({
            errorOnMissing: true,
        });
    });

    it('should reject a promise if there is wrong auth code provided', async () => {

        sdk.getTokensAuthorizationCodeGrant = jest.fn().mockImplementation(boxConfig.BOX_AUTH_CODE, null, cb => {
            cb('Error', null);
        });

        try {
            const tokens = await getTokensWithAuthCode();
        } catch (error) {
            expect(error).toBe('Error');
        }
    });
});

そして、テストしようとしている私の関数は次のとおりです。

import * as BoxSDK from 'box-node-sdk';
import { IEnvironmentMap, load } from 'dotenv-extended';
import {ITokenInfo} from '../typings/box-node-sdk';

const boxConfig: IEnvironmentMap = load({
    errorOnMissing: true,
});

export const sdk: BoxSDK = new BoxSDK({
    clientID: boxConfig.BOX_CLIENT_ID,
    clientSecret: boxConfig.BOX_CLIENT_SECRET,
});

/**
 * - Use the provided AUTH_CODE to get the tokens (access + refresh)
 * - Handle saving to local file if no external storage is provided.
 */
export async function getTokensWithAuthCode() {

    return new Promise((resolve: (tokenInfo: ITokenInfo) => void, reject: (err: Error) => void) => {

        if (boxConfig.BOX_AUTH_CODE === '') {
            reject(new Error('No Auth Code provided. Please provide auth code as env variable.'));
        }

        sdk.getTokensAuthorizationCodeGrant(boxConfig.BOX_AUTH_CODE, null, (err: Error, tokenInfo: ITokenInfo) => {
            if (err !== null) {
                reject(err);
            }

            resolve(tokenInfo);
        });
    });
}

冗談で機能をモックする他の方法はありますか?記事を読みました https://www.zhubert.com/blog/2017/04/12/testing-with-jest/

6
badal16

この行では、関数をmockImplementationに渡すのではなく、次の3つの引数を渡します。

jest.fn().mockImplementation(boxConfig.BOX_AUTH_CODE, null, cb => {
  cb('Error', null);
});

中かっこをいくつか見逃したようです。次のように切り替えてみてください。

jest.fn().mockImplementation((boxConfig.BOX_AUTH_CODE, null, cb) => {
  cb('Error', null);
});
6
Tom

他の場所で使用されているconstを変更しようとしない方がよいでしょう。
getTokensWithAuthCodeを変更して、パラメーターとしてsdkを受け取るようにすることができます。したがって、テストでは、モック関数を引数として渡すため、sdkを直接変更するよりも予測可能な動作になります。

コードでは、たとえば署名getTokensWithAuthCodeUnbound(sdk)を使用して2番目のgetTokensWithAuthCode実装を作成し、それをエクスポートできます。この実装は、テストで使用されます。
同じgetTokensWithAuthCode名を使用してエクスポートするには、次のように呼び出します。

export const getTokensWithAuthCode = getTokensWithAuthCodeUnbound.bind(null, sdk)

そうすれば、アプリはデフォルトのgetTokensWithAuthCodeUnboundにバインドされたsdkを使用し、その実装をより簡単にテストできます。

Mozilla Developer Network(MDN)bindドキュメント

0
rodgobbi