Ir al contenido

Pasos y adjuntos en Jest

Los pasos de una prueba aparecen bajo su resultado en Probara, anidados tal como se ejecutaron, cada uno con su estado, su duración y su error. Los archivos que adjunta la prueba aparecen en el resultado, o en el paso en el que se adjuntaron. Jest no tiene pasos ni archivos propios (ni capturas de pantalla ni trazas): lo que lleva un resultado es lo que la prueba registró con los helpers probara.*, más su salida de consola si la activas.

probara.step(title, body, options) ejecuta body, lo registra como un paso y devuelve lo que devuelve el cuerpo, así que un paso puede calcular un valor que usa la prueba (cart más abajo):

tests/checkout.test.js
const { probara } = require('@probara/jest-reporter');
test('checks out', async () => {
const cart = await probara.step('Open the cart', async () => ({ items: 2 }));
await probara.step('Pay', async () => {
probara.step('Enter the card', () => {
expect(cart.items).toBe(2);
});
await probara.step('Confirm', async () => {
expect(await Promise.resolve('declined')).toBe('paid');
});
});
});
[
{
"status": "failed",
"steps": [
{ "action": "Open the cart", "status": "passed" },
{
"action": "Pay",
"status": "failed",
"steps": [
{ "action": "Enter the card", "status": "passed" },
{ "action": "Confirm", "status": "failed" }
]
}
]
}
]
El cuerpoEl pasoQué hace probara.step()
Devuelve un valorpassedDevuelve su valor
Lanza un errorfailed, con el mensaje y la traza del error; sus padres fallanLanza el mismo error: la prueba falla como siempre
Devuelve una promesa (async)Termina cuando la promesa se resuelve: passed, o failedDevuelve una promesa que se resuelve igual
Devuelve otro thenableTermina cuando el cuerpo retorna (más abajo)Lo devuelve sin tocarlo
Ninguno (probara.step('Seeded'))passed, sin duraciónDevuelve undefined
  • El anidamiento sigue las llamadas: un paso que empieza dentro del cuerpo de otro es su hijo, también a través de await. Dos pasos del mismo padre ejecutados con Promise.all son ambos sus hijos.
  • La duración se mide con el reloj de Node, así que los temporizadores simulados de Jest (jest.useFakeTimers()) nunca la alteran.
  • Un paso que nunca terminó (una promesa que la prueba no esperó, aún pendiente cuando termina la prueba) es failed, con el error The step had not finished when the test ended. Espera con await cada probara.step() que tenga un cuerpo async.
  • Hooks: un paso en beforeEach o afterEach es un paso de la prueba en curso. En beforeAll, afterAll o el cuerpo de un describe no se ejecuta ninguna prueba concreta: el cuerpo se ejecuta, y el paso no se registra.

Los pasos de un resultado registran lo que se ejecutó. Los pasos de un caso son su especificación: una acción, el resultado esperado y los datos de prueba. Los pasos más externos de un intento, en el orden en que empezaron, son los pasos del caso que crea el informe; expected y data van con ellos:

tests/refund.test.js
const { probara } = require('@probara/jest-reporter');
test('refunds an order', () => {
probara.step('Open the order', () => {}, { expected: 'The order is shown', data: 'order=1042' });
probara.step(
'Refund it',
() => {
probara.step('Confirm the dialog', () => {});
},
{ expected: 'The order is refunded' },
);
});
[
{
"steps": [
{ "action": "Open the order", "expected": "The order is shown", "data": "order=1042" },
{
"action": "Refund it",
"expected": "The order is refunded",
"steps": [{ "action": "Confirm the dialog" }]
}
],
"case": {
"steps": [
{ "action": "Open the order", "expected": "The order is shown", "data": "order=1042" },
{ "action": "Refund it", "expected": "The order is refunded" }
]
}
}
]
  • Los pasos anidados (Confirm the dialog) son solo pasos del resultado: cómo funciona una prueba, no lo que especifica.
  • Como cualquier campo del caso, los pasos del caso solo se aplican cuando el informe crea el caso (solo casos creados). Un caso existente conserva sus propios pasos.
  • expected y data son texto: un paso que recibe otra cosa se registra solo con su título, y una advertencia lo indica.

