In one of our automation projects using Cucumber and Capybara, there was a use case where we needed to automate the process of submitting a multi-field form and checking the provided form details on the next page. We considered parameterization using Data Table and Scenario Outline provided by Cucumber. In this article, we'll take a look at why and how we combined Scenario Outline with Data Table to optimize the feature file.

We began with Scenario Outline because we only had four fields: First Name, Last Name, Password, Email, and we wanted to run the same scenario with different datasets. However, we were later given a new requirement that included additional fields such as Location, Age, and Phone Number, increasing the number of input parameters. As a result, the scenario and step definitions became more complex. This is how we can write a test case, which can be easily extended for new field requirements. (For reference we have included only the first four fields in the examples)

Scenario Outline: Validate User Registration Form
  Given I am on the registration page
  When I submit the form with the following details "<FirstName>", "<LastName>", "<Password>", "<Email>"
  Then the details should be displayed on my profile page

  Examples:
    |FirstName |LastName |Password  |Email             |
    |John      |Doe      |testPass1 |jdoe@email.com    |
    |Anne      |Smith    |testPass2 |asmith@email.com  |
    |Mike      |Stewart  |testPass3 |mstewart@email.com|
Feature File
Given('I am on the registration page') do
  log 'I am on registration page'
end

When('I submit the form with the following details {string}, {string}, {string}, {string}') do |first_name, last_name, password, email|
  # Storing the input parameters in instance variable to access it in subsequent steps
  @first_name = first_name
  @last_name = last_name
  @email = email

  # Fill the registration form
  fill_in('First Name', with: @first_name)
  fill_in('Last Name', with: @last_name)
  fill_in('Password', with: password)
  fill_in('Email', with: @email)
end

Then('the details should be displayed on my profile page') do
  expect(find('#firstname').value).to eq(@first_name)
  expect(find('#lastname').value).to eq(@last_name)
  expect(find('#email').value).to eq(@email)
end
Step Definition

We considered using Data Table because we needed to send multiple parameters for a scenario. In contrast to Scenario Outline, Data Table passes all datasets in a single step, and to retrieve dataset details we had to loop through the data map. As an alternative to iterating through the data map, we could repeat the scenario as many times as the dataset.

Scenario: Validate User Registration Form for User 1
  Given I am on the registration page
  When I submit the form with the following details
    |FirstName |LastName |Password  |Email         |
    |John      |Doe      |testPass1 |jdoe@email.com|
  Then the details should be displayed on my profile page

Scenario: Validate User Registration Form for User 2
  Given I am on the registration page
  When I submit the form with the following details
    |FirstName |LastName |Password  |Email           |
    |Anne      |Smith    |testPass2 |asmith@email.com|
  Then the details should be displayed on my profile page

Scenario: Validate User Registration Form for User 3
  Given I am on the registration page
  When I submit the form with the following details
    |FirstName |LastName |Password  |Email             |
    |Mike      |Stewart  |testPass3 |mstewart@email.com|
  Then the details should be displayed on my profile page
Feature File

To avoid the repetition of the Scenarios we passed the Reference Header of the Example Table as a parameter to the Data Table.

Scenario Outline: Validate User Registration Form
  Given I am on the registration page
  When I submit the form with the following details
  |FirstName  |LastName  |Password  |Email  |
  |<FirstName>|<LastName>|<Password>|<Email>|
  Then the details should be displayed on my profile page

  Examples:
    |FirstName |LastName |Password  |Email             |
    |John      |Doe      |testPass1 |jdoe@email.com    |
    |Anne      |Smith    |testPass2 |asmith@email.com  |
    |Mike      |Stewart  |testPass3 |mstewart@email.com|
Feature File

In the step definition, we retrieved the input parameter provided as the first row of the Data Map. We used the same hash in the subsequent steps by assigning it to an instance variable.

Given('I am on the registration page') do
  log 'I am on registration page'
end

When('I submit the form with the following details') do |user_details_map|
  # Fetch the user detail passed as the first argument of the data map
  # user_details_map = { hashes: [{"FirstName"=>"John", "LastName"=>"Doe",
  # "Password"=>"testPass1", "Email"=>"jdoe@email.com"}]}
  @user_detail = user_details_map.hashes[0]
  # Fill the registration form
  fill_in('First Name', with: @user_detail['FirstName'])
  fill_in('Last Name', with: @user_detail['LastName'])
  fill_in('Password', with: @user_detail['Password'])
  fill_in('Email', with: @user_detail['Email'])
end

Then('the details should be displayed on my profile page') do
  expect(find('#firstname').value).to eq(@user_detail['FirstName'])
  expect(find('#lastname').value).to eq(@user_detail['LastName'])
  expect(find('#email').value).to eq(@user_detail['email'])
end
Step Definition

In the above example, the scenario will run three times as we have three rows in the Example Table.

By combining the scenario outline with the data table, we were able to DRY our code and make it more readable at the same time.

References