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