percy-appium-app 0.0.1

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.
Files changed (53) hide show
  1. checksums.yaml +7 -0
  2. data/.github/ISSUE_TEMPLATE/bug_report.md +55 -0
  3. data/.github/dependabot.yml +14 -0
  4. data/.github/release-drafter.yml +28 -0
  5. data/.github/workflows/Semgrep.yml +48 -0
  6. data/.github/workflows/changelog.yml +11 -0
  7. data/.github/workflows/release.yml +22 -0
  8. data/.github/workflows/stale.yml +30 -0
  9. data/.github/workflows/test.yml +40 -0
  10. data/Gemfile +13 -0
  11. data/LICENSE +21 -0
  12. data/Makefile +3 -0
  13. data/README.md +1 -0
  14. data/Rakefile +1 -0
  15. data/percy/common/common.rb +19 -0
  16. data/percy/configs/devices.json +232 -0
  17. data/percy/environment.rb +25 -0
  18. data/percy/exceptions/exceptions.rb +13 -0
  19. data/percy/lib/app_percy.rb +55 -0
  20. data/percy/lib/cache.rb +53 -0
  21. data/percy/lib/cli_wrapper.rb +132 -0
  22. data/percy/lib/ignore_region.rb +8 -0
  23. data/percy/lib/percy_automate.rb +59 -0
  24. data/percy/lib/percy_options.rb +37 -0
  25. data/percy/lib/region.rb +22 -0
  26. data/percy/lib/tile.rb +28 -0
  27. data/percy/metadata/android_metadata.rb +79 -0
  28. data/percy/metadata/driver_metadata.rb +40 -0
  29. data/percy/metadata/ios_metadata.rb +83 -0
  30. data/percy/metadata/metadata.rb +108 -0
  31. data/percy/metadata/metadata_resolver.rb +21 -0
  32. data/percy/providers/app_automate.rb +159 -0
  33. data/percy/providers/generic_provider.rb +205 -0
  34. data/percy/providers/provider_resolver.rb +17 -0
  35. data/percy/screenshot.rb +23 -0
  36. data/percy/version.rb +5 -0
  37. data/percy-appium-app.gemspec +37 -0
  38. data/specs/android_metadata.rb +79 -0
  39. data/specs/app_automate.rb +124 -0
  40. data/specs/app_percy.rb +175 -0
  41. data/specs/cache.rb +56 -0
  42. data/specs/cli_wrapper.rb +135 -0
  43. data/specs/driver_metadata.rb +71 -0
  44. data/specs/generic_providers.rb +370 -0
  45. data/specs/ignore_regions.rb +51 -0
  46. data/specs/ios_metadata.rb +88 -0
  47. data/specs/metadata.rb +105 -0
  48. data/specs/metadata_resolver.rb +41 -0
  49. data/specs/mocks/mock_methods.rb +147 -0
  50. data/specs/percy_options.rb +114 -0
  51. data/specs/screenshot.rb +342 -0
  52. data/specs/tile.rb +33 -0
  53. metadata +194 -0
