ScreenshotNeo

BlogHow-to

How to Use Data Tables in Cucumber with Ruby

Pass Gherkin tables to Ruby step definitions, choose a useful table shape, and convert rows safely with version-aware examples.

By the ScreenshotNeo team4 October 20266 min read

Direct answer: Put a Gherkin data table directly below the step that uses it. Cucumber passes that table to the matching Ruby step-definition block as its final argument. The block might look like Given('the following products:') do |table| ... end. The exact methods for turning that table into arrays or hashes depend on the Cucumber Ruby version in your project, so check the versioned Ruby API before relying on a conversion method.

This guide shows how to structure tables, receive them in Ruby, keep scenarios readable, and investigate conversion problems without assuming that JVM-specific APIs work in Ruby.

1. Add a data table beneath the Gherkin step

A data table is part of a step in a feature file. The text in the step is matched against a registered step definition; the table is passed separately as a multiline argument.

Feature: Register products

  Scenario: Add several products
    Given the following products:
      | name   | price |
      | mug    | 12.50 |
      | bottle | 18.00 |

The first row here contains column headings. Each following row represents one product. Keep the table directly under its step and indent it as part of the scenario.

2. Receive the table in a Ruby step definition

Register a block whose expression matches the step text. Its final block parameter receives the table. This example intentionally leaves table conversion unspecified: check the API for the Cucumber Ruby version pinned in your project before choosing a conversion method.

Given('the following products:') do |table|
  # `table` is the multiline data-table argument for this step.
  # Inspect or convert it using the API supported by your
  # project's pinned Cucumber Ruby version.
end

Step definitions are commonly kept under features/step_definitions, with project support code under features/support. Cucumber Ruby uses block-style Given, When, and Then definitions. If you use regular expressions, captured groups become ordinary block arguments; the data table remains the trailing multiline argument. See the official Cucumber Ruby README and step-definition reference.

3. Choose a table shape that matches the data

Table shape Use it for Design note
One column A list of values Use when each item has the same meaning and no headings are needed.
Header plus rows A list of records Headings make each row’s fields clear in the scenario.
Two columns for key and value A compact mapping Use when each row is one setting or named value.

Choose headings that a reviewer can understand without reading the step implementation. Keep scenario data focused on behavior: a table with many incidental fields can make a feature hard to maintain.

Whether the step should receive raw cell strings, arrays, hashes, scalar values, or domain objects is a separate decision. Cucumber documentation describes table conversion concepts, but the conversion examples surfaced in its general reference are mainly for JVM implementations. Do not copy Java List or Map signatures into Ruby. Confirm Ruby methods against your installed version’s documentation or implementation. See the Cucumber API reference and configuration reference.

4. Set up and run a Ruby Cucumber project

Use the project’s existing dependency setup and lockfile so the Cucumber version is explicit. The Cucumber Ruby README documents the gem and the usual feature and step-definition layout. In a project where Cucumber is already installed through Bundler, run:

bundle exec cucumber

For a new project, follow the installation instructions in the official Cucumber Ruby README, then keep the selected gem version pinned in the project’s dependency lockfile. This matters because table conversion calls can vary by version.

5. Convert table data carefully

First decide what the step needs, then use a conversion supported by the installed Ruby API:

  1. Identify whether the table is a list, a set of headed records, or key/value data.
  2. Decide whether the step needs strings or typed application values.
  3. Check the Cucumber Ruby API corresponding to the locked gem version for a suitable conversion method.
  4. Keep parsing or domain-object construction explicit when it affects what the scenario means.
  5. Run the scenario through the project’s normal Cucumber command and inspect the failing row if conversion or validation fails.

For example, a price cell such as 12.50 is table text until your step or application code parses it. Decide deliberately whether the domain uses a decimal type, integer minor units, or another representation. Avoid relying on implicit conversions or treating a string as a number.

6. Keep step matching and table arguments distinct

The step expression matches the words before the table. The table itself is not part of those words. If an expression has capture groups, those captures are normal arguments; the table is still the trailing multiline argument supplied for the step. Keep the number and order of block parameters consistent with the expression and the table-bearing step. The official step-definition guide explains matching and captured arguments.

Prefer a step phrase that describes the action or context rather than encoding every table value into the phrase. Tables are useful when multiple values share the same operation; separate steps can be clearer when each value represents a materially different behavior.

7. Common errors and fixes

Symptom Likely cause What to check
The step is undefined The step text does not match any registered definition, or the definition file was not loaded. Compare the feature step text with the expression, check the step-definition directory, and run Cucumber through the project’s Bundler environment.
The block has an argument-count error The block parameters do not account for the step’s captured arguments and trailing table. Check expression capture groups and the table-bearing step’s final argument.
A Java collection method or signature fails in Ruby A JVM example was applied to Cucumber Ruby. Use the Ruby API documented for the gem version in the lockfile.
A row value has the wrong type Cells are being treated as typed values without deliberate parsing. Validate and convert each required field using the application’s intended type and error handling.
Headings are being treated as data The chosen table interpretation does not match the table shape or conversion method. Confirm how the version-specific Ruby conversion handles the first row; use a shape appropriate to records, lists, or mappings.
Changes in Cucumber break conversion The project upgraded across an API or behavior change, or relies on an unpinned dependency. Pin the dependency, consult documentation matching the installed version, and update conversion code deliberately.

8. Reliability, performance, and maintenance

Data tables primarily affect how scenario inputs are expressed; the table itself does not make the application operation faster. Keep the data set as small as needed to explain the behavior. If a scenario is slow, investigate the application work performed by the step and its test setup rather than assuming the table syntax is the cause.

For reliable scenarios, make parsing and validation failures clear, avoid hidden assumptions about cell types, and keep the Cucumber Ruby version locked. Prefer table headings when they reduce ambiguity, and avoid turning one scenario into a large test-data fixture that is difficult to review.

Or skip the browser setup

If your Ruby workflow also needs website screenshots for documentation or test artifacts, ScreenshotNeo can return an image or PDF from one API request. See the ScreenshotNeo API documentation.

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
import requests

r = requests.get(
    "https://api.screenshotneo.com/v1/shot",
    params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"},
    timeout=90,
)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
  • Cookie banners, popups, and chat widgets are removed before the shot.
  • Bot checks, blank pages, and failed loads are never billed.
  • An MCP server lets AI agents use screenshot tools.
  • 1,000 screenshots a month are free with no card; paid plans start at $5 for 3,000.

Sign up for 1,000 free screenshots a month, with no card required.

FAQ

Can a data table be used with Given, When, or Then?

Yes. A table can accompany the step that consumes it; the step’s meaning determines which keyword is clearest.

Does the table have to contain a header row?

No single shape fits every case. Use headings when they clarify records, and verify how the Ruby conversion you selected interprets the first row.

Where should I check a table conversion method?

Use the API documentation or implementation matching the Cucumber Ruby version pinned by your project. General Cucumber examples may show JVM-specific APIs.