Skip to content

A Markdown document back — create, update, report

POST
/v1/test-cases/markdown
curl --request POST \
--url https://beta-api.plune.ai/v1/test-cases/markdown \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: text/markdown' \
--data '<!-- test
id: 6f1c2b3a-0000-4000-8000-0000000000c1
type: automated
priority: high
state: draft
spec: e2e/catalog/search.spec.ts:9
-->
## search by sku, the exact match first @smoke @catalog
The exact match sits first; near matches follow.
<!-- test
type: manual
priority: normal
-->
## empty cart says so @cart
## Steps
* Open the cart with nothing in it
*Expected*: «Your cart is empty» and no checkout button
'

The same document, edited anywhere, read back (D9). Each <!-- test --> block is matched by its id: known — the case is updated (title, texts, priority, body, and its suite when the document has suite blocks); absent — a new draft in the suite of the block it sits under, last; unknown — refused by line. Nothing is deleted: a case or suite the document does not name is not touched. A case’s type never changes this way, and state: is only read back as a warning — states move through their own action. A document with no suite block moves nothing, so a single case pasted back keeps its suite. Suite blocks are matched by id, else by their path — missing segments are created (folders, then the suite), each with a warning. Each write is its own transaction, as in bulk: what was done before a refusal stays done, and the report says which was which. ?dryRun=true gives the same report and writes nothing — plune push shows it before writing.

Format. Testomat’s Classical Tests Markdown Format, verbatim, plus Plune’s columns: <!-- suite --> / <!-- test --> blocks with key: value metadata, the title as the first #/## heading after the block (its @tags are the tags), ## Steps with *Expected*: under each step, <!-- example --> tables. Cases before the first suite block are in no suite; a nested suite is its path in the title, # apps > web > checkout.spec.ts. Plune’s columns: id is the record’s UUID, type may be eval, state is written for the eye and only read back as a warning, spec carries an automated case’s specRef; ## Preconditions, ## Expected result, ## Prompt and ## Assertions (a JSON array) are the body. The full reference: https://docs.plune.ai/platform/cases/markdown/.

dryRun
boolean

Report only; nothing is written, not even the folders of a new path.

Media type text/markdown
string
Example
<!-- test
id: 6f1c2b3a-0000-4000-8000-0000000000c1
type: automated
priority: high
state: draft
spec: e2e/catalog/search.spec.ts:9
-->
## search by sku, the exact match first @smoke @catalog
The exact match sits first; near matches follow.
<!-- test
type: manual
priority: normal
-->
## empty cart says so @cart
## Steps
* Open the cart with nothing in it
*Expected*: «Your cart is empty» and no checkout button

The report — always, when the body is a document; refusals are inside it.

Media type application/json

What a Markdown push did, block by block (D9). Always 200 when the body is a document: refused names each block that could not become a case, with the line it starts on and the reason; warnings are the lines the reader skipped over (a Testomat id, a labels: key, an examples table). With dryRun the same report, nothing written.

object
dryRun
required
boolean
created
required
Array<object>
object
id

Absent on a dry run for a case that would be created.

string format: uuid
title
required
string
line
required

1-based line of the <!-- test that opens the block.

integer
updated
required
Array<object>
object
id

Absent on a dry run for a case that would be created.

string format: uuid
title
required
string
line
required

1-based line of the <!-- test that opens the block.

integer
unchanged
required
Array<object>
object
id

Absent on a dry run for a case that would be created.

string format: uuid
title
required
string
line
required

1-based line of the <!-- test that opens the block.

integer
refused
required
Array<object>
object
title
required
string
line
required
integer
error
required
string
suites
required
object
created
required
Array<object>
object
id
string format: uuid
path
required
string
line
required
integer
updated
required
Array<object>
object
id
required
string format: uuid
path
required
string
line
required
integer
warnings
required
Array<object>
object
line
required
integer
message
required
string
Example
{
"dryRun": false,
"created": [
{
"id": "6f1c2b3a-0000-4000-8000-0000000000c2",
"title": "empty cart says so @cart",
"line": 12
}
],
"updated": [
{
"id": "6f1c2b3a-0000-4000-8000-0000000000c1",
"title": "search by sku, the exact match first @smoke @catalog",
"line": 1
}
],
"unchanged": [],
"refused": [],
"suites": {
"created": [],
"updated": []
},
"warnings": []
}

An empty body

Media type application/json
object
error
required
string
Example generated
{
"error": "example"
}

No / invalid token or session

Over 10 MB

Media type application/json
object
error
required
string
Example generated
{
"error": "example"
}

A body that is not text/markdown (or text/plain)

Media type application/json
object
error
required
string
Example generated
{
"error": "example"
}

Rate-limited: either the per-route throttle or a tenant quota. Retry-After carries the seconds until the window rolls over.

Media type application/json
object
error
required
string
Example generated
{
"error": "example"
}
Retry-After
integer

Seconds until the window rolls over