Jest test metadata and links
probara tells the reporter more about a test, from the test body or a beforeEach or afterEach
hook. Require it (or import it) from the reporter’s package:
const { probara } = require('@probara/jest-reporter');
test('pays with a card', () => { probara.title('Pays with a saved card').suite(['Payments', 'Cards']).tags('smoke');});In a test file compiled from ES modules (Babel, ts-jest),
import { probara } from '@probara/jest-reporter' gives the same helpers. The package ships its
types, so TypeScript tests get them too.
| Helper | What it does | Repeated calls |
|---|---|---|
id(id | ids) | Links existing cases (linking) | Add up |
title(text) | Title of the case the report creates | The last one wins |
suite(title | titles) | Suite path of the case the report creates | The last one wins |
comment(text) | A comment, first in the notes of the result, before the error | The last one wins |
ignore() | Leaves this attempt out: it is not reported | — |
tags(...names) | Tags of the case the report creates | Add up, each once |
fields(record) | Fields of the case the report creates: system fields, custom fields, description | Merged by name |
parameters(record) | Parameters of the result, shown with it | Merged by name |
link(url, name?), issue(id) | Links of the result (links and issues) | Add up |
attach({ name, path | body, ... }) | Attaches a file (attachments) | Each one attaches |
step(title, body?, options?) | A step of the result, and of the new case (steps) | Each one is a step |
The helpers that return nothing else return probara, so calls chain. Each applies to the running
attempt only: a retry starts empty.
Created cases only
Section titled “Created cases only”title, suite, tags, fields and the case steps describe the case a report creates, the
first time a test is reported. An existing case never changes: Probara keeps what people wrote
there. The automation key never changes either
(keys), so a new title still matches
the same case.
const { probara } = require('@probara/jest-reporter');
test('pays', () => { probara .title('Pays with a saved card') .suite(['Payments', 'Cards']) .tags('smoke', 'payments') .fields({ description: 'A returning customer pays with the card saved in their profile.', severity: 'critical', priority: 'high', 'Risk area': 'Checkout', });});[ { "automationKey": "tests/payments.test.js > pays", "title": "Pays with a saved card", "suitePath": ["Payments", "Cards"], "case": { "description": "A returning customer pays with the card saved in their profile.", "tags": ["smoke", "payments"], "fields": { "severity": "critical", "priority": "high", "Risk area": "Checkout" } } }]Fields
Section titled “Fields”fields() takes names and values (numbers and booleans become strings):
| Name | What it sets |
|---|---|
description | The case description |
severity, priority, type, layer, behavior, status, is_flaky | The system fields, by the name of an option (high) |
preconditions, postconditions | The system text fields |
Any other name, such as 'Risk area' | The custom field of that name |
Probara resolves names and options when it creates the case. A field or an option it does not know is skipped and logged as a warning; the result is recorded all the same. A field with an empty value is skipped silently.
Title and suite
Section titled “Title and suite”The title of a created case is the test title (case ids removed) unless title() says otherwise.
Its suite is the test file (tests/payments.test.js) or, with keyIncludesFile: false, the
outermost describe, unless suite() gives one: suite('Payments'), or
suite(['Payments', 'Cards']) for nested suites, created as needed under suiteUlid.
Comment
Section titled “Comment”comment() writes a line first in the notes of the result, before the error and its stack:
const { probara } = require('@probara/jest-reporter');
test('searches the catalog', () => { probara.comment('Ran against the staging catalog');});[ { "automationKey": "tests/search.test.js > searches the catalog", "notes": "Ran against the staging catalog" }]When the attempt fails, its error follows the comment in the same notes, without the terminal’s colors: the comment never hides the error.
Parameters
Section titled “Parameters”parameters() records the values an attempt ran with, shown with its result, such as the user or
the data set of a data-driven test. They are never part of the key: the test is one case whatever
its parameters. When the case declares a parameter with the same name, the result is recorded on the run case with those values. A parameter the case does not declare stays on the result for display only. A case that a report creates takes its values as an Examples parameter when at least two of its results report the same names with different values.
const { probara } = require('@probara/jest-reporter');
test.each(['admin', 'viewer'])('opens the dashboard as %s', (role) => { probara.parameters({ role, seats: 5 });});[ { "automationKey": "tests/users.test.js > opens the dashboard as admin", "parameters": { "role": "admin", "seats": "5" } }, { "automationKey": "tests/users.test.js > opens the dashboard as viewer", "parameters": { "role": "viewer", "seats": "5" } }]A test.each title that holds the value (as above) is one case per value, which is how Jest names
its rows. Keep a placeholder in the title: rows with the same name in one file share one key, and
what their helpers said is left out
(names).
Ignore an attempt
Section titled “Ignore an attempt”ignore() leaves the running attempt out: it still runs, and Jest reports it, but Probara does not
get it. The count in the log says how many were left out.
const { probara } = require('@probara/jest-reporter');
test('tries the new checkout', () => { probara.ignore();});
test('pays', () => {});$ npx jest[probara] Sending 1 result of 1 test (1 passed, 0 failed, 0 skipped, 0 blocked); 1 ignored with probara.ignore()[probara] Recorded 1 result (1 new case, 0 unmatched) in R-1 (closed): https://app.probara.net/projects/SHOP/runs/R-1Links and issues
Section titled “Links and issues”A result can carry links, shown with it in Probara: the build that ran it, the page it tested, the issues of your tracker it is about.
probara.link()
Section titled “probara.link()”probara.link(url, name?) takes an absolute http or https URL and an optional name, shown
instead of the URL:
const { probara } = require('@probara/jest-reporter');
test('searches the catalog', () => { probara .link('https://shop.example.com/search?q=boots', 'Search page') .link('https://ci.example.com/builds/1042');});[ { "automationKey": "tests/search.test.js > searches the catalog", "links": [ { "url": "https://shop.example.com/search?q=boots", "name": "Search page" }, { "url": "https://ci.example.com/builds/1042" } ] }]probara.issue() and issueUrlTemplate
Section titled “probara.issue() and issueUrlTemplate”probara.issue(id) names an issue of your tracker by its id. With issueUrlTemplate
(PROBARA_ISSUE_URL_TEMPLATE), a URL with %s where the id goes, it becomes a link of the result,
named by the id:
reporters: [ 'default', ['@probara/jest-reporter', { issueUrlTemplate: 'https://jira.example.com/browse/%s' }],],const { probara } = require('@probara/jest-reporter');
test('rounds the total', () => { probara.issue('PAY-7').issue('PAY 12');});[ { "automationKey": "tests/checkout.test.js > rounds the total", "links": [ { "url": "https://jira.example.com/browse/PAY-7", "name": "PAY-7" }, { "url": "https://jira.example.com/browse/PAY%2012", "name": "PAY 12" } ] }]- The id goes into the template URL-encoded (
PAY 12becomesPAY%2012), in place of the first%s. - The template is an
httporhttpsURL with%s; any other value turns reporting off with an error that namesissueUrlTemplate. - Without a template, the issues are left out, and one warning says so: the result is recorded without them.
$ npx jest[probara] Dropped the issues of probara.issue(): no issueUrlTemplate turns their ids into links (first seen in "rounds the total"; repeats are logged at debug)[probara] Sending 1 result of 1 test (1 passed, 0 failed, 0 skipped, 0 blocked)[probara] Recorded 1 result (1 new case, 0 unmatched) in R-1 (closed): https://app.probara.net/projects/SHOP/runs/R-1Link rules
Section titled “Link rules”| Rule | What happens |
|---|---|
| Links and issues of one attempt | Sent in call order, links and issues together |
A URL that is not an absolute http/https URL | Left out, with a warning |
| A URL over 2048 characters | Left out, with a warning |
| A name over 255 characters | Cut to 255 characters, with a warning |
| More than 20 links in a result | The first 20 are sent, with a warning |
| A retry | Starts without links: each attempt sends its own |
Links belong to the result, not to the case: an existing case never changes, and each result keeps the links its attempt added. To link a case itself to a Jira issue, see Traceability with Jira.
Where to call the helpers
Section titled “Where to call the helpers”| Where | What happens |
|---|---|
The test body, beforeEach, afterEach | Applies to the running attempt |
| A helper function or module the test calls | The same: the helpers find the running test on their own |
The module scope, a describe body, beforeAll, afterAll | Ignored, with one warning: no single test runs there |
A test.concurrent test | Applies to that test |
A helper never throws into the test. A wrong argument, or a call while no test runs, is one
[probara] warning in the reporter’s log, naming the test file, and the call is ignored:
const { probara } = require('@probara/jest-reporter');
beforeAll(() => { probara.tags('orders');});
test('lists the orders', () => { probara.tags('orders');});$ npx jest[probara] probara.tags() only works while a test runs (in a test, or a beforeEach or afterEach hook) (first seen in tests/orders.test.js; repeats are logged at debug)[probara] Sending 1 result of 1 test (1 passed, 0 failed, 0 skipped, 0 blocked)[probara] Recorded 1 result (1 new case, 0 unmatched) in R-1 (closed): https://app.probara.net/projects/SHOP/runs/R-1Every worker, every environment
Section titled “Every worker, every environment”The helpers work wherever Jest runs a test: in its worker processes and in band (--runInBand), in
the node and jsdom test environments, in watch mode, and in test files written with import.
Nothing needs to be set up for them: the reporter tells the test processes where to write before
they start.
// jest.config.js (excerpt)testEnvironment: 'jsdom',const { probara } = require('@probara/jest-reporter');
test('shows the banner', () => { document.body.innerHTML = '<p role="banner">Free shipping</p>'; probara.parameters({ locale: document.documentElement.lang || 'en' });});[{ "automationKey": "tests/banner.test.js > shows the banner", "parameters": { "locale": "en" } }]How metadata travels
Section titled “How metadata travels”Jest runs tests in worker processes and the reporter in its main one. When the run starts, the
reporter creates a folder in the system’s temporary directory and names it to the test processes;
each probara.* call appends a line there, keyed by the test file, the test’s full name and its
attempt, which the helpers read from Jest’s own state (jest-circus). probara.attach() copies its
file there at once. The reporter reads the lines when each file ends, and removes the folder when
jest ends. Without the reporter, every helper does nothing (and probara.step() still runs its
body), so tests keep passing where the reporter is not registered.
Known limits:
- jest-circus only. With
testRunner: 'jest-jasmine2', no call is recorded, and one warning says so. jest.mock('fs')replaces the file system of the test file, which the helpers write with: their calls in that file are lost, silently. Mock only the modules your code imports, or usejest.spyOnon the functions it calls.- Two tests with the same full name in one file: what their calls said is left out, with a warning.
- Jest 30.0 to 30.4 and
test.concurrentretries: those versions do not say which attempt of a concurrent test runs, so the calls of a retry of atest.concurrenttest go to its first attempt. Jest 29 never retries concurrent tests, and 30.5 says.
Related: Steps and attachments · Linking · Migrating from Qase · Source: metadata.md, links.md