minitest-junit_formatter 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.github/workflows/main.yml +34 -0
- data/.gitignore +22 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +36 -0
- data/Rakefile +10 -0
- data/lib/minitest/junit_formatter/version.rb +6 -0
- data/lib/minitest/junit_formatter.rb +134 -0
- data/lib/minitest/junit_formatter_plugin.rb +24 -0
- data/minitest-junit_formatter.gemspec +28 -0
- data/test/.rubocop.yml +2 -0
- data/test/junit_plugin_test.rb +83 -0
- data/test/reporter_test.rb +114 -0
- data/test/testcase_formatter_test.rb +101 -0
- data/test/tmp/.keep +0 -0
- metadata +151 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 6187bdbdbb70fedb0f8ae74880f5dc52be2b5fcd1dbbf8c2c33d1d45ec50951c
|
|
4
|
+
data.tar.gz: d6f6d37a483382f086aae7257bfd11b5c4df6bdcfb8e95223ffdb3388e89bdd1
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: ef3ec5092642cd0a897e94710e959090f6745ec02a659bba65fa4ffda7159f9ed3a25c0c787eb17f0e27b0f37f2327322cb391d9718005f3841e03498f600c00
|
|
7
|
+
data.tar.gz: 85257d6d9755ba2829b0d83e6ce3132768b8ab3c287b177059e37f123996cec7ba93d80ce525f94c5a6d315b13d2518eb4995dbba541bc7d612a5a6c4942b9fe
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
name: Main
|
|
2
|
+
on:
|
|
3
|
+
push:
|
|
4
|
+
branches: [release]
|
|
5
|
+
pull_request:
|
|
6
|
+
types: [opened, synchronize]
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
tests:
|
|
10
|
+
name: Tests
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
strategy:
|
|
13
|
+
fail-fast: false
|
|
14
|
+
matrix:
|
|
15
|
+
ruby: ["2.7", "3.0", "3.1", "3.2"]
|
|
16
|
+
|
|
17
|
+
steps:
|
|
18
|
+
- name: Checkout code
|
|
19
|
+
uses: actions/checkout@v4
|
|
20
|
+
|
|
21
|
+
- name: Setup Ruby
|
|
22
|
+
uses: ruby/setup-ruby@v1
|
|
23
|
+
with:
|
|
24
|
+
ruby-version: ${{ matrix.ruby }}
|
|
25
|
+
bundler-cache: true
|
|
26
|
+
|
|
27
|
+
- name: Generate lockfile
|
|
28
|
+
run: bundle lock
|
|
29
|
+
|
|
30
|
+
- name: Bundle
|
|
31
|
+
run: bundle check || bundle install
|
|
32
|
+
|
|
33
|
+
- name: Run tests
|
|
34
|
+
run: bundle exec rake test
|
data/.gitignore
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
*.gem
|
|
2
|
+
*.rbc
|
|
3
|
+
.bundle
|
|
4
|
+
.config
|
|
5
|
+
.yardoc
|
|
6
|
+
Gemfile.lock
|
|
7
|
+
InstalledFiles
|
|
8
|
+
_yardoc
|
|
9
|
+
coverage
|
|
10
|
+
doc/
|
|
11
|
+
lib/bundler/man
|
|
12
|
+
pkg
|
|
13
|
+
rdoc
|
|
14
|
+
spec/reports
|
|
15
|
+
test/tmp
|
|
16
|
+
test/version_tmp
|
|
17
|
+
tmp
|
|
18
|
+
*.bundle
|
|
19
|
+
*.so
|
|
20
|
+
*.o
|
|
21
|
+
*.a
|
|
22
|
+
mkmf.log
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
Copyright (c) 2014 Allan Espinosa
|
|
2
|
+
|
|
3
|
+
MIT License
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
6
|
+
a copy of this software and associated documentation files (the
|
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
11
|
+
the following conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be
|
|
14
|
+
included in all copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# Minitest::JunitFormatter
|
|
2
|
+
|
|
3
|
+
Generates a JUnit-compatible XML report for consumption with Jenkins.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
Add this line to your application's Gemfile:
|
|
8
|
+
|
|
9
|
+
gem 'minitest-junit_formatter'
|
|
10
|
+
|
|
11
|
+
And then execute:
|
|
12
|
+
|
|
13
|
+
$ bundle
|
|
14
|
+
|
|
15
|
+
Or install it yourself as:
|
|
16
|
+
|
|
17
|
+
$ gem install minitest-junit
|
|
18
|
+
|
|
19
|
+
## Usage
|
|
20
|
+
|
|
21
|
+
$ ruby your_test.rb --help
|
|
22
|
+
minitest options:
|
|
23
|
+
...
|
|
24
|
+
Known extensions: junit, ...
|
|
25
|
+
--junit Generate a junit xml report
|
|
26
|
+
--junit-filename=OUT Target output filename. Defaults to report.xml
|
|
27
|
+
--junit-jenkins Sanitize test names for Jenkins display
|
|
28
|
+
...
|
|
29
|
+
|
|
30
|
+
## Contributing
|
|
31
|
+
|
|
32
|
+
1. Fork it ( https://github.com/aespinosa/minitest-junit/fork )
|
|
33
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
|
34
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
|
35
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
|
36
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
require "minitest/junit_formatter/version"
|
|
2
|
+
require 'minitest'
|
|
3
|
+
require 'ox'
|
|
4
|
+
require 'socket'
|
|
5
|
+
require 'time'
|
|
6
|
+
|
|
7
|
+
# :nodoc:
|
|
8
|
+
module Minitest
|
|
9
|
+
module JunitFormatter
|
|
10
|
+
# :nodoc:
|
|
11
|
+
class Reporter
|
|
12
|
+
def initialize(io, options)
|
|
13
|
+
@io = io
|
|
14
|
+
@results = []
|
|
15
|
+
@options = options
|
|
16
|
+
@options[:timestamp] = options.fetch(:timestamp, Time.now.iso8601)
|
|
17
|
+
@options[:hostname] = options.fetch(:hostname, Socket.gethostname)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def passed?
|
|
21
|
+
true
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def start; end
|
|
25
|
+
|
|
26
|
+
def record(result)
|
|
27
|
+
@results << result
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def report
|
|
31
|
+
doc = Ox::Document.new(version: '1.0', encoding: 'UTF-8')
|
|
32
|
+
instruct = Ox::Instruct.new(:xml)
|
|
33
|
+
instruct[:version] = '1.0'
|
|
34
|
+
instruct[:encoding] = 'UTF-8'
|
|
35
|
+
doc << instruct
|
|
36
|
+
|
|
37
|
+
testsuite = Ox::Element.new('testsuite')
|
|
38
|
+
testsuite['name'] = @options[:name] || 'minitest'
|
|
39
|
+
testsuite['timestamp'] = @options[:timestamp]
|
|
40
|
+
testsuite['hostname'] = @options[:hostname]
|
|
41
|
+
testsuite['tests'] = @results.size
|
|
42
|
+
testsuite['skipped'] = @results.count(&:skipped?)
|
|
43
|
+
testsuite['failures'] = @results.count { |result| !result.error? && result.failure }
|
|
44
|
+
testsuite['errors'] = @results.count(&:error?)
|
|
45
|
+
testsuite['time'] = format_time(@results.map(&:time).inject(0, :+))
|
|
46
|
+
@results.each do |result|
|
|
47
|
+
testsuite << format(result)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
testsuites = Ox::Element.new('testsuites')
|
|
51
|
+
testsuites << testsuite
|
|
52
|
+
|
|
53
|
+
doc << testsuites
|
|
54
|
+
@io << Ox.dump(doc)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def format(result, parent = nil)
|
|
58
|
+
testcase = Ox::Element.new('testcase')
|
|
59
|
+
testcase['classname'] = format_class(result)
|
|
60
|
+
testcase['name'] = format_name(result)
|
|
61
|
+
testcase['time'] = format_time(result.time)
|
|
62
|
+
testcase['file'] = relative_to_cwd(result.source_location.first)
|
|
63
|
+
testcase['line'] = result.source_location.last
|
|
64
|
+
testcase['assertions'] = result.assertions
|
|
65
|
+
|
|
66
|
+
if result.skipped?
|
|
67
|
+
skipped = Ox::Element.new('skipped')
|
|
68
|
+
skipped['message'] = result
|
|
69
|
+
skipped << ""
|
|
70
|
+
testcase << skipped
|
|
71
|
+
else
|
|
72
|
+
result.failures.each do |failure|
|
|
73
|
+
failure_tag = Ox::Element.new(classify(failure))
|
|
74
|
+
failure_tag['message'] = result
|
|
75
|
+
failure_tag << format_backtrace(failure)
|
|
76
|
+
testcase << failure_tag
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# Minitest 5.19 supports metadata
|
|
81
|
+
# Rails 7.1 adds `failure_screenshot_path` to metadata
|
|
82
|
+
# Output according to Gitlab format
|
|
83
|
+
# https://docs.gitlab.com/ee/ci/testing/unit_test_reports.html#view-junit-screenshots-on-gitlab
|
|
84
|
+
if result.respond_to?("metadata") && result.metadata[:failure_screenshot_path]
|
|
85
|
+
screenshot = Ox::Element.new("system-out")
|
|
86
|
+
screenshot << "[[ATTACHMENT|#{result.metadata[:failure_screenshot_path]}]]"
|
|
87
|
+
testcase << screenshot
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
testcase
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
private
|
|
94
|
+
|
|
95
|
+
def classify(failure)
|
|
96
|
+
if failure.instance_of? UnexpectedError
|
|
97
|
+
'error'
|
|
98
|
+
else
|
|
99
|
+
'failure'
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def working_directory
|
|
104
|
+
@working_directory ||= Dir.getwd
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def relative_to_cwd(path)
|
|
108
|
+
path.sub(working_directory, '.')
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def format_backtrace(failure)
|
|
112
|
+
Minitest.filter_backtrace(failure.backtrace).map do |line|
|
|
113
|
+
relative_to_cwd(line)
|
|
114
|
+
end.join("\n")
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def format_class(result)
|
|
118
|
+
if @options[:junit_jenkins]
|
|
119
|
+
result.klass.to_s.gsub(/(.*)::(.*)/, '\1.\2')
|
|
120
|
+
else
|
|
121
|
+
result.klass
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def format_name(result)
|
|
126
|
+
result.name
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def format_time(time)
|
|
130
|
+
Kernel::format('%.6f', time)
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
require "minitest/junit_formatter"
|
|
2
|
+
|
|
3
|
+
# :nodoc:
|
|
4
|
+
module Minitest
|
|
5
|
+
def self.plugin_junit_formatter_options(opts, options)
|
|
6
|
+
opts.on '--junit', 'Generate a junit xml report' do
|
|
7
|
+
options[:junit] = true
|
|
8
|
+
end
|
|
9
|
+
opts.on '--junit-filename=OUT', 'Target output filename.'\
|
|
10
|
+
' Defaults to report.xml' do |out|
|
|
11
|
+
options[:junit_filename] = out
|
|
12
|
+
end
|
|
13
|
+
opts.on '--junit-jenkins', 'Sanitize test names for Jenkins display' do
|
|
14
|
+
options[:junit_jenkins] = true
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def self.plugin_junit_formatter_init(options)
|
|
19
|
+
return unless options.delete :junit
|
|
20
|
+
file_klass = options.delete(:file_klass) || File
|
|
21
|
+
io = file_klass.new options.delete(:junit_filename) || 'report.xml', 'w'
|
|
22
|
+
reporter << JunitFormatter::Reporter.new(io, options)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
|
+
require 'minitest/junit_formatter/version'
|
|
5
|
+
|
|
6
|
+
Gem::Specification.new do |spec|
|
|
7
|
+
spec.name = 'minitest-junit_formatter'
|
|
8
|
+
spec.version = Minitest::JunitFormatter::VERSION
|
|
9
|
+
spec.authors = ["Jesse Chavez", "Allan Espinosa"]
|
|
10
|
+
spec.email = ["jesse.chavez.jp@gmail.com"]
|
|
11
|
+
spec.summary = "Junit report formatter for Minitest ~> 5.0"
|
|
12
|
+
spec.description = "Junit report formatter for Minitest ~> 5.0"
|
|
13
|
+
spec.homepage = "https://github.com/JesseChavez/minitest-junit_formatter"
|
|
14
|
+
spec.license = "MIT"
|
|
15
|
+
|
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
|
17
|
+
spec.executables = spec.files.grep(/^bin\//) { |f| File.basename(f) }
|
|
18
|
+
spec.test_files = spec.files.grep(/^(test)\//)
|
|
19
|
+
spec.require_paths = ['lib']
|
|
20
|
+
|
|
21
|
+
spec.add_dependency 'minitest', '~> 5.11'
|
|
22
|
+
spec.add_dependency 'ox', '~> 2', '>= 2.14.2'
|
|
23
|
+
|
|
24
|
+
spec.add_development_dependency 'bundler'
|
|
25
|
+
spec.add_development_dependency 'nokogiri'
|
|
26
|
+
spec.add_development_dependency 'rake', '~> 13'
|
|
27
|
+
spec.add_development_dependency 'rubocop', '~> 1'
|
|
28
|
+
end
|
data/test/.rubocop.yml
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
require 'minitest/autorun'
|
|
2
|
+
require 'minitest/mock'
|
|
3
|
+
require "minitest/junit_formatter_plugin"
|
|
4
|
+
|
|
5
|
+
class PluginTest < Minitest::Test
|
|
6
|
+
def test_by_default_the_plugin_is_disabled
|
|
7
|
+
opts = OptionParser.new
|
|
8
|
+
options = {}
|
|
9
|
+
|
|
10
|
+
Minitest.plugin_junit_formatter_options opts, options
|
|
11
|
+
opts.parse('')
|
|
12
|
+
|
|
13
|
+
assert_equal({}, options)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def test_setting_the_commandline_activates_the_plugin
|
|
17
|
+
opts = OptionParser.new
|
|
18
|
+
options = {}
|
|
19
|
+
Minitest.plugin_junit_formatter_options opts, options
|
|
20
|
+
opts.parse('--junit')
|
|
21
|
+
|
|
22
|
+
assert_equal({ junit: true }, options)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def test_by_default_doesnt_include_the_repoter
|
|
26
|
+
options = {}
|
|
27
|
+
Minitest.reporter = []
|
|
28
|
+
|
|
29
|
+
Minitest.plugin_junit_formatter_init(options)
|
|
30
|
+
|
|
31
|
+
assert_equal [], Minitest.reporter
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def test_when_enabled_adds_the_plugin_to_the_list_of_reporters
|
|
35
|
+
options = { junit: true }
|
|
36
|
+
Minitest.reporter = []
|
|
37
|
+
|
|
38
|
+
Minitest.plugin_junit_formatter_init(options)
|
|
39
|
+
|
|
40
|
+
assert_instance_of Minitest::JunitFormatter::Reporter, Minitest.reporter[0]
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def test_output_is_dumped_to_reportxml_by_default
|
|
44
|
+
file_klass = Minitest::Mock.new
|
|
45
|
+
options = { junit: true, file_klass: file_klass }
|
|
46
|
+
Minitest.reporter = []
|
|
47
|
+
|
|
48
|
+
file_klass.expect(:new, true, ['report.xml', 'w'])
|
|
49
|
+
Minitest.plugin_junit_formatter_init(options)
|
|
50
|
+
|
|
51
|
+
file_klass.verify
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def test_output_is_dumped_to_specified_filename
|
|
55
|
+
file_klass = Minitest::Mock.new
|
|
56
|
+
options = { junit: true, junit_filename: 'somefile.xml',
|
|
57
|
+
file_klass: file_klass }
|
|
58
|
+
Minitest.reporter = []
|
|
59
|
+
|
|
60
|
+
file_klass.expect(:new, true, ['somefile.xml', 'w'])
|
|
61
|
+
Minitest.plugin_junit_formatter_init(options)
|
|
62
|
+
|
|
63
|
+
file_klass.verify
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def test_custom_filename_is_specified_by_a_flag
|
|
67
|
+
opts = OptionParser.new
|
|
68
|
+
options = {}
|
|
69
|
+
|
|
70
|
+
Minitest.plugin_junit_formatter_options opts, options
|
|
71
|
+
opts.parse('--junit-filename=somefile.xml')
|
|
72
|
+
|
|
73
|
+
assert_equal 'somefile.xml', options[:junit_filename]
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def test_jenkins_sanitization_is_specified_by_a_flag
|
|
77
|
+
opts = OptionParser.new
|
|
78
|
+
options = {}
|
|
79
|
+
Minitest.plugin_junit_formatter_options opts, options
|
|
80
|
+
opts.parse('--junit-jenkins')
|
|
81
|
+
assert options[:junit_jenkins]
|
|
82
|
+
end
|
|
83
|
+
end
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
require 'minitest/autorun'
|
|
2
|
+
require 'stringio'
|
|
3
|
+
require 'time'
|
|
4
|
+
require 'nokogiri'
|
|
5
|
+
|
|
6
|
+
require "minitest/junit_formatter"
|
|
7
|
+
|
|
8
|
+
class FakeTestName; end
|
|
9
|
+
|
|
10
|
+
class ReporterTest < Minitest::Test
|
|
11
|
+
def test_no_tests_generates_an_empty_suite
|
|
12
|
+
reporter = create_reporter
|
|
13
|
+
|
|
14
|
+
reporter.report
|
|
15
|
+
|
|
16
|
+
assert_match(
|
|
17
|
+
%r{<?xml version="1.0" encoding="UTF-8"\?>\n<testsuites>\n <testsuite name="minitest" timestamp="[^"]+" hostname="[^"]+" tests="0" skipped="0" failures="0" errors="0" time="0.000000"\/>\n<\/testsuites>\n},
|
|
18
|
+
reporter.output
|
|
19
|
+
)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# NOTE: This test will generate a temp file: "test/tmp/report.xml"
|
|
23
|
+
def test_encoding
|
|
24
|
+
# Enforce File.external_encoding to UTF-8 to ensure that ASCII character will be correctly converted to UTF-8
|
|
25
|
+
file = File.new('test/tmp/report.xml', 'w:UTF-8')
|
|
26
|
+
reporter = Minitest::JunitFormatter::Reporter.new file, { hostname: '‹foo›' }
|
|
27
|
+
reporter.start
|
|
28
|
+
reporter.report
|
|
29
|
+
file.close
|
|
30
|
+
|
|
31
|
+
assert_match(/hostname="‹foo›"/, File.new('test/tmp/report.xml', 'r:UTF-8').read)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def test_formats_each_successful_result_with_a_formatter
|
|
35
|
+
reporter = create_reporter
|
|
36
|
+
|
|
37
|
+
results = do_formatting_test(reporter, count: rand(100), cause_failures: 0)
|
|
38
|
+
|
|
39
|
+
results.each do |result|
|
|
40
|
+
assert_match("<testcase classname=\"FakeTestName\" name=\"#{result.name}\"", reporter.output)
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def test_formats_each_failed_result_with_a_formatter
|
|
45
|
+
reporter = create_reporter
|
|
46
|
+
|
|
47
|
+
results = do_formatting_test(reporter, count: rand(100), cause_failures: 1)
|
|
48
|
+
parsed_report = Nokogiri::XML(reporter.output)
|
|
49
|
+
results.each do |result|
|
|
50
|
+
parsed_report.xpath("//testcase[@name='#{result.name}']").any?
|
|
51
|
+
end
|
|
52
|
+
# Check if some testcase has a failure and screenshot path
|
|
53
|
+
assert parsed_report.xpath("//testcase//failure").any?
|
|
54
|
+
assert parsed_report.xpath("//testcase//system-out").any?
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def test_xml_nodes_has_file_and_line_attributes
|
|
58
|
+
reporter = create_reporter
|
|
59
|
+
results = do_formatting_test(reporter, count: 2, cause_failures: 1)
|
|
60
|
+
parsed_report = Nokogiri::XML(reporter.output)
|
|
61
|
+
example_node = parsed_report.xpath("//testcase").first
|
|
62
|
+
assert example_node.has_attribute?('file')
|
|
63
|
+
assert example_node.has_attribute?('line')
|
|
64
|
+
assert_equal 'unknown', example_node.attribute('file').value
|
|
65
|
+
assert_equal '-1', example_node.attribute('line').value
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
private
|
|
69
|
+
|
|
70
|
+
def do_formatting_test(reporter, count: 1, cause_failures: 0)
|
|
71
|
+
results = count.times.map do |i|
|
|
72
|
+
result = create_test_result(methodname: "test_name#{i}", failures: cause_failures)
|
|
73
|
+
reporter.record result
|
|
74
|
+
result
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
reporter.report
|
|
78
|
+
|
|
79
|
+
results
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def create_test_result(name: FakeTestName, methodname: 'test_method_name', successes: 1, failures: 0)
|
|
83
|
+
test = Class.new Minitest::Test do
|
|
84
|
+
define_method 'class' do
|
|
85
|
+
name
|
|
86
|
+
end
|
|
87
|
+
end.new methodname
|
|
88
|
+
test.time = rand(100)
|
|
89
|
+
test.assertions = successes + failures
|
|
90
|
+
test.failures = failures.times.map do |i|
|
|
91
|
+
Class.new Minitest::Assertion do
|
|
92
|
+
define_method 'backtrace' do
|
|
93
|
+
["Model failure \##{i}", 'This is a test backtrace', "#{__FILE__}:#{__LINE__}"]
|
|
94
|
+
end
|
|
95
|
+
end.new
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
if failures.positive?
|
|
99
|
+
test.metadata[:failure_screenshot_path] = '/tmp/screenshot.png'
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
Minitest::Result.from test
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def create_reporter(options = {})
|
|
106
|
+
io = StringIO.new("")
|
|
107
|
+
reporter = Minitest::JunitFormatter::Reporter.new(io, options)
|
|
108
|
+
def reporter.output
|
|
109
|
+
@io.string
|
|
110
|
+
end
|
|
111
|
+
reporter.start
|
|
112
|
+
reporter
|
|
113
|
+
end
|
|
114
|
+
end
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
require 'minitest/autorun'
|
|
2
|
+
require 'stringio'
|
|
3
|
+
require 'time'
|
|
4
|
+
|
|
5
|
+
require "minitest/junit_formatter"
|
|
6
|
+
|
|
7
|
+
class FakeTestName; end
|
|
8
|
+
|
|
9
|
+
module FirstModule
|
|
10
|
+
module SecondModule
|
|
11
|
+
class TestClass; end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
class TestCaseFormatter < Minitest::Test
|
|
16
|
+
def test_all_tests_generate_testcase_tag
|
|
17
|
+
test = create_test_result
|
|
18
|
+
reporter = create_reporter
|
|
19
|
+
|
|
20
|
+
assert_match(
|
|
21
|
+
test.name,
|
|
22
|
+
reporter.format(test).attributes['name']
|
|
23
|
+
)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def test_skipped_tests_generates_skipped_tag
|
|
27
|
+
test = create_test_result
|
|
28
|
+
test.failures << create_error(Minitest::Skip)
|
|
29
|
+
reporter = create_reporter
|
|
30
|
+
reporter.record test
|
|
31
|
+
|
|
32
|
+
reporter.report
|
|
33
|
+
|
|
34
|
+
assert_match(/<skipped message="[^<>]+"\><\/skipped>\n\s+<\/testcase>\n\s*<\/testsuite>\n/, reporter.output)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def test_failing_tests_creates_failure_tag
|
|
38
|
+
test = create_test_result
|
|
39
|
+
test.failures << create_error(Minitest::Assertion)
|
|
40
|
+
reporter = create_reporter
|
|
41
|
+
reporter.record test
|
|
42
|
+
|
|
43
|
+
reporter.report
|
|
44
|
+
|
|
45
|
+
assert_match(/<failure/, reporter.output)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def test_other_errors_generates_error_tag
|
|
49
|
+
test = create_test_result
|
|
50
|
+
test.failures << Minitest::UnexpectedError.new(create_error(Exception))
|
|
51
|
+
reporter = create_reporter
|
|
52
|
+
reporter.record test
|
|
53
|
+
|
|
54
|
+
reporter.report
|
|
55
|
+
|
|
56
|
+
assert_match(/<error/, reporter.output)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def test_jenkins_sanitizer_uses_modules_as_packages
|
|
60
|
+
test = create_test_result FirstModule::SecondModule::TestClass
|
|
61
|
+
reporter = create_reporter junit_jenkins: true
|
|
62
|
+
reporter.record test
|
|
63
|
+
|
|
64
|
+
reporter.report
|
|
65
|
+
|
|
66
|
+
assert_match 'FirstModule::SecondModule.TestClass', reporter.output
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
private
|
|
70
|
+
|
|
71
|
+
def create_error(klass)
|
|
72
|
+
fail klass, "A #{klass} failure"
|
|
73
|
+
rescue klass => e
|
|
74
|
+
e
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def create_test_result(name = FakeTestName)
|
|
78
|
+
test = Class.new Minitest::Test do
|
|
79
|
+
define_method 'class' do
|
|
80
|
+
name
|
|
81
|
+
end
|
|
82
|
+
end.new 'test_method_name'
|
|
83
|
+
test.time = a_number
|
|
84
|
+
test.assertions = a_number
|
|
85
|
+
Minitest::Result.from test
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def a_number
|
|
89
|
+
rand(100)
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def create_reporter(options = {})
|
|
93
|
+
io = StringIO.new("")
|
|
94
|
+
reporter = Minitest::JunitFormatter::Reporter.new(io, options)
|
|
95
|
+
def reporter.output
|
|
96
|
+
@io.string
|
|
97
|
+
end
|
|
98
|
+
reporter.start
|
|
99
|
+
reporter
|
|
100
|
+
end
|
|
101
|
+
end
|
data/test/tmp/.keep
ADDED
|
File without changes
|
metadata
ADDED
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: minitest-junit_formatter
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Jesse Chavez
|
|
8
|
+
- Allan Espinosa
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: minitest
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - "~>"
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '5.11'
|
|
20
|
+
type: :runtime
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - "~>"
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '5.11'
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: ox
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - "~>"
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: '2'
|
|
34
|
+
- - ">="
|
|
35
|
+
- !ruby/object:Gem::Version
|
|
36
|
+
version: 2.14.2
|
|
37
|
+
type: :runtime
|
|
38
|
+
prerelease: false
|
|
39
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
40
|
+
requirements:
|
|
41
|
+
- - "~>"
|
|
42
|
+
- !ruby/object:Gem::Version
|
|
43
|
+
version: '2'
|
|
44
|
+
- - ">="
|
|
45
|
+
- !ruby/object:Gem::Version
|
|
46
|
+
version: 2.14.2
|
|
47
|
+
- !ruby/object:Gem::Dependency
|
|
48
|
+
name: bundler
|
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
|
50
|
+
requirements:
|
|
51
|
+
- - ">="
|
|
52
|
+
- !ruby/object:Gem::Version
|
|
53
|
+
version: '0'
|
|
54
|
+
type: :development
|
|
55
|
+
prerelease: false
|
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
57
|
+
requirements:
|
|
58
|
+
- - ">="
|
|
59
|
+
- !ruby/object:Gem::Version
|
|
60
|
+
version: '0'
|
|
61
|
+
- !ruby/object:Gem::Dependency
|
|
62
|
+
name: nokogiri
|
|
63
|
+
requirement: !ruby/object:Gem::Requirement
|
|
64
|
+
requirements:
|
|
65
|
+
- - ">="
|
|
66
|
+
- !ruby/object:Gem::Version
|
|
67
|
+
version: '0'
|
|
68
|
+
type: :development
|
|
69
|
+
prerelease: false
|
|
70
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
71
|
+
requirements:
|
|
72
|
+
- - ">="
|
|
73
|
+
- !ruby/object:Gem::Version
|
|
74
|
+
version: '0'
|
|
75
|
+
- !ruby/object:Gem::Dependency
|
|
76
|
+
name: rake
|
|
77
|
+
requirement: !ruby/object:Gem::Requirement
|
|
78
|
+
requirements:
|
|
79
|
+
- - "~>"
|
|
80
|
+
- !ruby/object:Gem::Version
|
|
81
|
+
version: '13'
|
|
82
|
+
type: :development
|
|
83
|
+
prerelease: false
|
|
84
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
85
|
+
requirements:
|
|
86
|
+
- - "~>"
|
|
87
|
+
- !ruby/object:Gem::Version
|
|
88
|
+
version: '13'
|
|
89
|
+
- !ruby/object:Gem::Dependency
|
|
90
|
+
name: rubocop
|
|
91
|
+
requirement: !ruby/object:Gem::Requirement
|
|
92
|
+
requirements:
|
|
93
|
+
- - "~>"
|
|
94
|
+
- !ruby/object:Gem::Version
|
|
95
|
+
version: '1'
|
|
96
|
+
type: :development
|
|
97
|
+
prerelease: false
|
|
98
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
99
|
+
requirements:
|
|
100
|
+
- - "~>"
|
|
101
|
+
- !ruby/object:Gem::Version
|
|
102
|
+
version: '1'
|
|
103
|
+
description: Junit report formatter for Minitest ~> 5.0
|
|
104
|
+
email:
|
|
105
|
+
- jesse.chavez.jp@gmail.com
|
|
106
|
+
executables: []
|
|
107
|
+
extensions: []
|
|
108
|
+
extra_rdoc_files: []
|
|
109
|
+
files:
|
|
110
|
+
- ".github/workflows/main.yml"
|
|
111
|
+
- ".gitignore"
|
|
112
|
+
- Gemfile
|
|
113
|
+
- LICENSE.txt
|
|
114
|
+
- README.md
|
|
115
|
+
- Rakefile
|
|
116
|
+
- lib/minitest/junit_formatter.rb
|
|
117
|
+
- lib/minitest/junit_formatter/version.rb
|
|
118
|
+
- lib/minitest/junit_formatter_plugin.rb
|
|
119
|
+
- minitest-junit_formatter.gemspec
|
|
120
|
+
- test/.rubocop.yml
|
|
121
|
+
- test/junit_plugin_test.rb
|
|
122
|
+
- test/reporter_test.rb
|
|
123
|
+
- test/testcase_formatter_test.rb
|
|
124
|
+
- test/tmp/.keep
|
|
125
|
+
homepage: https://github.com/JesseChavez/minitest-junit_formatter
|
|
126
|
+
licenses:
|
|
127
|
+
- MIT
|
|
128
|
+
metadata: {}
|
|
129
|
+
rdoc_options: []
|
|
130
|
+
require_paths:
|
|
131
|
+
- lib
|
|
132
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
133
|
+
requirements:
|
|
134
|
+
- - ">="
|
|
135
|
+
- !ruby/object:Gem::Version
|
|
136
|
+
version: '0'
|
|
137
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
138
|
+
requirements:
|
|
139
|
+
- - ">="
|
|
140
|
+
- !ruby/object:Gem::Version
|
|
141
|
+
version: '0'
|
|
142
|
+
requirements: []
|
|
143
|
+
rubygems_version: 3.6.9
|
|
144
|
+
specification_version: 4
|
|
145
|
+
summary: Junit report formatter for Minitest ~> 5.0
|
|
146
|
+
test_files:
|
|
147
|
+
- test/.rubocop.yml
|
|
148
|
+
- test/junit_plugin_test.rb
|
|
149
|
+
- test/reporter_test.rb
|
|
150
|
+
- test/testcase_formatter_test.rb
|
|
151
|
+
- test/tmp/.keep
|