Un cuerpo que devuelve una promesa termina su paso cuando la promesa se resuelve. probara.step() devuelve una promesa nueva que se resuelve igual, así que await probara.step(...) se comporta como esperar el cuerpo. Un rechazo que la prueba nunca gestiona sigue siendo un rechazo no gestionado, que hace fallar la prueba, igual que sin el paso.

Un cuerpo también puede devolver un thenable que no es una promesa: una petición de supertest, un query builder. Llamar a su then() lo iniciaría (o lo iniciaría dos veces), así que probara.step() lo devuelve sin tocarlo, y el paso termina en cuanto el cuerpo retorna, antes de que se envíe la petición. Para medir la petición dentro del paso, espérala en un cuerpo async:

tests/api.test.js
const { probara } = require('@probara/jest-reporter');
// A stand-in for a supertest request: it runs when awaited.
const request = () => ({ then: (resolve) => resolve({ status: 200 }) });
test('answers the health check', async () => {
const response = await probara.step('Call /health', async () => await request());
expect(response.status).toBe(200);
});
[{ "status": "passed", "steps": [{ "action": "Call /health", "status": "passed" }] }]

Pásale un archivo en disco o un cuerpo. Funciona desde cualquier lugar en el que se ejecute una prueba: el cuerpo de la prueba, un hook beforeEach o afterEach, un helper o un page object al que llama la prueba.

tests/receipt.test.js
const { writeFileSync } = require('node:fs');
const { tmpdir } = require('node:os');
const { join } = require('node:path');
const { probara } = require('@probara/jest-reporter');
test('prints the receipt', () => {
const path = join(tmpdir(), 'receipt.txt');
writeFileSync(path, 'Total: 25.00');
probara.attach({ name: 'receipt', path });
probara.attach({
name: 'order',
body: JSON.stringify({ id: 1042, total: 25 }),
contentType: 'application/json',
});
probara.attach({ name: 'log', body: 'paid in 1.2 s' });
});

El resultado recibe tres archivos:

receipt.txt text/plain
order.json application/json
log.txt text/plain
CampoCon pathCon body
nameObligatorio: el nombre en Probara; se añade la extensión del archivo si no tieneObligatorio: el nombre en Probara; se añade la extensión del tipo de contenido si no tiene
pathEl archivo, absoluto o relativo al directorio en el que se ejecuta jest—
body—Un string, un Buffer o un Uint8Array, enviado tal cual
contentTypeOpcional: se deduce del nombre del archivoOpcional: se deduce de la extensión de name; si no, text/plain para un string y application/octet-stream para bytes
  • Se copia al llamarlo. El archivo (o el cuerpo) se copia en el momento, así que una prueba puede borrarlo o sobrescribirlo justo después: Probara recibe lo que había en el momento de la llamada. probara.attach() devuelve una promesa ya resuelta; esperarla no hace daño.
  • Un string se envía tal cual, nunca se decodifica: pasa un Buffer para contenido binario.
  • Un archivo que no se puede adjuntar (porque no existe, por ejemplo) es una advertencia [probara] en el registro del reporter; la prueba continúa.
  • Cada intento tiene sus propios archivos: una prueba reintentada sube los archivos de cada intento, cada uno a su propio resultado.

Un archivo adjuntado mientras se ejecuta un probara.step() (desde el cuerpo del paso o desde cualquier cosa a la que llame) va a ese paso, y Probara lo muestra bajo el paso:

tests/upload.test.js
const { probara } = require('@probara/jest-reporter');
test('uploads an avatar', async () => {
await probara.step('Choose the file', async () => {
probara.attach({ name: 'avatar.png', body: Buffer.from([137, 80, 78, 71]) });
});
});
avatar.png image/png

Con captureOutput: true (PROBARA_CAPTURE_OUTPUT=true) y el archivo de setup del reporter, la salida de consola de cada intento se adjunta como stdout.log (console.log, console.info, console.debug) y stderr.log (console.warn, console.error), cuando la hay, incluidos sus hooks beforeEach y los hooks afterEach de sus bloques describe:

