We're using Cucumber and Selenium with Ruby. After reading the documentation on hooks I've tried my hand at setting a few tags to set (for example) some environment variables.
Here's a contrived example that demonstrates the problem.
When I establish a Before hook like so:
Before('#tag1', '#tag2') do
puts "in the before hook!"
end
It'll take effect with a scenario defined like so:
#tag1 #tag2
Scenario Outline: This is a test scenario
Given I run my first step for "<user>"
Then I complete my test
#firstrun
Scenarios:
|user|
|fred|
#secondrun
Scenarios:
|user|
|barney|
..however if I move #tag1 and #tag2 to the individual scenarios and not the scenario outline, the hook is never called, for instance:
#secondrun #tag1 #tag2
Scenarios:
|user|
|barney|
Is it possible to 'hook in' individual scenarios, or just the outlines?
Typically with scenario outlines the table of values you're testing is tied to that, not separate scenarios.
E.g
ScenarioOutline
Given I am on gmails website
When I login as <user> with <password>
Then I am able to view my primary inbox
Example:
| user | password |
| Fred | xd13#%& |
Related
My question is much more conceptual than ever. I'd like to describe a good scenario using the Cucumber feature file where I have to have for each row of my Data table a new access token from the Identity Provider.
I.e
Scenario:
Given <Code Authorization>
And <Access Token>
And The client has the following information
| email | FirstName | Phone |
| xpto# | Richard | 343242|
When the client via Post /xpto
Then The API response a Json file
| code | response |
| 200 | xpto |
I'll use a Data Table for this kind of approach. However, I cannot give a static Access Token because it will expire. I should get a new one every time when my test run but It is not my test it self. The Token is just a Data that I have to have to test my scenario.
Is it ok call a REST in an Given Step? If I do this I am mixing up the objective of my scenarios.
Any thougts are welcome not for your mind but by the book. :-)
Kind Regards,
It seems that you need the token in order to set up the scenario. In that case it is fine to have that in a Given step. You can perform REST or other calls in step definitions for that Given step. For ex: It may look something like below. You can change wordings as you like but try to word it in a manner that shows initial state of the application.
Given I have a token for this scenario
And The client has the following information
| email | FirstName | Phone |
|xpto# | Richard | 343242|
...
...
Given steps are meant to establish a given state. It is considered best practice in BDD. You can find this information in official BDD docs here
Also , if you want to read more about the purpose and structure of Given , When and Then , be sure to have a look here
I am working with Cucumber and Groovy in Katalon Studio. I have the cucumber feature file where it has Multiple Scenario Outlines as mentioned below.
When I run the cucumber feature file, it should run the TestCase1 of first section in the scenario outline along with the steps and TestCase1 of second section in scenario outline.
But, it is running the first section of feature file TestCase1 and TestCase2 first. That means it is just loggining with given credentials and closing the browser.
For reference, below mentioned the step definition code also.
Cucumber Feature File:
#Login1
Feature: Title of your feature
I want to use this template for my feature file
#Login1 `**SECTION ONE**`
Scenario Outline: Login into GMP Application
Given running indicator flag
And User is on GMP Application Login Screen
When User enters the in the Login
And User enters the in the password
And User clicks on the ok button
Then User logged in successful at Home Screen
Examples:
| atid | pwd1 | runind | -> Header
| nm1013 | test01g | Y | -> TestCase1
| nm0313 | test02g | Y | -> TestCase2
#Login1 `**SECTION TWO**`
Scenario Outline: Click on the Create Inquiry Menu Item
Given User is on GMP Home Screen
When user click on the Inquiry menu item
And select the billing mode should be
And user click create inquiry item from the heading
Then it should displays create inquiry pagef
Examples:
| contract | -> Header
| GS00T07NSD0007 | -> TestCase1
| GS00T07NSD0007 | -> TestCase2
Step Definition
#Given(“running indicator flag (.*)”)
def run_indicator_flag(String ind1) {
println "Passing Indicator " + ind1
}
#And(“User is on GMP Application Login Screen”)
def user_on_GMP_Application_Login_Screen() {
boolean store2a
WebUI.openBrowser(’’)
WebUI.navigateToUrl(‘https://URL’, FailureHandling.STOP_ON_FAILURE)
}
#When(“User enters the (.*) in the Login”)
def user_enter_userid_in_the_Login(String uid) {
WebUI.setText(findTestObject(‘Object Repository/ORTC01/Page_/input_userid’),
uid, FailureHandling.STOP_ON_FAILURE)
}
#And(“User enters the (.*) in the password”)
def User_enters_the_in_the_password(String pwd5) {
WebUI.setText(findTestObject(‘Object
Repository/ORTC01/Page_/input_password’), pwd5,
FailureHandling.STOP_ON_FAILURE)
}
First of all you cannot connect scenarios in Cucumber. Each scenario is a separate test that starts from nothing, does something and then resets back to nothing.
Secondly a scenario outline is just a way to write several scenarios in a more compact form. Each set of examples in an outline causes a single scenario to be created and run. I would strongly recommend you avoid using Scenario Outlines
Good scenarios describe WHAT is being done without getting into HOW things are done. Your scenarios are full of HOW things are done which makes them complex and very difficult to work with. You should push all the HOW down into your step definitions (or better still helper methods called by your step definitions.
If you do these things you will be able to write scenarios that will look something like
Scenario: Create a billing enquiry
Given I have a bill
And I am logged in
When I enquire about my bill
Then ...
Note: How the above scenario is much shorter and has no detail about HOW you do anything.
Is it possible for multiple scenarios to use the same Examples table?
So instead of having something like the following:
Scenario Outline: First Scenario
Given I am viewing "<url>"
Then I assert that the current URL "<url>"
Examples:
| url |
| https://google.com |
| https://twitter.com|
Scenario Outline: Second Scenario
Given I am viewing "<url>" with route "</contactus>"
Then I assert that "<url>" contains "contactus"
Examples:
| url |
| https://google.com |
| https://twitter.com|
I can do something like
Scenario Outline: Reusable Example
Examples:
| url |
| https://google.com |
| https://twitter.com|
Scenario: First Scenario
Given I am viewing "<url>"
Then I assert that the current URL "<url>"
Scenario: Second Scenario
Given I am viewing "<url>" with route "</contactus>"
Then I assert that "<url>" contains "contactus"
I found a similar question on StackOverflow, but merging all my scenarios in just one scenario is not an option for me. Since this question was posted in 2014, maybe there have been some advancements in the framework which I am not aware of :D
Thank you in advance.
You can use qaf-gherkin where you can move examples in external file and use it with one or more scenario. With qaf your feature file may look like below:
Scenario Outline: First Scenario
Given I am viewing "<url>"
Then I assert that the current URL "<url>"
Examples:{'datafile':'resources/testdata.txt'}
Scenario Outline: Second Scenario
Given I am viewing "<url>" with route "</contactus>"
Then I assert that "<url>" contains "contactus"
Examples:{'datafile':'resources/testdata.txt'}
And your datafile will look like:
url
https://google.com
https://twitter.com
Here is the reference.
You might use a Background to specify steps which are equal for all scenarios. (Have a look on the link for constraints)
A feature file might look like
Feature: use of reusable Given
Background: Reusable Example
Given I am viewing url
| https://google.com |
And a search phrase is entered in the search field
Scenario: First Scenario
And step for first scenario
Scenario: Second Scenario
And step for second scenario
implementing the glue code for the Given
#Given("^I am viewing url$")
public void iAmViewing(List<String> url) throws Throwable {
System.out.println("url = " + url);
}
edit After the question has been updated a Scenario Outline could work for both examples.
Feature: use of example
Scenario Outline: First Scenario
Given I am viewing "<host>" with path "<path>"
Then I assert that the current URL is "<host><path>"
Examples:
| host | path |
| https://google.com | / |
| https://twitter.com | /contactus |
I have 2 feature files i.e userstoryteacher1.feature and userstoryteacher2.feature . Basicaly userstoryteacher1.feature have the steps where it has 2 tags #Dev and #QA.
I want to run the feature files in following way :-
If i pass the #Dev,#tagteacher in Cucumber class then it should pick the dev url to open the page with crentials.
If i pass the #QA,#tagteacher in Cucumber class then it should pick the qa url to open the page with credentials.
import org.junit.runner.RunWith;
import com.optum.synergy.common.ui.controller.WebController;
import cucumber.api.CucumberOptions;
import cucumber.api.SnippetType;
import cucumber.api.junit.Cucumber;
#RunWith(Cucumber.class)
#CucumberOptions(
plugin = { "json:target/test_results/cucumber.json"},
features = { "src/main/resources/ui/features" },
tags ={"#Dev,#tagteacher"},
snippets = SnippetType.CAMELCASE
)
public class CucumberRunnerTest {
public static void tearDown(){
WebController.closeDeviceDriver();
}
}
---------------------------------------------------------------------------
userstoryteacher1.feature file :-
#TestStory
Feature: Teachers timesheet need to be filled
I want to use this template for my feature file
Background:
Scenario Outline: Open Webpage
Given User Open teacher application with given <ENDPOINT>
And Login into application with given <USERNAME> and <PASSWORD>
And User clicks on teacher submission link
#DEV
Examples:
| endpoint | USERNAME | PASSWORD |
| http://teachersheetdev.ggn.com | sdrdev| aknewdev|
#QA
Examples:
| endpoint | USERNAME | PASSWORD |
| http://teachersheetqa.ggn.com | sdrqa | aknewdev|
-----------------------------------------------------------------------------
userstoryteacher2.feature file :-
Feature : I'm at the teachers page
#tagteacher
Scenario: Open app home page and click the button
Given I'm at the teachersheet homepage
When User clicks Add Task button
Then User should see the tasks schedule
Cucumber is designed so that you can't link scenarios or feature files together. Each scenario should be run as an independent 'test' that starts from the beginning.
Programming with feature files is a terrible anti-pattern. Instead push the programming down into the step definition layer, or better yet into helpers that the step definitions use.
If you want to get the best out of Cucumber you need to use it to only express WHAT is being done and WHY its important. From your example this seems to be all about teachers filling in their timesheets so your scenarios should be things like
Scenario: Fill in timesheet
Given I am a teacher
And I am logged in
When I fill in my timesheet
Then I should see my timesheet has been saved.
You set up state in your Givens, and you build helper methods with each scenario you create, so that future scenarios can set up state easily. For example Given I am a teacher might be something like
def 'Given I am a teacher' do
teacher = create_new_teacher;
register_teacher(teacher)
return teacher
end
Which is building on previous scenarios to register new teachers. If you follow this pattern you can have simple scenarios with a single Given that do vast amounts of setup just using a single method call. This is much better than linking several feature files together!!
I'm using cucumber with webrat/mechanize to test a PHP site and I'm trying to improve the speed the tests run by avoiding running unnecessary steps.
I want to use a scenario outline to check a whole lot of pages are accessible/protected depending on the user who is logged in:
Scenario Outline: Check page access is secure
Given I am logged in as "<user>"
And I am on <page>
Then I should see "<message>"
Examples:
|user |page |message |
|admin |home page |Welcome to my site |
|admin |admin page|Site administration |
|editor|home page |Welcome to my site |
|editor|admin page|Access denied |
|guest |home page |Please login |
|guest |admin page|Access denied |
...
This works, but given I have 10 roles and hundreds of pages to check, there is a lot of overhead in running the login step every time the outline runs.
I'm wondering if there is a way to run the login step once for each role, then visit each page in turn without needing to login every time. i.e run "login, visit 1, visit 2, visit 3" instead of "login, visit 1, login, visit 2, login, visit 3".
I've tried using hooks, and Background, but can't seem to find an approach that works. Is this possible?
Instead of putting all the information about what is accessible/protected in the feature, consider putting them in the step defs (even better would be to use the definitions in your application, but that isn't easy if your app is not in process)
If you can live with a feature that is as abstract as
Given I am an admin
Then I should be able to access admin pages
Then you can do all the work much more efficiently in step defs
Following is just a code sketch to give some idea of what you can do ...
# step def
module AccessHelper
AdminPages = {
{page: ..., msg: ...
...
}
def login_as ... ; end
def correct_message? msg ...; end
def check_admin_access_for user
#errors = []
login_as #I
AdminPages.each do |page|
visit page[:path]
errors << page unless correct_message?
end
end
end
World(AccessHelper)
Then "I should be able to access admin pages" do
check_admin_access_for #I
#errors.should be_empty
end
You can of course expand this using the full power of ruby to meet you particular needs. The fundamental idea is that you can always take several cucumber actions and abstract them into one cucumber action.
Hope thats useful
You could implement the Given step to only log in once for each role:
# lazily log in each role as needed, and keep the login in a hash table
$logins = Hash.new do |_logins, role|
_logins[role] = do_expensive_login(role)
end
Given /^I am logged in as "([^"]+)"$/ |role|
#login = $logins[role]
end
Of course, if the future steps can change the state of the login, or change the world such that the login is no longer valid, this might hose you down the line, so tread carefully.