How to make cucumber instantiating Custom World for every Feature instead of every Scenario? - bdd

I have a Feature where the Scenarios in the Feature file is logically interconnected - hence my Scenarios cannot be run independently.
Nice: I created a CustomWorld to let Cucumber create and destroy the instance of my framework by itself.
Bad: Cucumber creates and destroys the instance for every scenario. But I want it to be created and destroyed for every feature instead of scenarios.
Here is my feature file
Feature: Table Headers
Scenario: Check the default headers ### My framework instance created here
Given I log in to the application ### A setup
When I navigate to the list page
Then the table should have the below headers
| Default Headers |
| First Name |
| Last Name |
| Age |
Scenario: Add columns ### want to reuse the instance created above and destroy automatically after this scenario
When I add the below columns to display
| Headers |
| City |
| Country |
Then the table should have the below headers
| Default Headers |
| First Name |
| Last Name |
| Age |
| City |
| Country |
And I log out from the application ### A teardown
A bite of my framework:
When I create an instance of my class, a selenium webdriver instance would be created, opens a browser and launches URL.
The real problem: I want to open the browser and launch URL only once per feature and not for every scenario.

This is breaking the rules of BDD and cucumber. You should not have dependencies across Scenario. What I would suggest is that your Given or Background do the setup and that steps are NOT explicit.
Given I am on the list page
|Application|
|###|
Then the table should have the below headers
| Default Headers |
| First Name |
| Last Name |
| Age |
Given I am on the list page
|Application|
|###|
When I add the below columns to display
| Headers |
| City |
| Country |
Then the table should have the below headers
| Default Headers |
| First Name |
| Last Name |
| Age |
| City |
| Country |
Also your final And is not a step and should not be included in your Scenario it should be part of AfterHook

Related

Gherkin Scenario Outline using the same table multiple times

I'm writing a Scenario Outline in Specflow for Visual Studio. The objective is to test a Person Name comparer feature, in order to choose the best name between the two.
In my case, I have properties that belong to the names and properties external to them, which belong to the Person entity.
The comparison flow is mad in two parts: first I check the properties of the persons (owners of the names) to decide and if that doesn't yield me a result (meaning their properties are the same) then I check the names' properties.
I've written separate tests for the names' properties comparison, so in this test I only care about the Person properties and the relation between the names - which can be: Name1 < Name2, Name1 > Name2 or Name1 ≡ Name2.
By now I have written a scenario outline for each of those three cases, since I need to run each of the parameters in my Examples table once for each of those cases.
The code looks something like this:
Scenario Outline: Comparing names
Given I have a first name <name1>
And the first person has properties <properties1>
And I have a second name <name2>
And the second person has properties <properties2>
When I choose the best name
Then the best name should be <best name>
Examples:
| properties1 | properties2 |
| FirstName:"Carlos" | FirstName:"Johny" |
| LastName:"Smith" | FirstName:"Johny" |
| FirstName:"John",LastName:"Smith" | LastName:"Smith" |
Now in place of the names, I wrote this 3 times, one time for each case of the relation between the names, where I have the names hard-coded on the scenario.
Ideally, I would like to have a table of tables to be able to have a primary parameter that is ran with every line of the table.
Any idea how to implement that without having three different Scenario Outlines?
A SpecFlow table for creating each person might be the ideal solution. This allows you to pass values for each name, or a null value:
Scenario Outline: Comparing names
Given I have a first name <name1>
And the first person has properties:
| Field | Value |
| First Name | <first name 1> |
| Last Name | <last name 1> |
And I have a second name <name2>
And the second person has properties:
| Field | Value |
| First Name | <first name 2> |
| Last Name | <last name 2> |
When I choose the best name
Then the best name should be <best name>
Examples:
| name1 | first name 1 | last name 1 | first name 2 | last name 2| best name |
| X | Carlos | | Johnny | | X |
| X | | Smith | Johnny | | X |
| X | John | Smith | | Smith | X |
The advantage of this approach is you can expand the properties you set on each person.

