Manual runs
A manual run is a run a person executes in the dashboard — the model Testomat.io’s manual test runs use, taken as it is: the run lists the cases it expects, each gets Passed · Failed · Skipped with a message and, for a case with steps, a mark per step; Finish run closes it. A mixed run is the same report with both halves in it: the manual cases are marked in the dashboard, the automated ones are reported by CI through the reporter, and the verdict counts both.
Nothing new was invented for it. A mark is a result — the same POST /v1/runs/{id}/results a
reporter sends — and a finish is the same finish event. What the feature adds is one right the
reporter does not have: a person who pressed the wrong button corrects the mark in place instead
of sending a second result that would count twice.
Starting one
Section titled “Starting one”Two roads, both ending on the run’s page:
- From a plan. A plan of kind
manualormixed— Test plans — launched with Launch run expects every case the plan collects at that moment. - Without a plan. On Runs, New run ▾ › Manual run…: all manual cases, or a selection made
with the same filter bar the cases screen has; Run automated cases as manual too widens it
the way a plan’s
asManualdoes; a title («Manual · date» by default) and an environment. The dialog counts what the run will expect as you narrow it, and will not start a run of nothing.
On the wire the second road is the start a reporter sends:
POST /v1/runs{ "schemaVersion": 2, "kind": "manual", "title": "Manual · 2026-09-17", "environment": "staging", "configuration": { "expected": [{ "testCaseId": "6f1c2b3a-0000-4000-8000-0000000000c1" }] }, "assignment": "prefer-assignee"}Who runs what
Section titled “Who runs what”Both dialogs end with an Assignment row — None or Prefer case assignee — and on the wire
that is assignment on POST /v1/runs and on POST /v1/plans/{id}/launch. With
prefer-assignee, the launch copies each expected case’s assignee
into the run:
"configuration": { "expected": [ … ], "assignees": { "6f1c…c1": "6f1c…a2" } }A copy, on purpose: the run holds who was to run what at launch, and a case that changes hands
afterwards does not rewrite a run already under way. Cases nobody held are absent from the map; a
launch with the strategy and nobody assigned anywhere records an empty map — the strategy was used,
there was nobody to copy. none (the default) stores the configuration as it was sent, which for a
reporter’s run is without the map at all.
On the run page the copy is what you see: the person on each «To run» row, prefer case assignee in
the head, and a Mine · n / All · n toggle above the list — «Mine» keeps the rows assigned to the
signed-in person, and the «x of n done» count follows the toggle. The toggle is there only when the
launch made a copy; without one every row would be nobody’s and it would have nothing to say.
GET /v1/runs/{id}/summary carries the same map as run.assignees, null when there is none.
Marking a case
Section titled “Marking a case”While the run is launched, its page has a To run section: every expected case that has no
result yet, in the order the run expected it, as a row —
- the case’s steps (a manual case with steps): a toggle per step that turns with each click — passed → failed → skipped → not marked — as Testomat.io has it;
- a Message, one line that grows;
- Passed · Failed · Skipped — the button is the request. There is no separate Save: a mark with nothing else said is the common case.
POST /v1/runs/{id}/results{ "results": [ { "resultKey": "manual:6f1c2b3a-0000-4000-8000-0000000000c1", "testCaseId": "6f1c2b3a-0000-4000-8000-0000000000c1", "source": "manual", "status": "failed", "errorContext": "Step 3: the coupon field accepted an expired code.", "steps": [ { "index": 0, "status": "passed" }, { "index": 1, "status": "passed" }, { "index": 2, "status": "failed" } ] } ]}| field | |
|---|---|
resultKey | manual:<testCaseId> — unique within the run, so the run holds one mark per case. A second identical mark is a duplicate; a different one is a conflict that names the result already holding the key, and the dashboard patches that one instead. |
source | manual — what tells the platform a person wrote this. A reporter names its runner here. |
status | The three a person gives: passed, failed, skipped. (broken and blocked are the reporter’s.) |
errorContext | The message. Redacted and truncated like a reporter’s error text. |
steps | Up to 200 { index, status } — the step’s position in the case’s steps, from 0, and passed, failed or skipped. Steps left unmarked are absent. |
Accepted, the row collapses: the badge, the step marks as glyphs (✓ ✕ ○), the message, and Change. The counter in the section’s head — «3 of 12 done» — and the run’s own counts come from the platform after each mark, not from the page’s guess.
Correcting a mark
Section titled “Correcting a mark”Change opens the same editor with the mark as it stands, and the new verdict goes in place:
PATCH /v1/results/{id}{ "status": "passed", "errorContext": null, "steps": [{ "index": 0, "status": "passed" }] }Any of status, errorContext (null clears it) and steps (null clears them), at least one.
The result keeps its id and its place in the run; outcome is recomputed from the new status; the
change is audited under the run with the status and the message before and after.
Finishing
Section titled “Finishing”Finish run sends POST /v1/runs/{id}/events with { "event": "finish" }. With cases still
to run, the dashboard asks first and says how many will stand as not run — «3 of 12 done →
finished · 9 cases not run». Once closed, the To run section is gone, the head is the verdict
of the counts, and the page names what never arrived: «9 expected cases produced no result» —
the run’s notRun, which a reporter’s crashed shard leaves behind in exactly the same way.
Mixed runs
Section titled “Mixed runs”A mixed run — from a plan of that kind — has both halves on one page. The manual cases are in
To run; the automated ones wait below under Waiting for a reporter, with the run’s
external key: a reporter that joins the run by that key (plune run start --key …, or the
Playwright reporter’s own) reports them, and its results take those cases out of both lists. The
counts, the verdict and notRun are one set of numbers over both sources, and Finish closes
the run for both — a reporter that reports afterwards is refused as it is today.
Not in this version
Section titled “Not in this version”A random distribution of cases among members (only «prefer case assignee» exists), run groups,
several environments per run, custom statuses, file
attachments (the contract has attachments; the dashboard does not upload yet), adding tests or
plans to a run already started, and the case page’s history — which counts an eval result’s
assertions and does not yet show a manual mark’s status or steps.