percy-selenium 1.0.2.pre.beta.0 → 1.1.0.pre.beta.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/ISSUE_TEMPLATE/bug_report.md +2 -2
- data/README.md +1 -1
- data/lib/percy.rb +114 -7
- data/lib/version.rb +1 -1
- data/package.json +7 -8
- data/spec/lib/percy/percy_spec.rb +121 -10
- metadata +5 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 84e0ed534fb2da64081b19d4c0b13e837e4c8800d3ed12e61c4e827e80c94e70
|
4
|
+
data.tar.gz: 8785427dd5e88ba487e55d14b3c0d634680737eee895971dd742e81efe7a3aca
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d6d71138d3d1267f8924858ee6f94a6a9969e3ce5b4e377d0f484194c5b595e99124f74a24e30761c611a730ee78f08b8542b51870c74b1c90d318935bdf2352
|
7
|
+
data.tar.gz: 9ece4fe3dd36379e07bc1024a3cc35aa005ab9fad3aedd42f26ed16e58b2bfee4445ce95adb71780a0cc2b3f38be2a519028d6c597ef7c16c911967809f15108
|
@@ -11,7 +11,7 @@ assignees: ''
|
|
11
11
|
|
12
12
|
There are common setup gotchas that happen with Percy's SDKs, it would be worth reading
|
13
13
|
the debugging document, which might already answer your question:
|
14
|
-
https://
|
14
|
+
https://www.browserstack.com/docs/percy/integrate/percy-sdk-workflow#debugging-sdks
|
15
15
|
|
16
16
|
## Reach out to Percy support instead?
|
17
17
|
|
@@ -43,7 +43,7 @@ If necessary, describe the problem you have been experiencing in more detail.
|
|
43
43
|
## Debug logs
|
44
44
|
|
45
45
|
If you are reporting a bug, _always_ include logs! [Give the "Debugging SDKs"
|
46
|
-
document a quick read for how to gather logs](https://
|
46
|
+
document a quick read for how to gather logs](https://www.browserstack.com/docs/percy/integrate/percy-sdk-workflow#debugging-sdks)
|
47
47
|
|
48
48
|
Please do not trim or edit these logs, often times there are hints in the full
|
49
49
|
logs that help debug what is going on.
|
data/README.md
CHANGED
@@ -61,4 +61,4 @@ $ percy exec -- [ruby test command]
|
|
61
61
|
|
62
62
|
- `driver` (**required**) - A selenium-webdriver driver instance
|
63
63
|
- `name` (**required**) - The snapshot name; must be unique to each snapshot
|
64
|
-
- `options` - [See per-snapshot configuration options](https://
|
64
|
+
- `options` - [See per-snapshot configuration options](https://www.browserstack.com/docs/percy/take-percy-snapshots/overview#per-snapshot-configuration)
|
data/lib/percy.rb
CHANGED
@@ -11,6 +11,7 @@ module Percy
|
|
11
11
|
PERCY_DEBUG = ENV['PERCY_LOGLEVEL'] == 'debug'
|
12
12
|
PERCY_SERVER_ADDRESS = ENV['PERCY_SERVER_ADDRESS'] || 'http://localhost:5338'
|
13
13
|
LABEL = "[\u001b[35m" + (PERCY_DEBUG ? 'percy:ruby' : 'percy') + "\u001b[39m]"
|
14
|
+
RESONSIVE_CAPTURE_SLEEP_TIME = ENV['RESONSIVE_CAPTURE_SLEEP_TIME']
|
14
15
|
|
15
16
|
# Take a DOM snapshot and post it to the snapshot endpoint
|
16
17
|
def self.snapshot(driver, name, options = {})
|
@@ -18,7 +19,11 @@ module Percy
|
|
18
19
|
|
19
20
|
begin
|
20
21
|
driver.execute_script(fetch_percy_dom)
|
21
|
-
dom_snapshot =
|
22
|
+
dom_snapshot = if responsive_snapshot_capture?(options)
|
23
|
+
capture_responsive_dom(driver, options)
|
24
|
+
else
|
25
|
+
get_serialized_dom(driver, options)
|
26
|
+
end
|
22
27
|
|
23
28
|
response = fetch('percy/snapshot',
|
24
29
|
name: name,
|
@@ -36,9 +41,96 @@ module Percy
|
|
36
41
|
body['data']
|
37
42
|
rescue StandardError => e
|
38
43
|
log("Could not take DOM snapshot '#{name}'")
|
44
|
+
log(e, 'debug')
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.get_browser_instance(driver)
|
49
|
+
if driver.is_a?(Capybara::Session)
|
50
|
+
return driver.driver.browser.manage
|
51
|
+
end
|
52
|
+
|
53
|
+
driver.manage
|
54
|
+
end
|
55
|
+
|
56
|
+
def self.get_serialized_dom(driver, options)
|
57
|
+
dom_snapshot = driver.execute_script("return PercyDOM.serialize(#{options.to_json})")
|
58
|
+
|
59
|
+
dom_snapshot['cookies'] = get_browser_instance(driver).all_cookies
|
60
|
+
dom_snapshot
|
61
|
+
end
|
62
|
+
|
63
|
+
def self.get_widths_for_multi_dom(options)
|
64
|
+
user_passed_widths = options[:widths] || []
|
65
|
+
|
66
|
+
# Deep copy mobile widths otherwise it will get overridden
|
67
|
+
all_widths = @eligible_widths['mobile']&.dup || []
|
68
|
+
if user_passed_widths.any?
|
69
|
+
all_widths.concat(user_passed_widths)
|
70
|
+
else
|
71
|
+
all_widths.concat(@eligible_widths['config'] || [])
|
72
|
+
end
|
73
|
+
|
74
|
+
all_widths.uniq
|
75
|
+
end
|
76
|
+
|
77
|
+
def self.change_window_dimension_and_wait(driver, width, height, resize_count)
|
78
|
+
begin
|
79
|
+
if driver.capabilities.browser_name == 'chrome' && driver.respond_to?(:execute_cdp)
|
80
|
+
driver.execute_cdp('Emulation.setDeviceMetricsOverride', {
|
81
|
+
height: height, width: width, deviceScaleFactor: 1, mobile: false,
|
82
|
+
},)
|
83
|
+
else
|
84
|
+
get_browser_instance(driver).window.resize_to(width, height)
|
85
|
+
end
|
86
|
+
rescue StandardError => e
|
87
|
+
log("Resizing using cdp failed, falling back to driver for width #{width} #{e}", 'debug')
|
88
|
+
get_browser_instance(driver).window.resize_to(width, height)
|
89
|
+
end
|
90
|
+
|
91
|
+
begin
|
92
|
+
wait = Selenium::WebDriver::Wait.new(timeout: 1)
|
93
|
+
wait.until { driver.execute_script('return window.resizeCount') == resize_count }
|
94
|
+
rescue Selenium::WebDriver::Error::TimeoutError
|
95
|
+
log("Timed out waiting for window resize event for width #{width}", 'debug')
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def self.capture_responsive_dom(driver, options)
|
100
|
+
widths = get_widths_for_multi_dom(options)
|
101
|
+
dom_snapshots = []
|
102
|
+
window_size = get_browser_instance(driver).window.size
|
103
|
+
current_width = window_size.width
|
104
|
+
current_height = window_size.height
|
105
|
+
last_window_width = current_width
|
106
|
+
resize_count = 0
|
107
|
+
driver.execute_script('PercyDOM.waitForResize()')
|
108
|
+
|
109
|
+
widths.each do |width|
|
110
|
+
if last_window_width != width
|
111
|
+
resize_count += 1
|
112
|
+
change_window_dimension_and_wait(driver, width, current_height, resize_count)
|
113
|
+
last_window_width = width
|
114
|
+
end
|
39
115
|
|
40
|
-
if
|
116
|
+
sleep(RESONSIVE_CAPTURE_SLEEP_TIME.to_i) if defined?(RESONSIVE_CAPTURE_SLEEP_TIME)
|
117
|
+
|
118
|
+
dom_snapshot = get_serialized_dom(driver, options)
|
119
|
+
dom_snapshot['width'] = width
|
120
|
+
dom_snapshots << dom_snapshot
|
41
121
|
end
|
122
|
+
|
123
|
+
change_window_dimension_and_wait(driver, current_width, current_height, resize_count + 1)
|
124
|
+
dom_snapshots
|
125
|
+
end
|
126
|
+
|
127
|
+
def self.responsive_snapshot_capture?(options)
|
128
|
+
# Don't run responsive snapshot capture when defer uploads is enabled
|
129
|
+
return false if @cli_config&.dig('percy', 'deferUploads')
|
130
|
+
|
131
|
+
options[:responsive_snapshot_capture] ||
|
132
|
+
options[:responsiveSnapshotCapture] ||
|
133
|
+
@cli_config&.dig('snapshot', 'responsiveSnapshotCapture')
|
42
134
|
end
|
43
135
|
|
44
136
|
# Determine if the Percy server is running, caching the result so it is only checked once
|
@@ -53,7 +145,7 @@ module Percy
|
|
53
145
|
log('You may be using @percy/agent ' \
|
54
146
|
'which is no longer supported by this SDK. ' \
|
55
147
|
'Please uninstall @percy/agent and install @percy/cli instead. ' \
|
56
|
-
'https://
|
148
|
+
'https://www.browserstack.com/docs/percy/migration/migrate-to-cli')
|
57
149
|
@percy_enabled = false
|
58
150
|
return false
|
59
151
|
end
|
@@ -64,12 +156,14 @@ module Percy
|
|
64
156
|
return false
|
65
157
|
end
|
66
158
|
|
159
|
+
response_body = JSON.parse(response.body)
|
160
|
+
@eligible_widths = response_body['widths']
|
161
|
+
@cli_config = response_body['config']
|
67
162
|
@percy_enabled = true
|
68
163
|
true
|
69
164
|
rescue StandardError => e
|
70
165
|
log('Percy is not running, disabling snapshots')
|
71
|
-
|
72
|
-
if PERCY_DEBUG then log(e) end
|
166
|
+
log(e, 'debug')
|
73
167
|
@percy_enabled = false
|
74
168
|
false
|
75
169
|
end
|
@@ -83,8 +177,19 @@ module Percy
|
|
83
177
|
@percy_dom = response.body
|
84
178
|
end
|
85
179
|
|
86
|
-
def self.log(msg)
|
87
|
-
|
180
|
+
def self.log(msg, lvl = 'info')
|
181
|
+
msg = "#{LABEL} #{msg}"
|
182
|
+
begin
|
183
|
+
fetch('percy/log', {message: msg, level: lvl})
|
184
|
+
rescue StandardError => e
|
185
|
+
if PERCY_DEBUG
|
186
|
+
puts "Sending log to CLI Failed #{e}"
|
187
|
+
end
|
188
|
+
ensure
|
189
|
+
if lvl != 'debug' || PERCY_DEBUG
|
190
|
+
puts msg
|
191
|
+
end
|
192
|
+
end
|
88
193
|
end
|
89
194
|
|
90
195
|
# Make an HTTP request (GET,POST) using Ruby's Net::HTTP. If `data` is present,
|
@@ -112,5 +217,7 @@ module Percy
|
|
112
217
|
def self._clear_cache!
|
113
218
|
@percy_dom = nil
|
114
219
|
@percy_enabled = nil
|
220
|
+
@eligible_widths = nil
|
221
|
+
@cli_config = nil
|
115
222
|
end
|
116
223
|
end
|
data/lib/version.rb
CHANGED
data/package.json
CHANGED
@@ -1,10 +1,9 @@
|
|
1
1
|
{
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
}
|
2
|
+
"private": true,
|
3
|
+
"scripts": {
|
4
|
+
"test": "percy exec --testing -- bundle exec rspec"
|
5
|
+
},
|
6
|
+
"devDependencies": {
|
7
|
+
"@percy/cli": "^1.29.5-beta.0"
|
9
8
|
}
|
10
|
-
|
9
|
+
}
|
@@ -1,7 +1,23 @@
|
|
1
1
|
# rubocop:disable RSpec/MultipleDescribes
|
2
2
|
RSpec.describe Percy, type: :feature do
|
3
|
+
dom_string = "<html><head><title>I am a page</title></head><body>Snapshot me\n</body></html>"
|
4
|
+
fetch_script_string = 'window.PercyDOM = {' \
|
5
|
+
'serialize: () => {' \
|
6
|
+
'return {' \
|
7
|
+
'html: document.documentElement.outerHTML,' \
|
8
|
+
'cookies: ""' \
|
9
|
+
'}' \
|
10
|
+
'},' \
|
11
|
+
'waitForResize: () => {' \
|
12
|
+
'if(!window.resizeCount) {' \
|
13
|
+
'window.addEventListener(\'resize\', () => window.resizeCount++)' \
|
14
|
+
'}' \
|
15
|
+
'window.resizeCount = 0;' \
|
16
|
+
'}};'
|
17
|
+
|
3
18
|
before(:each) do
|
4
19
|
WebMock.disable_net_connect!(allow: '127.0.0.1', disallow: 'localhost')
|
20
|
+
stub_request(:post, 'http://localhost:5338/percy/log').to_raise(StandardError)
|
5
21
|
Percy._clear_cache!
|
6
22
|
end
|
7
23
|
|
@@ -23,7 +39,7 @@ RSpec.describe Percy, type: :feature do
|
|
23
39
|
"#{Percy::LABEL} You may be using @percy/agent which" \
|
24
40
|
' is no longer supported by this SDK. Please uninstall' \
|
25
41
|
' @percy/agent and install @percy/cli instead.' \
|
26
|
-
" https://
|
42
|
+
" https://www.browserstack.com/docs/percy/migration/migrate-to-cli\n",
|
27
43
|
).to_stdout
|
28
44
|
end
|
29
45
|
|
@@ -59,12 +75,13 @@ RSpec.describe Percy, type: :feature do
|
|
59
75
|
|
60
76
|
it 'logs an error when sending a snapshot fails' do
|
61
77
|
stub_request(:get, "#{Percy::PERCY_SERVER_ADDRESS}/percy/healthcheck")
|
62
|
-
.to_return(status: 200, body: '
|
78
|
+
.to_return(status: 200, body: '{"success": "true" }',
|
79
|
+
headers: {'x-percy-core-version': '1.0.0'},)
|
63
80
|
|
64
81
|
stub_request(:get, "#{Percy::PERCY_SERVER_ADDRESS}/percy/dom.js")
|
65
82
|
.to_return(
|
66
83
|
status: 200,
|
67
|
-
body:
|
84
|
+
body: fetch_script_string,
|
68
85
|
headers: {},
|
69
86
|
)
|
70
87
|
|
@@ -77,12 +94,14 @@ RSpec.describe Percy, type: :feature do
|
|
77
94
|
|
78
95
|
it 'sends snapshots to the local server' do
|
79
96
|
stub_request(:get, "#{Percy::PERCY_SERVER_ADDRESS}/percy/healthcheck")
|
80
|
-
.to_return(status: 200, body: '', headers: {
|
97
|
+
.to_return(status: 200, body: '{"success": "true" }', headers: {
|
98
|
+
'x-percy-core-version': '1.0.0',
|
99
|
+
},)
|
81
100
|
|
82
101
|
stub_request(:get, "#{Percy::PERCY_SERVER_ADDRESS}/percy/dom.js")
|
83
102
|
.to_return(
|
84
103
|
status: 200,
|
85
|
-
body:
|
104
|
+
body: fetch_script_string,
|
86
105
|
headers: {},
|
87
106
|
)
|
88
107
|
|
@@ -98,7 +117,7 @@ RSpec.describe Percy, type: :feature do
|
|
98
117
|
name: 'Name',
|
99
118
|
url: 'http://127.0.0.1:3003/index.html',
|
100
119
|
dom_snapshot:
|
101
|
-
"
|
120
|
+
{"cookies": [], "html": dom_string},
|
102
121
|
client_info: "percy-selenium-ruby/#{Percy::VERSION}",
|
103
122
|
environment_info: "selenium/#{Selenium::WebDriver::VERSION} ruby/#{RUBY_VERSION}",
|
104
123
|
widths: [944],
|
@@ -108,14 +127,106 @@ RSpec.describe Percy, type: :feature do
|
|
108
127
|
expect(data).to eq(nil)
|
109
128
|
end
|
110
129
|
|
130
|
+
it 'sends multiple dom snapshots to the local server' do
|
131
|
+
stub_request(:get, "#{Percy::PERCY_SERVER_ADDRESS}/percy/healthcheck").to_return(
|
132
|
+
status: 200,
|
133
|
+
body: '{"success": "true", "widths": { "mobile": [390], "config": [765, 1280]} }',
|
134
|
+
headers: {
|
135
|
+
'x-percy-core-version': '1.0.0',
|
136
|
+
'config': {}, 'widths': {'mobile': [375], 'config': [765, 1280]},
|
137
|
+
},
|
138
|
+
)
|
139
|
+
|
140
|
+
stub_request(:get, "#{Percy::PERCY_SERVER_ADDRESS}/percy/dom.js")
|
141
|
+
.to_return(
|
142
|
+
status: 200,
|
143
|
+
body: fetch_script_string,
|
144
|
+
headers: {},
|
145
|
+
)
|
146
|
+
|
147
|
+
stub_request(:post, 'http://localhost:5338/percy/snapshot')
|
148
|
+
.to_return(status: 200, body: '{"success": "true" }', headers: {})
|
149
|
+
|
150
|
+
visit 'index.html'
|
151
|
+
data = Percy.snapshot(page, 'Name', {responsive_snapshot_capture: true})
|
152
|
+
|
153
|
+
expect(WebMock).to have_requested(:post, "#{Percy::PERCY_SERVER_ADDRESS}/percy/snapshot")
|
154
|
+
.with(
|
155
|
+
body: {
|
156
|
+
name: 'Name',
|
157
|
+
url: 'http://127.0.0.1:3003/index.html',
|
158
|
+
dom_snapshot: [
|
159
|
+
{'cookies': [], 'html': dom_string, 'width': 390},
|
160
|
+
{'cookies': [], 'html': dom_string, 'width': 765},
|
161
|
+
{'cookies': [], 'html': dom_string, 'width': 1280},
|
162
|
+
],
|
163
|
+
client_info: "percy-selenium-ruby/#{Percy::VERSION}",
|
164
|
+
environment_info: "selenium/#{Selenium::WebDriver::VERSION} ruby/#{RUBY_VERSION}",
|
165
|
+
responsive_snapshot_capture: true,
|
166
|
+
}.to_json,
|
167
|
+
).once
|
168
|
+
|
169
|
+
expect(data).to eq(nil)
|
170
|
+
end
|
171
|
+
|
172
|
+
it 'sends multiple dom snapshots to the local server using selenium' do
|
173
|
+
stub_request(:get, "#{Percy::PERCY_SERVER_ADDRESS}/percy/healthcheck").to_return(
|
174
|
+
status: 200,
|
175
|
+
body: '{"success": "true", "widths": { "mobile": [390], "config": [765, 1280]} }',
|
176
|
+
headers: {
|
177
|
+
'x-percy-core-version': '1.0.0',
|
178
|
+
'config': {}, 'widths': {'mobile': [375], 'config': [765, 1280]},
|
179
|
+
},
|
180
|
+
)
|
181
|
+
|
182
|
+
stub_request(:get, "#{Percy::PERCY_SERVER_ADDRESS}/percy/dom.js")
|
183
|
+
.to_return(
|
184
|
+
status: 200,
|
185
|
+
body: fetch_script_string,
|
186
|
+
headers: {},
|
187
|
+
)
|
188
|
+
|
189
|
+
stub_request(:post, 'http://localhost:5338/percy/snapshot')
|
190
|
+
.to_return(status: 200, body: '{"success": "true" }', headers: {})
|
191
|
+
|
192
|
+
driver = Selenium::WebDriver.for :firefox
|
193
|
+
|
194
|
+
driver.navigate.to 'http://localhost:5338/test/snapshot'
|
195
|
+
driver.manage.add_cookie({name: 'cookie-name', value: 'cookie-value'})
|
196
|
+
data = Percy.snapshot(driver, 'Name', {responsive_snapshot_capture: true})
|
197
|
+
|
198
|
+
expected_cookie = {name: 'cookie-name', value: 'cookie-value', path: '/',
|
199
|
+
domain: 'localhost', "expires": nil, "same_site": 'Lax',
|
200
|
+
"http_only": false, "secure": false,}
|
201
|
+
expected_dom = '<html><head></head><body><p>Snapshot Me!</p></body></html>'
|
202
|
+
expect(WebMock).to have_requested(:post, "#{Percy::PERCY_SERVER_ADDRESS}/percy/snapshot")
|
203
|
+
.with(
|
204
|
+
body: {
|
205
|
+
name: 'Name',
|
206
|
+
url: 'http://localhost:5338/test/snapshot',
|
207
|
+
dom_snapshot: [
|
208
|
+
{'cookies': [expected_cookie], 'html': expected_dom, 'width': 390},
|
209
|
+
{'cookies': [expected_cookie], 'html': expected_dom, 'width': 765},
|
210
|
+
{'cookies': [expected_cookie], 'html': expected_dom, 'width': 1280},
|
211
|
+
],
|
212
|
+
client_info: "percy-selenium-ruby/#{Percy::VERSION}",
|
213
|
+
environment_info: "selenium/#{Selenium::WebDriver::VERSION} ruby/#{RUBY_VERSION}",
|
214
|
+
responsive_snapshot_capture: true,
|
215
|
+
}.to_json,
|
216
|
+
).once
|
217
|
+
|
218
|
+
expect(data).to eq(nil)
|
219
|
+
end
|
220
|
+
|
111
221
|
it 'sends snapshots for sync' do
|
112
222
|
stub_request(:get, "#{Percy::PERCY_SERVER_ADDRESS}/percy/healthcheck")
|
113
|
-
.to_return(status: 200, body: '
|
223
|
+
.to_return(status: 200, body: '{"success": "true" }',
|
224
|
+
headers: {'x-percy-core-version': '1.0.0'},)
|
114
225
|
|
115
226
|
stub_request(:get, "#{Percy::PERCY_SERVER_ADDRESS}/percy/dom.js")
|
116
227
|
.to_return(
|
117
228
|
status: 200,
|
118
|
-
body:
|
229
|
+
body: fetch_script_string,
|
119
230
|
headers: {},
|
120
231
|
)
|
121
232
|
|
@@ -131,10 +242,10 @@ RSpec.describe Percy, type: :feature do
|
|
131
242
|
name: 'Name',
|
132
243
|
url: 'http://127.0.0.1:3003/index.html',
|
133
244
|
dom_snapshot:
|
134
|
-
|
245
|
+
{'cookies' => [], 'html' => dom_string},
|
135
246
|
client_info: "percy-selenium-ruby/#{Percy::VERSION}",
|
136
247
|
environment_info: "selenium/#{Selenium::WebDriver::VERSION} ruby/#{RUBY_VERSION}",
|
137
|
-
|
248
|
+
sync: true,
|
138
249
|
}.to_json,
|
139
250
|
).once
|
140
251
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: percy-selenium
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.1.0.pre.beta.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Perceptual Inc.
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-10-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: selenium-webdriver
|
@@ -145,11 +145,11 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
145
145
|
version: 2.3.0
|
146
146
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
147
147
|
requirements:
|
148
|
-
- - "
|
148
|
+
- - ">"
|
149
149
|
- !ruby/object:Gem::Version
|
150
|
-
version:
|
150
|
+
version: 1.3.1
|
151
151
|
requirements: []
|
152
|
-
rubygems_version: 3.
|
152
|
+
rubygems_version: 3.4.19
|
153
153
|
signing_key:
|
154
154
|
specification_version: 4
|
155
155
|
summary: Percy visual testing for Ruby Selenium
|