Execution lifecycle and concurrency
Project lifecycle
setup, fileSetup, and beforeAll
They run in the order setup → fileSetup → beforeAll → cases. Unconfigured parts are skipped.
In a normal run of two YAML files, setup runs once, while fileSetup and beforeAll each run twice. Concurrency limits do not change these counts.
Configure fileSetup once for all files; declare beforeAll in each file. Custom Nodes in beforeAll can also create resources, but this does not make the framework create an independent file context.
YAML lifecycle hooks
Lifecycle hooks prepare the environment, reset state, or clean up data around test cases. All four hooks are optional and appear at the same level as cases. Their steps use the same Node call syntax as case steps.
This Web example opens the store home page before each case and clears cookies afterward. data.prepare and data.cleanup are custom Nodes your project must implement and register to prepare and remove test products. gotoUrl, clearCookies, aiAct, and aiAssert are official Nodes registered by the Web scaffold:
Project, file, and case lifecycle
When running tests through the CLI or runTestProject(), each execution project has its own lifecycle. The following shows normal sequential execution for a project with two YAML files. YAML hooks that are not declared are skipped:
beforeAll and afterAll each run once per YAML file; beforeEach and afterEach surround every case attempt. With file concurrency enabled, files can advance together, while each file follows the order shown above.
Case retries reuse the file environment and repeat only beforeEach → steps → afterEach → Node cleanup for this attempt. Project setup, fileSetup, and beforeAll do not rerun. See Handling failures for retry conditions and skip rules.
The scope of onTeardown() depends on where it is registered:
Within each scope, callbacks run in reverse registration order. If one throws, remaining callbacks are still attempted; if it has not finished, later cleanup waits for it. See Resource lifecycle and cleanup for implementing Node cleanup.
Context sharing scope
The configuration determines which context Nodes receive:
Nodes within the same sharing scope receive the same object. A value written to context.orderId can remain visible to later cases. The framework does not reset the context, page, or login state between cases or retries; restore the required initial state in beforeEach.
Create resources and the returned object inside the setup() function. Projects or files invoke the function separately even when they reference the same definition; returning a mutable object from module scope would still share state. See Share context across Nodes for a data-passing example.
Handling failures
A failed step skips the remaining steps in its phase by default. Set continue-on-error to continue, while keeping the failed result. Cleanup Nodes should handle partially completed preparation.
A failed case does not prevent the next case from running by default. Set test.bail to skip later cases and retries after a failed-case threshold; the current attempt finishes before cleanup. Cancelling the run instead requests that running operations stop. Keep dependent business steps in the same case.
Resource failures or failed or unfinished registered cleanup stop retries and later cases in the current file. Whether other files continue depends on the sharing scope:
An ordinary afterEach step failure remains a case failure and can be retried after operations and registered cleanup finish. Run infrastructure errors, such as result publication failures, cancel the entire run.
See Create and clean up shared resources with setup for resource configuration, and Resource lifecycle and cleanup for cleanup inside Nodes.
Concurrency and isolation
Two limits apply together: maxConcurrentFiles limits files across the whole run, and maxConcurrentProjects limits projects whose preparation has started but whose cleanup has not finished. Each defaults to 1 independently. Set either to null to remove that limit; numeric values must be positive integers.
Execution is asynchronous within one Node.js process. Raising only the project limit does not raise file concurrency. Removing limits does not guarantee a faster run: browser capacity, devices, and model service quotas still matter.
File concurrency with maxConcurrentFiles
For example, with test: { maxConcurrentFiles: 3, maxConcurrentProjects: 2 } and Web and Android file limits of 2 each, two Web files and one Android file can run together, or one Web file and two Android files. The project count does not multiply the global file limit.
A file occupies a slot from preparation through completed cleanup, including device waits and case retries. Starting a new project claims both a project slot and its first file slot before setup; other files in that project wait for initialization without taking additional slots. Eligible projects take turns admitting files.
A project keeps its slot between files, even when none is currently running. Its last file retains a file slot through project cleanup; the project slot is released only when cleanup actually finishes. With maxConcurrentProjects: 1, the next project starts after the previous one is fully cleaned up. Setting only maxConcurrentFiles: 1 allows files from different projects to interleave if the project limit permits it.
After cancellation or bail, cleanup for initialized projects with no active files is also scheduled within the global file limit. See Timeouts and cancellation.
Existing configurations
test.maxConcurrency has been removed; loading an old configuration reports an error with a migration example. It controlled project concurrency, so simply renaming it to maxConcurrentFiles changes behavior. To preserve an old limit of 2, set test: { maxConcurrentProjects: 2, maxConcurrentFiles: 2 } and each project's maxConcurrentFiles to 1. Without explicit projects, keep the global file limit at 1.
fileSetup, project file limits, and preparation/cleanup timeouts can be configured without explicitly setting either global limit. When a project's effective file limit is 1, fileSetup is optional and its files can share the setup return value.
Cases are not automatically divided between projects. If two projects select the same YAML file, each runs it once. Use non-overlapping files or tags rules to split the work.
Legacy tasks/flow YAML still runs through midscene. Its concurrent / --concurrent, setup-file behavior, and browser reuse remain unchanged; those settings are handled separately from native Test's setup and fileSetup. See Migrate to Midscene Test.
Timeouts and cancellation
Timeout settings
Preparation and cleanup limits also apply when concurrency settings are omitted. After cancellation or bail, cleanup scopes share a shutdown deadline based on teardownTimeout.
Cancellation and cleanup
A step timeout aborts that step's signal. The CLI cancels the run on SIGINT (such as Ctrl+C) or SIGTERM. Nodes must pass signal to APIs that support cancellation or check its state; asynchronous operations do not stop automatically. See Asynchronous operations, errors, and cancellation.
After interruption, the framework still attempts cleanup. Nodes in afterEach and afterAll use a cleanup signal that has not been aborted. Step timeouts still apply, and cleanup cannot overlap an unfinished operation on the same Agent. Cleanup Nodes should handle partially completed preparation.
Callbacks registered with onTeardown() do not receive a new signal. Avoid reusing the original step's signal, which may already be aborted.
Timeouts bound the wait for results. If operations or cleanup remain unfinished, the framework records cleanup pending, keeps tracking resources, and releases them after operations actually finish. No new files start in this state. See Handling failures for the full rules.
Usage notes
- Configure what you need. Use only
fileSetupwhen there are no shared resources. With an effective file limit of1, omit it to share thesetupresult across files. - Concurrent files need isolation. An effective file limit above
1, including unlimited, requiresfileSetup, even if only one file is selected. Use separate pages, Agents, and devices; isolate backend accounts and data separately. - Retries do not repeat preparation.
setup,fileSetup, andbeforeAlldo not rerun. Reset state needed for each attempt inbeforeEach. - Register cleanup immediately. Call
onTeardown()after creating each resource. File cleanup precedes shared project cleanup; cleanup code must tolerate partial preparation.