jest.config.js
module.exports = {
reporters: ['default', ['@probara/jest-reporter', { captureOutput: true }]],
setupFilesAfterEnv: ['@probara/jest-reporter/setup'],
};
tests/logs.test.js
beforeEach(() => {
console.info('Seeding the cart');
});
test('prints what it does', () => {
console.log('Opening the cart');
console.error('Slow response: 2.1 s');
});
stdout.log text/plain
stderr.log text/plain

Jest sigue mostrando la salida como siempre. El archivo de setup envuelve la consola de cada archivo de prueba, en cada worker; sin él, las pruebas se ejecutan y se reportan sin su salida, con una advertencia:

[probara] captureOutput needs the setup file: add setupFilesAfterEnv: ['@probara/jest-reporter/setup'] to the Jest config (first seen in tests/checkout.test.js; repeats are logged at debug)
No se capturaPor qué
console.dir, table, group, count, time, timeEnd, trace, assertSolo se envuelven los cinco métodos de arriba
process.stdout.write, process.stderr.writeNo pasan por la consola
La salida de las pruebas test.concurrentSus cuerpos se ejecutan fuera de los beforeEach/afterEach de cada prueba
La salida de un afterEach de nivel superior del archivo de pruebaEl afterEach del propio archivo de setup, que termina la captura, se ejecuta antes
Un método de consola que la prueba simuló (jest.spyOn(console, 'log').mockImplementation(...), console.log = jest.fn())El mock recibe las llamadas; un spy que llama al original sí se captura
La salida en beforeAll, afterAll, el cuerpo de un describe o el ámbito del móduloAhí no se ejecuta ninguna prueba concreta

Cada flujo se corta a 32 MiB, el archivo más grande que acepta Probara, con una última línea que indica el corte. Con projects de Jest, pasa el archivo de setup a cada proyecto que lo necesite (proyectos de Jest).

LímiteQué pasa
32 MiB por archivoUn archivo mayor se omite con una advertencia
20 archivos por resultadoLos archivos que siguen a los 20 primeros se omiten, con una advertencia
Imágenes de más de 10 MiB o de más de 8192 px de ancho o altoSe omiten con una advertencia (Probara convierte las imágenes a WebP)
Ejecutables y scriptsSe omiten: Probara rechaza sus tipos de contenido
Un archivo que falta, que no se puede leer o que está vacíoSe omite con una advertencia
Un resultado que no registró nadaSus archivos no se suben

Las advertencias nombran el archivo, y el registro termina con cuántos archivos se adjuntaron, se omitieron y fallaron. uploadAttachments: false (PROBARA_UPLOAD_ATTACHMENTS=false) no sube ninguno. Cada resultado con archivos cuesta dos peticiones más frente al límite de peticiones de la organización.

Los archivos se suben después de que su informe queda registrado, mientras la ejecución sigue abierta, y después se cierra la ejecución. Hasta entonces, el reporter guarda sus copias en una carpeta del directorio temporal del sistema, que se elimina cuando termina jest; con un archivo de resultados, las copias de lo que no se envió se guardan junto a él.

  • Falta un paso. Solo probara.step() crea pasos: las llamadas a expect y las funciones auxiliares no. Un paso llamado fuera de una prueba (beforeAll, el cuerpo de un describe) ejecuta su cuerpo y no registra nada, con una advertencia.
  • Los pasos salen aplanados, o fallan con The step had not finished. Un paso iniciado sin await termina después de la prueba: espera con await cada probara.step() cuyo cuerpo sea async.
  • El caso no tiene pasos. Solo un caso que crea el informe recibe pasos. Un caso existente conserva los suyos.
  • Falta un archivo. El registro nombra cada archivo que omitió y por qué. Un archivo adjuntado dentro de un paso va a ese paso, no al resultado (solución de problemas).

Relacionado: Metadatos y enlaces · Configuración · Solución de problemas · Fuente: steps.md, attachments.md