#reactjs #redux #react-redux #jestjs #react-testing-library
Вопрос:
Я использую библиотеку тестирования jest react
И, как описано в названии, я пытаюсь проверить, что testAction отправляет второе действие, но я получаю сообщение об ошибке, в котором говорится, что второе действие не было отправлено, что не может быть правдой, потому что массаж функции печатается.
у кого-нибудь есть подсказка, как я могу заставить этот тест работать?
действие
export const testAction = () => async (dispatch) => {
dispatch(secondTestAction());
};
export const secondTestAction = () => {
console.log('second action have been dispatched');
};
испытание
import '@testing-library/jest-dom/extend-expect';
import * as userActions from '../../../redux/actions/userActions';
import store from '../../../redux/store';
const secondTestActionSpy = jest.spyOn(userActions, 'secondTestAction');
test('should dispatch secondTestActions ', async () => {
await store.dispatch(userActions.testAction());
expect(secondTestActionSpy.mock.calls.length).toBe(1);
});
ошибка
expect(received).toBe(expected) // Object.is equality
Expected: 1
Received: 0
expect(secondTestActionSpy.mock.calls.length).toBe(1);
Ответ №1:
Видите ли, вы импортируете все свои действия(это export
ред.) в тест. Затем вы локально — только в тесте — заменяете одно из импортированных действий оболочкой-шпионом. Но действия в userActions.js
не попадают в ваш тестовый файл, одна функция просто вызывает другую, напрямую, только ту версию, которая объявлена, а не завернутую со шпионской версией.
Что ты можешь сделать? Если вы хотите следовать подходу «проверьте, что действие было вызвано», вы можете использовать redux-mock-store
:
import { testAction, secondAction } from '../../../redux/actions/userActions';
test('should dispatch secondTestActions ', async () => {
mockedStore.dispatch(userActions.testAction());
expect(mockedStore.getActions()).toContainEqual(secondAction());
});
так как же это сделать mockedStore
? Просто используйте экспорт по умолчанию из redux-mock-store
:
import configureMockStore from 'redux-mock-store';
import thunk from 'redux-thunk';
const middlewares = [thunk];
const mockStore = configureMockStore(middlewares)(constantStoreData);
Поскольку redux-mock-store
не обрабатывает действия с помощью редукторов, на самом деле это не требует, чтобы вы полагались на редукторы. Так что ни ../store
то, ни другое здесь не нужно.
Но таким образом вы просто проверяете, какие действия называются(и в каком порядке — если вы используете expect(store.getActions()).toEqual(...
вместо expect(store.getActions()).toContainEqual(...
).
На мой взгляд, гораздо проще и надежнее тестировать хранилище в целом — как с помощью действий, так и с помощью редукторов, издеваясь только над взаимодействием с внешним миром(например, запросы к серверу, операции с локальным хранилищем и т. Д.). Затем тесты отправят некоторые действия и обеспечат, чтобы конечное состояние соответствовало ожиданиям:
it('sets loading once request started', () => {
const realStore = createStore(userReducer, someInitialState);
realStore.dispatch(loadUsersAction(someArgument));
expect(realStore.getState().isLoading).toEqual(true);
});
it('unsets loading once loading users failed', async () => {
// mock specific request to fail
const realStore = createStore(userReducer, someInitialState);
realStore.dispatch(loadUsersAction(someArgument));
await undefined; // let's skip Promises queue once; does nothing special, await 42 would work the same;
expect(realStore.getState().isLoading).toEqual(false);
});