class Minitest::Queue::JUnitReporter

Public Class Methods

new(report_path = 'log/junit.xml', options = {}) click to toggle source
Calls superclass method
# File lib/minitest/queue/junit_reporter.rb, line 12
def initialize(report_path = 'log/junit.xml', options = {})
  super({})
  @report_path = File.absolute_path(report_path)
  @base_path = options[:base_path] || Dir.pwd
end

Public Instance Methods

format_document(doc, io) click to toggle source
# File lib/minitest/queue/junit_reporter.rb, line 34
def format_document(doc, io)
  formatter = REXML::Formatters::Pretty.new
  formatter.write(doc, io)
  io << "\n"
end
generate_document() click to toggle source
# File lib/minitest/queue/junit_reporter.rb, line 18
def generate_document
  suites = tests.group_by { |test| test.klass }

  doc = REXML::Document.new(nil, {
    :prologue_quote => :quote,
    :attribute_quote => :quote,
  })
  doc << REXML::XMLDecl.new('1.1', 'utf-8')

  testsuites = doc.add_element('testsuites')
  suites.each do |suite, tests|
    add_tests_to(testsuites, suite, tests)
  end
  doc
end
report() click to toggle source
Calls superclass method
# File lib/minitest/queue/junit_reporter.rb, line 40
def report
  super

  FileUtils.mkdir_p(File.dirname(@report_path))
  File.open(@report_path, 'w+') do |file|
    format_document(generate_document, file)
  end
end

Private Instance Methods

add_tests_to(testsuites, suite, tests) click to toggle source
# File lib/minitest/queue/junit_reporter.rb, line 51
def add_tests_to(testsuites, suite, tests)
  suite_result = analyze_suite(tests)
  relative_path = location_for_runnable(tests.first) || '<unknown>'

  testsuite = testsuites.add_element(
    'testsuite',
    'name' => suite,
    'filepath' => relative_path,
    'skipped' => suite_result[:skip_count],
    'failures' => suite_result[:fail_count],
    'errors' => suite_result[:error_count],
    'tests' => suite_result[:test_count],
    'assertions' => suite_result[:assertion_count],
    'time' => suite_result[:time],
  )

  tests.each do |test|
    lineno = tests.first.source_location.last
    attributes = {
      'name' => test.name,
      'classname' => suite,
      'assertions' => test.assertions,
      'time' => test.time,
      'flaky_test' => test.flaked?,
      'run-command' => Minitest.run_command_for_runnable(test),
    }
    attributes['lineno'] = lineno if lineno != -1

    testcase = testsuite.add_element('testcase', attributes)
    add_xml_message_for(testcase, test) unless test.passed?
  rescue REXML::ParseException, RuntimeError => error
    step(red("Skipping adding '#{suite}##{test.name}' to JUnit report: #{error.message}"))
  end
end
add_xml_message_for(testcase, test) click to toggle source
# File lib/minitest/queue/junit_reporter.rb, line 86
def add_xml_message_for(testcase, test)
  failure = test.failure
  if test.skipped? && !test.flaked?
    testcase.add_element('skipped', 'type' => failure.error.class.name)
  elsif test.error?
    error = testcase.add_element('error', 'type' => failure.error.class.name, 'message' => truncate_message(failure.message))
    error.add_text(REXML::CData.new(message_for(test)))
  elsif failure
    failure = testcase.add_element('failure', 'type' => failure.error.class.name, 'message' => truncate_message(failure.message))
    failure.add_text(REXML::CData.new(message_for(test)))
  end
end
analyze_suite(tests) click to toggle source
# File lib/minitest/queue/junit_reporter.rb, line 132
def analyze_suite(tests)
  result = Hash.new(0)
  result[:time] = 0
  tests.each do |test|
    result[:"#{result(test)}_count"] += 1
    result[:assertion_count] += test.assertions
    result[:test_count] += 1
    result[:time] += test.time
  end
  result
end
location_for_runnable(runnable) click to toggle source
# File lib/minitest/queue/junit_reporter.rb, line 124
def location_for_runnable(runnable)
  if runnable.source_location.first == 'unknown'
    nil
  else
    Minitest::Queue.relative_path(runnable.source_location.first)
  end
end
message_for(test) click to toggle source
# File lib/minitest/queue/junit_reporter.rb, line 107
def message_for(test)
  suite = test.klass
  name = test.name
  error = test.failure

  message_with_relative_paths = error.message.gsub(project_root_path_matcher, '')
  if test.passed?
    nil
  elsif test.skipped?
    "\nSkipped:\n#{name}(#{suite}) [#{location_for_runnable(test)}]:\n#{message_with_relative_paths}\n"
  elsif test.failure
    "\nFailure:\n#{name}(#{suite}) [#{location_for_runnable(test)}]:\n#{message_with_relative_paths}\n"
  elsif test.error?
    "\nError:\n#{name}(#{suite}) [#{location_for_runnable(test)}]:\n#{message_with_relative_paths}\n"
  end
end
project_root_path_matcher() click to toggle source
# File lib/minitest/queue/junit_reporter.rb, line 103
def project_root_path_matcher
  @project_root_path_matcher ||= %r{(?<=\s)#{Regexp.escape(Minitest::Queue.project_root)}/}
end
truncate_message(message) click to toggle source
# File lib/minitest/queue/junit_reporter.rb, line 99
def truncate_message(message)
  message.lines.first.chomp.gsub(/\e\[[^m]+m/, '')
end