Skip to content

Step actual results

While executing a test run, a member records an actual result for each step. It is rich text: send it as Markdown in actualResult, or as a document in actualResultDocument (see Rich text fields). The text holds at most 20000 characters. Screenshots and other images go inline in the text: stage each one with POST /api/v1/images:stage and reference it as ![alt](attachment:<ULID>).

Files that are not images in the text, such as logs, traces and videos, are result attachments. A result file can name a step with stepIndex.

Writes need the attachments.execute permission, which members, admins and owners hold. Viewers receive 403 forbidden. Reads are always allowed. Writes follow the run state rules in Test-run settings: an open run accepts them, a closed run accepts them when allowResultsInClosedRuns resolves to true (the code default), and an aborted run always rejects them with 409.

PATCH/api/v1/runs/{runUlid}/cases/{runCaseUlid}/steps/{stepUlid}/result
{
"actualResult": "Saw HTTP 500 instead of the dashboard:\n\n![Error page](attachment:01J...IMG)"
}

Send actualResult (Markdown) or actualResultDocument (the document), never both. null clears the result. Omitting both leaves the stored result unchanged.

Errors:

  • 422 validation_failed — both forms are sent, or the text breaks a rich-text rule (see Rich text fields). An image that was never staged, or has expired, answers details.code unknown_image.
  • 403 forbidden — viewer role.
  • 409 — the run state rules above.
  • 413 storage_quota_exceeded — the images would take the organization past its storage quota. Nothing is changed.

Audit: emits run.case_step_actual_result_set with the plain-text change of actual_result.

GET /api/v1/runs/{runUlid}/cases/{runCaseUlid} returns each step’s actualResult (Markdown) and actualResultDocument. Both are null when the step has no result.

Stage an image with POST /api/v1/images:stage before the save that references it. Removing an image from the text and saving deletes it, unless another text or a stored revision still references it. Images in a result count toward the organization storage quota under content_image. A save that adds no image is never refused for storage.

  • POST /api/v1/runs/{runUlid}/cases/{runCaseUlid}/retry — resets the case (and its frozen step snapshots) to untested and recomputes the run aggregate. Emits run.case_retried.
  • DELETE /api/v1/runs/{runUlid}/cases/{runCaseUlid} — removes the case with its steps and recomputes the run aggregate. Emits run.case_removed.

Both follow the closed-run rule above.