Ir al contenido

Migrar al reporter de Jest

Vengas de donde vengas, el reporter es una entrada en reporters, con un archivo de setup opcional, y los helpers probara.* funcionan en cada worker de Jest, en banda, en los entornos node y jsdom, y en modo watch. Conservas tu propio testEnvironment.

jest.config.js
module.exports = {
reporters: ['default', ['@probara/jest-reporter', { projectId: 'SHOP' }]],
setupFilesAfterEnv: ['@probara/jest-reporter/setup'],
};

El archivo de setup solo hace falta para captureOutput y para la selección de pruebas.

Vienes deVe a
jest-junit y probara import junitLa importación JUnit
jest-qase-reporterQase
testit-adapter-jestTest IT
@reportportal/agent-js-jestReportPortal
allure-jestAllure
jest-junit y trcli parse_junitTestRail

Si tu pipeline escribe un informe con jest-junit y lo envía con probara import junit, el reporter puede sustituir ambos pasos sin desvincular ni un solo caso: da a cada prueba la clave de automatización que le da la importación. Un ajuste decide qué claves: si jest-junit escribió el archivo de prueba en el informe.

  1. Averigua cómo se ejecutaba jest-junit en tu pipeline: con JEST_JUNIT_ADD_FILE_ATTRIBUTE=true (o addFileAttribute: 'true' en sus opciones), o sin él (su valor por defecto).
  2. Añade el reporter a la configuración de Jest. Sin el atributo de archivo, define también keyIncludesFile: false.
  3. Comprueba las claves de ambos con las mismas pruebas: deben ser iguales.
  4. En CI, elimina jest-junit y el paso de importación, y pasa PROBARA_API_TOKEN al paso de pruebas.
jest-junit escribióAjuste del reporter
El atributo de archivo (JEST_JUNIT_ADD_FILE_ATTRIBUTE=true)Nada: keyIncludesFile: true es el valor por defecto
Sin atributo de archivo (el valor por defecto de jest-junit)keyIncludesFile: false (PROBARA_KEY_INCLUDES_FILE)

Las claves son las que da la importación con las plantillas por defecto de jest-junit: los bloques describe y el título unidos con espacios ({classname} {title}). Un informe escrito con otras plantillas (classNameTemplate, titleTemplate, ancestorSeparator, suiteNameTemplate) tiene otras claves: la comprobación de abajo muestra la diferencia, y los IDs en los títulos mantienen esas pruebas vinculadas sean cuales sean sus claves.

Ejecuta la batería una vez con jest-junit y otra con el archivo de resultados del reporter, con el envío desactivado, y compara las simulaciones de ambos: cada una imprime una línea por resultado, con su estado, su caso y su clave. Para este archivo de prueba:

tests/refund.test.js
describe('refund', () => {
test('SHOP-12 refunds an order', () => {
expect(25 - 25).toBe(0);
});
test('keeps the receipt', () => {
expect('receipt').toHaveLength(7);
});
test.todo('refunds a gift card');
});
$ JEST_JUNIT_ADD_FILE_ATTRIBUTE=true npx jest --reporters=default --reporters=jest-junit
$ npx @probara/cli import junit junit.xml --dry-run
passed SHOP-12 tests/refund.test.js > refund refunds an order
passed - tests/refund.test.js > refund keeps the receipt
passed - tests/refund.test.js > refund refunds a gift card
Total: 3 results from 1 file (3 passed, 0 failed, 0 skipped, 0 blocked)
$ PROBARA_ENABLED=false PROBARA_RESULTS_FILE=probara-results.json npx jest
[probara] Wrote 3 results to /work/shop/probara-results.json: send them with probara import results /work/shop/probara-results.json
$ npx @probara/cli import results probara-results.json --dry-run
passed SHOP-12 tests/refund.test.js > refund refunds an order
passed - tests/refund.test.js > refund keeps the receipt
skipped - tests/refund.test.js > refund refunds a gift card
Total: 3 results from 1 file (2 passed, 0 failed, 1 skipped, 0 blocked)

Las claves y los casos son los mismos; solo difiere el estado del test.todo (consulta qué cambia). En una batería real, escribe cada simulación en un archivo y compáralas con diff: una línea cuya clave cambió es una prueba que recibiría un caso nuevo. Borra después junit.xml y el archivo de resultados.

Antes, dos pasos: jest-junit escribe el informe, y la CLI lo envía.

- name: Run Jest tests
run: npx jest --ci --reporters=default --reporters=jest-junit
env:
JEST_JUNIT_ADD_FILE_ATTRIBUTE: 'true'
- name: Send the results
if: ${{ !cancelled() }}
run: npx @probara/cli import junit junit.xml
env:
PROBARA_API_TOKEN: ${{ secrets.PROBARA_API_TOKEN }}
PROBARA_PROJECT: SHOP

Después, un paso: el reporter, registrado en la configuración de Jest, envía cada resultado al final del paso de pruebas.

- name: Run Jest tests
run: npx jest --ci
env:
PROBARA_API_TOKEN: ${{ secrets.PROBARA_API_TOKEN }}
PROBARA_PROJECT: SHOP

Quita --reporters=jest-junit (sustituiría los reporters de la configuración, incluido el reporter), y el propio jest-junit salvo que otra cosa lea su informe. La ejecución recibe el nombre, el origen y el cierre como lo hacía la importación.

