Cucumber Data Tables can be used to add multiple parameters in Step Definition in a tabular form rather than putting all the parameters in the Gherkin statement. This is much easier to read and multiple rows of data can be passed in the same step. Data tables from Gherkin can be accessed by using the DataTable object as the last parameter in a Step Definition. This conversion can be done either by Cucumber or manually.
Pre-Requisite
- Cucumber – 6.10.4
- Java – 11
- Selenium – 3.141.59
- Junit – 4.13.2 ( You can use TestNG also)
- Cucumber JUnit – 6.10.4 (If using TestNG, then replace this with Cucumber TestNG)
Project Structure

Depending on the table shape, we can use one of the following collections:
List<List<String>> table
List<Map<String, String>> table
Map<String, String> table
Map<String, List<String>> table
Map<String, Map<String, String>> table
Let’s write a simple data table and see how we might use it.
1. Table into List of a List of Strings
| firstName | lastName | age |
| Thomas | Brown | 30 |
| Perry | Wilson | 26 |
| Ashley | William | 27 |
java type: List<List<String>>
The natural representation of list of a list of strings is shown below.
[
[ "firstName", "lastName", "age" ],
[ "Thomas", "Brown", "30" ],
[ "Perry", "Wilson", "26" ],
[ "Ashley", "William", "27" ]
]
2. Table into List of Maps
java type: List<Map<String, String>>
The natural representation of list of maps is shown below.
[
{ "firstName": "Thomas", "lastName": "Brown", "age": "30" },
{ "firstName": "Perry", "lastName": "Wilson", "age": "26" },
{ "firstName": "Ashley", "lastName": "William", "age": "27" }
]
3. Table into Single Map
Table where first colum is key as shown below
| IN | India |
| IRE | Ireland |
java type: Map<String, String>
TO convert the table into a single map
{
"IN": "India",
"IRE": "Ireland"
}
4. Table into map that uses a list as its value
A table with multiple column values per key.
| IN | India | 29 |
| IRE | Ireland | 8 |
java type: Map<String, List<String>>
{
"IN": ["India","29"],
"IRE": ["Ireland","8"]
}
Now, let us see how we can use DataTable in Cucumber
Cucumber Data Tables Example in Java
Data Table without Header Example
Below is an example of how to implement Data Tables without a Header. For example, we want to test the Login Page of an application. We can either mention all the arguments inside the Gherkin statement or use a table to list all the arguments, as we used below:
Feature: Login to HRM Application
@ValidCredentials
Scenario: Login with valid credentials
Given User is on HRMLogin page
When User enters valid credentials
| Admin | admin123 |
Then User should be able to login successfully and new page open
Below is the Step Definition of the above scenario.
import io.cucumber.datatable.DataTable;
import io.cucumber.java.After;
import io.cucumber.java.Before;
import io.cucumber.java.en.Given;
import io.cucumber.java.en.Then;
import io.cucumber.java.en.When;
import org.junit.Assert;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.MatcherAssert.assertThat;
public class DataTableDefinitions {
WebDriver driver;
@Before
public void setup() {
System.setProperty("webdriver.chrome.driver",
"C:\\Users\\Vibha\\Software\\chromedriver_win32_101\\chromedriver.exe");
driver = new ChromeDriver();
driver.manage().window().maximize();
driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
}
@Given("User is on HRMLogin page")
public void userOnHomePage() {
driver.get("https://opensource-demo.orangehrmlive.com/");
}
@When("User enters valid credentials")
public void entersValidCredential(DataTable dataTable) throws InterruptedException{
System.out.println("Credentials Entered");
List<String> signUpForm = dataTable.asList();
String userName = signUpForm.get(0);
String passWord = signUpForm.get(1);
driver.findElement(By.name("txtUsername")).sendKeys(userName);
driver.findElement(By.name("txtPassword")).sendKeys(passWord);
driver.findElement(By.id("btnLogin")).submit();
}
@Then("User should be able to login successfully and new page open")
public void successfulLogin() throws InterruptedException {
String newPageText = driver.findElement(By.id("welcome")).getText();
System.out.println("newPageText :" + newPageText);
assertThat(newPageText, containsString("Welcome"));
}
@After
public void teardown(){
driver.close();
}
}
To run the Feature file, we need a Cucumber TestRunner.
import io.cucumber.junit.Cucumber;
import io.cucumber.junit.CucumberOptions;
import org.junit.runner.RunWith;
@RunWith(Cucumber.class)
@CucumberOptions(monochrome = true, plugin = "pretty", features = "src/test/resources/Features/DataTable.feature",
glue = "definitions", tags="@ValidCredentials")
public class CucumberRunnerTest {
}
The output of the above program is

