Skip to content

Commit

Permalink
Merge pull request #700 from brasmusson/json-formatter-outline-expand
Browse files Browse the repository at this point in the history
V1.3.x: Support the cucumber-reporting tools also when using Scenario Outlines
  • Loading branch information
mattwynne committed Aug 5, 2014
2 parents 111411e + 3a4f8f6 commit b515c89
Show file tree
Hide file tree
Showing 4 changed files with 279 additions and 9 deletions.
195 changes: 195 additions & 0 deletions features/json_formatter.feature
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,23 @@ Feature: JSON output formatter
And I print from step definition
"""
And a file named "features/outline.feature" with:
"""
Feature: An outline feature
Scenario Outline: outline
Given a <type> step
Examples: examples1
| type |
| passing |
| failing |
Examples: examples2
| type |
| passing |
"""

# Need to investigate why this won't pass in-process. error_message doesn't get det?
@spawn
Expand Down Expand Up @@ -405,4 +422,182 @@ Feature: JSON output formatter
}
]
"""
@spawn
Scenario: scenario outline
When I run `cucumber --format json features/outline.feature`
Then it should fail with JSON:
"""
[
{
"uri": "features/outline.feature",
"id": "an-outline-feature",
"keyword": "Feature",
"name": "An outline feature",
"line": 1,
"description": "",
"elements": [
{
"id": "an-outline-feature;outline",
"keyword": "Scenario Outline",
"name": "outline",
"line": 3,
"description": "",
"type": "scenario_outline",
"steps": [
{
"keyword": "Given ",
"name": "a <type> step",
"line": 4,
"match": {
"location": "features/step_definitions/steps.rb:1"
}
}
],
"examples": [
{
"keyword": "Examples",
"name": "examples1",
"line": 6,
"description": "",
"id": "an-outline-feature;outline;examples1",
"rows": [
{
"cells": [
"type"
],
"line": 7,
"id": "an-outline-feature;outline;examples1;1"
},
{
"cells": [
"passing"
],
"line": 8,
"id": "an-outline-feature;outline;examples1;2"
},
{
"cells": [
"failing"
],
"line": 9,
"id": "an-outline-feature;outline;examples1;3"
}
]
},
{
"keyword": "Examples",
"name": "examples2",
"line": 11,
"description": "",
"id": "an-outline-feature;outline;examples2",
"rows": [
{
"cells": [
"type"
],
"line": 12,
"id": "an-outline-feature;outline;examples2;1"
},
{
"cells": [
"passing"
],
"line": 13,
"id": "an-outline-feature;outline;examples2;2"
}
]
}
]
}
]
}
]
"""
@spawn
Scenario: scenario outline expanded
When I run `cucumber --expand --format json features/outline.feature`
Then it should fail with JSON:
"""
[
{
"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": "a passing step",
"line": 4,
"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": "a failing step",
"line": 4,
"match": {
"location": "features/step_definitions/steps.rb:5"
},
"result": {
"status": "failed",
"error_message" : " (RuntimeError)\n./features/step_definitions/steps.rb:6:in `/a failing step/'\nfeatures/outline.feature:4:in `Given a <type> step'",
"duration": 1
}
}
]
},
{
"id": "an-outline-feature;outline;examples2;2",
"keyword": "Scenario Outline",
"name": "outline",
"line": 13,
"description": "",
"type": "scenario",
"steps": [
{
"keyword": "Given ",
"name": "a passing step",
"line": 4,
"match": {
"location": "features/step_definitions/steps.rb:1"
},
"result": {
"status": "passed",
"duration": 1
}
}
]
}
]
}
]
"""
6 changes: 4 additions & 2 deletions features/step_definitions/cucumber_steps.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,10 @@
actual.each do |feature|
feature['elements'].each do |scenario|
scenario['steps'].each do |step|
step['result']['duration'].should be >= 0
step['result']['duration'] = 1
if step['result']
step['result']['duration'].should be >= 0
step['result']['duration'] = 1
end
end
end
end
Expand Down
85 changes: 79 additions & 6 deletions lib/cucumber/formatter/gherkin_formatter_adapter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@ module Formatter
# Adapts Cucumber formatter events to Gherkin formatter events
# This class will disappear when Cucumber is based on Gherkin's model.
class GherkinFormatterAdapter
def initialize(gherkin_formatter, print_empty_match)
def initialize(gherkin_formatter, print_empty_match, options)
@gf = gherkin_formatter
@print_empty_match = print_empty_match
@options = options
end