@@ -0,0 +1,370 @@
1
+ # frozen_string_literal: true
2
+
3
+ # rubocop:disable Metrics/MethodLength
4
+ # rubocop:disable Metrics/AbcSize
5
+
6
+ require 'minitest/autorun'
7
+ require 'securerandom'
8
+ require 'appium_lib'
9
+ require_relative '../percy/providers/generic_provider'
10
+ require_relative '../percy/metadata/android_metadata'
11
+ require_relative '../percy/lib/region'
12
+ require_relative 'mocks/mock_methods'
13
+
14
+ # Test suite for the GenericProvider class
15
+ class TestGenericProvider < Minitest::Test
16
+ include Appium
17
+ COMPARISON_RESPONSE = { 'comparison' => { 'id' => 123, 'url' => 'https://percy-build-url' } }.freeze
18
+
19
+ def setup
20
+ @existing_dir = 'existing-dir'
21
+ Dir.mkdir(@existing_dir)
22
+
23
+ @mock_webdriver = Minitest::Mock.new
24
+ @mock_webdriver.expect(:capabilities, get_android_capabilities)
25
+ @mock_webdriver.expect(:orientation, 'PorTrait')
26
+ @mock_webdriver.expect(:get_system_bars, {
27
+ 'statusBar' => { 'height' => 10, 'width' => 20 },
28
+ 'navigationBar' => { 'height' => 10, 'width' => 20 }
29
+ })
30
+
31
+ png_bytes = 'some random bytes'
32
+ @mock_webdriver.expect(:screenshot_as, png_bytes, [:png])
33
+
34
+ @android_metadata = AndroidMetadata.new(@mock_webdriver)
35
+ @generic_provider = GenericProvider.new(@mock_webdriver, @android_metadata)
36
+ end
37
+
38
+ def teardown
39
+ FileUtils.remove_entry_secure(@existing_dir)
40
+ end
41
+
42
+ def test_get_dir_without_env_variable
43
+ ENV.delete('PERCY_TMP_DIR')
44
+ result = @generic_provider._get_dir
45
+ assert File.directory?(result), 'Directory should exist'
46
+ end
47
+
48
+ def test_get_dir_with_env_variable
49
+ ENV['PERCY_TMP_DIR'] = '/tmp/percy-apps'
50
+ result = @generic_provider._get_dir
51
+ assert_equal '/tmp/percy-apps', result
52
+ assert File.directory?(result), 'Directory should exist'
53
+ Dir.rmdir(result)
54
+ ENV.delete('PERCY_TMP_DIR')
55
+ end
56
+
57
+ def test_get_path
58
+ count = 1000
59
+ png_paths = Array.new(count) { @generic_provider._get_path(@existing_dir) }
60
+ assert_equal png_paths.uniq.length, count
61
+ end
62
+
63
+ def test_write_screenshot
64
+ png_bytes = 'some random bytes'
65
+ filepath = @generic_provider._write_screenshot(png_bytes, @existing_dir)
66
+ assert(File.exist?(filepath))
67
+ end
68
+
69
+ def test_get_debug_url
70
+ assert_equal @generic_provider.get_debug_url, ''
71
+ end
72
+
73
+ def test_get_tag
74
+ 10.times do
75
+ @mock_webdriver.expect(:capabilities, get_android_capabilities)
76
+ end
77
+ tag = @generic_provider._get_tag
78
+ assert_includes tag, 'name'
79
+ assert_equal tag['name'], @android_metadata.device_name
80
+ assert_includes tag, 'os_name'
81
+ assert_equal tag['os_name'], @android_metadata.os_name
82
+ assert_includes tag, 'os_version'
83
+ assert_equal tag['os_version'], @android_metadata.os_version
84
+ assert_includes tag, 'width'
85
+ assert_equal tag['width'], @android_metadata.device_screen_size['width']
86
+ assert_includes tag, 'height'
87
+ assert_equal tag['height'], @android_metadata.device_screen_size['height']
88
+ assert_includes tag, 'orientation'
89
+ assert_equal tag['orientation'], @android_metadata.get_orientation.downcase
90
+ end
91
+
92
+ def test_get_tag_kwargs
93
+ 10.times do
94
+ @mock_webdriver.expect(:capabilities, get_android_capabilities)
95
+ end
96
+ device_name = 'some-device-name'
97
+ tag = @generic_provider._get_tag(device_name: device_name)
98
+ assert_includes tag, 'name'
99
+ assert_equal tag['name'], device_name
100
+
101
+ orientation = 'Some-Orientation'
102
+ tag = @generic_provider._get_tag(orientation: orientation)
103
+ assert_includes tag, 'orientation'
104
+ assert_equal tag['orientation'], orientation.downcase
105
+ end
106
+
107
+ def test_get_tiles
108
+ session_id = 'session_id_123'
109
+ 10.times do
110
+ @mock_webdriver.expect(:session_id, session_id)
111
+ end
112
+ 10.times do
113
+ @mock_webdriver.expect(:get_system_bars, {
114
+ 'statusBar' => { 'height' => 10, 'width' => 20 },
115
+ 'navigationBar' => { 'height' => 10, 'width' => 20 }
116
+ })
117
+ end
118
+ tile = @generic_provider._get_tiles[0]
119
+ dict_tile = tile.to_h
120
+ assert_includes dict_tile, 'filepath'
121
+ assert_instance_of String, dict_tile['filepath']
122
+ assert(File.exist?(dict_tile['filepath']))
123
+ assert_includes dict_tile, 'status_bar_height'
124
+ assert_equal dict_tile['status_bar_height'], @android_metadata.status_bar_height
125
+ assert_includes dict_tile, 'nav_bar_height'
126
+ assert_equal dict_tile['nav_bar_height'], @android_metadata.navigation_bar_height
127
+ assert_includes dict_tile, 'header_height'
128
+ assert_equal dict_tile['header_height'], 0
129
+ assert_includes dict_tile, 'footer_height'
130
+ assert_equal dict_tile['footer_height'], 0
131
+ assert_includes dict_tile, 'fullscreen'
132
+ assert_equal dict_tile['fullscreen'], false
133
+ File.delete(tile.filepath)
134
+ end
135
+
136
+ def test_get_tiles_kwargs
137
+ status_bar_height = 135
138
+ nav_bar_height = 246
139
+ tile = @generic_provider._get_tiles(
140
+ status_bar_height: status_bar_height,
141
+ nav_bar_height: nav_bar_height,
142
+ full_screen: true
143
+ )[0]
144
+ dict_tile = tile.to_h
145
+ assert_includes dict_tile, 'status_bar_height'
146
+ assert_equal dict_tile['status_bar_height'], status_bar_height
147
+ assert_includes dict_tile, 'nav_bar_height'
148
+ assert_equal dict_tile['nav_bar_height'], nav_bar_height
149
+ assert_includes dict_tile, 'fullscreen'
150
+ assert_equal dict_tile['fullscreen'], true
151
+ end
152
+
153
+ def test_post_screenshots
154
+ session_id = 'session_id_123'
155
+
156
+ mock = Minitest::Mock.new
157
+ mock.expect(:post_screenshots, COMPARISON_RESPONSE, [String, Hash, Hash, String, Array, Array])
158
+ mock.expect(:session_id, session_id)
159
+ 10.times do
160
+ mock.expect(:get_system_bars, {
161
+ 'statusBar' => { 'height' => 10, 'width' => 20 },
162
+ 'navigationBar' => { 'height' => 10, 'width' => 20 }
163
+ })
164
+ end
165
+ 6.times do
166
+ @mock_webdriver.expect(:capabilities, get_android_capabilities)
167
+ end
168
+
169
+ Metadata.class_eval do
170
+ define_method(:session_id) do
171
+ mock.session_id
172
+ end
173
+ end
174
+
175
+ AndroidMetadata.class_eval do
176
+ 6.times do
177
+ define_method(:get_system_bars) do
178
+ mock.get_system_bars
179
+ end
180
+ end
181
+ end
182
+
183
+ tag = @generic_provider._get_tag
184
+ tiles = @generic_provider._get_tiles
185
+
186
+ @generic_provider.stub(:_post_screenshots, COMPARISON_RESPONSE) do
187
+ response = @generic_provider._post_screenshots(
188
+ 'screenshot 1', tag, tiles, '', [], []
189
+ )
190
+ assert_equal response, COMPARISON_RESPONSE
191
+ end
192
+ end
193
+
194
+ def test_supports
195
+ assert GenericProvider.supports('some-dummy-url')
196
+ end
197
+
198
+ def test_non_app_automate
199
+ session_id = 'session_id_123'
200
+ mock = Minitest::Mock.new
201
+ 4.times do
202
+ mock.expect(:session_id, session_id)
203
+ end
204
+
205
+ Metadata.class_eval do
206
+ 4.times do
207
+ define_method(:session_id) do
208
+ mock.session_id
209
+ end
210
+ end
211
+ end
212
+
213
+ 7.times do
214
+ @mock_webdriver.expect(:capabilities, get_android_capabilities)
215
+ end
216
+ 6.times do
217
+ @mock_webdriver.expect(:get_system_bars, {
218
+ 'statusBar' => { 'height' => 10, 'width' => 20 },
219
+ 'navigationBar' => { 'height' => 10, 'width' => 20 }
220
+ })
221
+ end
222
+
223
+ @generic_provider.stub(:_post_screenshots, COMPARISON_RESPONSE) do
224
+ response = @generic_provider.screenshot('screenshot 1')
225
+ assert_equal response, COMPARISON_RESPONSE
226
+ end
227
+ end
228
+
229
+ def test_get_device_name
230
+ device_name = @generic_provider.get_device_name
231
+ assert_equal device_name, ''
232
+ end
233
+
234
+ def test_get_region_object
235
+ mock_element = Minitest::Mock.new
236
+ mock_element.expect(:location, { 'x' => 10, 'y' => 20 })
237
+ mock_element.expect(:size, { 'width' => 100, 'height' => 200 })
238
+
239
+ result = @generic_provider.get_region_object('my-selector', mock_element)
240
+ expected_result = {
241
+ 'selector' => 'my-selector',
242
+ 'coOrdinates' => { 'top' => 20, 'bottom' => 220, 'left' => 10, 'right' => 110 }
243
+ }
244
+
245
+ assert_equal result, expected_result
246
+ mock_element.verify
247
+ end
248
+
249
+ def test_get_regions_by_xpath
250
+ mock_element = Minitest::Mock.new
251
+ mock_element.expect(:location, { 'x' => 10, 'y' => 20 })
252
+ mock_element.expect(:size, { 'width' => 100, 'height' => 200 })
253
+
254
+ @mock_webdriver.expect(:find_element, mock_element,
255
+ [Appium::Core::Base::SearchContext::FINDERS[:xpath], '//path/to/element'])
256
+
257
+ elements_array = []
258
+ xpaths = ['//path/to/element']
259
+ @generic_provider.get_regions_by_xpath(elements_array, xpaths)
260
+
261
+ expected_elements_array = [{
262
+ 'selector' => 'xpath: //path/to/element',
263
+ 'coOrdinates' => { 'top' => 20, 'bottom' => 220, 'left' => 10, 'right' => 110 }
264
+ }]
265
+
266
+ assert_equal elements_array, expected_elements_array
267
+ end
268
+
269
+ def test_get_regions_by_xpath_with_non_existing_element
270
+ @mock_webdriver.expect(:find_element, [Appium::Core::Base::SearchContext::FINDERS[:xpath], '//path/to/element']) do
271
+ raise Appium::Core::Error::NoSuchElementError, 'Test error'
272
+ end
273
+ elements_array = []
274
+ xpaths = ['//path/to/element']
275
+ @generic_provider.get_regions_by_xpath(elements_array, xpaths)
276
+
277
+ assert_empty elements_array
278
+ end
279
+
280
+ def test_get_regions_by_ids
281
+ mock_element = Minitest::Mock.new
282
+ mock_element.expect(:location, { 'x' => 10, 'y' => 20 })
283
+ mock_element.expect(:size, { 'width' => 100, 'height' => 200 })
284
+
285
+ @mock_webdriver.expect(:find_element, mock_element,
286
+ [Appium::Core::Base::SearchContext::FINDERS[:accessibility_id], 'some_id'])
287
+
288
+ elements_array = []
289
+ ids = ['some_id']
290
+ @generic_provider.get_regions_by_ids(elements_array, ids)
291
+
292
+ expected_elements_array = [{
293
+ 'selector' => 'id: some_id',
294
+ 'coOrdinates' => { 'top' => 20, 'bottom' => 220, 'left' => 10, 'right' => 110 }
295
+ }]
296
+
297
+ assert_equal elements_array, expected_elements_array
298
+ end
299
+
300
+ def test_get_regions_by_ids_with_non_existing_element
301
+ mock_element = Minitest::Mock.new
302
+ mock_element.expect(:location, { 'x' => 10, 'y' => 20 })
303
+ mock_element.expect(:size, { 'width' => 100, 'height' => 200 })
304
+
305
+ @mock_webdriver.expect(:find_element, [Appium::Core::Base::SearchContext::FINDERS[:accessibility_id], 'id1']) do
306
+ raise Appium::Core::Error::NoSuchElementError, 'Test error'
307
+ end
308
+
309
+ elements_array = []
310
+ ids = ['id1']
311
+ @generic_provider.get_regions_by_ids(elements_array, ids)
312
+
313
+ assert_empty elements_array
314
+ end
315
+
316
+ def test_get_regions_by_elements
317
+ mock_element = Minitest::Mock.new
318
+ mock_element.expect(:location, { 'x' => 10, 'y' => 20 })
319
+ mock_element.expect(:size, { 'width' => 100, 'height' => 200 })
320
+ mock_element.expect(:attribute, 'textView', ['class'])
321
+
322
+ elements_array = []
323
+ elements = [mock_element]
324
+ @generic_provider.get_regions_by_elements(elements_array, elements)
325
+
326
+ expected_elements_array = [{
327
+ 'selector' => 'element: 0 textView',
328
+ 'coOrdinates' => { 'top' => 20, 'bottom' => 220, 'left' => 10, 'right' => 110 }
329
+ }]
330
+
331
+ assert_equal elements_array, expected_elements_array
332
+ mock_element.verify
333
+ end
334
+
335
+ def test_get_regions_by_elements_with_non_existing_element
336
+ element_mock = Minitest::Mock.new
337
+ element_mock.expect(:attribute, 'class') do
338
+ raise Appium::Core::Error::NoSuchElementError, 'Test error'
339
+ end
340
+
341
+ elements_array = []
342
+ elements = [element_mock]
343
+
344
+ @generic_provider.get_regions_by_elements(elements_array, elements)
345
+
346
+ assert_equal 0, elements_array.length
347
+ end
348
+
349
+ def test_get_regions_by_location
350
+ @mock_webdriver.expect(:capabilities, get_android_capabilities)
351
+ @mock_webdriver.expect(:capabilities, get_android_capabilities)
352
+ @mock_webdriver.expect(:capabilities, get_android_capabilities)
353
+ @mock_webdriver.expect(:capabilities, get_android_capabilities)
354
+ @mock_webdriver.expect(:capabilities, get_android_capabilities)
355
+ @mock_webdriver.expect(:capabilities, get_android_capabilities)
356
+ valid_ignore_region = Region.new(100, 200, 200, 300)
357
+ invalid_ignore_region = Region.new(100, 2390, 200, 300)
358
+
359
+ elements_array = []
360
+ custom_locations = [valid_ignore_region, invalid_ignore_region]
361
+ @generic_provider.get_regions_by_location(elements_array, custom_locations)
362
+
363
+ expected_elements_array = [{
364
+ selector: 'custom ignore region: 0',
365
+ coOrdinates: { top: 100, bottom: 200, left: 200, right: 300 }
366
+ }]
367
+
368
+ assert_equal elements_array, expected_elements_array
369
+ end
370
+ end
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ # rubocop:disable Metrics/MethodLength
4
+
5
+ require 'minitest/autorun'
6
+ require_relative '../percy/lib/ignore_region'
7
+
8
+ # Test suite for the IgnoreRegions class
9
+ class TestIgnoreRegion < Minitest::Test
10
+ def test_ignore_region_valid_input
11
+ top = 10
12
+ bottom = 20
13
+ left = 30
14
+ right = 40
15
+ ignore_region = IgnoreRegion.new(top, bottom, left, right)
16
+
17
+ assert_equal ignore_region.top, top
18
+ assert_equal ignore_region.bottom, bottom
19
+ assert_equal ignore_region.left, left
20
+ assert_equal ignore_region.right, right
21
+ end
22
+
23
+ def test_ignore_region_negative_input
24
+ assert_raises(ArgumentError) { IgnoreRegion.new(-10, 20, 30, 40) }
25
+ assert_raises(ArgumentError) { IgnoreRegion.new(10, 20, -30, 40) }
26
+ assert_raises(ArgumentError) { IgnoreRegion.new(10, 20, 30, -40) }
27
+ assert_raises(ArgumentError) { IgnoreRegion.new(-10, -20, -30, -40) }
28
+ end
29
+
30
+ def test_ignore_region_invalid_input
31
+ assert_raises(ArgumentError) { IgnoreRegion.new(20, 10, 30, 40) } # bottom < top
32
+ assert_raises(ArgumentError) { IgnoreRegion.new(10, 20, 40, 30) } # right < left
33
+ end
34
+
35
+ def test_ignore_region_is_valid
36
+ ignore_region = IgnoreRegion.new(10, 20, 30, 40)
37
+ screen_height = 100
38
+ screen_width = 200
39
+ assert_equal true, ignore_region.valid?(screen_height, screen_width)
40
+
41
+ ignore_region = IgnoreRegion.new(10, 200, 30, 400)
42
+ height = 100
43
+ width = 200
44
+ assert_equal false, ignore_region.valid?(height, width)
45
+
46
+ ignore_region = IgnoreRegion.new(10, 20, 30, 40)
47
+ screen_height = 5
48
+ screen_width = 10
49
+ assert_equal false, ignore_region.valid?(screen_height, screen_width)
50
+ end
51
+ end
@@ -0,0 +1,88 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'minitest/autorun'
4
+ require 'minitest/mock'
5
+ require_relative 'mocks/mock_methods'
6
+ require_relative '../percy/metadata/ios_metadata'
7
+
8
+ # Test suite for the IOSMetadata class
9
+ class TestIOSMetadata < Minitest::Test
10
+ def setup
11
+ @mock_webdriver = Minitest::Mock.new
12
+ @bridge = Minitest::Mock.new
13
+ @http = Minitest::Mock.new
14
+ @server_url = Minitest::Mock.new
15
+ @ios_metadata = IOSMetadata.new(@mock_webdriver)
16
+ end
17
+
18
+ def test_ios_execute_script
19
+ command = 'some dummy command'
20
+ output = 'some output'
21
+ @mock_webdriver.expect(:execute_script, output, [command])
22
+
23
+ response = @ios_metadata.execute_script(command)
24
+ assert_equal(output, response)
25
+ end
26
+
27
+ def test_remote_url
28
+ @mock_webdriver.expect(:instance_variable_get, @bridge, [:@bridge])
29
+ @http.expect(:instance_variable_get, @server_url, [:@server_url])
30
+ @bridge.expect(:instance_variable_get, @http, [:@http])
31
+ @server_url.expect(:to_s, 'some-remote-url')
32
+
33
+ assert_equal('some-remote-url', @ios_metadata.remote_url)
34
+ end
35
+
36
+ def test_get_window_size
37
+ height = 100
38
+ width = 100
39
+ window_size = { 'height' => height, 'width' => width }
40
+ @mock_webdriver.expect(:get_window_size, window_size)
41
+ session_id = 'session_id_123'
42
+ @mock_webdriver.expect(:session_id, session_id)
43
+ @mock_webdriver.expect(:session_id, session_id)
44
+
45
+ assert_equal({}, @ios_metadata._window_size)
46
+ fetched_window_size = @ios_metadata.get_window_size
47
+ assert_equal(window_size, fetched_window_size)
48
+ end
49
+
50
+ def test_device_screen_size
51
+ session_id = 'session_id_123'
52
+ 5.times do
53
+ @mock_webdriver.expect(:session_id, session_id)
54
+ end
55
+ @mock_webdriver.expect(:capabilities, { 'deviceName' => 'iPhone 6' })
56
+ @mock_webdriver.expect(:get_window_size, { 'height' => 100, 'width' => 100 })
57
+ device_screen_size = @ios_metadata.device_screen_size
58
+ assert_equal({ 'height' => 200, 'width' => 200 }, device_screen_size)
59
+ end
60
+
61
+ def test_status_bar
62
+ @mock_webdriver.expect(:capabilities, { 'deviceName' => 'iPhone 6' })
63
+ session_id = 'session_id_123'
64
+ @mock_webdriver.expect(:session_id, session_id)
65
+ @mock_webdriver.expect(:session_id, session_id)
66
+
67
+ status_bar = @ios_metadata.status_bar
68
+ assert_equal({ 'height' => 40 }, status_bar)
69
+ end
70
+
71
+ def test_scale_factor_present_in_devices_json
72
+ @mock_webdriver.expect(:capabilities, { 'deviceName' => 'iPhone 6' })
73
+ assert_equal(2, @ios_metadata.scale_factor)
74
+ end
75
+
76
+ def test_scale_factor_not_present_in_devices_json
77
+ window_size = { 'height' => 100, 'width' => 100 }
78
+ session_id = 'session_id_123'
79
+ 4.times do
80
+ @mock_webdriver.expect(:session_id, session_id)
81
+ end
82
+ @mock_webdriver.expect(:capabilities, { 'deviceName' => 'iPhone 14' })
83
+ @mock_webdriver.expect(:get_window_size, window_size)
84
+ @mock_webdriver.expect(:execute_script, { 'height' => 100, 'width' => 200 }, ['mobile: viewportRect'])
85
+
86
+ assert_equal(2, @ios_metadata.scale_factor)
87
+ end
88
+ end
data/specs/metadata.rb ADDED
@@ -0,0 +1,105 @@
1
+ # frozen_string_literal: true
2
+
3
+ # rubocop:disable Metrics/MethodLength
4
+ # rubocop:disable Metrics/AbcSize
5
+
6
+ require 'minitest/autorun'
7
+ require_relative '../percy/metadata/metadata'
8
+
9
+ # Test suite for the Metadata class
10
+ class TestMetadata < Minitest::Test
11
+ def setup
12
+ @mock_webdriver = Minitest::Mock.new
13
+ @metadata = Metadata.new(@mock_webdriver)
14
+ end
15
+
16
+ def test_metadata_properties
17
+ assert_raises(NotImplementedError) { @metadata._device_name }
18
+ assert_raises(NotImplementedError) { @metadata.device_screen_size }
19
+ assert_raises(NotImplementedError) { @metadata.navigation_bar }
20
+ assert_raises(NotImplementedError) { @metadata.navigation_bar_height }
21
+ assert_raises(NotImplementedError) { @metadata.status_bar }
22
+ assert_raises(NotImplementedError) { @metadata.status_bar_height }
23
+ assert_raises(NotImplementedError) { @metadata.viewport }
24
+
25
+ assert_equal({}, @metadata.device_info)
26
+
27
+ device_config = @metadata.get_device_info('iPhone 6')
28
+ refute_equal({}, @metadata.device_info)
29
+ assert_equal(device_config, @metadata.get_device_info('iPhone 6'))
30
+
31
+ ENV['PERCY_LOGLEVEL'] = 'debug'
32
+ end
33
+
34
+ def test_get_device_info_device_not_present
35
+ device_name = 'Some Phone 123'
36
+ assert_output(/#{Regexp.escape(device_name.downcase)} does not exist in config\./) do
37
+ @metadata.get_device_info(device_name)
38
+ end
39
+ end
40
+
41
+ def test_metadata_get_orientation
42
+ orientation = 'PRTRT'
43
+ @mock_webdriver.expect(:get_orientation, orientation, [{ "orientation": orientation }])
44
+ assert(orientation, @metadata.get_orientation(orientation: orientation))
45
+
46
+ orientation = 'prtrt'
47
+ @mock_webdriver.expect(:get_orientation, orientation, [{ "orientation": orientation }])
48
+ assert_equal(orientation.upcase, @metadata.get_orientation(orientation: orientation))
49
+
50
+ orientation = 'OriENTation'
51
+ @mock_webdriver.expect(:get_orientation, orientation, [{ "orientation": 'AUTO' }])
52
+
53
+ @mock_webdriver.expect(:orientation, orientation)
54
+ assert(orientation.upcase, @metadata.get_orientation(orientation: 'AUTO'))
55
+
56
+ @mock_webdriver.expect(:orientation, orientation)
57
+ assert(orientation.upcase, @metadata.get_orientation(orientation: 'auto'))
58
+
59
+ @mock_webdriver.expect(:orientation, orientation)
60
+ assert(orientation.upcase, @metadata.get_orientation(orientation: 'Auto'))
61
+
62
+ orientation = 'OriEntaTion'
63
+ @mock_webdriver.expect(:capabilities, { 'orientation' => orientation })
64
+ assert_equal(orientation.upcase, @metadata.get_orientation)
65
+
66
+ @mock_webdriver.expect(:capabilities, {})
67
+ assert_equal('PORTRAIT', @metadata.get_orientation)
68
+ end
69
+
70
+ def test_metadata_session_id
71
+ session_id = 'Some Totally random session ID'
72
+ @mock_webdriver.expect(:session_id, session_id)
73
+ assert_equal(session_id, @metadata.session_id)
74
+ @mock_webdriver.verify
75
+ end
76
+
77
+ def test_metadata_os_version
78
+ capabilities = { 'os_version' => '10' }
79
+ @mock_webdriver.expect(:capabilities, capabilities)
80
+ @mock_webdriver.expect(:capabilities, capabilities)
81
+ @mock_webdriver.expect(:capabilities, capabilities)
82
+ os_ver = @metadata.os_version
83
+ assert_equal('10', os_ver)
84
+ end
85
+
86
+ def test_metadata_value_from_devices_info_for_android
87
+ android_device = 'google pixel 7'
88
+ android_device_info = { '13' => { 'status_bar' => '118', 'nav_bar' => '63' } }
89
+
90
+ @metadata.instance_variable_set(:@device_name, nil)
91
+ assert_equal(android_device_info['13']['status_bar'].to_i,
92
+ @metadata.value_from_devices_info('status_bar', android_device, '13'))
93
+ end
94
+
95
+ def test_metadata_value_from_devices_info_for_ios
96
+ ios_device = 'iphone 12 pro max'
97
+ ios_device_info = { 'scale_factor' => '3', 'status_bar' => '47' }
98
+
99
+ @metadata.instance_variable_set(:@device_name, nil)
100
+ assert_equal(
101
+ ios_device_info['scale_factor'].to_i,
102
+ @metadata.value_from_devices_info('scale_factor', ios_device)
103
+ )
104
+ end
105
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'minitest/autorun'
4
+ require 'minitest/mock'
5
+ require_relative '../percy/metadata/android_metadata'
6
+ require_relative '../percy/metadata/ios_metadata'
7
+ require_relative '../percy/metadata/metadata_resolver'
8
+
9
+ # Test suite for the MetadataResolver class
10
+ class MetadataResolverTestCase < Minitest::Test
11
+ def setup
12
+ @mock_webdriver = Minitest::Mock.new
13
+ end
14
+
15
+ def test_android_resolved
16
+ @mock_webdriver.expect(:capabilities, { 'platformName' => 'Android' })
17
+ @mock_webdriver.expect(:capabilities, { 'platformName' => 'Android' })
18
+ resolved_metadata = MetadataResolver.resolve(@mock_webdriver)
19
+
20
+ assert_instance_of(AndroidMetadata, resolved_metadata)
21
+ @mock_webdriver.verify
22
+ end
23
+
24
+ def test_ios_resolved
25
+ @mock_webdriver.expect(:capabilities, { 'platformName' => 'iOS' })
26
+ resolved_metadata = MetadataResolver.resolve(@mock_webdriver)
27
+
28
+ assert_instance_of(IOSMetadata, resolved_metadata)
29
+ @mock_webdriver.verify
30
+ end
31
+
32
+ def test_unknown_platform_exception
33
+ @mock_webdriver.expect(:capabilities, { 'platformName' => 'Something Random' })
34
+
35
+ assert_raises(Exception) do
36
+ MetadataResolver.resolve(@mock_webdriver)
37
+ end
38
+
39
+ @mock_webdriver.verify
40
+ end
41
+ end