Skip to content

Jest reporter configuration

Every setting of @probara/jest-reporter is an option of the reporter in the Jest config, and most have a PROBARA_* environment variable too. Keep the token in the environment, the project in the config (or the environment), and set the rest where it fits your pipeline.

  1. Create an app token from the Jest card in Workspace › Integrations (get started) and store it as a CI secret named PROBARA_API_TOKEN.
  2. Set the Project ID: projectId in the reporter options, or PROBARA_PROJECT. A Project ID is a capital letter, then capital letters or digits (SHOP, E2E): any other value turns reporting off with an error.
  3. Everything else has a default. The run is named after the CI build, and its branch, commit and build URL come from the CI on their own.
jest.config.js
module.exports = {
reporters: ['default', ['@probara/jest-reporter', { projectId: 'SHOP' }]],
};

Jest reads its config from jest.config.js, jest.config.mjs, jest.config.cjs or the jest key of package.json; the reporter entry is the same in each. In package.json:

package.json
{
"private": true,
"jest": {
"reporters": ["default", ["@probara/jest-reporter", { "projectId": "SHOP" }]],
},
}

Do not put the token in the Jest config: the config is committed. apiToken exists for code that reads the token from its own secret store.

The first source that sets a value wins:

OrderSourceExample
1An option of the reporter in the Jest config{ run: { name: 'Release 2.4' } }
2A PROBARA_* variablePROBARA_RUN_NAME=Nightly
3CI detectionCI #42 from the workflow and run number
4The defaultAutomated run 2026-09-29 14:05 UTC
  • An option set to undefined never hides its variable, and a blank variable counts as unset. To let a variable override an option, leave the option out (or pass process.env.X ?? default).
  • Booleans accept true, 1, yes, on and false, 0, no, off. Lists are comma-separated in variables (PROBARA_RUN_TAGS=nightly,smoke).
  • CI detection only fills the run’s name and its source (branch, commit, build URL, and in GitHub Actions the workflow run that groups parallel jobs). What each CI fills in is in CI providers.

Options and variables can be mixed. This config sets the project and tags:

reporters: [
'default',
['@probara/jest-reporter', { projectId: 'SHOP', run: { tags: ['unit', 'nightly'] } }],
],

and the pipeline adds the run’s environment and name:

