blinka-reporter 0.5.2 → 0.6.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 +4 -4
- data/.github/dependabot.yml +18 -0
- data/.github/release.yml +9 -0
- data/.github/workflows/main.yml +46 -0
- data/.gitignore +28 -0
- data/.ruby-version +1 -0
- data/CHANGELOG.md +152 -0
- data/Gemfile +4 -0
- data/LICENSE +21 -0
- data/README.md +162 -0
- data/Rakefile +7 -0
- data/bin/blinka_reporter +7 -0
- data/bin/setup +15 -0
- data/blinka_reporter.gemspec +41 -0
- data/lib/blinka_reporter/blinka.rb +169 -0
- data/lib/blinka_reporter/cli.rb +36 -0
- data/lib/blinka_reporter/client.rb +109 -0
- data/lib/blinka_reporter/config.rb +34 -0
- data/lib/blinka_reporter/error.rb +3 -0
- data/lib/blinka_reporter/minitest_adapter.rb +92 -0
- data/lib/blinka_reporter/tap.rb +51 -0
- data/lib/blinka_reporter/version.rb +1 -1
- data/lib/blinka_reporter.rb +4 -0
- data/lib/minitest/blinka_plugin.rb +14 -59
- data/package.json +22 -0
- data/yarn.lock +481 -0
- metadata +41 -5
- data/lib/blinka_client.rb +0 -195
- data/lib/blinka_minitest.rb +0 -90
@@ -0,0 +1,169 @@
|
|
1
|
+
require 'httparty'
|
2
|
+
require 'blinka_reporter/error'
|
3
|
+
|
4
|
+
module BlinkaReporter
|
5
|
+
class Blinka
|
6
|
+
SUPPORTED_MIME_TYPES = {
|
7
|
+
jpg: 'image/jpeg',
|
8
|
+
jpeg: 'image/jpeg',
|
9
|
+
png: 'image/png'
|
10
|
+
}
|
11
|
+
|
12
|
+
include HTTParty
|
13
|
+
|
14
|
+
def self.report(data:, config:)
|
15
|
+
Blinka.new(data: data, config: config).report
|
16
|
+
end
|
17
|
+
|
18
|
+
def initialize(data:, config:)
|
19
|
+
@data = data
|
20
|
+
@config = config
|
21
|
+
self.class.base_uri("#{@config.host}/api/v1")
|
22
|
+
end
|
23
|
+
|
24
|
+
def report
|
25
|
+
if ENV.fetch('BLINKA_ALLOW_WEBMOCK_DISABLE', 'true') == 'true' &&
|
26
|
+
defined?(WebMock) && WebMock.respond_to?(:disable!)
|
27
|
+
WebMock.disable!
|
28
|
+
end
|
29
|
+
|
30
|
+
@config.validate_blinka
|
31
|
+
self.authenticate
|
32
|
+
|
33
|
+
results =
|
34
|
+
@data
|
35
|
+
.fetch(:results, [])
|
36
|
+
.map do |result|
|
37
|
+
if !result[:image].nil?
|
38
|
+
result[:image] = Blinka.upload_image(filepath: result[:image])
|
39
|
+
result
|
40
|
+
else
|
41
|
+
result
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
body = {
|
46
|
+
report: {
|
47
|
+
repository: @config.repository,
|
48
|
+
tag: @config.tag,
|
49
|
+
commit: @config.commit,
|
50
|
+
metadata: {
|
51
|
+
total_time: @data[:total_time],
|
52
|
+
nbr_tests: @data[:nbr_tests],
|
53
|
+
nbr_assertions: @data[:nbr_assertions],
|
54
|
+
seed: @data[:seed]
|
55
|
+
}.compact,
|
56
|
+
results: results
|
57
|
+
}
|
58
|
+
}
|
59
|
+
|
60
|
+
response =
|
61
|
+
self.class.post(
|
62
|
+
'/report',
|
63
|
+
body: body.to_json,
|
64
|
+
headers: {
|
65
|
+
'Content-Type' => 'application/json',
|
66
|
+
'Authorization' => "Bearer #{@jwt_token}"
|
67
|
+
}
|
68
|
+
)
|
69
|
+
case response.code
|
70
|
+
when 200
|
71
|
+
puts "Reported #{@data[:nbr_tests]} tests of commit #{@config.commit}!"
|
72
|
+
else
|
73
|
+
raise(
|
74
|
+
BlinkaReporter::Error,
|
75
|
+
"Could not report, got response code #{response.code}"
|
76
|
+
)
|
77
|
+
end
|
78
|
+
rescue => error
|
79
|
+
raise(BlinkaReporter::Error, <<-EOS)
|
80
|
+
BLINKA:
|
81
|
+
Failed to create report because of #{error.class} with message:
|
82
|
+
#{error.message}
|
83
|
+
EOS
|
84
|
+
ensure
|
85
|
+
WebMock.enable! if defined?(WebMock) && WebMock.respond_to?(:enable!)
|
86
|
+
end
|
87
|
+
|
88
|
+
def authenticate
|
89
|
+
response =
|
90
|
+
self.class.post(
|
91
|
+
'/authentication',
|
92
|
+
body: {
|
93
|
+
token_id: @config.team_id,
|
94
|
+
token_secret: @config.team_secret
|
95
|
+
}.to_json,
|
96
|
+
headers: { 'Content-Type' => 'application/json' }
|
97
|
+
)
|
98
|
+
case response.code
|
99
|
+
when 200
|
100
|
+
@jwt_token = JSON.parse(response.body).dig('auth_token')
|
101
|
+
else
|
102
|
+
raise(BlinkaReporter::Error, 'Could not authenticate to API')
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def self.upload_image(filepath:)
|
107
|
+
return unless File.exist?(filepath)
|
108
|
+
|
109
|
+
file = File.open(filepath)
|
110
|
+
filename = File.basename(filepath)
|
111
|
+
extension = File.extname(filepath).delete('.').to_sym
|
112
|
+
content_type = SUPPORTED_MIME_TYPES[extension]
|
113
|
+
return if content_type.nil?
|
114
|
+
|
115
|
+
presigned_post =
|
116
|
+
Blinka.presign_image(filename: filename, content_type: content_type)
|
117
|
+
Blinka.upload_to_storage(presigned_post: presigned_post, file: file)
|
118
|
+
|
119
|
+
puts "Uploaded: #{filename}"
|
120
|
+
Blinka.to_shrine_object(
|
121
|
+
presigned_post: presigned_post,
|
122
|
+
file: file,
|
123
|
+
filename: filename
|
124
|
+
)
|
125
|
+
end
|
126
|
+
|
127
|
+
def self.presign_image(filename:, content_type:)
|
128
|
+
response =
|
129
|
+
self.get(
|
130
|
+
'/presign',
|
131
|
+
body: { filename: filename, content_type: content_type }
|
132
|
+
)
|
133
|
+
|
134
|
+
case response.code
|
135
|
+
when 200
|
136
|
+
JSON.parse(response.body)
|
137
|
+
else
|
138
|
+
raise(BlinkaReporter::Error, 'Could not presign file')
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
def self.upload_to_storage(presigned_post:, file:)
|
143
|
+
url = URI.parse(presigned_post.fetch('url'))
|
144
|
+
|
145
|
+
body = presigned_post['fields'].merge({ 'file' => file.read })
|
146
|
+
response = HTTParty.post(url, multipart: true, body: body)
|
147
|
+
|
148
|
+
case response.code
|
149
|
+
when 204
|
150
|
+
true
|
151
|
+
else
|
152
|
+
raise(BlinkaReporter::Error, 'Could not upload file to storage')
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
def self.to_shrine_object(presigned_post:, file:, filename:)
|
157
|
+
storage, idx = presigned_post.dig('fields', 'key').split('/')
|
158
|
+
{
|
159
|
+
"id": idx,
|
160
|
+
"storage": storage,
|
161
|
+
"metadata": {
|
162
|
+
"size": file.size,
|
163
|
+
"filename": filename,
|
164
|
+
"mime_type": presigned_post.dig('fields', 'Content-Type')
|
165
|
+
}
|
166
|
+
}
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'blinka_reporter/client'
|
2
|
+
require 'blinka_reporter/version'
|
3
|
+
|
4
|
+
module BlinkaReporter
|
5
|
+
class Cli
|
6
|
+
def self.run(argv)
|
7
|
+
if (argv.index('--help') || -1) >= 0
|
8
|
+
puts(<<~EOS)
|
9
|
+
blinka_reporter version #{BlinkaReporter::VERSION}
|
10
|
+
|
11
|
+
Options:
|
12
|
+
--tap: Flag for outputting test results in TAP-protocol, helpful on Heroku CI.
|
13
|
+
--blinka: Flag for reporting test results to blinka.app, requires setting environment:
|
14
|
+
- BLINKA_TEAM_ID
|
15
|
+
- BLINKA_TEAM_SECRET
|
16
|
+
- BLINKA_REPOSITORY
|
17
|
+
--path <path>: Path to test results file, works for
|
18
|
+
- ./blinka_results.json blinka json format [default]
|
19
|
+
- ./rspec.xml from https://github.com/sj26/rspec_junit_formatter
|
20
|
+
EOS
|
21
|
+
return 0
|
22
|
+
end
|
23
|
+
|
24
|
+
tap = (argv.index('--tap') || -1) >= 0
|
25
|
+
blinka = (argv.index('--blinka') || -1) >= 0
|
26
|
+
path = argv_value_for(argv, '--path') || './blinka_results.json'
|
27
|
+
BlinkaReporter::Client.report(blinka: blinka, tap: tap, path: path)
|
28
|
+
0
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.argv_value_for(argv, option_name)
|
32
|
+
return unless (index = argv.index(option_name))
|
33
|
+
argv[index + 1]
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
require 'httparty'
|
2
|
+
require 'ox'
|
3
|
+
|
4
|
+
require 'blinka_reporter/blinka'
|
5
|
+
require 'blinka_reporter/config'
|
6
|
+
require 'blinka_reporter/error'
|
7
|
+
require 'blinka_reporter/tap'
|
8
|
+
|
9
|
+
module BlinkaReporter
|
10
|
+
class Client
|
11
|
+
def initialize
|
12
|
+
@config = BlinkaReporter::Config.new
|
13
|
+
end
|
14
|
+
|
15
|
+
def report(path: './blinka_results.json', blinka: false, tap: false)
|
16
|
+
unless File.exist?(path)
|
17
|
+
raise(
|
18
|
+
BlinkaReporter::Error,
|
19
|
+
"Could not find #{path}, was it generated when running the tests?"
|
20
|
+
)
|
21
|
+
end
|
22
|
+
|
23
|
+
data =
|
24
|
+
if path.end_with?('.xml')
|
25
|
+
self.class.parse_xml(path: path)
|
26
|
+
elsif path.end_with?('.json')
|
27
|
+
self.class.parse_json(path: path)
|
28
|
+
else
|
29
|
+
raise(
|
30
|
+
BlinkaReporter::Error,
|
31
|
+
"Unknown format of #{path}, needs to be .json or .xml"
|
32
|
+
)
|
33
|
+
end
|
34
|
+
|
35
|
+
BlinkaReporter::Tap.report(data) if tap
|
36
|
+
BlinkaReporter::Blinka.report(config: @config, data: data) if blinka
|
37
|
+
0
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.report(path:, tap: false, blinka: false)
|
41
|
+
Client.new.report(path: path, tap: tap, blinka: blinka)
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.parse_json(path:)
|
45
|
+
JSON.parse(File.open(path).read, symbolize_names: true)
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.parse_xml(path:)
|
49
|
+
data = Ox.load_file(path, { symbolize_keys: true, skip: :skip_none })
|
50
|
+
test_suite = data.root
|
51
|
+
unless test_suite.name == 'testsuite'
|
52
|
+
raise("Root element is not <testsuite>, instead #{test_suite.name}")
|
53
|
+
end
|
54
|
+
|
55
|
+
properties = test_suite.nodes.select { |node| node.name == 'properties' }
|
56
|
+
test_cases = test_suite.nodes.select { |node| node.name == 'testcase' }
|
57
|
+
{
|
58
|
+
nbr_tests: Integer(test_suite.tests || 0),
|
59
|
+
total_time: Float(test_suite.time),
|
60
|
+
seed: xml_seed(properties),
|
61
|
+
results: xml_test_cases(test_cases)
|
62
|
+
}
|
63
|
+
end
|
64
|
+
|
65
|
+
def self.xml_seed(ox_properties)
|
66
|
+
ox_properties.each do |property|
|
67
|
+
property.nodes.each do |node|
|
68
|
+
return node.attributes[:value] if node.attributes[:name] == 'seed'
|
69
|
+
end
|
70
|
+
end
|
71
|
+
nil
|
72
|
+
end
|
73
|
+
|
74
|
+
# Kind is extracted from the second part of spec.models.customer_spec
|
75
|
+
def self.xml_test_cases(test_cases)
|
76
|
+
test_cases.map do |test_case|
|
77
|
+
result = {
|
78
|
+
kind: Array(test_case.attributes[:classname]&.split('.'))[1],
|
79
|
+
name: test_case.attributes[:name],
|
80
|
+
path: test_case.attributes[:file]&.delete_prefix('./'),
|
81
|
+
time: Float(test_case.attributes[:time] || 0)
|
82
|
+
}
|
83
|
+
if test_case.nodes.any?
|
84
|
+
skipped = test_case.nodes.any? { |node| node.name == 'skipped' }
|
85
|
+
result[:result] = 'skip' if skipped
|
86
|
+
failure =
|
87
|
+
test_case.nodes.select { |node| node.name == 'failure' }.first
|
88
|
+
if failure
|
89
|
+
result[:image] = get_image_path(failure.text)
|
90
|
+
result[:result] = 'fail'
|
91
|
+
result[:backtrace] = failure.text.split('\n')
|
92
|
+
result[:message] = failure.attributes[:message]
|
93
|
+
end
|
94
|
+
else
|
95
|
+
result[:result] = 'pass'
|
96
|
+
end
|
97
|
+
result
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def self.get_image_path(text)
|
102
|
+
path = /^\[Screenshot\]:\s([\S]*)$/.match(text)
|
103
|
+
return if path.nil?
|
104
|
+
path = path[1]
|
105
|
+
return unless File.exists?(path)
|
106
|
+
path
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'blinka_reporter/error'
|
2
|
+
|
3
|
+
module BlinkaReporter
|
4
|
+
class Config
|
5
|
+
attr_reader(:commit, :host, :repository, :tag, :team_id, :team_secret)
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@commit = find_commit
|
9
|
+
@host = ENV.fetch('BLINKA_HOST', 'https://www.blinka.app')
|
10
|
+
@repository = ENV.fetch('BLINKA_REPOSITORY', nil)
|
11
|
+
@tag = ENV.fetch('BLINKA_TAG', nil)
|
12
|
+
@team_id = ENV.fetch('BLINKA_TEAM_ID', nil)
|
13
|
+
@team_secret = ENV.fetch('BLINKA_TEAM_SECRET', nil)
|
14
|
+
end
|
15
|
+
|
16
|
+
def validate_blinka
|
17
|
+
if @team_id.nil? || @team_secret.nil? || @repository.nil?
|
18
|
+
raise(BlinkaReporter::Error, <<~EOS)
|
19
|
+
Missing configuration, make sure to set required environment variables:
|
20
|
+
- BLINKA_TEAM_ID
|
21
|
+
- BLINKA_TEAM_SECRET
|
22
|
+
- BLINKA_REPOSITORY
|
23
|
+
EOS
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def find_commit
|
28
|
+
ENV.fetch(
|
29
|
+
'BLINKA_COMMIT',
|
30
|
+
ENV.fetch('HEROKU_TEST_RUN_COMMIT_VERSION', `git rev-parse HEAD`.chomp)
|
31
|
+
)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
module BlinkaReporter
|
2
|
+
class MinitestAdapter
|
3
|
+
def initialize(test_result)
|
4
|
+
@test_result = test_result
|
5
|
+
end
|
6
|
+
|
7
|
+
def path
|
8
|
+
@path ||= source_location.first.gsub(Dir.getwd, '').delete_prefix('/')
|
9
|
+
end
|
10
|
+
|
11
|
+
def line
|
12
|
+
@line ||= source_location.last
|
13
|
+
end
|
14
|
+
|
15
|
+
# Handle broken API in Minitest between 5.10 and 5.11
|
16
|
+
# https://github.com/minitest-reporters/minitest-reporters/blob/e9092460b5a5cf5ca9eb375428217cbb2a7f6dbb/lib/minitest/reporters/default_reporter.rb#L159
|
17
|
+
def source_location
|
18
|
+
@source_location ||=
|
19
|
+
if @test_result.respond_to?(:klass)
|
20
|
+
@test_result.source_location
|
21
|
+
else
|
22
|
+
@test_result.method(@test_result.name).source_location
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def kind
|
27
|
+
parts = self.path.gsub('test/', '').split('/')
|
28
|
+
parts.length > 1 ? parts.first : 'general'
|
29
|
+
end
|
30
|
+
|
31
|
+
def message
|
32
|
+
failure = @test_result.failure
|
33
|
+
return unless failure
|
34
|
+
"#{failure.error.class}: #{failure.error.message}"
|
35
|
+
end
|
36
|
+
|
37
|
+
def backtrace
|
38
|
+
return unless @test_result.failure
|
39
|
+
Minitest.filter_backtrace(@test_result.failure.backtrace)
|
40
|
+
end
|
41
|
+
|
42
|
+
def result
|
43
|
+
if @test_result.error?
|
44
|
+
:error
|
45
|
+
elsif @test_result.skipped?
|
46
|
+
:skip
|
47
|
+
elsif @test_result.failure
|
48
|
+
:fail
|
49
|
+
else
|
50
|
+
:pass
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def time
|
55
|
+
@test_result.time
|
56
|
+
end
|
57
|
+
|
58
|
+
def name
|
59
|
+
@test_result.name
|
60
|
+
end
|
61
|
+
|
62
|
+
def image
|
63
|
+
return unless kind == 'system'
|
64
|
+
|
65
|
+
image_path =
|
66
|
+
if defined?(Capybara) && Capybara.respond_to?(:save_path) &&
|
67
|
+
Capybara.save_path.present?
|
68
|
+
"#{Capybara.save_path}/failures_#{name}.png"
|
69
|
+
else
|
70
|
+
"./tmp/screenshots/failures_#{name}.png"
|
71
|
+
end
|
72
|
+
|
73
|
+
return unless File.exist?(image_path)
|
74
|
+
|
75
|
+
image_path
|
76
|
+
end
|
77
|
+
|
78
|
+
def report
|
79
|
+
{
|
80
|
+
backtrace: backtrace,
|
81
|
+
message: message,
|
82
|
+
line: line,
|
83
|
+
image: image,
|
84
|
+
kind: kind,
|
85
|
+
name: name,
|
86
|
+
path: path,
|
87
|
+
result: result,
|
88
|
+
time: time
|
89
|
+
}.compact
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module BlinkaReporter
|
2
|
+
class Tap
|
3
|
+
# Based on https://github.com/kern/minitest-reporters/blob/master/lib/minitest/reporters/progress_reporter.rb
|
4
|
+
# Tries to adhere to https://testanything.org/tap-specification.html
|
5
|
+
TAP_COMMENT_PAD = 8
|
6
|
+
attr_reader(:data)
|
7
|
+
|
8
|
+
def self.report(data)
|
9
|
+
Tap.new(data).report
|
10
|
+
end
|
11
|
+
|
12
|
+
def initialize(data)
|
13
|
+
results = Array(data[:results])
|
14
|
+
return if results.size == 0
|
15
|
+
|
16
|
+
@data = <<~REPORT
|
17
|
+
TAP version 13
|
18
|
+
1..#{results.size}
|
19
|
+
#{test_results(results)}
|
20
|
+
REPORT
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_results(results)
|
24
|
+
report = []
|
25
|
+
results.each_with_index do |test, index|
|
26
|
+
test_str = "#{test[:path]} - #{test[:name].tr('#', '_')}"
|
27
|
+
result = test[:result]
|
28
|
+
if result == 'pass'
|
29
|
+
report << "ok #{index + 1} - #{test_str}"
|
30
|
+
elsif result == 'skip'
|
31
|
+
report << "ok #{index + 1} # skip: #{test_str}"
|
32
|
+
elsif result == 'fail'
|
33
|
+
report << "not ok #{index + 1} - failed: #{test_str}"
|
34
|
+
test[:message].split('\n') do |line|
|
35
|
+
report << "##{' ' * TAP_COMMENT_PAD + line}"
|
36
|
+
end
|
37
|
+
report << '#'
|
38
|
+
Array(test[:backtrace]).each do |line|
|
39
|
+
report << "##{' ' * TAP_COMMENT_PAD + line}"
|
40
|
+
end
|
41
|
+
report << ''
|
42
|
+
end
|
43
|
+
end
|
44
|
+
report.join("\n")
|
45
|
+
end
|
46
|
+
|
47
|
+
def report
|
48
|
+
puts(@data)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'minitest'
|
2
2
|
require 'json'
|
3
|
-
require '
|
4
|
-
require '
|
3
|
+
require 'blinka_reporter/minitest_adapter'
|
4
|
+
require 'blinka_reporter/client'
|
5
5
|
|
6
6
|
module Minitest
|
7
7
|
def self.plugin_blinka_init(options)
|
@@ -12,7 +12,6 @@ module Minitest
|
|
12
12
|
|
13
13
|
module BlinkaPlugin
|
14
14
|
REPORT_PATH = 'blinka_results.json'.freeze
|
15
|
-
TAP_COMMENT_PAD = 8
|
16
15
|
class Reporter < Minitest::StatisticsReporter
|
17
16
|
attr_accessor :tests
|
18
17
|
|
@@ -29,12 +28,8 @@ module Minitest
|
|
29
28
|
def report
|
30
29
|
super
|
31
30
|
|
32
|
-
|
33
|
-
|
34
|
-
json_report(append: !ENV['BLINKA_APPEND'].nil?)
|
35
|
-
end
|
36
|
-
BlinkaClient.new.report if ENV['BLINKA_REPORT']
|
37
|
-
rescue BlinkaClient::BlinkaError => error
|
31
|
+
json_report(append: !ENV['BLINKA_APPEND'].nil?) if ENV['BLINKA_JSON']
|
32
|
+
rescue BlinkaReporter::Client::BlinkaReporter::Error => error
|
38
33
|
puts(error)
|
39
34
|
end
|
40
35
|
|
@@ -45,11 +40,11 @@ module Minitest
|
|
45
40
|
total_time: total_time,
|
46
41
|
nbr_tests: count,
|
47
42
|
nbr_assertions: assertions,
|
48
|
-
commit: find_commit,
|
49
|
-
tag: ENV.fetch('BLINKA_TAG', ''),
|
50
43
|
seed: options[:seed],
|
51
44
|
results:
|
52
|
-
tests.map
|
45
|
+
tests.map do |test_result|
|
46
|
+
BlinkaReporter::MinitestAdapter.new(test_result).report
|
47
|
+
end
|
53
48
|
}
|
54
49
|
result = append_previous(result) if append
|
55
50
|
|
@@ -61,63 +56,23 @@ module Minitest
|
|
61
56
|
puts("Test results written to `#{REPORT_PATH}`")
|
62
57
|
end
|
63
58
|
|
64
|
-
# Based on https://github.com/kern/minitest-reporters/blob/master/lib/minitest/reporters/progress_reporter.rb
|
65
|
-
# Tries to adhere to https://testanything.org/tap-specification.html
|
66
|
-
def tap_report
|
67
|
-
puts
|
68
|
-
puts('TAP version 13')
|
69
|
-
puts("1..#{tests.length}")
|
70
|
-
tests.each_with_index do |test, index|
|
71
|
-
blinka = BlinkaMinitest.new(test)
|
72
|
-
test_str = "#{blinka.path} - #{test.name.tr('#', '_')}"
|
73
|
-
if test.passed?
|
74
|
-
puts "ok #{index + 1} - #{test_str}"
|
75
|
-
elsif test.skipped?
|
76
|
-
puts "ok #{index + 1} # skip: #{test_str}"
|
77
|
-
elsif test.failure
|
78
|
-
puts "not ok #{index + 1} - failed: #{test_str}"
|
79
|
-
blinka.message.each_line { |line| print_padded_comment(line) }
|
80
|
-
|
81
|
-
# test.failure.message.each_line { |line| print_padded_comment(line) }
|
82
|
-
unless test.failure.is_a?(MiniTest::UnexpectedError)
|
83
|
-
blinka.backtrace.each { |line| print_padded_comment(line) }
|
84
|
-
end
|
85
|
-
puts
|
86
|
-
end
|
87
|
-
end
|
88
|
-
end
|
89
|
-
|
90
|
-
def print_padded_comment(line)
|
91
|
-
puts "##{' ' * TAP_COMMENT_PAD + line}"
|
92
|
-
end
|
93
|
-
|
94
|
-
def find_commit
|
95
|
-
ENV.fetch(
|
96
|
-
'BLINKA_COMMIT',
|
97
|
-
ENV.fetch(
|
98
|
-
'HEROKU_TEST_RUN_COMMIT_VERSION',
|
99
|
-
`git rev-parse HEAD`.chomp
|
100
|
-
)
|
101
|
-
)
|
102
|
-
end
|
103
|
-
|
104
59
|
private
|
105
60
|
|
106
61
|
def parse_report
|
107
62
|
return unless File.exist?(REPORT_PATH)
|
108
|
-
JSON.parse(File.read(REPORT_PATH))
|
63
|
+
JSON.parse(File.read(REPORT_PATH), symbolize_names: true)
|
109
64
|
end
|
110
65
|
|
111
66
|
def append_previous(result)
|
112
67
|
previous = parse_report
|
113
68
|
return if previous.nil?
|
114
|
-
return if result[:commit] != previous[
|
115
|
-
return if result[:tag] != previous[
|
69
|
+
return if result[:commit] != previous[:commit]
|
70
|
+
return if result[:tag] != previous[:tag]
|
116
71
|
|
117
|
-
result[:total_time] += previous[
|
118
|
-
result[:nbr_tests] += previous[
|
119
|
-
result[:nbr_assertions] += previous[
|
120
|
-
result[:results] += previous[
|
72
|
+
result[:total_time] += previous[:total_time] || 0
|
73
|
+
result[:nbr_tests] += previous[:nbr_tests] || 0
|
74
|
+
result[:nbr_assertions] += previous[:nbr_assertions] || 0
|
75
|
+
result[:results] += previous[:results] || []
|
121
76
|
result
|
122
77
|
end
|
123
78
|
end
|
data/package.json
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
{
|
2
|
+
"name": "blinka_reporter",
|
3
|
+
"version": "0.0.1",
|
4
|
+
"author": "David Wessman <david@wessman.co>",
|
5
|
+
"license": "MIT",
|
6
|
+
"devDependencies": {
|
7
|
+
"@prettier/plugin-ruby": "^2.0.0",
|
8
|
+
"husky": "^7.0.4",
|
9
|
+
"lint-staged": "^12.3.4"
|
10
|
+
},
|
11
|
+
"scripts": {
|
12
|
+
"pretty": "./node_modules/.bin/prettier --write ."
|
13
|
+
},
|
14
|
+
"husky": {
|
15
|
+
"hooks": {
|
16
|
+
"pre-commit": "lint-staged"
|
17
|
+
}
|
18
|
+
},
|
19
|
+
"lint-staged": {
|
20
|
+
"*.{md,rb,json,yml,gemspec}": "./node_modules/.bin/prettier --write"
|
21
|
+
}
|
22
|
+
}
|