Declaring a project
{project.file} is the first file an adopting repository writes. It is found by walking up from
wherever a run starts, and every relative path in it resolves against its own directory — so a
case that names what it drives can be moved to another checkout unchanged.
Every key is optional, and that matters more than it sounds. A reading that needs a key this file does not declare is recorded as not taken, never quietly skipped, so an incomplete declaration is safe to start from and an unasked question never reads like an answered one. The last column below is what each omission actually does.
The keys
Section titled “The keys”| Key | Holds | What it declares | Left out |
|---|---|---|---|
executable | a path | the binary a launch starts, resolved against this file's own directory | asking for it refuses, naming the key and that it was launching the application under test; a run that attaches to a process already running never asks |
sourceRoot | a path | the source a staleness check compares the built binary against | the staleness reading is recorded as not taken, so a run cannot report on a build from last week and say nothing about it |
fingerprintStore | a path | the region of the machine a run must leave exactly as it found it — where the application keeps the settings and caches it owns | nothing is fingerprinted, so a run that drove a path writing a real setting finishes quietly |
captures | a path to a directory | where a picture a case asks for is written; the case's own name is the folder inside it, so two cases asking for 'the menu' do not answer each other | a capture step refuses at the door rather than after launching the application |
languageFiles | an array of paths | the strings this application ships, which is what lets a locator say {a.key} and an expectation derive a label instead of typing words a translation rewrites | there is no well to derive from, and every claim that reads one is refused where it is written rather than at run time |
loading | an array of keys | the keys of the strings shown while a page is still computing, so a page still saying it is loading is a failure rather than a photograph refuses a key none of the languageFiles carries — a check that silently matches nothing reports every page as finished forever | no page is held to having finished computing |
sourceIgnore | an array of directory names | what the staleness walk steps past, by simple name at any depth | the names DefaultSourceIgnore lists stand — build output and tooling state, which is the set that matters: with bin counted as source the binary is always newer than itself |
timeouts | an object of names to milliseconds | how long this project is willing to wait, by name, declared once rather than typed into the case that needed it refuses a value that is not a positive number | the names Timeouts.Defaults seeds stand, and a declared name nothing seeds is simply this project's own |
language | an object | how the run works out which language the application is actually in | the display language is the whole of the resolution |
attempts | a whole number | how many times a flaky act may be attempted — a fact about this project rather than about a case refuses a number outside Retry's own bounds, named against this file rather than thrown once per step about an argument out of range | Retry.DefaultCap stands |
destructive | an array of {"id"} or {"key"} entries | the entries that end the run, which no step may touch without saying it meant to refuses a bare name where the project ships more than one language, a name being exactly the field a translation rewrites | nothing is destructive, and no step has to say it meant it |
reportedSets | an object of names to argument arrays | the sets the application reports about itself, each with the arguments that make it print one per line — for a set that is this machine's data rather than a string the product ships refuses an entry with no name, or one with no arguments, since nothing would then say how the application is asked | 'covers' has only the language files to derive from |
reportedValues | an object of names to argument arrays | the single values the application reports about itself, for a fact about this machine that no case may type refuses an entry with no name, or one with no arguments | 'expectReported' has no well to ask |
language
Section titled “language”| Key | Holds | What it declares | Left out |
|---|---|---|---|
preferenceFile | a path | the JSON file this application saves the user's chosen language in | the display language is the whole of the resolution |
preferenceKey | a key, dotted for a nested one | where inside that file the chosen language sits | the preference file is not read |
fallback | a language tag | the language the application itself falls back to when it ships no strings for the one the machine is in | there is no fallback to make, and reading a label in a language nobody declared is refused rather than answered in English |
What you get without declaring anything
Section titled “What you get without declaring anything”Three keys have defaults rather than an absence, and they are read off the engine on every build rather than written here.
attempts is 3.
timeouts is seeded with these, in milliseconds. A declared name replaces the seeded one; a
name nothing seeds is simply this project’s own.
resolve— 5,000 msact— 2,000 mslaunch— 15,000 msstop— 5,000 mspoll— 25 ms
sourceIgnore is seeded with the directories a staleness walk must not read as source:
binobj.git.vs.ideanode_modulesTestResults.roadkeep
That last default is the one worth understanding rather than copying. With build output counted as source, the binary is always newer than itself, nothing is ever stale, and the staleness check quietly answers nothing — which is a green about a build from last week.
The two refusals worth reading before you meet them
Section titled “The two refusals worth reading before you meet them”An example to start from
Section titled “An example to start from”Every key above, so there is nothing to discover later:
{ "executable": "bin/Debug/net10.0-windows/YourApp.exe", "sourceRoot": "src/YourApp", "sourceIgnore": ["bin", "obj"], "fingerprintStore": "%APPDATA%/YourApp", "captures": "TestResults/captures", "languageFiles": ["strings.en.json", "strings.pt-BR.json"], "loading": ["report.computing", "common.pleaseWait"], "reportedSets": { "profiles": ["--print-profiles"] }, "reportedValues": { "activeProfile": ["--print-active-profile"] }, "language": { "preferenceFile": "settings.json", "preferenceKey": "ui.language", "fallback": "en" }, "timeouts": { "resolve": 5000, "stop": 5000 }, "attempts": 3, "destructive": [{ "id": "quitCommand" }, { "key": "menu.exit" }]}An environment variable is expanded, so an installed application can be named without a path that only exists on one machine.
Where to go next
Section titled “Where to go next”- Your first case — the file this declaration is for, and the four calls that run it.
- The case format — every field a case may carry, including the ones that read the wells declared here.
- The verbs — what each verb needs before it can answer.