Skip to content

Features and the glossary

Voice's behaviour is written as Gherkin features under features/, one file per stage of the loop, and each file runs as a suite against the whole service. The words a step may use are the glossary's, GLOSSARY.md at the root of the repository, and a checker holds the two together with the specifications that name scenarios.

The checker

just check
0 findings in 59 scenarios and 1 spec

It reads every feature, the glossary and the specifications, and reports:

Finding Means
undefined-term a step uses a word that is neither a glossary term nor an everyday word
refused-synonym a step uses a word a glossary entry says to avoid, such as "user" for participant
contradiction two scenarios share preconditions and an action and state different outcomes
repeated-scenario, duplicated-scenario the same scenario twice, or a scenario's steps copied into a specification
unknown-scenario, untraced-requirement a specification names a scenario that does not exist, or a requirement no scenario shows
parse Gherkin that does not parse

A continuous-integration job runs it on every push, so a feature that drifts from the glossary fails the build before it fails a reader.

Adding a word

A step that needs a word the glossary lacks adds the word to GLOSSARY.md, in its section, with one sense and the near-synonyms it refuses. A word whose sense is not yet settled is marked Proposed until the scenarios that use it pass against the service. The everyday words at the end of the glossary are the ones any step may use without a definition; a word that carries meaning in Voice belongs in a section, not there.

Writing a scenario

  • A scenario describes the domain, never the interface: no screen, button, route or status code. "the reviewer approves the derivative", not "the reviewer clicks Approve".
  • A scenario that asserts a text is not public uses a text of its own, because the suites share one service and another scenario may have published the same words.
  • A scenario that asserts on an aggregate uses enough synthetic participants to clear the suppression threshold, or asserts on the suppression.
  • A scenario that needs a model reply needs a recorded fixture under modules/service/src/test/resources/model/, matched on the message's text; a step that sends a message with no fixture fails naming the request.

The step definitions

Each feature file has a steps object in modules/service/src/test/scala/voice/features/, and the suite binds the steps to the service through its three endpoints, with helpers that take a role and a route: a reviewer's helper adds the /staff prefix, so a step names the route beneath it. A step with more than six placeholders needs the suite's own step-body instance.