e2e/runner runs a suite from code without invoking the CLI. run executes
tests and returns their report, explore runs one exploration and returns
its findings, list returns a selection, and openHost hosts e2e sessions
in another test runner. Importing e2e from a test file does not load the
runner.
Reference
Functions
run
run(options?: RunOptions) executes a complete suite. It finishes cleanup
before resolving and never exits the caller’s process.
Options
filestakes paths, globs, bare names, orfile:line.changedSinceworks as--changed-since.- Aborting
interruptSignalinterrupts tests and executes teardown. onEventreceives typed progress events. Terminal progress is off. It must not block. A throwing or rejecting callback is disabled without failing the run.- Put execution settings, such as retries and workers, in the config.
- A runtime config (an
E2EConfigvalue) runs with one worker in the caller’s process. A file config supports the configured worker processes.
Result
Test failures, config failures, and interruption resolve with their status and errors in the report.
- Helper modules your test files import stay cached between
runcalls in one process. An edit to them needs a new process. - Each run that returns a report sends one anonymous
e2e_run_completedevent, with the same opt-outs as the CLI. The first call can print the telemetry notice on stderr. - Suite output uses UTF-8 text redaction and does not preserve binary data. Your application’s logs and progress callback output stay under your control.
explore
explore(options?: ExploreOptions) runs one exploration, the run
e2e explore starts. It finishes cleanup before resolving and never exits
the caller’s process.
Options
goalis at most 2,000 characters.sessionnames a session a setup test saves. That setup runs first, and the exploration starts from it, as--sessiondoes.maxStepsis from 1 to 12.timeoutMsis from180000to900000.onEventreceives the same events as forrun, plus anexploreevent for each planning decision, step, and finding. Whate2e exploreprints before the run starts, such as the target it chose, arrives as anoticeevent with targetrun, before theplanevent.- Recording and output settings, such as
video,trace, andoutput, come from the config.
Result
ExploreResult has every RunResult field, plus explore, the
record report.run.explore also holds.
Once the exploration starts, findings, failures, and interruption resolve
with their status in the report. Options or a config that cannot start one
reject first, as the matching e2e explore flags do. Recognize them with
isE2EError.
Each exploration that returns a report sends one anonymous
e2e_run_completed event, as run does.
list
list(options?: ListOptions) collects and selects the way
e2e list does, and stops there. No app process,
engine, or worker starts, and nothing is written.
Each call imports the test files again, so a later list() in the same
process sees an edit.
Options
targetsnames targets, as--targetdoes.filesis the positional file selection: paths, globs, bare names, andfile:line.tags,tagMode, andexcludeTagsare the--tag,--tag-mode, and--exclude-tagfilters.grepandgrepInvert: a test’s describe titles and title, joined by spaces, must match onegreppattern and nogrepInvertpattern.lastFailedkeeps only tests the previous run did not pass, read fromreport.jsonunderoutput.shardis the--shard index/totalslice.changedSinceworks as--changed-since. The test filters run in the calling process;listprints none of their lines,e2e listdoes.passWithNoTestsresolves with no runnable test instead of throwingNO_TESTS.outputis the results directory.envis the environment the config resolves against.
Result
ListResult is { pairs, unmatched, targets }.
pairsis oneListedPairper test, target, and agent, in selection order, including pairs a filter removed. Repeats are not expanded.unmatchedis the positional arguments, as written, that selected no discovered file.targetsis the selected target names, in config order.
e2e list prints the run and skip pairs, and the pairs a test filter
left out. list returns every filtered pair.
Errors
A failure is the same classified error e2e list exits with. Recognize one
with isE2EError and branch on error.code.
openHost
openHost<Fixtures>(options?: OpenHostOptions) prepares e2e for Playwright
Test, Vitest, Jest, or your own harness, and returns a host.
- Your runner owns collection, retries, and reporting.
- The host prepares the target’s engine, starts app processes, and initializes the engine once per worker lifetime. Use a worker-scoped host and a test-scoped session; see the Playwright Test example.
- Each
host.openSessioncreates a test-lifetime attempt with fresh fixtures, a deadline, steps, and artifacts. - If opening fails, e2e tears down what started before throwing the error.
Options
configis a config file path relative tocwd, or anE2EConfigvalue. Omit it to discover the config fromcwd, the same walklistdoes.cwdis the directory for config discovery, and the project root of a config value.targetis required when the config declares several targets.envis the environment the config, engines, and providers read.signalcancels host provisioning, a pending session open, or live fixture calls.headedruns a browser engine headed.onNoticereceives progress outside a step, such as provisioning or an app process. It must not throw.
A host given a config path loads the file and its project-file imports fresh. Package imports stay shared, so their singleton state is not recreated per host. A config value uses its own engine instances. Each instance belongs to one host until that host closes, so a second host must use another instance.
Opening failures are classified, redacted errors; raw engine causes are not
exposed. Match them with isE2EError and error.code.
isE2EError
A type guard that recognizes a classified e2e error. Branch on its
error.code.
instanceof can miss an e2e error across copies of the package, so use
isE2EError. ConfigurationError and isE2EError are both exported
from e2e/runner.
Host
E2EHost<Fixtures> is what openHost returns.
runId and target are the identity the host’s sessions share.
Only one hosted attempt may be opening, live, or closing per process, even across different hosts and whether the config is a file or a value.
- An overlapping open is rejected before engine attempt state starts. Await
session.close()before opening the next session on the same host. - A launch that fails or is cancelled ends what it opened and leaves the host usable, as a run keeps its worker for the retry.
- A session whose engine cleanup failed closes the host permanently, since its isolation is uncertain; open a new host.
host.openSession
host.openSession(options: OpenSessionOptions) opens a fresh
session on this host’s target. A session is one test attempt with
no retry loop. A retry opens a new session on the same worker host.
Options
nameis the test name for step and trace reporting.timeoutis the deadline for the session’s operations in milliseconds, positive and finite, counted from when the session opens. It does not bound provisioning or opening, and it does not close the session.signalcancels opening or live fixture calls. The host’ssignalalso applies. Provisioning happens inopenHost, so only the host’ssignalcancels it; either signal cancels a launch.agentis the agent theagentfixture uses when a call names none.onStepreceives liveStepProgress, the same feed reporters receive. It must not block or throw. Itsphaseisstart,event,activity,replay, orend. Anendevent includesstatus,durationMs,modelCalls, and a redactederrorwhen the step failed.timeout,agent, andonStepbelong to the session, notopenHost.
host.close
host.close() cancels any active or pending session, waits for it to close,
then disposes the engine, stops app processes, and releases provisioning.
- Idempotent: it disposes and releases resources only once.
- A host is
AsyncDisposable:await using host = await openHost()closes it at scope exit and throws anAggregateErrorwhen closing reports failures.
Session
E2ESession<Fixtures> is what host.openSession returns.
fixturesholdsagent,app,screen,platform, and the engine’s fixtures.runIdandtargetare the host’s run and target;attemptIdis unique to this attempt.steps()returns read-onlyStepRecords for steps run so far, as the report records them.report()returns the sessionReportthe trace is rendered from, after close and a successful trace write; otherwiseundefined. Its status describes the SDK session, not your runner’s test-body verdict.artifactsDiris the absolute directory for this attempt’s screenshots, recordings, and trace.tracePathis the absolute path totrace.md; attach or read it afterclose()settles.
session.close
session.close() cancels remaining operations, ends the attempt, and writes
its trace. It returns soft expectation, abandoned-operation (an unsettled
poll or step), and cleanup failures instead of throwing them.
- Idempotent: later calls return the same failures.
- The host stays open for the next test.
- A session is
AsyncDisposable:await using session = await host.openSession({ name: 'checkout' })closes it at scope exit and throws anAggregateErrorof the returned failures.
Deadline and soft failures
expect.soft collects failures for the session’s whole lifetime. Check
close()’s result to fail the host runner’s test.
expect.polluses the session’s remaining budget, even when its own timeout is longer.- Contributed fixture operations also honor that budget, including operations that disable their own timeout.
- When the deadline passes, a poll or operation that was watching it reports
its own cut. Everything else still running, including an operation an
engine or a model never answered, fails with
TEST_TIMEOUT. - Either way the session’s outcome is timed out and
close()returns the timeout. Later operations fail withTEST_TIMEOUT; close the session.
Artifacts
Artifacts live under <output>/results/host/<resultSegment>/. At close,
e2e writes trace.md there through the same redacted formatting reports
use.
- e2e generates a safe
resultSegmentfrom the name and the unique attempt identity. The name never becomes a raw path component. - Repeated names and retries get separate directories.
- With provider-backed secrets, the directory uses an identity-only segment, since unresolved values cannot be redacted from a title slug. The trace still shows the redacted name.
- Artifact paths are relative to
<output>/results, notsession.artifactsDir. - Video follows the target’s mode for a first attempt. Failure-only video is kept for soft failures and for failed, blocked, timed-out, or cancelled steps.
A hosted session writes its trace, not report.json. For your runner’s
reporting, use onStep, steps(), report(), and close()’s failures.
Your runner’s test-body failures are not passed to e2e.
The one-shot attempt e2e mcp uses stays internal. There is no top-level
openSession export.
Types
e2e/runner exports these types beside the functions.
Examples
Playwright Test fixtures
A worker-scoped host and a test-scoped session: