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?

2 Answers

Daniel Fintinariu On

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')

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!

diabolist On

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

Given 'I am an admin' do
  @i = create_user role: 'admin'

Given 'I am logged in' do
  @i = create_user
  login as: @i

Given 'I am logged in as an admin' do
  @i = create_user role: 'admin'
  login as: @i

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/