Is it possible to generate example table for scenario in specflow?

The main problem is that example table is too long (below the example is a mock short, my real test would be ~300 lines). Is it possible to generate these table? I have mypage30.. it would be hard to maintain it
Scenario Outline: Check categories
Given I visit '<mypage>'
When I select '<category>'
Then the selected category is shown
Examples:
| mypage | category |
| page1 | mouse |
| page1 | cat |
| page1 | horse |
| page1 | do |
| page1 | duck |
| page2 | mouse |
| page2 | cat |
| page2 | horse |
| page2 | do |
| page2 | duck |
It's impossible to generate a content of .feature file automatically.
Yet I guess in your case you can make it other way.
One way is to store your table in .xlsx file and to use this file as a data source.
If you choose this option, it's very simply implemented in SpecFlow: https://specflow.org/plus/documentation/Prepare-feature-files-for-external-examples/
All you need is to specify the path to your source file:
#source:CalculatorExamples.xlsx
Examples:
| case | a | b | result |
Another way is to generate all the data within your test scenario. I don't know how you wanted to generate this table so I assume that the first way is better.

How to achieve conditional formatting of names between pages?

I have a Google Sheet with one page for team leaders to list their desired team members (first names, last names, emails) by row--each TL fills in one row--, and a second page where team members are listed who have actually registered with my program.
Page 1
+------------------------+------------+---------------+------------+--------------------+
| Team Leader First Name | First Name | Email Address | First Name | Email Address |
+------------------------+------------+---------------+------------+--------------------+
| Danielle | Elizabeth | XXX#tamu.edu | Matthew | XXX#tamu.edu |
| Stoian | William | XXX#tamu.edu | Victoria | XXX#email.tamu.edu |
| Christa | Olivia | XXX#tamu.edu | | |
+------------------------+------------+---------------+------------+--------------------+
Page 2
+--------------------+-------------------------+
| Scholar First Name | Scholar Preferred Email |
+--------------------+-------------------------+
| elizabeth | xxx#gmail.com |
| william | xxx#tamu.edu |
+--------------------+-------------------------+
I want to be able to see at a glance which of the names listed by the TL on pg 1 have not registered and thus don't appear on pg 2.
In the example above, I want Olivia, Matthew, and Victoria's names to appear red because she does not show up on pg2 (which means they still need to register). Everyone else should appear normally.
I tried at first to importrange from pg1 to get a clean list of the team members, then conditional formatting to match against pg2, the idea I had being it shows up red if a name is not found.
Import range from page 2 to page 1 the scholar first name to F12:F14
Conditional Formatting: Apply to range B2:B999(first name list in page 1)
=NOT(OR(ISNUMBER(MATCH(TRIM(B2),$F$12:$F$13,0)),ISBLANK(B2)))
Conditional Formatting2: Apply to range D2:D999(Second First name list)
=NOT(OR(ISNUMBER(MATCH(TRIM(D2),$F$12:$F$13,0)),ISBLANK(D2)))
Note: Instead of importing, You could also reference the second sheet using INDIRECT.

Behave - Common features between applications, avoiding duplication

