vitrinka.docs

Test runs and the QA record

A feature's QA plan as journeys you can walk, and your test runner's results folded into it — verdicts, screenshots and a bug draft per failing case — without vitrinka ever running your tests.

The QA plan

A feature's test plan is a qa task under its epic, and each user path under it is a journey task. A journey's flow is a list of steps. Each step has a kind — act, verify or wait — and says what to do; optionally where (at), what proves it (see), a locator, and next. next points at another journey, or at one of its steps (<journey-key>#<step>): that is how a flow branches or loops back. The checklist a tester ticks is derived from the flow, so nobody keeps two lists.

The server draws the plan as one living diagram, top-down: a lane per role, the journeys of a role side by side, each journey's steps left to right, and only the edges next and blocks links make. Past a size cap, journeys collapse back to single nodes so a large plan still renders.

  • Edit it in place — click a step node and the journey opens with that step focused in the flow editor (kind · do · at · see · next). Agents change the same thing with edit_journey_node, or update {kind: "task"} on the journey's fields.
  • The plan is its board — a qa task's panel shows its board read-only, fitted to the plan; vitrinka task qa-board <id> creates or returns that board, a Plan section plus one section per journey.
  • Every plan in one place — the project's Record › QA lists every plan with its verdict, its coverage (journeys passed over journeys), its journey count and whether an agent is walking it right now, above the sessions, runs and bug reports that fed it.

Vitrinka reads, your runner runs

Teams keep Playwright, Appium, Selenium, Cypress, Maestro or their own harness untouched. Vitrinka reads what a run leaves behind and never starts a browser or drives a device; a runner integration is a file format, not a plugin, and nothing in your suite has to change to use it.

One command

vitrinka qa run -- bun x playwright test
vitrinka qa run --task 412 --pr acme/shop#42 -- bun x wdio run wdio.conf.ts

vitrinka qa run -- <test command> runs your command verbatim, with a few variables any reporter may honour: VITRINKA_RUN_ID, VITRINKA_RUN_DIR, VITRINKA_RUN_STARTED_AT and VITRINKA_SHOTS=always. When it exits, the CLI finds what the run left behind — the repository's declared runners first (vitrinka setup --runners writes them into vitrinka.config.json), else the newest results written since the start — folds them into one run manifest and publishes it. The test command's exit code is the CLI's exit code: a failed publish never hides a failing test, and the other way round.

The run lands on --task (a qa task, a journey, a story or an epic), else on the feature of the checkout's vt-<id> branch, else on the project's rolling Unplanned runs epic. --results <path> skips the search; --dry-run runs and folds, prints the manifest and publishes nothing.

What it folds

FormatWhat vitrinka reads
JUnit XMLThe JUnit reporter of Playwright, Jest, wdio, Go and most others — alone it covers Selenium, Cypress, Maestro, Detox, TestCafe and a home-grown harness. Screenshots ride as [[ATTACHMENT|…]] lines or as files written under VITRINKA_RUN_DIR.
Playwright JSONThe JSON reporter's file, with its attachments.
allureAn allure-results directory.
wdioThe @wdio/json-reporter files.
Run manifestA v1 manifest a runner, or vitrinka qa usertest, already wrote.

The run manifest

Whatever the format, a run becomes one v1 manifest. A runner can also write it itself and publish it with vitrinka qa run publish <manifest.json>:

{ "version": 1, "runId": "20260909-093000-ab12", "runner": "playwright", "app": "web",
  "branch": "vt-410-checkout", "sha": "7a3da39", "pr": "acme/shop#42",
  "specs": [ { "key": "checkout", "file": "e2e/checkout.spec.ts", "title": "Checkout",
    "cases": [ { "title": "pays with a saved card", "verdict": "fail", "ms": 4210,
                 "shots": ["shots/checkout-1.png"], "error": "Expected total 42.00" } ] } ] }

A case's verdict is pass, fail or skip. Shot paths are relative to the manifest's directory, and a manifest holds at most 200 specs and 500 cases per spec; a case carries any number of shots.

What lands on the record

One door, POST /api/v1/tasks/{id}/run (MCP publish_run), turns the manifest into the feature's QA record — no publisher agent, no hand-written comments.

  • The plan exists by construction — without a qa task, one is created under the feature's epic with a journey per spec. Journeys match by key, then by title; new ones are appended.
  • Verdicts fold per journey — every case passed is pass, any failure is fail, passes with skips are partial, all skipped or no cases is untested. The plan's coverage rolls up from its journeys.
  • Evidence on the qa board — each journey's section carries a run callout, the cases as a checklist and a media card per screenshot. Publishing the same run again replaces its cards; a new run appends beneath.
  • Refs where they belong — the run on the qa task and the epic, the board section and the shots on each journey, the log on the qa task, the pull request on the epic.
  • A bug per failing case — --bugs intake (the default) files a bug draft through intake that blocks its journey; direct files a live bug under the journey's story or epic; none files nothing.

Exploratory testing as a run

Testing by hand produces the same record. A person, or an agent running /vitrinka:usertest (capture skills), opens a session, opens a case per thing tried, snaps screens into it and closes it with a verdict; finish folds the session into a manifest — one journey per case — and publishes it through the same door.

vitrinka qa usertest start --task 412 --platform web
vitrinka qa usertest case "Pays with a saved card"
vitrinka board capture web --file cart.png --viewport 1440x900 --route /cart --note "Coupon applied"
vitrinka qa usertest verdict fail --note "Total ignores the coupon"
vitrinka qa usertest finish

Every vitrinka board capture between case and verdict attaches to the open case, and a failing case's note becomes the first line of its bug draft.

On this page