#reactjs #unit-testing #redux #jestjs #enzyme
Вопрос:
Чтобы визуализировать компонент контейнера, подключенный к хранилищу redux, я использую эту функцию для визуализации компонента
function render(Component, props, storeData) {
const mockStore = configureStore([thunkMiddleware]);
const store = mockStore(storeData);
return mount(
<Provider store={store}>
<Component {...props} />
</Provider>
);
}
Теперь мне нужно проверить изменение реквизитов отображаемого компонента, но, похоже ReactWrapper.setProps
, это работает только для корневого компонента.
MyComponent
это компонент контейнера, который подключен к хранилищу с помощью connect
.
describe('MyComponent', () => {
it('should work at props change', () => {
const wrapper = render(MyComponent, { value: 1 }, initialStoreValue);
wrapper.find(MyComponent).setProps({ value: 2});
// then expect something.
});
});
Комментарии:
1. Аналогичная проблема возникает, когда я использую компонент, использующий Радий. Мне пришлось обернуть компонент,
<StyleRoot>
чтобы смонтировать этот компонент, и из-за этого я не смог обновить реквизиты.
Ответ №1:
Несколько вещей, которые следует учитывать:
redux-mock-store
позволяет передавать функцию в качестве источника состояния —redux-mock-store
будет вызывать эту функцию каждый раз- для запуска компонента повторного рендеринга с
useSelector
помощью илиconnect()
мы можем простоdispatch()
использовать любой тип действия. Буквально любой. - Нам нужно завернуть магазин обновлений в
act()
, иначе он может не работать и, безусловно, будет жаловатьсяconsole.error
.
Поэтому, помня об этом, мы можем улучшить render
:
function render(Component, props, initialStoreData) {
let currentStoreData = initialStoreData;
const mockStore = configureStore([thunkMiddleware]);
const store = mockStore(() => currentStoreData);
const wrapper = mount(
<Provider store={store}>
<Component {...props} />
</Provider>
);
const updateStore = (newStoreData) => {
currentStoreData = newStoreData;
act(() => {
store.dispatch({ type: '' }); // just to trigger re-rendering components
});
}
return { wrapper, updateStore };
}
А затем в тесте:
describe('MyComponent', () => {
it('does something when store changes somehow', () => {
const { wrapper, updateStore } = render(MyComponent, { value: 1 }, initialStoreValue);
updateStore({ someReduxValue: 2});
// then expect something.
});
});
Комментарии:
1. Но это не обновляет реквизиты, предоставленные компоненту, не так ли?
2. Я не понимаю вопроса. Если тестируемый компонент на самом деле
connect()
базовый компонент, то базовый компонент получит новые реквизиты после обновления хранилища. И все внутри, что потребляет реквизит, будет другим(что вам на самом деле лучше проверить вместо обнаружения изменений реквизита — скрывается ли кнопка, изменяется ли текстовая метка и т. Д.)3. или вы имеете в виду, что при таком подходе реальные редукторы не включаются и запуск действия не обновляет хранилище соответствующим образом? но в том-то и дело: вы просто издеваетесь над данными хранилища вместо того, чтобы издеваться над каждым отдельным
fetch
или другими сторонними вызовами API.