Skip to main content
Version: 27.x

Tests de código asíncrono

Es común en JavaScript ejecutar código de forma asíncrona. Si tienes código que se ejecuta de forma asíncrona, Jest debe saber cuándo ha terminado de ejecutarse el código de prueba, antes de que puede pasar a otro test. Jest tiene varias formas de manejar esto.

Promesas

Devolver una promesa desde el test, y Jest esperará a que esa promesa resuelva. If the promise is rejected, the test will fail.

For example, let's say that fetchData returns a promise that is supposed to resolve to the string 'peanut butter'. Podríamos testearlo con:

test('el dato es peanut butter', () => {
return fetchData().then(data => {
expect(data).toBe('peanut butter');
});
});

Async/Await

Como alternativa, se puede usar async y await en tests. Para escribir un test asíncrono, sólo tienes que utilizar la palabra clave async al frente de la función pasada al test. Por ejemplo, puede probarse el mismo escenario de fetchData con:

test(el dato es peanut butter', async () => {
const data = await fetchData();
expect(data).toBe('peanut butter');
});

test('the fetch fails with an error', async () => {
expect.assertions(1);
try {
await fetchData();
} catch (e) {
expect(e).toMatch('error');
}
});

Puede combinar async y await con resolves o rejects.

test('el dato es peanut butter', async () => {
await expect(fetchData()).resolves.toBe('peanut butter');
});

test('el fecth falla con un error', async () => {
await expect(fetchData()).rejects.toMatch('error');
});

En estos casos, async y await son simplemente una mejora sintáctica para la misma lógica usada en los ejemplos de las promesas.

caution

Be sure to return (or await) the promise - if you omit the return/await statement, your test will complete before the promise returned from fetchData resolves or rejects.

Si esperas que una promesa se rechazada, usa el método catch. Asegúrate de añadir expect.assertions para verificar que un cierto número de afirmaciones están siendo llamadas. De lo contrario, una promesa cumplida no hará que el test falle.

test('el fetch falla con un error', () => {
expect.assertions(1);
return fetchData().catch(e => expect(e).toMatch('error'));
});

Callbacks

If you don't use promises, you can use callbacks. For example, let's say that fetchData, instead of returning a promise, expects a callback, i.e. fetches some data and calls callback(null, data) when it is complete. Quieres comprobar que devuelve 'peanut butter'.

Por defecto, Jest da por completos los tests una vez que llegan al final de su ejecución. Esto significa que este test no funciona como estaba previsto:

// ¡No hagas esto!
test('the data is peanut butter', () => {
function callback(error, data) {
if (error) {
throw error;
}
expect(data).toBe('peanut butter');
}

fetchData(callback);
});

El problema es que el test terminará tan pronto como fetchData finalize, antes de llamar a la función callback.

Hay una forma alternativa de test que soluciona esto. En lugar de poner el test en una función con un argumento vacío, utilice un solo argumento llamado done. Jest esperará hasta que se llame el callback done antes de terminar la prueba.

test('the data is peanut butter', done => {
function callback(error, data) {
if (error) {
done(error);
return;
}
try {
expect(data).toBe('peanut butter');
done();
} catch (error) {
done(error);
}
}

fetchData(callback);
});

Si no se llama la función done(), la prueba fallará (por tiempo de espera excedido), que es lo que quieres que ocurra.

Si la sentencia expect falla, lanza un error y done() no es llamada. Si queremos ver en el registro de pruebas por qué falló, tenemos que envolver el expect en un bloque try y pasar el error en el bloque catch a done. De lo contrario, terminamos con un error de tiempo de espera no explicativo que no muestra qué valor fue recibido por expect(data).

Note: done() should not be mixed with Promises as this tends to lead to memory leaks in your tests.

resolves / rejects

También puede utilizar el matcher .resolves en su declaración de expect y Jest esperará a que esa promesa resuelva. Si se rechaza la promesa, la prueba fallará automáticamente.

test('el dato es peanut butter', () => {
return expect(fetchData()).resolves.toBe('peanut butter');
});

Asegúrate de devolver la aserción—si omites este return su test se completará antes de que la promesa devuelta de fetchData sea resuelta y then() ejecutará el callback.

Si esperas que una promesa sea rechazada usa el matcher rejects. Actúa análogamente al marcador .resolves. Si se cumple la promesa, el test fallará automáticamente.

test('the fetch fails with an error', () => {
return expect(fetchData()).rejects.toMatch('error');
});

Ninguna de estas formas es particularmente superior a las demás, y se pueden mezclar y combinar a través de una base de código o incluso en un solo archivo. Depende del estilo que sientas que hace tus tests más sencillos.