| name | open-testing-convert-testersai-dynamic |
| description | Convert Testers.AI Dynamic natural-language tests (JSON with `test_steps[]` plus an optional `hints[]` array of probabilistic selector/value guidance, and a `{tests:[...]}` envelope) to and from Selenium, Playwright, Cypress, Appium, Cucumber, Eggplant (SenseTalk), OpenTest.AI, and Testers.AI Recorder. Dynamic is the AI-runtime sibling of OpenTest.AI — same step grammar but with per-step hints that the AI can accept or override at execution. Use whenever the user wants to migrate a Dynamic suite, convert dynamic AI-runtime tests into code, or round-trip through another framework. MANDATORY TRIGGERS — "convert Dynamic", "Testers.AI Dynamic to <target>", "AI-runtime tests to code", "migrate dynamic tests", "convert dynamic with hints", "dynamic.json to Playwright", "Testers.AI Dynamic to Selenium", any mention of Testers.AI Dynamic alongside any supported target. |
| license | MIT |
| metadata | {"family":"open-testing-convert","source":"testersai-dynamic","orchestrator":"open-testing-convert","targets":["selenium","playwright","cypress","appium","cucumber","eggplant","opentestai","testersai-recorder"]} |
Convert — Testers.AI Dynamic
Converts Testers.AI Dynamic tests to any supported target, and builds Dynamic-format output from any source. Defers orchestration, cross-framework rules, and target semantics to the open-testing-convert master skill.
When to use
Trigger when:
- The user references a Testers.AI Dynamic test,
dynamic.json, the Dynamic product, or an AI-runtime test with hints.
- The user uploads JSON matching:
{ "tests": [ { "test_case_id": "...", "test_steps": [...], "hints": [...] } ] } — canonical Dynamic envelope.
- The same shape without
hints (still Dynamic, just no selector guidance was supplied).
- A single bare Dynamic test-case object (wrap during normalisation).
hints[] entries shape: { step_index: N, locator: {...}, value?: ..., reason?: "..." }.
- The user asks to reverse-engineer automation from AI-runtime step definitions.
How to use
- Read the master orchestrator first. Open
../open-testing-convert/SKILL.md.
- Normalise the wrapper. Dynamic almost always uses
{ "tests": [...] }; handle bare single-test input by wrapping. The wrapper key differs from OpenTest.AI (test_cases vs tests) — be precise on forward/reverse.
- Read the Dynamic target primer.
../open-testing-convert/reference/targets/testersai-dynamic.md documents the envelope and the semantics of hints[].
- Read the relevant target primer for where you're going:
../open-testing-convert/reference/targets/opentestai.md
../open-testing-convert/reference/targets/testersai-recorder.md
../open-testing-convert/reference/targets/eggplant.md
- For code targets, consult the per-source profile for the target's canonical shape.
- Read this skill's reference files:
reference/source-profile.md — the Dynamic schema, hint semantics, relationship to OpenTest.AI and Recorder.
reference/extraction.md — how to parse steps and merge hints into canonical intent.
reference/mappings.md — per-target cookbook.
- Read shared references as needed:
open-testing-convert/reference/shared/{locator-mapping,wait-strategies,assertion-mapping,lifecycle-mapping}.md.
- Emit per target Emission Checklist. Preamble must note: tests converted, hints coverage (percentage of steps with hints), hint types used (label/role+name/testId/css/xpath), and — critically — the AI-runtime semantic note: "Dynamic hints are guidance, not authoritative. Converted code uses them as chosen locators unless overridden."
Dynamic vs OpenTest.AI vs Recorder — positioning
| Property | OpenTest.AI | Dynamic | Recorder |
|---|
| Envelope key | test_cases | tests | tests |
| Step array | test_steps | test_steps | test_steps + recordedActions |
| Selector authority | None | Hints (probabilistic) | Hints (deterministic, from capture) |
| Runtime model | AI interprets | AI + hints (prefer hints, override if needed) | Replay captured selectors |
| 1:1 invariant | N/A | N/A | Yes (test_steps[i] === recordedActions[i].naturalStep) |
| Typical origin | Hand-authored | Hand-authored with AI authoring assist | Browser-captured |
Dynamic sits between OpenTest.AI (zero selector info) and Recorder (full selector info). The hints layer is opportunistic — a Dynamic test with empty hints[] is indistinguishable from OpenTest.AI except for the envelope key.
Hints semantics — how AI runtime uses them
Each hint suggests one or more locator candidates for a specific step index. The AI runtime:
- Interprets the NL step to understand intent.
- Cross-references the hint's locator shape as a starting point.
- If the hint resolves to a unique element with the right semantics, uses it.
- Otherwise, ignores the hint and falls back to AI element-inference from the page state.
- Records which hints were used vs overridden in a run log.
For conversion to code targets:
- Use the hint's chosen locator directly when a concrete locator can be derived. Prefer the most specific hint field.
- If the hint is ambiguous or lacks DOM specificity (only
reason text, no locator), fall back to the OpenTest.AI-style pattern-matching on the NL step.
- Never preserve the "AI may override" semantics in code targets — they require deterministic locators. Flag in preamble.
Scope
{ "tests": [...] } envelope (canonical).
- Single bare Dynamic test (wrap).
hints[] with any of these locator shapes: {testId, label, role+name, text, placeholder, css, xpath, altText, title, accessibilityId}.
- Steps in any language (inherits OpenTest.AI i18n rules).
- Platform fields:
web, ios, android, desktop.
data.expected_test_input_parameters, data.expected_results, overall_description, validation_conditions, tags, priority, owner.
Out of scope
- OpenTest.AI (sibling, no hints) — use
open-testing-convert-opentestai.
- Testers.AI Recorder (sibling, 1:1 invariant + deterministic selectors) — use
open-testing-convert-testersai-recorder.
- AI-agent test runners from other vendors (Mabl, Testim, Functionize) — these have their own envelopes; detect and route elsewhere.
Quick reference: step + hint → canonical
test_step NL | hints[] entry | Canonical |
|---|
Click the '<label>' button. | {step_index: N, locator: {role: "button", name: "x"}} | {kind: "click", locator: {strategy: "role_name", value: "button", name: "x"}, source: "hint"} |
Click the '<label>' button. | {step_index: N, locator: {testId: "y"}} | {kind: "click", locator: {strategy: "testid", value: "y"}, source: "hint"} |
Click the 'Sign in' button. | (no hint at index N) | {kind: "click", locator: {strategy: "role_name", value: "button", name: "Sign in"}, source: "pattern"} |
Enter '<v>' into the '<l>' field. | {step_index: N, locator: {label: "l"}, value: "<v>"} | {kind: "input", locator, value, source: "hint"} |
source: "hint" vs source: "pattern" is preserved on canonical steps so reverse conversions know whether to emit a hint entry.
See reference/mappings.md for the full per-target cookbook.