Qué cambia respecto a la importación JUnit

Sección titulada «Qué cambia respecto a la importación JUnit»
Temaprobara import junit sobre jest-junitEl reporter
test.todopassed: jest-junit escribe un todo como un testcase aprobadoskipped, con la nota Todo: una prueba aún no escrita nunca cuenta como aprobada
Reintentos (jest.retryTimes)Solo el último intentoCada intento, en orden; el caso de la ejecución conserva el último resultado
Pruebas excluidas por -t o .onlyskippedskipped también
Un hook afterAll que fallaUn testcase fallido más para el archivoEl mismo resultado fallido, con la misma clave
Un archivo que no se cargaNada (jest-junit no escribe nada para él por defecto)Nada que reportar, y una advertencia nombra el archivo
Cuándo se envían los resultadosDespués de toda la ejecución, en un paso posteriorAl final de la ejecución, desde el paso de pruebas; un archivo de resultados guarda lo que no se pudo enviar
Suite de un caso creado, sin el archivoEl primer describe de la primera prueba del archivo, para todas las pruebas del archivoEl primer describe de cada prueba (ninguno para una prueba fuera de cualquier describe)

La última fila solo cambia a dónde va un caso que crea el informe, con keyIncludesFile: false: una prueba nueva en un archivo cuyas pruebas están en distintos describes de nivel superior. Su clave, y por tanto el caso que encuentra una prueba existente, es la misma. Con el atributo de archivo, ambos ponen un caso creado en una suite con el nombre del archivo.

El reporter sigue al pie de la letra la forma de nombrar de jest-junit, peculiaridades incluidas, para que las claves sigan siendo iguales: {displayName} se convierte en el nombre del proyecto de Jest, los patrones $ de String.replace en un título se expanden como en las plantillas de jest-junit, y un archivo cuyo afterAll lanza un error recibe el resultado fallido extra con la clave <file> > Test execution failure: could be caused by test hooks like 'afterAll'.

Lo que ganas: cada intento de una prueba reintentada; pasos anidados; archivos y salida de consola; enlaces e incidencias; parámetros y los campos de los casos nuevos; la selección de pruebas; y los resultados fallidos asignados a las personas que indiques, como hacía --assign-failed-to en la importación.

Pasar de jest-qase-reporter es sobre todo cambiar nombres: la entrada del reporter, sus ajustes y las llamadas qase.*. Por el camino, una cosa mejora: los helpers probara.* funcionan en cada worker de Jest, en jsdom y en modo watch, mientras que los de Qase solo funcionan en banda.

  1. npm uninstall jest-qase-reporter && npm i -D @probara/jest-reporter.
  2. En la configuración de Jest, sustituye ['jest-qase-reporter', {...}] por ['@probara/jest-reporter', {...}], traduciendo las opciones (abajo). Borra qase.config.json y .qaserc: el reporter solo lee sus opciones y las variables PROBARA_*.
  3. Sustituye en CI las variables QASE_* por las PROBARA_*: como mínimo PROBARA_API_TOKEN (un token de aplicación de la tarjeta Jest) y PROBARA_PROJECT.
  4. Sustituye require('jest-qase-reporter/jest') por require('@probara/jest-reporter'), y traduce las llamadas (abajo). Los IDs de caso pasan a ser IDs visibles de Probara (SHOP-12), no números.
  5. Quita --runInBand si lo añadiste solo por los helpers de Qase: los de Probara no necesitan nada.

Antes:

jest.config.js
module.exports = {
reporters: [
'default',
[
'jest-qase-reporter',
{
mode: 'testops',
testops: {
project: 'SHOP',
run: { title: 'Nightly', complete: true, tags: ['nightly'] },
uploadAttachments: true,
},
},
],
],
};

Después:

jest.config.js
module.exports = {
reporters: [
'default',
[
'@probara/jest-reporter',
{ projectId: 'SHOP', run: { name: 'Nightly', tags: ['nightly'] }, captureOutput: true },
],
],
setupFilesAfterEnv: ['@probara/jest-reporter/setup'],
};

captureOutput y su archivo de setup son opcionales: adjuntan la salida de consola de cada prueba, algo que captureLogs de Qase nunca hizo para Jest.

