Steps and snippets
A manual case is a list of steps, and a project’s manual cases repeat the same steps a hundred times in slightly different words: Open the cart, open the Cart, Open the cart page. Two things on this page keep that vocabulary in one place, the way Testomat.io’s Steps Database and snippets do — the model taken as it is, the form Plune’s own.
The Steps Database
Section titled “The Steps Database”Every action of a manual case is a row of the project’s Steps Database, written when the case is
saved: each * line under ## Steps — each steps[].action on the API — becomes one row, one per
exact text (trimmed; inside, verbatim, so Open the cart with two spaces is another step). The row
counts the live cases carrying it: a deleted case drops out of the count and a restored one
comes back. A case that is not manual contributes nothing.
GET /v1/settings/stepsGET /v1/settings/steps?q=open{ "steps": [ { "id": "…", "step": "Open the cart", "description": "From the shop's header.", "count": 12 }, { "id": "…", "step": "open the Cart", "count": 1 }, { "id": "…", "step": "Pay by card", "count": 3 } ]}Ordered case-insensitively by text, so the duplicates sit next to each other; q narrows to
steps that start with it, case-insensitively — the way the case form’s suggestions ask.
Suggestions in the form
Section titled “Suggestions in the form”On the dashboard the action field of every step offers the Steps Database as you type — the browser’s own completion list, the step’s note as its label. Pick one and the case carries that exact text, which is what keeps the vocabulary from drifting; write a new one and it joins the database on save.
Rename — every case follows
Section titled “Rename — every case follows”PATCH /v1/settings/steps/{id}{ "step": "Open the cart page" }The action is rewritten in every live case that carries the step, in one transaction. Each of
those cases gets a new version — the step is its content, not its metadata — and its own audit
entry with the reason (step renamed: Open the cart → Open the cart page), so the change reads in
the case’s history like any edit. The answer is the surviving row and how many cases followed:
{ "step": { "id": "…", "step": "Open the cart page", "count": 12 }, "affected": 12 }When the new text already exists, the rename is a merge into that row: "merged": true, and
step.id is the survivor’s, not the one you patched. A description in the same body — or alone
— is the note under the step in Settings and the label of the suggestion; it touches no case, and
null removes it.
Merge — several into one
Section titled “Merge — several into one”POST /v1/settings/steps/merge{ "ids": ["…", "…"], "into": "Open the cart" }Every live case carrying any step in ids has that action rewritten to into — the same per-case
write as a rename, one audit entry per case. into need not exist yet: an existing row of that
text is the survivor and keeps its note; otherwise the first of ids is renamed in place. The other
rows go with their links. An unknown id is a 404 before anything is written.
A step by hand, and deleting
Section titled “A step by hand, and deleting”POST /v1/settings/steps with { "step": "Sign in as the shop owner.", "description": "…" } adds
a row no case carries yet (count: 0), so the suggestions offer it before anyone writes it; the
same text again is a 409 that carries the existing row.
Deleting is only for what nothing carries. DELETE /v1/settings/steps/{id} answers 204 for a
step with count: 0 and 409 — the step is used by cases — rename or merge it instead — for
one that cases carry: deleting it would mean rewriting those cases, which is what rename and merge
are for. DELETE /v1/settings/steps?unused=true sweeps every row with a count of 0 — steps made
by hand and never used, steps orphaned when a case was edited — and answers { "deleted": n }.
Without unused=true the request is refused.
On the dashboard all of this is Settings → Steps: the list with counts and notes, Rename and Merge into… on each row through the same Was → Becomes dialog as tags, with the number of cases the change rewrites; Note; Delete only on unused rows; + step; Delete unused in the header.
Snippets
Section titled “Snippets”A snippet is a titled piece of Markdown a case is written from — preconditions you repeat, a checklist of steps, a whole case to start from. It is inserted into a case as a copy: editing the snippet later changes no case, and deleting it leaves every case as it was. There is no bin for a snippet.
GET /v1/snippetsGET /v1/snippets/{id}POST /v1/snippets { "title": "Refund — checklist", "text": "## Steps\n* …", "template": true }PATCH /v1/snippets/{id} { "title"?, "text"?, "template"? }DELETE /v1/snippets/{id}The title is unique within the project (409 otherwise); the text is Markdown up to 16 KiB;
template marks the snippet as one a new case may start from. All three writes are in the audit
feed under the entity snippet.
In the form
Section titled “In the form”The case form has Insert snippet ▾ beside its Form / Markdown tabs:
- on the Markdown tab the text goes in at the caret, as text;
- on the Form tab the text is read by the same parser the Markdown tab uses: a
## Stepssection — or bare*/1.items with no heading — joins the case’s steps at the end, with their Expected: lines; anything else joins the description. A line under the header says which happened.
On a new case, when the project has snippets flagged as templates, Start from ▾ lists them: pick one and the form is filled from it the same way, once.
On the dashboard the snippets themselves are Settings → Snippets: the list with a template
badge and the first line of each, one form for adding and editing (title, Markdown text, the
template checkbox), and Delete with a confirmation that says the cases keep their copy.