Saltar al contenido principal
Versión: 30.0

Pruebas de código asíncrono

Traducción Beta No Oficial

Esta página fue traducida por PageTurner AI (beta). No está respaldada oficialmente por el proyecto. ¿Encontraste un error? Reportar problema →

Es común en JavaScript que el código se ejecute de forma asíncrona. Cuando tienes código que se ejecuta asíncronamente, Jest necesita saber cuándo ha finalizado el código que está probando antes de pasar a otra prueba. Jest ofrece varias formas de manejar esto.

Promesas

Devuelve una promesa desde tu prueba, y Jest esperará a que esa promesa se resuelva. Si la promesa es rechazada, la prueba fallará.

Por ejemplo, supongamos que fetchData devuelve una promesa que debe resolverse con la cadena 'peanut butter'. Podríamos probarlo con:

test('the data is peanut butter', () => {
return fetchData().then(data => {
expect(data).toBe('peanut butter');
});
});

Async/Await

Alternativamente, puedes usar async y await en tus pruebas. Para escribir una prueba asíncrona, usa la palabra clave async delante de la función pasada a test. Por ejemplo, el mismo escenario de fetchData se puede probar con:

test('the data is 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 (error) {
expect(error).toMatch('error');
}
});

Puedes combinar async y await con .resolves o .rejects.

test('the data is peanut butter', async () => {
await expect(fetchData()).resolves.toBe('peanut butter');
});

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

En estos casos, async y await son básicamente azúcar sintáctica para la misma lógica que utiliza el ejemplo de promesas.

precaución

Asegúrate de devolver (o usar await) la promesa. Si omites la sentencia return/await, tu prueba finalizará antes de que la promesa devuelta por fetchData se resuelva o rechace.

Si esperas que una promesa sea rechazada, usa el método .catch. Asegúrate de agregar expect.assertions para verificar que se llama a un número específico de afirmaciones. De lo contrario, una promesa cumplida no hará fallar la prueba.

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

Callbacks

Si no usas promesas, puedes utilizar callbacks. Por ejemplo, supongamos que fetchData, en lugar de devolver una promesa, espera un callback que llama con callback(null, data) cuando completa la obtención de datos. Quieres probar que estos datos devueltos sean la cadena 'peanut butter'.

Por defecto, las pruebas de Jest finalizan cuando alcanzan el final de su ejecución. Esto significa que esta prueba no funcionará como se espera:

// Don't do this!
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 la prueba finalizará tan pronto como fetchData se complete, sin haber llamado nunca al callback.

Existe una forma alternativa de test que soluciona esto. En lugar de poner la prueba en una función sin argumentos, usa un único argumento llamado done. Jest esperará hasta que se llame al callback done antes de finalizar 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 done() nunca se llama, la prueba fallará (con error de timeout), que es lo que deseas que ocurra.

Si la afirmación expect falla, lanza un error y done() no se llama. Si queremos ver en el registro de pruebas por qué falló, debemos envolver expect en un bloque try y pasar el error en el bloque catch a done. De lo contrario, obtendremos un error de timeout opaco que no muestra qué valor recibió expect(data).

precaución

Jest lanzará un error si la misma función de prueba recibe un callback done() y devuelve una promesa. Esto se hace como precaución para evitar fugas de memoria en tus pruebas.

.resolves / .rejects

También puedes usar el comparador .resolves en tu afirmación expect, y Jest esperará a que esa promesa se resuelva. Si la promesa es rechazada, la prueba fallará automáticamente.

test('the data is peanut butter', () => {
return expect(fetchData()).resolves.toBe('peanut butter');
});

Asegúrate de devolver la afirmación. Si omites esta sentencia return, tu prueba finalizará antes de que se resuelva la promesa devuelta por fetchData y then() tenga oportunidad de ejecutar el callback.

Si esperas que una promesa sea rechazada, usa el comparador .rejects. Funciona de manera análoga al comparador .resolves. Si la promesa se cumple, la prueba 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 puedes combinarlas en una misma base de código o incluso en un solo archivo. Simplemente depende del estilo que consideres que hace tus pruebas más sencillas.