Is it possible to add an "Else" after "Given, When, Then"? - gherkin

I'm new to Gherking and trying to write my first scenarios as best as I can, but I regularly find myself in situations where I'm really tempted to add an "Else" to my scenario. "Given, When, Then" becomes "Given, When, Then, Else". I know that the "Else" keyword is not defined and so not implemented in Gherkin tools but it doesn't care to me because I don't use these tools.
Do you think it is correct to write this :
Example :
Scenario : Application starts
Given I start the application
When I already have an open session
Then I see the home screen
Else I see the login screen
Or is it better to write two different scenarios :
Scenario : Application started by authenticated user
Given I have an open session
When I start the application
Then I see the home screen
Scenario : Application started by unauthenticated user
Given I don't have an open session
When I start the application
Then I see the login screen

In short no, but here are options to handle multiple variants of a scenario:
If it was only tailing elements of the scenario steps that differed you could of moved early steps in to a common 'Background' section, making repeated differing scenarios shorter and clearer.
But from your example it is all steps differing slightly so you can:-
accept the repitition of multiple scenarios
Or
parametise the differences and use data tables in the 'given' and 'then' sections to give before and after values.
Or (my prefernece)
Use the 'scenario outline' syntax that uses an examples table to provide sets of data fixtures with their expected results. These replace in the scenario steps as runtime. The scenario is then 'played out' once for each row in the examples table.
So:
Scenario : Application started by authenticated user
Given I have an open session
When I start the application
Then I see the home screen
Scenario : Application started by unauthenticated user
Given I don't have an open session
When I start the application
Then I see the login screen
Becomes:
Scenario Outline: Application Start and login
Given Application started by <AuthenticationStatus> user
And I have <SessionState> session
When I start the application
Then I see the <FirstScreen> screen
Examples:
|AuthenticationStatus |SessionState |FirstScreen|
|Authenticated |open |home |
|Un-Authenticated |not open |login |
IMHO for 2 scenarios it might not be worth the loss of readabiltiy but for more than that I think it's definitely worth it.

Related

How to not continually repeat a background scenario for Cucumber features that depend on that background scenario

