unit-testing - mock - react redux testing
¿Cómo se puede probar la unidad React-Redux Connected Components? (4)
El problema con la respuesta aceptada es que estamos exportando algo innecesariamente solo para poder probarlo. Y exportar una clase solo para probarlo no es una buena idea en mi opinión.
Aquí hay una solución más ordenada sin la necesidad de exportar nada más que el componente conectado:
Si está utilizando la broma, puede simular el método de connect
para devolver tres cosas:
- mapStateToProps
- mapDispatchToProps
- ReactComponent
Hacerlo es bastante simple. Hay 2 formas: burlas en línea o burlas globales.
1. Usando el simulacro en línea
Agregue el siguiente fragmento antes de la función de descripción de la prueba.
jest.mock(''react-redux'', () => {
return {
connect: (mapStateToProps, mapDispatchToProps) => (ReactComponent) => ({
mapStateToProps,
mapDispatchToProps,
ReactComponent
}),
Provider: ({ children }) => children
}
})
2. Usando el simulacro de archivo
- Cree un archivo
__mocks__/react-redux.js
en la raíz (donde se encuentra el paquete.json) - Agregue el siguiente fragmento en el archivo.
module.exports = {
connect: (mapStateToProps, mapDispatchToProps) => (ReactComponent) => ({
mapStateToProps,
mapDispatchToProps,
ReactComponent,
}),
Provider: ({children}) => children
};
Después de burlarse, podrá acceder a los tres anteriores utilizando Container.mapStateToProps
, Container.mapDispatchToProps
y Container.ReactComponent
.
El contenedor se puede importar simplemente haciendo
import Container from ''<path>/<fileName>.container.js''
Espero eso ayude.
Tenga en cuenta que si usa el archivo falso. El archivo jest.unmock(''react-redux''))
se usará globalmente para todos los casos de prueba (a menos que lo haga jest.unmock(''react-redux''))
antes del caso de prueba.
Estoy usando Mocha, Chai, Karma, Sinon, Webpack para pruebas unitarias.
Seguí este enlace para configurar mi entorno de prueba para el código de React-Redux.
Puedo probar con éxito mi acción y el código javascript de los reductores, pero cuando se trata de probar mis componentes siempre arroja algún error.
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'': ''[email protected]'',
''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();
})
});
Este siguiente error aparece con el código anterior.
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.
Intenté pasar de los espías sinón a los chai-espías.
¿Cómo debo probar mis componentes React-Redux Connected (Smart Components)?
Intente crear 2 archivos, uno con el componente en sí, sin tener conocimiento de ninguna tienda ni nada (PhoneVerification-component.js). Luego el segundo (PhoneVerification.js), que usará en su aplicación y que solo devuelve el primer componente suscrito a la tienda a través de la función de connect
, algo así como
import PhoneVerificationComponent from ''./PhoneVerification-component.js''
import {connect} from ''react-redux''
...
export default connect(mapStateToProps, mapDispatchToProps)(PhoneVerificationComponent)
Entonces puede probar su componente "tonto" requiriendo PhoneVerification-component.js
en su prueba y proporcionándole los apoyos burlados necesarios. No hay ningún punto de prueba ya probado (connect decorator, mapStateToProps, mapDispatchToProps, etc.)
Puedes probar tu componente conectado y creo que deberías hacerlo. Es posible que desee probar el componente desconectado primero, pero le sugiero que no tenga una cobertura de prueba completa sin probar también el componente conectado.
A continuación se muestra un extracto no probado de lo que hago con Redux y Enzyme. La idea central es usar Proveedor para conectar el estado en prueba al componente conectado en prueba.
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)
Es posible que desee crear una tienda con Redux puro. redux-mock-store es una versión ligera de prueba.
Es posible que desee utilizar react-addons-test-utils en lugar de la enzima de airbnb.
Utilizo la chai-enzima de airbnb para tener opciones de espera de React-aware. No fue necesario en este ejemplo.
Una forma más bonita de hacerlo es exportar tanto su componente simple como el componente envuelto en connect. La exportación nombrada sería el componente, el valor predeterminado es el componente envuelto:
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);
De esta manera, puede importar normalmente en su aplicación, pero cuando se trata de pruebas, puede importar su exportación con nombre usando la import { Sample } from ''component''
.