percy-selenium 1.1.3.pre.beta.1 → 1.1.4.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/test.yml +13 -4
- data/lib/percy.rb +32 -3
- data/lib/version.rb +1 -1
- data/spec/lib/percy/percy_spec.rb +79 -0
- data/spec/spec_helper.rb +29 -2
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 964b34504d72f46df90ac38f0c122efb350e6a46673899855cbf668523d93349
|
|
4
|
+
data.tar.gz: 7f2cbab4d9f0228ce5b29d24601a04dea8f11dfb2a359dea52eddfe741463c85
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e4914dc15a922d03df46fa24a68576d89e784314d9e40c55b1dd3f3e2b32a746a94eca1e55c7f54a204046a3a98c13954d3e29200ebfbae8fe8f49c7e9d5fc74
|
|
7
|
+
data.tar.gz: b562acce5038bbaf57e50767d6c9a1cf10e19beabe46f97686576e427071a37492ea0b90b9936dec6ad7c9e5ee9c545283ae766744d79290984c82c17cb664d5
|
data/.github/workflows/test.yml
CHANGED
|
@@ -51,16 +51,25 @@ jobs:
|
|
|
51
51
|
- run: yarn
|
|
52
52
|
- name: Set up @percy/cli from git
|
|
53
53
|
if: ${{ github.event_name == 'workflow_dispatch' }}
|
|
54
|
+
env:
|
|
55
|
+
BRANCH: ${{ github.event.inputs.branch }}
|
|
54
56
|
run: |
|
|
55
57
|
cd /tmp
|
|
56
|
-
git clone --branch $
|
|
58
|
+
git clone --branch "$BRANCH" --depth 1 https://github.com/percy/cli
|
|
57
59
|
cd cli
|
|
58
60
|
PERCY_PACKAGES=`find packages -mindepth 1 -maxdepth 1 -type d | sed -e 's/packages/@percy/g' | tr '\n' ' '`
|
|
59
61
|
git log -1
|
|
60
62
|
yarn
|
|
61
63
|
yarn build
|
|
62
64
|
yarn global:link
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
65
|
+
# Expose the freshly built `percy` on PATH. yarn link symlinks the
|
|
66
|
+
# package but not its bin, so `npx percy` would miss it and download
|
|
67
|
+
# the unrelated public `percy`. Link is best-effort; PATH is what
|
|
68
|
+
# makes percy resolvable.
|
|
69
|
+
echo "$(yarn global bin)" >> "$GITHUB_PATH"
|
|
70
|
+
export PATH="$(yarn global bin):$PATH"
|
|
71
|
+
cd ${{ github.workspace }}
|
|
72
|
+
yarn remove @percy/cli >/dev/null 2>&1 || true
|
|
73
|
+
yarn link `echo $PERCY_PACKAGES` >/dev/null 2>&1 || true
|
|
74
|
+
percy --version
|
|
66
75
|
- run: npx percy exec --testing -- bundle exec rspec
|
data/lib/percy.rb
CHANGED
|
@@ -66,6 +66,25 @@ module Percy
|
|
|
66
66
|
region
|
|
67
67
|
end
|
|
68
68
|
|
|
69
|
+
# Recursively convert all Hash keys (at every nesting level) to symbols so
|
|
70
|
+
# config (string keys from JSON) and per-call options (symbol keys) merge on
|
|
71
|
+
# consistent keys. Arrays are walked; scalars are returned as-is.
|
|
72
|
+
def self.deep_symbolize(obj)
|
|
73
|
+
case obj
|
|
74
|
+
when Hash then obj.each_with_object({}) { |(k, v), h| h[k.to_sym] = deep_symbolize(v) }
|
|
75
|
+
when Array then obj.map { |e| deep_symbolize(e) }
|
|
76
|
+
else obj
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# Deep-merge `override` onto `base`: nested Hashes merge recursively, while
|
|
81
|
+
# arrays and scalars from `override` replace those in `base`.
|
|
82
|
+
def self.deep_merge_options(base, override)
|
|
83
|
+
base.merge(override) do |_key, old_val, new_val|
|
|
84
|
+
old_val.is_a?(Hash) && new_val.is_a?(Hash) ? deep_merge_options(old_val, new_val) : new_val
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
69
88
|
def self.snapshot(driver, name, options = {})
|
|
70
89
|
return unless percy_enabled?
|
|
71
90
|
|
|
@@ -79,10 +98,20 @@ module Percy
|
|
|
79
98
|
begin
|
|
80
99
|
percy_dom_script = fetch_percy_dom
|
|
81
100
|
driver.execute_script(percy_dom_script)
|
|
82
|
-
|
|
83
|
-
|
|
101
|
+
|
|
102
|
+
# Merge .percy.yml config options with snapshot options (snapshot options take priority)
|
|
103
|
+
config_options = @cli_config&.dig('snapshot') || {}
|
|
104
|
+
# Config keys are strings (JSON parse); per-call options use symbols, as
|
|
105
|
+
# do downstream consumers (responsive_snapshot_capture?, capture_responsive_dom).
|
|
106
|
+
# Deep-symbolize both sides so nested keys are consistent, then deep-merge
|
|
107
|
+
# so nested Hashes merge recursively (per-call wins at leaves; arrays/scalars
|
|
108
|
+
# replace) instead of a shallow top-level overwrite dropping config siblings.
|
|
109
|
+
merged_options = deep_merge_options(deep_symbolize(config_options), deep_symbolize(options))
|
|
110
|
+
|
|
111
|
+
dom_snapshot = if responsive_snapshot_capture?(merged_options)
|
|
112
|
+
capture_responsive_dom(driver, merged_options, percy_dom_script: percy_dom_script)
|
|
84
113
|
else
|
|
85
|
-
get_serialized_dom(driver,
|
|
114
|
+
get_serialized_dom(driver, merged_options, percy_dom_script: percy_dom_script)
|
|
86
115
|
end
|
|
87
116
|
|
|
88
117
|
# Strip `readiness` before POSTing -- SDK-local config that the CLI
|
data/lib/version.rb
CHANGED
|
@@ -342,6 +342,85 @@ RSpec.describe Percy, type: :feature do
|
|
|
342
342
|
|
|
343
343
|
expect(data).to eq('sync_data')
|
|
344
344
|
end
|
|
345
|
+
|
|
346
|
+
it 'merges .percy.yml config with per-snapshot options (per-call wins)' do
|
|
347
|
+
# Healthcheck returns a config whose `snapshot` block carries a
|
|
348
|
+
# config-only key (enableJavaScript) and a percyCSS value that the
|
|
349
|
+
# per-snapshot call will override.
|
|
350
|
+
stub_request(:get, "#{Percy::PERCY_SERVER_ADDRESS}/percy/healthcheck")
|
|
351
|
+
.to_return(
|
|
352
|
+
status: 200,
|
|
353
|
+
body: {
|
|
354
|
+
success: true,
|
|
355
|
+
config: {'snapshot' => {'enableJavaScript' => true, 'percyCSS' => 'FROM_CONFIG'}},
|
|
356
|
+
}.to_json,
|
|
357
|
+
headers: {'x-percy-core-version': '1.0.0'},
|
|
358
|
+
)
|
|
359
|
+
|
|
360
|
+
stub_request(:get, "#{Percy::PERCY_SERVER_ADDRESS}/percy/dom.js")
|
|
361
|
+
.to_return(status: 200, body: fetch_script_string, headers: {})
|
|
362
|
+
|
|
363
|
+
stub_request(:post, 'http://localhost:5338/percy/snapshot')
|
|
364
|
+
.to_return(status: 200, body: '{"success":true}', headers: {})
|
|
365
|
+
|
|
366
|
+
# Capture the argument passed to PercyDOM.serialize so we can assert how
|
|
367
|
+
# config and per-call options were merged before serialization.
|
|
368
|
+
captured_serialize_call = nil
|
|
369
|
+
allow(page).to receive(:execute_script).and_wrap_original do |original, script, *args|
|
|
370
|
+
captured_serialize_call = script if script.to_s.include?('PercyDOM.serialize')
|
|
371
|
+
original.call(script, *args)
|
|
372
|
+
end
|
|
373
|
+
|
|
374
|
+
visit 'index.html'
|
|
375
|
+
Percy.snapshot(page, 'Name', percyCSS: 'FROM_CALL')
|
|
376
|
+
|
|
377
|
+
expect(captured_serialize_call).to_not be_nil
|
|
378
|
+
serialized = JSON.parse(captured_serialize_call[/PercyDOM\.serialize\((.*)\)/m, 1])
|
|
379
|
+
# Config-only key still reaches serialize...
|
|
380
|
+
expect(serialized['enableJavaScript']).to eq(true)
|
|
381
|
+
# ...and the per-call option wins over the config value.
|
|
382
|
+
expect(serialized['percyCSS']).to eq('FROM_CALL')
|
|
383
|
+
end
|
|
384
|
+
|
|
385
|
+
it 'deep-merges nested config and per-snapshot options (sibling kept, leaf overridden)' do
|
|
386
|
+
# Config `snapshot` block carries a nested `discovery` hash; the per-call
|
|
387
|
+
# discovery only overrides one leaf, so the sibling key must survive.
|
|
388
|
+
stub_request(:get, "#{Percy::PERCY_SERVER_ADDRESS}/percy/healthcheck")
|
|
389
|
+
.to_return(
|
|
390
|
+
status: 200,
|
|
391
|
+
body: {
|
|
392
|
+
success: true,
|
|
393
|
+
config: {
|
|
394
|
+
'snapshot' => {
|
|
395
|
+
'discovery' => {'networkIdleTimeout' => 50, 'disableCache' => false},
|
|
396
|
+
},
|
|
397
|
+
},
|
|
398
|
+
}.to_json,
|
|
399
|
+
headers: {'x-percy-core-version': '1.0.0'},
|
|
400
|
+
)
|
|
401
|
+
|
|
402
|
+
stub_request(:get, "#{Percy::PERCY_SERVER_ADDRESS}/percy/dom.js")
|
|
403
|
+
.to_return(status: 200, body: fetch_script_string, headers: {})
|
|
404
|
+
|
|
405
|
+
stub_request(:post, 'http://localhost:5338/percy/snapshot')
|
|
406
|
+
.to_return(status: 200, body: '{"success":true}', headers: {})
|
|
407
|
+
|
|
408
|
+
captured_serialize_call = nil
|
|
409
|
+
allow(page).to receive(:execute_script).and_wrap_original do |original, script, *args|
|
|
410
|
+
captured_serialize_call = script if script.to_s.include?('PercyDOM.serialize')
|
|
411
|
+
original.call(script, *args)
|
|
412
|
+
end
|
|
413
|
+
|
|
414
|
+
visit 'index.html'
|
|
415
|
+
Percy.snapshot(page, 'Name', discovery: {disableCache: true})
|
|
416
|
+
|
|
417
|
+
expect(captured_serialize_call).to_not be_nil
|
|
418
|
+
serialized = JSON.parse(captured_serialize_call[/PercyDOM\.serialize\((.*)\)/m, 1])
|
|
419
|
+
# Sibling from config survives; per-call leaf overrides the config value.
|
|
420
|
+
expect(serialized['discovery']).to eq(
|
|
421
|
+
'networkIdleTimeout' => 50, 'disableCache' => true,
|
|
422
|
+
)
|
|
423
|
+
end
|
|
345
424
|
end
|
|
346
425
|
end
|
|
347
426
|
|
data/spec/spec_helper.rb
CHANGED
|
@@ -35,8 +35,35 @@ RSpec.configure do |config|
|
|
|
35
35
|
Kernel.srand config.seed
|
|
36
36
|
|
|
37
37
|
# See https://github.com/teamcapybara/capybara#selecting-the-driver for other options
|
|
38
|
-
|
|
39
|
-
|
|
38
|
+
# Default to Firefox headless (matches CI), but when a Chromium/Chrome binary is
|
|
39
|
+
# provided via CHROME_BIN (e.g. the containerised e2e image), register and use a
|
|
40
|
+
# headless Chrome driver pointing at it instead.
|
|
41
|
+
if ENV['CHROME_BIN'] && !ENV['CHROME_BIN'].empty?
|
|
42
|
+
Capybara.register_driver :selenium_chrome_headless_bin do |app|
|
|
43
|
+
options = Selenium::WebDriver::Chrome::Options.new
|
|
44
|
+
options.binary = ENV['CHROME_BIN']
|
|
45
|
+
options.add_argument('--headless=new')
|
|
46
|
+
options.add_argument('--no-sandbox')
|
|
47
|
+
options.add_argument('--disable-gpu')
|
|
48
|
+
options.add_argument('--disable-dev-shm-usage')
|
|
49
|
+
Capybara::Selenium::Driver.new(app, browser: :chrome, options: options)
|
|
50
|
+
end
|
|
51
|
+
Capybara.default_driver = :selenium_chrome_headless_bin
|
|
52
|
+
Capybara.javascript_driver = :selenium_chrome_headless_bin
|
|
53
|
+
else
|
|
54
|
+
Capybara.default_driver = :selenium_headless
|
|
55
|
+
Capybara.javascript_driver = :selenium_headless
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# Capybara's built-in :selenium_headless driver still passes `options:` to
|
|
59
|
+
# driver init, which newer selenium-webdriver logs as a [DEPRECATION]
|
|
60
|
+
# [:browser_options] warning on first use. The suite asserts exact stdout
|
|
61
|
+
# via `output(...).to_stdout`, so any example that first boots the driver
|
|
62
|
+
# inside such a block fails on that extra line (seed-dependent). Silence
|
|
63
|
+
# just that deprecation id.
|
|
64
|
+
if Selenium::WebDriver.logger.respond_to?(:ignore)
|
|
65
|
+
Selenium::WebDriver.logger.ignore(:browser_options)
|
|
66
|
+
end
|
|
40
67
|
|
|
41
68
|
# Setup for Capybara to test Jekyll static files served by Rack
|
|
42
69
|
Capybara.server_port = 3003
|