Opción de Qase (variable QASE_*)Opción de Probara (variable PROBARA_*)
mode: 'testops' (QASE_MODE)Activado siempre que haya un token y un proyecto
mode: 'off'enabled: false (PROBARA_ENABLED=false), o sin token
mode: 'report', fallback (QASE_FALLBACK)resultsFile (PROBARA_RESULTS_FILE)
mode: 'testops_multi', testops_multi.*projectId más projects y run.ulids
debug (QASE_DEBUG)debug (PROBARA_DEBUG)
environment (QASE_ENVIRONMENT), un slug, ignorado si no existerun.environment (PROBARA_ENVIRONMENT), un nombre, que se crea si falta
rootSuite (QASE_ROOT_SUITE)suiteUlid (PROBARA_SUITE_ULID): una suite existente, por ULID
captureLogs (QASE_CAPTURE_LOGS): el reporter de Jest de Qase lo ignoracaptureOutput (PROBARA_CAPTURE_OUTPUT), con el archivo de setup
statusMapping (QASE_STATUS_MAPPING)statusMapping (PROBARA_STATUS_MAPPING), sin invalid ni disabled
logging.console, logging.fileLos registros van a stderr; la opción logger para código
testops.api.token (QASE_TESTOPS_API_TOKEN)PROBARA_API_TOKEN (apiToken para código)
testops.api.host (QASE_TESTOPS_API_HOST)baseUrl (PROBARA_BASE_URL), una URL completa
testops.api.timeout (segundos)timeoutMs (milisegundos), para cada petición
testops.api.retries, testops.api.retryBackoffmaxRetries, para cada petición; el backoff es fijo
testops.project (QASE_TESTOPS_PROJECT)projectId (PROBARA_PROJECT)
testops.uploadAttachmentsuploadAttachments (PROBARA_UPLOAD_ATTACHMENTS)
testops.attachments.concurrency, .timeoutattachmentConcurrency; las subidas tienen al menos 120 s
testops.run.id (QASE_TESTOPS_RUN_ID)run.ulid (PROBARA_RUN_ULID)
testops.run.title, .description, .tagsrun.name, run.description, run.tags (PROBARA_RUN_*)
testops.run.complete (QASE_TESTOPS_RUN_COMPLETE)closeRun (PROBARA_CLOSE_RUN); una ejecución creada se cierra por defecto
testops.plan.id (QASE_TESTOPS_PLAN_ID)run.plan (PROBARA_PLAN): el ID visible o el nombre del plan
testops.configurations.values (group=value)run.configurations (PROBARA_CONFIGURATIONS=Group=Name)
testops.statusFilter (QASE_TESTOPS_STATUS_FILTER)statusFilter (PROBARA_STATUS_FILTER); skipped también descarta las pruebas todo
testops.batch.size (QASE_TESTOPS_BATCH_SIZE)chunkSize (de 1 a 500)
(ninguna)run.milestone (PROBARA_MILESTONE): el reporter de Qase no tiene hitos
QaseProbara
test(qase(12, 'pays'), ...), (Qase ID: 12) en un títulotest('SHOP-12 pays', ...): un ID en el título o en un describe
test(qase([12, 13], 'pays'), ...)test('SHOP-12 SHOP-13 pays', ...), o probara.id(['SHOP-12', 'SHOP-13'])
qase.projects({ WEB: [3] }, 'pays')WEB-3 en el título, con projects: ['WEB']
(ninguna: el reporter de Jest de Qase no tiene qase.id())probara.id('SHOP-12')
qase.title('...')probara.title('...')
qase.suite('Payments')probara.suite('Payments'), o probara.suite(['Payments', 'Cards']) para anidar
qase.fields({ severity: 'critical' })probara.fields({ severity: 'critical' })
qase.tags('smoke')probara.tags('smoke')
qase.comment('...')probara.comment('...')
qase.ignore()probara.ignore()
qase.parameters({...}), qase.groupParameters({...})probara.parameters({...})
qase.attach({ paths: [a, b] })probara.attach({ name, path }), una vez por archivo
qase.attach({ name, content, type })probara.attach({ name, body, contentType })
await qase.step('Pay', fn, 'Paid', 'card=visa')await probara.step('Pay', fn, { expected: 'Paid', data: 'card=visa' })
s.step(...), s.attach(...) dentro del cuerpo de un pasoprobara.step(...), probara.attach(...) dentro del cuerpo: se anidan solos

Antes:

tests/checkout.test.js
const { qase } = require('jest-qase-reporter/jest');
test(qase(12, 'pays with a card'), async () => {
qase.fields({ severity: 'critical' });
qase.tags('smoke');
await qase.step('Pay', async () => {}, 'The order is paid');
qase.attach({ name: 'order.json', content: '{"id":1042}', type: 'application/json' });
});

Después:

tests/checkout.test.js
const { probara } = require('@probara/jest-reporter');
test('SHOP-12 pays with a card', async () => {
probara.fields({ severity: 'critical' }).tags('smoke');
await probara.step('Pay', async () => {}, { expected: 'The order is paid' });
await probara.attach({
name: 'order.json',
body: '{"id":1042}',
contentType: 'application/json',
});
});
[
{
"caseDisplayId": "SHOP-12",
"automationKey": "tests/checkout.test.js > pays with a card",
"status": "passed",
"steps": [{ "action": "Pay", "expected": "The order is paid", "status": "passed" }],
"case": {
"tags": ["smoke"],
"fields": { "severity": "critical" },
"steps": [{ "action": "Pay", "expected": "The order is paid" }]
}
}
]

El ID sale del título y de la clave: añadirlo o quitarlo nunca cambia qué caso encuentra la prueba.

Las llamadas qase.* de Qase llegan a su reporter a través de una variable global del proceso principal de Jest. Esa global solo existe en una prueba cuando Jest se ejecuta en banda y el entorno de prueba es node: con workers (lo que usa Jest por defecto con más de un archivo), en jsdom, y siempre en modo watch, las llamadas lanzan un error y hacen fallar la prueba. Además, Jest decide por su cuenta si ejecuta en banda o con workers, según los tiempos de ejecuciones anteriores, así que la misma batería puede pasar un día y fallar al siguiente.

Los helpers de Probara escriben en un canal al que llega cada worker, y cada llamada identifica su prueba por su archivo, su nombre completo y su intento. Funcionan en workers, en banda, en node y jsdom, en modo watch y en pruebas test.concurrent; una llamada fuera de una prueba en curso se omite con una advertencia, nunca se lanza como error.

