Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

V1.3.x: Support the cucumber-reporting tools also when using Scenario Outlines #700

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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