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 passes
require '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 fails
Feature: 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 fails
Feature: 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 undefined
Feature: 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 subdirectory
Given(/^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 state
Given(/^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 file
Given(/^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 missing
Feature: second Scenario: foo second Given missing Scenario: bar second Given missing
Feature: 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 passes
Feature: Scenario: Hit Given this step passes 1 scenario (1 passed) 1 step (1 passed)
Feature: Sample Scenario: Passing Given this step passes
features/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 fails
F.
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 expectation
Given /^failing expectation$/ do x=1 expect('this').to eq 'that' end
Feature: 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 peace
UUUUU 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 passes
Feature: Pending Scenario: Pending Given this step is pending
Feature: 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 } end
turtle! 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 end
Given /two turtles/ do steps %{ Given turtles: | name | | Sturm | | Liouville | } end
Sturm Liouville
Given /two turtles/ do steps %Q{ Given turtles: """ Sturm Liouville """ } end
Given /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 step
Given /^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 } end
turtle! turtle!
Given two turtles
Given /turtles:/ do |table| table.hashes.each do |row| puts row[:name] end end
Given /two turtles/ do step %{turtles:}, table(%{ | name | | Sturm | | Liouville | }) end
Sturm Liouville
Given /two turtles/ do step %{turtles:}, "Sturm and Lioville" end
Given /turtles:/ do |text| puts text end
Sturm and Lioville
Given /two turtles/ do step %{turtles:}, doc_string('Sturm and Lioville','math') end
Given /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_done
Feature: Scenario: When I do the action Then the action should be done
class 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) end
Feature: 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: anno2
Ann .. 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 passes
Given /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 passes
Before 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 step
Given(/^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 | })) end
Feature: 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 hair
class Person attr_accessor :age def to_s "I am #{age} years old" end end
Transform(/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 end
In 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 end
Feature: Sample Scenario: Naughty Step Given this step does something naughty Scenario: Success Given this step passes
Feature: 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 end
Feature: Sample Scenario: Naughty Step Given this step does something naughty Scenario: Success Given this step passes
Feature: 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 passes
Feature: 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 passes
Feature: 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") end
Feature: Sample Scenario: Run a good step Given this step passes
Feature: 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 passes
Feature: 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 passes
F- 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 step
require '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 end
Feature: I'll use my own Scenario: Just print me Given this step passes
module 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 end
I'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 end
I'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 end
I'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 passes
before_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 5
Given(/^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 end
step 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 something
makeYellow('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 fails
Given /^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" end
Feature: 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 fails
Feature: Subdirectory - One passing scenario, one failing scenario Scenario: Passing Given this step passes Scenario: Failing Given this step fails
Feature: Pending step Scenario: Pending Given this step is pending Scenario: Undefined Given this step is undefined
Feature: Pending step Scenario: Pending Given this step is pending Scenario: Undefined Given this step is undefined
Feature: 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 passes
Before 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 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 passes
features/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 passes
features/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 C
Given(/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' cukes
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 |
@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' cukes
Feature: 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' cukes
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 Then I should have '10' global cukes
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 |
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' end
Feature: 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 cukes
Feature: 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(', ')}" end
AfterConfiguration 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 error
default: 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 ran
foo: --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} end
Feature: 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} end
Feature: 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 missing
require 'cucumber/rake/task' Cucumber::Rake::Task.new do |t| t.cucumber_opts = %w{--quiet --no-color} end
Feature: 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 passes
Feature: 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 end
Feature: Scenario: Given this step fails
eek
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 passes
Second 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 called
Feature: 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 order
Feature: 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 hooks
Feature: 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 end
Feature: Around hooks @one Scenario: Around hooks with tags Then the Around hooks with matching tags are called
Feature: 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 what
Feature: Feature name Scenario: Scenario name Given a step
names = [] 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 end
NAMES: 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 step
Event 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 nil
Given /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' end
Feature: 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