Qué es distinto respecto a Qase, y por qué

Sección titulada «Qué es distinto respecto a Qase, y por qué»
TemaQaseProbara
PrecedenciaSu código hace que las variables ganen a qase.config.json, que gana a las opciones del reporter (su documentación dice lo contrario)Opciones en la configuración de Jest, después variables PROBARA_*, después valores por defecto: lo que dice la configuración es lo que se ejecuta
Archivo de configuraciónqase.config.json o .qasercNinguno: un archivo de configuración con un token podría acabar en el repositorio. Las opciones viven en la configuración de Jest
IDs de casoNúmeros, solo en el título de la propia pruebaIDs visibles (SHOP-12) en el título o en cualquier describe: el ID del Proyecto dirige cada ID a su proyecto
Atribución de metadatosPor tiempos: las llamadas van a la siguiente prueba que reporta (las de beforeAll a la primera, las de afterAll a la del archivo siguiente)Por identidad: cada llamada pertenece a la prueba que la ejecuta; fuera de una prueba se omite con una advertencia
PasosPlanos, los hijos antes que su padre; el resultado esperado y los datos codificados en el nombre del pasoAnidados tal como se ejecutaron, cada uno con su estado, duración y error; expected y data como opciones
Adjuntos de pasosSolo a través del s.attach() del cuerpo del paso; qase.attach() siempre va a la pruebaprobara.attach() dentro de un paso va a ese paso
test.failingUn cuerpo que lanza un error pasa; un cuerpo que pasa suele quedar invalidEl veredicto de Jest: un cuerpo que lanza un error pasa, un cuerpo que pasa falla
Estadosinvalid para un fallo cuyo error no parece una aserción (una suposición a partir del mensaje)passed, failed, skipped; blocked solo mediante statusMapping. Sin suposiciones a partir del texto del error
test.todoOmitido, pero statusFilter necesita disabled para descartarloOmitido, con la nota Todo; statusFilter: ['skipped'] lo descarta
Pruebas excluidas por -t o .onlySe reportan como omitidasTambién se reportan como omitidas: Jest las reporta así, y el reporter envía lo que reporta Jest
Un afterAll que fallaNo se reporta: las pruebas siguen en verde en QaseUn resultado fallido más para el archivo, el que escribe jest-junit
Un archivo que no se cargaNo se reporta ni se dice nadaNada que reportar (no se ejecutó ninguna prueba), y una advertencia nombra el archivo
qase.comment()Sustituye el mensaje de error de un resultado fallidoSe escribe al principio de las notas, antes del error, que se conserva
Llamadas a fields() y parameters()La última llamada sustituye a las demásSe combinan por nombre
Campos del casoSe envían con cada resultadoSolo cuando el informe crea el caso: un caso existente conserva lo que escribieron las personas
Cierre de la ejecuciónSolo con run.complete: true; sin definir la deja abiertaUna ejecución que crea el reporter se cierra al final; una reutilizada queda abierta
ShardsCada shard crea su propia ejecución salvo que reciba un ID de ejecuciónprobara run create, cada shard con PROBARA_RUN_ULID, y después probara run close
Modo watchUna ejecución nueva por repetición; los helpers lanzan errores (nunca en banda)Una ejecución para toda la sesión, que queda abierta
Cuando falla el envíofallback a un informe local, de forma definitiva, desde el primer errorUn archivo de resultados, que probara import results envía después a las mismas ejecuciones
Strings en attach()Un string que parece base64 se decodifica ('Hello' sube basura)Un string se envía tal cual; pasa un Buffer para contenido binario
attach({ paths })Debe ser un array (un string se lee carácter a carácter); el tipo de contenido es type, no contentTypeUn archivo por llamada, path o body, y contentType
El final de la ejecuciónNo se espera: --forceExit puede cortar los últimos resultadosJest espera al reporter: cada resultado se envía antes de que Jest salga
Ejecutar solo las pruebas de un planUna CLI externa (qasectl) construye un filtro -trunCasesOnly ejecuta solo las pruebas de los casos de una ejecución
Función de QasePor qué
Enlace público al informe (showPublicReportLink)Un enlace público a los resultados de las pruebas es una decisión de compartición de la aplicación Probara, no algo que deba activar un job de CI
Defectos automáticos (testops.defect)Registrar un defecto por cada fallo inunda la lista de defectos; reporta los defectos desde el resultado en Probara
Perfilador de red (profilers: ['network'])Registra las llamadas HTTP del proceso principal, lo que en Jest significa solo en banda, y es ruido; adjunta en su lugar lo que importe
Enlace de Jira en las ejecuciones (run.externalLink)Probara vincula las incidencias de Jira a casos y defectos, que es donde vive la trazabilidad; probara.issue() vincula un resultado a una incidencia
qase.mute()Qase lo documenta, pero no existe en su reporter
Crear configuraciones (createIfNotExists)Las configuraciones forman parte de la planificación de un proyecto; una desconocida se rechaza, así que una errata nunca crea una nueva
El estado invalidEs una suposición a partir del texto del error; Probara mantiene cuatro estados y el error completo en las notas
Registrar en un archivo (logging.file)Los registros van a stderr, donde los guarda el CI; redirige stderr para tener un archivo
Plan y entorno por proyecto (testops_multi.projects[].plan, .environment)Las entidades de planificación pertenecen a un proyecto, donde un nombre desconocido rechazaría el informe: crea primero la ejecución de ese proyecto y pásala en run.ulids

