Javascript 如何使用Jest模拟导入模块中的函数?

Javascript 如何使用Jest模拟导入模块中的函数?,javascript,jestjs,msal,Javascript,Jestjs,Msal,我有一个名为authProvider.js的模块,当我在api.js中测试我的一个函数时,我想模拟它。 我已经在我的jest配置中设置了“automock”:true 这是我的结构 src |-auth | |-__mocks__ | | |-authProvider.js | |-authProvider.js |-utils |-api.js |-api.test.js 这是我迄今为止尝试过的,但仅在第一个测试用例中成功。我不知道如何在第二个测试用例中设置

我有一个名为authProvider.js的模块,当我在api.js中测试我的一个函数时,我想模拟它。 我已经在我的jest配置中设置了“automock”:true

这是我的结构

src
 |-auth
 |  |-__mocks__
 |  |  |-authProvider.js
 |  |-authProvider.js
 |-utils
    |-api.js
    |-api.test.js
这是我迄今为止尝试过的,但仅在第一个测试用例中成功。我不知道如何在第二个测试用例中设置模拟

api.test.js

import { mockAuthProvider } from "../auth/__mocks__/authProvider";
import { getDefaultHeaders, getValueIndexByColumnName } from './api';

describe('API utils', () => {
    describe('getDefaultHeaders', () => {
        it('Not authenticated', async () => {
            expect(await getDefaultHeaders()).toEqual({
                'Content-Type': 'application/json'
            });
        });

        it('Authenticated', async () => {
            mockAuthProvider.getAccount.mockImplementationOnce(() =>
                Promise.resolve({user: 'test'})
            );

            const headers = await getDefaultHeaders();

            expect(mockAuthProvider.getAccount).toBeCalled();
            expect(headers).toEqual({
                Authorization: 'Bearer abc123',
                'Content-Type': 'application/json'
            });
        });
    });
});
api.js

import { authProvider } from '../auth/authProvider';
import settings from '../settings';

export async function getDefaultHeaders() {
    const account = await authProvider.getAccount();
    const authenticationParameters = {
        scopes: ['api://' + settings.AD_CLIENT_ID + '/login'],
        redirectUri: window.location.origin + '/auth.html'
    };
    let token;

    if (account) {
        try {
            token = await authProvider.acquireTokenSilent(authenticationParameters);
        } catch (error) {
            token = await authProvider.acquireTokenPopup(authenticationParameters);
        }
    }

    if (token) {
        return {
            Authorization: `Bearer ${token.accessToken}`,
            'Content-Type': 'application/json'
        }
    }
    return {
        'Content-Type': 'application/json'
    }
}
__mocks\uu\u/authProvider.js

const mockAuthProvider = {
    getAccount: jest.fn(),
    acquireTokenSilent: jest.fn(),
    acquireTokenPopup: jest.fn()
};

module.exports = {
    mockAuthProvider
};
错误消息

Expected number of calls: >= 1
Received number of calls:    0

  18 |             const headers = await getDefaultHeaders();
  19 |
> 20 |             expect(mockAuthProvider.getAccount).toBeCalled();
     |                                                 ^
更新

我添加了一个文件来模拟导出auth提供者的整个模块,但我认为这仍然不是解决这个问题的最佳方法。我很难在多个测试用例中使用它,因为我需要按特定顺序指定返回值

有没有更好的办法来解决这个问题

__mocks _u/react-aad-msal.js

import React from 'react';

const errorObj = {
    message: 'Some error'
};

export const mockGetAccount = jest.fn()
    .mockReturnValueOnce(null) // Not authenticated
    .mockReturnValueOnce({user: 'test'}) // Authenticated silent
    .mockReturnValueOnce({user: 'test'}); // Authenticated popup
export const mockAcquireTokenSilent = jest.fn()
    .mockReturnValueOnce({accessToken: 'abc123'}) // Authenticated silent
    .mockRejectedValueOnce(errorObj); // Authenticated popup
export const mockAcquireTokenPopup = jest.fn()
    .mockReturnValueOnce({accessToken: 'abc123'}); // Authenticated popup

export const MsalAuthProvider = jest.fn(() => ({
    getAccount: mockGetAccount,
    acquireTokenSilent: mockAcquireTokenSilent,
    acquireTokenPopup: mockAcquireTokenPopup
}));

export const AuthenticationState = {
    Authenticated: 'Authenticated',
    Unauthenticated: 'Unauthenticated'
};

export const LoginType = {
    Popup: 'popup'
};

export const AuthenticationActions = {
    Initializing: 'Initializing',
    Initialized: 'Initialized',
    AcquiredIdTokenSuccess: 'AcquiredIdTokenSuccess',
    AcquiredAccessTokenSuccess: 'AcquiredAccessTokenSuccess',
    AcquiredAccessTokenError: 'AcquiredAccessTokenError',
    LoginSuccess: 'LoginSuccess',
    LoginError: 'LoginError',
    AcquiredIdTokenError: 'AcquiredIdTokenError',
    LogoutSucc: 'LogoutSucc',
    AuthenticatedStateChanged: 'AuthenticatedStateChanged'
};

export const AzureAD = ({children}) => <div>{children}</div>;

第二次测试显示了什么错误?我在帖子中添加了错误消息
import { getDefaultHeaders, axiosCreate, getValueIndexByColumnName } from './api';

describe('API utils', () => {
    describe('getDefaultHeaders', () => {
        it('Not authenticated', async () => {
            const headers = await getDefaultHeaders();

            expect(headers).toEqual({
                'Content-Type': 'application/json'
            });
        });

        it('Authenticated silent', async () => {
            const headers = await getDefaultHeaders();

            expect(headers).toEqual({
                Authorization: 'Bearer abc123',
                'Content-Type': 'application/json'
            });
        });

        it('Authenticated popup', async () => {
            const headers = await getDefaultHeaders();

            expect(headers).toEqual({
                Authorization: 'Bearer abc123',
                'Content-Type': 'application/json'
            });
        });
    });

    describe('axiosCreate', () => {
        it('Create axios API base', () => {
            expect(axiosCreate()).toBeTruthy();
        });
    });

    describe('getValueIndexByColumnName', () => {
        it('Invalid input data', () => {
            expect(getValueIndexByColumnName([], null)).toEqual(null);
            expect(getValueIndexByColumnName(['column1'], null)).toEqual(-1);
        });

        it('Valid input data', () => {
            expect(getValueIndexByColumnName(['column1'], 'column')).toEqual(-1);
            expect(getValueIndexByColumnName(['column1'], 'column1')).toEqual(0);
            expect(getValueIndexByColumnName(['column1', 'column2', 'column3'], 'column2')).toEqual(1);
        });
    });
});