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.
data/lib/blinka_client.rb DELETED
@@ -1,195 +0,0 @@
1
- require 'httparty'
2
-
3
- class BlinkaClient
4
- DEFAULT_HOST = 'https://www.blinka.app'.freeze
5
- SUPPORTED_MIME_TYPES = {
6
- jpg: 'image/jpeg',
7
- jpeg: 'image/jpeg',
8
- png: 'image/png'
9
- }
10
-
11
- include HTTParty
12
-
13
- class BlinkaConfig
14
- attr_reader(:host, :repository, :team_id, :team_secret, :jwt_token)
15
-
16
- def initialize
17
- @host = ENV.fetch('BLINKA_HOST', DEFAULT_HOST)
18
- @team_id = ENV.fetch('BLINKA_TEAM_ID', nil)
19
- @team_secret = ENV.fetch('BLINKA_TEAM_SECRET', nil)
20
- @repository = ENV.fetch('BLINKA_REPOSITORY', nil)
21
-
22
- if @team_id.nil? || @team_secret.nil? || @repository.nil?
23
- raise(BlinkaError, <<~EOS)
24
- Missing configuration, make sure to set required environment variables:
25
- - BLINKA_TEAM_ID
26
- - BLINKA_TEAM_SECRET
27
- - BLINKA_REPOSITORY
28
- EOS
29
- end
30
- end
31
- end
32
-
33
- class BlinkaError < StandardError; end
34
-
35
- def initialize
36
- @config = BlinkaConfig.new
37
- self.class.base_uri("#{@config.host}/api/v1")
38
- end
39
-
40
- def report(filepath: './blinka_results.json')
41
- unless File.exist?(filepath)
42
- raise(
43
- BlinkaError,
44
- 'Could not find blinka_results.json, did tests run with environment variable BLINKA_JSON=true set?'
45
- )
46
- end
47
-
48
- if ENV.fetch('BLINKA_ALLOW_WEBMOCK_DISABLE', 'true') == 'true' &&
49
- defined?(WebMock) && WebMock.respond_to?(:disable!)
50
- WebMock.disable!
51
- end
52
-
53
- self.authenticate
54
- data = JSON.parse(File.open(filepath).read)
55
-
56
- results =
57
- data
58
- .fetch('results', [])
59
- .map do |result|
60
- if result.key?('image')
61
- result['image'] =
62
- BlinkaClient.upload_image(filepath: result['image'])
63
- result
64
- else
65
- result
66
- end
67
- end
68
-
69
- body = {
70
- report: {
71
- repository: @config.repository,
72
- tag: data['tag'],
73
- commit: data['commit'],
74
- metadata: {
75
- total_time: data['total_time'],
76
- nbr_tests: data['nbr_tests'],
77
- nbr_assertions: data['nbr_assertions'],
78
- seed: data['seed']
79
- }.compact,
80
- results: results
81
- }
82
- }
83
-
84
- response =
85
- self.class.post(
86
- '/report',
87
- body: body.to_json,
88
- headers: {
89
- 'Content-Type' => 'application/json',
90
- 'Authorization' => "Bearer #{@jwt_token}"
91
- }
92
- )
93
- case response.code
94
- when 200
95
- puts "Reported #{data['nbr_tests']} tests of commit #{data['commit']}!"
96
- else
97
- raise(BlinkaError, "Could not report, got response code #{response.code}")
98
- end
99
- rescue => error
100
- raise(BlinkaError, <<-EOS)
101
- BLINKA:
102
- Failed to create report because of #{error.class} with message:
103
- #{error.message}
104
- EOS
105
- ensure
106
- WebMock.enable! if defined?(WebMock) && WebMock.respond_to?(:enable!)
107
- end
108
-
109
- def self.report(filepath: './blinka_results.json')
110
- client = BlinkaClient.new
111
- client.report(filepath: filepath)
112
- end
113
-
114
- def self.upload_image(filepath:)
115
- return unless File.exist?(filepath)
116
-
117
- file = File.open(filepath)
118
- filename = File.basename(filepath)
119
- extension = File.extname(filepath).delete('.').to_sym
120
- content_type = SUPPORTED_MIME_TYPES[extension]
121
- return if content_type.nil?
122
-
123
- presigned_post =
124
- BlinkaClient.presign_image(filename: filename, content_type: content_type)
125
- BlinkaClient.upload_to_storage(presigned_post: presigned_post, file: file)
126
-
127
- puts "Uploaded: #{filename}"
128
- BlinkaClient.to_shrine_object(
129
- presigned_post: presigned_post,
130
- file: file,
131
- filename: filename
132
- )
133
- end
134
-
135
- def authenticate
136
- response =
137
- self.class.post(
138
- '/authentication',
139
- body: {
140
- token_id: @config.team_id,
141
- token_secret: @config.team_secret
142
- }.to_json,
143
- headers: { 'Content-Type' => 'application/json' }
144
- )
145
- case response.code
146
- when 200
147
- @jwt_token = JSON.parse(response.body).dig('auth_token')
148
- else
149
- raise(BlinkaError, 'Could not authenticate to API')
150
- end
151
- end
152
-
153
- def self.presign_image(filename:, content_type:)
154
- response =
155
- self.get(
156
- '/presign',
157
- body: { filename: filename, content_type: content_type }
158
- )
159
-
160
- case response.code
161
- when 200
162
- JSON.parse(response.body)
163
- else
164
- raise(BlinkaError, 'Could not presign file')
165
- end
166
- end
167
-
168
- def self.upload_to_storage(presigned_post:, file:)
169
- url = URI.parse(presigned_post.fetch('url'))
170
- fields = presigned_post.fetch('fields')
171
-
172
- body = presigned_post['fields'].merge({ 'file' => file.read })
173
- response = HTTParty.post(url, multipart: true, body: body)
174
-
175
- case response.code
176
- when 204
177
- true
178
- else
179
- raise(BlinkaError, 'Could not upload file to storage')
180
- end
181
- end
182
-
183
- def self.to_shrine_object(presigned_post:, file:, filename:)
184
- storage, idx = presigned_post.dig('fields', 'key').split('/')
185
- {
186
- "id": idx,
187
- "storage": storage,
188
- "metadata": {
189
- "size": file.size,
190
- "filename": filename,
191
- "mime_type": presigned_post.dig('fields', 'Content-Type')
192
- }
193
- }
194
- end
195
- end
@@ -1,90 +0,0 @@
1
- class BlinkaMinitest
2
- def initialize(test_result)
3
- @test_result = test_result
4
- end
5
-
6
- def path
7
- @path ||= source_location.first.gsub(Dir.getwd, '').delete_prefix('/')
8
- end
9
-
10
- def line
11
- @line ||= source_location.last
12
- end
13
-
14
- # Handle broken API in Minitest between 5.10 and 5.11
15
- # https://github.com/minitest-reporters/minitest-reporters/blob/e9092460b5a5cf5ca9eb375428217cbb2a7f6dbb/lib/minitest/reporters/default_reporter.rb#L159
16
- def source_location
17
- @source_location ||=
18
- if @test_result.respond_to?(:klass)
19
- @test_result.source_location
20
- else
21
- @test_result.method(@test_result.name).source_location
22
- end
23
- end
24
-
25
- def kind
26
- parts = self.path.gsub('test/', '').split('/')
27
- parts.length > 1 ? parts.first : 'general'
28
- end
29
-
30
- def message
31
- failure = @test_result.failure
32
- return unless failure
33
- "#{failure.error.class}: #{failure.error.message}"
34
- end
35
-
36
- def backtrace
37
- return unless @test_result.failure
38
- Minitest.filter_backtrace(@test_result.failure.backtrace)
39
- end
40
-
41
- def result
42
- if @test_result.error?
43
- :error
44
- elsif @test_result.skipped?
45
- :skip
46
- elsif @test_result.failure
47
- :fail
48
- else
49
- :pass
50
- end
51
- end
52
-
53
- def time
54
- @test_result.time
55
- end
56
-
57
- def name
58
- @test_result.name
59
- end
60
-
61
- def image
62
- return unless kind == 'system'
63
-
64
- image_path =
65
- if defined?(Capybara) && Capybara.respond_to?(:save_path) &&
66
- Capybara.save_path.present?
67
- "#{Capybara.save_path}/failures_#{name}.png"
68
- else
69
- "./tmp/screenshots/failures_#{name}.png"
70
- end
71
-
72
- return unless File.exist?(image_path)
73
-
74
- image_path
75
- end
76
-
77
- def report
78
- {
79
- backtrace: backtrace,
80
- message: message,
81
- line: line,
82
- image: image,
83
- kind: kind,
84
- name: name,
85
- path: path,
86
- result: result,
87
- time: time
88
- }.compact
89
- end
90
- end