testit-adapter-jest es un entorno de prueba (testEnvironment: 'testit-adapter-jest') con un globalSetup y un globalTeardown: cada worker envía sus propios resultados a Test IT, archivo de prueba por archivo de prueba. Sustituye los tres por la entrada del reporter del principio de esta página.

// jest.config.js (before)
module.exports = {
testEnvironment: 'testit-adapter-jest',
globalSetup: 'testit-adapter-jest/dist/globalSetup.js',
globalTeardown: 'testit-adapter-jest/dist/globalTeardown.js',
testEnvironmentOptions: {
url: 'https://testit.example.com',
projectId: '5236eb3f-7c05-46f9-a609-dc0278896464',
adapterMode: 2,
testRunName: 'Nightly',
},
};
Ajuste de Test IT (variable)Probara (variable)
url (TMS_URL)baseUrl (PROBARA_BASE_URL), solo para un Probara autoalojado
privateToken (TMS_PRIVATE_TOKEN)PROBARA_API_TOKEN: un token de aplicación de la tarjeta Jest
projectId (TMS_PROJECT_ID), un UUIDprojectId (PROBARA_PROJECT), el ID del Proyecto (SHOP)
configurationId (TMS_CONFIGURATION_ID)run.configurations (PROBARA_CONFIGURATIONS=Browser=Chrome), por nombre
adapterMode: 2, una ejecución nuevaEl valor por defecto: cada jest crea una ejecución y la cierra al final
adapterMode: 1 y testRunId (TMS_TEST_RUN_ID)run.ulid (PROBARA_RUN_ULID): reportar en una ejecución existente, que queda abierta
testRunName (TMS_TEST_RUN_NAME)run.name (PROBARA_RUN_NAME), solo para una ejecución nueva
testRunTags (TMS_TEST_RUN_TAGS)run.tags (PROBARA_RUN_TAGS)
automaticCreationTestCasescreateMissingCases (PROBARA_CREATE_MISSING_CASES), activado por defecto
syncStorageEnabled, syncStoragePort, importRealtimeNada que definir: cada resultado pasa por el reporter en el proceso principal de Jest
LOG_LEVEL=debugdebug (PROBARA_DEBUG)
Llamada de Test IT (testit.*)Probara (probara.*)
workItemIds(['1042']), workItemId('1042')id('SHOP-12'), o SHOP-12 en el título o en un describe
displayName('...'), title('...')title('...'): el título del caso que crea un informe
description('...')fields({ description: '...' })
labels(['smoke']), tags(['smoke'])tags('smoke')
layer('API')fields({ layer: 'API' }), un campo de sistema del caso
namespace('...'), classname('...')suite(['...', '...']): la ruta de suites del caso que crea un informe
params({ user: 'ana' })parameters({ user: 'ana' })
step('Pay', 'description')step('Pay', () => {...}, { expected: '...' }): anidado, con estado y duración
addAttachments(['a.png'])attach({ name: 'a.png', path: 'a.png' }), una vez por archivo
addAttachments('text', 'log.txt')attach({ name: 'log.txt', body: 'text' })
addLinks({ url, title }), links([...])link(url, title), una vez por enlace
addMessage('...')comment('...')
TemaTest ITProbara
IdentidadUn hash del archivo y del título de la propia prueba: dos pruebas con el mismo título en distintos describes colisionanEl archivo, cada describe y el título
Pruebas omitidas y test.todoNo se reportanSe reportan como omitidas (Todo en las notas de un todo)
PasosPlanos, sin estado ni duraciónAnidados, cada uno con su estado, su duración y su error
test.concurrentUn búfer por archivo de prueba: las pruebas concurrentes sobrescriben los datos de las demásCada llamada pertenece a la prueba que la hizo
Cierre de la ejecuciónEl adaptador nunca la cierraUna ejecución que crea el reporter se cierra al final; una reutilizada queda abierta
Nombre de una ejecución existenteSe renombra a testRunNameNunca cambia: las opciones de una ejecución nueva se ignoran en una reutilizada, con una advertencia
PrecedenciaDepende del tipo: los strings primero desde las opciones, los booleanos primero desde tms.config.jsonOpciones, después variables PROBARA_*, después valores por defecto, para cada ajuste
Ejecutar las pruebas de una ejecuciónUna CLI externa escribe un filtro -trunCasesOnly lee por sí mismo los casos de la ejecución

Lo que no se porta de Test IT:

Test ITPor qué
automaticUpdationLinksToTestCases, actualizar autotestsUn informe nunca cambia un caso existente: lo que está escrito ahí es de las personas
testit.externalId()La clave sale del archivo y de los nombres, igual que la de probara import junit; vincula un caso por su ID
Pasos de setup y teardown desde hooksLos hooks son cómo se ejecuta una prueba, no lo que especifica; envuelve lo importante en probara.step()
testRunLinks (enlaces en la ejecución)La ejecución registra por sí sola la URL de su build de CI, su rama y su commit; los enlaces pertenecen a los resultados (probara.link())
certValidation: falseLa verificación TLS no se puede desactivar; pasa en su lugar tu autoridad de certificación a Node

