Skip to main content
Wildo.ai Coming soon

Testing harnesses

Dependency-free end-to-end spine

The pieces every test lane needs, from running a scenario to surviving a backend restart, live in one package with no third-party dependencies, so packages that must stay isolated can still share them.

What it is
Tool — something you run.
What it does
One scenario engine drives every end-to-end lane: a step triggers a real capability, observes the outcome on one or more channels, optionally extracts a value later steps read, and asserts what the application's own store says.
Where it stops
It cannot contain anything that needs a dependency, and that boundary is enforced by the fact that it has none.

The engine

End-to-end scenarios

A running stack

Customer double

Client integration double

Vendor simulators

Drawn for Testing harnesses, the area this capability belongs to.

@wildo-ai/testing-core holds the parts every test lane needs and none of the parts any one lane is about: the scenario engine, the surface and adapter contracts, the isolation assertion, backend-flap resilience, the log observer and the managed child process. It declares no runtime dependency at all, and it is exported as TypeScript source rather than as a build, which is what lets a package with its own lockfile consume it without inheriting anything.

The problem it solves

Test doubles have to be independent to be worth anything. A double that impersonates a customer’s identity provider is only evidence if it speaks the protocol on its own terms rather than borrowing the types of the thing it is testing, and a double that shares a lockfile with the engine cannot demonstrate that it resolved a signature the way an outsider would.

Independence usually costs duplication. Each isolated package ends up with its own copy of the scenario loop, its own retry, its own idea of what an assertion is, and the copies drift until the same failure reads differently in two lanes. This package is the way out: the parts that are genuinely common carry no dependencies, so importing them costs an isolated package none of its isolation.

What it does

One scenario engine drives every end-to-end lane: a step triggers a real capability, observes the outcome on one or more channels, optionally extracts a value later steps read, and asserts what the application’s own store says.

Cross-scope isolation is not a separate mechanism. It is a flag on an assertion, asserting that the active scope recorded the expected traffic AND every other scope stayed silent. That detects misrouting from record counts alone, with no payload parsing — which is why it works identically over an identity provider, a webhook receiver and a security-event sink.

The whole engine is generic, so a surface brings its own kinds rather than the engine knowing about any of them. That is what makes one loop drive an HTTP API, a browser, a message queue, a backend log and an external double.

One seam injects the application. An application supplies provisioning, capability configuration, a trigger, a store read and its addresses; the subprocess form turns that into a cross-process contract — so the adapter runs in the application’s own workspace with the application’s own module resolution, while the scenario stays application-agnostic.

The resilience module exists because a development stack restarts under recompile churn. Rather than widening timeouts, every application-facing call gates on the health endpoint and retries within a readiness ceiling — and a transport failure is described AS one, so a caller can tell an absent backend from a wrong answer.

Limits

It cannot contain anything that needs a dependency, and that boundary is enforced by the fact that it has none. The browser-backed surface therefore lives in its own package, and every concrete surface implementation lives with its lane.

It defines the surface contract and the isolation assertion; it does not know what a Wildo resource, role or organisation is. Everything domain-shaped is on the far side of the adapter.

The log observer parses one record per line, so a stack running its logs in human-readable mode yields nothing parseable to it — which is why the fatal gate in the harness reads raw lines instead of reusing this parser.

Building a B2B product or an internal tool?

Wildo is not self-service yet. Tell us what you have in mind and we will say plainly whether it fits, and what happens next.