In the above example, as we don’t have a header, we have just got the List object and get the values of DataTable starting from 0 index.
Cucumber converts the above table into a list of lists by treating each row as a list of the column values. We use the asLists method — supplying a String.class argument — to convert the DataTable argument to a List<List<String>>. This Class argument informs the asLists method of what data type we expect each element to be.
Data Table with Header and Single Row Example
Below is a cucumber data tables example with the header.
Adding a header to your table makes it easier to read and maintain.
@InValidCredential
Scenario: Login with invalid credential
Given User is on HRMLogin page
When User enters invalid credentials and Login will be unsuccessful with error message
| Username | Password | ErrorMessage |
| Admin1 | admin123!$ | Invalid credentials |
Below is the Step Definition of the above scenario.
import io.cucumber.datatable.DataTable;
import io.cucumber.java.After;
import io.cucumber.java.Before;
import io.cucumber.java.en.Given;
import io.cucumber.java.en.Then;
import io.cucumber.java.en.When;
import org.junit.Assert;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.MatcherAssert.assertThat;
public class DataTableDefinitions {
WebDriver driver;
@Before
public void setup() {
System.setProperty("webdriver.chrome.driver",
"C:\\Users\\Vibha\\Software\\chromedriver_win32_101\\chromedriver.exe");
driver = new ChromeDriver();
driver.manage().window().maximize();
driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
}
@Given("User is on HRMLogin page")
public void userOnHomePage() {
driver.get("https://opensource-demo.orangehrmlive.com/");
}
@When("User enters invalid credentials and Login will be unsuccessful with error message")
public void entersInvalidCredential(DataTable userTable) throws InterruptedException {
System.out.println("Enter Credentials");
List<Map<String, String>> user = userTable.asMaps(String.class, String.class);
String userName = user.get(0).get("Username");
System.out.println("Username :" + userName);
driver.findElement(By.name("txtUsername")).sendKeys(userName);
String passWord = user.get(0).get("Password");
System.out.println("Password :" + passWord);
driver.findElement(By.name("txtPassword")).sendKeys(passWord);
driver.findElement(By.id("btnLogin")).submit();
String errorMessage = user.get(0).get("ErrorMessage");
String actualErrorMessage = driver.findElement(By.id("spanMessage")).getText();
System.out.println("Actual Error Message :" + actualErrorMessage);
Assert.assertTrue(actualErrorMessage.equalsIgnoreCase(errorMessage));
}
@After
public void teardown(){
driver.close();
}
}
The output of the above program is

In the above example, we have only 1 row with the header, so have used get(0) to retrieve the first row of DataTable. After that, I used get(“HeaderName”) to get the value of the row of DataTable.
Data Table with Header and Multiple Rows Example
Below is a cucumber data table example with multiple rows of data with the header. This is helpful when we want to test multiple combinations of data in a step.
@InValidCredentials
Scenario: Login with invalid credentials
Given User is on HRMLogin page
When User enters invalid credentials and Login will be unsuccessful with custom error messages
| Username | Password | ErrorMessage |
| Admin1 | admin123! | Invalid credentials |
| Admina | admin123a | Invalid credentials |
Below is the Step Definition of the above scenario
import io.cucumber.datatable.DataTable;
import io.cucumber.java.After;
import io.cucumber.java.Before;
import io.cucumber.java.en.Given;
import io.cucumber.java.en.Then;
import io.cucumber.java.en.When;
import org.junit.Assert;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.MatcherAssert.assertThat;
public class DataTableDefinitions {
WebDriver driver;
@Before
public void setup() {
System.setProperty("webdriver.chrome.driver",
"C:\\Users\\Vibha\\Software\\chromedriver_win32_101\\chromedriver.exe");
driver = new ChromeDriver();
driver.manage().window().maximize();
driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
}
@Given("User is on HRMLogin page")
public void userOnHomePage() {
driver.get("https://opensource-demo.orangehrmlive.com/");
}
@When("User enters invalid credentials and Login will be unsuccessful with custom error messages")
public void entersInvalidCredentials(DataTable userTable) throws InterruptedException {
System.out.println("Enter Credentials");
List<Map<String, String>> user = userTable.asMaps(String.class, String.class);
for (Map<String, String> form : user) {
String userName = form.get("Username");
System.out.println("Username :" + userName);
driver.findElement(By.name("txtUsername")).sendKeys(userName);
String passWord = form.get("Password");
System.out.println("Password :" + passWord);
driver.findElement(By.name("txtPassword")).sendKeys(passWord);
driver.findElement(By.id("btnLogin")).submit();
String errorMessage = form.get("ErrorMessage");
String actualErrorMessage = driver.findElement(By.id("spanMessage")).getText();
System.out.println("Actual Error Message :" + actualErrorMessage);
Assert.assertTrue(actualErrorMessage.equalsIgnoreCase(errorMessage));
}
}
@After
public void teardown(){
driver.close();
}
}
The output of the above program is

Cucumber creates a list containing each row, but instead maps the column heading to each column value. Cucumber repeats this process for each subsequent row. We use the asMaps method — supplying two String.class arguments — to convert the DataTable argument to a List<Map<String, String>>.
The first argument denotes the data type of the key (header) and the second indicates the data type of each column value. Thus, we supply two String.class arguments because our headers (key) and title and author (values) are all Strings.
That’s it! We are done!!!
Congratulations on making it through this tutorial and hope you found it useful! Happy Learning!! Cheers!!