Configure test projects
midscene.config.ts is the project configuration file for Midscene Test. Use it to configure browser or device initialization, register Nodes for test cases to call, and set execution options such as concurrency and timeouts. This guide covers manual setup, Agent and platform integration, multiple execution projects, and programmatic execution.
Configuration structure
Export a configuration with defineTestProject(). An Execution Project selects cases and supplies their runtime environment.
The example below uses one explicit execution project. Configure and manage a Test Project covers multiple projects and local Node registrations.
Configure a project manually
The scaffold provides platform configuration. To manage browser and Agent resources yourself, use the complete Playwright configuration below. It registers the built-in navigation and AI Nodes and checks an example page.
1. Install dependencies
Create an empty project and install Midscene Test's core dependencies and driver tools:
Before using a Midscene Agent, follow Model configuration to set the required environment variables, including your API Key.
2. Create the project files
We recommend the following basic directory structure:
3. Configure the Test Project and register Nodes
Create midscene.config.ts in the project root. This file registers reusable Nodes and defines the execution environment (Project):
4. Write and run a test case
Create cases/midscene.yaml:
Run the test from the project root:
Midscene Test automatically loads midscene.config.ts, finds matching test cases, and runs them.
Manage project resources
Project setup runs once before the execution project's YAML files. Its returned context is shared across those files. Reset case-specific state explicitly; cleanup registered by a Node has its own execution scope.
Register project cleanup with onTeardown() as soon as a resource is acquired. The framework attempts these callbacks when the project finishes, including after setup or execution fails. Callbacks run in reverse registration order. In the Playwright example, the Agent is destroyed before the browser closes.
Each device instance belongs to one Agent. Agent.destroy() also destroys its device. Create separate resources for each execution project, and do not reuse a device after its Agent is destroyed.
Integrate a Midscene Agent
createMidsceneNodes() from @midscene/test/midscene registers common Nodes: aiAct, aiTap,
aiAssert, aiBoolean, aiNumber, aiString, aiAsk, recordToReport,
wait, and agent.
Call createMidsceneNodes() with the Agent class that declares the Nodes and a getAgent callback that supplies the Agent instance at execution time:
Agent-backed Node inputs mirror the Agent method parameters. Positional
parameters become named top-level fields, while structured parameters keep their original nesting. For example, recordToReport(title, options) uses title and options, and a multimodal TUserPrompt stays entirely inside prompt:
agentClass is the sole source of Agent-backed Node definitions. The factory throws during registration if the class does not expose
getTestRunnerNodeDefinitions(). A platform Agent class registers its common and platform Node definitions together. The base or web Agent registers no platform lifecycle Nodes. You can also compose the platform-only factories described below.
For an Android/iOS registration example, see Configure and manage a Test Project. Register each platform Node once: a platform Agent factory already includes its platform definitions.
Register platform preset Nodes
Midscene Test publishes platform preset factories as separate entry points. Each factory receives getters instead of assuming property names in your Project Context.
Playwright
For Playwright, register gotoUrl, setCookies, clearCookies, and
setViewportSize. The playwright package is an optional peer dependency of
@midscene/test; install it in projects that use this preset:
The following example uses the Playwright ProjectContext from the manual configuration above. Add the returned Nodes to the project’s nodes array:
setCookies does not accept cookie values in YAML. Midscene Test persists every
Node input in the run result. An inline cookie would be copied into that
record.
Use exactly one of cookiesEnv, profile, or storageStatePath as a cookie
reference. The Node resolves the actual cookies only at execution time and
passes them directly to the Playwright BrowserContext. Its result contains only
the reference name and cookie count. Cookie names, values, and scopes are not
written to the run result.
An environment variable may contain a Cookie header, a JSON cookie array, or
Playwright storage-state JSON. Relative storage-state paths resolve from the
current working directory by default; use resolveStorageStatePath when a
project needs a different root. References prevent Midscene Test from persisting
the cookies, but the environment variable, profile, or storage-state file must
still be protected. Do not commit storage-state files containing real cookies.
gotoUrl follows Playwright's navigation semantics. When navigation completes,
HTTP 4xx and 5xx responses are returned as successful Node results with their
status code, so later steps can assert the error page. Network errors and
navigation timeouts still fail the Node.
Android
For the device presets below, define a ProjectContext with an agent of the corresponding platform type and return it from setup. Each snippet shows an alternative platform registration.
For Android, the platform preset registers launch, terminate, runAdbShell, back, home, and recentApps. Its Agent contract requires the corresponding Agent methods:
iOS
For iOS, the platform preset registers launch, terminate,
runWdaRequest, home, and appSwitcher:
HarmonyOS
For HarmonyOS, the platform preset registers launch, terminate,
runHdcShell, back, home, and recentApps:
Platform operation results
runAdbShell, runWdaRequest, and runHdcShell preserve their complete response in the Node
result, but Midscene Test does not automatically pass that response to later
Nodes or Midscene Agent calls. Use command-side filtering when the complete
output is not needed in the run result, or explicitly store only the value a
later Node needs in the Project context.
launch and gotoUrl are intentionally not aliases. launch manages an app,
URL, or URI through a device Agent. gotoUrl navigates the current Playwright
Page and supports Web-specific baseUrl, lifecycle, and HTTP response
semantics.
Configure and manage a Test Project
defineTestProject() supports one or more Execution Projects in the same configuration. Top-level nodes apply to every Project and default to [] when omitted. projects[].nodes, alongside setup and files, apply only to that Project. A local Node replaces the entire global definition with the same name; other global Nodes are inherited. Duplicate names within either registration layer remain errors.
For a mixed Android/iOS configuration, register each platform Agent's official Nodes locally. The example assumes ./setup exports independent setups that each return { agent }, and ./nodes exports shared business Nodes. Each setup owns its Agent and resources:
Both Projects can use the same YAML: launch and other platform Nodes resolve through the current Project's catalog, including during collection and input validation. Local Nodes do not become available to other Projects.
Select cases and control execution
See Run tests for CLI project selection and configuration file options, and Configure timeouts and error handling for step overrides.
Concurrency and isolation
Each Execution Project has its own setup and resources. test.maxConcurrency limits the number of active Projects and defaults to 1. A Project occupies a slot from setup through teardown.
Within a Project, YAML files, cases, and steps run sequentially. To drive several devices or browsers concurrently, declare a Project for each and increase maxConcurrency. Each setup must create and clean up its own resources.
Generate a Markdown reference for each Project
The generated Markdown reference includes the effective Nodes after combining global and Project-local registrations. Select one Execution Project with --project:
Without a selector, nodes generates a shared reference only when every Project has the same effective Node set. If the sets differ, it reports an error asking you to select a Project instead of merging potentially different definitions with the same name.
You can also specify a test directory or a custom configuration file:
The reference includes an Available Nodes overview and Node Details with descriptions and input schemas. The reference and stdout list aiAct and aiAssert first, then the remaining Nodes by name. Midscene Test converts each Zod inputSchema to standard JSON Schema.
The reference lists Case files (each Execution Project's files.include / files.exclude glob patterns) and Config file separately. Both use paths relative to the reference file, so authors can locate their YAML files and configuration. Created projects select cases/**/*.{yaml,yml} by default. Without a files configuration, Midscene Test searches **/*.{yaml,yml} under the test directory.
Timeouts and cancellation
A step timeout aborts that step's signal. When running tests through the CLI, SIGINT (for example, pressing Ctrl+C) or SIGTERM aborts the run and forwards cancellation to the currently executing steps.
Cancellation notifies a Node through AbortSignal; it does not forcibly terminate asynchronous operations inside the Node. Custom Nodes need to pass signal to APIs that support cancellation or explicitly check its state. See Asynchronous operations, errors, and cancellation for usage.
After a run is interrupted, the framework still attempts to run afterEach, afterAll, and cleanup functions registered with onTeardown(). When executing Nodes in afterEach and afterAll, if the run's signal has already been aborted, the framework uses a new signal that has not been aborted so cleanup operations can continue. Step timeout settings still apply to these cleanup steps.
Cleanup functions registered with onTeardown() do not receive a new signal. Avoid reusing the original step's signal in these functions: a timeout or run interruption may have already aborted it, causing cleanup requests to fail immediately.
Programmatic APIs
Most teams only need the project configuration, YAML files, and CLI. To embed Midscene Test in another tool, such as a local GUI test panel, use these exported programmatic APIs:
loadTestProject(): asynchronously loads the TypeScript project configuration frommidscene.config.ts. Midscene Test does not support synchronous loading.runTestProject(): asynchronously discovers, runs, and summarizes the entire project. It is exported from@midscene/test/config.CaseRunner/createCaseRunner(): directly runs one test case represented as a plain object, without file parsing or lifecycle management.runWorkflowDocument(): runs the complete lifecycle and every Case in one document.

