Skip to content

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.

FieldHoldsWhat it is for
casesrequiredCasesthe cases the file holds, as an array
fixturesFixtureswhat to launch them against, as an array
FieldHoldsWhat it is for
namerequiredTextwhat the case is called, and what a run of it is reported under
stepsrequiredStepsits steps, in the order they are performed
tagsWordswhat selects it besides its name, as an array of words
needsWordswhat this machine has to have before it can observe anything, as an array of names
catchesTextthe defect it exists to catch — what went wrong without it
filedTextthe task it was filed under
fixtureTextwhich of this file's 'fixtures' to launch it against
forEachTextthe key whose every declared string this case runs once for — derived from the project's own strings, with the member reaching a locator through '{}'
onlyReadsTruththat 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.

Every step says what to do and what to do it to, and at most one thing it claims about the result.

  • act is required. What it needs written beside it is the verb’s own business: with is required exactly where the act takes something and refused where it does not.
  • Exactly one of locator and tray. 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. reads is not a claim: it says which reading the claim is about.
FieldHoldsWhat it is for
locatorone of the subjectTextwhat to act on, in the locator grammar
trayone of the subjectTextthe 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
actrequiredTextwhat 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
withTextwhat the act needs said, where it needs anything
expectclaimTextwhat the reading should be once the act has landed
readsTextwhich reading the expectation is about
One of: anything, value, range, toggle, selected, picked, expanded, text, name, description, enabled, focused
movesclaimTruththat the reading should end up different, where the case cannot know what it will be
answersclaimTruththat the reading it names should say something rather than nothing, where the case cannot know what
matchesclaimTextthe regular expression the reading should match, where the case cannot name the value but can name its shape
disclosesclaimTruththat the act put something under the locator that was not in the tree before it
sameAsclaimTextthe '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
unlikeclaimTextthe '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
sameCountdownAsclaimTextthe 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
containsclaimTextthe '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
labelclaimTextthe key whose declared string the reading should be — the label itself, derived from the project's own strings and never typed here
expectReportedclaimTextthe 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
notLabelclaimTextthe key whose declared string the reading should not be, for the state an application has a word for and must not be showing
beginsWithLabelclaimTextthe 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
endsWithLabelclaimTextthe 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
notEndsWithLabelclaimTextthe 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
absentclaimTruththat 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
ownHeaderclaimTruththat 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
eachSpokenclaimTruththat 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
spokenclaimTruththat everything under the locator which announces anything announces a name — never a glyph, a template or an id handed back — and that something does
neverclaimTextthe 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
coversclaimTextthe 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
coversAtLeastclaimTextthe 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
coversWithinclaimTextthe 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
meansItTruththat this step means a destructive entry it names
popupTextthe 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
namedTextwhat a report should call it, where the act and the locator will not do

A fixture says what the application is launched with. Any case in the suite may name one declared in any file.

FieldHoldsWhat it is for
namerequiredTextwhat to call it, and what a case names to be launched against it
environmentTextthe sampled environment it is — the one field both the launch and the expectations read
flagTextthe argument the environment reaches the application through, without its value
argumentsWordseverything else the launch carries, as an array
variablesPairsthe environment variables it sets, as an object
shareableTruththat this window may be lent to a case that only reads it
languageTextthe language tag the window it launches is in, so a derived set reads the strings that window is actually showing
residentTruththat 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.

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.

HoldsWhat a value may be
TextText.
TruthTrue or false.
WordsAn array of text.
PairsAn object whose every value is text.
CasesAn array of cases.
StepsAn array of steps.
FixturesAn array of fixtures.

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.

  • The verbs — everything act accepts, and what each one needs of the desk before it can answer.
  • Addressing an element — the grammar every locator field 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 act accepts, what each needs of the desk, and the reasoning behind each refusal.