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.
- checksums.yaml +7 -0
- data/.github/ISSUE_TEMPLATE/bug_report.md +55 -0
- data/.github/dependabot.yml +14 -0
- data/.github/release-drafter.yml +28 -0
- data/.github/workflows/Semgrep.yml +48 -0
- data/.github/workflows/changelog.yml +11 -0
- data/.github/workflows/release.yml +22 -0
- data/.github/workflows/stale.yml +30 -0
- data/.github/workflows/test.yml +40 -0
- data/Gemfile +13 -0
- data/LICENSE +21 -0
- data/Makefile +3 -0
- data/README.md +1 -0
- data/Rakefile +1 -0
- data/percy/common/common.rb +19 -0
- data/percy/configs/devices.json +232 -0
- data/percy/environment.rb +25 -0
- data/percy/exceptions/exceptions.rb +13 -0
- data/percy/lib/app_percy.rb +55 -0
- data/percy/lib/cache.rb +53 -0
- data/percy/lib/cli_wrapper.rb +132 -0
- data/percy/lib/ignore_region.rb +8 -0
- data/percy/lib/percy_automate.rb +59 -0
- data/percy/lib/percy_options.rb +37 -0
- data/percy/lib/region.rb +22 -0
- data/percy/lib/tile.rb +28 -0
- data/percy/metadata/android_metadata.rb +79 -0
- data/percy/metadata/driver_metadata.rb +40 -0
- data/percy/metadata/ios_metadata.rb +83 -0
- data/percy/metadata/metadata.rb +108 -0
- data/percy/metadata/metadata_resolver.rb +21 -0
- data/percy/providers/app_automate.rb +159 -0
- data/percy/providers/generic_provider.rb +205 -0
- data/percy/providers/provider_resolver.rb +17 -0
- data/percy/screenshot.rb +23 -0
- data/percy/version.rb +5 -0
- data/percy-appium-app.gemspec +37 -0
- data/specs/android_metadata.rb +79 -0
- data/specs/app_automate.rb +124 -0
- data/specs/app_percy.rb +175 -0
- data/specs/cache.rb +56 -0
- data/specs/cli_wrapper.rb +135 -0
- data/specs/driver_metadata.rb +71 -0
- data/specs/generic_providers.rb +370 -0
- data/specs/ignore_regions.rb +51 -0
- data/specs/ios_metadata.rb +88 -0
- data/specs/metadata.rb +105 -0
- data/specs/metadata_resolver.rb +41 -0
- data/specs/mocks/mock_methods.rb +147 -0
- data/specs/percy_options.rb +114 -0
- data/specs/screenshot.rb +342 -0
- data/specs/tile.rb +33 -0
- metadata +194 -0
@@ -0,0 +1,147 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
|
5
|
+
def get_android_capabilities
|
6
|
+
{
|
7
|
+
'platform' => 'LINUX',
|
8
|
+
'webStorageEnabled' => false,
|
9
|
+
'takesScreenshot' => true,
|
10
|
+
'javascriptEnabled' => true,
|
11
|
+
'databaseEnabled' => false,
|
12
|
+
'networkConnectionEnabled' => true,
|
13
|
+
'locationContextEnabled' => false,
|
14
|
+
'warnings' => {},
|
15
|
+
'desired' => {
|
16
|
+
'percy:options' => {
|
17
|
+
'enabled' => true,
|
18
|
+
'ignoreErrors' => false
|
19
|
+
},
|
20
|
+
'percyOptions' => {
|
21
|
+
'enabled' => true,
|
22
|
+
'ignoreErrors' => false
|
23
|
+
},
|
24
|
+
'platformName' => 'Android',
|
25
|
+
'bstack:options' => {
|
26
|
+
'appiumVersion' => '1.17.0'
|
27
|
+
},
|
28
|
+
'goog:chromeOptions' => {},
|
29
|
+
'newCommandTimeout' => 0,
|
30
|
+
'deviceName' => 'google pixel 4',
|
31
|
+
'chromedriverPorts' => [
|
32
|
+
[
|
33
|
+
18_144,
|
34
|
+
18_154
|
35
|
+
]
|
36
|
+
],
|
37
|
+
'automationName' => 'uiautomator2',
|
38
|
+
'systemPort' => 8204,
|
39
|
+
'chromedriverPort' => 18_084,
|
40
|
+
'build' => 'android-builds',
|
41
|
+
'os_version' => '10.0',
|
42
|
+
'sessionName' => 'first-session',
|
43
|
+
'skipServerInstallation' => true,
|
44
|
+
'udid' => '9A301FFAZ0043B',
|
45
|
+
'appPackage' => 'org.wikipedia.alpha',
|
46
|
+
'appActivity' => 'org.wikipedia.main.MainActivity',
|
47
|
+
'nativeWebScreenshot' => true,
|
48
|
+
'disableSuppressAccessibilityService' => true
|
49
|
+
},
|
50
|
+
'percy:options' => {
|
51
|
+
'enabled' => true,
|
52
|
+
'ignoreErrors' => true
|
53
|
+
},
|
54
|
+
'percyOptions' => {
|
55
|
+
'enabled' => true,
|
56
|
+
'ignoreErrors' => true
|
57
|
+
},
|
58
|
+
'platformName' => 'Android',
|
59
|
+
'bstack:options' => {
|
60
|
+
'appiumVersion' => '1.17.0'
|
61
|
+
},
|
62
|
+
'goog:chromeOptions' => {},
|
63
|
+
'newCommandTimeout' => 0,
|
64
|
+
'deviceName' => '9A301FFAZ0043B',
|
65
|
+
'chromedriverPorts' => [
|
66
|
+
[
|
67
|
+
18_144,
|
68
|
+
18_154
|
69
|
+
]
|
70
|
+
],
|
71
|
+
'automationName' => 'uiautomator2',
|
72
|
+
'systemPort' => 8204,
|
73
|
+
'chromedriverPort' => 18_084,
|
74
|
+
'build' => 'android-builds',
|
75
|
+
'os_version' => '10.0',
|
76
|
+
'sessionName' => 'first-session',
|
77
|
+
'skipServerInstallation' => true,
|
78
|
+
'udid' => '9A301FFAZ0043B',
|
79
|
+
'appPackage' => 'org.wikipedia.alpha',
|
80
|
+
'appActivity' => 'org.wikipedia.main.MainActivity',
|
81
|
+
'nativeWebScreenshot' => true,
|
82
|
+
'disableSuppressAccessibilityService' => true,
|
83
|
+
'deviceUDID' => '9A301FFAZ0043B',
|
84
|
+
'deviceApiLevel' => 29,
|
85
|
+
'platformVersion' => '10',
|
86
|
+
'deviceScreenSize' => '1080x2280',
|
87
|
+
'deviceScreenDensity' => 440,
|
88
|
+
'deviceModel' => 'Pixel 4',
|
89
|
+
'deviceManufacturer' => 'Google',
|
90
|
+
'pixelRatio' => 2.75,
|
91
|
+
'statBarHeight' => 83,
|
92
|
+
'viewportRect' => {
|
93
|
+
'left' => 0,
|
94
|
+
'top' => 83,
|
95
|
+
'width' => 1080,
|
96
|
+
'height' => 2153
|
97
|
+
}
|
98
|
+
}
|
99
|
+
end
|
100
|
+
|
101
|
+
def get_ios_capabilities
|
102
|
+
{
|
103
|
+
'webStorageEnabled' => false,
|
104
|
+
'locationContextEnabled' => false,
|
105
|
+
'browserName' => '',
|
106
|
+
'platform' => 'MAC',
|
107
|
+
'javascriptEnabled' => true,
|
108
|
+
'databaseEnabled' => false,
|
109
|
+
'takesScreenshot' => true,
|
110
|
+
'networkConnectionEnabled' => false,
|
111
|
+
'percy:options' => {
|
112
|
+
'enabled' => true,
|
113
|
+
'ignoreErrors' => true
|
114
|
+
},
|
115
|
+
'percyOptions' => {
|
116
|
+
'enabled' => true,
|
117
|
+
'ignoreErrors' => false
|
118
|
+
},
|
119
|
+
'platformName' => 'iOS',
|
120
|
+
'bstack:options' => {
|
121
|
+
'appiumVersion' => '1.21.0'
|
122
|
+
},
|
123
|
+
'newCommandTimeout' => 0,
|
124
|
+
'realMobile' => 'true',
|
125
|
+
'deviceName' => 'iphone 14',
|
126
|
+
'safariIgnoreFraudWarning' => true,
|
127
|
+
'orientation' => 'PORTRAIT',
|
128
|
+
'deviceOrientation' => 'PORTRAIT',
|
129
|
+
'noReset' => true,
|
130
|
+
'automationName' => 'XCUITest',
|
131
|
+
'keychainPath' => '[REDACTED VALUE]',
|
132
|
+
'keychainPassword' => '[REDACTED VALUE]',
|
133
|
+
'useXctestrunFile' => true,
|
134
|
+
'bootstrapPath' => '/usr/local/.browserstack/config/wda_derived_data_16_1.21.0_e9279c32-baa8-4e44-b03e-00aa591b5c2b/Build/Products',
|
135
|
+
'browserstack.isTargetBased' => 'true',
|
136
|
+
'build' => 'ios-builds',
|
137
|
+
'os_version' => '16',
|
138
|
+
'sessionName' => 'v0.0.1',
|
139
|
+
'udid' => '00008110-001019020AA1401E',
|
140
|
+
'bundleID' => 'com.browserstack.Sample-iOS',
|
141
|
+
'bundleId' => 'com.browserstack.Sample-iOS',
|
142
|
+
'webkitResponseTimeout' => 20_000,
|
143
|
+
'safariInitialUrl' => 'http://mobile-internet-check.browserstack.com',
|
144
|
+
'waitForQuiescence' => false,
|
145
|
+
'wdaStartupRetries' => 3
|
146
|
+
}
|
147
|
+
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'minitest/autorun'
|
4
|
+
require 'minitest/mock'
|
5
|
+
require_relative '../percy/lib/percy_options'
|
6
|
+
|
7
|
+
# Test suite for the PercyOptions class
|
8
|
+
class TestPercyOptions < Minitest::Test
|
9
|
+
# Defaults
|
10
|
+
def test_percy_options_not_provided
|
11
|
+
capabilities = {}
|
12
|
+
percy_options = PercyOptions.new(capabilities)
|
13
|
+
assert_equal true, percy_options.enabled
|
14
|
+
assert_equal true, percy_options.ignore_errors
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_percy_options_w3c_enabled
|
18
|
+
capabilities = { 'percy:options' => { 'enabled' => true } }
|
19
|
+
percy_options = PercyOptions.new(capabilities)
|
20
|
+
assert_equal true, percy_options.enabled
|
21
|
+
assert_equal true, percy_options.ignore_errors
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_percy_options_json_wire_enabled
|
25
|
+
capabilities = { 'percy.enabled' => true }
|
26
|
+
percy_options = PercyOptions.new(capabilities)
|
27
|
+
assert_equal true, percy_options.enabled
|
28
|
+
assert_equal true, percy_options.ignore_errors
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_percy_options_w3c_not_enabled
|
32
|
+
capabilities = { 'percy:options' => { 'enabled' => false } }
|
33
|
+
percy_options = PercyOptions.new(capabilities)
|
34
|
+
assert_equal false, percy_options.enabled
|
35
|
+
assert_equal true, percy_options.ignore_errors
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_percy_options_json_wire_not_enabled
|
39
|
+
capabilities = { 'percy.enabled' => false }
|
40
|
+
percy_options = PercyOptions.new(capabilities)
|
41
|
+
assert_equal false, percy_options.enabled
|
42
|
+
assert_equal true, percy_options.ignore_errors
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_percy_options_w3c_ignore_errors
|
46
|
+
capabilities = { 'percy:options' => { 'ignoreErrors' => true } }
|
47
|
+
percy_options = PercyOptions.new(capabilities)
|
48
|
+
assert_equal true, percy_options.ignore_errors
|
49
|
+
assert_equal true, percy_options.enabled
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_percy_options_json_wire_ignore_errors
|
53
|
+
capabilities = { 'percy.ignoreErrors' => true }
|
54
|
+
percy_options = PercyOptions.new(capabilities)
|
55
|
+
assert_equal true, percy_options.ignore_errors
|
56
|
+
assert_equal true, percy_options.enabled
|
57
|
+
end
|
58
|
+
|
59
|
+
def test_percy_options_w3c_not_ignore_errors
|
60
|
+
capabilities = { 'percy:options' => { 'ignoreErrors' => false } }
|
61
|
+
percy_options = PercyOptions.new(capabilities)
|
62
|
+
assert_equal false, percy_options.ignore_errors
|
63
|
+
assert_equal true, percy_options.enabled
|
64
|
+
end
|
65
|
+
|
66
|
+
def test_percy_options_json_wire_not_ignore_errors
|
67
|
+
capabilities = { 'percy.ignoreErrors' => false }
|
68
|
+
percy_options = PercyOptions.new(capabilities)
|
69
|
+
assert_equal false, percy_options.ignore_errors
|
70
|
+
assert_equal true, percy_options.enabled
|
71
|
+
end
|
72
|
+
|
73
|
+
def test_percy_options_w3c_all_options_false
|
74
|
+
capabilities = { 'percy:options' => { 'ignoreErrors' => false, 'enabled' => false } }
|
75
|
+
percy_options = PercyOptions.new(capabilities)
|
76
|
+
assert_equal false, percy_options.ignore_errors
|
77
|
+
assert_equal false, percy_options.enabled
|
78
|
+
end
|
79
|
+
|
80
|
+
def test_percy_options_json_wire_all_options_false
|
81
|
+
capabilities = { 'percy.ignoreErrors' => false, 'percy.enabled' => false }
|
82
|
+
percy_options = PercyOptions.new(capabilities)
|
83
|
+
assert_equal false, percy_options.ignore_errors
|
84
|
+
# assert_equal false, percy_options.enabled
|
85
|
+
end
|
86
|
+
|
87
|
+
def test_percy_options_w3c_all_options_true
|
88
|
+
capabilities = { 'percy:options' => { 'ignoreErrors' => true, 'enabled' => true } }
|
89
|
+
percy_options = PercyOptions.new(capabilities)
|
90
|
+
assert_equal true, percy_options.ignore_errors
|
91
|
+
assert_equal true, percy_options.enabled
|
92
|
+
end
|
93
|
+
|
94
|
+
def test_percy_options_json_wire_all_options_true
|
95
|
+
capabilities = { 'percy.ignoreErrors' => true, 'percy.enabled' => true }
|
96
|
+
percy_options = PercyOptions.new(capabilities)
|
97
|
+
assert_equal true, percy_options.ignore_errors
|
98
|
+
assert_equal true, percy_options.enabled
|
99
|
+
end
|
100
|
+
|
101
|
+
def test_percy_options_json_wire_and_w3c_case_1
|
102
|
+
capabilities = { 'percy.ignoreErrors' => false, 'percy:options' => { 'enabled' => false } }
|
103
|
+
percy_options = PercyOptions.new(capabilities)
|
104
|
+
assert_equal false, percy_options.ignore_errors
|
105
|
+
assert_equal false, percy_options.enabled
|
106
|
+
end
|
107
|
+
|
108
|
+
def test_percy_options_json_wire_and_w3c_case_2
|
109
|
+
capabilities = { 'percy.enabled' => false, 'percy:options' => { 'ignoreErrors' => false } }
|
110
|
+
percy_options = PercyOptions.new(capabilities)
|
111
|
+
assert_equal false, percy_options.ignore_errors
|
112
|
+
assert_equal false, percy_options.enabled
|
113
|
+
end
|
114
|
+
end
|
data/specs/screenshot.rb
ADDED
@@ -0,0 +1,342 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# rubocop:disable Metrics/MethodLength
|
4
|
+
# rubocop:disable Metrics/AbcSize
|
5
|
+
|
6
|
+
require 'minitest/autorun'
|
7
|
+
require 'json'
|
8
|
+
require 'webmock/minitest'
|
9
|
+
require 'appium_lib'
|
10
|
+
require 'webrick'
|
11
|
+
|
12
|
+
require_relative '../percy/screenshot'
|
13
|
+
require_relative '../percy/lib/app_percy'
|
14
|
+
require_relative 'mocks/mock_methods'
|
15
|
+
|
16
|
+
# Test suite for the percy_screenshot
|
17
|
+
class MockServerRequestHandler < WEBrick::HTTPServlet::AbstractServlet
|
18
|
+
def do_GET(_request, response)
|
19
|
+
response.status = 200
|
20
|
+
response['Content-Type'] = 'application/json'
|
21
|
+
response.body = 'Screenshot Me'
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
mock_server = WEBrick::HTTPServer.new(Port: 8000)
|
26
|
+
mock_server.mount('/', MockServerRequestHandler)
|
27
|
+
mock_server_thread = Thread.new { mock_server.start }
|
28
|
+
|
29
|
+
# Mock helpers
|
30
|
+
def mock_healthcheck(fail: false, fail_how: 'error', type: 'AppPercy')
|
31
|
+
health_body = JSON.dump(success: true, build: { 'id' => '123', 'url' => 'dummy_url' }, type: type)
|
32
|
+
health_headers = { 'X-Percy-Core-Version' => '1.27.0-beta.1' }
|
33
|
+
health_status = 200
|
34
|
+
|
35
|
+
if fail && fail_how == 'error'
|
36
|
+
health_body = '{"success": false, "error": "test"}'
|
37
|
+
health_status = 500
|
38
|
+
elsif fail && fail_how == 'wrong-version'
|
39
|
+
health_headers = { 'X-Percy-Core-Version' => '2.0.0' }
|
40
|
+
elsif fail && fail_how == 'no-version'
|
41
|
+
health_headers = {}
|
42
|
+
end
|
43
|
+
|
44
|
+
stub_request(:get, 'http://localhost:5338/percy/healthcheck')
|
45
|
+
.with(headers: health_headers)
|
46
|
+
.to_return(body: health_body, status: health_status)
|
47
|
+
|
48
|
+
stub_request(:get, 'http://localhost:5338/percy/healthcheck')
|
49
|
+
.with(
|
50
|
+
headers: {
|
51
|
+
'Accept' => '*/*',
|
52
|
+
'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3',
|
53
|
+
'Host' => 'localhost:5338',
|
54
|
+
'User-Agent' => 'Ruby'
|
55
|
+
}
|
56
|
+
)
|
57
|
+
.to_return(status: health_status, body: health_body, headers: health_headers)
|
58
|
+
end
|
59
|
+
|
60
|
+
def mock_screenshot(fail: false)
|
61
|
+
stub_request(:post, 'http://localhost:5338/percy/comparison')
|
62
|
+
.to_return(body: "{\"success\": #{fail ? 'false, "error": "test"' : 'true'}}", status: (fail ? 500 : 200))
|
63
|
+
end
|
64
|
+
|
65
|
+
def mock_poa_screenshot(fail: false)
|
66
|
+
stub_request(:post, 'http://localhost:5338/percy/automateScreenshot')
|
67
|
+
.to_return(body: "{\"success\": #{fail ? 'false, "error": "test"' : 'true'}}", status: (fail ? 500 : 200))
|
68
|
+
end
|
69
|
+
|
70
|
+
def mock_session_request
|
71
|
+
stub_request(:post, 'http://127.0.0.1:4723/wd/hub/session')
|
72
|
+
.to_return(status: 200, body: '', headers: {})
|
73
|
+
end
|
74
|
+
|
75
|
+
class TestPercyScreenshot < Minitest::Test
|
76
|
+
def setup
|
77
|
+
@mock_webdriver = Minitest::Mock.new
|
78
|
+
@bridge = Minitest::Mock.new
|
79
|
+
@http = Minitest::Mock.new
|
80
|
+
@server_url = Minitest::Mock.new
|
81
|
+
@mock_webdriver.expect(:class, Appium::Core::Base::Driver)
|
82
|
+
WebMock.enable!
|
83
|
+
@requests = []
|
84
|
+
WebMock.after_request do |request, _response|
|
85
|
+
@requests << request
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def teardown
|
90
|
+
WebMock.disable!
|
91
|
+
end
|
92
|
+
|
93
|
+
def test_throws_error_when_app_percy_arg_type_mismatch
|
94
|
+
6.times do
|
95
|
+
@mock_webdriver.expect(:is_a?, true, [Appium::Core::Base::Driver])
|
96
|
+
end
|
97
|
+
30.times do
|
98
|
+
@mock_webdriver.expect(:capabilities, get_android_capabilities)
|
99
|
+
end
|
100
|
+
6.times do
|
101
|
+
@mock_webdriver.expect(:instance_variable_get, @bridge, [:@bridge])
|
102
|
+
@http.expect(:instance_variable_get, @server_url, [:@server_url])
|
103
|
+
@bridge.expect(:instance_variable_get, @http, [:@http])
|
104
|
+
@server_url.expect(:to_s, 'https://hub-cloud.browserstack.com/wd/hub')
|
105
|
+
end
|
106
|
+
|
107
|
+
assert_raises(TypeError) { AppPercy.new(@mock_webdriver).screenshot(123) }
|
108
|
+
assert_raises(TypeError) { AppPercy.new(@mock_webdriver).screenshot('screenshot 1', device_name: 123) }
|
109
|
+
assert_raises(TypeError) { AppPercy.new(@mock_webdriver).screenshot('screenshot 1', full_screen: 123) }
|
110
|
+
assert_raises(TypeError) { AppPercy.new(@mock_webdriver).screenshot('screenshot 1', orientation: 123) }
|
111
|
+
assert_raises(TypeError) { AppPercy.new(@mock_webdriver).screenshot('screenshot 1', status_bar_height: 'height') }
|
112
|
+
assert_raises(TypeError) { AppPercy.new(@mock_webdriver).screenshot('screenshot 1', nav_bar_height: 'height') }
|
113
|
+
end
|
114
|
+
|
115
|
+
def test_throws_error_when_a_driver_is_not_provided
|
116
|
+
assert_raises(Exception) { percy_screenshot }
|
117
|
+
end
|
118
|
+
|
119
|
+
def test_throws_error_when_a_name_is_not_provided
|
120
|
+
assert_raises(Exception) { percy_screenshot(@mock_webdriver) }
|
121
|
+
end
|
122
|
+
|
123
|
+
def test_disables_screenshots_when_the_healthcheck_fails
|
124
|
+
mock_healthcheck(fail: true)
|
125
|
+
|
126
|
+
assert_output(/Percy is not running, disabling screenshots/) do
|
127
|
+
percy_screenshot(@mock_webdriver, 'screenshot 1')
|
128
|
+
percy_screenshot(@mock_webdriver, 'screenshot 2')
|
129
|
+
end
|
130
|
+
|
131
|
+
assert_equal('/percy/healthcheck', @requests.last.uri.path)
|
132
|
+
end
|
133
|
+
|
134
|
+
def test_disables_screenshots_when_the_healthcheck_version_is_wrong
|
135
|
+
mock_healthcheck(fail: true, fail_how: 'wrong-version')
|
136
|
+
|
137
|
+
assert_output(/Unsupported Percy CLI version, 2.0.0/) do
|
138
|
+
percy_screenshot(@mock_webdriver, 'screenshot 1')
|
139
|
+
percy_screenshot(@mock_webdriver, 'screenshot 2')
|
140
|
+
end
|
141
|
+
|
142
|
+
assert_equal('/percy/healthcheck', @requests.last.uri.path)
|
143
|
+
end
|
144
|
+
|
145
|
+
def test_posts_screenshot_poa
|
146
|
+
mock_healthcheck(type: 'automate')
|
147
|
+
mock_poa_screenshot
|
148
|
+
mock_session_request
|
149
|
+
|
150
|
+
driver = Minitest::Mock.new
|
151
|
+
@bridge = Minitest::Mock.new
|
152
|
+
@http = Minitest::Mock.new
|
153
|
+
@server_url = Minitest::Mock.new
|
154
|
+
|
155
|
+
2.times do
|
156
|
+
driver.expect(:is_a?, true, [Appium::Core::Base::Driver])
|
157
|
+
end
|
158
|
+
10.times do
|
159
|
+
driver.expect(:session_id, 'Dummy_session_id')
|
160
|
+
end
|
161
|
+
4.times do
|
162
|
+
driver.expect(:capabilities, { 'key' => 'value' })
|
163
|
+
end
|
164
|
+
2.times do
|
165
|
+
driver.expect(:desired_capabilities, { 'key' => 'value' })
|
166
|
+
end
|
167
|
+
2.times do
|
168
|
+
driver.expect(:instance_variable_get, @bridge, [:@bridge])
|
169
|
+
@http.expect(:instance_variable_get, @server_url, [:@server_url])
|
170
|
+
@bridge.expect(:instance_variable_get, @http, [:@http])
|
171
|
+
@server_url.expect(:to_s, 'https://hub-cloud.browserstack.com/wd/hub')
|
172
|
+
end
|
173
|
+
|
174
|
+
element = Minitest::Mock.new
|
175
|
+
element.expect(:id, 'Dummy_id')
|
176
|
+
|
177
|
+
consider_element = Minitest::Mock.new
|
178
|
+
consider_element.expect(:id, 'Consider_Dummy_id')
|
179
|
+
@mock_webdriver.expect(:capabilities, { 'key' => 'value' })
|
180
|
+
|
181
|
+
percy_screenshot(driver, 'Snapshot 1', options: {})
|
182
|
+
percy_screenshot(driver, 'Snapshot 2', options: { 'enable_javascript' => true,
|
183
|
+
'ignore_region_appium_elements' => [element],
|
184
|
+
'consider_region_appium_elements' => [consider_element] })
|
185
|
+
|
186
|
+
assert_equal('/percy/automateScreenshot', @requests.last.uri.path)
|
187
|
+
|
188
|
+
s1 = JSON.parse(@requests[1].body)
|
189
|
+
assert_equal('Snapshot 1', s1['snapshotName'])
|
190
|
+
assert_equal('Dummy_session_id', s1['sessionId'])
|
191
|
+
assert_equal(
|
192
|
+
driver.instance_variable_get(:@bridge).instance_variable_get(:@http).instance_variable_get(:@server_url).to_s,
|
193
|
+
s1['commandExecutorUrl']
|
194
|
+
)
|
195
|
+
driver_caps = driver.capabilities
|
196
|
+
assert_equal(driver_caps, s1['capabilities'])
|
197
|
+
driver_desired_caps = driver.desired_capabilities
|
198
|
+
assert_equal(driver_desired_caps, s1['sessionCapabilities'])
|
199
|
+
assert_match(%r{percy-appium-app/\d+}, s1['client_info'])
|
200
|
+
assert_match(%r{appium/\d+}, s1['environment_info'][0])
|
201
|
+
assert_match(%r{ruby/\d+\.\d+\.\d+}, s1['environment_info'][1])
|
202
|
+
|
203
|
+
s2 = JSON.parse(@requests[-1].body)
|
204
|
+
assert_equal('Snapshot 2', s2['snapshotName'])
|
205
|
+
assert_equal(true, s2['options']['enable_javascript'])
|
206
|
+
assert_equal(['Dummy_id'], s2['options']['ignore_region_elements'])
|
207
|
+
assert_equal(['Consider_Dummy_id'], s2['options']['consider_region_elements'])
|
208
|
+
end
|
209
|
+
|
210
|
+
def test_posts_multiple_screenshots_to_the_local_percy_server
|
211
|
+
mock_healthcheck
|
212
|
+
mock_screenshot
|
213
|
+
|
214
|
+
driver = Minitest::Mock.new
|
215
|
+
|
216
|
+
2.times do
|
217
|
+
driver.expect(:is_a?, true, [Appium::Core::Base::Driver])
|
218
|
+
end
|
219
|
+
|
220
|
+
10.times do
|
221
|
+
driver.expect(:session_id, 'Dummy_session_id')
|
222
|
+
end
|
223
|
+
|
224
|
+
26.times do
|
225
|
+
driver.expect(:capabilities, get_android_capabilities)
|
226
|
+
end
|
227
|
+
|
228
|
+
2.times do
|
229
|
+
driver.expect(:instance_variable_get, @bridge, [:@bridge])
|
230
|
+
@http.expect(:instance_variable_get, @server_url, [:@server_url])
|
231
|
+
@bridge.expect(:instance_variable_get, @http, [:@http])
|
232
|
+
@server_url.expect(:to_s, 'https://hub-cloud.browserstack.com/wd/hub')
|
233
|
+
end
|
234
|
+
|
235
|
+
6.times do
|
236
|
+
driver.expect(
|
237
|
+
:execute_script,
|
238
|
+
'{"success":true,"result":"[{\"sha\":\"sha-something\",\"status_bar\":null'\
|
239
|
+
',\"nav_bar\":null,\"header_height\":0,\"footer_height\":0,\"index\":0}]"}',
|
240
|
+
[String]
|
241
|
+
)
|
242
|
+
end
|
243
|
+
|
244
|
+
4.times do
|
245
|
+
driver.expect(:get_system_bars, {
|
246
|
+
'statusBar' => { 'height' => 10, 'width' => 20 },
|
247
|
+
'navigationBar' => { 'height' => 10, 'width' => 20 }
|
248
|
+
})
|
249
|
+
end
|
250
|
+
|
251
|
+
percy_screenshot(driver, 'screenshot 1')
|
252
|
+
percy_screenshot(driver, 'screenshot 2', full_screen: false)
|
253
|
+
|
254
|
+
assert_equal('/percy/comparison', @requests.last.uri.path)
|
255
|
+
|
256
|
+
body = JSON.parse(@requests[-1].body)
|
257
|
+
assert_match(%r{percy-appium-app/\d+}, body['client_info'])
|
258
|
+
assert_match(%r{appium/\d+}, body['environment_info'][0])
|
259
|
+
assert_match(%r{ruby/\d+\.\d+\.\d+}, body['environment_info'][1])
|
260
|
+
end
|
261
|
+
|
262
|
+
def test_ignore_region_screenshots_to_the_local_percy_server
|
263
|
+
mock_healthcheck
|
264
|
+
mock_screenshot
|
265
|
+
|
266
|
+
mock_element = Minitest::Mock.new
|
267
|
+
mock_element.expect(:location, { 'x' => 10, 'y' => 20 })
|
268
|
+
mock_element.expect(:size, { 'width' => 200, 'height' => 400 })
|
269
|
+
|
270
|
+
xpaths = ['//path/to/element']
|
271
|
+
|
272
|
+
driver = Minitest::Mock.new
|
273
|
+
|
274
|
+
2.times do
|
275
|
+
driver.expect(:is_a?, true, [Appium::Core::Base::Driver])
|
276
|
+
end
|
277
|
+
|
278
|
+
10.times do
|
279
|
+
driver.expect(:session_id, 'Dummy_session_id')
|
280
|
+
end
|
281
|
+
|
282
|
+
26.times do
|
283
|
+
driver.expect(:capabilities, get_android_capabilities)
|
284
|
+
end
|
285
|
+
|
286
|
+
2.times do
|
287
|
+
driver.expect(:instance_variable_get, @bridge, [:@bridge])
|
288
|
+
@http.expect(:instance_variable_get, @server_url, [:@server_url])
|
289
|
+
@bridge.expect(:instance_variable_get, @http, [:@http])
|
290
|
+
@server_url.expect(:to_s, 'https://hub-cloud.browserstack.com/wd/hub')
|
291
|
+
end
|
292
|
+
|
293
|
+
5.times do
|
294
|
+
driver.expect(
|
295
|
+
:execute_script,
|
296
|
+
'{"success":true,"result":"[{\"sha\":\"sha-something\",\"status_bar\":null'\
|
297
|
+
',\"nav_bar\":null,\"header_height\":0,\"footer_height\":0,\"index\":0}]"}',
|
298
|
+
[String]
|
299
|
+
)
|
300
|
+
end
|
301
|
+
|
302
|
+
4.times do
|
303
|
+
driver.expect(:get_system_bars, {
|
304
|
+
'statusBar' => { 'height' => 10, 'width' => 20 },
|
305
|
+
'navigationBar' => { 'height' => 10, 'width' => 20 }
|
306
|
+
})
|
307
|
+
end
|
308
|
+
driver.expect(:find_element, mock_element,
|
309
|
+
[Appium::Core::Base::SearchContext::FINDERS[:xpath], '//path/to/element'])
|
310
|
+
|
311
|
+
percy_screenshot(driver, 'screenshot 1', ignore_regions_xpaths: xpaths)
|
312
|
+
|
313
|
+
assert_equal('/percy/comparison', @requests.last.uri.path)
|
314
|
+
|
315
|
+
body = JSON.parse(@requests[-1].body)
|
316
|
+
assert_match(%r{percy-appium-app/\d+}, body['client_info'])
|
317
|
+
assert_match(%r{appium/\d+}, body['environment_info'][0])
|
318
|
+
assert_equal(body['ignored_elements_data']['ignoreElementsData'].size, 1)
|
319
|
+
|
320
|
+
ignored_element_data = body['ignored_elements_data']['ignoreElementsData'][0]
|
321
|
+
assert_equal(ignored_element_data['selector'], 'xpath: //path/to/element')
|
322
|
+
assert_equal(ignored_element_data['coOrdinates']['top'], 20)
|
323
|
+
assert_equal(ignored_element_data['coOrdinates']['bottom'], 420)
|
324
|
+
assert_equal(ignored_element_data['coOrdinates']['left'], 10)
|
325
|
+
assert_equal(ignored_element_data['coOrdinates']['right'], 210)
|
326
|
+
end
|
327
|
+
|
328
|
+
def test_throws_error_when_a_driver_is_not_provided_poa
|
329
|
+
mock_healthcheck(type: 'automate')
|
330
|
+
assert_raises(Exception) { percy_screenshot }
|
331
|
+
end
|
332
|
+
|
333
|
+
def test_throws_error_when_invalid_driver_provided_poa
|
334
|
+
mock_healthcheck(type: 'automate')
|
335
|
+
assert_raises(Exception) { percy_screenshot('Wrong driver') }
|
336
|
+
end
|
337
|
+
|
338
|
+
def test_throws_error_when_a_name_is_not_provided_poa
|
339
|
+
mock_healthcheck(type: 'automate')
|
340
|
+
assert_raises(Exception) { percy_screenshot(@mock_webdriver) }
|
341
|
+
end
|
342
|
+
end
|
data/specs/tile.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'minitest/autorun'
|
4
|
+
require_relative '../percy/lib/tile'
|
5
|
+
|
6
|
+
# Test suite for the Tile class.
|
7
|
+
class TileTest < Minitest::Test
|
8
|
+
def setup
|
9
|
+
@tile = Tile.new(20, 120, 150, 0, filepath: 'some-file-path', sha: 'some-sha')
|
10
|
+
@hash_tile = @tile.to_h
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_tile_hash_keys
|
14
|
+
assert_equal @hash_tile, @tile.to_h
|
15
|
+
assert_includes @hash_tile, 'filepath'
|
16
|
+
assert_includes @hash_tile, 'status_bar_height'
|
17
|
+
assert_includes @hash_tile, 'nav_bar_height'
|
18
|
+
assert_includes @hash_tile, 'header_height'
|
19
|
+
assert_includes @hash_tile, 'footer_height'
|
20
|
+
assert_includes @hash_tile, 'fullscreen'
|
21
|
+
assert_includes @hash_tile, 'sha'
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_tile_values
|
25
|
+
assert_equal 'some-file-path', @hash_tile['filepath']
|
26
|
+
assert_equal 20, @hash_tile['status_bar_height']
|
27
|
+
assert_equal 120, @hash_tile['nav_bar_height']
|
28
|
+
assert_equal 150, @hash_tile['header_height']
|
29
|
+
assert_equal 0, @hash_tile['footer_height']
|
30
|
+
assert_equal 'some-sha', @hash_tile['sha']
|
31
|
+
assert_equal false, @hash_tile['fullscreen'] # Default
|
32
|
+
end
|
33
|
+
end
|