Report exports: PDF, JUnit XML and JSON
AutoTestX results can leave the app as files people and other tools read:
- PDF of a run, a suite run or a release report, to read, sign off or attach to a ticket.
- JUnit XML, the test-result format of GitHub, GitLab, Azure DevOps and Jenkins, so a pipeline shows AutoTestX tests in its own test tab.
- JSON in a versioned envelope, for integrations and archiving.
An export reads the same records as the report on screen, so the two always agree. Whoever can open a run or a suite run can export it, Viewers included. A private test’s runs export only for the test’s owner, the same as its report.
Getting them
Section titled “Getting them”| From | How |
|---|---|
| A pipeline | atx run --suite Smoke --junit results.xml (CLI) |
| A local run | atx run test.json --junit results.xml (CLI) |
| The API | The routes below, with a session or an API token |
| Method | Path | Returns |
|---|---|---|
| GET | /api/executions/:id/report.junit.xml |
A suite run as JUnit XML |
| GET | /api/runs/:id/report.junit.xml |
One run as JUnit XML |
| GET | /api/executions/:id/export.json |
A suite run and every run it started, as autotestx.execution/1 |
| GET | /api/runs/:id/export.json |
One run, as autotestx.run/1 |
| GET | /api/runs/:id/report.pdf |
One run’s report as PDF |
| GET | /api/executions/:id/report.pdf |
A suite run’s report as PDF |
| GET | /api/releases/:release/report.pdf |
The release evidence report as PDF. ?environment= as on /report. |
| GET | /api/releases/:release/export.json |
The release evidence report, as autotestx.release-report/1. ?environment= as on /report. |
Each answers with Content-Disposition: attachment and a file name (exec_….junit.xml,
run_….json). A suite run still in progress, or a run not yet finished, answers 409:
export it once it has finished.
In the app, Download PDF sits at the top of the run report, of the suite run panel and of the release report (Test Suites → Recent suite runs → pick a release).
| Report | What the PDF holds |
|---|---|
| Run | The test, its version, environment, release, start, duration, failure class and AI suggestion; then every step as executed with its screenshot, expected and actual, retries, fallback locators and self-healing; database checks with their rows; the run’s variables. A data-driven run has the rows table, then each row’s steps, with screenshots only for the steps that did not pass. |
| Suite run | The result with its counts, environment, release, commit, branch, build and what started it; every test with status, steps, duration, why it failed or was skipped, and a link to its run. |
| Release | The recommendation with its blockers and risks, totals, likely causes, the suites that count, suites that did not run, failing tests marked Regression, New or Known, and tests fixed since the release before. |
Every page’s header names the report, the environment, the release and the timezone; its footer the report’s id, “Generated
A video or a trace can’t go in a PDF: the run PDF says whether they were kept and links to the run. Values are as the run page shows them, secrets masked. The server prints the PDF with the Chromium the runner already uses, two at a time.
JUnit XML
Section titled “JUnit XML”One <testsuite> per suite run, one <testcase> per test:
<?xml version="1.0" encoding="UTF-8"?><testsuites name="AutoTestX" tests="3" failures="1" errors="0" skipped="1" time="184.200"> <testsuite name="Checkout smoke" timestamp="2026-10-27T09:14:02" hostname="Staging" tests="3" failures="1" errors="0" skipped="1" time="184.200"> <properties> <property name="atx.executionId" value="exec_…"/> <property name="atx.url" value="https://app.autotestx.com/#/suites/exec_…"/> <property name="atx.trigger" value="api"/> <property name="atx.status" value="failed"/> <property name="atx.release" value="v2.14.0"/> <property name="atx.commit" value="9f2c1ab"/> </properties> <testcase name="Sign in" classname="Checkout smoke" time="3.000"> <system-out>PASS 1. Open 0.500sPASS 2. Sign in 1.200sReport: https://app.autotestx.com/#/runs/run_…</system-out> </testcase> <testcase name="Place an order" classname="Checkout smoke" time="14.800"> <failure message="Step 7 'Order total': Text did not match" type="assertion">Expected: 42.00Actual: 40.00AssertionError: Text did not matchFailure class: Wrong valueReport: https://app.autotestx.com/#/runs/run_…</failure> <system-out>…</system-out> </testcase> <testcase name="Refund" classname="Checkout smoke" time="0.000"> <skipped message="Draft: not run with --ready"/> </testcase> </testsuite></testsuites>How results map
Section titled “How results map”| AutoTestX | JUnit |
|---|---|
| Run passed | <testcase> with no <failure> or <error> |
| Run failed | <failure>. message is the first failed step and its error; type is the failure class (assertion, locator, server-error, …). The body has expected and actual, the error, the class and the report link. |
| Run error (could not complete) | <error>, with the same fields |
Test skipped by the suite run (a Draft under --ready, a Deprecated test) |
<skipped> with the reason |
| Test cancelled (the suite run was stopped before it started) | <skipped message="Cancelled"/>. JUnit has no cancelled state. |
| Data-driven run | One <testcase> per row, named Test [row 3], so 2 failed rows of 40 count as 2 failures, not 1 |
A soft assertion that failed the run is reported like any failure, naming its step.
What else is in it
Section titled “What else is in it”<system-out>of each test lists every step asPASS 3. Save 0.412s(FAIL,WARN,SKIP,HEAL), then anything a green result would hide: steps that self-healed, steps that needed a retry, steps found by a fallback locator. The last line is the run report’s link.- Properties are on the
<testsuite>only: the suite run’s id and link, what started it, its final status, and the release, commit, branch and build it was labelled with. Properties it doesn’t have are left out. A single run’s export carriesatx.runId,atx.urlandatx.testVersion. timestampis the start time in UTC, written without a zone (2026-10-27T09:14:02), as the JUnit schema requires.hostnameis the environment’s name, ornone.
What is never in it
Section titled “What is never in it”No screenshot, and no value typed into the page or read from a data row: values are masked in the run already, but a CI log is the wrong place for them either way. Control characters and terminal colour codes in error messages are removed, so the file always parses.
Every JSON export has the same envelope:
{ "schema": "autotestx.run/1", "generatedAt": "2026-10-27T09:20:11.402Z", "generatedBy": { "kind": "user", "id": "usr_…", "name": "Vera" }, "server": { "url": "https://app.autotestx.com", "version": "0.1.0" }, "data": { … }}| Field | Meaning |
|---|---|
schema |
What data is, and its version: autotestx.run/1, autotestx.execution/1, autotestx.release-report/1. The number changes only when a field is removed or changes meaning. A new field does not change it. |
generatedBy.kind |
user for a person, token for an API token |
data |
The record the API returns for it, unchanged, plus url (its page). autotestx.execution/1 adds runs: every run the suite run started, in run order. |
atx run --json keeps writing the plain result, without the envelope, so pipelines that
already read it don’t break.