Extend and maintain test projects
@midscene/test supports registering business Nodes, managing runtime resources, and defining execution lifecycles. Framework maintainers can use these capabilities to integrate browsers, Agents, external tools, and business APIs into a customized testing foundation for their teams.
For an overview of the design, see Midscene Test overview.
Create a project
Use create to generate a project with a platform Agent and example cases. Installing dependencies also generates a Node reference:
The command requires Node.js ^20.19.0 || ^22.12.0 || >=24.0.0 and the selected package manager (npm or pnpm). After writing the project files, it asks whether to install dependencies and generate midscene-node-reference.md. The default is yes.
In an interactive terminal, pnpm dlx @midscene/test create asks for the directory, platform, and package manager. In CI or other noninteractive environments, supply the directory and platform. Existing destination files are never overwritten, including when --yes is set.
The final prompt is “Install dependencies and generate midscene-node-reference.md now?”. Choosing no keeps the project files and prints the command to install later. Cancelling this final prompt also preserves the files. In noninteractive environments, installation runs automatically unless --skip-install is set.
To create files now and install later:
The generated package.json includes a postinstall script:
Manual npm install or pnpm install runs this script and refreshes the reference, including on later installations. If lifecycle scripts are disabled, run npm run nodes or pnpm run nodes manually. When create installs dependencies, it reuses the postinstall output; if the file was not generated, it runs nodes once itself. A generation failure makes the installation or creation command fail.
An explicit --package-manager takes priority and skips the package manager prompt. Otherwise, the prompt defaults to the manager used to launch the command, detected from npm_config_user_agent. In noninteractive environments or with --yes, that detected manager is used directly. If npm or pnpm cannot be detected, the default is npm.
For example, use npm to create and install a project without pnpm:
Dependency installation, Node reference generation, the generated README, and recovery instructions all use the selected manager. The examples below use pnpm. For npm projects, use npm test, npm run nodes, and npm exec -- playwright install chromium instead.
harmony uses @midscene/harmony to connect to HarmonyOS devices through HDC. computer uses @midscene/computer to control the local Windows, macOS, or Linux desktop:
Both platforms also support --with to register external Node packages.
After installation with pnpm, the project contains the following files. If installation is skipped, midscene-node-reference.md and the lockfile are created later during installation. npm creates package-lock.json instead of pnpm-lock.yaml. The README is generated only as README.md:
Copy .env.example to .env and fill in your model configuration. For Web, install Chromium with pnpm exec playwright install chromium. For Android, connect a device and optionally set ANDROID_DEVICE_ID. For iOS, start WebDriverAgent and configure WDA_HOST and WDA_PORT.
For HarmonyOS, verify the connection with hdc list targets and optionally set HARMONY_DEVICE_ID. Set HDC_HOME if HDC is not on PATH. For desktop, follow the desktop setup guide to install system dependencies and grant permissions. Optionally set COMPUTER_DISPLAY_ID to select a display. On headless Linux, install Xvfb and enable MIDSCENE_COMPUTER_HEADLESS_LINUX.
The desktop example inspects the current screen with aiAsk; mobile examples use home followed by aiAsk. Each generated configuration registers the Nodes provided by its platform Agent.
Run pnpm test to execute the example. Creation and Node reference generation do not run project setup or tests, so they do not require a model API Key, an installed browser, or a connected device. After editing Node registrations, run pnpm run nodes to refresh the reference.
If installation or reference generation fails, the command exits with an error and preserves the generated files. Follow the recovery commands in the error message; there is no need to rerun create over those files.
Add Node packages during creation
--with is only available on create. It adds the packages to devDependencies and writes explicit factory imports and Node registrations into midscene.config.ts. Subsequent test runs and nodes load that configuration without additional CLI flags. The generated reference includes the external Nodes.
Packages must expose a named, synchronous createMidsceneTestNodes(options) factory from their root entry point. Both ESM and CommonJS are supported. The factory receives platform and getAgent, and returns a Node array. NodePackageOptions is exported from @midscene/test/config for package authors:
Declare @midscene/test as a peer dependency and publish the factory's TypeScript declarations. Access runtime resources through getAgent inside execute; package imports and factory calls must not connect to devices or require model credentials. A factory can validate platform and reject unsupported platforms. Additional business resources must be wired explicitly in the project configuration.
Node names must be unique across built-in and external Nodes. Missing factories, invalid definitions, or duplicate Node names cause reference generation to fail. --with currently accepts registry package names with optional versions or tags; local paths, Git URLs, package subpaths, and repeated package names are not supported.
Configure a project manually
The following example shows how to set up a simple test project that switches the browser's user-agent language.
1. Install dependencies
Create an empty project and install Midscene Test's core dependencies and driver tools:
Note: Before using a Midscene Agent, follow Model configuration to set the required model environment variables, such as 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.
Register custom business Nodes
Use defineNode() to encapsulate complex API calls, database operations, cleanup tasks, or specialized browser interactions as named Nodes. Test case authors can then call these Nodes directly from their test cases.
Basic business Node example
The following example wraps an HTTP API that creates a test order:
After adding the Node to the configuration's nodes array, test case authors can use it directly:
Define and strictly validate input with Zod
Although inputSchema is optional, we strongly recommend defining it.
- Type inference and validation: Midscene Test validates the input with Zod before entering
execute(). Invalid input immediately throws aNodeInputValidationError, while TypeScript provides compile-time type inference without a separate interface. - Unknown parameter rejection: use
z.strictObject()so Midscene Test rejects unexpected fields in a test case. - Automatic reference generation: information from each field's
.describe()call is included in the generated Node reference for AI Agents and human test case authors.
Node execution context
The ctx passed to execute(ctx) contains these commonly used fields:
input: business parameters passed from YAML and validated by Zod.$: general Step properties controlled by Midscene Test, such as normalizedtimeoutandcontinue-on-errorvalues.signal: anAbortSignaltriggered by a timeout or cancellation. Use it in asynchronous requests or long-running tasks to exit early and cleanly.context: Project-level runtime resources returned bydefineProjectSetup()and shared within the Project.onTeardown(): registers cleanup functions for resources created by the current Node. Cleanup can use attempt or Document scope and runs in LIFO order.scope: identifies the current Node execution boundary as eithercaseordocument.caseordocument: detailed runtime information for the current execution position.
Nodes do not receive previous Node results automatically. When later Nodes need a value, store it explicitly in the Project context as described below.
Share state across Nodes
In real-world tests, multiple Nodes often need to share state. For example, an order refund test can create an order and store its ID in beforeEach, access the ID from steps, and clean up the data in afterEach.
Define state properties in a custom ProjectContext to enable this coordination:
Integrate a Midscene Agent
@midscene/test/midscene exports common system 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.
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.
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:
Then create the preset Nodes:
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.
For Android, the platform preset registers launch, terminate, runAdbShell, back, home, and recentApps. Its Agent contract requires the corresponding Agent methods:
For iOS, the platform preset registers launch, terminate,
runWdaRequest, home, and appSwitcher:
For HarmonyOS, the platform preset registers launch, terminate,
runHdcShell, back, home, and recentApps:
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.
Generate a Node reference
Midscene Test provides the nodes tool so test case authors, including AI Agents, can clearly discover the registered Nodes and their parameter schemas. It compiles each Node's title, description, and Zod inputSchema into a standard Markdown reference.
Run the following command to generate a reference for your team:
The command writes midscene-node-reference.md in the specified test directory (or the current directory when omitted). After generation succeeds, stdout lists every registered Node by name and description, followed by the absolute path to the reference file. No output redirection is needed.
You can also specify a test directory or a custom configuration file:
The generated reference includes every Node registered in the active Test Project, including the system Nodes returned by createMidsceneNodes(). It starts with an Available Nodes overview table, followed by usage conventions and a Node Details section containing each Node's description and input schema. Both the reference and stdout list aiAct and aiAssert first, then the remaining Nodes sorted by name. Midscene Test automatically 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.
Configure and manage a Test Project
defineTestProject() is the main configuration entry point for the testing foundation and supports one or more Execution Projects:
Key configuration strategies
- Environment and resource isolation: each Execution Project has an independent
setupenvironment, such as a separate browser or a specific test device. - Multi-Project concurrency and lifecycle slots:
test.maxConcurrencycontrols the number of active Projects. The default is1.- One concurrency slot covers the entire lifecycle from Project setup through teardown.
- Within a single Project, all Workflow Documents, Cases, and Steps still run strictly in sequence to ensure deterministic tests.
- To drive multiple mobile devices or browser instances at the same time, declare multiple entries in
projectsand increase the concurrency value.
- Lifecycle cleanup: use
defineProjectSetup()to define environment preparation. Register cleanup hooks withonTeardown()so that long-lived resources are safely released in reverse LIFO order even if a test is interrupted or fails partway through.
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.
After configuring the project, continue to Write and run test cases for test case syntax and parameters.

