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.
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 de | Ve a |
|---|---|
jest-junit y probara import junit | La importación JUnit |
jest-qase-reporter | Qase |
testit-adapter-jest | Test IT |
@reportportal/agent-js-jest | ReportPortal |
allure-jest | Allure |
jest-junit y trcli parse_junit | TestRail |
Desde la importación JUnit
Sección titulada «Desde la importación JUnit»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.
- Averigua cómo se ejecutaba jest-junit en tu pipeline: con
JEST_JUNIT_ADD_FILE_ATTRIBUTE=true(oaddFileAttribute: 'true'en sus opciones), o sin él (su valor por defecto). - Añade el reporter a la configuración de Jest. Sin el atributo de archivo, define también
keyIncludesFile: false. - Comprueba las claves de ambos con las mismas pruebas: deben ser iguales.
- En CI, elimina jest-junit y el paso de importación, y pasa
PROBARA_API_TOKENal 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.
Comprueba las claves antes de cambiar
Sección titulada «Comprueba las claves antes de cambiar»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:
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-runpassed SHOP-12 tests/refund.test.js > refund refunds an orderpassed - tests/refund.test.js > refund keeps the receiptpassed - tests/refund.test.js > refund refunds a gift cardTotal: 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-runpassed SHOP-12 tests/refund.test.js > refund refunds an orderpassed - tests/refund.test.js > refund keeps the receiptskipped - tests/refund.test.js > refund refunds a gift cardTotal: 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: SHOPDespué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: SHOPQuita --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»| Tema | probara import junit sobre jest-junit | El reporter |
|---|---|---|
test.todo | passed: jest-junit escribe un todo como un testcase aprobado | skipped, con la nota Todo: una prueba aún no escrita nunca cuenta como aprobada |
Reintentos (jest.retryTimes) | Solo el último intento | Cada intento, en orden; el caso de la ejecución conserva el último resultado |
Pruebas excluidas por -t o .only | skipped | skipped también |
Un hook afterAll que falla | Un testcase fallido más para el archivo | El mismo resultado fallido, con la misma clave |
| Un archivo que no se carga | Nada (jest-junit no escribe nada para él por defecto) | Nada que reportar, y una advertencia nombra el archivo |
| Cuándo se envían los resultados | Después de toda la ejecución, en un paso posterior | Al 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 archivo | El primer describe de la primera prueba del archivo, para todas las pruebas del archivo | El 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.
Desde Qase
Sección titulada «Desde Qase»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.
npm uninstall jest-qase-reporter && npm i -D @probara/jest-reporter.- En la configuración de Jest, sustituye
['jest-qase-reporter', {...}]por['@probara/jest-reporter', {...}], traduciendo las opciones (abajo). Borraqase.config.jsony.qaserc: el reporter solo lee sus opciones y las variablesPROBARA_*. - Sustituye en CI las variables
QASE_*por lasPROBARA_*: como mínimoPROBARA_API_TOKEN(un token de aplicación de la tarjeta Jest) yPROBARA_PROJECT. - Sustituye
require('jest-qase-reporter/jest')porrequire('@probara/jest-reporter'), y traduce las llamadas (abajo). Los IDs de caso pasan a ser IDs visibles de Probara (SHOP-12), no números. - Quita
--runInBandsi lo añadiste solo por los helpers de Qase: los de Probara no necesitan nada.
Antes:
module.exports = { reporters: [ 'default', [ 'jest-qase-reporter', { mode: 'testops', testops: { project: 'SHOP', run: { title: 'Nightly', complete: true, tags: ['nightly'] }, uploadAttachments: true, }, }, ], ],};Después:
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.
Opciones y variables de Qase
Sección titulada «Opciones y variables de Qase»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 existe | run.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 ignora | captureOutput (PROBARA_CAPTURE_OUTPUT), con el archivo de setup |
statusMapping (QASE_STATUS_MAPPING) | statusMapping (PROBARA_STATUS_MAPPING), sin invalid ni disabled |
logging.console, logging.file | Los 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.retryBackoff | maxRetries, para cada petición; el backoff es fijo |
testops.project (QASE_TESTOPS_PROJECT) | projectId (PROBARA_PROJECT) |
testops.uploadAttachments | uploadAttachments (PROBARA_UPLOAD_ATTACHMENTS) |
testops.attachments.concurrency, .timeout | attachmentConcurrency; las subidas tienen al menos 120 s |
testops.run.id (QASE_TESTOPS_RUN_ID) | run.ulid (PROBARA_RUN_ULID) |
testops.run.title, .description, .tags | run.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 |
Las llamadas qase.*
Sección titulada «Las llamadas qase.*»| Qase | Probara |
|---|---|
test(qase(12, 'pays'), ...), (Qase ID: 12) en un título | test('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 paso | probara.step(...), probara.attach(...) dentro del cuerpo: se anidan solos |
Antes:
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:
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.
Los helpers funcionan en cada worker
Sección titulada «Los helpers funcionan en cada worker»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é»| Tema | Qase | Probara |
|---|---|---|
| Precedencia | Su 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ón | qase.config.json o .qaserc | Ninguno: 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 caso | Números, solo en el título de la propia prueba | IDs visibles (SHOP-12) en el título o en cualquier describe: el ID del Proyecto dirige cada ID a su proyecto |
| Atribución de metadatos | Por 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 |
| Pasos | Planos, los hijos antes que su padre; el resultado esperado y los datos codificados en el nombre del paso | Anidados tal como se ejecutaron, cada uno con su estado, duración y error; expected y data como opciones |
| Adjuntos de pasos | Solo a través del s.attach() del cuerpo del paso; qase.attach() siempre va a la prueba | probara.attach() dentro de un paso va a ese paso |
test.failing | Un cuerpo que lanza un error pasa; un cuerpo que pasa suele quedar invalid | El veredicto de Jest: un cuerpo que lanza un error pasa, un cuerpo que pasa falla |
| Estados | invalid 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.todo | Omitido, pero statusFilter necesita disabled para descartarlo | Omitido, con la nota Todo; statusFilter: ['skipped'] lo descarta |
Pruebas excluidas por -t o .only | Se reportan como omitidas | También se reportan como omitidas: Jest las reporta así, y el reporter envía lo que reporta Jest |
Un afterAll que falla | No se reporta: las pruebas siguen en verde en Qase | Un resultado fallido más para el archivo, el que escribe jest-junit |
| Un archivo que no se carga | No se reporta ni se dice nada | Nada que reportar (no se ejecutó ninguna prueba), y una advertencia nombra el archivo |
qase.comment() | Sustituye el mensaje de error de un resultado fallido | Se escribe al principio de las notas, antes del error, que se conserva |
Llamadas a fields() y parameters() | La última llamada sustituye a las demás | Se combinan por nombre |
| Campos del caso | Se envían con cada resultado | Solo cuando el informe crea el caso: un caso existente conserva lo que escribieron las personas |
| Cierre de la ejecución | Solo con run.complete: true; sin definir la deja abierta | Una ejecución que crea el reporter se cierra al final; una reutilizada queda abierta |
| Shards | Cada shard crea su propia ejecución salvo que reciba un ID de ejecución | probara run create, cada shard con PROBARA_RUN_ULID, y después probara run close |
| Modo watch | Una 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ío | fallback a un informe local, de forma definitiva, desde el primer error | Un 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 contentType | Un archivo por llamada, path o body, y contentType |
| El final de la ejecución | No se espera: --forceExit puede cortar los últimos resultados | Jest espera al reporter: cada resultado se envía antes de que Jest salga |
| Ejecutar solo las pruebas de un plan | Una CLI externa (qasectl) construye un filtro -t | runCasesOnly ejecuta solo las pruebas de los casos de una ejecución |
Lo que no se porta de Qase
Sección titulada «Lo que no se porta de Qase»| Función de Qase | Por 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 invalid | Es 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 |
Desde Test IT
Sección titulada «Desde Test IT»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 UUID | projectId (PROBARA_PROJECT), el ID del Proyecto (SHOP) |
configurationId (TMS_CONFIGURATION_ID) | run.configurations (PROBARA_CONFIGURATIONS=Browser=Chrome), por nombre |
adapterMode: 2, una ejecución nueva | El 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) |
automaticCreationTestCases | createMissingCases (PROBARA_CREATE_MISSING_CASES), activado por defecto |
syncStorageEnabled, syncStoragePort, importRealtime | Nada que definir: cada resultado pasa por el reporter en el proceso principal de Jest |
LOG_LEVEL=debug | debug (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('...') |
| Tema | Test IT | Probara |
|---|---|---|
| Identidad | Un hash del archivo y del título de la propia prueba: dos pruebas con el mismo título en distintos describes colisionan | El archivo, cada describe y el título |
Pruebas omitidas y test.todo | No se reportan | Se reportan como omitidas (Todo en las notas de un todo) |
| Pasos | Planos, sin estado ni duración | Anidados, cada uno con su estado, su duración y su error |
test.concurrent | Un búfer por archivo de prueba: las pruebas concurrentes sobrescriben los datos de las demás | Cada llamada pertenece a la prueba que la hizo |
| Cierre de la ejecución | El adaptador nunca la cierra | Una ejecución que crea el reporter se cierra al final; una reutilizada queda abierta |
| Nombre de una ejecución existente | Se renombra a testRunName | Nunca cambia: las opciones de una ejecución nueva se ignoran en una reutilizada, con una advertencia |
| Precedencia | Depende del tipo: los strings primero desde las opciones, los booleanos primero desde tms.config.json | Opciones, después variables PROBARA_*, después valores por defecto, para cada ajuste |
| Ejecutar las pruebas de una ejecución | Una CLI externa escribe un filtro -t | runCasesOnly lee por sí mismo los casos de la ejecución |
Lo que no se porta de Test IT:
| Test IT | Por qué |
|---|---|
automaticUpdationLinksToTestCases, actualizar autotests | Un 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 hooks | Los 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: false | La verificación TLS no se puede desactivar; pasa en su lugar tu autoridad de certificación a Node |
Desde ReportPortal
Sección titulada «Desde ReportPortal»@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, launchUuidPrint | probara run create imprime el ULID en el que reporta cada shard |
restClientConfig (timeout, retries) | timeoutMs, maxRetries |
debug | debug (PROBARA_DEBUG) |
ReportingApi.attachment(file, description) | probara.attach({ name, path }) o { name, body, contentType } |
| Tema | ReportPortal | Probara |
|---|---|---|
| API dentro de la prueba | Solo attachment, y solo en banda: vive en el proceso del reporter | Cada helper, en cada worker |
| Reintentos | Cada 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.todo | Nunca se reporta | Omitido, con la nota Todo |
| Errores | El primer mensaje de fallo, como log y en la descripción | Cada error del intento, en las notas de su resultado |
| Estructura | Un elemento de suite por describe; el archivo no es un elemento | Cada caso en una suite con el nombre de su archivo |
| Ajustes desde jest-junit | Su sección jest-junit de package.json y las variables JEST_JUNIT_* sustituyen sus opciones | Solo las opciones del reporter y las variables PROBARA_* |
Lo que no se porta de ReportPortal:
| ReportPortal | Por qué |
|---|---|
skippedIssue y el tipo de defecto NOT_ISSUE | Los problemas conocidos y la clasificación de defectos viven en Probara, en el resultado, no en un ajuste de CI |
rerun, rerunOf | Reporta 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 OAuth | El CI reporta con un token de aplicación de la organización, que no ocupa puesto y sobrevive a la persona que lo creó |
Desde Allure
Sección titulada «Desde Allure»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 Allure | Probara |
|---|---|
resultsDir | Nada: los resultados van a Probara. Un archivo de resultados guarda lo que no se pudo enviar |
links.issue.urlTemplate | issueUrlTemplate (PROBARA_ISSUE_URL_TEMPLATE) |
environmentInfo | run.environment (un nombre) y el origen de la ejecución, detectado del CI |
ALLURE_TESTPLAN_PATH | runCasesOnly 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, subSuite | suite(['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') |
| Tema | Allure | Probara |
|---|---|---|
| Estados | failed para una aserción, broken para cualquier otro error | failed para ambos, con el error en las notas: sin suposiciones a partir del tipo de error |
Un afterEach o afterAll que falla | La prueba sigue aprobada; solo el fixture del hook queda roto | El 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 pruebas | Las pruebas excluidas se siguen ejecutando, hooks incluidos, y solo se dejan fuera del informe | runCasesOnly las omite antes de ejecutarlas, y no las reporta |
| Adjuntos | Cada uno envuelto en un paso propio | En el resultado, o en el paso en el que se adjuntaron |
| Reintentos e historial | Un archivo de resultado por intento; el generador del informe los agrupa | Cada intento es un resultado de la ejecución; el caso conserva su historial entre ejecuciones |
| Modo watch | Los archivos de resultados se acumulan en resultsDir | Una ejecución para toda la sesión |
| Campos del caso | Etiquetas en cada resultado | Campos y etiquetas del caso que crea un informe; un caso existente conserva los suyos |
Lo que no se porta de Allure:
| Allure | Por 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 hooks | Los hooks son cómo se ejecuta una prueba, no lo que especifica; envuelve lo importante en probara.step() |
El estado broken | Una suposición a partir del tipo de error; Probara mantiene cuatro estados y el error completo |
categories, marcas de conocido, silenciado e inestable | La 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 excluidos | Los 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 roto | El 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 |
listeners | Ningú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 |
Desde TestRail
Sección titulada «Desde TestRail»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.
# Beforenpx jest --ci --reporters=default --reporters=jest-junittrcli -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-runCon el reporter, basta con el paso de pruebas:
npx jest --ci| trcli | Probara |
|---|---|
-h (host), -u, -p, -k | baseUrl para un Probara autoalojado; PROBARA_API_TOKEN |
--project (un nombre) | projectId (PROBARA_PROJECT), el ID del Proyecto |
--title, --run-description | run.name, run.description |
--run-id | run.ulid (PROBARA_RUN_ULID) |
--plan-id, --config-ids, --milestone-id | run.plan, run.configurations, run.milestone, por ID visible o nombre |
--close-run | El 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-id | suiteUlid (PROBARA_SUITE_ULID): la suite bajo la que van los casos creados |
--case-fields type_id:3 | probara.fields({ type: 'Regression' }) en la prueba, por nombre |
-a, --assign (correos) | assignFailedTo (PROBARA_ASSIGN_FAILED_TO) |
-b, --batch-size | chunkSize (de 1 a 500) |
-t, --timeout (segundos, por petición) | timeoutMs (milisegundos, por petición) |
--proxy, --noproxy | HTTPS_PROXY y NO_PROXY con NODE_USE_ENV_PROXY=1 |
-v (detallado) | debug (PROBARA_DEBUG) |
Propiedad testrail_result_comment | probara.comment() |
Propiedad testrail_attachment | probara.attach() |
Propiedad testrail_result_step | probara.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.
| Tema | trcli sobre jest-junit | Probara |
|---|---|---|
| Pruebas omitidas | Retest | Omitidas |
test.todo | Aprobado (jest-junit lo escribe como aprobado) | Omitido, con la nota Todo |
| Reintentos | Solo el último intento | Cada intento |
| Describes anidados | Sin soporte: una sección por test suite | La suite de un caso creado es su archivo; probara.suite() nombra suites anidadas |
| Duraciones | Redondeadas a segundos (--allow-ms para milisegundos) | Milisegundos, y el inicio de cada intento |
| Un ID de caso desconocido | Aborta la subida | Ese resultado no se registra, y el registro lo nombra; los demás sí |
| Una subida fallida | Revierte la ejecución, los casos y las secciones que creó | No se revierte nada; un archivo de resultados guarda lo que no se envió |
| Shards | add_run -f run.yml, y después -c run.yml en cada shard | probara run create, PROBARA_RUN_ULID en cada shard, probara run close |
Lo que no se porta de TestRail:
| trcli | Por qué |
|---|---|
--update-existing-cases, --update-strategy, refs | Un informe nunca cambia un caso existente: lo que está escrito ahí es de las personas |
Sustituir custom_automation_id | La 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_field | Los resultados de Probara no tienen campos personalizados: los parámetros (probara.parameters()) y los enlaces (probara.link()) llevan los datos adicionales |
--test-run-ref | La ejecución registra la URL de su build de CI, su rama y su commit; las incidencias se vinculan desde los resultados (probara.issue()) |
--insecure | La 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_rating | Jest no tiene escenarios Gherkin; una ejecución abarca un proyecto, y projects reparte por ID de caso |
| Revertir ante un fallo | Un resultado registrado se conserva: revertir perdería los que sí llegaron |
Actualizar el reporter
Sección titulada «Actualizar el reporter»@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 enpackage.json(o conserva el lockfile) y actualiza de forma deliberada. - 1.0 y posteriores: cambios incompatibles solo en una versión mayor.
@probara/jest-reporterdepende de@probara/corede la misma línea de versiones; instala solo el reporter y deja que traiga su core.
Qué es un cambio incompatible
Sección titulada «Qué es un cambio incompatible»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
keyIncludesFileactivado 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 contrato de la clave de automatización
Sección titulada «El contrato de la clave de automatización»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 ejecutajest), cuandokeyIncludesFileestá activado, como lo escribe jest-junit conJEST_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.
Versiones de Jest y de Node.js
Sección titulada «Versiones de Jest y de Node.js»| Necesita | Soportado |
|---|---|
jest | 29.6 y posteriores (el rango de peer): probado en 29.7 y en la última 30 |
| Node.js | 22.12 y posteriores (el campo engines) |
| Un runner | jest-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:
| Jest | Qué cambia |
|---|---|
| 29 | Un 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.4 | Una 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 posteriores | Cada 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