Parameterize Cucumber BDD with selenium

Parameterizing is nothing but using the custom values or using values without hard-coding the values.

In the previous chapter examples, we have seen everything as hard coded, from Google to search term, but our requirements may change and we should be in a position to change the values without touching the step definitions.

Real Time Scenario : Product Owner (BA) gives you a requirement saying that all the links present in the webpage should have a color code of #0000ff (Blue).

Based on the given requirement you have automated the scenario condition and you took a long sick leave because of your appraisal review ( just kidding )

Now Product owner realizes that she has to change the color code to #000080 (Navy Blue), but as an intelligent person, you have hardcoded the #0000ff in step definition.

As Long as I am familiar with, Product Owners are not familiar with programming and because which only they wanted the cucumber, In that also you have hard coded the values, so because of this she cannot change the value in the feature file, if she changes something tests will fails the step definitions are not available for the changed step.

But if you can provide the Product owner the ability to change the values on need basis and if your step definition can work based on the change of value, would not it be great ?

To enable the parameterization in cucumber we have to provide the values in ""(double quotes) which we want to parameterize.

Lets' re-write the above example in the parameterize way, Before that when we parameterize the step then we have to receive those parameter values in your step definition to use it for further.

As you know, Cucumber invokes the step definition method using a regular expression but we are not that much sure that we can write the regular expression, so instead of writing a regular expression, run the TestRunner file and in output cucumber suggest as that there is some step missing.

suggested-parameter-cucumber-bdd-selenium

We have to take that regular expression(I have highlighted in the above image) use it along without step definition.


Feature: Sample test
  Search Chercher Tech in Goole and click first result

Scenario: Search Google for Chercher Tech
  Given There is opened "Chrome browser" 
  When I searched "Chercher Tech" in searchbar
  And When I press Enter key
  Then I should see Chercher Tech results
  Then I click on the First result to see the Home page			


Change the step definition steps like below one based on the regular expression copied, keep remaining methods same as the previous code.


public class Steps_Sample {
	WebDriver driver;
	@Given("^There is opened \"([^\"]*)\"$")
	public void there_is_opened_Chrome_browser(String browser) throws Throwable {
		if(browser.equals("chrome"))
		{
			System.setProperty("webdriver.chrome.driver", "D:\\Eclipse progs\\driverserver\\chromedriver.exe");
			driver = new ChromeDriver();
		}else if(browser.equals("firefox")) {
			System.setProperty("webdriver.firefox.driver", "D:\\Eclipse progs\\driverserver\\geckodriver.exe");
			driver = new FirefoxDriver();
		}
		
		driver.get("https://google.com");
		System.out.println("Opening "+browser);
	}
	@When("^I searched \"([^\"]*)\" in searchbar$")
	public void i_searched_Chercher_Tech_in_searchbar(String searchTerm) throws Throwable {
		driver.findElement(By.name("q")).sendKeys(searchTerm);
		System.out.println("Searching the text on search bar");
	}			

Also, change the Feature file according to the parameter you accept.

Data from Examples in Cucumber BDD

In the above example, we have seen to read the data from the user input but if the user wants to test the same scenario with more than one data, then we should use a concept called Data table in Cucumber or it is also called as Examples in Cucumber BDD.

Data table in cucumber should be formed using Pipe ( | )symbol, and every new line will be considered as new data. examples-data-table-cucumber-bdd-selenium

We can have n-number of tables and n-number of columns in the data table in cucumber BDD

The parameters which you want to read from the data table must be mentioned inside the < > . Parameter name inside the angular brace should match with the column name in the Examples we provided.

Normally people will write the Examples at the end of every scenario if required. To use an example, we need to change the Scenario: tag into Scenario Outline:, otherwise cucumber bdd throws an error on compilation.

Let's rewrite the above scenario to read the data from the Examples.


Feature: Sample test
  Search Chercher Tech in Google and click first result

  Scenario Outline: Search Google for Chercher Tech
    Given There is opened "<browser>"
    When I searched "<searchterm>" in searchbar
    And When I press Enter key
    Then I should see results
    Then I click on the First result to see the Home page

