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

Handle data tables #16

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
Open
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
20 changes: 20 additions & 0 deletions acceptance/cucumber/cucumber_example.feature
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,23 @@ Feature: Example Cucumber feature
Given that I can't code for peanuts
And I write step definitions that throw exceptions
Then I shouldn't be allowed out in public

Scenario: Using a data table in a scenario
Given that I want to include the following data table
| Data Column 1 | Data Column 2 | Data Column 3 |
| Data Cell A | Data Cell B | Data Cell C |
| Data Cell D | Data Cell E | Data Cell F |
Then I should not see each row in the table treated as a separate example

Scenario Outline: Using a scenario outline
Given that I might use a scenario outline with a data table and an examples table
And that I want to include the following data table
| Data Column 4 | Data Column 5 | Data Column 6 |
| Data Cell G | Data Cell H | Data Cell I |
| Data Cell J | Data Cell K | Data Cell L |
Then I want values for <Example Column 1>, <Example Column 2>, and <Example Column 3>

Examples:
| Example Column 1 | Example Column 2 | Example Column 3 |
| Example Cell A | Example Cell B | Example Cell C |
| Example Cell D | Example Cell E | Example Cell F |
16 changes: 16 additions & 0 deletions acceptance/cucumber/step_definitions/development_steps.rb
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,19 @@

Then /^I shouldn't be allowed out in public$/ do
end

Given /^that I want to include the following data table$/ do |table|
expect(table).to be_a(Cucumber::Ast::Table)
end

Then /^I should not see each row in the table treated as a separate example$/ do
end

Given /^that I might use a scenario outline with a data table and an examples table$/ do
end

Then /^I want values for (.*), (.*), and (.*)$/ do |arg_1, arg_2, arg_3|
expect(arg_1).to be_a(String)
expect(arg_2).to be_a(String)
expect(arg_3).to be_a(String)
end
31 changes: 30 additions & 1 deletion acceptance/verification_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
it { is_expected.to have(0).errors }
it { expect(result.skipped_count).to be 1 }
it { is_expected.to have(2).failures }
it { is_expected.to have(4).testcases }
it { is_expected.to have(7).testcases }

it_behaves_like "a report with consistent attribute counts"
it_behaves_like "assertions are not tracked"
Expand Down Expand Up @@ -56,6 +56,35 @@
end
end
end

describe "the test that uses a data table" do
subject(:testcase) { result.testcase('Using a data table in a scenario') }

it { is_expected.to have(0).failures }
end

context "the scenario outline with an examples table" do

let(:scenario_name) { 'Using a scenario outline' }
let(:example_1_string) { '| Example Cell A | Example Cell B | Example Cell C |' }
let(:example_2_string) { '| Example Cell D | Example Cell E | Example Cell F |' }

describe "the first example in the table" do
subject(:testcase) {
result.testcase("#{scenario_name} (outline: #{example_1_string})")
}

it { is_expected.to have(0).failures }
end

describe "the second example in the table" do
subject(:testcase) {
result.testcase("#{scenario_name} (outline: #{example_2_string})")
}

it { is_expected.to have(0).failures }
end
end
end

def load_xml_result(path)
Expand Down
84 changes: 53 additions & 31 deletions lib/ci/reporter/cucumber.rb
Original file line number Diff line number Diff line change
Expand Up @@ -65,39 +65,61 @@ def feature_name(keyword, name)
@name = (name || "Unnamed feature").split("\n").first
end

def before_feature_element(feature_element)
@feature_element = feature_element
end

def after_feature_element(feature_element)
@feature_element = nil
end

def feature_element_type
if @feature_element.instance_of?(::Cucumber::Ast::Scenario)
return :scenario
elsif @feature_element.instance_of?(::Cucumber::Ast::ScenarioOutline)
return :scenario_outline
else
return :unknown
end
end

def scenario_name(keyword, name, *args)
@scenario = (name || "Unnamed scenario").split("\n").first
end

def before_steps(steps)
@test_case = TestCase.new(@scenario)
@test_case.start
if feature_element_type == :scenario
@test_case = TestCase.new(@scenario)
@test_case.start
end
end

def treat_pending_as_failure?
ENV['CI_PENDING_IS_FAILURE'] == 'true'
end

def after_steps(steps)
@test_case.finish

case steps.status
when :pending, :undefined
if treat_pending_as_failure?
@test_case.failures << CucumberFailure.new(steps)
else
@test_case.name = "#{@test_case.name} (PENDING)"
@test_case.skipped = true
if feature_element_type == :scenario
@test_case.finish

