reactjs - vida - react js tutorial español 2018
Cómo hacer que Jest espere a que todo el código asíncrono termine de ejecutarse antes de esperar una aserción (5)
Aquí hay un fragmento que espera hasta que se resuelvan las Promesas pendientes:
const flushPromises = () => {
return new Promise(resolve => setImmediate(resolve));
};
Tenga en cuenta que setImmediate es una característica estándar (y no se espera que se convierta en estándar). Pero si es suficiente para su entorno de prueba, debería ser una buena solución. Su descripción:
Este método se utiliza para dividir las operaciones de larga ejecución y ejecutar una función de devolución de llamada inmediatamente después de que el navegador haya completado otras operaciones, como eventos y actualizaciones de pantalla.
Aquí se explica cómo usarlo usando async / await:
it(''is an example using flushPromises'', async () => {
const wrapper = mount(<App/>);
await flushPromises();
wrapper.update(); // In my experience, Enzyme didn''t always facilitate component updates based on state changes resulting from Promises -- hence this forced re-render
// make assertions
});
Utilicé esto mucho en este proyecto si quieres algunos ejemplos reales de trabajo.
Estoy escribiendo una prueba de integración para una aplicación React, es decir, una prueba que prueba muchos componentes juntos, y quiero burlarme de cualquier llamada a servicios externos.
El problema es que la prueba parece ejecutarse antes de que se ejecute la devolución de llamada asíncrona, lo que hace que mis pruebas fallen.
¿Hay alguna manera alrededor de esto? ¿Puedo esperar de alguna manera a que termine el código async de llamada?
Aquí hay un mal pseudo código para ilustrar mi punto.
Me gustaría probar que cuando monte Parent, su componente Child muestra el contenido que regresó de un servicio externo, del cual me burlaré.
class Parent extends component
{
render ()
{
<div>
<Child />
</div>
}
}
class Child extends component
{
DoStuff()
{
aThingThatReturnsAPromise().then((result) => {
Store.Result = result
})
}
render()
{
DoStuff()
return(<div>{Store.Result}</div>)
}
}
function aThingThatReturnsAPromise()
{
return new Promise(resolve =>{
eternalService.doSomething(function callback(result) {
resolve(result)
}
}
}
Cuando hago esto en mi prueba, falla porque se ejecuta antes de que se active la devolución de llamada.
jest.mock(''eternalService'', () => {
return jest.fn(() => {
return { doSomething: jest.fn((cb) => cb(''fakeReturnValue'');
});
});
describe(''When rendering Parent'', () => {
var parent;
beforeAll(() => {
parent = mount(<Parent />)
});
it(''should display Child with response of the service'', () => {
expect(parent.html()).toMatch(''fakeReturnValue'')
});
});
¿Cómo puedo probar esto? Entiendo que esto se resuelve angularmente con zonejs, ¿hay un enfoque equivalente en Reaccionar?
La naturaleza asíncrona de JavaScript es una de las principales razones por las que las pruebas unitarias de JavaScript han tardado tanto tiempo en madurar. Jest proporciona muchos patrones para probar el código asíncrono que se describe aquí: jestjs.io/docs/en/asynchronous.html Utilizo async / await más extensamente, ya que permite realizar pruebas extremadamente legibles.
Pero como se está burlando del método asíncrono, no hay necesidad de ningún código asíncrono. Vea abajo.
let parent
let eternalService = jest.fn(() => ''fakeReturnValue'');
beforeEach(() => {
parent = mount(<Parent />)
parent.instance().externalService = externalService
})
describe(''When rendering Parent'', () => {
it(''should display Child with response of the service'', () => {
expect(parent.html()).toMatch(''fakeReturnValue'')
});
});
Le sugiero que exporte aThingThatReturnsAPromise()
de su módulo o archivo y luego lo importe a su caso de prueba.
Ya que aThingThatReturnsAPromise()
devuelve una promesa, puede hacer uso de las funciones de prueba asíncronas de Jest. Jest esperará a que se cumpla su promesa y luego podrá hacer sus afirmaciones.
describe(''When rendering Parent'', () => {
var parent;
beforeAll(() => {
parent = mount(<Parent />)
});
it(''should display Child with response of the service'', () => {
expect.assertions(1);
return aThingThatReturnsAPromise().then( () => {
expect(parent.html()).toMatch(''fakeReturnValue'');
});
});
});
Para obtener más información, lea cómo Jest maneja los casos de prueba con Promesas en Jest Docs here
No tengo conocimiento de nada nativo de React para lograr lo que estás buscando.
Sin embargo, pude lograr esto en un código similar llamando a @All () ''sdone después de completar la configuración. Vea los cambios en su código a continuación:
let setupComplete;
jest.mock(''eternalService'', () => {
return jest.fn(() => {
return { doSomething: jest.fn((cb) => { cb(''fakeReturnValue''); setupComplete(); }) };
});
.
.
.
beforeAll(done => {
parent = mount(<Parent />)
setupComplete = done;
});
});
Nunca los he usado, pero de interés potencial son runAllTicks y runAllImmediates .
Si bien el pseudo código se puede refactorizar para que siga el ciclo de vida de React (usando componentWillMount()
componentDidMount()
, sería mucho más fácil de probar. Sin embargo, a continuación se encuentra mi pseudo código no probado para los cambios de sus códigos de prueba, no dude en probarlo y actualízalo. ¡Espero que te ayude!
describe(''When rendering Parent'', () => {
it(''should display Child with the response of the service'', function(done) => {
const parent = mount(<Parent />);
expect(parent.html()).toMatch(''fakeReturnValue'');
done();
});
});