From Local Experiment to CI System
This chapter turns tester-army/e2e’s architecture into an operating path: configure a target, start the right app or device, run deterministic and agent steps, interpret reports, and move from live discovery to a verified regression test. The focus is ownership and evidence across a real run. The reader should be able to adopt the framework without treating an interactive session, a model finding, or a green-looking command as proof by itself.
The security and replay boundaries from the previous chapters make operations more disciplined, not less. A CI run needs model credentials without exposing them, browser or device resources without leaking them between attempts, artifacts without retaining unsafe pixels, and a cache policy that does not silently rewrite the team’s shared evidence. Exploration is useful, but it must return to the authored test suite before a finding becomes an engineering claim.
Owning a real run
The first configuration decision is the target. A web target declares an app URL and can declare a structured command for the runner to start, log, probe, and stop. A mobile target declares the installed app or build it should launch, along with launch arguments and permissions. The engine is selected beside the app declaration. This arrangement keeps “what is under test” separate from “how this platform is driven.”
For a local Vite or Next.js application, the runner can start a development command and poll the target URL or a separate readiness URL. It gives the process a bounded startup budget and stops it when the run ends, fails, or is interrupted. The command is structured rather than shell-interpreted, so the target’s working directory and environment are explicit. If a server is already running, local reuse can be configured, but CI should not assume that an unrelated process on a fixed port is the intended app.
A mobile target has a different starting condition. The engine needs an iOS simulator, Android emulator, or connected phone, and a compatible app identity or build. A device may need signing, developer mode, USB authorization, or an installed runtime. The runner provisions device workers, opens the target app when the test calls app.open(), and applies launch arguments and permissions at the appropriate lifecycle point. A test that assumes a browser URL on a mobile target is not portable just because the rest of its assertions use the same screen API.
Preparation happens before ordinary test timing where possible. The web engine can install a missing Playwright browser once per run, before workers start and before the run clock includes test execution. A hosted browser or device provider can provision leased resources at a declared scope and release them during cleanup. Attempts then receive their own isolation, such as a browser context or a device observation generation. This distinction matters when diagnosing a slow first run: a browser download is not the same failure as an app that never became ready or a test that timed out after the page opened.
The run proceeds through selection, worker initialization, attempt setup, test and hook execution, artifact recording, and cleanup. A test file can mix model-free checks with agent steps. An agent model is needed only when the selected test acquires an agent and calls an agent operation; the deterministic greeting example can run without a provider. This makes a gradual rollout possible: a team can establish the app command, semantic locators, and exact assertions before paying the operational cost of model-backed flows.
The app process, engine, attempt, and artifact store each have a different owner.