Синон Шпион никогда не звонила, но это должно быть

Проблема

Я тестирую пользовательское промежуточное ПО Redux с использованием Jest и SinonJS, и, точнее, я хочу проверить, вызываются ли некоторые функции в особых условиях внутри промежуточного программного обеспечения.

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

Код

Вот промежуточное ПО, которое я хочу протестировать:

import { Cookies } from 'react-cookie';
import setAuthorizationToken from './setAuthorizationToken';

let cookies = new Cookies();

export const bindTokenWithApp = (store) => (next) => (action) => {
    // Select the token before action
    const previousToken = getToken(store.getState());
    // Dispatch action
    const result = next(action);
    // Select the token after dispatched action
    const nextToken = getToken(store.getState());

    if (previousToken !== nextToken) {
        if (nextToken === '') {
            setAuthorizationToken(false);
            cookies.remove(SESSION_COOKIE_NAME, COOKIE_OPTIONS);
        } else {
            cookies.set(SESSION_COOKIE_NAME, nextToken, COOKIE_OPTIONS);
            setAuthorizationToken(nextToken);
        }
    }

    return result;
};

Вот мой реальный тест

import { bindTokenWithApp } from './middleware';
import { Cookies } from 'react-cookie';
import sinon, { assert } from 'sinon';
import setAuthorizationToken from './setAuthorizationToken';

describe('bindTokenWithApp', () => {
    const next = jest.fn();
    const action = jest.fn();
    let cookies = new Cookies();

    it('removes cookies when there is no token', () => {
        // My actual not working spies
        const cookieSpy = sinon.spy(cookies.remove);
        const authSpy = sinon.spy(setAuthorizationToken);

        // Stub for the specific case. This code works, 
        // I console.logged in the middleware and I'm getting the below values
        const getState = sinon.stub();
        getState.onFirstCall().returns({ auth: { token: 'a token' } });
        getState.onSecondCall().returns({ auth: { token: '' } });
        const store = { getState: getState };

        bindTokenWithApp(store)(next)(action);

        assert.calledOnce(cookieSpy);
        assert.calledOnce(authSpy);
        // Output : AssertError: expected remove to be called once but was called 0 times
        // AssertError: expected setAuthorizationToken to be called once but was called 0 times

        cookieSpy.restore(); // <= This one works
        authSpy.restore(); // TypeError: authSpy.restore is not a function 

  });
});

Я прочитал документ SinonJS и несколько сообщений StackOverFlow, но без решений. Я также не могу позвонить authSpy.restore();. Я думаю, что неправильно инициализирую шпионов, и я неправильно понимаю концепцию SinonJS, но я не могу найти, какую именно!

Подпись setAuthorizationToken:
(псевдоним) const setAuthorizationToken: (token: any) => void
import setAuthorizationToken

Я думаю, что это классический модуль, поэтому я не могу понять, почему у меня проблемы с authSpy.restore();


person Tenshock    schedule 13.02.2019    source источник


Ответы (1)


Два шпиона, которые у вас есть, на самом деле имеют два разных исправления, оба с одной и той же основной проблемой. sinon.spy(someFunction) на самом деле не обертывает someFunction, он возвращает для него шпиона, но не выполняет никакой замены.

Для первого шпиона существует сокращение для автоматического переноса метода объекта: sinon.spy(cookie, 'remove') должен делать то, что вам нужно.

Для второго шпиона это сложнее, так как вам нужно обернуть шпиона вокруг экспорта по умолчанию setAuthorizationToken. Для этого вам понадобится что-то вроде proxyquire. Proxyquire — это специализированный механизм, который позволяет вам заменять импорт желаемыми методами тестирования. Вот краткое изложение того, что вам нужно сделать:

const authSpy = sinon.spy(setAuthorizationToken);
bindTokenWithApp = proxyquire('./middleware', { './setAuthorizationToken': authSpy});
person Michael Pratt    schedule 13.02.2019
comment
Спасибо за объяснение. Я пробовал два решения, но ни одно из них не работает. Я понимаю основную проблему, для первого шпиона, который у меня сейчас есть в моем тесте: sinon.spy(cookies, 'remove'); assert.calledOnce(cookies.remove);, но с тем же результатом. Для второго шпиона я пробовал с proxyquire и jest.mock (из этого статья, но безуспешно). Я не могу утверждать bindTokenWithApp = proxyquire…, потому что он доступен только для чтения при импорте. И когда я утверждаю const bindTokenWithApp =…, я не могу его выполнить, потому что это не функция... - person Tenshock; 13.02.2019