Terminal window
PROBARA_ENVIRONMENT=staging PROBARA_RUN_NAME=Nightly npx jest
OptionVariableTypeDefaultWhat it does
enabledPROBARA_ENABLEDbooleanonfalse turns reporting off: nothing is sent, and nothing is logged
apiTokenPROBARA_API_TOKENstringnone (required)The app token. Keep it in the environment
projectIdPROBARA_PROJECTstringnone (required)The Project ID (capital letters and digits), such as SHOP
baseUrlPROBARA_BASE_URLstringhttps://app.probara.netThe Probara to report to (self-hosted)
run.ulidPROBARA_RUN_ULIDstringnone: a new runReport into an existing run (an existing run)
run.namePROBARA_RUN_NAMEstringthe CI build name, else Automated run <date>Name of a new run
run.descriptionPROBARA_RUN_DESCRIPTIONstringnoneDescription of a new run
run.environmentPROBARA_ENVIRONMENTstringnoneEnvironment of a new run by name, created when none matches
run.environmentIdPROBARA_ENVIRONMENT_IDstringnoneEnvironment of a new run by ULID
run.milestonePROBARA_MILESTONEstringnoneMilestone of a new run by display id (M-3) or name
run.milestoneIdPROBARA_MILESTONE_IDstringnoneMilestone of a new run by ULID
run.planPROBARA_PLANstringnoneTest plan of a new run by display id (PLAN-2) or name: the run starts with its cases
run.configurationsPROBARA_CONFIGURATIONS{ group, name }[]noneConfigurations of a new run by name (Browser=Chrome,OS=Linux), each group once
run.configurationUlidsPROBARA_CONFIGURATION_ULIDSstring[]noneConfigurations of a new run by ULID
run.tagsPROBARA_RUN_TAGSstring[]noneTags of a new run
run.ulidsPROBARA_RUN_ULIDSRecord<string, string>noneThe run to reuse in each project (WEB=<ulid>,API=<ulid>)
projectsPROBARA_PROJECTSstring[]noneOther projects results may go to (WEB,API) (several projects)
source—false | object (GitHub fields below)detected from the CIfalse sends no source; an object overrides the detected fields one by one
source.branchPROBARA_BRANCHstringdetected from the CIBranch of the run source
source.commitPROBARA_COMMITstringdetected from the CICommit of the run source
source.buildUrlPROBARA_BUILD_URLstringdetected from the CICI build URL of the run source
createMissingCasesPROBARA_CREATE_MISSING_CASESbooleantrueCreate a case for a test that matches none
suiteUlidPROBARA_SUITE_ULIDstringthe project rootSuite that created cases go under
closeRunPROBARA_CLOSE_RUNbooleantrue for a new run, false for a reused oneClose the run at the end (never in watch mode)
closeRuns—Record<string, boolean>noneClose the run of each project ({ SHOP: true, WEB: false }) when closeRun is not set
uploadAttachmentsPROBARA_UPLOAD_ATTACHMENTSbooleantruefalse uploads no file
keyIncludesFilePROBARA_KEY_INCLUDES_FILEbooleantrueStart each automation key with the test file (keyIncludesFile)
captureOutputPROBARA_CAPTURE_OUTPUTbooleanfalseAttach each attempt’s console output as stdout.log and stderr.log (captureOutput)
issueUrlTemplatePROBARA_ISSUE_URL_TEMPLATEstringnoneThe URL each probara.issue(id) becomes, with %s for the id (issueUrlTemplate)
runCasesOnlyPROBARA_RUN_CASES_ONLYbooleanfalseRun only the tests of the cases of run.ulid (runCasesOnly)
statusMappingPROBARA_STATUS_MAPPING{ passed, failed, skipped, blocked }noneSend a status as another (failed=blocked) (statuses)
statusFilterPROBARA_STATUS_FILTERstring[]noneSend no result with these statuses, after the mapping (skipped)
resultsFilePROBARA_RESULTS_FILEstringnoneJSON file for what could not be sent (results file)
assignFailedToPROBARA_ASSIGN_FAILED_TOstring[]noneAssign each failed result without an assignee to one of these members, in turn (ana@example.com,bo@example.com)
debugPROBARA_DEBUGbooleanfalseLog every request (debugging)
rootDir—stringthe working directoryDirectory the file paths of automation keys are relative to (keyIncludesFile)
chunkSize—number500Results per report request, 1 to 500
timeoutMs—number30000Timeout of one HTTP attempt, in milliseconds, 1 to 600000
maxRetries—number4Retries of a failed request, 0 to 10
attachmentConcurrency—number2Results whose attachments upload at the same time, 1 to 8

The reporter sends its own name and version in the User-Agent (such as probara-jest-reporter/0.1.0 probara-core/0.2.0 node/22.12.0); there is no option for it.

In GitHub Actions the source also gets these fields, detected from GITHUB_* variables:

OptionVariableTypeDefaultWhat it does
source.provider—stringdetected from GitHub Actionsgithub_actions (detected) or other
source.repository—stringdetected from GitHub ActionsRepository of the run source, owner/name
source.commitAuthor—stringdetected from GitHub ActionsWho triggered the build
source.pullRequestNumber—numberdetected from GitHub ActionsPull request of the build
source.workflow—stringdetected from GitHub ActionsCI workflow of the run source
source.ciRunId—stringdetected from GitHub ActionsCI run id: the jobs of one GitHub Actions run share one run
source.ciRunAttempt—numberdetected from GitHub ActionsAttempt of the CI run: a re-run reports into a run of its own
source.ciJob—stringdetected from GitHub ActionsCI job of the run source

For code and tests, the reporter also takes the seams of @probara/core. They have no variable, and a Jest config rarely needs them:

