Making and extending tests
Every project can be driven through the OpenEditor canvas: click things, check states,
capture the outcome of each step, and replay the whole flow against a live frame.
Tests live in a single oe-tests.json at your project root.
How a test runs
- Open the project's Tests view in the editor.
- Pick an environment and run the test live (browser / simulator) or replay from prior canvas captures.
- Each step reports pass / fail, its duration, and (when asked) a screenshot.
- Results and screenshots stream into the canvas next to the live app frame.
oe-tests.json
{
"project": "fullstack-init",
"simulator": "iPhone 16 Pro",
"defaultEnvironmentId": "local",
"environments": [
{ "id": "local", "label": "Local", "baseUrl": "http://localhost:9111", "kind": "local" },
{ "id": "preview", "label": "Preview", "baseUrl": "https://preview.example.com", "kind": "preview" },
{ "id": "production", "label": "Production", "baseUrl": "https://example.com", "kind": "production" }
],
"flows": [
{ "id": "checkout", "name": "Checkout", "description": "Core purchase flow" }
],
"tests": [
{
"name": "Add to cart and checkout",
"flow": "Checkout",
"flowId": "checkout",
"type": "web",
"environmentId": "local",
"description": "Verifies the primary purchase path.",
"steps": [
{ "action": "navigate", "url": "http://localhost:9111/", "wait": 1200 },
{ "action": "clickSelector", "selector": "[data-testid='add-to-cart']", "wait": 600 },
{ "action": "assertText", "selector": "[data-testid='cart-count']", "text": "1" },
{ "action": "screenshot", "name": "Cart with one item" },
{ "action": "clickSelector", "selector": "button[aria-label='Checkout']" },
{ "action": "assertPath", "expectedPath": "/checkout" }
]
}
]
} Step actions
Web tests drive a live browser; iOS tests drive a simulator. The runtime is inferred from the
test type (or project type), but you can force it with "type": "web" | "ios" | "shopify".
| Action | Runtime | What it does | Fields |
|---|---|---|---|
navigate | web | Load a URL for the selected environment. | url | path, wait |
clickSelector | web | Click the first element matching a selector. | selector, wait |
typeText | web | Type text into the first matching field. | selector, text, wait |
assertText | web | Pass if the text is present (optionally scoped to a selector). | text, selector? |
assertPath | web | Pass if the app is on the expected path. | expectedPath | url |
screenshot | web · ios | Capture the current screen as a step outcome. | name |
wait | web · ios | Pause for a duration. | wait |
deepLink | web · ios | Open a deep link / route in the app. | url | path |
tapXY | ios | Tap a normalized x/y coordinate in the simulator. | x, y |
tapLabel | ios | Tap a control by its accessibility label. | label |
scenario | ios | Launch a deterministic app fixture scenario. | scenario, environment |
Selectors
Selectors resolve in priority order. Prefer data-testid when you control the markup —
it is stable across redesigns and localization.
[data-testid="add-to-cart"]
[data-component="ProductCard"]
#main-submit
button[aria-label="Checkout"]
input[name="email"] Environments
A test can run against any declared environment. Steps that use path resolve against the
selected environment's baseUrl, so the same test runs locally, on a preview, or in production.
- local — a running dev server on your machine.
- preview — a branch / staging deployment.
- production — the live app.
- cloud — a hosted OpenEditor runtime.
Extending tests
- Group into flows — give related tests the same
flowIdso they run and render together as a product flow. - Override environments per test — set
environmentIdon a test to pin it to a specific target. - Record instead of hand-writing — the in-app recorder turns clicks and typing into steps and writes robust selectors automatically.
- Capture outcomes — add a
screenshotstep wherever you need visual evidence; each step already records pass/fail, duration, and logs. - Replay — the canvas stores per-step captures so you can replay a flow from snapshots without booting a simulator or browser.