Expand All
Collapse All
In order to build tools on top of Cucumber
As a tool developer
I want to be able to query a features directory for all the step definitions it contains
Given(/foo/i) { }
Given(/b.r/xm) { }require 'cucumber' puts Cucumber::StepDefinitions.new.to_json
[
{"source": "foo", "flags": "i"},
{"source": "b.r", "flags": "mx"}
]Given(/foo/) { }
Given(/b.r/x) { }require 'cucumber' puts Cucumber::StepDefinitions.new(:autoload_code_paths => ['my_weird']).to_json
[
{"source": "foo", "flags": ""},
{"source": "b.r", "flags": "x"}
]
This is the API that Spork uses. It creates an existing runtime then
calls load_programming_language('rb') on it to load the RbDsl.
When the process forks, Spork them passes the runtime to Cli::Main to
run it.
Feature:
Scenario:
Given this step passesrequire 'cucumber'
runtime = Cucumber::Runtime.new
runtime.load_programming_language('rb')
Cucumber::Cli::Main.new([]).execute!(runtime)
Given this step passes
Dry run gives you a way to quickly scan your features without actually running them.
- Invokes formatters without executing the steps.
- This also omits the loading of your support/env.rb file if it exists.
Feature: test
Scenario:
Given this step failsFeature: test
Scenario: # features/test.feature:2
Given this step fails # features/step_definitions/steps.rb:4
1 scenario (1 skipped)
1 step (1 skipped)
Feature: test
Scenario:
Given this step failsFeature: test
Scenario: # features/test.feature:2
Given this step fails # features/step_definitions/steps.rb:4
1 scenario (1 skipped)
1 step (1 skipped)
Feature: test
Scenario:
Given this step is undefinedFeature: test
Scenario: # features/test.feature:2
Given this step is undefined # features/test.feature:3
Undefined step: "this step is undefined" (Cucumber::Undefined)
features/test.feature:3:in `Given this step is undefined'
1 scenario (1 undefined)
1 step (1 undefined)
Developers are able to easily exclude files from cucumber runs
This is a nice feature to have in conjunction with profiles, so you can exclude
certain environment files from certain runs.
In order to conveniently run subsets of features
As a Cuker
I want to select features using logical AND/OR of tags
@feature
Feature: Sample
@one @three
Scenario: Example
Given passing
@one
Scenario: Another Example
Given passing
@three
Scenario: Yet another Example
Given passing
@ignore
Scenario: And yet another Example@feature
Feature: Sample
@one @three
Scenario: Example
Given passing
1 scenario (1 undefined)
1 step (1 undefined)
@feature
Feature: Sample
@one @three
Scenario: Example
Given passing
@one
Scenario: Another Example
Given passing
@three
Scenario: Yet another Example
Given passing
3 scenarios (3 undefined)
3 steps (3 undefined)
@feature
Feature: Sample
@one
Scenario: Another Example
Given passing
@ignore
Scenario: And yet another Example
2 scenarios (1 undefined, 1 passed)
1 step (1 undefined)@one occurred 2 times, but the limit was set to 1 features/test.feature:5 features/test.feature:9
@feature occurred 4 times, but the limit was set to 1 features/test.feature:5 features/test.feature:9 features/test.feature:13 features/test.feature:17
@one occurred 2 times, but the limit was set to 1
As a User
In order to run features in subdirectories without having to pass extra options
I want cucumber to load all step files
Feature: Feature in Subdirectory
Scenario: A step not in the subdirectory
Given not found in subdirectoryGiven(/^not found in subdirectory$/) { }Feature: Feature in Subdirectory
Scenario: A step not in the subdirectory
Given not found in subdirectory
1 scenario (1 passed)
1 step (1 passed)
Use the `--order random` switch to run scenarios in random order.
This is especially helpful for detecting situations where you have state
leaking between scenarios, which can cause flickering or fragile tests.
If you do find a randmon run that exposes dependencies between your tests,
you can reproduce that run by using the seed that's printed at the end of
the test run.
Feature: Bad practice
Scenario: Set state
Given I set some state
Scenario: Depend on state
When I depend on the stateGiven(/^I set some state$/) do $global_state = "set" end Given(/^I depend on the state$/) do raise "I expect the state to be set!" unless $global_state == "set" end
Randomized with seed 41515
Cucumber allows you to require extra files using the `-r` option.
Feature: Sample
Scenario: Sample
Given found in extra fileGiven(/^found in extra file$/) { }Feature: Sample
Scenario: Sample
Given found in extra file
1 scenario (1 passed)
1 step (1 passed)
The `--name NAME` option runs only scenarios which match a certain
name. The NAME can be a substring of the names of Features, Scenarios,
Scenario Outlines or Example blocks.
Feature: first feature
Scenario: foo first
Given missing
Scenario: bar first
Given missingFeature: second
Scenario: foo second
Given missing
Scenario: bar second
Given missingFeature: outline
Scenario Outline: baz outline
Given outline step <name>
Examples: quux example
| name |
| a |
| b |Feature: first feature
Scenario: foo first
Given missing
Scenario: bar first
Given missing
2 scenarios (2 undefined)
2 steps (2 undefined)Feature: first feature
Scenario: foo first
Given missing
Feature: second
Scenario: foo second
Given missing
2 scenarios (2 undefined)
2 steps (2 undefined)Feature: outline
Scenario Outline: baz outline
Given outline step <name>
Examples: quux example
| name |
| a |
| b |
2 scenarios (2 undefined)
2 steps (2 undefined)Feature: outline
Scenario Outline: baz outline
Given outline step <name>
Examples: quux example
| name |
| a |
| b |
2 scenarios (2 undefined)
2 steps (2 undefined)
You can choose to run a specific scenario using the file:line format,
or you can pass in a file with a list of scenarios using @-notation.
The line number can fall anywhere within the body of a scenario, including
steps, tags, comments, description, data tables or doc strings.
For scenario outlines, if the line hits one example row, just that one
will be run. Otherwise all examples in the table or outline will be run.
Feature:
Scenario: Miss
Given this step is undefined
Scenario: Hit
Given this step passesFeature:
Scenario: Hit
Given this step passes
1 scenario (1 passed)
1 step (1 passed)
Feature: Sample
Scenario: Passing
Given this step passesfeatures/test.feature:2
Feature: Sample
Scenario: Passing
Given this step passes
1 scenario (1 passed)
1 step (1 passed)Feature:
Scenario:
Given this step passes
Scenario:
Given this step failsF.
Cucumber will helpfully show you the expectation error that your
testing library gives you, in the context of the failing scenario.
When using RSpec, for example, this will show the difference between
the expected and the actual output.
Feature: Failing expectation
Scenario: Failing expectation
Given failing expectationGiven /^failing expectation$/ do x=1
expect('this').to eq 'that'
endFeature: Failing expectation
Scenario: Failing expectation
Given failing expectation
expected: "that"
got: "this"
(compared using ==)
(RSpec::Expectations::ExpectationNotMetError)
./features/step_definitions/steps.rb:2:in `/^failing expectation$/'
features/failing_expectation.feature:4:in `Given failing expectation'
Failing Scenarios:
cucumber features/failing_expectation.feature:3
1 scenario (1 failed)
1 step (1 failed)
When running cucumber, you are able to using multiple different
formatters and redirect the output to text files.
Two formatters cannot both print to the same file (or to STDOUT)
Feature: Lots of undefined
Scenario: Implement me
Given it snows in Sahara
Given it's 40 degrees in Norway
And it's 40 degrees in Norway
When I stop procrastinating
And there is world peaceUUUUU 1 scenario (1 undefined) 5 steps (5 undefined)
Feature: Lots of undefined
Scenario: Implement me
Given it snows in Sahara
Given it's 40 degrees in Norway
And it's 40 degrees in Norway
When I stop procrastinating
And there is world peace
1 scenario (1 undefined)
5 steps (5 undefined)
All but one formatter must use --out, only one can print to each stream (or STDOUT) (RuntimeError)
default: -q
All but one formatter must use --out, only one can print to each stream (or STDOUT) (RuntimeError)
Using the `--strict` flag will cause cucumber to fail unless all the
step definitions have been defined.
Feature: Missing
Scenario: Missing
Given this step passesFeature: Pending
Scenario: Pending
Given this step is pendingFeature: Missing
Scenario: Missing
Given this step passes
Undefined step: "this step passes" (Cucumber::Undefined)
features/missing.feature:3:in `Given this step passes'
1 scenario (1 undefined)
1 step (1 undefined)Feature: Pending
Scenario: Pending
Given this step is pending
TODO (Cucumber::Pending)
./features/step_definitions/steps.rb:3:in `/^this step is pending$/'
features/pending.feature:3:in `Given this step is pending'
1 scenario (1 pending)
1 step (1 pending)Feature: Missing
Scenario: Missing
Given this step passes
1 scenario (1 passed)
1 step (1 passed)Given two turtles
Given /a turtle/ do puts "turtle!" end
Given /two turtles/ do
steps %{
Given a turtle
And a turtle
}
endturtle! turtle!
Given /two turtles/ do step "a turtle" step "a turtle" end
turtle! turtle!
Given /turtles:/ do |table|
table.hashes.each do |row|
puts row[:name]
end
endGiven /two turtles/ do
steps %{
Given turtles:
| name |
| Sturm |
| Liouville |
}
endSturm Liouville
Given /two turtles/ do
steps %Q{
Given turtles:
"""
Sturm
Liouville
"""
}
endGiven /turtles:/ do |string| puts string end
Sturm Liouville
Given /two turtles/ do
step "I have a couple turtles"
end
When(/I have a couple turtles/) { raise 'error' }error (RuntimeError) ./features/step_definitions/steps2.rb:5:in `/I have a couple turtles/' ./features/step_definitions/steps2.rb:2:in `/two turtles/' features/test_feature_1.feature:3:in `Given two turtles' Failing Scenarios: cucumber features/test_feature_1.feature:2 # Scenario: Test Scenario 1 1 scenario (1 failed) 1 step (1 failed)
Feature: Calling undefined step
Scenario: Call directly
Given a step that calls an undefined step
Scenario: Call via another
Given a step that calls a step that calls an undefined stepGiven /^a step that calls an undefined step$/ do step 'this does not exist' end Given /^a step that calls a step that calls an undefined step$/ do step 'a step that calls an undefined step' end
Feature: Calling undefined step
Scenario: Call directly
Given a step that calls an undefined step
Undefined dynamic step: "this does not exist" (Cucumber::UndefinedDynamicStep)
./features/step_definitions/steps.rb:2:in `/^a step that calls an undefined step$/'
features/call_undefined_step_from_step_def.feature:4:in `Given a step that calls an undefined step'
Scenario: Call via another
Given a step that calls a step that calls an undefined step
Undefined dynamic step: "this does not exist" (Cucumber::UndefinedDynamicStep)
./features/step_definitions/steps.rb:2:in `/^a step that calls an undefined step$/'
./features/step_definitions/steps.rb:6:in `/^a step that calls a step that calls an undefined step$/'
features/call_undefined_step_from_step_def.feature:7:in `Given a step that calls a step that calls an undefined step'
Failing Scenarios:
cucumber features/call_undefined_step_from_step_def.feature:3
cucumber features/call_undefined_step_from_step_def.feature:6
2 scenarios (2 failed)
2 steps (2 failed)
前提 two turtles
# -*- coding: utf-8 -*- 前提 /a turtle/ do puts "turtle!" end
# -*- coding: utf-8 -*-
前提 /two turtles/ do
steps %{
前提 a turtle
かつ a turtle
}
endturtle! turtle!
Given two turtles
Given /turtles:/ do |table|
table.hashes.each do |row|
puts row[:name]
end
endGiven /two turtles/ do
step %{turtles:}, table(%{
| name |
| Sturm |
| Liouville |
})
endSturm Liouville
Given /two turtles/ do
step %{turtles:}, "Sturm and Lioville"
endGiven /turtles:/ do |text| puts text end
Sturm and Lioville
Given /two turtles/ do
step %{turtles:}, doc_string('Sturm and Lioville','math')
endGiven /turtles:/ do |text| puts text.content_type end
math
Everybody knows you can do step definitions in Cucumber
but did you know you can do this?
module Driver
def do_action
@done = true
end
def assert_done
expect(@done).to be true
end
end
World(Driver)
When /I do the action/, :do_action
Then /The action should be done/, :assert_doneFeature:
Scenario:
When I do the action
Then the action should be doneclass Thing
def do_action
@done = true
end
def assert_done
expect(@done).to be true
end
end
module Driver
def thing
@thing ||= Thing.new
end
end
World(Driver)
When /I do the action to the thing/, :do_action, :on => lambda { thing }
Then /The thing should be done/, :assert_done, :on => lambda { thing }Feature:
Scenario:
When I do the action to the thing
Then the thing should be done
When you want to print to Cucumber's output, just call `puts` from
a step definition. Cucumber will grab the output and print it via
the formatter that you're using.
Your message will be printed out after the step has run.
Given /^I use puts with text "(.*)"$/ do |ann|
puts(ann)
end
Given /^I use multiple putss$/ do
puts("Multiple")
puts("Announce","Me")
end
Given /^I use message (.+) in line (.+) (?:with result (.+))$/ do |ann, line, result|
puts("Last message") if line == "3"
puts("Line: #{line}: #{ann}")
fail if result =~ /fail/i
end
Given /^I use puts and step fails$/ do
puts("Announce with fail")
fail
end
Given /^I puts the world$/ do
puts(self)
endFeature:
Scenario:
Given I use puts with text "Ann"
And this step passes
Scenario:
Given I use multiple putss
And this step passes
Scenario Outline:
Given I use message <ann> in line <line>
Examples:
| line | ann |
| 1 | anno1 |
| 2 | anno2 |
| 3 | anno3 |
Scenario:
Given I use puts and step fails
And this step passes
Scenario Outline:
Given I use message <ann> in line <line> with result <result>
Examples:
| line | ann | result |
| 1 | anno1 | fail |
| 2 | anno2 | pass |Feature: puts_world
Scenario: puts_world
Given I puts the world# Don't know why, but we need to spawn this for JRuby otherwise it gives wierd errors@spawnfeatures/docs/defining_steps/printing_messages.feature:80
Feature:
Scenario:
Given I use puts with text "Ann"
Ann
And this step passes
Scenario:
Given I use multiple putss
Multiple
Announce
Me
And this step passes
Scenario Outline:
Given I use message <ann> in line <line>
Examples:
| line | ann |
| 1 | anno1 |
| 2 | anno2 |
| 3 | anno3 |
Scenario:
Given I use puts and step fails
Announce with fail
(RuntimeError)
./features/step_definitions/puts_steps.rb:18:in `/^I use puts and step fails$/'
features/f.feature:21:in `Given I use puts and step fails'
And this step passes
Scenario Outline:
Given I use message <ann> in line <line> with result <result>
Examples:
| line | ann | result |
| 1 | anno1 | fail | Line: 1: anno1
(RuntimeError)
./features/step_definitions/puts_steps.rb:13:in `/^I use message (.+) in line (.+) (?:with result (.+))$/'
features/f.feature:29:in `Given I use message anno1 in line 1 with result fail'
features/f.feature:25:in `Given I use message <ann> in line <line> with result <result>'
| 2 | anno2 | pass | Line: 2: anno2Ann .. Multiple Announce Me ..UUU Announce with fail F- Line: 1: anno1 F Line: 2: anno2 .
Feature: test
Scenario: test
Given this step says to skip
And this step passesGiven /skip/ do skip_this_scenario end
Feature: test
Scenario: test
Given this step says to skip
And this step passes
1 scenario (1 skipped)
2 steps (2 skipped)
Feature: test
Scenario: test
Given this step passes
And this step passesBefore do |scenario| scenario.skip_invoke! end
Feature: test
Scenario: test
Given this step passes
And this step passes
1 scenario (1 skipped)
2 steps (2 skipped)
Cucumber helpfully prints out any undefined step definitions as a code
snippet suggestion, which you can then paste into a step definitions
file of your choosing.
Feature:
Scenario: pystring
Given a pystring
"""
example with <html> entities
"""
When a simple when step
And another when step
Then a simple then stepGiven(/^a pystring$/) do |string| pending # Write code here that turns the phrase above into concrete actions end When(/^a simple when step$/) do pending # Write code here that turns the phrase above into concrete actions end When(/^another when step$/) do pending # Write code here that turns the phrase above into concrete actions end Then(/^a simple then step$/) do pending # Write code here that turns the phrase above into concrete actions end
Feature:
Scenario: table
Given a table
| table |
|example|Given(/^a table$/) do |table| # table is a Cucumber::Core::Ast::DataTable pending # Write code here that turns the phrase above into concrete actions end
To allow you to more easily compare data in tables, you are able
to easily diff a table with expected data and see the diff in your
output.
Feature: Tables
Scenario: Extra row
Then the table should be:
| x | y |
| a | b |Then /the table should be:/ do |expected| x=1
expected.diff!(table(%{
| x | y |
| a | c |
}))
endFeature: Tables
Scenario: Extra row # features/tables.feature:2
Then the table should be: # features/step_definitions/steps.rb:1
| x | y |
| a | b |
Tables were not identical:
| x | y |
| (-) a | (-) b |
| (+) a | (+) c |
(Cucumber::MultilineArgument::DataTable::Different)
./features/step_definitions/steps.rb:2:in `/the table should be:/'
features/tables.feature:3:in `Then the table should be:'
Failing Scenarios:
cucumber features/tables.feature:2 # Scenario: Extra row
1 scenario (1 failed)
1 step (1 failed)
0m0.012s
If you see certain phrases repeated over and over in your step definitions, you can
use transforms to factor out that duplication, and make your step definitions simpler.
Feature:
Scenario:
Given a Person aged 15 with blonde hairclass Person
attr_accessor :age
def to_s
"I am #{age} years old"
end
endTransform(/a Person aged (\d+)/) do |age| person = Person.new person.age = age.to_i person end Given /^(a Person aged \d+) with blonde hair$/ do |person| expect(person.age).to eq 15 end
A_PERSON = Transform(/a Person aged (\d+)/) do |age|
person = Person.new
person.age = age.to_i
person
end
Given /^(#{A_PERSON}) with blonde hair$/ do |person|
expect(person.age).to eq 15
endIn order to use custom assertions at the end of each scenario
As a developer
I want exceptions raised in After blocks to be handled gracefully and reported by the formatters
Given /^this step does something naughty$/ do x=1 @naughty = true end
class NaughtyScenarioException < Exception; end
After do
if @naughty
raise NaughtyScenarioException.new("This scenario has been very very naughty")
end
endFeature: Sample
Scenario: Naughty Step
Given this step does something naughty
Scenario: Success
Given this step passesFeature: Sample
Scenario: Naughty Step # features/naughty_step_in_scenario.feature:3
Given this step does something naughty # features/step_definitions/naughty_steps.rb:1
This scenario has been very very naughty (NaughtyScenarioException)
./features/support/env.rb:4:in `After'
Scenario: Success # features/naughty_step_in_scenario.feature:6
Given this step passes # features/step_definitions/steps.rb:1
Failing Scenarios:
cucumber features/naughty_step_in_scenario.feature:3 # Scenario: Naughty Step
2 scenarios (1 failed, 1 passed)
2 steps (2 passed)
Feature: Sample
Scenario Outline: Naughty Step
Given this step <Might Work>
Examples:
| Might Work |
| passes |
| does something naughty |
| passes |
Scenario: Success
Given this step passes
Feature: Sample
Scenario Outline: Naughty Step
Given this step <Might Work>
Examples:
| Might Work |
| passes |
| does something naughty |
This scenario has been very very naughty (NaughtyScenarioException)
./features/support/env.rb:4:in `After'
| passes |
Scenario: Success
Given this step passes
Failing Scenarios:
cucumber features/naughty_step_in_scenario_outline.feature:9
4 scenarios (1 failed, 3 passed)
4 steps (4 passed)
Feature: Sample
Scenario: Naughty Step
Given this step does something naughty
Scenario: Success
Given this step passes.F. Failing Scenarios: cucumber features/naughty_step_in_scenario.feature:3 # Scenario: Naughty Step 2 scenarios (1 failed, 1 passed) 2 steps (2 passed)
In order to use custom assertions at the end of each step
As a developer
I want exceptions raised in AfterStep blocks to be handled gracefully and reported by the formatters
Given /^this step does something naughty$/ do x=1 @naughty = true end
class NaughtyStepException < Exception; end
AfterStep do
if @naughty
raise NaughtyStepException.new("This step has been very very naughty")
end
endFeature: Sample
Scenario: Naughty Step
Given this step does something naughty
Scenario: Success
Given this step passesFeature: Sample
Scenario: Naughty Step # features/naughty_step_in_scenario.feature:3
Given this step does something naughty # features/step_definitions/naughty_steps.rb:1
This step has been very very naughty (NaughtyStepException)
./features/support/env.rb:4:in `AfterStep'
features/naughty_step_in_scenario.feature:4:in `Given this step does something naughty'
Scenario: Success # features/naughty_step_in_scenario.feature:6
Given this step passes # features/step_definitions/steps.rb:1
Failing Scenarios:
cucumber features/naughty_step_in_scenario.feature:3 # Scenario: Naughty Step
2 scenarios (1 failed, 1 passed)
2 steps (2 passed)
Feature: Sample
Scenario Outline: Naughty Step
Given this step <Might Work>
Examples:
| Might Work |
| passes |
| does something naughty |
| passes |
Scenario: Success
Given this step passes
Feature: Sample
Scenario Outline: Naughty Step # features/naughty_step_in_scenario_outline.feature:3
Given this step <Might Work> # features/naughty_step_in_scenario_outline.feature:4
Examples:
| Might Work |
| passes |
| does something naughty |
This step has been very very naughty (NaughtyStepException)
./features/support/env.rb:4:in `AfterStep'
features/naughty_step_in_scenario_outline.feature:9:in `Given this step does something naughty'
features/naughty_step_in_scenario_outline.feature:4:in `Given this step <Might Work>'
| passes |
Scenario: Success # features/naughty_step_in_scenario_outline.feature:12
Given this step passes # features/step_definitions/steps.rb:1
Failing Scenarios:
cucumber features/naughty_step_in_scenario_outline.feature:9 # Scenario Outline: Naughty Step, Examples (#2)
4 scenarios (1 failed, 3 passed)
4 steps (4 passed)
Around hooks are awkward beasts to handle internally.
Right now, if there's an error in your Around hook before you call `block.call`,
we won't even print the steps for the scenario.
This is because that `block.call` invokes all the logic that would tell Cucumber's
UI about the steps in your scenario. If we never reach that code, we'll never be
told about them.
There's another scenario to consider, where the exception occurs after the steps
have been run. How would we want to report in that case?
Around do |scenario, block| fail "this should be reported" block.call end
Feature:
Scenario:
Given this step passesFeature: Scenario: this should be reported (RuntimeError) ./features/support/env.rb:2:in `Around' Failing Scenarios: cucumber features/test.feature:2 1 scenario (1 failed) 0 steps
Around do |scenario, block| block.call fail "this should be reported" end
Feature:
Scenario:
Given this step passesFeature:
Scenario:
Given this step passes
this should be reported (RuntimeError)
./features/support/env.rb:3:in `Around'
Failing Scenarios:
cucumber features/test.feature:2
1 scenario (1 failed)
1 step (1 passed)
In order to know with confidence that my before blocks have run OK
As a developer
I want exceptions raised in Before blocks to be handled gracefully and reported by the formatters
class SomeSetupException < Exception; end
class BadStepException < Exception; end
Before do
raise SomeSetupException.new("I cannot even start this scenario")
endFeature: Sample
Scenario: Run a good step
Given this step passesFeature: Sample
Scenario: Run a good step # features/naughty_step_in_scenario.feature:3
I cannot even start this scenario (SomeSetupException)
./features/support/env.rb:4:in `Before'
Given this step passes # features/step_definitions/steps.rb:1
Failing Scenarios:
cucumber features/naughty_step_in_scenario.feature:3 # Scenario: Run a good step
1 scenario (1 failed)
1 step (1 skipped)
Feature: Sample
Background:
Given this step passes
Scenario: Run a good step
Given this step passesFeature: Sample
Background: # features/naughty_step_in_before.feature:3
I cannot even start this scenario (SomeSetupException)
./features/support/env.rb:4:in `Before'
Given this step passes # features/step_definitions/steps.rb:1
Scenario: Run a good step # features/naughty_step_in_before.feature:6
Given this step passes # features/step_definitions/steps.rb:1
Failing Scenarios:
cucumber features/naughty_step_in_before.feature:6 # Scenario: Run a good step
1 scenario (1 failed)
2 steps (2 skipped)
0m0.012s
Feature: Sample
Scenario: Run a good step
Given this step passesF- Failing Scenarios: cucumber features/naughty_step_in_scenario.feature:3 # Scenario: Run a good step 1 scenario (1 failed) 1 step (1 skipped)
Feature:
Scenario:
Given my special steprequire 'cucumber/core/filter'
MakeAnythingPass = Cucumber::Core::Filter.new do
def test_case(test_case)
activated_steps = test_case.test_steps.map do |test_step|
test_step.with_action { }
end
test_case.with_steps(activated_steps).describe_to receiver
end
end
AfterConfiguration do |config|
config.filters << MakeAnythingPass.new
endFeature: I'll use my own
Scenario: Just print me
Given this step passesmodule MyCustom
class Formatter
def initialize(runtime, io, options)
@io = io
end
def before_test_case(test_case)
feature = test_case.source.first
scenario = test_case.source.last
@io.puts feature.short_name.upcase
@io.puts " #{scenario.name.upcase}"
end
end
endI'LL USE MY OWN JUST PRINT ME
module MyCustom
class LegacyFormatter
def initialize(runtime, io, options)
@io = io
end
def before_feature(feature)
@io.puts feature.short_name.upcase
end
def scenario_name(keyword, name, file_colon_line, source_indent)
@io.puts " #{name.upcase}"
end
end
endI'LL USE MY OWN JUST PRINT ME
module MyCustom
class MixedFormatter
def initialize(runtime, io, options)
@io = io
end
def before_test_case(test_case)
feature = test_case.source.first
@io.puts feature.short_name.upcase
end
def scenario_name(keyword, name, file_colon_line, source_indent)
@io.puts " #{name.upcase}"
end
end
endI'LL USE MY OWN JUST PRINT ME
In order to help you easily visualise the listener API, you can use
the `debug` formatter that prints the calls to the listener as a
feature is run.
Feature:
Scenario:
Given this step passesbefore_test_case before_features before_feature before_tags after_tags feature_name before_test_step after_test_step before_test_step before_feature_element before_tags after_tags scenario_name before_steps before_step before_step_result step_name after_step_result after_step after_test_step after_steps after_feature_element after_test_case after_feature after_features done
To all reporter to understand location of current executing step let's fetch this information
from step/step_invocation and pass to reporters
Feature: I'll use my own
because I'm worth it
Scenario: just print step current line and feature file name
Given step at line 4
Given step at line 5Given(/^step at line (.*)$/) {|line| }module Jb
class Formatter
def initialize(runtime, io, options)
@io = io
end
def before_step_result(keyword, step_match, multiline_arg, status, exception, source_indent, background, file_colon_line)
@io.puts "step result event: #{file_colon_line}"
end
def step_name(keyword, step_match, status, source_indent, background, file_colon_line)
@io.puts "step name event: #{file_colon_line}"
end
end
endstep result event: features/f.feature:4 step name event: features/f.feature:4 step result event: features/f.feature:5 step name event: features/f.feature:5
Feature:
Scenario Outline:
Given this step is undefined
Examples:
|foo|
|bar|Feature: Outline
Scenario Outline: Will it blend?
Given this step is pending
And other step
When I do something with <example>
Then I should see something
Examples:
| example |
| one |
| two |
| three |Feature: Feature with failing background step
Background:
Given this step fails
Scenario:
When I do something
Then I should see somethingmakeYellow('scenario_1')makeRed('scenario_1')file | flag |
|---|---|
features/scenario_outline_with_pending_step.feature | --expand |
features/scenario_outline_with_pending_step.feature |
file | flag |
|---|---|
features/scenario_outline_with_undefined_steps.feature | --expand |
features/scenario_outline_with_undefined_steps.feature |
default: -r features
Using the default profile...
makeRed('scenario_0')makeRed('background_0')In order to simplify processing of Cucumber features and results
Developers should be able to consume features as JSON
@a
Feature: One passing scenario, one failing scenario
@b
Scenario: Passing
Given this step passes
@c
Scenario: Failing
Given this step failsGiven /^I embed a screenshot/ do
File.open("screenshot.png", "w") { |file| file << "foo" }
embed "screenshot.png", "image/png"
end
Given /^I print from step definition/ do
puts "from step definition"
end
Given /^I embed data directly/ do
data = "YWJj"
embed data, "mime-type;base64"
endFeature: A screenshot feature
Scenario:
Given I embed a screenshot
Feature: An outline feature
Scenario Outline: outline
Given this step <status>
Examples: examples1
| status |
| passes |
| fails |
Examples: examples2
| status |
| passes |Feature: A print from step definition feature
Scenario:
Given I print from step definition
And I print from step definition
Feature: A print from step definition feature
Scenario:
Given I print from step definition
And I print from step definition
Feature: An embed data directly feature
Scenario:
Given I embed data directly
Scenario Outline:
Given I embed data directly
Examples:
| dummy |
| 1 |
| 2 |
Feature:
Scenario:
Given this step passes
Scenario Outline:
Given this step <status>
Examples:
| status |
| passes |# Need to investigate why this won't pass in-process. error_message doesn't get det?@spawnfeatures/docs/formatters/json_formatter.feature:108
[
{
"uri": "features/one_passing_one_failing.feature",
"keyword": "Feature",
"id": "one-passing-scenario,-one-failing-scenario",
"name": "One passing scenario, one failing scenario",
"line": 2,
"description": "",
"tags": [
{
"name": "@a",
"line": 1
}
],
"elements": [
{
"keyword": "Scenario",
"id": "one-passing-scenario,-one-failing-scenario;passing",
"name": "Passing",
"line": 5,
"description": "",
"tags": [
{
"name": "@a",
"line": 1
},
{
"name": "@b",
"line": 4
}
],
"type": "scenario",
"steps": [
{
"keyword": "Given ",
"name": "this step passes",
"line": 6,
"match": {
"location": "features/step_definitions/steps.rb:1"
},
"result": {
"status": "passed",
"duration": 1
}
}
]
},
{
"keyword": "Scenario",
"id": "one-passing-scenario,-one-failing-scenario;failing",
"name": "Failing",
"line": 9,
"description": "",
"tags": [
{
"name": "@a",
"line": 1
},
{
"name": "@c",
"line": 8
}
],
"type": "scenario",
"steps": [
{
"keyword": "Given ",
"name": "this step fails",
"line": 10,
"match": {
"location": "features/step_definitions/steps.rb:4"
},
"result": {
"status": "failed",
"error_message": " (RuntimeError)\n./features/step_definitions/steps.rb:4:in `/^this step fails$/'\nfeatures/one_passing_one_failing.feature:10:in `Given this step fails'",
"duration": 1
}
}
]
}
]
}
]
[
{
"uri": "features/one_passing_one_failing.feature",
"keyword": "Feature",
"id": "one-passing-scenario,-one-failing-scenario",
"name": "One passing scenario, one failing scenario",
"line": 2,
"description": "",
"tags": [
{
"name": "@a",
"line": 1
}
],
"elements": [
{
"keyword": "Scenario",
"id": "one-passing-scenario,-one-failing-scenario;passing",
"name": "Passing",
"line": 5,
"description": "",
"tags": [
{
"name": "@a",
"line": 1
},
{
"name": "@b",
"line": 4
}
],
"type": "scenario",
"steps": [
{
"keyword": "Given ",
"name": "this step passes",
"line": 6,
"match": {
"location": "features/step_definitions/steps.rb:1"
},
"result": {
"status": "passed",
"duration": 1
}
}
]
},
{
"keyword": "Scenario",
"id": "one-passing-scenario,-one-failing-scenario;failing",
"name": "Failing",
"line": 9,
"description": "",
"tags": [
{
"name": "@a",
"line": 1
},
{
"name": "@c",
"line": 8
}
],
"type": "scenario",
"steps": [
{
"keyword": "Given ",
"name": "this step fails",
"line": 10,
"match": {
"location": "features/step_definitions/steps.rb:4"
},
"result": {
"status": "failed",
"error_message": " (RuntimeError)\n./features/step_definitions/steps.rb:4:in `/^this step fails$/'\nfeatures/one_passing_one_failing.feature:10:in `Given this step fails'",
"duration": 1
}
}
]
}
]
}
]
Feature: A DocString feature
Scenario:
Then I should fail with
"""
a string
"""Then /I should fail with/ do |s| raise RuntimeError, s end
[
{
"id": "a-docstring-feature",
"uri": "features/doc_string.feature",
"keyword": "Feature",
"name": "A DocString feature",
"line": 1,
"description": "",
"elements": [
{
"id": "a-docstring-feature;",
"keyword": "Scenario",
"name": "",
"line": 3,
"description": "",
"type": "scenario",
"steps": [
{
"keyword": "Then ",
"name": "I should fail with",
"line": 4,
"doc_string": {
"content_type": "",
"value": "a string",
"line": 5
},
"match": {
"location": "features/step_definitions/steps.rb:1"
},
"result": {
"status": "failed",
"error_message": "a string (RuntimeError)\n./features/step_definitions/steps.rb:2:in `/I should fail with/'\nfeatures/doc_string.feature:4:in `Then I should fail with'",
"duration": 1
}
}
]
}
]
}
][
{
"uri": "features/embed.feature",
"id": "a-screenshot-feature",
"keyword": "Feature",
"name": "A screenshot feature",
"line": 1,
"description": "",
"elements": [
{
"id": "a-screenshot-feature;",
"keyword": "Scenario",
"name": "",
"line": 3,
"description": "",
"type": "scenario",
"steps": [
{
"keyword": "Given ",
"name": "I embed a screenshot",
"line": 4,
"embeddings": [
{
"mime_type": "image/png",
"data": "Zm9v"
}
],
"match": {
"location": "features/step_definitions/json_steps.rb:1"
},
"result": {
"status": "passed",
"duration": 1
}
}
]
}
]
}
]
[
{
"uri": "features/outline.feature",
"id": "an-outline-feature",
"keyword": "Feature",
"name": "An outline feature",
"line": 1,
"description": "",
"elements": [
{
"id": "an-outline-feature;outline;examples1;2",
"keyword": "Scenario Outline",
"name": "outline",
"description": "",
"line": 8,
"type": "scenario",
"steps": [
{
"keyword": "Given ",
"name": "this step passes",
"line": 8,
"match": {
"location": "features/step_definitions/steps.rb:1"
},
"result": {
"status": "passed",
"duration": 1
}
}
]
},
{
"id": "an-outline-feature;outline;examples1;3",
"keyword": "Scenario Outline",
"name": "outline",
"description": "",
"line": 9,
"type": "scenario",
"steps": [
{
"keyword": "Given ",
"name": "this step fails",
"line": 9,
"match": {
"location": "features/step_definitions/steps.rb:4"
},
"result": {
"status": "failed",
"error_message": " (RuntimeError)\n./features/step_definitions/steps.rb:4:in `/^this step fails$/'\nfeatures/outline.feature:9:in `Given this step fails'\nfeatures/outline.feature:4:in `Given this step <status>'",
"duration": 1
}
}
]
},
{
"id": "an-outline-feature;outline;examples2;2",
"keyword": "Scenario Outline",
"name": "outline",
"description": "",
"line": 13,
"type": "scenario",
"steps": [
{
"keyword": "Given ",
"name": "this step passes",
"line": 13,
"match": {
"location": "features/step_definitions/steps.rb:1"
},
"result": {
"status": "passed",
"duration": 1
}
}
]
}
]
}
]
[
{
"uri": "features/print_from_step_definition.feature",
"id": "a-print-from-step-definition-feature",
"keyword": "Feature",
"name": "A print from step definition feature",
"line": 1,
"description": "",
"elements": [
{
"id": "a-print-from-step-definition-feature;",
"keyword": "Scenario",
"name": "",
"line": 3,
"description": "",
"type": "scenario",
"steps": [
{
"keyword": "Given ",
"name": "I print from step definition",
"line": 4,
"output": [
"from step definition"
],
"match": {
"location": "features/step_definitions/json_steps.rb:6"
},
"result": {
"status": "passed",
"duration": 1
}
},
{
"keyword": "And ",
"name": "I print from step definition",
"line": 5,
"output": [
"from step definition"
],
"match": {
"location": "features/step_definitions/json_steps.rb:6"
},
"result": {
"status": "passed",
"duration": 1
}
}
]
}
]
}
]
[
{
"uri": "features/outline.feature",
"id": "an-outline-feature",
"keyword": "Feature",
"name": "An outline feature",
"line": 1,
"description": "",
"elements": [
{
"id": "an-outline-feature;outline;examples1;2",
"keyword": "Scenario Outline",
"name": "outline",
"line": 8,
"description": "",
"type": "scenario",
"steps": [
{
"keyword": "Given ",
"name": "this step passes",
"line": 8,
"match": {
"location": "features/step_definitions/steps.rb:1"
},
"result": {
"status": "passed",
"duration": 1
}
}
]
},
{
"id": "an-outline-feature;outline;examples1;3",
"keyword": "Scenario Outline",
"name": "outline",
"line": 9,
"description": "",
"type": "scenario",
"steps": [
{
"keyword": "Given ",
"name": "this step fails",
"line": 9,
"match": {
"location": "features/step_definitions/steps.rb:4"
},
"result": {
"status": "failed",
"error_message" : " (RuntimeError)\n./features/step_definitions/steps.rb:4:in `/^this step fails$/'\nfeatures/outline.feature:9:in `Given this step fails'\nfeatures/outline.feature:4:in `Given this step <status>'",
"duration": 1
}
}
]
},
{
"id": "an-outline-feature;outline;examples2;2",
"keyword": "Scenario Outline",
"name": "outline",
"line": 13,
"description": "",
"type": "scenario",
"steps": [
{
"keyword": "Given ",
"name": "this step passes",
"line": 13,
"match": {
"location": "features/step_definitions/steps.rb:1"
},
"result": {
"status": "passed",
"duration": 1
}
}
]
}
]
}
]
[
{
"uri": "features/embed_data_directly.feature",
"id": "an-embed-data-directly-feature",
"keyword": "Feature",
"name": "An embed data directly feature",
"line": 1,
"description": "",
"elements": [
{
"id": "an-embed-data-directly-feature;",
"keyword": "Scenario",
"name": "",
"line": 3,
"description": "",
"type": "scenario",
"steps": [
{
"keyword": "Given ",
"name": "I embed data directly",
"line": 4,
"embeddings": [
{
"mime_type": "mime-type",
"data": "YWJj"
}
],
"match": {
"location": "features/step_definitions/json_steps.rb:10"
},
"result": {
"status": "passed",
"duration": 1
}
}
]
},
{
"keyword": "Scenario Outline",
"name": "",
"line": 11,
"description": "",
"id": "an-embed-data-directly-feature;;;2",
"type": "scenario",
"steps": [
{
"keyword": "Given ",
"name": "I embed data directly",
"line": 11,
"embeddings": [
{
"mime_type": "mime-type",
"data": "YWJj"
}
],
"match": {
"location": "features/step_definitions/json_steps.rb:10"
},
"result": {
"status": "passed",
"duration": 1
}
}
]
},
{
"keyword": "Scenario Outline",
"name": "",
"line": 12,
"description": "",
"id": "an-embed-data-directly-feature;;;3",
"type": "scenario",
"steps": [
{
"keyword": "Given ",
"name": "I embed data directly",
"line": 12,
"embeddings": [
{
"mime_type": "mime-type",
"data": "YWJj"
}
],
"match": {
"location": "features/step_definitions/json_steps.rb:10"
},
"result": {
"status": "passed",
"duration": 1
}
}
]
}
]
}
]
Before do puts "Before hook 1" embed "src", "mime_type", "label" end Before do puts "Before hook 2" embed "src", "mime_type", "label" end AfterStep do puts "AfterStep hook 1" embed "src", "mime_type", "label" end AfterStep do puts "AfterStep hook 2" embed "src", "mime_type", "label" end After do puts "After hook 1" embed "src", "mime_type", "label" end After do puts "After hook 2" embed "src", "mime_type", "label" end
In order for developers to create test reports with ant
Cucumber should be able to output JUnit xml files
Feature: One passing scenario, one failing scenario
Scenario: Passing
Given this step passes
Scenario: Failing
Given this step failsFeature: Subdirectory - One passing scenario, one failing scenario
Scenario: Passing
Given this step passes
Scenario: Failing
Given this step failsFeature: Pending step
Scenario: Pending
Given this step is pending
Scenario: Undefined
Given this step is undefinedFeature: Pending step
Scenario: Pending
Given this step is pending
Scenario: Undefined
Given this step is undefinedFeature: Scenario outlines
Scenario Outline: Using scenario outlines
Given this step <type>
Examples:
| type |
| passes |
| fails |
| is pending |
| is undefined |<?xml version="1.0" encoding="UTF-8"?>
<testsuite failures="1" errors="0" skipped="0" tests="2" time="0.05" name="One passing scenario, one failing scenario">
<testcase classname="One passing scenario, one failing scenario" name="Passing" time="0.05">
<system-out>
<![CDATA[]]>
</system-out>
<system-err>
<![CDATA[]]>
</system-err>
</testcase>
<testcase classname="One passing scenario, one failing scenario" name="Failing" time="0.05">
<failure message="failed Failing" type="failed">
<![CDATA[Scenario: Failing
Given this step fails
Message:
]]>
<![CDATA[ (RuntimeError)
./features/step_definitions/steps.rb:4:in `/^this step fails$/'
features/one_passing_one_failing.feature:7:in `Given this step fails']]>
</failure>
<system-out>
<![CDATA[]]>
</system-out>
<system-err>
<![CDATA[]]>
</system-err>
</testcase>
</testsuite>
<?xml version="1.0" encoding="UTF-8"?>
<testsuite failures="1" errors="0" skipped="0" tests="2" time="0.05" name="Subdirectory - One passing scenario, one failing scenario">
<testcase classname="Subdirectory - One passing scenario, one failing scenario" name="Passing" time="0.05">
<system-out>
<![CDATA[]]>
</system-out>
<system-err>
<![CDATA[]]>
</system-err>
</testcase>
<testcase classname="Subdirectory - One passing scenario, one failing scenario" name="Failing" time="0.05">
<failure message="failed Failing" type="failed">
<![CDATA[Scenario: Failing
Given this step fails
Message:
]]>
<![CDATA[ (RuntimeError)
./features/step_definitions/steps.rb:4:in `/^this step fails$/'
features/some_subdirectory/one_passing_one_failing.feature:7:in `Given this step fails']]>
</failure>
<system-out>
<![CDATA[]]>
</system-out>
<system-err>
<![CDATA[]]>
</system-err>
</testcase>
</testsuite>
<?xml version="1.0" encoding="UTF-8"?>
<testsuite failures="0" errors="0" skipped="2" tests="2" time="0.05" name="Pending step">
<testcase classname="Pending step" name="Pending" time="0.05">
<skipped/>
<system-out>
<![CDATA[]]>
</system-out>
<system-err>
<![CDATA[]]>
</system-err>
</testcase>
<testcase classname="Pending step" name="Undefined" time="0.05">
<skipped/>
<system-out>
<![CDATA[]]>
</system-out>
<system-err>
<![CDATA[]]>
</system-err>
</testcase>
</testsuite>
<?xml version="1.0" encoding="UTF-8"?>
<testsuite failures="2" errors="0" skipped="0" tests="2" time="0.05" name="Pending step">
<testcase classname="Pending step" name="Pending" time="0.05">
<failure message="pending Pending" type="pending">
<![CDATA[Scenario: Pending
Given this step is pending
Message:
]]>
<![CDATA[TODO (Cucumber::Pending)
./features/step_definitions/steps.rb:3:in `/^this step is pending$/'
features/pending.feature:4:in `Given this step is pending']]>
</failure>
<system-out>
<![CDATA[]]>
</system-out>
<system-err>
<![CDATA[]]>
</system-err>
</testcase>
<testcase classname="Pending step" name="Undefined" time="0.05">
<failure message="undefined Undefined" type="undefined">
<![CDATA[Scenario: Undefined
Given this step is undefined
Message:
]]>
<![CDATA[Undefined step: "this step is undefined" (Cucumber::Core::Test::Result::Undefined)
features/pending.feature:7:in `Given this step is undefined']]>
</failure>
<system-out>
<![CDATA[]]>
</system-out>
<system-err>
<![CDATA[]]>
</system-err>
</testcase>
</testsuite>
can't convert .* into String \(TypeError\)
You *must* specify --out DIR for the junit formatter
<?xml version="1.0" encoding="UTF-8"?>
<testsuite failures="3" errors="0" skipped="0" tests="4" time="0.05" name="Scenario outlines">
<testcase classname="Scenario outlines" name="Using scenario outlines (outline example : | passes |)" time="0.05">
<system-out>
<![CDATA[]]>
</system-out>
<system-err>
<![CDATA[]]>
</system-err>
</testcase>
<testcase classname="Scenario outlines" name="Using scenario outlines (outline example : | fails |)" time="0.05">
<failure message="failed Using scenario outlines (outline example : | fails |)" type="failed">
<![CDATA[Scenario Outline: Using scenario outlines
Example row: | fails |
Message:
]]>
<![CDATA[ (RuntimeError)
./features/step_definitions/steps.rb:4:in `/^this step fails$/'
features/scenario_outline.feature:9:in `Given this step fails'
features/scenario_outline.feature:4:in `Given this step <type>']]>
</failure>
<system-out>
<![CDATA[]]>
</system-out>
<system-err>
<![CDATA[]]>
</system-err>
</testcase>
<testcase classname="Scenario outlines" name="Using scenario outlines (outline example : | is pending |)" time="0.05">
<failure message="pending Using scenario outlines (outline example : | is pending |)" type="pending">
<![CDATA[Scenario Outline: Using scenario outlines
Example row: | is pending |
Message:
]]>
<![CDATA[TODO (Cucumber::Pending)
./features/step_definitions/steps.rb:3:in `/^this step is pending$/'
features/scenario_outline.feature:10:in `Given this step is pending'
features/scenario_outline.feature:4:in `Given this step <type>']]>
</failure>
<system-out>
<![CDATA[]]>
</system-out>
<system-err>
<![CDATA[]]>
</system-err>
</testcase>
<testcase classname="Scenario outlines" name="Using scenario outlines (outline example : | is undefined |)" time="0.05">
<failure message="undefined Using scenario outlines (outline example : | is undefined |)" type="undefined">
<![CDATA[Scenario Outline: Using scenario outlines
Example row: | is undefined |
Message:
]]>
<![CDATA[Undefined step: "this step is undefined" (Cucumber::Core::Test::Result::Undefined)
features/scenario_outline.feature:11:in `Given this step is undefined'
features/scenario_outline.feature:4:in `Given this step <type>']]>
</failure>
<system-out>
<![CDATA[]]>
</system-out>
<system-err>
<![CDATA[]]>
</system-err>
</testcase>
</testsuite>
<?xml version="1.0" encoding="UTF-8"?>
<testsuite failures="3" errors="0" skipped="0" tests="4" time="0.05" name="Scenario outlines">
<testcase classname="Scenario outlines" name="Using scenario outlines (outline example : | passes |)" time="0.05">
<system-out>
<![CDATA[]]>
</system-out>
<system-err>
<![CDATA[]]>
</system-err>
</testcase>
<testcase classname="Scenario outlines" name="Using scenario outlines (outline example : | fails |)" time="0.05">
<failure message="failed Using scenario outlines (outline example : | fails |)" type="failed">
<![CDATA[Scenario Outline: Using scenario outlines
Example row: | fails |
Message:
]]>
<![CDATA[ (RuntimeError)
./features/step_definitions/steps.rb:4:in `/^this step fails$/'
features/scenario_outline.feature:9:in `Given this step fails'
features/scenario_outline.feature:4:in `Given this step <type>']]>
</failure>
<system-out>
<![CDATA[]]>
</system-out>
<system-err>
<![CDATA[]]>
</system-err>
</testcase>
<testcase classname="Scenario outlines" name="Using scenario outlines (outline example : | is pending |)" time="0.05">
<failure message="pending Using scenario outlines (outline example : | is pending |)" type="pending">
<![CDATA[Scenario Outline: Using scenario outlines
Example row: | is pending |
Message:
]]>
<![CDATA[TODO (Cucumber::Pending)
./features/step_definitions/steps.rb:3:in `/^this step is pending$/'
features/scenario_outline.feature:10:in `Given this step is pending'
features/scenario_outline.feature:4:in `Given this step <type>']]>
</failure>
<system-out>
<![CDATA[]]>
</system-out>
<system-err>
<![CDATA[]]>
</system-err>
</testcase>
<testcase classname="Scenario outlines" name="Using scenario outlines (outline example : | is undefined |)" time="0.05">
<failure message="undefined Using scenario outlines (outline example : | is undefined |)" type="undefined">
<![CDATA[Scenario Outline: Using scenario outlines
Example row: | is undefined |
Message:
]]>
<![CDATA[Undefined step: "this step is undefined" (Cucumber::Core::Test::Result::Undefined)
features/scenario_outline.feature:11:in `Given this step is undefined'
features/scenario_outline.feature:4:in `Given this step <type>']]>
</failure>
<system-out>
<![CDATA[]]>
</system-out>
<system-err>
<![CDATA[]]>
</system-err>
</testcase>
</testsuite>
Feature:
Scenario Outline:
Given this step is undefined
Examples:
|foo|
|bar|default: -r features
Using the default profile...
Feature:
Scenario:
Given this step passesBefore do puts "Before hook" end AfterStep do puts "AfterStep hook" end After do puts "After hook" raise "error" end
Feature:
Scenario:
Before hook
Given this step passes
AfterStep hook
After hook
error (RuntimeError)
./features/step_definitions/output_steps.rb:11:in `After'
Failing Scenarios:
cucumber features/test.feature:2
1 scenario (1 failed)
1 step (1 passed)Feature:
Scenario Outline:
Given this step is undefined
Examples:
|foo|
|bar|default: -r features
Using the default profile...
The rerun formatter writes an output that's perfect for
passing to Cucumber when you want to rerun only the
scenarios that prevented the exit code to be zero.
You can save off the rerun output to a file by using it like this:
`cucumber -f rerun --out .cucumber.rerun`
Now you can pass that file's content to Cucumber to tell it
which scenarios to run:
`cucumber \`cat .cucumber.rerun\``
This is useful when debugging in a large suite of features.
Feature: Mixed
Scenario:
Given this step is undefined
Scenario:
Given this step is pending
Scenario:
Given this step passes
Feature: Mixed
Scenario:
Given this step fails
Scenario:
Given this step is undefined
Scenario:
Given this step is pending
Scenario:
Given this step passes
Feature: All good
Scenario:
Given this step passesFeature: Mixed
Scenario:
Given this step fails
Scenario:
Given this step is undefined
Scenario:
Given this step is pending
Scenario:
Given this step passes
Feature: All good
Scenario:
Given this step passesfeatures/mixed.feature:3:6:9
Feature: One passing example, one failing example
Scenario Outline:
Given this step <status>
Examples:
| status |
| passes |
| fails |
features/one_passing_one_failing.feature:9
Feature: Failing background sample
Background:
Given this step fails
Scenario: failing background
Then this step passes
Scenario: another failing background
Then this step passesfeatures/failing_background.feature:6:9
Feature: Failing background sample with scenario outline
Background:
Given this step fails
Scenario Outline:
Then this step <status>
Examples:
| status |
| passes |
| passes |features/failing_background_outline.feature:11:12
Feature: One passing example, one failing example
Scenario Outline:
Given this step <status>
Examples:
| status |
| passes |
| fails |
features/one_passing_one_failing.feature:9
In order to see where step definitions are used
Developers should be able to see a list of step definitions and their use
Feature: F
Background: A
Given A
Scenario: B
Given B
Scenario Outline: CA
Given <x>
And B
Examples:
|x|
|C|
|A|
Scenario: AC
Given A
Given CGiven(/A/) { }
Given(/B/) { }
Given(/C/) { }
Given(/D/) { }----------- /A/ # features/step_definitions/steps.rb:1 Given A # features/f.feature:3 Given A # features/f.feature:12 Given A # features/f.feature:14 /B/ # features/step_definitions/steps.rb:2 Given B # features/f.feature:5 And B # features/f.feature:11 And B # features/f.feature:12 /C/ # features/step_definitions/steps.rb:3 Given C # features/f.feature:11 Given C # features/f.feature:15 /D/ # features/step_definitions/steps.rb:4 NOT MATCHED BY ANY STEPS 4 scenarios (4 skipped) 11 steps (11 skipped)
----------- /A/ # features/step_definitions/steps.rb:1 Given A # features/f.feature:3 Given A # features/f.feature:12 Given A # features/f.feature:14 /B/ # features/step_definitions/steps.rb:2 Given B # features/f.feature:5 And B # features/f.feature:11 And B # features/f.feature:12 /C/ # features/step_definitions/steps.rb:3 Given C # features/f.feature:11 Given C # features/f.feature:15 /D/ # features/step_definitions/steps.rb:4 NOT MATCHED BY ANY STEPS 4 scenarios (4 skipped) 11 steps (11 skipped)
----------- /A/ # features/step_definitions/steps.rb:1 /B/ # features/step_definitions/steps.rb:2 /C/ # features/step_definitions/steps.rb:3 /D/ # features/step_definitions/steps.rb:4 NOT MATCHED BY ANY STEPS 4 scenarios (4 skipped) 11 steps (11 skipped)
To get started, just open a command prompt in an empty directory and run
`cucumber`. You'll be prompted for what to do next.
No such file or directory - features. You can use `cucumber --init` to get started.
puts 'this will not be shown'
this will not be shown
Often you find that several scenarios in the same feature start with
a common context.
Cucumber provides a mechanism for this, by providing a `Background` keyword
where you can specify steps that should be run before each scenario in the
feature. Typically these will be `Given` steps, but you can use any steps
that you need to.
**Hint:** if you find that some of the scenarios don't fit the background,
consider splitting them into a separate feature.
Feature: Passing background sample
Background:
Given '10' cukes
Scenario: passing background
Then I should have '10' cukes
Scenario: another passing background
Then I should have '10' cukesFeature: Passing background with scenario outlines sample
Background:
Given '10' cukes
Scenario Outline: passing background
Then I should have '<count>' cukes
Examples:
|count|
| 10 |
Scenario Outline: another passing background
Then I should have '<count>' cukes
Examples:
|count|
| 10 |@background_tagged_before_on_outline
Feature: Background tagged Before on Outline
Background:
Given this step passes
Scenario Outline: passing background
Then I should have '<count>' cukes
Examples:
| count |
| 888 |Feature: Failing background sample
Background:
Given this step raises an error
And '10' cukes
Scenario: failing background
Then I should have '10' cukes
Scenario: another failing background
Then I should have '10' cukesFeature: Failing background with scenario outlines sample
Background:
Given this step raises an error
Scenario Outline: failing background
Then I should have '<count>' cukes
Examples:
|count|
| 10 |
Scenario Outline: another failing background
Then I should have '<count>' cukes
Examples:
|count|
| 10 |Feature: Pending background sample
Background:
Given this step is pending
Scenario: pending background
Then I should have '10' cukes
Scenario: another pending background
Then I should have '10' cukesFeature: Failing background after previously successful background sample
Background:
Given this step passes
And '10' global cukes
Scenario: passing background
Then I should have '10' global cukes
Scenario: failing background
Then I should have '10' global cukesFeature: Failing background after previously successful background sample
Background:
Given this step passes
And '10' global cukes
Scenario Outline: passing background
Then I should have '<count>' global cukes
Examples:
| count |
| 10 |
Scenario Outline: failing background
Then I should have '<count>' global cukes
Examples:
| count |
| 10 |
Feature: Passing background with multiline args
Background:
Given table
|a|b|
|c|d|
And multiline string
"""
I'm a cucumber and I'm okay.
I sleep all night and I test all day
"""
Scenario: passing background
Then the table should be
|a|b|
|c|d|
Then the multiline string should be
"""
I'm a cucumber and I'm okay.
I sleep all night and I test all day
"""
Scenario: another passing background
Then the table should be
|a|b|
|c|d|
Then the multiline string should be
"""
I'm a cucumber and I'm okay.
I sleep all night and I test all day
"""Given /^'(.+)' cukes$/ do |cukes| x=1
raise "We already have #{@cukes} cukes!" if @cukes
@cukes = cukes
end
Given /^'(.+)' global cukes$/ do |cukes| x=1
$scenario_runs ||= 0
raise 'FAIL' if $scenario_runs >= 1
$cukes = cukes
$scenario_runs += 1
end
Then /^I should have '(.+)' global cukes$/ do |cukes| x=1
expect($cukes).to eq cukes
end
Then /^I should have '(.+)' cukes$/ do |cukes| x=1
expect(@cukes).to eq cukes
end
Before('@background_tagged_before_on_outline') do
@cukes = '888'
end
After('@background_tagged_before_on_outline') do
expect(@cukes).to eq '888'
endFeature: Passing background sample
Background:
Given '10' cukes
Scenario: another passing background
Then I should have '10' cukes
1 scenario (1 passed)
2 steps (2 passed)
Feature: Passing background sample
Background:
Given '10' cukes
Scenario: passing background
Then I should have '10' cukes
Scenario: another passing background
Then I should have '10' cukes
2 scenarios (2 passed)
4 steps (4 passed)
Feature: Passing background with scenario outlines sample
Background:
Given '10' cukes
Scenario Outline: passing background
Then I should have '<count>' cukes
Examples:
| count |
| 10 |
Scenario Outline: another passing background
Then I should have '<count>' cukes
Examples:
| count |
| 10 |
2 scenarios (2 passed)
4 steps (4 passed)
@background_tagged_before_on_outline
Feature: Background tagged Before on Outline
Background:
Given this step passes
Scenario Outline: passing background
Then I should have '<count>' cukes
Examples:
| count |
| 888 |
1 scenario (1 passed)
2 steps (2 passed)
Feature: Failing background sample
Background:
Given this step raises an error
error (RuntimeError)
./features/step_definitions/steps.rb:2:in `/^this step raises an error$/'
features/failing_background.feature:4:in `Given this step raises an error'
And '10' cukes
Scenario: failing background
Then I should have '10' cukes
Scenario: another failing background
Then I should have '10' cukes
Failing Scenarios:
cucumber features/failing_background.feature:7
cucumber features/failing_background.feature:10
2 scenarios (2 failed)
6 steps (2 failed, 4 skipped)
Feature: Failing background with scenario outlines sample
Background:
Given this step raises an error
error (RuntimeError)
./features/step_definitions/steps.rb:2:in `/^this step raises an error$/'
features/scenario_outline_failing_background.feature:4:in `Given this step raises an error'
Scenario Outline: failing background
Then I should have '<count>' cukes
Examples:
| count |
| 10 |
Scenario Outline: another failing background
Then I should have '<count>' cukes
Examples:
| count |
| 10 |
Failing Scenarios:
cucumber features/scenario_outline_failing_background.feature:10
cucumber features/scenario_outline_failing_background.feature:16
2 scenarios (2 failed)
4 steps (2 failed, 2 skipped)
Feature: Pending background sample
Background:
Given this step is pending
TODO (Cucumber::Pending)
./features/step_definitions/steps.rb:3:in `/^this step is pending$/'
features/pending_background.feature:4:in `Given this step is pending'
Scenario: pending background
Then I should have '10' cukes
Scenario: another pending background
Then I should have '10' cukes
2 scenarios (2 pending)
4 steps (2 skipped, 2 pending)
Feature: Failing background after previously successful background sample
Background:
Given this step passes
And '10' global cukes
Scenario: passing background
Then I should have '10' global cukes
Scenario: failing background
And '10' global cukes
FAIL (RuntimeError)
./features/step_definitions/cuke_steps.rb:8:in `/^'(.+)' global cukes$/'
features/failing_background_after_success.feature:5:in `And '10' global cukes'
Then I should have '10' global cukes
Failing Scenarios:
cucumber features/failing_background_after_success.feature:10
2 scenarios (1 failed, 1 passed)
6 steps (1 failed, 1 skipped, 4 passed)
Feature: Failing background after previously successful background sample
Background:
Given this step passes
And '10' global cukes
Scenario Outline: passing background
Then I should have '<count>' global cukes
Examples:
| count |
| 10 |
Scenario Outline: failing background
Then I should have '<count>' global cukes
Examples:
| count |
| 10 |
FAIL (RuntimeError)
./features/step_definitions/cuke_steps.rb:8:in `/^'(.+)' global cukes$/'
features/failing_background_after_success_outline.feature:5:in `And '10' global cukes'
Failing Scenarios:
cucumber features/failing_background_after_success_outline.feature:19
2 scenarios (1 failed, 1 passed)
6 steps (1 failed, 1 skipped, 4 passed)
Feature: Failing background after previously successful background sample
Background:
Given this step passes
And '10' global cukes
Scenario Outline: passing background
Then I should have '<count>' global cukes
Examples:
Scenario: | 10 |
Then I should have '10' global cukes
Scenario Outline: failing background
Then I should have '<count>' global cukes
Examples:
Scenario: | 10 |
And '10' global cukes
FAIL (RuntimeError)
./features/step_definitions/cuke_steps.rb:8:in `/^'(.+)' global cukes$/'
features/failing_background_after_success_outline.feature:5:in `And '10' global cukes'
Then I should have '10' global cukes
Failing Scenarios:
cucumber features/failing_background_after_success_outline.feature:19
2 scenarios (1 failed, 1 passed)
6 steps (1 failed, 1 skipped, 4 passed)
Given /^table$/ do |table| x=1 @table = table end Given /^multiline string$/ do |string| x=1 @multiline = string end Then /^the table should be$/ do |table| x=1 expect(@table.raw).to eq table.raw end Then /^the multiline string should be$/ do |string| x=1 expect(@multiline).to eq string end
Feature: Passing background with multiline args
Background:
Given table
| a | b |
| c | d |
And multiline string
"""
I'm a cucumber and I'm okay.
I sleep all night and I test all day
"""
Scenario: passing background
Then the table should be
| a | b |
| c | d |
Then the multiline string should be
"""
I'm a cucumber and I'm okay.
I sleep all night and I test all day
"""
Scenario: another passing background
Then the table should be
| a | b |
| c | d |
Then the multiline string should be
"""
I'm a cucumber and I'm okay.
I sleep all night and I test all day
"""
2 scenarios (2 passed)
8 steps (8 passed)
If you need to specify information in a scenario that won't fit on a single line,
you can use a DocString.
A DocString follows a step, and starts and ends with three double quotes, like this:
```gherkin
When I ask to reset my password
Then I should receive an email with:
"""
Dear bozo,
Please click this link to reset your password
"""
```
It's possible to annotate the DocString with the type of content it contains. This is used by
formatting tools like http://relishapp.com which will render the contents of the DocString
appropriately. You specify the content type after the triple quote, like this:
```gherkin
Given there is some Ruby code:
"""ruby
puts "hello world"
"""
```
You can read the content type from the argument passed into your step definition, as shown
in the example below.
Given I have a lot to say: """ One Two Three """
Given /say/ do |text| puts text end
One Two Three
Given I have some code for you: """ruby # hello """
Given /code/ do |text| puts text.content_type end
ruby
In order to make it easier to write certain editor plugins and also
for some people to understand scenarios, Cucumber will expand examples
in outlines if you add the `--expand` option when running them.
Feature:
Scenario Outline:
Given the secret code is <code>
When I guess <guess>
Then I am <verdict>
Examples:
| code | guess | verdict |
| blue | blue | right |
| red | blue | wrong |Feature:
Scenario Outline:
Given the secret code is <code>
When I guess <guess>
Then I am <verdict>
Examples:
Scenario: | blue | blue | right |
Given the secret code is blue
When I guess blue
Then I am right
Scenario: | red | blue | wrong |
Given the secret code is red
When I guess blue
Then I am wrong
2 scenarios (2 undefined)
6 steps (6 undefined)
In order to simplify command line and settings in IDEs, Cucumber picks
up the parser language from a `# language` comment at the beginning of
any feature file. See the examples below for the exact syntax.
# language: en-lol
OH HAI: STUFFING
B4: HUNGRY
I CAN HAZ EMPTY BELLY
MISHUN: CUKES
DEN KTHXBAI# language: en-lol
OH HAI: STUFFING
B4: HUNGRY
I CAN HAZ EMPTY BELLY
MISHUN: CUKES
DEN KTHXBAI
1 scenario (1 undefined)
2 steps (2 undefined)
It's possible to ask cucumber which keywords are used for any
particular language by running:
`cucumber --i18n <language code> help`
This will print a table showing all the different words we use for
that language, to allow you to easily write features in any language
you choose.
| feature | "Funcionalidade", "Característica", "Caracteristica" |
| background | "Contexto", "Cenário de Fundo", "Cenario de Fundo", "Fundo" |
| scenario | "Cenário", "Cenario" |
| scenario_outline | "Esquema do Cenário", "Esquema do Cenario", "Delineação do Cenário", "Delineacao do Cenario" |
| examples | "Exemplos", "Cenários", "Cenarios" |
| given | "* ", "Dado ", "Dada ", "Dados ", "Dadas " |
| when | "* ", "Quando " |
| then | "* ", "Então ", "Entao " |
| and | "* ", "E " |
| but | "* ", "Mas " |
| given (code) | "Dado", "Dada", "Dados", "Dadas" |
| when (code) | "Quando" |
| then (code) | "Então", "Entao" |
| and (code) | "E" |
| but (code) | "Mas" |
Copying and pasting scenarios to use different values quickly
becomes tedious and repetitive. Scenario outlines allow us to more
concisely express these examples through the use of a template with
placeholders, using Scenario Outline, Examples with tables and < >
delimited parameters.
The Scenario Outline steps provide a template which is never directly
run. A Scenario Outline is run once for each row in the Examples section
beneath it (not counting the first row).
The way this works is via placeholders. Placeholders must be contained
within < > in the Scenario Outline's steps - see the examples below.
**IMPORTANT:** Your step definitions will never have to match a
placeholder. They will need to match the values that will replace the
placeholder.
Feature: Outline Sample
Scenario: I have no steps
Scenario Outline: Test state
Given <state> without a table
Given <other_state> without a table
Examples: Rainbow colours
| state | other_state |
| missing | passing |
| passing | passing |
| failing | passing |
Examples:Only passing
| state | other_state |
| passing | passing |Given(/^passing without a table$/) { }
Given(/^failing without a table$/) { raise RuntimeError }Feature: Outline Sample
Scenario: I have no steps
Scenario Outline: Test state
Given <state> without a table
Given <other_state> without a table
Examples: Rainbow colours
| state | other_state |
| missing | passing |
| passing | passing |
| failing | passing |
RuntimeError (RuntimeError)
./features/step_definitions/steps.rb:2:in `/^failing without a table$/'
features/outline_sample.feature:12:in `Given failing without a table'
features/outline_sample.feature:6:in `Given <state> without a table'
Examples: Only passing
| state | other_state |
| passing | passing |
Failing Scenarios:
cucumber features/outline_sample.feature:12
5 scenarios (1 failed, 1 undefined, 3 passed)
8 steps (1 failed, 2 skipped, 1 undefined, 4 passed)Feature: Outline Sample
Scenario Outline: Test state
Given <state> without a table
Given <other_state> without a table
Examples: Rainbow colours
| state | other_state |
| missing | passing |
| passing | passing |
| failing | passing |
RuntimeError (RuntimeError)
./features/step_definitions/steps.rb:2:in `/^failing without a table$/'
features/outline_sample.feature:12:in `Given failing without a table'
features/outline_sample.feature:6:in `Given <state> without a table'
Examples: Only passing
| state | other_state |
| passing | passing |
Failing Scenarios:
cucumber features/outline_sample.feature:12
4 scenarios (1 failed, 1 undefined, 2 passed)
8 steps (1 failed, 2 skipped, 1 undefined, 4 passed)
Feature: Outline Sample
Scenario Outline: Test state
Given <state> without a table
Given <other_state> without a table
Examples: Rainbow colours
| state | other_state |
| failing | passing |
RuntimeError (RuntimeError)
./features/step_definitions/steps.rb:2:in `/^failing without a table$/'
features/outline_sample.feature:12:in `Given failing without a table'
features/outline_sample.feature:6:in `Given <state> without a table'
Failing Scenarios:
cucumber features/outline_sample.feature:12
1 scenario (1 failed)
2 steps (1 failed, 1 skipped)
U-..F-.. (::) failed steps (::) RuntimeError (RuntimeError) ./features/step_definitions/steps.rb:2:in `/^failing without a table$/' features/outline_sample.feature:12:in `Given failing without a table' features/outline_sample.feature:6:in `Given <state> without a table' Failing Scenarios: cucumber features/outline_sample.feature:12 5 scenarios (1 failed, 1 undefined, 3 passed) 8 steps (1 failed, 2 skipped, 1 undefined, 4 passed)
You are free to use unicode in your tables: we've taken care to
ensure that the tables are properly aligned so that your output is as
readable as possible.
Feature: Featuring unicode
Scenario: table with unicode
Given passing
| Brüno | abc |
| Bruno | æøå |Feature: Featuring unicode
Scenario: table with unicode
Given passing
| Brüno | abc |
| Bruno | æøå |
1 scenario (1 undefined)
1 step (1 undefined)
When writing your feature files its very helpful to use description
text at the beginning of the feature file, to write a preamble to the
feature describing clearly exactly what the feature does.
You can also write descriptions attached to individual scenarios - see
the examples below for how this can be used.
It's possible to have your descriptions run over more than one line,
and you can have blank lines too. As long as you don't start a line
with a Given, When, Then, Background:, Scenario: or similar, you're
fine: otherwise Gherkin will start to pay attention.
Feature: descriptions everywhere
We can put a useful description here of the feature, which can
span multiple lines.
Background:
We can also put in descriptions showing what the background is
doing.
Given this step passes
Scenario: I'm a scenario with a description
You can also put descriptions in front of individual scenarios.
Given this step passes
Scenario Outline: I'm a scenario outline with a description
Scenario outlines can have descriptions.
Given this step <state>
Examples: Examples
Specific examples for an outline are allowed to have
descriptions, too.
| state |
| passes |Feature: descriptions everywhere
We can put a useful description here of the feature, which can
span multiple lines.
Background:
We can also put in descriptions showing what the background is
doing.
Given this step passes
Scenario: I'm a scenario with a description
You can also put descriptions in front of individual scenarios.
Given this step passes
Scenario Outline: I'm a scenario outline with a description
Scenario outlines can have descriptions.
Given this step <state>
Examples: Examples
Specific examples for an outline are allowed to have
descriptions, too.
| state |
| passes |
2 scenarios (2 passed)
4 steps (4 passed)
Cucumber supports the star notation when writing features: instead of
using Given/When/Then, you can simply use a star rather like you would
use a bullet point.
When you run the feature for the first time, you still get a nice
message showing you the code snippet you need to use to implement the
step.
Feature: Star-notation feature
Scenario: S
* I have some cukesFeature: Star-notation feature
Scenario: S # features/f.feature:2
* I have some cukes # features/f.feature:3
1 scenario (1 undefined)
1 step (1 undefined)You can implement step definitions for undefined steps with these snippets: Given(/^I have some cukes$/) do pending # Write code here that turns the phrase above into concrete actions end
# language: no
# encoding: iso-8859-1
In order to extend Cucumber
As a developer
I want to manipulate the Cucumber configuration after it has been created
# Fails on Travis under JRuby@spawn @wip-jrubyfeatures/docs/post_configuration_hook.feature:10
AfterConfiguration do |config| config.options[:blah] end
Deprecated
AfterConfiguration do |config| config.formats << ['html', config.out_stream] end
html
AfterConfiguration do |config|
config.out_stream << "AfterConfiguration hook read feature directories: #{config.feature_dirs.join(', ')}"
endAfterConfiguration hook read feature directories: features
In order to save time and prevent carpal tunnel syndrome
Cucumber users can save and reuse commonly used cucumber flags in a 'cucumber.yml' file.
These named arguments are called profiles and the yml file should be in the root of your project.
Any cucumber argument is valid in a profile. To see all the available flags type 'cucumber --help'
For more information about profiles please see the wiki:
http://wiki.github.com/cucumber/cucumber/cucumber.yml
Feature: Sample
Scenario: this is a test
Given this step raises an errordefault: features/sample.feature --require features/support/env.rb -v super: features/sample.feature --require features/support/super_env.rb -v
Using the super profile...
<% requires = "--require features/support/super_env.rb" %>
super: <%= "features/sample.feature #{requires} -v" %>Using the super profile...
Using the default and super profiles...
Could not find profile: 'foo' Defined profiles in cucumber.yml: * default * super
Disabling profiles...
flag |
|---|
-P |
--no-profile |
Feature: Just this one should be ran
default: features/sample.feature --require features/support/env.rb -v --format profile
Feature: Sample
cucumber -p super features/sample.feature:2
format |
|---|
pretty |
progress |
In order to ease the development process
As a developer and CI server administrator
Cucumber features should be executable via Rake
Feature: Sample
Scenario: Wanted
Given I want to run this
Scenario: Unwanted
Given I don't want this ranfoo: --quiet --no-color features/missing_step_definitions.feature:3
require 'cucumber/rake/task' Cucumber::Rake::Task.new do |t| t.profile = "foo" end
Feature: Sample
Scenario: Wanted
Given I want to run this
1 scenario (1 undefined)
1 step (1 undefined)require 'cucumber/rake/task'
Cucumber::Rake::Task.new do |t|
t.cucumber_opts = %w{--quiet --no-color}
endFeature: Sample
Scenario: Wanted
Given I want to run this
Scenario: Unwanted
Given I don't want this ran
2 scenarios (2 undefined)
2 steps (2 undefined)bar: ['features/missing_step_definitions.feature:3']
require 'cucumber/rake/task'
Cucumber::Rake::Task.new do |t|
t.profile = "bar"
t.cucumber_opts = %w{--quiet --no-color}
endFeature: Sample
Scenario: Wanted
Given I want to run this
1 scenario (1 undefined)
1 step (1 undefined)no_bomb: features/missing_step_definitions.feature:3 --require features/support/env.rb --verbose
require 'cucumber/rake/task'
Cucumber::Rake::Task.new do |t|
t.profile = "no_bomb"
t.cucumber_opts = %w{--quiet --no-color}
end* features/support/dont_require_me.rb
Feature: The futures green
Scenario: Orange
Given this is missingrequire 'cucumber/rake/task'
Cucumber::Rake::Task.new do |t|
t.cucumber_opts = %w{--quiet --no-color}
endFeature: The futures green
Scenario: Orange
Given this is missing
In order to use cucumber's rake task
As a Cuker
I do not want to see rake's backtraces when it fails
Also I want to get zero exit status code on failures
And non-zero exit status code when it pases
Feature: Sample
Scenario: Passing
Given this step passes
Scenario: Failing
Given this step raises an error require 'cucumber/rake/task'
SAMPLE_FEATURE_FILE = 'features/passing_and_failing.feature'
Cucumber::Rake::Task.new(:pass) do |t|
t.cucumber_opts = "#{SAMPLE_FEATURE_FILE}:3"
end
Cucumber::Rake::Task.new(:fail) do |t|
t.cucumber_opts = "#{SAMPLE_FEATURE_FILE}:6"
end
As a developer on server with multiple users
I want to be able to configure which port my wire server runs on
So that I can avoid port conflicts
Feature: High strung
Scenario: Wired
Given we're all wired
host: localhost port: <%= ENV['PORT'] || 12345 %>
request | response |
["step_matches",{"name_to_match":"we're all wired"}] | ["success",[]] |
U 1 scenario (1 undefined) 1 step (1 undefined)
host: localhost port: <%= ENV['PORT'] || 12345 %>
request | response |
["step_matches",{"name_to_match":"we're all wired"}] | ["success",[]] |
U 1 scenario (1 undefined) 1 step (1 undefined)
When the server sends us back a message we don't understand, this is how Cucumber will behave.
Feature: High strung
Scenario: Wired
Given we're all wired
host: localhost port: 54321
request | response |
["begin_scenario"] | ["yikes"] |
["step_matches",{"name_to_match":"we're all wired"}] | ["success",[{"id":"1", "args":[]}]] |
undefined method `handle_yikes'
Assuming a StepMatch was returned for a given step name, when it's time to
invoke that step definition, Cucumber will send an invoke message.
The invoke message contains the ID of the step definition, as returned by
the wire server in response to the the step_matches call, along with the
arguments that were parsed from the step name during the same step_matches
call.
The wire server will normally reply one of the following:
* `success`
* `fail`
* `pending` - optionally takes a message argument
This isn't quite the whole story: see also table_diffing.feature
Feature: High strung
Scenario: Wired
Given we're all wired
host: localhost port: 54321
request | response |
["step_matches",{"name_to_match":"we're all wired"}] | ["success",[{"id":"1", "args":[]}]] |
["begin_scenario"] | ["success"] |
["invoke",{"id":"1","args":[]}] | ["pending", "I'll do it later"] |
["end_scenario"] | ["success"] |
Feature: High strung
Scenario: Wired
Given we're all wired
I'll do it later (Cucumber::Pending)
features/wired.feature:3:in `Given we're all wired'
1 scenario (1 pending)
1 step (1 pending)
request | response |
["step_matches",{"name_to_match":"we're all wired"}] | ["success",[{"id":"1", "args":[]}]] |
["begin_scenario"] | ["success"] |
["invoke",{"id":"1","args":[]}] | ["success"] |
["end_scenario"] | ["success"] |
. 1 scenario (1 passed) 1 step (1 passed)
request | response |
["step_matches",{"name_to_match":"we're all wired"}] | ["success",[{"id":"1", "args":[]}]] |
["begin_scenario"] | ["success"] |
["invoke",{"id":"1","args":[]}] | ["fail",{"message":"The wires are down", "exception":"Some.Foreign.ExceptionType"}] |
["end_scenario"] | ["success"] |
F (::) failed steps (::) The wires are down (Some.Foreign.ExceptionType from localhost:54321) features/wired.feature:3:in `Given we're all wired' Failing Scenarios: cucumber features/wired.feature:2 # Scenario: Wired 1 scenario (1 failed) 1 step (1 failed)
request | response |
["step_matches",{"name_to_match":"we're all wired"}] | ["success",[{"id":"1", "args":[{"val":"wired", "pos":10}]}]] |
["begin_scenario"] | ["success"] |
["invoke",{"id":"1","args":["wired"]}] | ["success"] |
["end_scenario"] | ["success"] |
. 1 scenario (1 passed) 1 step (1 passed)
Feature: High strung
Scenario: Wired and more
Given we're all:
| wired |
| high |
| happy |request | response |
["step_matches",{"name_to_match":"we're all:"}] | ["success",[{"id":"1", "args":[{"val":"we're", "pos":0}]}]] |
["begin_scenario"] | ["success"] |
["invoke",{"id":"1","args":["we're",[["wired"],["high"],["happy"]]]}] | ["success"] |
["end_scenario"] | ["success"] |
. 1 scenario (1 passed) 1 step (1 passed)
Feature:
Scenario Outline:
Given we're all <arg>
Examples:
| arg |
| wired |request | response |
["step_matches",{"name_to_match":"we're all wired"}] | ["success",[{"id":"1", "args":[]}]] |
["begin_scenario"] | ["success"] |
["invoke",{"id":"1","args":[]}] | ["success"] |
["end_scenario"] | ["success"] |
. 1 scenario (1 passed) 1 step (1 passed)
step_matches |
begin_scenario |
invoke |
end_scenario |
If a step doesn't match, Cucumber will ask the wire server to return a snippet of code for a
step definition.
Feature: High strung
Scenario: Wired
Given we're all wired
host: localhost port: 54321
request | response |
["step_matches",{"name_to_match":"we're all wired"}] | ["success",[]] |
["snippet_text",{"step_keyword":"Given","multiline_arg_class":"","step_name":"we're all wired"}] | ["success","foo()
bar;
baz"] |
["begin_scenario"] | ["success"] |
["end_scenario"] | ["success"] |
Feature: High strung
Scenario: Wired # features/wired.feature:2
Given we're all wired # features/wired.feature:3
1 scenario (1 undefined)
1 step (1 undefined)You can implement step definitions for undefined steps with these snippets: foo() bar; baz
When the features have been parsed, Cucumber will send a `step_matches`
message to ask the wire server if it can match a step name. This happens for
each of the steps in each of the features.
The wire server replies with an array of StepMatch objects.
When each StepMatch is returned, it contains the following data:
* `id` - identifier for the step definition to be used later when if it
needs to be invoked. The identifier can be any string value and
is simply used for the wire server's own reference.
* `args` - any argument values as captured by the wire end's own regular
expression (or other argument matching) process.
Feature: High strung
Scenario: Wired
Given we're all wired
host: localhost port: 54321
request | response |
["step_matches",{"name_to_match":"we're all wired"}] | ["success",[]] |
U 1 scenario (1 undefined) 1 step (1 undefined)
request | response |
["step_matches",{"name_to_match":"we're all wired"}] | ["success",[{"id":"1", "args":[]}]] |
- 1 scenario (1 skipped) 1 step (1 skipped)
request | response |
["step_matches",{"name_to_match":"we're all wired"}] | ["success",[{"id":"1", "args":[], "source":"MyApp.MyClass:123", "regexp":"we.*"}]] |
- we.* # MyApp.MyClass:123 1 scenario (1 skipped) 1 step (1 skipped)
In order to use the amazing functionality in the Cucumber table object
As a wire server
I want to be able to ask for a table diff during a step definition invocation
Feature: Hello
Scenario: Wired
Given we're all wired
host: localhost port: 54321
request | response |
["step_matches",{"name_to_match":"we're all wired"}] | ["success",[{"id":"1", "args":[]}]] |
["begin_scenario"] | ["success"] |
["invoke",{"id":"1","args":[]}] | ["diff",[[["a","b"],["c","d"]],[["x","y"],["z","z"]]]] |
["diff_failed"] | ["fail",{"message":"Not same", "exception":"DifferentException", "backtrace":["a.cs:12","b.cs:34"]}] |
["end_scenario"] | ["success"] |
F (::) failed steps (::) Not same (DifferentException from localhost:54321) a.cs:12 b.cs:34 features/wired.feature:3:in `Given we're all wired' Failing Scenarios: cucumber features/wired.feature:2 # Scenario: Wired 1 scenario (1 failed) 1 step (1 failed)
request | response |
["step_matches",{"name_to_match":"we're all wired"}] | ["success",[{"id":"1", "args":[]}]] |
["begin_scenario"] | ["success"] |
["invoke",{"id":"1","args":[]}] | ["diff",[[["a"],["b"]],[["a"],["b"]]]] |
["diff_ok"] | ["success"] |
["end_scenario"] | ["success"] |
. 1 scenario (1 passed) 1 step (1 passed)
request | response |
["step_matches",{"name_to_match":"we're all wired"}] | ["success",[{"id":"1", "args":[]}]] |
["begin_scenario"] | ["success"] |
["invoke",{"id":"1","args":[]}] | ["diff",[[["a"],["b"]],[["a"],["b"]]]] |
["diff_ok"] | ["fail",{"message":"I wanted things to be different for us"}] |
["end_scenario"] | ["success"] |
F (::) failed steps (::) I wanted things to be different for us (Cucumber::WireSupport::WireException) features/wired.feature:3:in `Given we're all wired' Failing Scenarios: cucumber features/wired.feature:2 # Scenario: Wired 1 scenario (1 failed) 1 step (1 failed)
request | response |
["step_matches",{"name_to_match":"we're all wired"}] | ["success",[{"id":"1", "args":[]}]] |
["begin_scenario"] | ["success"] |
["invoke",{"id":"1","args":[]}] | ["diff!",[[["a"]],[["b"]]]] |
["end_scenario"] | ["success"] |
F (::) failed steps (::) Tables were not identical: | (-) a | (+) b | (Cucumber::MultilineArgument::DataTable::Different) features/wired.feature:3:in `Given we're all wired' Failing Scenarios: cucumber features/wired.feature:2 # Scenario: Wired 1 scenario (1 failed) 1 step (1 failed) 0m0.012s
In order to use Before and After hooks in a wire server, we send tags with the
scenario in the begin_scenario and end_scenario messages
host: localhost port: 54321
@foo @bar
Feature: Wired
@baz
Scenario: Everybody's Wired
Given we're all wired
request | response |
["step_matches",{"name_to_match":"we're all wired"}] | ["success",[{"id":"1", "args":[]}]] |
["begin_scenario", {"tags":["bar","baz","foo"]}] | ["success"] |
["invoke",{"id":"1","args":[]}] | ["success"] |
["end_scenario", {"tags":["bar","baz","foo"]}] | ["success"] |
@foo @bar
Feature: Wired
@baz
Scenario: Everybody's Wired
Given we're all wired
1 scenario (1 passed)
1 step (1 passed)
@foo @bar
Feature: Wired
@baz
Scenario Outline: Everybody's Wired
Given we're all <something>
Examples:
| something |
| wired |
request | response |
["step_matches",{"name_to_match":"we're all wired"}] | ["success",[{"id":"1", "args":[]}]] |
["begin_scenario", {"tags":["bar","baz","foo"]}] | ["success"] |
["invoke",{"id":"1","args":[]}] | ["success"] |
["end_scenario", {"tags":["bar","baz","foo"]}] | ["success"] |
@foo @bar
Feature: Wired
@baz
Scenario Outline: Everybody's Wired
Given we're all <something>
Examples:
| something |
| wired |
1 scenario (1 passed)
1 step (1 passed)
We don't want Cucumber to hang forever on a wire server that's not even there,
but equally we need to give the user the flexibility to allow step definitions
to take a while to execute, if that's what they need.
Feature: Telegraphy
Scenario: Wired
Given we're all wired
host: localhost port: 54321
Unable to contact the wire server at localhost:54321
host: localhost port: 54321 timeout: invoke: 0.1
request | response |
["step_matches",{"name_to_match":"we're all wired"}] | ["success",[{"id":"1", "args":[{"val":"wired", "pos":10}]}]] |
["begin_scenario"] | ["success"] |
["invoke",{"id":"1","args":["wired"]}] | ["success"] |
["end_scenario"] | ["success"] |
Feature: Telegraphy
Scenario: Wired # features/wired.feature:2
Given we're all wired # Unknown
Timed out calling wire server with message 'invoke' (Timeout::Error)
features/wired.feature:3:in `Given we're all wired'
Failing Scenarios:
cucumber features/wired.feature:2 # Scenario: Wired
1 scenario (1 failed)
1 step (1 failed)
In order to ensure that feature scenarios do not pass until they are expected to
Developers should be able to run cucumber in a mode that
- will fail if any scenario passes completely
- will not fail otherwise
Feature: WIP
@failing
Scenario: Failing
Given this step raises an error
@undefined
Scenario: Undefined
Given this step is undefined
@pending
Scenario: Pending
Given this step is pending
@passing
Scenario: Passing
Given this step passesFeature: Not WIP
Scenario Outline: Passing
Given this step <what>
Examples:
| what |
| passes |Feature: WIP
@failing
Scenario: Failing
Given this step raises an error
error (RuntimeError)
./features/step_definitions/steps.rb:2:in `/^this step raises an error$/'
features/wip.feature:4:in `Given this step raises an error'
Failing Scenarios:
cucumber features/wip.feature:3
1 scenario (1 failed)
1 step (1 failed)The --wip switch was used, so the failures were expected. All is good.
Feature: WIP
@undefined
Scenario: Undefined
Given this step is undefined
1 scenario (1 undefined)
1 step (1 undefined)The --wip switch was used, so the failures were expected. All is good.
Feature: WIP
@pending
Scenario: Pending
Given this step is pending
TODO (Cucumber::Pending)
./features/step_definitions/steps.rb:3:in `/^this step is pending$/'
features/wip.feature:12:in `Given this step is pending'
1 scenario (1 pending)
1 step (1 pending)The --wip switch was used, so the failures were expected. All is good.
Feature: WIP
@passing
Scenario: Passing
Given this step passes
1 scenario (1 passed)
1 step (1 passed)The --wip switch was used, so I didn't expect anything to pass. These scenarios passed: (::) passed scenarios (::) features/wip.feature:15:in `Scenario: Passing'
Feature: Not WIP
Scenario Outline: Passing
Given this step <what>
Examples:
| what |
| passes |
1 scenario (1 passed)
1 step (1 passed)The --wip switch was used, so I didn't expect anything to pass. These scenarios passed: (::) passed scenarios (::) features/passing_outline.feature:7:in `Scenario Outline: Passing, Examples (#1)'
After hooks can be used to clean up any state you've altered during your
scenario, or to check the status of the scenario and act accordingly.
You can ask a scenario whether it has failed, for example.
Mind you, even if it hasn't failed yet, you can still make the scenario
fail if your After hook throws an error.
After do |scenario| puts scenario.status.inspect end
Feature:
Scenario:
Given this step <result>result | status symbol |
|---|---|
passes | :passed |
fails | :failed |
is pending | :pending |
After do |scenario|
if scenario.failed?
puts "eek"
end
endFeature:
Scenario:
Given this step failseek
After do fail 'yikes' end
Feature:
Scenario:
Given this step passes Scenario: # features/pass.feature:2
Given this step passes # features/step_definitions/steps.rb:1
yikes (RuntimeError)
./features/support/bad_hook.rb:2:in `After'After do puts "First" end After do puts "Second" end
Feature:
Scenario:
Given this step passesSecond First
In order to support transactional scenarios for database libraries
that provide only a block syntax for transactions, Cucumber should
permit definition of Around hooks.
Then /^the hook is called$/ do expect($hook_called).to be true end
Around do |scenario, block| $hook_called = true block.call end
Feature: Around hooks
Scenario: using hook
Then the hook is calledFeature: Around hooks
Scenario: using hook # features/f.feature:2
Then the hook is called # features/step_definitions/steps.rb:1
1 scenario (1 passed)
1 step (1 passed)
Then /^the hooks are called in the correct order$/ do expect($hooks_called).to eq ['A', 'B', 'C'] end
Around do |scenario, block| $hooks_called ||= [] $hooks_called << 'A' block.call end Around do |scenario, block| $hooks_called ||= [] $hooks_called << 'B' block.call end Around do |scenario, block| $hooks_called ||= [] $hooks_called << 'C' block.call end
Feature: Around hooks
Scenario: using multiple hooks
Then the hooks are called in the correct orderFeature: Around hooks
Scenario: using multiple hooks # features/f.feature:2
Then the hooks are called in the correct order # features/step_definitions/steps.rb:1
1 scenario (1 passed)
1 step (1 passed)
Then /^the Around hook is called around Before and After hooks$/ do expect($hooks_called).to eq ['Around', 'Before'] end
Around do |scenario, block| $hooks_called ||= [] $hooks_called << 'Around' block.call $hooks_called << 'Around' $hooks_called.should == ['Around', 'Before', 'After', 'Around'] #TODO: Find out why this fails using the new rspec expect syntax. end Before do |scenario| $hooks_called ||= [] $hooks_called << 'Before' end After do |scenario| $hooks_called ||= [] $hooks_called << 'After' expect($hooks_called).to eq ['Around', 'Before', 'After'] end
Feature: Around hooks
Scenario: Mixing Around, Before, and After hooks
Then the Around hook is called around Before and After hooksFeature: Around hooks
Scenario: Mixing Around, Before, and After hooks # features/f.feature:2
Then the Around hook is called around Before and After hooks # features/step_definitions/steps.rb:1
1 scenario (1 passed)
1 step (1 passed)
Then /^the Around hooks with matching tags are called$/ do expect($hooks_called).to eq ['one', 'one or two'] end
Around('@one') do |scenario, block|
$hooks_called ||= []
$hooks_called << 'one'
block.call
end
Around('@one,@two') do |scenario, block|
$hooks_called ||= []
$hooks_called << 'one or two'
block.call
end
Around('@one', '@two') do |scenario, block|
$hooks_called ||= []
$hooks_called << 'one and two'
block.call
end
Around('@two') do |scenario, block|
$hooks_called ||= []
$hooks_called << 'two'
block.call
endFeature: Around hooks
@one
Scenario: Around hooks with tags
Then the Around hooks with matching tags are calledFeature: Around hooks
@one
Scenario: Around hooks with tags
Then the Around hooks with matching tags are called
1 scenario (1 passed)
1 step (1 passed)
Then /^the hook is called$/ do expect($hook_called).to be true end
Around do |scenario, block| $hook_called = true block.call end
Feature: Around hooks with scenario outlines
Scenario Outline: using hook
Then the hook is called
Examples:
| Number |
| one |
| two |Feature: Around hooks with scenario outlines
Scenario Outline: using hook # features/f.feature:2
Then the hook is called # features/f.feature:3
Examples:
| Number |
| one |
| two |
2 scenarios (2 passed)
2 steps (2 passed)
Then /^the world should be available in the hook$/ do $previous_world = self expect($hook_world).to eq(self) end Then /^what$/ do expect($hook_world).not_to eq($previous_world) end
Around do |scenario, block| $hook_world = self block.call end
Feature: Around hooks
Scenario: using hook
Then the world should be available in the hook
Scenario: using the same hook
Then whatFeature: Feature name
Scenario: Scenario name
Given a stepnames = []
Before do |scenario|
expect(scenario).to_not respond_to(:scenario_outline)
names << scenario.feature.name.split("\n").first
names << scenario.name.split("\n").first
if(names.size == 2)
raise "NAMES:\n" + names.join("\n") + "\n"
end
endNAMES: Feature name Scenario name
Feature: Feature name
Scenario Outline: Scenario Outline name
Given a <placeholder>
Examples: Examples Table name
| <placeholder> |
| step |names = []
Before do |scenario|
names << scenario.scenario_outline.feature.name.split("\n").first
names << scenario.scenario_outline.name.split("\n").first
names << scenario.name.split("\n").first
if(names.size == 3)
raise "NAMES:\n" + names.join("\n") + "\n"
end
end NAMES:
Feature name
Scenario Outline name, Examples Table name (#1)
Scenario Outline name, Examples Table name (#1)
Given /^background step$/ do; $EventOrder.push(:background_step) end Given /^scenario step$/ do; $EventOrder.push(:scenario_step) end
$EventOrder = []
Around('@around') do |scenario,block|
$EventOrder.push :around_begin
block.call
$EventOrder.push :around_end
end
Before('@before') do
$EventOrder.push :before
end
After('@after') do |scenario|
$EventOrder.push :after
end
at_exit {
puts "Event order: #{$EventOrder.join(' ')}"
}@around
Feature: Around hooks cover background steps
Background:
Given background step
Scenario:
Given scenario step@around
@before
@after
Feature: All hooks execute in expected order
Background:
Given background step
Scenario:
Given scenario stepEvent order: around_begin background_step scenario_step around_end
Event order: around_begin before background_step scenario_step after around_end
When you're developing a gem, it's convenient if your project's `lib` directory
is already in the load path. Cucumber does this for you.
require 'something'
class Something end
You can pass state between step by setting instance variables,
but those instance variables will be gone when the next scenario runs.
Feature:
Scenario:
Given I have set @flag = true
Then @flag should be true
Scenario:
Then @flag should be nilGiven /set @flag/ do @flag = true end Then /flag should be true/ do expect(@flag).to be_truthy end Then /flag should be nil/ do expect(@flag).to be_nil end
Before('~@no-boom') do
raise 'boom'
endFeature: With and without hooks
Scenario: using hook
Given this step passes
@no-boom
Scenario: omitting hook
Given this step passes
Scenario Outline: omitting hook on specified examples
Given this step passes
Examples:
| Value |
| Irrelevant |
@no-boom
Examples:
| Value |
| Also Irrelevant |Feature: With and without hooks
Scenario: using hook # features/f.feature:2
boom (RuntimeError)
./features/support/hooks.rb:2:in `Before'
Given this step passes # features/step_definitions/steps.rb:1
Failing Scenarios:
cucumber features/f.feature:2 # Scenario: using hook
1 scenario (1 failed)
1 step (1 skipped)
0m0.012s
Feature: With and without hooks
@no-boom
Scenario: omitting hook # features/f.feature:6
Given this step passes # features/step_definitions/steps.rb:1
1 scenario (1 passed)
1 step (1 passed)
0m0.012s
Feature: With and without hooks
Scenario Outline: omitting hook on specified examples # features/f.feature:9
Given this step passes # features/f.feature:10
Examples:
| Value |
boom (RuntimeError)
./features/support/hooks.rb:2:in `Before'
| Irrelevant |
Failing Scenarios:
cucumber features/f.feature:14 # Scenario Outline: omitting hook on specified examples, Examples (#1)
1 scenario (1 failed)
1 step (1 skipped)
0m0.012s