OptionTypeDefaultWhat it does
logger{ debug, info, warn, error }[probara] lines on stderrWhere the reporter logs
envRecord<string, string>process.envWhere PROBARA_* and CI variables are read from
fetchfunctionthe global fetchThe HTTP client
sleepfunctionsetTimeoutWaits between retries
randomfunctionMath.randomJitter of the retry backoff
nowfunctionthe current timeClock of the default run name and of Retry-After dates

An option the reporter does not know is left out with a warning, and reporting goes on:

reporters: ['default', ['@probara/jest-reporter', { projectId: 'SHOP', captureOutputs: true }]],
$ npx jest
[probara] Ignored the unknown option "captureOutputs" of @probara/jest-reporter
[probara] Sending 3 results of 3 tests (3 passed, 0 failed, 0 skipped, 0 blocked)
[probara] Recorded 3 results (2 new cases, 0 unmatched) in R-1 (closed): https://app.probara.net/projects/SHOP/runs/R-1

Each test is matched to its case by an automation key: the test file relative to rootDir (the real path of the directory jest runs in), then > between spaces, then the describe blocks and the title joined by spaces, without the case ids: tests/cart.test.js > cart adds an item. That is the key probara import junit gives the same test on jest-junit’s report written with JEST_JUNIT_ADD_FILE_ATTRIBUTE=true.

keyIncludesFile: false leaves the file out, like jest-junit’s report without the file attribute (its default). Switch to it when your cases were imported from such reports, so each test keeps its case. A test then gets the same key as a test with the same describe blocks and title in another file.

reporters: ['default', ['@probara/jest-reporter', { keyIncludesFile: false }]],
[
{ "automationKey": "cart adds an item", "caseDisplayId": "SHOP-12" },
{ "automationKey": "cart removes an item" },
{ "automationKey": "login logs in with a valid password" }
]

Changing keyIncludesFile changes every key: tests that name no case in their titles then create new cases. A case the report creates goes in a suite named after the test file or, with keyIncludesFile: false, after its outermost describe block, when it has one. Jest projects add nothing to the key (linking).

captureOutput: true attaches what each attempt writes with console.log, console.info and console.debug as stdout.log, and with console.warn and console.error as stderr.log. Jest still prints the output as usual. It needs the reporter’s setup file:

reporters: ['default', ['@probara/jest-reporter', { captureOutput: true }]],
setupFilesAfterEnv: ['@probara/jest-reporter/setup'],

Without the setup file, the tests run and are reported without their output, with one warning. What is and is not captured is in console output.

