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!!
Related
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.
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#%& |
I have a scenario to validate 100 employee names, The QueryString will return them in xml format.All I want to do is to validate all the employee names in an Assertion statement like given below. Instead of adding each name in the Scenario Outline Example, Is it possible to send a list of 100 employee names as input so that I can Iterate through them in java and could easily validate in Assertion condition. Please advice.
Scenario Outline: When the User queries for employee information, the correct records are returned
Given the webservice is running
When the User queries for employee information "<QueryString>"
Then the User receives correct data "<Name>"
Examples:
|QueryString|Name|
|Some localhost url|Peter|
|Some localhost url|Sam|
.
.
#Then("^the User receives correct data\"([^\"]*)\"$")
public void the_user_receives_correct_data(String arg1) throws Throwable {
queryResultPage = selenium.getPageSource();
assertTrue(queryResultPage.contains(arg1));
}
so i will answere here to LINGS comment
What you can do, is use these filenames in your step definition to load the files in your code. Cucumber doesnt support direct file loading as far as i know.
i use something like this to locate full ressource pathes for my relative path file names:
public static String getAbsoluteResourcePath(String resourcePath) {
if (SystemUtils.IS_OS_WINDOWS) {
return Utils.class.getResource(resourcePath).getPath().substring(1).replace("/", File.separator);
} else {
return Utils.class.getResource(resourcePath).getPath().replace("/", File.separator);
}
}
The resourcePath should then be your relative file path
What you are looking for is external test data support, which is supported with QAF. You can use any inbuilt data provider with interceptor to modify data set or custom data provider.
If you are using cucumber version 5+ you can use qaf-cucumber that will give you all qaf features with cucumber. For lower version you can run your existing feature files with QAF runner.
I'm new to cucumber, but enjoying it.
I'm currently writing some Frank tests, and would like to reuse blocks of cucumber script across multiple features - I'd like to do this a the cucumber level if possible (not inside the ruby).
For example, I might have 4 scripts that all start by doing the same login steps:
given my app has started
then enter "guest" in "user-field"
and enter "1234" in "password-field"
and press "login"
then I will see "welcome"
then *** here's the work specific to each script ***
Is there any way to share these first 5 lines across multiple scripts? Some kind of "include" syntax?
Generally there are 2 approaches:
Backgrounds
If you want a set of steps to run before each of the scenarios in a feature file:
Background:
given my app has started
then enter "guest" in "user-field"
and enter "1234" in "password-field"
and press "login"
then I will see "welcome"
Scenario: Some scenario
then *** here's the work specific to this scenario ***
Scenario: Some other scenario
then *** here's the work specific to this scenario ***
Calling steps from step definitions
If you need the 'block' of steps to be used in different feature files, or a Background section is not suitable because some scenarios don't need it, then create a high-level step definition which calls the other ones:
Given /^I have logged in$/ do
steps %Q {
given my app has started
then enter "guest" in "user-field"
and enter "1234" in "password-field"
and press "login"
then I will see "welcome"
}
end
Also, in this case I'd be tempted not to implement your common steps as separate steps at all, but to create a single step definition: (assuming Capybara)
Given /^I have logged in$/ do
fill_in 'user-field', :with => 'guest'
fill_in 'password-field', :with => '1234'
click_button 'login'
end
This lends a little bit more meaning to your step definitions, rather than creating a sequence of page interactions which need to be mentally parsed before you realise 'oh, this section is logging me in'.
A better approach is suggested to use ruby level "methods" to code reuse instead of nested steps from code maintenance and debugging perspective.
Here is the link to more detail:
Reuse Cucumber steps
Description
The following method proposes an alternative approach to one of the solutions described in Jon M's answer.
Namely, instead of calling nested steps inside step definitions, such common blocks of steps can be extracted into external .feature files which can be included into your feature file (in a manner of speaking).
How-to
1. Expose utility / helper methods to be able to run steps parsed from a .feature file
# features/support/env.rb
# expose Cucumber runtime
InstallPlugin do |_, registry|
runtime = registry.instance_variable_get('#registry').instance_variable_get('#runtime')
Cucumber.define_singleton_method(:runtime) { runtime }
end
# extend current World with methods to run dynamic (already parsed) steps
Before do
step_invoker = Cucumber::Runtime::SupportCode::StepInvoker.new(Cucumber.runtime.support_code)
define_singleton_method(:dynamic_steps) do |steps|
steps.each do |step|
dynamic_step(step)
end
end
define_singleton_method(:dynamic_step) do |step|
LOGGER.info("Running template step: #{step[:text]}")
step_invoker.step(step)
end
end
2. Create a template file which will contain the steps to be shared
# features/templates/my_profile.template.feature
#template
Feature: Steps to navigate to my_profile_page
Scenario: login_page
Given my app has started on "login_page"
And I enter "guest" in "user-field" on "login_page"
And I enter "1234" in "password-field" on "login_page"
And I press "login" on "login_page" and go to "welcome_page"
Scenario: welcome_page
Given that I am on "welcome_page"
And I click "my_profile_button" on "welcome_page" and go to "my_profile_page"
Scenario: my_profile_page
...
3. Create an utility module which will parse steps from a .feature file
# features/support/template_parser.rb
require 'gherkin/parser'
require 'gherkin/pickles/compiler'
module TemplateParser
class << self
def read_from_template(template_path, from: nil, till: nil)
pickles = load_template(template_path)
flow = construct_flow(pickles)
slice_flow(flow, from, till)
end
private
def load_template(template_path)
source = {
uri: template_path,
data: File.read(template_path),
mediaType: 'text/x.cucumber.gherkin+plain'
}
def source.uri
self[:uri]
end
gherkin_document = Gherkin::Parser.new.parse(source[:data])
id_generator = Cucumber::Messages::IdGenerator::UUID.new
Gherkin::Pickles::Compiler.new(id_generator).compile(gherkin_document, source)
end
def construct_flow(pickles)
pickles.to_h do |pickle|
[
pickle.name,
pickle.steps.map(&:to_h).map { |step| step[:argument] ? step.merge(step[:argument]) : step }
]
end
end
def slice_flow(flow, from, till)
raise NameError, "From step '#{from}' does not exist!" unless from.nil? || flow.keys.include?(from)
raise NameError, "Till step '#{till}' does not exist!" unless till.nil? || flow.keys.include?(till)
from_idx = from.nil? ? 0 : flow.keys.index(from)
till_idx = till.nil? ? -1 : flow.keys.index(till)
flow.slice(*flow.keys[from_idx...till_idx])
end
end
end
4. Create a step definition that will load this template and inject the specified steps dynamically at runtime
And('I complete the {string} template from the {string} until the {string}') do |template, from, till|
template_path = "features/templates/#{template}.template.feature"
flow = TemplateParser.read_from_template(
template_path,
from: from.empty? ? nil : from,
till: till.empty? ? nil : till
)
flow.each_value { |steps| dynamic_steps(steps) }
end
5. Use this step inside your main feature file, by declaring which blocks of steps to use
# features/tests/welcome.feature
Feature: User is welcomed
Scenario: Verify that user sees welcome text
Given I complete the 'my_profile' template from the 'login_page' until the 'my_profile_page'
Then I see 'welcome' on 'welcome_page'
6. Make sure you omit the #template .feature files from being run in your tests
$ bundle exec cucumber --tags ~#template
Limitations
Con:
This method exposes some internals of the private API of cucumber-ruby, which may change in future.
Con:
This is a non-standard way of sharing steps between feature files.
Helper methods are the preferred way to achieve this, as per FAQ.
Pro:
The common blocks of steps are syntax-highlighted, and have proper IntelliSense support in your editor of choice.
Pro:
You can encode entire "workflows" easily this way, allowing you to encode your workflow expectations in a DRY way.
Namely, you can reuse those workflow steps by completing the first part of a workflow, change a few things on a single page as per your test requirements, resume those workflow steps from the follow-up page, and add an appropriate verification at the end of the workflow that covers those test requirements.
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.