Keeps a BDD step-definition library DRY across a Cucumber / Behave / Reqnroll project - inventories every step definition, detects duplicates (different patterns matching the same intent), recommends canonical consolidations, reorganizes steps by domain, publishes a step-library README the team greps for "is there already a step for X?" before authoring new ones, and builds a scenario coverage map that fingerprints new Gherkin scenarios against the live suite to classify each as duplicate, partial overlap, or genuine gap before any test is authored. Use when a BDD project's step count grows past ~50, on a quarterly step-library review, when a new engineer is about to write a duplicate step, or when fresh .feature files need a covered-already check.
73
92%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Low
Low-risk findings worth noting
Deep reference for bdd-step-library-curator (the "scenario coverage map"
section). Consult before authoring tests for freshly generated .feature
files: it classifies each new scenario as already-covered, partially
covered, or a genuine gap.
Cucumber's Gherkin reference makes the step text - not the keyword - the
stable identity unit: "Keywords are not taken into account when looking for
a step definition. This means you cannot have a Given, When, Then,
And or But step with the same text as another step."
(cucumber.io/docs/gherkin/reference) Fingerprint on the text.
This is a structural check on the step layer; it does not execute assertions or report pass/fail - never a substitute for running the suite.
Read each new .feature file (typically produced by
gherkin-from-stories). For each Scenario and Scenario Outline,
collect:
Given, When, Then, And, But) - keywords are cosmetic; the text
is what step definitions match (gherkin-ref).@tags declared on the scenario or inherited from the Feature
block (cucumber.io/docs/cucumber/api).Scenario Outline, note the parameter names from the Examples:
table as placeholder tokens (e.g., "<status>").Output: a new-scenario list of { id, title, tags[], steps[] } objects.
Glob all existing .feature files (excluding the new ones). Extract every
step text with the same keyword-strip rule; normalize whitespace and
lower-case. Build a step-usage index:
normalized_step_text -> [{ feature_file, scenario_title, line_number }].
If the project produces Cucumber's json report
(cucumber.io/docs/cucumber/reporting), prefer loading
the report over re-parsing - it contains every executed step with its text,
status, and parent scenario, guaranteed to reflect the last run:
# Cucumber-JS
npx cucumber-js --format json:reports/cucumber.json
# JVM (Maven)
mvn test -Dcucumber.plugin="json:target/cucumber.json"A scenario fingerprint is the ordered tuple of its normalized step texts.
| Status | Condition |
|---|---|
DUPLICATE | All steps already present in the index under one existing scenario |
PARTIAL | At least two steps overlap; one or more steps are new |
GAP | Zero steps match any entry in the index |
Tags on a new scenario may correspond to existing test runs (tag
expressions like @smoke and @fast / not @wip per
cucumber-api). A @smoke-tagged PARTIAL scenario may
already be executed in a @smoke run; flag it explicitly as
PARTIAL (tag match).
## Coverage map for `<story-id>` (<date>)
**New scenarios evaluated:** N
**Exact duplicates:** A (skip these)
**Partial overlaps:** B (extend step definitions only)
**Genuine gaps:** C (author full scenarios)
**Step-usage index built from:** M existing .feature files / JSON report
### Duplicates (do not author - already covered)
| New Scenario | Existing Scenario | File |
|---|---|---|
| "User logs in with valid credentials" | "User submits correct password" | `auth/login.feature:14` |
### Partial overlaps (author only the new steps)
**Scenario: "Admin resets user password"**
- Already covered steps (3): step text A, step text B, step text C
- New steps required (1): "the user receives a password-reset email"
- Recommendation: add one new step definition; reuse the 3 covered steps.
### Gaps (author full scenario)
- "Password reset rate-limits after 5 attempts" (0 of 4 steps covered)Halt and report the blocker (a BLOCKED message naming the condition and
remediation) instead of emitting a map when:
.feature files and no Cucumber JSON report exist - a map
against an empty suite is vacuous (everything is GAP)..feature files contain unparseable Gherkin (missing Feature:
keyword, unclosed Examples: table, illegal step keyword) - fix the
syntax first.| Anti-pattern | Why it fails | Fix |
|---|---|---|
| Stripping keywords but not normalizing whitespace | "Given the user is logged in" and "Given the user…" fingerprint differently; false GAPs | Collapse whitespace and trim before comparing |
Treating Scenario Outline rows as separate scenarios | Each Examples row shares the same step template | Fingerprint the template (placeholder tokens), not expanded rows |
| Ignoring the JSON report when one exists | Source files may include scenarios never run | Prefer the report; flag when only source parsing was possible |
Counting Background steps toward DUPLICATE | Background steps are shared context, not scenario identity | Exclude Background steps from fingerprint comparison |
New password-reset.feature has three scenarios. The index (built from
auth/login.feature + auth/session.feature) shows: scenario 1's 4 steps
all present at auth/login.feature:32 → DUPLICATE (do not author);
scenario 3 shares 2 of 5 steps with auth/session.feature:18 → PARTIAL
(author 3 new step definitions, reuse 2); scenario 2 matches nothing →
GAP (author in full).