Architecture
Testing architecture in SolidX, including the engine, adapters, registries, steps, and reporters.
Mental Model
Think about SolidX testing as a layered execution pipeline.
testingmetadata defines what should run.- The runner prepares the runtime, adapters, and registries.
- The engine executes normalized steps against the shared context.
- Adapters talk to HTTP services or the browser.
This separation is what lets SolidX support API and UI testing without duplicating the core orchestration model.
SolidX testing is implemented as a shared execution engine with pluggable adapters and step registries.
The architecture is designed so API and UI tests can use the same scenario format, interpolation rules, reporting flow, and runtime context.
High-Level Structure
The main testing implementation lives under solid-core-module/src/testing/.
src/testing/
├── contracts/ # Metadata and runtime context types
├── core/ # Engine, interpolation, resource store, registries
├── adapters/ # API adapter and Playwright UI adapter
├── steps/ # Built-in operations grouped by domain
├── reporter/ # Reporting types and console reporter
└── runner/ # Metadata execution and lifecycle helpersMain Building Blocks
Quick reference:
- Runner: Turns testing metadata into an executable test session.
- Engine: Executes normalized scenario steps against the shared runtime context.
- Step Registry: Maps operation names such as
api.requestorui.gototo their handlers. - Adapters: Bridge generic scenario steps to concrete tools such as HTTP execution and Playwright.
- Reporter: Consumes scenario and step lifecycle events and turns them into visible output.
- Resource Store: Persists values between steps through
saveAsand${res:...}interpolation.
Testing Metadata
Testing starts from module metadata under the testing key.
That metadata describes:
- Test fixtures.
- Scenarios.
- Optional testing roles and users.
- Optional custom test spec registrars.
This makes testing part of the application's metadata model rather than something external to it.
Runner
The runner turns metadata into an executable test session.
Its main responsibilities are:
- Build the step registry.
- Register built-in step families.
- Load and filter scenarios.
- Build the test data index.
- Create the runtime context.
- Initialize adapters.
- Invoke the engine for each scenario.
This orchestration is centered in runner/run-from-metadata.ts.
Code Entry Point
When tracing execution in code, start from runner/run-from-metadata.ts, then follow how the runner builds the registry, context, adapters, and engine.
Testing Engine
The TestingEngine is the shared executor.
The engine is responsible for:
- Receiving a scenario and a runtime context.
- Applying retries and scenario timeouts.
- Normalizing
given/when/then/andblocks into executable steps. - Interpolating step values before execution.
- Invoking the correct step handler.
- Storing results in the resource store when
saveAsis used. - Emitting lifecycle events to the reporter.
The engine is the common orchestration layer for every scenario type.
Step Registry
The step registry maps operation names such as:
api.requestui.gotoassert.httpStatusutil.sleeptest.spec
to their corresponding handlers.
Built-in registrations are grouped by domain:
- API steps.
- UI steps.
- Assert steps.
- Util steps.
- Test-spec steps.
Adapters
Adapters bridge generic scenario steps to concrete execution tools.
API Adapter
The API adapter uses Axios-style HTTP execution and powers operations such as:
api.requestapi.auth.bearerFromLogin
UI Adapter
The UI adapter is Playwright-based and powers operations such as:
- Navigation.
- Form filling.
- Clicks.
- Assertions on visibility, text, and URL.
This is how SolidX supports frontend E2E testing without embedding browser logic directly into the engine itself.
Reporter
Reporters consume lifecycle events such as:
- Scenario start.
- Step start.
- Step end.
- Scenario end.
The built-in reporter is a console reporter, but the architecture already supports additional reporters later.
Resource Store
The resource store is the shared runtime object used to persist values between steps.
For example, it can hold:
- An auth token returned by one step.
- A created record id.
- A custom test spec result.
- Any intermediate response referenced later.
Steps write to the store using saveAs, and later steps read those values through ${res:...} interpolation.
Shared Runtime Context
Every scenario executes with a runtime context that contains:
- Scenario id and scenario type.
- Resolved params.
- The shared resource store.
- API and UI adapters.
- The last API response.
- The reporter.
- The spec registry.
- Indexed test data.
- Runtime options such as API log printing.
This shared context is what allows API steps, UI steps, assertions, and custom specs to cooperate cleanly.
Scenario Types
SolidX currently supports these scenario types:
apiuimixed
mixed is especially useful when a workflow crosses both layers, for example:
- Authenticate through an API step.
- Create data through an API step.
- Verify the result through a UI step.
Built-In Step Families
Built-in steps are registered from these domains:
apiuiassertutiltest
This gives SolidX a good balance between standardization for common testing needs and extensibility when a project needs custom logic.
Custom Specs
When built-in steps are not enough, SolidX provides test.spec as an escape hatch.
Custom specs:
- Are registered through
testing.specs. - Are resolved through the spec registry.
- Receive the shared runtime context plus free-form input.
- Return structured results that can be saved and reused.
The venue module shows this pattern clearly:
testing.specspoints totesting/register-test-specs.js.- That registrar maps a stable id such as
venue.customHealth. - A scenario invokes
test.spec. - The spec receives
ctxandinput. - It can read previously saved resources from
ctx.resources.
That pattern is useful when built-in steps are almost enough, but a project still needs domain-specific verification logic.
UI Lifecycle
The runner starts the Playwright adapter only when a scenario requires UI execution.
That means:
- Pure API runs do not pay the browser startup cost.
- UI scenarios still run within the same framework.
- Browser lifecycle is handled centrally by the runner.
Mental Model
The cleanest way to reason about the architecture is:
- Metadata defines what to test.
- The runner prepares the runtime.
- The engine executes the scenario.
- Adapters talk to the outside world.
- The resource store carries state between steps.
- Reporters make the run visible.
Scenario Chaining
In real projects, a common execution pattern looks like this:
- One scenario saves a reusable bootstrap resource such as
loginSuccess. - Later scenarios assert that dependency with
util.require. - Those scenarios interpolate the saved result via
${res:...}. - Custom specs can read the same saved resource through the runtime context.
That is how SolidX supports lightweight scenario chaining without needing a separate dependency graph.
Next
Continue with Workflow.