I have many applications which I want to test, which have a largely overlapping set of features. Here is an oversimplified example of a scenario I might have:
Given <name> is playing a game,
When they shoot at a <color> target
Then they should <event>
Examples:
| name | color | event |
| Alice | red | hit |
| Alice | blue | miss |
| Bob | red | miss |
| Bob | blue | hit |
| Bob | green | hit |
It's a silly example, but suppose really I have a lot of players with different hit/miss conditions, and I want to run just the scenarios for a given name? Say, I only want to run the tests for Alice. There's still advantage to having all the hit/miss tests in a single Scenario Outline (since, after all, they're all closely related).
One approach would be to just duplicate the test for every name and tag them, so something like:
#Alice
Given Alice is playing a game
When she shoots at a <color> target
Then she should <event>
Examples:
| color | event |
| red | hit |
| blue | miss |
This way I can run behave --tags #Alice, But then I'm repeated the same scenario for every user, and that's a lot of duplication. Is there a good way to still compress all the examples into one scenario - but only selectively run some of them? What's the right approach here?
Version 1.2.5 introduced better ways to distinguish scenario outlines. It is now possible to uniquely distinguish them and thus select a unique scenario generated from an outline with --name= at the command line. For instance, suppose the following feature file:
Feature: test
Scenario Outline: test
Given <name> is playing a game,
When they shoot at a <color> target
Then they should <event>
Examples:
| name | color | event |
| Alice | red | hit |
| Alice | blue | miss |
| Bob | red | miss |
| Bob | blue | hit |
| Bob | green | hit |
Let's say I want to run only the test for Bob, red, miss. It is in the first table, 3rd row. So:
behave --name="#1.3"
will select this test. In version 1.2.5 and subsequent versions. A generated scenario gets a name which includes "#<table number>.<row number>" where <table number> is the number of the table (starting from 1) and <row number> is the number of the row.
This won't easily allow you to select all scenarios that pertain to a single user. However, you can achieve it in another way. You can split your examples in two:
Examples: Alice
| name | color | event |
| Alice | red | hit |
| Alice | blue | miss |
Examples: Bob
| name | color | event |
| Bob | red | miss |
| Bob | blue | hit |
| Bob | green | hit |
The table names will appear in the generated scenario names and you could ask behave to run all the tests associated with one table:
behave --name="Alice"
I do not know of a way to access the example name in steps and thus get rid of the first column.
The full set of details is in the release notes for 1.2.5.

Cucumber and DELETE with Mongoid

So, I am currently trying to test a Rails app wired up with Mongoid with Cucumber. I have everything setup (or so I believe) so that the following test will run:
Feature: Create and manage about entries
In order to use the about data effectively
As an application consumer
I want to create and manage some about entries
Scenario: Create about entries
Given the following abouts exist
| title | body_copy |
| "About entry #1" | "hello body!" |
When I go to the list of about entries
Then I should see "About entry #1"
Scenario: Create and retreive specific about entry
Given the following abouts exist
| id | title | body_copy |
| 4e4d37756ea257f031000003 | "About entry #1" | "hello body!" |
When I go to about entry with id 4e4d37756ea257f031000003
Then I should see "About entry #1"
In my paths file, I have the following entries to support the above tests:
when /^the list of about entries$/i
'/abouts'
when /^about entry with id (.+)$/i
"/abouts/#{$1}"
These tests work great. However, I need to test the delete action. I did some research online but everything seems to be going through the UI to delete these items and the problem I have is that my Rails app only serves JSON files and JSON files and I need a better (more programatic) way of testing things without the UI being involved. As far as mocks goes, I am using the default mocks built into Pickle. I am open to using other mocking software if necessary such as factory-girl, but you'll have to give me some detailed feedback how I can wire that up. What I have currently for my delete test (that DOESN'T work) is:
Scenario: Delete about
Given the following abouts exist
| title | body_copy |
| title 1 | body_copy 1 |
| title 2 | body_copy 2 |
| title 3 | body_copy 3 |
| title 4 | body_copy 4 |
When I delete the 3rd about
Then I should see the following abouts:
| Title | body_copy |
| title 1 | body_copy 1 |
| title 2 | body_copy 2 |
| title 4 | body_copy 4 |
The problem is that the auto-generated test (seen above) uses the click_link "Destroy" method call but that will not work.
You'll need to change the implementation of the delete step (in your web_steps.rb if your using the Cucumber generated defaults) to send a DELETE HTTP request. I'd recommend the RestClient gem for this, but there are plenty other choices.
The Cucumber Book currently in beta from PragProg has a chapter about using Cucumber to test REST APIs like this.

Resources