    Examples: 
      | browser | searchterm        |
      | firefox | chercher tech     |
      | chrome  | selenium chercher |
			


The step definition file is below, and there is no change in TestRunner class


package testDefinitions;

import org.openqa.selenium.By;
import org.openqa.selenium.Keys;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.firefox.FirefoxDriver;

import cucumber.api.java.en.Given;
import cucumber.api.java.en.Then;
import cucumber.api.java.en.When;

public class Steps_Sample {
	WebDriver driver;
	@Given("^There is opened \"([^\"]*)\"$")
	public void there_is_opened_Chrome_browser(String browser) throws Throwable {
		if(browser.equals("chrome"))
		{
			System.setProperty("webdriver.chrome.driver", "D:\\Eclipse progs\\driverserver\\chromedriver.exe");
			driver = new ChromeDriver();
		}else if(browser.equals("firefox")) {
			System.setProperty("webdriver.gecko.driver", "D:\\Eclipse progs\\driverserver\\geckodriver.exe");
			driver = new FirefoxDriver();
		}
		
		driver.get("https://google.com");
		System.out.println("Opening "+browser);
	}
	@When("^I searched \"([^\"]*)\" in searchbar$")
	public void i_searched_Chercher_Tech_in_searchbar(String searchTerm) throws Throwable {
		driver.findElement(By.name("q")).sendKeys(searchTerm);
		System.out.println("Searching the text on search bar");
	}
	@When("^When I press Enter key$")
	public void when_I_press_Enter_key() throws Throwable {
		driver.findElement(By.name("q")).sendKeys(Keys.ENTER);
		System.out.println("Press Enter key");
	}
	@Then("^I should see results$")
	public void i_should_see_Chercher_Tech_results() throws Throwable {
		driver.findElement(By.partialLinkText("CherCher"));
		System.out.println("User should see results relate to CherCher Tech");
	}
	@Then("^I click on the First result to see the Home page$")
	public void i_click_on_the_First_result_to_see_the_Home_page() throws Throwable {
		driver.findElement(By.partialLinkText("CherCher")).click();
		System.out.println("User should able to click first link");
	}
}
			
data-table-cucumber-bdd-selenium

Data table in Cucumber

With Cucumber data tables, you can pass parameters from feature files in tabular format. And you can then use this data in the step definition methods in the form of Maps.

In Cucumber, you can add data tables in two different formats :

  • Data table with a header
  • Data table without a header

Here, a header means to have a top row which tells what type of data you have.

Cucumber data table without header :

Notice the last line in the below example. Here, 'karthiq' and 'pwd123' are the parameters, that we have added between the pipe ( | ) symbols. This is what we refer to as a data table in cucumber.


Feature: Sample test
  Search Chercher Tech in Google and click first result

  Scenario Outline: Search Google for Chercher Tech
    Given There is opened Google
    And I set the value with following details.
    | q  | selenium chercher |
			


After making/creating the above scenario, try to run it. You might get an error like below one about the step definitions


You can implement missing steps with the snippets below:

@Given("^There is opened Google$")
public void there_is_opened_Google() throws Throwable {
    // Write code here that turns the phrase above into concrete actions
    throw new PendingException();
}

@Given("^I set the value with following details\\.$")
public void i_set_the_value_with_following_details(DataTable arg1) throws Throwable {
    // Write code here that turns the phrase above into concrete actions
    // For automatic transformation, change DataTable to one of
    // List<YourType>, List<List<E>>, List<Map<K,V>> or Map<K,V>.
    // E,K,V must be a scalar (String, Integer, Date, enum etc)
    throw new PendingException();
}			


You got the error because we have not implemented those steps, let's implement the steps in the steps definition file.


@Given("^There is opened Google$")
	public void there_is_opened_Google() throws Throwable {
		System.setProperty("webdriver.chrome.driver", "D:\\PATH\\chromedriver.exe");
		driver = new ChromeDriver();
		driver.get("https://google.com");
	}

@Given("^I set the value with following details\\.$")
public void i_set_the_value_with_following_details(DataTable data) throws Throwable {
	List<String> list = data.asList(String.class);
	driver.findElement(By.name(list.get(0))).sendKeys(list.get(1));
}	
single-row-cucumber-datatable-selenium-bdd

In this example, We have received the value in the format of DataTable object, We have to convert the DataTable into list format so that we can access the values based on an index.

Also, since the DataTable parameters that we have are of type String, so we will use List<String> to fetch the data. If the data is numbers, then you need to use List<Integer>.

In the above example, we had only one row of value so we have used it as List, but if we have more than one row in datatable how to handle it in cucumber.

When we have more than one row in cucumber datatable we must convert the DataTable parameter as List of Lists. Then we have to Iterator over first list which is nothing but rows, from these rows(List) we have to get the values using get() method.


Feature: Sample test
  Search Chercher Tech in Google and click first result