I'm writing some end-to-end tests for my application using Cucumber and Selenium. I'm keeping every scenario totally independent of one another, as advised on the Cucumber website. However, my application has session based authentication, so every time a new scenario is run, it will required a login process in order to first access the site. Right now my approach is to put the login scenario as a background scenario for all other scenarios, like so:
Background: User is Logged In
Given I am on the login screen
When I enter my login details
And I click submit
Then I should be logged in
However, this feels like a lot of duplicated 'code'. Moreover, having each scenario run independently requires a new WebDriver instance being created and a browser being run for each scenario, which feels a bit inefficient?
Can anyone advise firstly on how I can avoid duplicating the background scenario in every other scenario (if possible) and secondly if having a separate WebDriver instance for each scenario is the correct approach?
First of all each of your scenarios is going to have to login and create a new session. Thats the price you pay to do end to end testing. The cost of this in runtime should be relatively small with a standard login process as most login screens are simple, and have short rendering times and very little db access. It really is a very bad idea to tray and save runtime here by trying to share sessions between scenarios.
To start tidying your cukes you could follow Daniel's answer, but instead of nesting the steps I would recommend extracting the code to a helper method and calling that instead.
To do this elegantly with power, i.e. deal with different users with roles and extra attributes you need to do a bit more. You can see a detailed example of this here (https://github.com/diabolo/cuke_up).
To use this effectively follow the commit history and focus mostly on the features folder.
This has some framework code that allows you to register/create users and then use them in lots of different configurations. There is some underlying code that is a little complex, which gives you the power to create users who know their own passwords, as well as add other attributes like roles.
The end result is that you can write a step definitions like
Given I am registered
Given I am an admin
Given I am logged in
Given I am logged in as an admin
which are implemented as
Given 'I am registered' do
#i = create_user
end
Given 'I am an admin' do
#i = create_user role: 'admin'
end
Given 'I am logged in' do
#i = create_user
login as: #i
end
Given 'I am logged in as an admin' do
#i = create_user role: 'admin'
login as: #i
end
note: the variable #i is used to pass the user from one step to the next
You don't have to worry about repetition here as all the steps make calls to the same helper methods. You can use the patterns shown here in a much wider context to simplify your features/
This example is in Ruby. You can group up the steps used for Login in login_steps.rb file.
In the .feature file you'll need to write a step like "Given the user is logged in". You can pass in login data in this step as well, if you want. Then in the login_steps.rb file, you create:
Given(/^the user is logged in$/) do
step('I am on the login screen')
step('I enter my login details')
step('I click submit')
step('I should be logged in')
end
I'm sure you can find the equivalent in any other language. Now you can write a the background like:
Background: Given the user is logged in
and it will be used before each scenario of that specific .feature file
As for the Webdriver, as far as I'm aware, you create a session when the test starts and you quit when it ends.
Hope it helps!

Using Background title as Background in cucumber

Let's say I use Background feature which has the below steps:
Background: My pre-requisites
Given Step one
When Step Two
Then Step Three
....
Then Step Fifteen
So basically my Background has 15 common steps that is required for a set of scenario to run.
My question is : Is it possible to use the Background title My pre-requisites in other feature files, instead of writing down all the 15 steps as Background? Or is there any other way to handle this more gracefully.
You can create a before hook to code the background logic and reuse it across any feature file. Even tag the hook so u can filter out scenarios where u do not want the before hook to run.
Alongside the existing answer, you could also write a new step that compresses the functionality of the 15 steps into one or two steps that express what you are setting up.
The questions revolving around it are these:
Does the business need to know how the user will interact with the site to get to the point where you are ready to begin the test?
Can you bypass how the user will interact with the site to get there without information surrounding the test getting lost in translation between the dev team and the business?
For the former, I would go with a Background. The latter, I would go with a Hook.
For example:
I need to register a user in order to log in as them in my test. The Givens will start at me logging in, so I'll register the user through an API in a Hook.
I need to register a user in order to test the functionality of a new user on exiting the form, and various items surrounding registration, so I'll register the user, starting with some Background steps.

Behat using BeforeScenario vs Given

For something that REALLY needs to be set up before every scenario then BeforeScenario is used.
Sometimes there are things that only need to be set up for some scenarios, but for a significant proportion of them. For example, if the scenario needs a "regular user account" to exist, then it goes on to login as that user and do some stuff.
You can make an #BeforeScenario #RegularUser method that will run for each Scenario tagged as #RegularUser. So scenarios end up looking like:
#RegularUser
Scenario login as a regular user
Given I am on the login page
When I login to a regular user account
Then the welcome screen is displayed
The alternative is to
Scenario login as a regular user
Given a regular user exists
And I am on the login page
When I login to a regular user account
Then the welcome screen is displayed
"a regular user exists" would be associated with the method that creates the regular user.
With the first approach, I can make #AfterScenario #RegularUser that will delete the user after the scenario ends. So that seems "a good thing".
But the 2nd approach kind of looks nicer to me from a BDD viewpoint. But its limitation is that then there is nothing happening at the end of the scenario to delete the user.
Which approach is the better practice?
In my opinion, i would go with first option.
The problem is that, both options are not so good, because normally you have context of this scenario added:
In order to ..
As a Regular User
I need to ..
That should show what was you intention of running this scenario. The process of creating RegularUser don't adding value to scenario itself.
Then, if you need to confirmation in scenario of having regular user - then is OK. But in here in my opinion, it is not the point - then second option is not so good - we have context to add informations like that.
That is why, I think first option (not ideal, but better that second) is good solution.
I don't know in Behat functionality to set up user by context, but tag option should be more elastic.

Cucumber - Javascript Invoke Login Step Definitions Before Other Step Definitions

Using Chimp.js, Cucumberjs and WebdriverIO, I'm trying to run login step definitions in a browser instance, before other step definitions that depend on a user to be logged in. And possibly without adding them into the Background over and over again for each feature file.
Is this possible? I'm quite new to Wedbdriver.io and Cucumber and any advice would be a great help. Please let me know if more info is needed.
Personally I don't think this is a good idea. To log someone in you have to specify 'who' the user is. Later when your application becomes more complex you might have interactions between different users. Hiding any of this from the scenario is not good.
What you can do is combine user specification and login in single steps e.g.
Given I am logged in as an admin
Given Fred is logged in as a sales executive
etc.
If you are clever about how you implement these steps you can keep things fairly dry by extracting helper methods from the step definitions and using global variables to store people e.g.
Given 'I am logged in as an admin' do
#i = create_user role: admin
login as: admin, user: #i
and reuse these methods in other login steps.
If you organise your features well, you can background alot of these calls e.g.
Feature: Basic admin ops
Background:
Given I am logged in as an admin
Scenario: I can foo
When I foo
Scenario: I can bar
When I bar
Some final thoughts ...
Each scenario is there to drive a particular piece of development. Compared to the work of doing the development writing "Given I am logged in" is trivial.
When something goes wrong knowing that you were supposed to be logged in is an essential piece of information.

Bypass login between each scenario?

I am using rspec/capybara here.
I'd like to be able to log into the system only once, then run a bunch of scenarios. Should a scenario fail, it can effectively move onto the next one.
The problem is that once a scenario fails, a new browser session is started and I am asked to log in again. Is there a way around this?
How is this type of testing handled? Many systems require a user to log in first prior to exercising all its functions/features.
So many ways to achieve this but I myself prefer a new instance per spec at least if not context or sometimes even it. I like atomic self contained tests.
Anyway, if you decide want to do this, then you could;
Reuse a cookie session between tests but still open a new browser. Obviously this depends upon the system under test
Create a global Before all which only creates a browser and sign in if you are not already signed in.
Create a global After all which navigates to a known state (eg. Home page) but doesn't log out.
There are many approaches which could work