react examples example reactjs enzyme react-intl

reactjs - examples - Inyectar el objeto react-intl en componentes de Enzyme montados para realizar pruebas



react intl examples (1)

He creado funciones de ayuda para parchear las funciones existentes de Enzyme mount() y shallow() . Ahora estamos usando estos métodos de ayuda en todas nuestras pruebas donde usamos los componentes React Intl.

Puede encontrar la información esencial aquí: https://gist.github.com/mirague/c05f4da0d781a9b339b501f1d5d33c37

Por el bien de mantener los datos accesibles, aquí está el código en pocas palabras:

helpers / intl-test.js

/** * Components using the react-intl module require access to the intl context. * This is not available when mounting single components in Enzyme. * These helper functions aim to address that and wrap a valid, * English-locale intl context around them. */ import React from ''react''; import { IntlProvider, intlShape } from ''react-intl''; import { mount, shallow } from ''enzyme''; const messages = require(''../locales/en''); // en.json const intlProvider = new IntlProvider({ locale: ''en'', messages }, {}); const { intl } = intlProvider.getChildContext(); /** * When using React-Intl `injectIntl` on components, props.intl is required. */ function nodeWithIntlProp(node) { return React.cloneElement(node, { intl }); } export default { shallowWithIntl(node) { return shallow(nodeWithIntlProp(node), { context: { intl } }); }, mountWithIntl(node) { return mount(nodeWithIntlProp(node), { context: { intl }, childContextTypes: { intl: intlShape } }); } };

CustomComponent

class CustomComponent extends Component { state = { foo: ''bar'' } render() { return ( <div> <FormattedMessage id="world.hello" defaultMessage="Hello World!" /> </div> ); } }

CustomComponentTest.js

import { mountWithIntl } from ''helpers/intl-test''; const wrapper = mountWithIntl( <CustomComponent /> ); expect(wrapper.state(''foo'')).to.equal(''bar''); // OK expect(wrapper.text()).to.equal(''Hello World!''); // OK

EDITAR: ¡Resuelto! Desplácese hacia abajo para la respuesta

En nuestras pruebas de componentes, necesitamos que tengan acceso al contexto react-intl . El problema es que estamos montando componentes individuales (con Enzyme''s mount() ) sin su <IntlProvider /> parent wrapper. Esto se resuelve envolviendo al proveedor, pero luego la root apunta a la instancia de IntlProvider y no a CustomComponent .

Las pruebas con React-Intl: documentos de enzimas todavía están vacías.

<CustomComponent />

class CustomComponent extends Component { state = { foo: ''bar'' } render() { return ( <div> <FormattedMessage id="world.hello" defaultMessage="Hello World!" /> </div> ); } }

Caso de prueba estándar (deseado) (Enzyme + Mocha + Chai)

// This is how we mount components normally with Enzyme const wrapper = mount( <CustomComponent params={params} /> ); expect( wrapper.state(''foo'') ).to.equal(''bar'');

Sin embargo, dado que nuestro componente utiliza FormattedMessage como parte de la biblioteca react-intl , obtenemos este error cuando react-intl el código anterior:

Uncaught Invariant Violation: [React Intl] Could not find required `intl` object. <IntlProvider> needs to exist in the component ancestry.

Envolviéndolo con IntlProvider

const wrapper = mount( <IntlProvider locale="en"> <CustomComponent params={params} /> </IntlProvider> );

Esto proporciona a CustomComponent el contexto intl que solicita. Sin embargo, al tratar de hacer afirmaciones de prueba como estas:

expect( wrapper.state(''foo'') ).to.equal(''bar'');

plantea la siguiente excepción:

AssertionError: expected undefined to equal ''''

Esto, por supuesto, porque intenta leer el estado de IntlProvider y no nuestro CustomComponent .

Intentos de acceder a CustomComponent

He intentado lo siguiente en vano:

const wrapper = mount( <IntlProvider locale="en"> <CustomComponent params={params} /> </IntlProvider> ); // Below cases have all individually been tried to call `.state(''foo'')` on: // expect( component.state(''foo'') ).to.equal(''bar''); const component = wrapper.childAt(0); > Error: ReactWrapper::state() can only be called on the root const component = wrapper.children(); > Error: ReactWrapper::state() can only be called on the root const component = wrapper.children(); component.root = component; > TypeError: Cannot read property ''getInstance'' of null

La pregunta es: ¿Cómo podemos montar CustomComponent con el contexto intl mientras todavía podemos realizar operaciones "root" en nuestro CustomComponent ?