Adding a step or a resource¶
This page is for people changing tomato itself. For writing a suite with tomato, start at Getting started.
Two rules shape everything below. Steps, config fields, CLI flags and Action
inputs are a stable surface: never rename or remove one in place. And
step wording is the product — users read it from tomato steps, and
tomato docs generates the reference from the same definitions, so the
wording you write is the documentation.
Adding a step to a resource¶
- Add a
StepDefto the resource'sSteps()ininternal/resource/<name>/, withGroup,Pattern(use{resource}where the resource name goes),Description,ExampleandHandler. -
Use it in a scenario in
tests/features/<resource>.feature. CI fails when any step of any resource type is unused — check locally with: -
Regenerate the reference and commit the result:
The Example is not decoration. It appears in the generated page, and
TestDocsExamplesUseRealSteps checks every Gherkin snippet in docs/ against
the live patterns, so an example that does not parse as a real step fails CI.
Adding a resource type¶
-
The handler. Create
internal/resource/<name>/<name>.gowithimplementing
resource.Handler:Name,Init,Ready,Reset,RegisterSteps,Cleanup. The package importsinternal/resourceand nothing from another resource —TestResourcesDoNotImportEachOtherenforces that. If two resources need the same helper, it belongs ininternal/resourceorinternal/jsonmatch. -
Reset.
Resetruns before every scenario and has to leave the resource genuinely clean, including state that survives the obvious command — Postgres truncates withRESTART IDENTITYbecause plainTRUNCATEleaves sequences advanced, which made scenarios order-dependent. Exclude only what the application needs to exist, such as migration tables. -
Steps. Implement
Steps() resource.StepCategoryand callresource.RegisterStepsToGodog(ctx, r.name, r.Steps())fromRegisterSteps. -
Register it once, in
internal/registry/registry.go: add it tohandlerFactoriesand tocanonicalTypes. The first makes it buildable bytomato runand accepted bytomato validate; the second gives it a documentation page and a place intomato steps. Two tests pin the lists against each other, so missing one fails CI. Add it toContainerBasedTypes()if it normally points at a container. -
Documentation. Add a page under
docs/configuration/for its options, and add it and the generateddocs/resources/page to thenavinmkdocs.yml. The step reference generates itself. -
Tests. Unit tests in the resource's own package, a container in
tests/tomato.yml, andtests/features/<name>.featureexercising every step. -
Changelog. A line under
## [Unreleased].
Agree the config shape and the step wording in an issue before writing the code. Both are a stable surface from the moment they ship.
Changing or removing a step or an option¶
Add the replacement, then mark the old one:
{
Pattern: `^"{resource}" old wording$`,
Deprecated: "use the new wording instead",
Handler: r.handler,
}
A deprecated step keeps working and warns once per run, and the generated reference labels it. Note the replacement under Deprecated in the changelog. See Stability for how long it has to stay.
Before opening the pull request¶
make coveragepasses. It is what CI runs: unit and integration coverage merged, every resource step used by a scenario, and the floors in.coverage-min. When coverage rises, raise the floors in the same PR../tomato docshas been run and the result committed.- If the change touches timing or the infrastructure the suite runs on — a broker, a database image, startup order, a reset, anything concurrent — run the affected features several times. One green run proves very little about a race.
See also¶
- Architecture — what is in the repository, and which parts CI checks
- Stability — what counts as a breaking change
- CONTRIBUTING.md — setup, commits and review