@reportportal/agent-js-jest es un reporter, como este. Cambia la entrada y sus opciones:

// jest.config.js (before)
module.exports = {
reporters: [
'default',
[
'@reportportal/agent-js-jest',
{ endpoint: 'https://rp.example.com/api/v1', project: 'shop', launch: 'Nightly' },
],
],
};
ReportPortal (variable)Probara (variable)
apiKey (RP_API_KEY, RP_TOKEN)PROBARA_API_TOKEN
endpoint (RP_ENDPOINT)baseUrl (PROBARA_BASE_URL), la URL de la aplicación sin ruta
project (RP_PROJECT_NAME)projectId (PROBARA_PROJECT)
launch (RP_LAUNCH)run.name (PROBARA_RUN_NAME)
description (RP_DESCRIPTION)run.description (PROBARA_RUN_DESCRIPTION)
attributes (RP_ATTRIBUTES=build:42,nightly)run.tags (PROBARA_RUN_TAGS=build:42,nightly): las etiquetas son nombres simples, dos puntos incluidos
launchId (RP_LAUNCH_ID)run.ulid (PROBARA_RUN_ULID)
isLaunchMergeRequired, launchUuidPrintprobara run create imprime el ULID en el que reporta cada shard
restClientConfig (timeout, retries)timeoutMs, maxRetries
debugdebug (PROBARA_DEBUG)
ReportingApi.attachment(file, description)probara.attach({ name, path }) o { name, body, contentType }
TemaReportPortalProbara
API dentro de la pruebaSolo attachment, y solo en banda: vive en el proceso del reporterCada helper, en cada worker
ReintentosCada intento, marcado como retry cuando su referencia de código ya se vio antes en el proceso (también repeticiones en watch y nombres duplicados)Cada intento es un resultado, sin marca: el historial lo muestra
test.todoNunca se reportaOmitido, con la nota Todo
ErroresEl primer mensaje de fallo, como log y en la descripciónCada error del intento, en las notas de su resultado
EstructuraUn elemento de suite por describe; el archivo no es un elementoCada caso en una suite con el nombre de su archivo
Ajustes desde jest-junitSu sección jest-junit de package.json y las variables JEST_JUNIT_* sustituyen sus opcionesSolo las opciones del reporter y las variables PROBARA_*

Lo que no se porta de ReportPortal:

ReportPortalPor qué
skippedIssue y el tipo de defecto NOT_ISSUELos problemas conocidos y la clasificación de defectos viven en Probara, en el resultado, no en un ajuste de CI
rerun, rerunOfReporta en la misma ejecución con run.ulid: cada caso de la ejecución conserva el último resultado y todo su historial
Launches con mode: 'DEBUG'Una ejecución de depuración es una ejecución: desactiva el envío en local (sin token), o comprueba qué se enviaría
Inicio de sesión con OAuthEl CI reporta con un token de aplicación de la organización, que no ocupa puesto y sobrevive a la persona que lo creó

allure-jest es un entorno de prueba (allure-jest/node, allure-jest/jsdom) que escribe archivos de resultados en allure-results/; un paso aparte los convierte en un informe. El reporter envía los resultados a Probara al terminar la ejecución, y no necesita ningún entorno: vuelve a node, jsdom o el tuyo propio.

// jest.config.js (before)
module.exports = {
testEnvironment: 'allure-jest/node',
testEnvironmentOptions: {
resultsDir: 'allure-results',
links: { issue: { urlTemplate: 'https://jira.example.com/browse/%s' } },
},
};
Ajuste de AllureProbara
resultsDirNada: los resultados van a Probara. Un archivo de resultados guarda lo que no se pudo enviar
links.issue.urlTemplateissueUrlTemplate (PROBARA_ISSUE_URL_TEMPLATE)
environmentInforun.environment (un nombre) y el origen de la ejecución, detectado del CI
ALLURE_TESTPLAN_PATHrunCasesOnly con PROBARA_RUN_ULID
Llamada de Allure (allure-js-commons)Probara (probara.*)
@allure.id:12 en un título, allureId('12')SHOP-12 en el título o en un describe, o id('SHOP-12')
displayName('...')title('...')
description('...')fields({ description: '...' })
severity('critical'), layer('api')fields({ severity: 'critical', layer: 'api' })
tag('smoke'), tags(...)tags('smoke')
epic, feature, story, label(name, value)fields({ Feature: 'Checkout' }): un campo personalizado con ese nombre, o tags(...)
parentSuite, suite, subSuitesuite(['Payments', 'Cards'])
parameter('user', 'ana')parameters({ user: 'ana' })
step('Pay', async () => {...})step('Pay', async () => {...})
logStep('Paid')step('Paid'): un paso sin cuerpo, aprobado
attachment(name, content, type)attach({ name, body: content, contentType: type })
attachmentPath(name, path)attach({ name, path })
link(url, name)link(url, name)
issue('PAY-7')issue('PAY-7'), con issueUrlTemplate
tms('12')id('SHOP-12')
TemaAllureProbara
Estadosfailed para una aserción, broken para cualquier otro errorfailed para ambos, con el error en las notas: sin suposiciones a partir del tipo de error
Un afterEach o afterAll que fallaLa prueba sigue aprobada; solo el fixture del hook queda rotoEl veredicto de Jest: un afterEach que falla hace fallar su prueba, un afterAll que falla añade un resultado fallido para el archivo
Un plan de pruebasLas pruebas excluidas se siguen ejecutando, hooks incluidos, y solo se dejan fuera del informerunCasesOnly las omite antes de ejecutarlas, y no las reporta
AdjuntosCada uno envuelto en un paso propioEn el resultado, o en el paso en el que se adjuntaron
Reintentos e historialUn archivo de resultado por intento; el generador del informe los agrupaCada intento es un resultado de la ejecución; el caso conserva su historial entre ejecuciones
Modo watchLos archivos de resultados se acumulan en resultsDirUna ejecución para toda la sesión
Campos del casoEtiquetas en cada resultadoCampos y etiquetas del caso que crea un informe; un caso existente conserva los suyos

