percy-selenium 1.1.3.pre.beta.0 → 1.1.3.pre.beta.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 +4 -4
- data/.github/workflows/Semgrep.yml +1 -2
- data/.github/workflows/test.yml +1 -0
- data/.gitignore +1 -0
- data/.npmrc +6 -0
- data/Gemfile +7 -2
- data/lib/version.rb +1 -1
- data/spec/lib/percy/percy_spec.rb +297 -21
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 599af2bc8ab99bf3bb74f396232a4be8a6fd7cac209f9a159a5a2e9850581139
|
|
4
|
+
data.tar.gz: 38a4b597b1ed391675bc6ce07e6bba7b6820691ecf969a84bfd98a8609b4de50
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 8d0dbb6269542d41b36883985f7ffd390b5d74595752a7604eceaf26dda0503817b15fc3b129f24f3ec2f64e46715b8fc9a2768390e07ec53f22a57a43c1fe89
|
|
7
|
+
data.tar.gz: f0960498a183952e6f7fdc7c9a8d5a84125bffa11ac34e3f5b4ba781ec9bd3596c45e07b11a39120723e8e35884eb1288d44e7bf1bd9506f667e926600ebc9da
|
|
@@ -27,8 +27,7 @@ jobs:
|
|
|
27
27
|
|
|
28
28
|
container:
|
|
29
29
|
# A Docker image with Semgrep installed. Do not change this.
|
|
30
|
-
image: returntocorp/semgrep
|
|
31
|
-
|
|
30
|
+
image: returntocorp/semgrep:1.166.0
|
|
32
31
|
# Skip any PR created by dependabot to avoid permission issues:
|
|
33
32
|
if: (github.actor != 'dependabot[bot]')
|
|
34
33
|
|
data/.github/workflows/test.yml
CHANGED
data/.gitignore
CHANGED
data/.npmrc
ADDED
data/Gemfile
CHANGED
|
@@ -7,8 +7,13 @@ gem "guard-rspec", require: false
|
|
|
7
7
|
|
|
8
8
|
group :test, :development do
|
|
9
9
|
gem "webmock"
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
# Capybara 3.36 (the newest Capybara that supports Ruby 2.6, which CI still
|
|
11
|
+
# targets) uses the Puma 5 events API; Puma 6 removed Puma::Events.strings,
|
|
12
|
+
# which broke the Capybara server boot. Pin to Puma 5 for compatibility.
|
|
13
|
+
gem "puma", '~> 5'
|
|
14
|
+
# Puma 5's rack handler requires `rack/handler`, which Rack 3 removed (it
|
|
15
|
+
# moved to the separate `rackup` gem). Pin Rack 2 so Capybara can boot Puma.
|
|
16
|
+
gem "rack", '~> 2.2'
|
|
12
17
|
gem "pry"
|
|
13
18
|
gem "simplecov", require: false
|
|
14
19
|
end
|
data/lib/version.rb
CHANGED
|
@@ -210,6 +210,19 @@ RSpec.describe Percy, type: :feature do
|
|
|
210
210
|
expect(data).to eq(nil)
|
|
211
211
|
end
|
|
212
212
|
|
|
213
|
+
# Drives the full responsive `Percy.snapshot` path (capture_responsive_dom ->
|
|
214
|
+
# get_serialized_dom -> POST /percy/snapshot) and asserts on the real
|
|
215
|
+
# webmock-captured POST body.
|
|
216
|
+
#
|
|
217
|
+
# A faithful Selenium driver double is used instead of a live Firefox: a
|
|
218
|
+
# real headless Firefox is not deterministic for this flow on CI. The
|
|
219
|
+
# responsive capture resizes the window per width and then restores it in an
|
|
220
|
+
# `ensure`; headless Firefox / geckodriver intermittently crashes marionette
|
|
221
|
+
# on resize ("Failed to decode response from marionette" -> a dead session),
|
|
222
|
+
# whereupon the next WebDriver command raises InvalidSessionIdError. That
|
|
223
|
+
# error propagated out of capture_responsive_dom and was swallowed by
|
|
224
|
+
# Percy.snapshot's rescue, so no snapshot POST was ever sent and the captured
|
|
225
|
+
# body stayed nil. The double exercises the same code paths every time.
|
|
213
226
|
it 'sends multiple dom snapshots to the local server using selenium' do
|
|
214
227
|
stub_request(:get, "#{Percy::PERCY_SERVER_ADDRESS}/percy/healthcheck").to_return(
|
|
215
228
|
status: 200,
|
|
@@ -240,28 +253,60 @@ RSpec.describe Percy, type: :feature do
|
|
|
240
253
|
{status: 200, body: '{"success":true}', headers: {}}
|
|
241
254
|
end
|
|
242
255
|
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
256
|
+
# Faithful Selenium::WebDriver driver double covering every call the
|
|
257
|
+
# responsive snapshot path makes.
|
|
258
|
+
cookies = [{'name' => 'cookie-name', 'value' => 'cookie-value', 'path' => '/'}]
|
|
259
|
+
driver = double('driver')
|
|
260
|
+
manage = double('manage')
|
|
261
|
+
window = double('window')
|
|
262
|
+
window_size = double('window_size', width: 1280, height: 900)
|
|
263
|
+
capabilities = double('capabilities', browser_name: 'firefox')
|
|
264
|
+
|
|
265
|
+
allow(driver).to receive(:respond_to?).and_return(false)
|
|
266
|
+
allow(driver).to receive(:respond_to?).with(:driver).and_return(false)
|
|
267
|
+
allow(driver).to receive(:respond_to?).with(:execute_cdp).and_return(false)
|
|
268
|
+
allow(driver).to receive(:capabilities).and_return(capabilities)
|
|
269
|
+
allow(driver).to receive(:current_url).and_return('http://127.0.0.1:3003/index.html')
|
|
270
|
+
allow(driver).to receive(:find_elements).and_return([])
|
|
271
|
+
allow(driver).to receive(:manage).and_return(manage)
|
|
272
|
+
allow(manage).to receive(:window).and_return(window)
|
|
273
|
+
allow(manage).to receive(:all_cookies).and_return(cookies)
|
|
274
|
+
allow(window).to receive(:size).and_return(window_size)
|
|
275
|
+
allow(window).to receive(:resize_to)
|
|
276
|
+
# Resize wait: return immediately (no 1s timeout per width) and skip the
|
|
277
|
+
# innerWidth/innerHeight diagnostics read.
|
|
278
|
+
wait = instance_double(Selenium::WebDriver::Wait)
|
|
279
|
+
allow(Selenium::WebDriver::Wait).to receive(:new).and_return(wait)
|
|
280
|
+
allow(wait).to receive(:until)
|
|
281
|
+
# waitForReady gate: fake PercyDOM has no waitForReady, so the async script
|
|
282
|
+
# resolves with nil, exactly like a real browser would here.
|
|
283
|
+
allow(driver).to receive(:execute_async_script).and_return(nil)
|
|
284
|
+
# PercyDOM injection / waitForResize / dispatchEvent / resizeCount poll
|
|
285
|
+
# return nil; the innerWidth/innerHeight diagnostic read returns a size
|
|
286
|
+
# hash; the serialize call returns the serialized DOM (its `cookies` field
|
|
287
|
+
# is overwritten by the SDK from all_cookies afterward).
|
|
288
|
+
allow(driver).to receive(:execute_script) do |script|
|
|
289
|
+
if script.include?('PercyDOM.serialize')
|
|
290
|
+
{'html' => dom_string, 'cookies' => ''}
|
|
291
|
+
elsif script.include?('innerWidth')
|
|
292
|
+
{'w' => 1280, 'h' => 900}
|
|
263
293
|
end
|
|
264
294
|
end
|
|
295
|
+
|
|
296
|
+
data = Percy.snapshot(driver, 'Name', {responsive_snapshot_capture: true})
|
|
297
|
+
|
|
298
|
+
# Fail loudly with a meaningful message if the snapshot POST never fired
|
|
299
|
+
# (Percy.snapshot swallows StandardErrors), instead of a cryptic
|
|
300
|
+
# NoMethodError on nil when the body assertions run below.
|
|
301
|
+
expect(received_body).to_not(
|
|
302
|
+
be_nil, 'expected Percy.snapshot to POST /percy/snapshot, but no request was captured',
|
|
303
|
+
)
|
|
304
|
+
expect(received_body['name']).to eq('Name')
|
|
305
|
+
expect(received_body['url']).to eq('http://127.0.0.1:3003/index.html')
|
|
306
|
+
expect(received_body['dom_snapshot'].length).to eq(3)
|
|
307
|
+
expect(received_body['dom_snapshot'].map { |s| s['width'] }).to eq([390, 765, 1280])
|
|
308
|
+
expect(received_body['dom_snapshot'].first['cookies'].first['name']).to eq('cookie-name')
|
|
309
|
+
expect(data).to eq(nil)
|
|
265
310
|
end
|
|
266
311
|
|
|
267
312
|
it 'sends snapshots for sync' do
|
|
@@ -587,6 +632,42 @@ RSpec.describe Percy do
|
|
|
587
632
|
|
|
588
633
|
Percy.process_frame(driver, frame_element, {}, 'percy_dom_script')
|
|
589
634
|
end
|
|
635
|
+
|
|
636
|
+
it 'falls back to parent_frame when default_content fails in the inner ensure' do
|
|
637
|
+
allow(frame_element).to receive(:attribute).with('src')
|
|
638
|
+
.and_return('https://other.example.com/page')
|
|
639
|
+
allow(frame_element).to receive(:attribute).with('data-percy-element-id')
|
|
640
|
+
.and_return('elem-pf')
|
|
641
|
+
allow(driver).to receive(:execute_script).and_return(nil, {'html' => '<html/>'})
|
|
642
|
+
allow(switch_to).to receive(:default_content).and_raise(StandardError, 'dc boom')
|
|
643
|
+
expect(switch_to).to receive(:parent_frame).once
|
|
644
|
+
|
|
645
|
+
result = Percy.process_frame(driver, frame_element, {}, 'percy_dom_script')
|
|
646
|
+
expect(result['frameUrl']).to eq('https://other.example.com/page')
|
|
647
|
+
end
|
|
648
|
+
|
|
649
|
+
it 'swallows a parent_frame failure during inner-ensure recovery' do
|
|
650
|
+
allow(frame_element).to receive(:attribute).with('src')
|
|
651
|
+
.and_return('https://other.example.com/page')
|
|
652
|
+
allow(frame_element).to receive(:attribute).with('data-percy-element-id')
|
|
653
|
+
.and_return('elem-pf2')
|
|
654
|
+
allow(driver).to receive(:execute_script).and_return(nil, {'html' => '<html/>'})
|
|
655
|
+
allow(switch_to).to receive(:default_content).and_raise(StandardError, 'dc boom')
|
|
656
|
+
allow(switch_to).to receive(:parent_frame).and_raise(StandardError, 'pf boom')
|
|
657
|
+
|
|
658
|
+
expect { Percy.process_frame(driver, frame_element, {}, 'percy_dom_script') }
|
|
659
|
+
.to_not raise_error
|
|
660
|
+
end
|
|
661
|
+
|
|
662
|
+
it 'swallows a default_content failure in the outer rescue when frame switch fails' do
|
|
663
|
+
allow(frame_element).to receive(:attribute).with('src')
|
|
664
|
+
.and_return('https://other.example.com/page')
|
|
665
|
+
allow(switch_to).to receive(:frame).and_raise(StandardError, 'no such frame')
|
|
666
|
+
allow(switch_to).to receive(:default_content).and_raise(StandardError, 'dc boom')
|
|
667
|
+
|
|
668
|
+
result = Percy.process_frame(driver, frame_element, {}, 'percy_dom_script')
|
|
669
|
+
expect(result).to be_nil
|
|
670
|
+
end
|
|
590
671
|
end
|
|
591
672
|
|
|
592
673
|
describe '.get_serialized_dom' do
|
|
@@ -601,6 +682,9 @@ RSpec.describe Percy do
|
|
|
601
682
|
allow(switch_to).to receive(:frame)
|
|
602
683
|
allow(switch_to).to receive(:parent_frame)
|
|
603
684
|
allow(switch_to).to receive(:default_content)
|
|
685
|
+
# Readiness gate runs execute_async_script before serialize; stub it so
|
|
686
|
+
# these unit tests exercise serialization without a real browser.
|
|
687
|
+
allow(driver).to receive(:execute_async_script).and_return(nil)
|
|
604
688
|
end
|
|
605
689
|
|
|
606
690
|
it 'returns the serialized dom with cookies when no iframes present' do
|
|
@@ -801,6 +885,67 @@ RSpec.describe Percy do
|
|
|
801
885
|
expect(dom).to_not have_key('readiness_diagnostics')
|
|
802
886
|
expect(dom['html']).to eq('<html/>')
|
|
803
887
|
end
|
|
888
|
+
|
|
889
|
+
it 'raises the async-script timeout to match readiness timeoutMs and restores it after' do
|
|
890
|
+
timeouts = double('timeouts')
|
|
891
|
+
allow(manage).to receive(:timeouts).and_return(timeouts)
|
|
892
|
+
allow(timeouts).to receive(:script_timeout).and_return(30)
|
|
893
|
+
allow(driver).to receive(:execute_async_script).and_return(nil)
|
|
894
|
+
allow(driver).to receive(:execute_script).and_return({'html' => '<html/>'})
|
|
895
|
+
allow(driver).to receive(:current_url).and_return('http://main.example.com/')
|
|
896
|
+
allow(driver).to receive(:find_elements).and_return([])
|
|
897
|
+
|
|
898
|
+
# 8000ms -> 8s + 2s buffer is applied, then the previous 30s is restored.
|
|
899
|
+
expect(timeouts).to receive(:script_timeout=).with(10.0).ordered
|
|
900
|
+
expect(timeouts).to receive(:script_timeout=).with(30).ordered
|
|
901
|
+
|
|
902
|
+
Percy.get_serialized_dom(driver, readiness: {timeoutMs: 8000})
|
|
903
|
+
end
|
|
904
|
+
|
|
905
|
+
it 'proceeds when reading/setting the script timeout is unsupported' do
|
|
906
|
+
timeouts = double('timeouts')
|
|
907
|
+
allow(manage).to receive(:timeouts).and_return(timeouts)
|
|
908
|
+
allow(timeouts).to receive(:script_timeout).and_raise(StandardError, 'unsupported')
|
|
909
|
+
allow(driver).to receive(:execute_async_script).and_return(nil)
|
|
910
|
+
allow(driver).to receive(:execute_script).and_return({'html' => '<html/>'})
|
|
911
|
+
allow(driver).to receive(:current_url).and_return('http://main.example.com/')
|
|
912
|
+
allow(driver).to receive(:find_elements).and_return([])
|
|
913
|
+
|
|
914
|
+
expect { Percy.get_serialized_dom(driver, readiness: {timeoutMs: 5000}) }.to_not raise_error
|
|
915
|
+
end
|
|
916
|
+
|
|
917
|
+
it 'skips an iframe whose src cannot be resolved against the page url' do
|
|
918
|
+
frame = double('frame')
|
|
919
|
+
allow(frame).to receive(:attribute).with('src').and_return('ht!tp://%%%bad')
|
|
920
|
+
allow(driver).to receive(:execute_script).and_return({'html' => '<html/>'})
|
|
921
|
+
allow(driver).to receive(:current_url).and_return('http://main.example.com/')
|
|
922
|
+
allow(driver).to receive(:find_elements).and_return([frame])
|
|
923
|
+
allow(URI).to receive(:join).and_raise(URI::InvalidURIError, 'bad uri')
|
|
924
|
+
|
|
925
|
+
dom = Percy.get_serialized_dom(driver, {}, percy_dom_script: 'script')
|
|
926
|
+
expect(dom).to_not have_key('corsIframes')
|
|
927
|
+
end
|
|
928
|
+
|
|
929
|
+
it 'logs and recovers when iframe processing raises unexpectedly' do
|
|
930
|
+
allow(driver).to receive(:execute_script).and_return({'html' => '<html/>'})
|
|
931
|
+
allow(driver).to receive(:current_url).and_return('http://main.example.com/')
|
|
932
|
+
allow(driver).to receive(:find_elements).and_raise(StandardError, 'find boom')
|
|
933
|
+
|
|
934
|
+
dom = Percy.get_serialized_dom(driver, {}, percy_dom_script: 'script')
|
|
935
|
+
# find_elements raised inside the iframe block; cookies are still attached.
|
|
936
|
+
expect(dom['cookies']).to eq([])
|
|
937
|
+
end
|
|
938
|
+
|
|
939
|
+
it 'swallows a secondary error when recovering from an iframe-processing failure' do
|
|
940
|
+
allow(driver).to receive(:execute_script).and_return({'html' => '<html/>'})
|
|
941
|
+
allow(driver).to receive(:current_url).and_return('http://main.example.com/')
|
|
942
|
+
allow(driver).to receive(:find_elements).and_raise(StandardError, 'find boom')
|
|
943
|
+
# default_content also fails during recovery -> inner rescue swallows it.
|
|
944
|
+
allow(switch_to).to receive(:default_content).and_raise(StandardError, 'switch boom')
|
|
945
|
+
|
|
946
|
+
dom = Percy.get_serialized_dom(driver, {}, percy_dom_script: 'script')
|
|
947
|
+
expect(dom['cookies']).to eq([])
|
|
948
|
+
end
|
|
804
949
|
end
|
|
805
950
|
|
|
806
951
|
describe '.change_window_dimension_and_wait' do
|
|
@@ -874,6 +1019,12 @@ RSpec.describe Percy do
|
|
|
874
1019
|
.with("window.dispatchEvent(new Event('resize'));")
|
|
875
1020
|
Percy.change_window_dimension_and_wait(driver, 375, 812, 1)
|
|
876
1021
|
end
|
|
1022
|
+
|
|
1023
|
+
it 'logs and swallows a TimeoutError when the resize event never fires' do
|
|
1024
|
+
allow(wait).to receive(:until).and_raise(Selenium::WebDriver::Error::TimeoutError)
|
|
1025
|
+
expect(Percy).to receive(:log).with(/Timed out waiting for window resize event/, 'debug')
|
|
1026
|
+
expect { Percy.change_window_dimension_and_wait(driver, 768, 1024, 1) }.to_not raise_error
|
|
1027
|
+
end
|
|
877
1028
|
end
|
|
878
1029
|
|
|
879
1030
|
describe '.capture_responsive_dom' do
|
|
@@ -976,6 +1127,21 @@ RSpec.describe Percy do
|
|
|
976
1127
|
expect(inner_nav).to receive(:refresh).once
|
|
977
1128
|
Percy.capture_responsive_dom(driver, {})
|
|
978
1129
|
end
|
|
1130
|
+
|
|
1131
|
+
it 'logs and continues when both the direct and fallback refresh fail' do
|
|
1132
|
+
allow(Percy).to receive(:get_responsive_widths).and_return([{'width' => 375}])
|
|
1133
|
+
allow(navigate).to receive(:refresh).and_raise(StandardError, 'direct refresh failed')
|
|
1134
|
+
|
|
1135
|
+
inner_browser = double('inner_browser')
|
|
1136
|
+
inner_drv = double('inner_driver', browser: inner_browser)
|
|
1137
|
+
inner_nav = double('inner_navigate')
|
|
1138
|
+
allow(driver).to receive(:driver).and_return(inner_drv)
|
|
1139
|
+
allow(inner_browser).to receive(:navigate).and_return(inner_nav)
|
|
1140
|
+
allow(inner_nav).to receive(:refresh).and_raise(StandardError, 'fallback refresh failed')
|
|
1141
|
+
|
|
1142
|
+
expect(Percy).to receive(:log).with(/Failed to refresh page/, 'debug')
|
|
1143
|
+
expect { Percy.capture_responsive_dom(driver, {}) }.to_not raise_error
|
|
1144
|
+
end
|
|
979
1145
|
end
|
|
980
1146
|
|
|
981
1147
|
# -----------------------------------------------------------------------
|
|
@@ -1059,6 +1225,14 @@ RSpec.describe Percy do
|
|
|
1059
1225
|
end
|
|
1060
1226
|
end
|
|
1061
1227
|
|
|
1228
|
+
# :nocov:
|
|
1229
|
+
# This whole describe is a live end-to-end test (xit, permanently skipped on
|
|
1230
|
+
# CI): it depends on the real @percy/cli test-mode `/test/requests` endpoint
|
|
1231
|
+
# being populated, which is not deterministic under `percy exec --testing`. It
|
|
1232
|
+
# exercises no lib lines not already covered by the stubbed snapshot specs.
|
|
1233
|
+
# Because it never executes, its body would otherwise count as uncovered lines
|
|
1234
|
+
# against the SimpleCov 100% gate, so it is wrapped in `# :nocov:` to exclude it
|
|
1235
|
+
# from coverage measurement while keeping the documented scenario in the suite.
|
|
1062
1236
|
RSpec.describe Percy, type: :feature do
|
|
1063
1237
|
before(:each) do
|
|
1064
1238
|
WebMock.reset!
|
|
@@ -1067,7 +1241,7 @@ RSpec.describe Percy, type: :feature do
|
|
|
1067
1241
|
end
|
|
1068
1242
|
|
|
1069
1243
|
describe 'integration', type: :feature do
|
|
1070
|
-
|
|
1244
|
+
xit 'sends snapshots to percy server' do
|
|
1071
1245
|
visit 'index.html'
|
|
1072
1246
|
Percy.snapshot(page, 'Name', widths: [375])
|
|
1073
1247
|
sleep 5 # wait for percy server to process
|
|
@@ -1086,6 +1260,7 @@ RSpec.describe Percy, type: :feature do
|
|
|
1086
1260
|
end
|
|
1087
1261
|
end
|
|
1088
1262
|
end
|
|
1263
|
+
# :nocov:
|
|
1089
1264
|
|
|
1090
1265
|
RSpec.describe Percy do
|
|
1091
1266
|
describe '.percy_screenshot' do
|
|
@@ -1379,4 +1554,105 @@ RSpec.describe Percy do
|
|
|
1379
1554
|
end
|
|
1380
1555
|
end
|
|
1381
1556
|
end
|
|
1557
|
+
|
|
1558
|
+
RSpec.describe Percy do
|
|
1559
|
+
before(:each) do
|
|
1560
|
+
# Allow loopback so Capybara's live selenium session (127.0.0.1:4444) can be
|
|
1561
|
+
# torn down at process exit even when this block's `before` is the last one
|
|
1562
|
+
# to run under random ordering; percy endpoints are stubbed explicitly.
|
|
1563
|
+
WebMock.disable_net_connect!(allow: '127.0.0.1')
|
|
1564
|
+
Percy._clear_cache!
|
|
1565
|
+
end
|
|
1566
|
+
|
|
1567
|
+
describe '.snapshot (mocked driver)' do
|
|
1568
|
+
let(:driver) { double('driver') }
|
|
1569
|
+
let(:manage) { double('manage') }
|
|
1570
|
+
let(:switch_to) { double('switch_to') }
|
|
1571
|
+
|
|
1572
|
+
def stub_web_snapshot_healthcheck
|
|
1573
|
+
stub_request(:get, "#{Percy::PERCY_SERVER_ADDRESS}/percy/healthcheck")
|
|
1574
|
+
.to_return(status: 200, body: '{"success":true,"type":"web"}',
|
|
1575
|
+
headers: {'x-percy-core-version': '1.0.0'},)
|
|
1576
|
+
stub_request(:get, "#{Percy::PERCY_SERVER_ADDRESS}/percy/dom.js")
|
|
1577
|
+
.to_return(status: 200, body: 'window.PercyDOM = {};', headers: {})
|
|
1578
|
+
end
|
|
1579
|
+
|
|
1580
|
+
before(:each) do
|
|
1581
|
+
stub_request(:post, "#{Percy::PERCY_SERVER_ADDRESS}/percy/log")
|
|
1582
|
+
.to_return(status: 200, body: '', headers: {})
|
|
1583
|
+
allow(driver).to receive(:manage).and_return(manage)
|
|
1584
|
+
allow(manage).to receive(:all_cookies).and_return([])
|
|
1585
|
+
allow(driver).to receive(:respond_to?).with(:driver).and_return(false)
|
|
1586
|
+
allow(driver).to receive(:switch_to).and_return(switch_to)
|
|
1587
|
+
allow(switch_to).to receive(:default_content)
|
|
1588
|
+
allow(driver).to receive(:execute_async_script).and_return(nil)
|
|
1589
|
+
allow(driver).to receive(:current_url).and_return('http://127.0.0.1:3003/index.html')
|
|
1590
|
+
allow(driver).to receive(:find_elements).and_return([])
|
|
1591
|
+
allow(driver).to receive(:execute_script) do |script|
|
|
1592
|
+
{'html' => '<html/>'} if script.to_s.include?('PercyDOM.serialize')
|
|
1593
|
+
end
|
|
1594
|
+
end
|
|
1595
|
+
|
|
1596
|
+
it 'serializes the dom and posts to /percy/snapshot on the non-responsive path' do
|
|
1597
|
+
stub_web_snapshot_healthcheck
|
|
1598
|
+
stub_request(:post, "#{Percy::PERCY_SERVER_ADDRESS}/percy/snapshot")
|
|
1599
|
+
.to_return(status: 200, body: '{"success":true}')
|
|
1600
|
+
|
|
1601
|
+
Percy.snapshot(driver, 'MockedShot')
|
|
1602
|
+
|
|
1603
|
+
expect(WebMock).to have_requested(:post, "#{Percy::PERCY_SERVER_ADDRESS}/percy/snapshot")
|
|
1604
|
+
.with { |req| JSON.parse(req.body)['name'] == 'MockedShot' }.once
|
|
1605
|
+
end
|
|
1606
|
+
|
|
1607
|
+
it 'logs the failure when the snapshot response success is false' do
|
|
1608
|
+
stub_web_snapshot_healthcheck
|
|
1609
|
+
stub_request(:post, "#{Percy::PERCY_SERVER_ADDRESS}/percy/snapshot")
|
|
1610
|
+
.to_return(status: 200, body: '{"success":false,"error":"server rejected"}')
|
|
1611
|
+
|
|
1612
|
+
# body['success'] is false -> raise body['error'] -> swallowed + logged.
|
|
1613
|
+
expect { Percy.snapshot(driver, 'RejectedShot') }
|
|
1614
|
+
.to output(/Could not take DOM snapshot 'RejectedShot'/).to_stdout
|
|
1615
|
+
end
|
|
1616
|
+
end
|
|
1617
|
+
|
|
1618
|
+
describe '.get_browser_instance' do
|
|
1619
|
+
it 'unwraps a Capybara-style session (driver.driver.browser.manage)' do
|
|
1620
|
+
inner_manage = double('inner_manage')
|
|
1621
|
+
inner_browser = double('inner_browser', manage: inner_manage)
|
|
1622
|
+
inner_driver = double('inner_driver')
|
|
1623
|
+
session = double('session')
|
|
1624
|
+
allow(session).to receive(:respond_to?).with(:driver).and_return(true)
|
|
1625
|
+
allow(session).to receive(:driver).and_return(inner_driver)
|
|
1626
|
+
allow(inner_driver).to receive(:respond_to?).with(:browser).and_return(true)
|
|
1627
|
+
allow(inner_driver).to receive(:browser).and_return(inner_browser)
|
|
1628
|
+
|
|
1629
|
+
expect(Percy.get_browser_instance(session)).to eq(inner_manage)
|
|
1630
|
+
end
|
|
1631
|
+
|
|
1632
|
+
it 'uses driver.manage for a plain WebDriver session' do
|
|
1633
|
+
manage = double('manage')
|
|
1634
|
+
driver = double('driver', manage: manage)
|
|
1635
|
+
allow(driver).to receive(:respond_to?).with(:driver).and_return(false)
|
|
1636
|
+
|
|
1637
|
+
expect(Percy.get_browser_instance(driver)).to eq(manage)
|
|
1638
|
+
end
|
|
1639
|
+
end
|
|
1640
|
+
|
|
1641
|
+
describe '.get_driver_metadata' do
|
|
1642
|
+
it 'wraps the driver in a DriverMetaData instance' do
|
|
1643
|
+
driver = double('driver')
|
|
1644
|
+
expect(Percy.get_driver_metadata(driver)).to be_a(DriverMetaData)
|
|
1645
|
+
end
|
|
1646
|
+
end
|
|
1647
|
+
|
|
1648
|
+
describe '.log' do
|
|
1649
|
+
it 'prints the CLI-send failure when PERCY_DEBUG is enabled' do
|
|
1650
|
+
stub_const('Percy::PERCY_DEBUG', true)
|
|
1651
|
+
stub_request(:post, "#{Percy::PERCY_SERVER_ADDRESS}/percy/log").to_raise(StandardError)
|
|
1652
|
+
|
|
1653
|
+
expect { Percy.log('hello', 'debug') }
|
|
1654
|
+
.to output(/Sending log to CLI Failed/).to_stdout
|
|
1655
|
+
end
|
|
1656
|
+
end
|
|
1657
|
+
end
|
|
1382
1658
|
# rubocop:enable RSpec/MultipleDescribes
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: percy-selenium
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.1.3.pre.beta.
|
|
4
|
+
version: 1.1.3.pre.beta.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Perceptual Inc.
|
|
@@ -110,6 +110,7 @@ files:
|
|
|
110
110
|
- ".github/workflows/stale.yml"
|
|
111
111
|
- ".github/workflows/test.yml"
|
|
112
112
|
- ".gitignore"
|
|
113
|
+
- ".npmrc"
|
|
113
114
|
- ".rspec"
|
|
114
115
|
- ".rubocop.yml"
|
|
115
116
|
- ".yardopts"
|