def before_feature(feature)
Expand All @@ -28,14 +29,47 @@ def before_feature_element(feature_element)
@gf.scenario(feature_element.gherkin_statement)
when Ast::ScenarioOutline
@outline = true
@gf.scenario_outline(feature_element.gherkin_statement)
if @options[:expand]
@in_instantiated_scenario = false
@current_scenario_hash = to_hash(feature_element.gherkin_statement)
else
@gf.scenario_outline(feature_element.gherkin_statement)
end
else
raise "Bad type: #{feature_element.class}"
end
end

def scenario_name(keyword, name, file_colon_line, source_indent)
if @outline and @options[:expand]
return if not @in_instantiated_scenario
if @new_example_table
@example_row = 1
@new_example_table = false
else
@example_row += 1
end
example_row_hash = @current_example_rows[@example_row].to_hash
scenario = Gherkin::Formatter::Model::Scenario.new(
@current_scenario_hash['comments'],
@current_scenario_hash['tags'],
@current_scenario_hash['keyword'],
@current_scenario_hash['name'],
@current_scenario_hash['description'],
example_row_hash['line'],
example_row_hash['id'])
@gf.scenario(scenario)
end
end

def before_step(step)
@gf.step(step.gherkin_statement)
unless @outline and @options[:expand]
@gf.step(step.gherkin_statement)
else
if @in_instantiated_scenario
@current_step_hash = to_hash(step.gherkin_statement)
end
end
if @print_empty_match
if(@outline)
match = Gherkin::Formatter::Model::Match.new(step.gherkin_statement.outline_args, nil)
Expand All @@ -55,23 +89,52 @@ def before_step_result(keyword, step_match, multiline_arg, status, exception, so
# Trick the formatter to believe that's what was printed previously so we get arg highlights on #result
@gf.instance_variable_set('@match', match)
else
@gf.match(match)
unless @outline and @options[:expand]
@gf.match(match)
end
end

error_message = exception ? "#{exception.message} (#{exception.class})\n#{exception.backtrace.join("\n")}" : nil
unless @outline
@gf.result(Gherkin::Formatter::Model::Result.new(status, nil, error_message))
else
if @options[:expand] and @in_instantiated_scenario
@current_match = match
@current_result = Gherkin::Formatter::Model::Result.new(status, nil, error_message)
end
end
end

def step_name(keyword, step_match, status, source_indent, background, file_colon_line)
if @outline and @options[:expand] and @in_instantiated_scenario
@gf.step(Gherkin::Formatter::Model::Step.new(
@current_step_hash['comments'],
@current_step_hash['keyword'],
step_match.format_args(),
@current_step_hash['line'],
@current_step_hash['rows'],
@current_step_hash['doc_string']))
@gf.match(@current_match)
@gf.result(@current_result)
end
end

def before_examples(examples)
@gf.examples(examples.gherkin_statement)
unless @options[:expand]
@gf.examples(examples.gherkin_statement)
else
@in_instantiated_scenario = true
@new_example_table = true
@current_example_rows = to_hash(examples.gherkin_statement)['rows']
end
end

#used for capturing duration
def after_step(step)
step_finish = (Time.now - @step_time)
@gf.append_duration(step_finish)
unless @outline and @options[:expand] and not @in_instantiated_scenario
@gf.append_duration(step_finish)
end
end

def after_feature(feature)
Expand All @@ -93,6 +156,16 @@ def embed(file, mime_type, label)
def puts(message)
@gf.write(message)
end

private

def to_hash(gherkin_statement)
if defined?(JRUBY_VERSION)
gherkin_statement.toMap()
else
gherkin_statement.to_hash
end
end
end
end
end
2 changes: 1 addition & 1 deletion lib/cucumber/formatter/json.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ class Json < GherkinFormatterAdapter

def initialize(runtime, io, options)
@io = ensure_io(io, "json")
super(Gherkin::Formatter::JSONFormatter.new(@io), false)
super(Gherkin::Formatter::JSONFormatter.new(@io), false, options)
end
end
end
Expand Down

0 comments on commit b515c89

Please sign in to comment.