The case format
A case is a data file. Any file ending .cases.json, anywhere under the directory a run
points at, read recursively in path order.
This page is the whole format, and it is not a summary of it. The tables are generated from
ScenarioSchema on every build — the same declaration the loader enforces and the same one
winwright_format serves to an agent — so a field renamed in the engine is renamed here, and a
field the engine does not have cannot appear.
A scenario file
Section titled “A scenario file”| Field | Holds | What it is for |
|---|---|---|
casesrequired | Cases | the cases the file holds, as an array |
fixtures | Fixtures | what to launch them against, as an array |
A case
Section titled “A case”| Field | Holds | What it is for |
|---|---|---|
namerequired | Text | what the case is called, and what a run of it is reported under |
stepsrequired | Steps | its steps, in the order they are performed |
tags | Words | what selects it besides its name, as an array of words |
needs | Words | what this machine has to have before it can observe anything, as an array of names |
catches | Text | the defect it exists to catch — what went wrong without it |
filed | Text | the task it was filed under |
fixture | Text | which of this file's 'fixtures' to launch it against |
forEach | Text | the key whose every declared string this case runs once for — derived from the project's own strings, with the member reaching a locator through '{}' |
onlyReads | Truth | that it leaves the window as it found it, so a window may be lent to it |
name has to be unique across the whole suite, not just its file: a name declared twice is
refused, naming both files, before anything runs.
catches is optional and worth writing anyway. It is what the case exists to catch, and a run
counts the cases that passed without saying — a check nobody can justify is one nobody dares
delete and nobody dares change.
A step
Section titled “A step”Every step says what to do and what to do it to, and at most one thing it claims about the result.
actis required. What it needs written beside it is the verb’s own business:withis required exactly where the act takes something and refused where it does not.- Exactly one of
locatorandtray. A tray icon is named by the shell rather than located in a window’s tree, so it is a second kind of subject. Naming both addresses two things and is refused; naming neither is refused too. - At most one claim. The fields marked claim below are alternatives — a step makes one of
them, or none and simply acts.
readsis not a claim: it says which reading the claim is about.
| Field | Holds | What it is for |
|---|---|---|
locatorone of the subject | Text | what to act on, in the locator grammar |
trayone of the subject | Text | the notification-area icon to act on, by the name the shell gives it — a tooltip, matched on its first line, for the surface no locator reaches |
actrequired | Text | what to do to it One of: read, invoke, toggle, set value, set range, select, expand, collapse, type, click, nudge, press, pick, pick at, open submenu, open tray menu, click tray icon, capture |
with | Text | what the act needs said, where it needs anything |
expectclaim | Text | what the reading should be once the act has landed |
reads | Text | which reading the expectation is about One of: anything, value, range, toggle, selected, picked, expanded, text, name, description, enabled, focused |
movesclaim | Truth | that the reading should end up different, where the case cannot know what it will be |
answersclaim | Truth | that the reading it names should say something rather than nothing, where the case cannot know what |
matchesclaim | Text | the regular expression the reading should match, where the case cannot name the value but can name its shape |
disclosesclaim | Truth | that the act put something under the locator that was not in the tree before it |
sameAsclaim | Text | the 'named' of an earlier step in this case whose reading this one claims to be back to, for the round trip whose value no case can name |
unlikeclaim | Text | the 'named' of an earlier step in this case whose reading this one claims to differ from, for the change whose value no case can name at either end |
sameCountdownAsclaim | Text | the same claim as 'sameAs' for a reading that counts down while the case runs — the numbers in it must match, except the last, which may have ticked by one |
containsclaim | Text | the 'named' of an earlier step in this case whose reading this one claims to hold inside its own — for the dialog that quotes the thing it opened for, where neither string is one a case can type |
labelclaim | Text | the key whose declared string the reading should be — the label itself, derived from the project's own strings and never typed here |
expectReportedclaim | Text | the name whose value the application reports and the reading should be — declared in the project's reportedValues, for a fact about this machine that no case may type |
notLabelclaim | Text | the key whose declared string the reading should not be, for the state an application has a word for and must not be showing |
beginsWithLabelclaim | Text | the key whose declared string the reading should begin with, for a state announced as a word in front of a sentence — a prefix and never a containment, because the sentence behind may hold the word too |
endsWithLabelclaim | Text | the key whose declared string the reading should end with, for a state an application appends rather than announces in front — the same precision as the prefix and for the same reason, since the name before it is free text that can hold the word |
notEndsWithLabelclaim | Text | the key whose declared string the reading must NOT end with, for a state an application appends and must not be showing — the mirror of 'endsWithLabel', because a mark that can only be claimed present is one a window drawing it always would pass |
absentclaim | Truth | that this step's locator matches nothing — the claim an application makes by what its window does NOT hold, refused where the region the last step is looked for under is not there either |
ownHeaderclaim | Truth | that no control inside a row this locator matches announces a different row's header — the pairing a check for whether a name exists is blind to |
eachSpokenclaim | Truth | that every element this step's locator matches announces a name — a sweep over elements, where 'covers' is a sweep over the strings a key declares |
spokenclaim | Truth | that everything under the locator which announces anything announces a name — never a glyph, a template or an id handed back — and that something does |
neverclaim | Text | the key whose string must not be showing anywhere in the window at any moment while this step waits for its locator — a key and never the text, like the project's own loading strings |
coversclaim | Text | the key whose every string must be read somewhere the locator matches, and nothing else — derived from the project's own strings and never listed here |
coversAtLeastclaim | Text | the same set, claiming only that every declared string is read here and allowing values that are not in it — for a container the locator cannot separate from its neighbours |
coversWithinclaim | Text | the same set, claiming each declared string appears inside the name of something read rather than equalling it — for an entry that decorates what it is about |
meansIt | Truth | that this step means a destructive entry it names |
popup | Text | the popup inside this step's window whose tree the picture is of, by the name the application's own author gave it — for a capture, and the one surface no copy of the screen can ever take |
named | Text | what a report should call it, where the act and the locator will not do |
A fixture
Section titled “A fixture”A fixture says what the application is launched with. Any case in the suite may name one declared in any file.
| Field | Holds | What it is for |
|---|---|---|
namerequired | Text | what to call it, and what a case names to be launched against it |
environment | Text | the sampled environment it is — the one field both the launch and the expectations read |
flag | Text | the argument the environment reaches the application through, without its value |
arguments | Words | everything else the launch carries, as an array |
variables | Pairs | the environment variables it sets, as an object |
shareable | Truth | that this window may be lent to a case that only reads it |
language | Text | the language tag the window it launches is in, so a derived set reads the strings that window is actually showing |
resident | Truth | that this launch draws no window of its own — a tray — so the run holds it as a process and its locators resolve against the desktop |
environment is the machine setting the launch samples and flag is the argument it reaches
the application through; language says which language the resulting window is in, so
derived expectations read the strings that window is actually showing. A fixture naming an
environment nothing carries to the launch is refused, and so is one that names it twice — two
places deciding one thing means whichever the application reads last wins while the
expectations still describe the other.
What a value may be
Section titled “What a value may be”The Holds column above is one of these. It is data rather than prose because the loader
asks it before it reads a field, so the kind published here is the kind the run enforces: a
schema saying tags is text where the loader reads an array is a tool that accepts what the
run refuses.
| Holds | What a value may be |
|---|---|
| Text | Text. |
| Truth | True or false. |
| Words | An array of text. |
| Pairs | An object whose every value is text. |
| Cases | An array of cases. |
| Steps | An array of steps. |
| Fixtures | An array of fixtures. |
A key nobody recognises is refused
Section titled “A key nobody recognises is refused”Every level of the format is closed. "expects" beside "expect" is a check the author wrote
and the run never made, and a loader that shrugged at it would hand that green back — so an
unrecognised key is refused, listing the keys there are.
That is the same list as the tables above, because there is only one. It is also why
winwright_check cannot be sent a misspelled key at all: the tool’s input schema is this
schema, so the refusal arrives before the file exists rather than on the first run.
Where to go next
Section titled “Where to go next”- The verbs — everything
actaccepts, and what each one needs of the desk before it can answer. - Addressing an element — the grammar every
locatorfield is written in. - Your first case — the same fields as a file you can copy, and the four calls that run it.
- The README — every verb
actaccepts, what each needs of the desk, and the reasoning behind each refusal.