DataTables in Cucumber

HOME

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.

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 sucessfully and new page open

Below is the Step Definition of the above scenario.

public class LoginDefinitions {

	 WebDriver driver;
	 
	 @Before
	 public void setup() {
	 
		 System.setProperty("webdriver.gecko.driver",
	                "C:\\Users\\Vibha\\Desktop\\Drivers\\geckodriver-v0.26.0-win64\\geckodriver.exe");
	        driver = new FirefoxDriver();
	        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 sucessfully and new page open")
	  public void sucessfullLogin() 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();
	  }
}

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 Clasargument 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 valid credentials
     
   Given User is on HRMLogin page
   When User enters invalid credentials and Login will be unsuccessfull with error message
   |Username  |Password  | ErrorMessage      |              
   |Admin1    |admin123!|Invalid credentials |

Below is the Step Definition of above scenario.

  @When("User enters invalid credentials and Login will be unsuccessfull with error message")
	    public void entersInvalidCredentials(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);
	        
	        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));       
	 
	    }

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 have 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 tables 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 valid credentials
     
    Given User is on HRMLogin page
    When User enters invalid credentials and Login will be unsuccessfull with error message
    |Username    |Password  | ErrorMessage       |
    |Admin1      |admin123!|Invalid credentials  |
    |Admina      |admin123a|Invalid credentials  |
   

Below is the Step Definition of the above scenario

  @When("User enters invalid credentials and Login will be unsuccessfull with error message")
	    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));
	      
	        }         
	    }

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!!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s