lib/test_spec/rspec/formatter.rb in test_spec-1.0.0 vs lib/test_spec/rspec/formatter.rb in test_spec-1.1.0

- old
+ new

@@ -1,28 +1,79 @@ +require "test_spec/rspec/example" +require "erb" +require "rouge" +require "fileutils" +require "active_support" +require "active_support/inflector" +require "active_support/core_ext/numeric" require "rspec/core/formatters/documentation_formatter" module RSpec module TestSpec + # rubocop:disable Metrics/ClassLength class Formatter < ::RSpec::Core::Formatters::DocumentationFormatter ::RSpec::Core::Formatters.register( self, :example_started, :example_passed, :example_step_passed, - :example_step_pending, :example_step_failed + :example_step_pending, :example_pending, :example_step_failed, + :example_group_finished, :example_group_started ) + DEFAULT_REPORT_PATH = File.join( + '.', 'reports', Time.now.strftime('%Y%m%d-%H%M%S') + ) + + REPORT_PATH = ENV['REPORT_PATH'] || DEFAULT_REPORT_PATH + SCREENRECORD_DIR = File.join(REPORT_PATH, 'screenrecords') + SCREENSHOT_DIR = File.join(REPORT_PATH, 'screenshots') + + def initialize(_output) + super + create_report_directory + create_screenshots_directory + create_screenrecords_directory + provide_resources + + @all_groups = {} + + # REPEATED FROM THE SUPER + # @group_level = 0 + end + # rubocop:disable Metrics/LineLength def example_started(notification) return unless notification.example.metadata[:with_steps] full_message = "#{current_indentation}#{notification.example.description}" output.puts Core::Formatters::ConsoleCodes.wrap(full_message, :default) + + # For reporter + @group_example_count += 1 end + # This comes from the DocumentationFormatter. def example_passed(notification) super unless notification.example.metadata[:with_steps] + + # For reporter + @group_example_success_count += 1 + @examples << Example.new(notification.example) end + # This comes from the DocumentationFormatter. + def example_failed(notification) + @group_example_failure_count += 1 + @examples << Example.new(notification.example) + end + + # This comes from the DocumentationFormatter. + # Needed for Reporter. + def example_pending(notification) + @group_example_pending_count += 1 + @examples << Example.new(notification.example) + end + def example_step_passed(notification) full_message = "#{current_indentation} #{notification.type.to_s.capitalize} #{notification.message}" output.puts Core::Formatters::ConsoleCodes.wrap(full_message, :success) end @@ -46,8 +97,153 @@ def example_step_failed(notification) full_message = "#{current_indentation} #{notification.type.to_s.capitalize} #{notification.message} (FAILED)" output.puts Core::Formatters::ConsoleCodes.wrap(full_message, :failure) end # rubocop:enable Metrics/LineLength + + # ADDED FOR REPORTING + + def example_group_started(_notification) + if @group_level.zero? + @examples = [] + @group_example_count = 0 + @group_example_success_count = 0 + @group_example_failure_count = 0 + @group_example_pending_count = 0 + end + + super + + # REPEATED FROM THE SUPER + # @group_level += 1 + end + + # rubocop:disable Metrics/LineLength + # rubocop:disable Metrics/MethodLength + # rubocop:disable Metrics/AbcSize + def example_group_finished(notification) + super + + return unless @group_level.zero? + + # rubocop:disable Metrics/BlockLength + File.open("#{REPORT_PATH}/#{notification.group.description.parameterize}.html", "w") do |f| + @passed = @group_example_success_count + @failed = @group_example_failure_count + @pending = @group_example_pending_count + + duration_values = @examples.map(&:run_time) + duration_keys = duration_values.size.times.to_a + + if duration_values.size < 2 && !duration_values.empty? + duration_values.unshift(duration_values.first) + duration_keys = duration_keys << 1 + end + + @title = notification.group.description + @durations = duration_keys.zip(duration_values) + @summary_duration = duration_values.inject(0) { |sum, i| sum + i }.to_s(:rounded, precision: 5) + + Example.load_spec_comments!(@examples) + + class_map = { + passed: 'success', + failed: 'danger', + pending: 'warning' + } + + statuses = @examples.map(&:status) + + status = + if statuses.include?('failed') + 'failed' + elsif statuses.include?('passed') + 'passed' + else + 'pending' + end + + @all_groups[notification.group.description.parameterize] = { + group: notification.group.description, + examples: @examples.size, + status: status, + klass: class_map[status.to_sym], + passed: statuses.select { |s| s == 'passed' }, + failed: statuses.select { |s| s == 'failed' }, + pending: statuses.select { |s| s == 'pending' }, + duration: @summary_duration + } + + template_file = File.read( + File.dirname(__FILE__) + "/../../../templates/report.erb" + ) + + f.puts ERB.new(template_file).result(binding) + end + # rubocop:enable Metrics/BlockLength + + # THIS ONE IS FROM THE SUPER + # @group_level -= 1 if @group_level > 0 + end + # rubocop:enable Metrics/MethodLength + # rubocop:enable Metrics/AbcSize + + # This is from BaseTextFormatter. + # rubocop:disable Metrics/MethodLength + # rubocop:disable Metrics/AbcSize + def close(notification) + File.open("#{REPORT_PATH}/overview.html", "w") do |f| + @overview = @all_groups + + @passed = @overview.values.map { |g| g[:passed].size }.inject(0) { |sum, i| sum + i } + @failed = @overview.values.map { |g| g[:failed].size }.inject(0) { |sum, i| sum + i } + @pending = @overview.values.map { |g| g[:pending].size }.inject(0) { |sum, i| sum + i } + + duration_values = @overview.values.map { |e| e[:duration] } + duration_keys = duration_values.size.times.to_a + + if duration_values.size < 2 + duration_values.unshift(duration_values.first) + duration_keys = duration_keys << 1 + end + + @durations = duration_keys.zip(duration_values.map { |d| d.to_f.round(5) }) + @summary_duration = duration_values.map { |d| d.to_f.round(5) }.inject(0) { |sum, i| sum + i }.to_s(:rounded, precision: 5) + @total_examples = @passed + @failed + @pending + + template_file = File.read( + File.dirname(__FILE__) + "/../../../templates/overview.erb" + ) + + f.puts ERB.new(template_file).result(binding) + end + + super + end + # rubocop:enable Metrics/AbcSize + # rubocop:enable Metrics/MethodLength + # rubocop:enable Metrics/LineLength + + private + + def create_report_directory + FileUtils.rm_rf(REPORT_PATH) if File.exist?(REPORT_PATH) + FileUtils.mkpath(REPORT_PATH) + end + + def create_screenshots_directory + FileUtils.mkdir_p SCREENSHOT_DIR unless File.exist?(SCREENSHOT_DIR) + end + + def create_screenrecords_directory + FileUtils.mkdir_p SCREENRECORD_DIR unless File.exist?(SCREENRECORD_DIR) + end + + def provide_resources + FileUtils.cp_r( + File.dirname(__FILE__) + "/../../../resources", REPORT_PATH + ) + end end + # rubocop:enable Metrics/ClassLength end end