4. Use Case Document Format
Permalink to 4. Use Case Document FormatThis section is normative.
4.1 File extension and encoding
Permalink to 4.1 File extension and encodingUse case documents MUST be encoded as UTF-8 YAML 1.2 ([YAML]). The RECOMMENDED
file extension is .uc.yaml. Processors that operate on directories SHOULD
discover use case documents by globbing for **/*.uc.yaml.
4.2 Top-level fields
Permalink to 4.2 Top-level fieldsEach document is a single YAML mapping with the following keys.
| Key | Type | Required | Description |
|---|---|---|---|
id |
non-empty string | yes | Unique identifier within a project. |
title |
non-empty string | yes | Human-readable title. |
type |
enum: positive, negative |
yes | Intent of the case. Has no effect on resolution; see below. |
description |
string | no | Free-form description. |
extends |
string (id of another use case) | no | Inherits from the referenced case. See §7.3. |
preconditions |
array of strings | no (defaults to []) |
Human-readable preconditions; carried into reports. |
start_location |
string (URL) | yes for non-extension cases | URL navigated to before step 1. |
expected_result |
string | yes for non-extension cases | Statement of the expected outcome; carried into reports. |
data |
mapping | no (defaults to {}) |
Template variables. Values MAY be nested objects. |
scope |
object | no | Iteration scope. See §5.8. |
steps |
array of step entries | yes for non-extension cases without steps_override |
Ordered list. See §5. |
steps_override |
object | no | Used in extension cases. See §7.3. |
before |
array of step entries | no | Setup steps run before steps. See §4.6. |
A single document defines exactly one use case. A directory MAY contain any number of documents.
A non-extension case in the table above is a document with no extends
field. The conditional requirements key on the presence of extends, not on
type: Appendix C.2 is type: negative and inherits its start_location from
its parent. type records what the case is for — a happy path or an error
path — and does not change how the document is resolved. A document with
extends MAY omit all three conditional fields and inherit them
(§7.3).
A document without extends that omits one of them is not a conforming
document, and a processor MUST reject it. Accepting it produces a case that
resolves to an empty start_location and zero steps and then scores pass,
because nothing in it failed — "pass" meaning nothing was evaluated.
A processor MUST also reject a top-level field this specification does not
define, rather than ignoring it. A misspelled steps_overide: is otherwise
dropped in silence, and the document reads as an extension case while running as
its parent.
4.3 The steps_override object
Permalink to 4.3 The steps_override objectUsed in extension cases to replace parent steps from a given point onward.
| Key | Type | Required | Description |
|---|---|---|---|
from_anchor |
string | one of these two | Name of an anchor: step in the parent to splice at. Preferred. |
from_step |
positive integer | one of these two | 1-based index in the parent's resolved step list. |
condition |
string | no | Why the extension branches here. Carried into reports. |
steps |
array of step entries | yes | Replacement steps. Either spelling of §4.5. |
Exactly one of from_anchor and from_step MUST be supplied; both, or neither,
is a parse error.
from_anchor is preferred because from_step couples a child to a position in
someone else's file. Inserting one step into a parent re-targets every child
that extends it, and nothing errors: the override still applies cleanly, just at
the wrong point, and the extension tests something nobody wrote. A label
survives edits to the surrounding flow.
An unresolvable from_anchor MUST be an error naming the anchors the parent
does define. The from_step value MUST NOT exceed parent.steps.length + 1.
Anchors do not occupy a step index (§5.6.20), so a parent MAY be
annotated with anchors before any of its children are converted, without
re-targeting the ones still using from_step.
4.4 The data block
Permalink to 4.4 The data blockdata is a mapping of names to values. Values MAY be nested mappings, in which
case dot notation is used to address them from steps (see
§7.4). Values MAY be strings, numbers, booleans,
or null; arrays are permitted but addressing into them is not defined.
4.5 Step entries
Permalink to 4.5 Step entriesA step entry is a YAML mapping with exactly one key. The key is the step keyword. The value is a string conforming to the grammar for that keyword in §5.
steps:
- locate: button "Sign Up"
- activate: button "Sign Up"
- verify: url "/welcome"
A value that YAML resolves to a number rather than a string — wait: 2000
unquoted — is accepted: the processor converts it to its decimal string form and
parses it as if it had been quoted.
A step entry with zero keys, more than one key, or a key that is not a recognized keyword MUST cause the document to be rejected.
A bare string keyword: rest is the second spelling of the same entry, and a
processor MUST accept it wherever it accepts the mapping form. It is normalised
to the mapping form before parsing — split at the first colon, the keyword
trimmed, one matching pair of surrounding quotes stripped from the rest, as YAML
would have done for a mapping value — so the two spellings cannot parse
differently. All three step lists — steps, before
(§4.6) and steps_override.steps
(§4.3) — accept both. The string form is useful
where the mapping form's YAML quoting gets in the way, as it does for a
keyboard: 'Escape' override; the mapping form is the one this document uses in
its examples.
4.6 The before block
Permalink to 4.6 The before blockbefore is an OPTIONAL array of steps that run after navigation to
start_location and before the first entry in steps. Entries use the step
language of §5 in either spelling of
§4.5, as steps_override.steps entries do.
The block performs setup the case depends on but is not itself asserting — a
log-in, dismissing a consent gate, seeding application state. It complements
preconditions, which records such requirements as prose for the report:
preconditions states what must be true, before makes it so.
A processor MUST observe the following:
- Entries run in document order, and the block halts at the first failing
step; entries after it are recorded with status
skiprather than executed. The halt is unconditional:continue_on_failure(§12.1) does not apply to the block, whatever it is set to. Gathering further diagnostics from a case whose setup did not complete has no value, because nothing after it can be trusted. - If any entry fails, the main
stepsMUST NOT run and the use case scoreserrorrather thanfail(§11) — the case never reached the behaviour it exists to judge. - Results of the block are kept separate from the main step results and MUST NOT be merged into them, so a report cannot present setup work as though it were the behaviour under test.
- Template variables are interpolated as in
steps(§7.4). - Extension cases inherit the block, or replace it by declaring their own. See §7.3.
The block is part of the document like any other, so §8.3 applies to it: both execution modes MUST reach the same outcome for a document that declares one.
Codegen has no equivalent of the error score — a generated test either passes
or fails. A processor generating code for a document that declares a before
block MUST therefore emit the block's entries ahead of the steps under test,
such that the first failing entry fails the generated test and the steps under
test do not run. That is the closest faithful mapping of rules 1 and 2 above. A
processor SHOULD keep the emitted entries distinguishable from the steps under
test, so a reader of the generated test's output can tell a setup failure from a
failure of the behaviour under test; the reference implementation groups them in
a Playwright test.step named Setup (before).
Emitting the block MUST NOT renumber the steps under test (§10.4).