A reporter receives the run’s events as they happen and the finished run
once its report is written. reporters in e2e.config.ts lists built-in
reporters by id beside reporter objects.
Reference
Built-in reporters
list
Renders terminal progress, failures, and the run summary.
- It renders the same events
onEventreceives. - The summary rows reporters return print under its summary.
json
Prints the report document to stdout.
junit
Writes junit.xml beside the report.
- It reads
run.report, writesjunit.xmlbesiderun.reportPath, and returns one row naming the file. It is the smallest complete example of a reporter. - A second Ctrl-C still lets it write its file, so no file from the previous run is left beside the new report.
markdown
Writes summary.md beside the report.
It does what junit does, second Ctrl-C included, with summary.md and
through renderMarkdownReport.
renderMarkdownReport
Renders a report as the Markdown page the markdown reporter writes, so
your own reporter can post the same page elsewhere.
traceslinks each block to its trace page by result id.@e2e-dev/githubis that reporter for GitHub Actions.
github()
@e2e-dev/github posts the run as one pull request comment from GitHub
Actions, keeps it current on reruns, and writes the same text to the job
summary.
keytells one job’s comment apart from another’s when the workflow, job, and project are the same, as in a matrix. Without it, matrix replicas of one job share a comment, and the last one to finish wins. Never use the run id: a rerun must find the old comment. The key also names the comment in its headline:e2e chromium: 77 passed.- It reads the token, the event, and the repository when the run finishes, never when the config loads.
- With
--last-failed, it folds the rerun intolastRunto show both runs as one comment. - Setup and permissions are on Pull request comments.
Custom reporters
A reporter object has a name and at least one handler. Use onEvent for
live progress and onRunFinished to process the final report and artifacts.
Cached steps expose cache.recordedBy: { provider, model } in report.json
and on the trace page when the recording has it. Older recordings omit it.
The console prints replayed · recorded with provider/model only when that
identity differs from the configured model. It stays quiet for multi-agent
runs and for pinned agents whose model is not in the run header.
name
The reporter’s label in diagnostics. Required and non-empty.
onEvent
Receives every run event as it happens, as plain JSON.
Events lists them.
onEvent must not block and must not throw. Do slow work in
onRunFinished. A throw quarantines the reporter for the rest of the run and
prints one line on stderr naming the reporter, the event type, and the error.
The run’s outcome is unchanged.
onRunFinished
Runs once the report is written and the terminal summary prints, with the
finished run and an AbortSignal.
- All reporters run concurrently, each with a one-minute deadline.
- A timeout, exception, or invalid return value is reported on stderr. The run’s status, exit code, and report do not change.
- One Ctrl-C still lets reporters finish. A second Ctrl-C stops waiting for
them, except
junitandmarkdown. signalaborts when the budget runs out or the run is forced to stop.- The runner writes the trace pages,
results/<test>/trace.md, before it callsonRunFinished.
Hand signal to every request and timer. The CLI exits without waiting for
a reporter it abandoned, cutting off what it still does; under
e2e/runner, that work keeps your process alive.
Summary rows
The rows a reporter resolves with print under the list summary, in the
same layout as its own rows. The json reporter does not carry them.
Artifacts
- Artifact paths in the report are POSIX paths relative to
artifactsRoot. path,size, andsha256are optional: an artifact whose file never appeared, or that a redaction withheld, is recorded without them. Check forpathbefore reading.- A video a hosted service keeps has an
http(s)urlin place ofpath.
Reruns with --last-failed
- The rerun’s own report lists the tests it left out as unselected. A
reporter that keeps one place current, the way
@e2e-dev/githubkeeps a pull request comment, folds the rerun intolastRunto show both runs as one. - A test the rerun owed but another filter left out is in the rerun’s
run.carried. It holds the test’s last result, the serial group its attempts live on, and thebeforeAllorafterAllfailure whose scope holds it, from whichever earlier run reported them. - A fold shows the carried result in place of the unselected one and counts a carried failure or hook error against the outcome.
- The artifacts both reports name are on disk under
artifactsRoot.
Test filters
- A test a test filter left out is an unselected result with
skip.causefilteredandskip.filternaming the filter. run.filtersholds one record per filter that was called, in order:name,candidates,excluded(the tests left out once serial groups took back their members),note(cut to 1024 characters; for a filter that failed or timed out, the warning saying why), andoutcome, set when the filter left nothing out:failedwhen it threw or returned an invalid result,timed-outwhen it ran past 5 minutes. A filter left with no tests is not called and has no record.- Once the filters have decided,
run.changesholds the change they judged, by counts:base(the merge base),files, andskipped(why no filter ran, such asno files changed since abc1234). It is present when filters are configured and the run passed--changed-since, except undere2e explore, on--watchreruns, and when the run ends before the filters decide. On--last-failed, or with no tests to judge, it holdsskippedalone. - A failure while the filters decide, such as
INVALID_CHANGED_SINCEfor a ref that names no commit, is inrun.errorswithphasefilter. A malformedchangedSincehasphaseconfig.
Events
onEvent receives one of these facts. Each event also has a sequence
number, seq, and an ISO timestamp, at.
run-startedcomes first andrun-finishedlast.judgeonrun-startedis the run agent’s judge model, present only when judgments use a model other thanmodel.setupbrackets the work before the tests start. Itsstep.kindiscollect,filter(one test filter, by itsname),prepare,service, orapp.outcomeisreusedwhen a service or app command attached to a process already serving its URL,failedwhen a filter threw or returned an invalid result, andtimed-outwhen a filter ran past 5 minutes.- A
noticenames what its line is about intarget: a target,app,collect,filterfor a test filter’s progress and summary, orrun. outputis one write a test made to stdout or stderr;pairnames the test running at the time and is undefined between tests.test-finishedcarries the full result record, including every attempt’s artifacts.exploreappears only in ane2e explorerun:started,planning,step-started,step-finished,finding, andfinished. The record of all of it isrun.explorein the report.- New event types are added over time. Handle the types you know and ignore
the rest; leave the
defaultbranch of aswitchempty.
Tests and attempts
- A test pinned to several agents starts and finishes once per agent, so key running state by test id, target, and agent together.
- Ordinary tests emit
test-startedonce for that combination. Serial members emit it on each group attempt they execute. - Use step progress identity to distinguish retries.
- An attempt that fails before any step emits no step progress and appears in the final result.
Secrets are redacted before events are built. Error messages are only stripped of control characters, so treat them as untrusted.
Step progress
The phase field describes step progress:
startandendmark the step’s boundaries.eventreports a completed model turn, tool call, or observation.activityreports work starting:observe,action, ormodel.replayreports when replay from the cache starts or returns control to the agent.
An end phase’s error and explanation are redacted. Keep its status,
including blocked and cancelled. Do not treat every non-passed step as a
product failure.
Every step phase the runner emits includes progress.identity:
- The IDs match the final report. Both indexes start at zero.
- A retry has a new attempt ID and a higher attempt index; its step indexes start again at zero.
- Serial-group members share the group’s attempt ID and index. Each member’s step IDs stay distinct.
- Use
stepIdto match start, activity, event, replay, and end phases, including nested steps. identityis optional in the type so a reporter can also accept older streams.
What --reporter does to reporter objects
--reporter replaces only the built-in reporters; configured reporter
objects still run.
- A config with only reporter objects has no built-in terminal output.
Where a reporter runs
Handlers run in the runner process. Workers also load the config, so reporter construction must have no side effects.
- Read tokens and start requests inside handlers.
- Adding a reporter leaves cached traces valid.
Types
Reporter, FinishedRun, ReporterSummary, Report, RunEvent, and
RunEventOf are exported from the main entrypoint, and so is
renderMarkdownReport(report, options).
Related
Pull request comments sets up @e2e-dev/github. The
CLI reference lists what the built-in reporters write.