Как модульный тест React-Redux подключенных компонентов?
Я использую Mocha, Chai, Karma, Sinon, Webpack для модульных тестов.
Я пошел по этой ссылке, чтобы настроить мою среду тестирования для кода React-Redux.
Я могу успешно протестировать свои действия и редукторы javascript-кода, но когда дело доходит до тестирования моих компонентов, он всегда бросает некоторые ошибка.
import React from 'react';
import TestUtils from 'react/lib/ReactTestUtils'; //I like using the Test Utils, but you can just use the DOM API instead.
import chai from 'chai';
// import sinon from 'sinon';
import spies from 'chai-spies';
chai.use(spies);
let should = chai.should()
, expect = chai.expect;
import { PhoneVerification } from '../PhoneVerification';
let fakeStore = {
'isFetching': false,
'usernameSettings': {
'errors': {},
'username': 'sahil',
'isEditable': false
},
'emailSettings': {
'email': 'test@test.com',
'isEmailVerified': false,
'isEditable': false
},
'passwordSettings': {
'errors': {},
'password': 'showsomestarz',
'isEditable': false
},
'phoneSettings': {
'isEditable': false,
'errors': {},
'otp': null,
'isOTPSent': false,
'isOTPReSent': false,
'isShowMissedCallNumber': false,
'isShowMissedCallVerificationLink': false,
'missedCallNumber': null,
'timeLeftToVerify': null,
'_verifiedNumber': null,
'timers': [],
'phone': '',
'isPhoneVerified': false
}
}
function setup () {
console.log(PhoneVerification);
// PhoneVerification.componentDidMount = chai.spy();
let output = TestUtils.renderIntoDocument(<PhoneVerification {...fakeStore}/>);
return {
output
}
}
describe('PhoneVerificationComponent', () => {
it('should render properly', (done) => {
const { output } = setup();
expect(PhoneVerification.prototype.componentDidMount).to.have.been.called;
done();
})
});
эта следующая ошибка приходит с вышеуказанным кодом.
FAILED TESTS:
PhoneVerificationComponent
✖ should render properly
Chrome 48.0.2564 (Mac OS X 10.11.3)
Error: Invariant Violation: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined.
пробовал переключение с Синон шпионов чай-шпионов.
Как я должен тестировать мои React-Redux подключенные компоненты(интеллектуальные компоненты)?
4 ответов
более красивый способ сделать это-экспортировать как простой компонент, так и компонент, завернутый в connect. Именованный экспорт будет компонентом, по умолчанию это обернутый компонент:
export class Sample extends Component {
render() {
let { verification } = this.props;
return (
<h3>This is my awesome component.</h3>
);
}
}
const select = (state) => {
return {
verification: state.verification
}
}
export default connect(select)(Sample);
таким образом, вы можете импортировать нормально в своем приложении, но когда дело доходит до тестирования, вы можете импортировать именованный экспорт с помощью import { Sample } from 'component'
.
вы можете проверить свой подключенный компонент, и я думаю, что вы должны это сделать. Вы можете сначала протестировать несвязанный компонент, но я предлагаю, чтобы у вас не было полного тестового покрытия без тестирования подключенного компонента.
Ниже приведен непроверенный экстракт того, что я делаю с Redux и ферментом. Основная идея заключается в использовании поставщика для подключения состояния в тесте к подключенному компоненту в тесте.
import { Provider } from 'react-redux';
import configureMockStore from 'redux-mock-store';
import SongForm from '../SongForm'; // import the CONNECTED component
// Use the same middlewares you use with Redux's applyMiddleware
const mockStore = configureMockStore([ /* middlewares */ ]);
// Setup the entire state, not just the part Redux passes to the connected component.
const mockStoreInitialized = mockStore({
songs: {
songsList: {
songs: {
songTags: { /* ... */ }
}
}
}
});
const nullFcn1 = () => null;
const nullFcn2 = () => null;
const nullFcn3 = () => null;
const wrapper = mount( // enzyme
<Provider store={store}>
<SongForm
screen="add"
disabled={false}
handleFormSubmit={nullFcn1}
handleModifySong={nullFcn2}
handleDeleteSong={nullFcn3}
/>
</Provider>
);
const formPropsFromReduxForm = wrapper.find(SongForm).props(); // enzyme
expect(
formPropsFromReduxForm
).to.be.deep.equal({
screen: 'add',
songTags: initialSongTags,
disabled: false,
handleFormSubmit: nullFcn1,
handleModifySong: nullFcn2,
handleDeleteSong: nullFcn3,
});
===== ../SongForm.js
import React from 'react';
import { connect } from 'react-redux';
const SongForm = (/* object */ props) /* ReactNode */ => {
/* ... */
return (
<form onSubmit={handleSubmit(handleFormSubmit)}>
....
</form>
};
const mapStateToProps = (/* object */ state) /* object */ => ({
songTags: state.songs.songTags
});
const mapDispatchToProps = () /* object..function */ => ({ /* ... */ });
export default connect(mapStateToProps, mapDispatchToProps)(SongForm)
вы можете создать магазин с чистым Redux. redux-mock-store - это всего лишь легкая версия, предназначенная для тестирования.
вы можете использовать react-addons-test-utils вместо фермента airbnb.
Я использую chai-энзим airbnb, чтобы иметь реагирующие варианты ожидания. В этом примере она была не нужна.
проблема с принятым ответом заключается в том, что мы экспортируем что-то излишне просто, чтобы иметь возможность проверить его. И экспортировать класс только для того, чтобы проверить его, на мой взгляд, не очень хорошая идея.
вот более аккуратное решение без необходимости экспорта ничего, кроме подключенного компонента:
если вы используете jest, вы можете издеваться connect
метод для возврата трех вещи:
- mapStateToProps
- mapDispatchToProps
- ReactComponent
сделать это довольно просто. Есть 2 способа: встроенные насмешки или глобальные насмешки.
1. Использование встроенного макета
добавьте следующий фрагмент перед функцией описания теста.
jest.mock('react-redux', () => {
return {
connect: (mapStateToProps, mapDispatchToProps) => (ReactComponent) => ({
mapStateToProps,
mapDispatchToProps,
ReactComponent
}),
Provider: ({ children }) => children
}
})
2. Используя макет файла
- создайте файл
__mocks__/react-redux.js
в корень (где пакет.JSON-это находится) - добавьте следующий фрагмент в файл.
module.exports = {
connect: (mapStateToProps, mapDispatchToProps) => (ReactComponent) => ({
mapStateToProps,
mapDispatchToProps,
ReactComponent,
}),
Provider: ({children}) => children
};
после издевательства вы сможете получить доступ ко всем вышеперечисленным трем, используя Container.mapStateToProps
,Container.mapDispatchToProps
и Container.ReactComponent
.
контейнер можно импортировать просто делаю
import Container from '<path>/<fileName>.container.js'
надеюсь, что это помогает.
обратите внимание, что если вы используете пробный файл. Высмеянный файл будет использоваться глобально для всех тестов случаи (если вы не делаете jest.unmock('react-redux'))
перед началом теста.
попробуйте создать 2 файла, один с самим компонентом, не зная о каком-либо магазине или чем-либо (PhoneVerification-component.в JS). Затем второй (Фоневеризация.js), который вы будете использовать в своем приложении и который возвращает только первый компонент, подписанный на store через