Как я могу макетировать функции в импортированном модуле, используя Jest? - PullRequest
3 голосов
/ 27 января 2020

У меня есть модуль с именем authProvider. js, который я хочу смоделировать при тестировании одной из моих функций в API. js. Я установил "automock": true в моей конфигурации jest.

Это моя структура

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 __ / 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();
     |                                                 ^

ОБНОВЛЕНИЕ

Я добавил файл, чтобы смоделировать весь модуль, который экспортирует провайдера аутентификации, но все еще не лучший способ решить его, я думаю. У меня возникают трудности с использованием его в нескольких тестовых случаях, поскольку мне нужно указать возвращаемые значения в указанном порядке c.

Есть ли лучший способ решить эту проблему?

__ mocks __ / response-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>;

Новый api.test. js выглядит следующим образом, обратите внимание, что порядок тестов теперь важен, поскольку возвращаемые значения из макеты в фиксированном порядке.

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);
        });
    });
});
...