cucumber data table step definition mismatch: how to fix
Shows how to fix cucumber steps that take a data table: match the step definition pattern to the feature text exactly and declare the table as the last parameter in cucumber-js or cucumber-ruby. Use for undefined-step errors on table steps, tables arriving as undefined, or arity mismatches. Not for DocString steps or pattern-only mismatches with no table involved.
TL;DR
Make the step definition's pattern match the feature file's step text exactly, and declare the DataTable as the last parameter of the step function. Most mismatches are a plural, article, or quoting difference between the .feature line and the pattern, or the table argument missing from the function signature.
Problem
A scenario step passes a data table, but the run reports the step as undefined, or the step function receives the wrong arguments (the table arrives as undefined, or an arity error is raised).
Steps
- Copy the step text from the
.featurefile character for character and compare it with the step definition pattern. Fix plurals, articles, and punctuation first; they are the usual culprits.
Expected: the pattern and the step text agree on every word.
- In cucumber-js, declare the table as the final argument:
const { Given } = require('@cucumber/cucumber');
Given('the following users exist:', function (dataTable) {
const rows = dataTable.hashes();
// rows is an array like [{ name: 'ann', role: 'admin' }]
}); Expected: dataTable.hashes() returns the rows instead of throwing.
- In cucumber-ruby, use a block whose last parameter receives the table:
Given('the following users exist:') do |table|
table.hashes.each do |row|
create_user(name: row['name'], role: row['role'])
end
end Expected: table.hashes yields one hash per row.
- Re-run with
--dry-runto confirm every step is now defined, then run for real.
Expected: no undefined steps; the scenario executes.
When to use
- "Undefined step" on a step that clearly has a definition.
- DataTable arrives as undefined in the step function.
- Arity errors after adding a table to an existing step.
When not to use
- DocString (triple-quoted text) steps: those pass a string, not a table; different handling.
- Steps with no table where only the pattern mismatches: fix the pattern, the table advice does not apply.
- Mixing cucumber expressions and regexes: pick one style per project.
Tool compatibility
- cucumber-js 9.x through 11.x (
@cucumber/cucumber);dataTable.hashes()is stable API. - cucumber-ruby 8.x through 9.x; the block-last-parameter table convention is unchanged.
Variant phrasings
cucumber step definition not matching data table step
Check for a trailing colon difference: the feature step Given the following users exist: needs the colon in the pattern too.
dataTable is undefined in cucumber-js step
The function signature is missing the final parameter; add dataTable last, after any capture-group params.
Why it happens
Cucumber binds steps by matching the full step text against the definition pattern, then passes capture groups plus the table or DocString positionally. A one-word mismatch means no binding; a missing final parameter means the table has nowhere to land.
Edge cases
- Tables under Scenario Outline steps: the table binds to the step while Examples fill the placeholders; both can coexist.
- Empty tables (header row only):
hashes()returns an empty array; guard the loop if setup must run at least once. - Trailing whitespace in the feature file step text is invisible but breaks matching; enable visible-whitespace in your editor.
Provenance
Resolved from the public thread: https://vectle.com/posts/pstqNFG3lLFm9jXbNFIDtUpg
Maintainer review
No maintainer verification is recorded for this version.
This records the version a maintainer checked. It does not assert that the version is the latest upstream release.