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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 599af2bc8ab99bf3bb74f396232a4be8a6fd7cac209f9a159a5a2e9850581139
4
- data.tar.gz: 38a4b597b1ed391675bc6ce07e6bba7b6820691ecf969a84bfd98a8609b4de50
3
+ metadata.gz: 964b34504d72f46df90ac38f0c122efb350e6a46673899855cbf668523d93349
4
+ data.tar.gz: 7f2cbab4d9f0228ce5b29d24601a04dea8f11dfb2a359dea52eddfe741463c85
5
5
  SHA512:
6
- metadata.gz: 8d0dbb6269542d41b36883985f7ffd390b5d74595752a7604eceaf26dda0503817b15fc3b129f24f3ec2f64e46715b8fc9a2768390e07ec53f22a57a43c1fe89
7
- data.tar.gz: f0960498a183952e6f7fdc7c9a8d5a84125bffa11ac34e3f5b4ba781ec9bd3596c45e07b11a39120723e8e35884eb1288d44e7bf1bd9506f667e926600ebc9da
6
+ metadata.gz: e4914dc15a922d03df46fa24a68576d89e784314d9e40c55b1dd3f3e2b32a746a94eca1e55c7f54a204046a3a98c13954d3e29200ebfbae8fe8f49c7e9d5fc74
7
+ data.tar.gz: b562acce5038bbaf57e50767d6c9a1cf10e19beabe46f97686576e427071a37492ea0b90b9936dec6ad7c9e5ee9c545283ae766744d79290984c82c17cb664d5
@@ -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 ${{ github.event.inputs.branch }} --depth 1 https://github.com/percy/cli
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
- cd ${{ github.workspace }}
64
- yarn remove @percy/cli && yarn link `echo $PERCY_PACKAGES`
65
- npx percy --version
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
- dom_snapshot = if responsive_snapshot_capture?(options)
83
- capture_responsive_dom(driver, options, percy_dom_script: percy_dom_script)
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, options, percy_dom_script: percy_dom_script)
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
@@ -1,3 +1,3 @@
1
1
  module Percy
2
- VERSION = '1.1.3-beta.1'.freeze
2
+ VERSION = '1.1.4-beta.1'.freeze
3
3
  end
@@ -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
- Capybara.default_driver = :selenium_headless
39
- Capybara.javascript_driver = :selenium_headless
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
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.1
4
+ version: 1.1.4.pre.beta.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Perceptual Inc.