case steps.status
when :pending, :undefined
if treat_pending_as_failure?
@test_case.failures << CucumberFailure.new(steps)
else
@test_case.name = "#{@test_case.name} (PENDING)"
@test_case.skipped = true
end
when :skipped
@test_case.name = "#{@test_case.name} (SKIPPED)"
@test_case.skipped = true
when :failed
@test_case.failures << CucumberFailure.new(steps)
end
when :skipped
@test_case.name = "#{@test_case.name} (SKIPPED)"
@test_case.skipped = true
when :failed
@test_case.failures << CucumberFailure.new(steps)
end

test_suite.testcases << @test_case
@test_case = nil
test_suite.testcases << @test_case
@test_case = nil
end
end

def before_examples(*args)
Expand All @@ -108,25 +130,25 @@ def after_examples(*args)
end

def before_table_row(table_row)
row = table_row # shorthand for table_row
# check multiple versions of the row and try to find the best fit
outline = (row.respond_to? :name) ? row.name :
(row.respond_to? :scenario_outline) ? row.scenario_outline :
row.to_s
@test_case = TestCase.new("#@scenario (outline: #{outline})")
@test_case.start
if table_row.respond_to?(:scenario_outline) && !@header_row
@test_case = TestCase.new("#@scenario (outline: #{table_row.name})")
@test_case.start
end
end

def after_table_row(table_row)
if @header_row
@header_row = false
return
end
@test_case.finish
if table_row.respond_to? :failed?
@test_case.failures << CucumberFailure.new(table_row) if table_row.failed?
test_suite.testcases << @test_case
@test_case = nil

if table_row.respond_to?(:scenario_outline)
@test_case.finish
if table_row.respond_to? :failed?
@test_case.failures << CucumberFailure.new(table_row) if table_row.failed?
test_suite.testcases << @test_case
@test_case = nil
end
end
end
end
Expand Down
64 changes: 64 additions & 0 deletions spec/ci/reporter/cucumber_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -84,11 +84,19 @@ def new_instance
let(:test_suite) { double("test_suite", testcases: testcases) }
let(:cucumber) { new_instance }
let(:test_case) { double("test_case", start: nil, finish: nil, name: "Step Name") }
let(:scenario) { double("scenario") }
let(:step) { double("step", :status => :passed, name: "Step Name") }

before :each do
allow(cucumber).to receive(:test_suite).and_return(test_suite)
allow(CI::Reporter::TestCase).to receive(:new).and_return(test_case)
cucumber.before_feature_element(scenario)

allow(cucumber).to receive(:feature_element_type).and_return(:scenario)
end

after :each do
cucumber.after_feature_element(scenario)
end

context "before steps" do
Expand Down Expand Up @@ -218,5 +226,61 @@ def new_instance
end
end
end

context "inside a scenario outline" do
let(:testcases) { [] }
let(:test_suite) { double("test_suite", testcases: testcases) }
let(:cucumber) { new_instance }
let(:test_case) { double("test_case", start: nil, finish: nil, name: "Step Name") }
let(:scenario_outline) { double("scenario_outline") }
let(:step_collection) { double("step_collection") }

before :each do
allow(cucumber).to receive(:test_suite).and_return(test_suite)
allow(CI::Reporter::TestCase).to receive(:new).and_return(test_case)

cucumber.before_feature_element(scenario_outline)
cucumber.scenario_name(nil, "Scenario Name")

allow(cucumber).to receive(:feature_element_type).and_return(:scenario_outline)
end

after :each do
cucumber.after_feature_element(scenario_outline)
end

context "before steps" do
it "does not create a new test case" do
expect(CI::Reporter::TestCase).to_not receive(:new)
cucumber.before_steps(step_collection)
end
end

context "processing a data table" do
let(:table_row) { double("table_row", name: "Table Row Name") }

describe "before table row" do
it "does not create a new test case" do
expect(CI::Reporter::TestCase).to_not receive(:new)
cucumber.before_table_row(table_row)
end
end
end

context "processing an examples table" do
let(:table_row) do
double("table_row", name: "Table Row Name", scenario_outline: scenario_outline)
end
let(:expected_test_case_name) { "Scenario Name (outline: Table Row Name)" }

describe "before table row" do
it "creates a new test case" do
expect(CI::Reporter::TestCase).to receive(:new).with(expected_test_case_name)
cucumber.before_table_row(table_row)
end
end
end
end

end
end