Lo que no se porta de Allure:

AllurePor qué
testCaseId(), historyId()La clave sale del archivo y de los nombres, igual que la de probara import junit; vincula un caso por su ID
Fixtures de setup y teardown desde hooksLos hooks son cómo se ejecuta una prueba, no lo que especifica; envuelve lo importante en probara.step()
El estado brokenUna suposición a partir del tipo de error; Probara mantiene cuatro estados y el error completo
categories, marcas de conocido, silenciado e inestableLa clasificación vive en Probara, en los resultados y los defectos; cada intento es un resultado, así que la inestabilidad se ve en el historial
owner()Un caso de Probara no tiene campo de propietario; asigna en su lugar los resultados fallidos (assignFailedTo)
Parámetros enmascarados, ocultos y excluidosLos parámetros se muestran con el resultado y nunca forman parte de la clave: omite un secreto en lugar de enmascararlo
logStep() con estado fallido o rotoEl estado de un paso es lo que hizo su cuerpo: un paso que lanza un error falla
globalAttachment(), globalError()Los archivos y los errores pertenecen a un resultado; adjúntalos desde la prueba que los produjo
descriptionHtml()La descripción es texto; Probara le da formato
listenersNingún hook cambia un resultado antes de enviarlo; statusMapping y statusFilter cubren los estados
Etiquetas globales ALLURE_LABEL_*Etiqueta la ejecución con run.tags; las etiquetas del caso salen de probara.tags() en la prueba

TestRail no tiene reporter para Jest: un pipeline escribe JUnit XML con jest-junit, y después la CLI de Python de TestRail, trcli parse_junit, lo envía al terminar la ejecución. El reporter sustituye ambos pasos, y envía lo que jest-junit no puede escribir: pasos, archivos, comentarios y cada intento.

Ventana de terminal
# Before
npx jest --ci --reporters=default --reporters=jest-junit
trcli -h https://example.testrail.io --project "Shop" -u ci@example.com -k "$TESTRAIL_KEY" \
parse_junit --title "Nightly" --case-matcher name -f junit.xml --close-run

Con el reporter, basta con el paso de pruebas:

Ventana de terminal
npx jest --ci
trcliProbara
-h (host), -u, -p, -kbaseUrl para un Probara autoalojado; PROBARA_API_TOKEN
--project (un nombre)projectId (PROBARA_PROJECT), el ID del Proyecto
--title, --run-descriptionrun.name, run.description
--run-idrun.ulid (PROBARA_RUN_ULID)
--plan-id, --config-ids, --milestone-idrun.plan, run.configurations, run.milestone, por ID visible o nombre
--close-runEl valor por defecto para una ejecución que crea el reporter; closeRun para una reutilizada
--case-matcher name (C123 en el nombre)SHOP-12 en el título o en un describe
--case-matcher auto (classname.name)La clave de automatización: archivo, describes y título
-y (crear secciones y casos)createMissingCases, activado por defecto; suites a partir del archivo de prueba
--suite-id, --section-idsuiteUlid (PROBARA_SUITE_ULID): la suite bajo la que van los casos creados
--case-fields type_id:3probara.fields({ type: 'Regression' }) en la prueba, por nombre
-a, --assign (correos)assignFailedTo (PROBARA_ASSIGN_FAILED_TO)
-b, --batch-sizechunkSize (de 1 a 500)
-t, --timeout (segundos, por petición)timeoutMs (milisegundos, por petición)
--proxy, --noproxyHTTPS_PROXY y NO_PROXY con NODE_USE_ENV_PROXY=1
-v (detallado)debug (PROBARA_DEBUG)
Propiedad testrail_result_commentprobara.comment()
Propiedad testrail_attachmentprobara.attach()
Propiedad testrail_result_stepprobara.step()

jest-junit no escribe propiedades de testcase, así que las tres últimas filas estaban fuera del alcance de Jest: los helpers las hacen posibles.

Tematrcli sobre jest-junitProbara
Pruebas omitidasRetestOmitidas
test.todoAprobado (jest-junit lo escribe como aprobado)Omitido, con la nota Todo
ReintentosSolo el último intentoCada intento
Describes anidadosSin soporte: una sección por test suiteLa suite de un caso creado es su archivo; probara.suite() nombra suites anidadas
DuracionesRedondeadas a segundos (--allow-ms para milisegundos)Milisegundos, y el inicio de cada intento
Un ID de caso desconocidoAborta la subidaEse resultado no se registra, y el registro lo nombra; los demás sí
Una subida fallidaRevierte la ejecución, los casos y las secciones que creóNo se revierte nada; un archivo de resultados guarda lo que no se envió
Shardsadd_run -f run.yml, y después -c run.yml en cada shardprobara run create, PROBARA_RUN_ULID en cada shard, probara run close