probara.issue(id) names an issue of your tracker: issueUrlTemplate turns it into a link of the result, named by the id, with the URL-encoded id in place of %s (https://jira.example.com/browse/%s). The template is an http or https URL with %s; any other value turns reporting off with an error. Without a template, issues are left out with a warning (links).

runCasesOnly: true (or PROBARA_RUN_CASES_ONLY=true) runs only the tests of the cases of the run run.ulid (PROBARA_RUN_ULID), and reports into that run, leaving it open. It needs the setup file and jest-circus. Turn it on per job with the variables rather than in the config: with the option in the config, every job without a run ULID warns and runs every test. Run selection has the matching rules and every fallback.

SetupWhat the reporter does
No token and no project, or enabled: falseStays off and quiet: nothing is sent, and nothing is logged (but at debug).
Only one of them, or an invalid valueReporting is off; each problem is logged, and the tests run as usual.
A token and a project, every value validReports.

A value of the wrong type (such as run.tags: 'nightly' instead of a list) is an invalid value:

reporters: ['default', ['@probara/jest-reporter', { projectId: 'SHOP', run: { tags: 'nightly' } }]],
$ npx jest
[probara] Probara reporting is off: run.tags must be a list of strings

Problems name the option or the variable at fault, never its value, so a token never shows up.

Set enabled: false or PROBARA_ENABLED=false, or leave the token out: the reporter sends nothing and stays quiet. Builds of pull requests from forks get no secrets, so they report nothing on their own. To keep what a run could not send, even with reporting off, set a results file.

Point the reporter at another Probara with baseUrl or PROBARA_BASE_URL: the URL of the app, without a path. Requests go to that host and nowhere else. For proxies and private certificate authorities, see network.

The reporter talks HTTPS to one host, the base URL, from Jest’s main process: the test workers never call Probara.

WhenRequests
Before the tests start, only with runCasesOnlyRead the case keys of the run, 200 cases per page until the last page
After the last test file (Jest’s onRunComplete)The reports, then the attachment uploads, then the close of the run (when needed)

Nothing is sent while the tests run: the reporter collects the results and sends them once Jest is done. Jest waits for the reporter before it exits (with --forceExit too), so the time the requests take, retries included, is part of the jest command. With runCasesOnly, the case keys are read once per jest (and once per re-run in watch mode); when they cannot be read after the retries, every test runs and is reported, with one warning.

SettingDefaultRangeWhat it bounds
timeoutMs30000 ms1 to 600000One attempt of a request, the response body included
uploads120000 ms or timeoutMs if larger—One attempt of an attachment upload (a large file on a slow link)

A timed-out attempt is retried like a network error.

AnswerWhat happens
Network error, timeout, 408, 429, 500, 502, 503, 504Retried
409 with a Retry-After (the same request is still in flight)Retried
A 201 whose body never arrivedRetried; the idempotency key replays it
Any other answer (400, 401, 403, 404, 409, 413, 422…)Not retried: the request fails
  • maxRetries (0 to 10, default 4) sets the retries after the first attempt: 5 attempts in all by default.
  • The wait before retry n is 1 s × 2ⁿ⁻¹, at most 30 s, plus up to 20 % of random jitter.
  • A Retry-After header (seconds or an HTTP date) replaces that wait, capped at 120 s.
  • Each retry is logged, with the attempt and the wait.

With the defaults, a report that keeps failing gives up after about 15 s of waiting (1 + 2 + 4 + 8 s, up to 18 s with the jitter), plus the attempts themselves, each at most timeoutMs. The worst case is a Retry-After on every answer: 120 s before each retry, so 8 minutes of waiting with the default 4 retries (20 minutes with maxRetries: 10), plus up to 5 attempts of 30 s. That is per request, and a failed report stops the later ones of its project. Lower maxRetries or timeoutMs to bound a CI step.

Probara limits API requests per organization (60 requests per minute on Free, 1,200 on Pro, and 3,000 on Enterprise), for every token of the organization together. What a run costs:

RequestHow many
Case keys1 per 200 cases of the run, only with runCasesOnly
Report1 per chunk of up to 500 results (chunkSize)
Attachment stage1 per result with files (per 20 files or 64 MiB)
Attachment commit1 per result with files
Close1, when attachments were queued (otherwise the last report closes the run)

A run of 2000 attempts without files costs 4 requests; one where 100 attempts attach a file (or their console output, with captureOutput) costs about 200 more. 429 answers are retried after their Retry-After. To spread uploads, lower attachmentConcurrency; to send fewer files, attach only what matters, or set uploadAttachments: false.

  • Results go out in chunks of chunkSize (1 to 500, default 500), one after another, in the order Jest ended the test files, each file’s attempts in order. A run case keeps the last outcome recorded, so the order matters. A chunk also stays within Probara’s totals of steps and tags per report.
  • The first chunk creates the run (unless run.ulid names one); the others reuse it.
  • When a chunk fails after its retries, the later chunks of that project are not sent and the run is left open; a results file keeps them.
  • Uploads start once their report is recorded, attachmentConcurrency results at a time (1 to 8, default 2), and the run is closed after the uploads.

Every report, run creation, run close and attachment commit carries an Idempotency-Key, the same on each retry of that request. A retried report whose first attempt was recorded after all is replayed by Probara, never recorded twice. Running jest again is a new run, with every result recorded again.

The reporter uses Node’s built-in fetch, and has no proxy option of its own:

Node.jsProxy support
22.21 or later, 24 or laterSet NODE_USE_ENV_PROXY=1 with HTTPS_PROXY (and NO_PROXY); fetch goes through it
22.12 to 22.20Not supported: fetch ignores HTTPS_PROXY and HTTP_PROXY
Terminal window
NODE_USE_ENV_PROXY=1 HTTPS_PROXY=http://proxy.example.com:8080 npx jest

Node added fetch support for NODE_USE_ENV_PROXY in 22.21.0 and 24.0.0 (Node’s docs). The variables reach Jest’s workers too: put localhost in NO_PROXY if your tests reach a local server through fetch. On older Node versions, upgrade Node or allow the base URL through the firewall.

For a self-hosted Probara behind a private certificate authority, give Node the CA certificate (PEM) when it starts:

Terminal window
NODE_EXTRA_CA_CERTS=/etc/ssl/certs/company-ca.pem npx jest

Node reads NODE_EXTRA_CA_CERTS once at startup, so set it in the environment of the step. On Node 22.19 and later, NODE_USE_SYSTEM_CA=1 trusts the operating system’s certificate store instead. There is no option to turn TLS verification off.

jest --watch and jest --watchAll re-run tests as you save files. The reporter gives the whole session one Probara run: the first run creates it, every re-run reports into it, and it stays open, since a closed run would refuse the next re-run.

$ npx jest --watchAll
[probara] Sending 3 results of 3 tests (3 passed, 0 failed, 0 skipped, 0 blocked)
[probara] Recorded 3 results (2 new cases, 0 unmatched) in R-1 (open): https://app.probara.net/projects/SHOP/runs/R-1
[probara] Watch mode: every re-run reports into R-1 of SHOP, which stays open: close it in Probara, or with probara run close --project SHOP --run-ulid 01J9Z3K4M5N6P7Q8R9S0T1V2W3
[probara] Sending 3 results of 3 tests (3 passed, 0 failed, 0 skipped, 0 blocked)
[probara] Recorded 3 results (0 new cases, 0 unmatched) in R-1 (open): https://app.probara.net/projects/SHOP/runs/R-1
In a watch sessionWhat the reporter does
The first run (or re-run) with resultsCreates the run, and logs the Watch mode line with the command that closes it
Every later re-runReports into that run: each re-run’s results add to its cases’ history
The end of the session (q, Ctrl+C)Nothing: the run stays open. Close it in Probara, or with the logged command
closeRun, closeRunsIgnored: a watch session never closes its runs
run.ulid (PROBARA_RUN_ULID)Every re-run reports into that run, which stays open
projectsOne run per Probara project, created with its first result
runCasesOnlyThe run’s cases are read again before each re-run

Close the session’s run when you are done:

Terminal window
npx @probara/cli run close --run-ulid 01J9Z3K4M5N6P7Q8R9S0T1V2W3

Watch mode is for your own machine: the reporter reports only with a token and a project, so a local session sends nothing unless you set them. The probara.* helpers and the setup file work in watch mode as in any run. --watch re-runs only the tests related to changed files (and needs git or Mercurial); --watchAll re-runs every test. Either way, each re-run is one report into the session’s run.

Someone may close (or delete) the session’s run in Probara while you keep working. The next re-run is refused, so the reporter sends that re-run’s results into a new run at once, and every later re-run reports into the new one:

[probara] 3 results were not sent: Probara answered 409 conflict: <message from Probara>. No run was created or updated
[probara] The run R-1 of SHOP was closed: sent the 3 results of this re-run into a new run
[probara] Recorded 3 results (0 new cases, 0 unmatched) in R-2 (open): https://app.probara.net/projects/SHOP/runs/R-2
  • Only a refusal moves the session. A closed run (409 conflict) or a deleted one (404 not_found) refuses the re-run for good, so its results go into a new run. Any other failure (Probara unreachable, a 409 retried because the same report was still in flight) may have recorded the results after all: they are never sent twice, and the session keeps its run.
  • A run closed halfway through a re-run. Only the results it did not record go into the new run; the rest stays in the old run, and the log line names both.
  • With a results file, a refused re-run is kept in the file, which still names the refused run, and the next re-run reports into a new run. The log line gives the command that sends the file into an open run instead (probara import results <file> --run-ulid <ulid>). When the file cannot be written, the re-run goes into a new run as above.
  • With several Probara projects, each project gets its own run, created with its first result in the session, and its own Watch mode line.

Related: Get started · Results and retries · Troubleshooting · Source: configuration.md, network.md, watch.md