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 configuration structure, Agent and platform integration, multiple execution projects, and file resource isolation.
Configuration structure
Use defineTestProject() to define and export your project configuration. An Execution Project selects cases and supplies their runtime environment.
Midscene Test supports the following configuration files:
Midscene Test loads midscene.config.ts or midscene.config.mjs by default. If both files exist, it reports a conflict instead of choosing one silently; use --config <path> to select the intended file explicitly.
Prepare shared project resources in setup, prepare resources for each file in fileSetup, and register the corresponding Agent Nodes through nodes.
The example below starts with a single execution project. To manage multiple execution projects or register different Nodes for each project, see Configure multiple execution projects.
Configure the runtime environment
Complete example: Playwright
This sequential configuration uses only setup: all files in the execution project share one page. Add fileSetup when each file needs its own environment, even without concurrency.
To add Midscene Test to an existing project manually, first install @midscene/test, @midscene/web, and playwright (pnpm add -D @midscene/test @midscene/web playwright), then run pnpm exec playwright install chromium to install the browser. Before running tests, follow Model configuration to set the required environment variables, including your API Key.
For a handwritten configuration, load .env explicitly (for example, install dotenv, import dotenv/config at the top, and run from the project root), or supply shell/CI variables. See Environment loading.
The configuration connects these parts:
setupcreates the browser and page and registers cleanup functions throughonTeardown().contextholds runtime resources. Nodes obtain the Agent throughgetAgent, which creates an instance on first use and stores it incontext.agentfor subsequent calls. Playwright Nodes use that Agent’s page.nodesregisters common AI operations and Playwright operations for YAML cases to call.projectsdeclares an execution project namedchromium, connecting itssetupto the YAML files undercases/.
You can now write YAML test cases and run tests. The next section explains how these resources are shared and cleaned up.
Create and clean up shared resources with setup
defineProjectSetup() defines project preparation, assigned through the setup field. During a test run, each execution project calls its setup() function once. The example above returns a browser and page for the project's Nodes to share.
For file isolation, define per-file preparation with defineFileSetup() and assign it through fileSetup. It receives the project setup's return value and creates resources for the current file. See Isolate resources with fileSetup for the relationship and an example.
Shared resources are not automatically recreated before each case. To reset pages, cookies, or business state, call the appropriate Nodes through YAML lifecycle hooks. For reading and updating shared data in custom Nodes, see Share context across Nodes.
After creating a browser, Agent, or other resource, immediately register its cleanup function with onTeardown(). The framework attempts the registered cleanup functions when the project finishes, even if setup or test execution fails. Cleanup runs in reverse registration order: in the Playwright example above, the Agent is destroyed before the browser closes.
The onTeardown() callbacks registered here run when the project finishes. Cleanup functions registered inside Nodes have their own execution scope.
Isolate resources with fileSetup
Use setup for shared project resources and fileSetup for resources owned by each file. Web tests can share one Browser while creating a separate BrowserContext, Page, and Agent per file to isolate cookies and other browser state.
The YAML uses the prepared Agent: beforeAll sets the viewport, and beforeEach opens the home page for every case:
This example creates the Agent in fileSetup. File cleanup destroys the Agent and then closes the BrowserContext. The shared Browser closes after all file cleanup.
The type parameters in defineFileSetup<FileContext, SharedContext> describe the file return value and the project return value, respectively. fileSetup returns the complete file context; it is not automatically merged with projectContext. Explicitly return shared fields that Nodes need.
The preparation function receives these arguments:
For a single configuration, omit projects and put setup and fileSetup at the top level. If a file can prepare all its resources itself, configure only fileSetup.
On Android, iOS, and other device platforms, allocate an exclusive device to each concurrent file and create a separate Device/Agent. Each Device instance belongs to one Agent, and Agent.destroy() destroys that Device; return the device allocation after destroying the Agent. Project code supplies the device pool and business-state reset. With one phone or one desktop, set that project's limit to 1; multiple Agents operating the same device still interfere with each other.
See Project lifecycle for context scope and cleanup order, and Handling failures for preparation failures.
Nodes or fileSetup must explicitly report shared-resource failures; Browser closure messages alone do not establish ownership. See Asynchronous operations, errors, and cancellation for how to report them.
Register official Nodes
Common AI operations and Agent integration
The Midscene Test kernel does not register Nodes implicitly. Configuration generated by midscene-test create calls createMidsceneNodes() from @midscene/test/midscene to register official Nodes for the selected platform. In handwritten configuration, explicitly add the returned definitions to top-level nodes or projects[].nodes.
createMidsceneNodes() returns the common and platform Node definitions declared by agentClass.getTestRunnerNodeDefinitions(), plus the Test-provided wait Node. Common capabilities cover AI operations, assertions and extraction, interface location, and report recording. Platform Agents add browser or device operations. The website does not maintain a duplicate exhaustive list; use the current Project's generated Node Spec for exact names and inputs.
When calling createMidsceneNodes(), use agentClass to specify the platform-specific Midscene GUI Agent class and a getAgent callback to supply the Agent instance at runtime:
createMidsceneNodes() does not mutate a global registry; its Nodes become available only after the returned array is included in project configuration. agentClass is the sole source of Agent-backed Node definitions, while getAgent describes how execution obtains an Agent instance from the current context. The factory throws during registration if the class does not expose getTestRunnerNodeDefinitions(). PlaywrightAgent, PlaywrightPageAgent, PlaywrightBrowserAgent, PuppeteerAgent, PuppeteerPageAgent, PuppeteerBrowserAgent, AndroidAgent, IOSAgent, and HarmonyAgent provide common and platform Node definitions together. The base Agent and ComputerAgent only provide common Agent Nodes.
Name Nodes for multiple Midscene Agents
When one workflow uses multiple Midscene Agents, set namespace to register their Nodes under different names. Have your setup return separate Midscene Agent instances in the context, then register both sets in the same Project:
Add nodes to your Project configuration. YAML calls the registered names:
The namespace prefixes every returned Node, including common AI operations, platform operations, and wait. For example, this registration provides mobile.aiAct and mobile.wait; it does not also register the unprefixed names. Omit namespace to keep the original names.
A namespace must be a non-empty string without whitespace, leading or trailing dots, or empty dot-separated segments. Nested namespaces such as checkout.mobile are supported. Invalid values fail during registration, before an Agent is acquired.
Namespaces only change Node names. getAgent or agentProvider.getAgent still selects the runtime Agent, and execution traces remain associated with the corresponding Steps. Namespaces do not create resources or provide concurrency isolation. Separate Projects can register the same Node names without a namespace.
For an Android/iOS registration example, see Configure multiple execution projects.
When integrating an Agent on device platforms such as Android or iOS, observe resource ownership. 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.
Register each platform through createMidsceneNodes(): specify its Agent class with agentClass and supply the instance through getAgent. You can choose your own field names for the project context.
Once registered, these Nodes can be called from YAML. See Calling other Nodes for parameter syntax, and consult the project-generated Node Spec for specific fields.
Playwright
Use createMidsceneNodes({ agentClass: PlaywrightAgent, getAgent }) to automatically register gotoUrl, setCookies, clearCookies, and setViewportSize. Before using these Nodes, install playwright in your project. It is a peer dependency of @midscene/web:
Cookies are read from process.env by default. Only configure Agent testRunner options such as getEnv, getCookieProfile, or resolveStorageStatePath when you need custom cookie sources. The context in these callbacks is the current Agent.
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.
See the current project's Node Spec for navigation inputs.
Puppeteer
Puppeteer exposes the same gotoUrl, setCookies, clearCookies, and setViewportSize Node names. Install the puppeteer peer dependency and pass PuppeteerAgent (or PuppeteerBrowserAgent) to createMidsceneNodes():
The Playwright and Puppeteer integrations use the same Web Node schemas and execution implementation. Browser-specific code is limited to a driver adapter. For portable YAML, use domcontentloaded, load, or networkidle for gotoUrl.waitUntil; the Puppeteer adapter maps networkidle to networkidle0. Existing engine-specific values remain supported: Playwright accepts commit, while Puppeteer accepts networkidle0 and networkidle2. Using one of those values with the other driver produces an explicit error. Cookie references and result redaction also behave the same on both integrations. Relative URLs resolve against testRunner.baseURL, then against the current HTTP(S) page URL.
Android
To use the device presets below, declare an agent of the corresponding platform type in ProjectContext and include that instance in the object returned by setup. Each platform example is independent; choose the one you need.
Use createMidsceneNodes({ agentClass: AndroidAgent, getAgent }) to register launch, terminate, runAdbShell, back, home, and recentApps. The supplied Agent must provide the methods these Nodes call:
The complete response from runAdbShell is saved in the Node result.
iOS
Use createMidsceneNodes({ agentClass: IOSAgent, getAgent }) to register launch, terminate,
runWdaRequest, home, and appSwitcher:
The complete response from runWdaRequest is saved in the Node result.
HarmonyOS
Use createMidsceneNodes({ agentClass: HarmonyAgent, getAgent }) to register launch, terminate,
runHdcShell, back, home, and recentApps:
The complete response from runHdcShell is saved in the Node result.
Configure execution projects
An execution project connects a runtime environment to its cases. Even a single execution project can configure case selection, variables, and retries. Declare multiple execution projects to run across browsers, devices, or environments.
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.
The scaffold generates a configuration that selects cases/**/*.{yaml,yml} by default. Without a files configuration, Midscene Test recursively searches for **/*.{yaml,yml} under the test directory.
Selected files are deduplicated and sorted by path. See Project lifecycle for execution order and retry scope, and Concurrency and isolation for concurrency settings.
Native Test always generates a combined report. The CLI prints its path after the run. See Run tests for report outputs and archiving.
Configure multiple execution projects
To run tests across different browsers or devices, configure multiple Execution Projects with defineTestProject().
Nodes registered in the top-level nodes field apply to every Project; the field defaults to [] when omitted. Within an individual Project, you can also register local Nodes using the nodes field alongside setup and files. A local Node applies only to that Project and replaces the entire global definition with the same name. Other global Nodes remain available. Duplicate names within the same registration layer cause an error.
When configuring both Android and iOS projects, register each platform Agent's official Nodes within its Project. The example below imports two independent setups from ./setup, each managing its own resources and returning { agent }. It imports shared business Nodes from ./nodes:
Both Projects can use the same YAML file. During case collection, input validation, and test execution, launch and other platform Nodes use the definitions that apply to the current Project. A Project's local Nodes do not affect other Projects.
Generate a Node Spec for each Project
Run midscene-test nodes to generate a Node Spec of the available Nodes. Use --project to select an execution project and list the Nodes available after combining its global and local registrations:
When projects is declared, omitting --project generates a separate Spec for each Execution Project, even when their Node definitions are identical.
For filenames, output rules, Spec contents, and command options, see Generate the current Project's Node Spec.
Programmatic APIs
You can also use APIs to integrate Midscene Test into other tools, such as a local test panel with a graphical interface. The following APIs let you load project configuration, run an entire project, or execute an individual case:
loadTestProject(path): asynchronously loads an explicitly provided TypeScript (.ts) or JavaScript ESM (.mjs) project configuration. Without--config, the CLI discoversmidscene.config.tsormidscene.config.mjs; if both exist, it asks you to select one explicitly. Midscene Test does not support synchronous loading.runTestProject(): asynchronously discovers, runs, and summarizes the entire project.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.
Run a complete project and preserve its failure exit status:
Next steps
- Execution lifecycle and concurrency: resource sharing, retries, concurrency, timeouts, and cancellation.
- Run tests and CLI reference: targets, paths, and environment variables.

