I am trying out cucumber for browser testing and am learning about BDD testing for the first time – so i am quite a beginner to BDD. I have encountered a problem and would like to know the best-practice way of solving it.
(I am using it for a node.js webapp, so it is cucumber.js and selenium WebDriverJS, but the platform should not matter for this question)
DESCRIPTION:
In tutorials for the Gherkin syntax, you often see examples on clicking a button at a specific page, like for example:
Given (something)
When I click the submit button
Then (something)
Implementing the step-definition for this step is quite simple – just make selenium locate the element with whatever css-selector happens to match the button and then make selenium click on it.
PROBLEM:
But what if you have different buttons on different pages with the same "human readable" name (i.e. the same name in the cucumber step-text), but which must be located by different css-selectors?
It seems that you can't have step-definitions which are local to features, but that all step-definitions are shared among all features. This means that if you create a step "I click the submit button", as above, the step-definition must work for testing all pages in the entire webapp which has a submit button. I am not really sure what is the proper way to do this.
QUESTION:
What is the best practice for handling this?
EXAMPLE OF THE PROBLEM:
Let's say we have 3 pages which all have a ”next” button, which does something completely different on each page and are located completely differently in the DOM. Let's say we have one feature for each of these pages. In each feature, the scenarios involving the ”next” button looks like this:
Given I am on page xyz
And ...
And I click the next button
And ...
When ...
Then ...
The problem is that on the first page, the ”next” button is perhaps located by ”.next-button”, on the second page it could be ”#someContainer .btn.btn-primary” and on the third page”#assetButtons li:nth-child(3)”. If we had a step-definition local to each feature, they could simply look like:
this.Given(/^I click the next button$/, function(callback) {
this.driver.findElement(this.webdriver.By.css(”.next-button”).click();
callback();
});
this.Given(/^I click the next button$/, function(callback) {
this.driver.findElement(this.webdriver.By.css(”#someContainer .btn.btn-primary”).click();
callback();
});
this.Given(/^I click the next button$/, function(callback) {
this.driver.findElement(this.webdriver.By.css(”#assetButtons li:nth-child(3)”).click();
callback();
});
But since the step-definitions are global to all features, and you naturally can't create two step-definitions for the same regex, the step-definition for "I click the next button" need to know which page we are on or which ”next” button the scenario is referring to.
Some of my own thoughts: optional reading
But what is the RIGHT way to do it?
Saying you "click on the submit button" is bad gherkin. You want to write declarative sentence that state what you are doing, but not how you are doing it. Imperative sentences like "click on this button" should not be found in your test design. I understand you point about being able to do things in more than one way, in which case that is an important detail, but abstract away as much as possible.
You state you have three next buttons that do three completely different things, state those actions in your gherkin
When I advance the image carousel
When I go to the next news page
When I view the next page of search results
As for the different paths...
When I swipe to view the next page of search results
When I use the keyboard to view the next page of search results
When I click on the next link to view the next page of search results
now we can turn that into one stepdef that has three different actions tied to it.
The point of cucumber and gherkin isn't to dry out your scenarios, it's to make it human readable, understandable by non-programmer types and a form of living documentation. If you have a few more words in there it won't be the end of the World()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With