  Scenario: Search Google for Chercher Tech
    Given There is opened Google
    And I set the value with following details.
    | q  | selenium chercher |
    | q  | **** karthiq |		


The Step definition would be.


@Given("^I set the value with following details\\.$")
public void i_set_the_value_with_following_details(DataTable data) throws Throwable {
	List<List<String>> lists = data.asLists(String.class);
	for (List<String> list : lists) {
		driver.findElement(By.name(list.get(0))).sendKeys(list.get(1));
	}		
}			
table-without-header-multirows-cucumber

When someone reads the cucumber scenario, it is easy for them to figure out that the first column would be the user name and the second one will be password. But what happens when you have multiple columns in the data table.

Cucumber data table with header :

We add the header to the Data table when we have more columns in the data table, so that we can improve the readability of our cucumber scenarios and scripts.

After adding the header, the scenario will have readability is better compared to the last example :


Feature: Sample test
  Search Chercher Tech in Google and click first result

  Scenario Outline: Search in Search engine
    Given There is opened Browser
    And I set the value with following details.
	| URL 			         | name_locator | SeartchTerm       |
	| https://google.com | q            | selenium chercher |			


Run the tests with above Gherkin Features, which may give you below error.


@Given("^I set the value with following details\\.$")
public void i_set_the_value_with_following_details(DataTable arg1) throws Throwable {
    // Write code here that turns the phrase above into concrete actions
    // For automatic transformation, change DataTable to one of
    // List<YourType>, List<List<E>>, List<Map<K,V>> or Map<K,V>.
    // E,K,V must be a scalar (String, Integer, Date, enum etc)
    throw new PendingException();
}			


Change the step definition file like below


@Given("^There is opened Browser$")
public void there_is_opened_Google() throws Throwable {
	System.setProperty("webdriver.chrome.driver", "D:\\Eclipse progs\\driverserver\\chromedriver.exe");
	driver = new ChromeDriver();
	
}

@Given("^I set the value with following details\\.$")
public void i_set_the_value_with_following_details(DataTable data) throws Throwable {
	List<Map<String, String>> map = data.asMaps(String.class, String.class);
	driver.get(map.get(0).get("URL"));
	driver.findElement(By.name(map.get(0).get("name_locator")))
			.sendKeys(map.get(0).get("SeartchTerm"));	
}			


The DataTable contains headers as well so we have to handle the dataTable using list of maps. cucumber-datatable-with-hedaer-selenium-bdd

Cucumber data table with header has Multiple rows:

When we perform any data driven testing we might have more than one row of data, so let's see how to handle when we have more than one row of data.

In this case as well, when you run the cucumber scenario, the structure of the missing step definition method will be the same as all the previous examples. The only difference here is you will have to use a loop or index-based logic to fetch values from different rows of data.


Feature: Sample test
  Search Chercher Tech in Google and click first result

  Scenario: Search in Search engine
    Given There is opened Browser
    And I set the value with following details.
	| URL 			         | name_locator | SeartchTerm       |
	| https://bing.com | q            | selenium chercher |	
	|https://google.com|q							| karthiq  					|		


Step definition file


@Given("^I set the value with following details\\.$")
public void i_set_the_value_with_following_details(DataTable data) throws Throwable {
	List<Map<String, String>> maps = data.asMaps(String.class, String.class);
	
	for (Map<String, String> map : maps) {
		driver.get(map.get("URL"));
		driver.findElement(By.name(map.get("name_locator")))
				.sendKeys(map.get("SeartchTerm"));
	}	
}		
Comment / Suggestion Section
Point our Mistakes and Post Your Suggestions