lib/allure-cucumber/formatter.rb in allure-cucumber-0.4.4 vs lib/allure-cucumber/formatter.rb in allure-cucumber-0.5.0

- old
+ new

@@ -4,185 +4,200 @@ module AllureCucumber class Formatter include AllureCucumber::DSL + + TEST_HOOK_NAMES_TO_IGNORE = ['Before hook', 'After hook'] + POSSIBLE_STATUSES = ['passed', 'failed', 'pending', 'skipped', 'undefined'] + def initialize(step_mother, io, options) dir = Pathname.new(AllureCucumber::Config.output_dir) FileUtils.rm_rf(dir) + FileUtils.mkdir_p(dir) @tracker = AllureCucumber::FeatureTracker.create + @deferred_before_test_steps = [] + @deferred_after_test_steps = [] end + # Start the test suite def before_feature(feature) - @has_background = false feature_identifier = ENV['FEATURE_IDENTIFIER'] && "#{ENV['FEATURE_IDENTIFIER']} - " @tracker.feature_name = "#{feature_identifier}#{feature.name.gsub(/\n/, " ")}" - AllureRubyAdaptorApi::Builder.start_suite(@tracker.feature_name, :severity => :normal) + AllureRubyAdaptorApi::Builder.start_suite(@tracker.feature_name) end - def before_background(*args) - @in_background = true - @has_background = true - @background_before_steps = [] - @background_after_steps = [] + # Find sceanrio type + def before_feature_element(feature_element) + @scenario_outline = feature_element.instance_of?(Cucumber::Core::Ast::ScenarioOutline) end - - def after_background(*args) - @in_background = false + + def scenario_name(keyword, name, *args) + scenario_name = (name.nil? || name == "") ? "Unnamed scenario" : name.gsub(/\n/, " ") + @scenario_outline ? @scenario_outline_name = scenario_name : @tracker.scenario_name = scenario_name end - def before_feature_element(feature_element) - @scenario_outline = feature_element.instance_of?(Cucumber::Ast::ScenarioOutline) + def before_examples(*args) + @header_row = true + @row_count = 0 end - - def scenario_name(keyword, name, file_colon_line, source_indent) - unless @scenario_outline - @tracker.scenario_name = (name.nil? || name == "") ? "Unnamed scenario" : name.gsub(/\n/, " ") - AllureRubyAdaptorApi::Builder.start_test(@tracker.feature_name, @tracker.scenario_name, :feature => @tracker.feature_name, :story => @tracker.scenario_name) - @tracker.scenario_started_at = Time.now - post_background_steps if @has_background - else - @scenario_outline_name = (name.nil? || name == "") ? "Unnamed scenario" : name.gsub(/\n/, " ") - end - end + # Start the test for normal scenarios def before_steps(steps) - @example_before_steps = [] - @example_after_steps = [] - @exception = nil - end - - def before_step(step) - unless step.background? - unless @scenario_outline - @tracker.step_name = step.name - AllureRubyAdaptorApi::Builder.start_step(@tracker.feature_name, @tracker.scenario_name, @tracker.step_name) - attach_multiline_arg(step.multiline_arg) - else - @example_before_steps << step - end - else - @background_before_steps << step + if !@scenario_outline + start_test end end - - def after_step(step) - unless step.background? - unless @scenario_outline - AllureRubyAdaptorApi::Builder.stop_step(@tracker.feature_name, @tracker.scenario_name, @tracker.step_name, step.status.to_sym) - else - @example_after_steps << step - end - else - @background_after_steps << step + + # Stop the test for normal scenarios + def after_steps(steps) + if !@scenario_outline + result = test_result(steps) + stop_test(result) end end - def after_steps(steps) - return if @in_background || @scenario_outline - result = { :status => steps.status, :exception => steps.exception, :started_at => @tracker.scenario_started_at, :finished_at => Time.now } - AllureRubyAdaptorApi::Builder.stop_test(@tracker.feature_name, @tracker.scenario_name, result) + # Start the test for scenario examples + def before_table_row(table_row) + if @scenario_outline && !@header_row && !@in_multiline_arg + @row_count += 1 + @tracker.scenario_name = "Example #{@row_count} : #{@scenario_outline_name}" + start_test + end end - def before_examples(*args) - @header_row = true - @in_examples = true - end - - def before_examples(*args) - @header_row = true - @in_examples = true - end - - def before_outline_table(outline_table) - headers = outline_table.headers - rows = outline_table.rows - @current_row = -1 - @table = [] - rows.each do |element| - row_hash = {} - element.each_with_index do |item, index| - row_hash[headers[index]] = item + # Stop the test for scenario examples + def after_table_row(table_row) + unless @multiline_arg + if @scenario_outline && !@header_row + result = test_result(table_row) + stop_test(result) end - @table << row_hash + @header_row = false end end - def before_table_row(table_row) - return unless @in_examples - unless @header_row - @scenario_status = :passed - @exception = nil - @tracker.scenario_name = "#{@scenario_outline_name} Example: #{table_row.name}" - AllureRubyAdaptorApi::Builder.start_test(@tracker.feature_name, @tracker.scenario_name, :feature => @tracker.feature_name, :story => @tracker.scenario_name) - @tracker.scenario_started_at = Time.now - post_background_steps if @has_background - @current_row += 1 - @example_before_steps.each do |step| - @tracker.step_name = transform_step_name_for_outline(step.name, @current_row) - AllureRubyAdaptorApi::Builder.start_step(@tracker.feature_name, @tracker.scenario_name, @tracker.step_name) - attach_multiline_arg(step.multiline_arg) - end + def before_test_step(test_step) + if !TEST_HOOK_NAMES_TO_IGNORE.include?(test_step.name) + if @tracker.scenario_name + @tracker.step_name = test_step.name + start_step + else + @deferred_before_test_steps << {:step => test_step, :timestamp => Time.now} + end end end - def after_table_row(table_row) - return unless @in_examples or Cucumber::Ast::OutlineTable::ExampleRow === table_row - unless @header_row - @example_after_steps.each do |step| - @tracker.step_name = transform_step_name_for_outline(step.name, @current_row) - if table_row.status == :failed - @exception = table_row.exception - @scenario_status = :failed - end - AllureRubyAdaptorApi::Builder.stop_step(@tracker.feature_name, @tracker.scenario_name, @tracker.step_name, step.status.to_sym) + def after_test_step(test_step, result) + if !TEST_HOOK_NAMES_TO_IGNORE.include?(test_step.name) + if @tracker.scenario_name + status = step_status(result) + stop_step(status) + else + @deferred_after_test_steps << {:step => test_step, :result => result, :timestamp => Time.now} end - AllureRubyAdaptorApi::Builder.stop_test(@tracker.feature_name, @tracker.scenario_name, {:status => @scenario_status, :exception => @exception, :started_at => @tracker.scenario_started_at, :finished_at => Time.now }) end - @header_row = false if @header_row end - def after_outline_table(*args) - @in_examples = false - end - + # Stop the suite def after_feature(feature) AllureRubyAdaptorApi::Builder.stop_suite(@tracker.feature_name) end def after_features(features) AllureRubyAdaptorApi::Builder.build! end + def before_multiline_arg(multiline_arg) + @in_multiline_arg = true + # For background steps defer multiline attachment + if @tracker.scenario_name.nil? + @deferred_before_test_steps[-1].merge!({:multiline_arg => multiline_arg}) + else + attach_multiline_arg_to_file(multiline_arg) + end + end + + def after_multiline_arg(multiline_arg) + @in_multiline_arg = false + end + private + + def step_status(result) + POSSIBLE_STATUSES.each do |status| + return cucumber_status_to_allure_status(status) if result.send("#{status}?") + end + end - def transform_step_name_for_outline(step_name, row_num) - transformed_name = '' - @table[row_num].each do |k, v| - transformed_name == '' ? transformed_name = step_name.gsub(k, v) : transformed_name = transformed_name.gsub(k,v) + def test_result(result) + status = cucumber_status_to_allure_status(result.status) + exception = status == 'failed' && result.exception.nil? ? Exception.new("Some steps were undefined") : result.exception + if exception + return {:status => status, :exception => exception} + else + return {:status => status} end - transformed_name end + + def cucumber_status_to_allure_status(status) + case status.to_s + when "undefined" + return "failed" + when "skipped" + return "pending" + else + return status.to_s + end + end + + def attach_multiline_arg_to_file(multiline_arg) + dir = File.expand_path(AllureCucumber::Config.output_dir) + out_file = "#{dir}/#{UUID.new.generate}.txt" + File.open(out_file, "w+") { |file| file.write(multiline_arg.to_s.gsub(/\e\[(\d+)(;\d+)*m/,'')) } + attach_file("multiline_arg", File.open(out_file)) + end - def attach_multiline_arg(multiline_arg) - if multiline_arg - File.open('tmp_file.txt', 'w'){ |file| file.write(multiline_arg.to_s.gsub(/\e\[(\d+)(;\d+)*m/,'')) } - attach_file("table", File.open('tmp_file.txt')) + def start_test + if @tracker.scenario_name + AllureRubyAdaptorApi::Builder.start_test(@tracker.feature_name, @tracker.scenario_name, :feature => @tracker.feature_name, :story => @tracker.scenario_name) + post_deferred_steps end end - def post_background_steps - @background_before_steps.each do |step| - @tracker.step_name = "Background : #{step.name}" - AllureRubyAdaptorApi::Builder.start_step(@tracker.feature_name, @tracker.scenario_name, @tracker.step_name) - attach_multiline_arg(step.multiline_arg) + def post_deferred_steps + @deferred_before_test_steps.size.times do |index| + @tracker.step_name = @deferred_before_test_steps[index][:step].name + start_step + multiline_arg = @deferred_before_test_steps[index][:multiline_arg] + attach_multiline_arg_to_file(multiline_arg) if multiline_arg + if index < @deferred_after_test_steps.size + result = step_status(@deferred_after_test_steps[index][:result]) + stop_step(result) + end end - @background_before_steps.each do |step| - @tracker.step_name = "Background : #{step.name}" - AllureRubyAdaptorApi::Builder.stop_step(@tracker.feature_name, @tracker.scenario_name, @tracker.step_name, step.status.to_sym) - attach_multiline_arg(step.multiline_arg) - end end + def stop_test(result) + if @deferred_before_test_steps != [] + result[:started_at] = @deferred_before_test_steps[0][:timestamp] + end + if @tracker.scenario_name + AllureRubyAdaptorApi::Builder.stop_test(@tracker.feature_name, @tracker.scenario_name, result) + @tracker.scenario_name = nil + @deferred_before_test_steps = [] + @deferred_after_test_steps = [] + end + end + + def start_step(step_name = @tracker.step_name) + AllureRubyAdaptorApi::Builder.start_step(@tracker.feature_name, @tracker.scenario_name, step_name) + end + + def stop_step(status, step_name = @tracker.step_name) + AllureRubyAdaptorApi::Builder.stop_step(@tracker.feature_name, @tracker.scenario_name, step_name, status) + end + end end +