Lo que no se porta de TestRail:

trcliPor qué
--update-existing-cases, --update-strategy, refsUn informe nunca cambia un caso existente: lo que está escrito ahí es de las personas
Sustituir custom_automation_idLa clave sale del archivo y de los nombres, igual que la de probara import junit; vincula un caso por su ID
--result-fields, testrail_result_fieldLos resultados de Probara no tienen campos personalizados: los parámetros (probara.parameters()) y los enlaces (probara.link()) llevan los datos adicionales
--test-run-refLa ejecución registra la URL de su build de CI, su rama y su commit; las incidencias se vinculan desde los resultados (probara.issue())
--insecureLa verificación TLS no se puede desactivar; pasa en su lugar tu autoridad de certificación a Node
Los parsers bdd, multisuite y saucectl, quality_ratingJest no tiene escenarios Gherkin; una ejecución abarca un proyecto, y projects reparte por ID de caso
Revertir ante un falloUn resultado registrado se conserva: revertir perdería los que sí llegaron

@probara/jest-reporter sigue el versionado semántico. Lee el changelog antes de actualizar: cada cambio que requiere una acción por tu parte aparece ahí primero.

  • 0.x (ahora): el reporter es joven. Una versión menor (0.2.0) puede cambiar opciones, líneas del registro o valores por defecto; una versión de parche (0.1.1) solo corrige errores. Fija la versión en package.json (o conserva el lockfile) y actualiza de forma deliberada.
  • 1.0 y posteriores: cambios incompatibles solo en una versión mayor.
  • @probara/jest-reporter depende de @probara/core de la misma línea de versiones; instala solo el reporter y deja que traiga su core.

Cualquiera de estos requiere una versión mayor a partir de la 1.0, y una menor antes:

  • Una opción o una variable PROBARA_* eliminada o renombrada, o con otro significado.
  • Un valor por defecto cambiado (cierre de ejecuciones, creación de casos que faltan, keyIncludesFile, qué se adjunta).
  • Un helper probara.* o el archivo de setup eliminado, o con otro comportamiento.
  • Un cambio en el estado con el que se envía un intento para el mismo intento.
  • Cualquier cambio en la clave de automatización que recibe una prueba, con keyIncludesFile activado o desactivado. Una clave distinta desvincula la prueba de su caso: la siguiente ejecución crea uno nuevo.
  • Dejar de soportar una versión de Jest o de Node.js que sigue teniendo soporte oficial.

Añadir una opción, un helper, una línea de registro o un archivo que se sube no es un cambio incompatible. Las líneas en stderr son para personas: no las analices con scripts.

El algoritmo de la clave es la clave de automatización v1, congelada en @probara/core y fijada por vectores de referencia: ninguna versión del reporter la cambia. Lo que añade el reporter es cómo una prueba de Jest se convierte en las partes de la clave, de la misma forma en que probara import junit lee el informe de jest-junit con sus plantillas por defecto:

  • el archivo de prueba relativo a rootDir (la ruta real del directorio en el que se ejecuta jest), cuando keyIncludesFile está activado, como lo escribe jest-junit con JEST_JUNIT_ADD_FILE_ATTRIBUTE=true;
  • los describes y el título, unidos por espacios y divididos por › (con sus espacios), sin los IDs de caso;
  • {displayName} en un describe o un título, rellenado con el nombre del proyecto de Jest, y los patrones $ ($$, $&) expandidos, como hacen las plantillas de jest-junit.

Esa correspondencia también forma parte del contrato: una versión que cambia la clave de una prueba es un cambio incompatible, y el changelog lo indica como tal. Para comprobar una actualización, compara lo que enviarían ambas versiones, cada ejecución con su propio archivo de resultados (comprobar qué se enviaría). Cualquier clave que cambie es una prueba que recibiría un caso nuevo.

NecesitaSoportado
jest29.6 y posteriores (el rango de peer): probado en 29.7 y en la última 30
Node.js22.12 y posteriores (el campo engines)
Un runnerjest-circus, el de Jest por defecto, para los helpers probara.* y el archivo de setup

Jest 29.6 es la primera versión que avisa a un reporter cuando empieza cada prueba, de ahí el rango de peer. Algunos detalles dependen de la versión:

JestQué cambia
29Un test.todo o una prueba omitida recibe la hora de inicio de su archivo. jest.retryTimes nunca reintenta una prueba test.concurrent
30.0 a 30.4Una prueba test.concurrent reintentada por jest.retryTimes: las llamadas probara.* de sus reintentos se unen a las de su primer intento (Jest 30.5 distingue cada intento)
30.5 y posterioresCada intento de cada prueba, incluido test.concurrent, recibe sus propias llamadas probara.*

Con testRunner: 'jest-jasmine2' las pruebas se reportan, pero las llamadas probara.* no registran nada (la primera muestra una advertencia), captureOutput no adjunta nada, y runCasesOnly ejecuta y reporta todas las pruebas, con una advertencia. 0.1.0 es la primera versión: todavía no hay nada desde lo que migrar.

Relacionado: Primeros pasos · Vincular · CLI · Fuente: migrating-from-junit.md, migrating-from-qase.md, coming-from-other-tools.md, upgrade.md