percy-capybara 4.3.0 → 5.0.0.pre.2

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.
@@ -0,0 +1,103 @@
1
+ LABEL = PercyCapybara::PERCY_LABEL
2
+
3
+ RSpec.describe PercyCapybara, type: :feature do
4
+ before(:each) do
5
+ WebMock.disable_net_connect!(allow: '127.0.0.1', disallow: 'localhost')
6
+ page.__percy_clear_cache!
7
+ end
8
+
9
+ describe 'snapshot', type: :feature do
10
+ it 'disables when healthcheck version is incorrect' do
11
+ stub_request(:get, "#{PercyCapybara::PERCY_SERVER_ADDRESS}/percy/healthcheck")
12
+ .to_return(status: 200, body: '', headers: {'x-percy-core-version': '0.1.0'})
13
+
14
+ expect { page.percy_snapshot('Name') }
15
+ .to output("#{LABEL} Unsupported Percy CLI version, 0.1.0\n").to_stdout
16
+ end
17
+
18
+ it 'disables when healthcheck version is missing' do
19
+ stub_request(:get, "#{PercyCapybara::PERCY_SERVER_ADDRESS}/percy/healthcheck")
20
+ .to_return(status: 200, body: '', headers: {})
21
+
22
+ expect { page.percy_snapshot('Name') }
23
+ .to output(
24
+ "#{LABEL} You may be using @percy/agent which" \
25
+ ' is no longer supported by this SDK. Please uninstall' \
26
+ ' @percy/agent and install @percy/cli instead.' \
27
+ " https://docs.percy.io/docs/migrating-to-percy-cli\n",
28
+ ).to_stdout
29
+ end
30
+
31
+ it 'disables when healthcheck fails' do
32
+ stub_request(:get, "#{PercyCapybara::PERCY_SERVER_ADDRESS}/percy/healthcheck")
33
+ .to_return(status: 500, body: '', headers: {})
34
+
35
+ expect { page.percy_snapshot('Name') }
36
+ .to output("#{LABEL} Percy is not running, disabling snapshots\n").to_stdout
37
+ end
38
+
39
+ it 'disables when healthcheck fails to connect' do
40
+ stub_request(:get, "#{PercyCapybara::PERCY_SERVER_ADDRESS}/percy/healthcheck")
41
+ .to_raise(StandardError)
42
+
43
+ expect { page.percy_snapshot('Name') }
44
+ .to output("#{LABEL} Percy is not running, disabling snapshots\n").to_stdout
45
+ end
46
+
47
+ it 'throws an error when name is not provided' do
48
+ stub_request(:get, "#{PercyCapybara::PERCY_SERVER_ADDRESS}/percy/healthcheck")
49
+ .to_return(status: 500, body: '', headers: {})
50
+
51
+ expect { page.percy_snapshot }.to raise_error(ArgumentError)
52
+ end
53
+
54
+ it 'logs an error when sending a snapshot fails' do
55
+ stub_request(:get, "#{PercyCapybara::PERCY_SERVER_ADDRESS}/percy/healthcheck")
56
+ .to_return(status: 200, body: '', headers: {'x-percy-core-version': '1.0.0'})
57
+
58
+ stub_request(:get, "#{PercyCapybara::PERCY_SERVER_ADDRESS}/percy/dom.js")
59
+ .to_return(
60
+ status: 200,
61
+ body: 'window.PercyDOM = { serialize: () => document.documentElement.outerHTML };',
62
+ headers: {},
63
+ )
64
+
65
+ stub_request(:post, 'http://localhost:5338/percy/snapshot')
66
+ .to_return(status: 200, body: '', headers: {})
67
+
68
+ expect { page.percy_snapshot('Name') }
69
+ .to output("#{LABEL} Could not take DOM snapshot 'Name'\n").to_stdout
70
+ end
71
+
72
+ it 'sends snapshots to the local server' do
73
+ stub_request(:get, "#{PercyCapybara::PERCY_SERVER_ADDRESS}/percy/healthcheck")
74
+ .to_return(status: 200, body: '', headers: {'x-percy-core-version': '1.0.0'})
75
+
76
+ stub_request(:get, "#{PercyCapybara::PERCY_SERVER_ADDRESS}/percy/dom.js")
77
+ .to_return(
78
+ status: 200,
79
+ body: 'window.PercyDOM = { serialize: () => document.documentElement.outerHTML };',
80
+ headers: {},
81
+ )
82
+
83
+ stub_request(:post, 'http://localhost:5338/percy/snapshot')
84
+ .to_return(status: 200, body: '{"success": "true" }', headers: {})
85
+
86
+ visit 'index.html'
87
+ page.percy_snapshot('Name')
88
+
89
+ expect(WebMock)
90
+ .to have_requested(:post, "#{PercyCapybara::PERCY_SERVER_ADDRESS}/percy/snapshot")
91
+ .with(
92
+ body: {
93
+ name: 'Name',
94
+ url: 'http://127.0.0.1:3003/index.html',
95
+ dom_snapshot:
96
+ "<html><head><title>I am a page</title></head><body>Snapshot me\n</body></html>",
97
+ client_info: "percy-capybara/#{PercyCapybara::VERSION}",
98
+ environment_info: "capybara/#{Capybara::VERSION} ruby/#{RUBY_VERSION}",
99
+ }.to_json,
100
+ ).once
101
+ end
102
+ end
103
+ end
data/spec/spec_helper.rb CHANGED
@@ -1,6 +1,11 @@
1
+ # This must be required & started before any app code (for proper coverage)
2
+ require 'simplecov'
3
+ SimpleCov.start
4
+ SimpleCov.minimum_coverage 100
5
+
1
6
  require 'capybara/rspec'
2
- require 'selenium-webdriver'
3
- require 'percy'
7
+ require 'webmock/rspec'
8
+ require 'percy/capybara'
4
9
 
5
10
  RSpec.configure do |config|
6
11
  config.expect_with :rspec do |expectations|
@@ -28,6 +33,19 @@ RSpec.configure do |config|
28
33
  Kernel.srand config.seed
29
34
 
30
35
  # See https://github.com/teamcapybara/capybara#selecting-the-driver for other options
31
- Capybara.default_driver = :selenium_chrome
32
- Capybara.javascript_driver = :selenium_chrome
36
+ Capybara.default_driver = :selenium_headless
37
+ Capybara.javascript_driver = :selenium_headless
38
+
39
+ # Setup for Capybara to test static files served by Rack
40
+ Capybara.server_port = 3003
41
+ Capybara.server = :puma, { Silent: true }
42
+ Capybara.app = Rack::File.new(File.join(File.dirname(__FILE__), 'fixture'))
33
43
  end
44
+
45
+ ## Add cache clearing methods for tests
46
+ Capybara::Session.class_eval {
47
+ def __percy_clear_cache!
48
+ @percy_dom = nil
49
+ @percy_enabled = nil
50
+ end
51
+ }
metadata CHANGED
@@ -1,15 +1,43 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: percy-capybara
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.3.0
4
+ version: 5.0.0.pre.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Perceptual Inc.
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-09-01 00:00:00.000000000 Z
11
+ date: 2021-05-06 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: capybara
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '3'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: selenium-webdriver
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 4.0.0.beta1
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: 4.0.0.beta1
13
41
  - !ruby/object:Gem::Dependency
14
42
  name: bundler
15
43
  requirement: !ruby/object:Gem::Requirement
@@ -66,20 +94,6 @@ dependencies:
66
94
  - - "~>"
67
95
  - !ruby/object:Gem::Version
68
96
  version: '3.31'
69
- - !ruby/object:Gem::Dependency
70
- name: selenium-webdriver
71
- requirement: !ruby/object:Gem::Requirement
72
- requirements:
73
- - - ">="
74
- - !ruby/object:Gem::Version
75
- version: '0'
76
- type: :development
77
- prerelease: false
78
- version_requirements: !ruby/object:Gem::Requirement
79
- requirements:
80
- - - ">="
81
- - !ruby/object:Gem::Version
82
- version: '0'
83
97
  - !ruby/object:Gem::Dependency
84
98
  name: percy-style
85
99
  requirement: !ruby/object:Gem::Requirement
@@ -101,28 +115,28 @@ executables: []
101
115
  extensions: []
102
116
  extra_rdoc_files: []
103
117
  files:
104
- - ".circleci/config.yml"
118
+ - ".github/dependabot.yml"
119
+ - ".github/release-drafter.yml"
120
+ - ".github/workflows/changelog.yml"
121
+ - ".github/workflows/lint.yml"
122
+ - ".github/workflows/release.yml"
123
+ - ".github/workflows/test.yml"
105
124
  - ".gitignore"
106
125
  - ".rspec"
107
126
  - ".rubocop.yml"
108
127
  - ".yardopts"
109
- - CHANGELOG.md
110
- - DEVELOPING.md
111
128
  - Gemfile
112
129
  - Guardfile
113
130
  - LICENSE
131
+ - Makefile
114
132
  - README.md
115
- - RELEASING.md
116
133
  - Rakefile
117
- - lib/environment.rb
118
- - lib/percy.rb
119
- - lib/version.rb
120
- - package.json
134
+ - lib/percy/capybara.rb
135
+ - lib/percy/version.rb
121
136
  - percy-capybara.gemspec
122
- - spec/lib/percy/environment_spec.rb
123
- - spec/lib/percy/percy_spec.rb
137
+ - spec/fixture/index.html
138
+ - spec/lib/percy/percy_capybara_spec.rb
124
139
  - spec/spec_helper.rb
125
- - yarn.lock
126
140
  homepage: ''
127
141
  licenses:
128
142
  - MIT
@@ -137,19 +151,18 @@ required_ruby_version: !ruby/object:Gem::Requirement
137
151
  requirements:
138
152
  - - ">="
139
153
  - !ruby/object:Gem::Version
140
- version: '0'
154
+ version: 2.3.0
141
155
  required_rubygems_version: !ruby/object:Gem::Requirement
142
156
  requirements:
143
- - - ">="
157
+ - - ">"
144
158
  - !ruby/object:Gem::Version
145
- version: '0'
159
+ version: 1.3.1
146
160
  requirements: []
147
- rubyforge_project:
148
- rubygems_version: 2.7.10
161
+ rubygems_version: 3.0.3
149
162
  signing_key:
150
163
  specification_version: 4
151
- summary: Percy
164
+ summary: Percy visual testing for Capybara
152
165
  test_files:
153
- - spec/lib/percy/environment_spec.rb
154
- - spec/lib/percy/percy_spec.rb
166
+ - spec/fixture/index.html
167
+ - spec/lib/percy/percy_capybara_spec.rb
155
168
  - spec/spec_helper.rb
data/.circleci/config.yml DELETED
@@ -1,38 +0,0 @@
1
- version: 2.1
2
-
3
- default_steps: &default_steps
4
- steps:
5
- - checkout
6
- - run: sudo gem update --system
7
- - run: ruby -v
8
- - run: yarn
9
- - run: bundle install
10
- - run: yarn percy exec -- bundle exec rspec
11
- - run: bundle exec rubocop -D
12
-
13
- jobs:
14
- ruby_latest_with_percy:
15
- # This is the one environment where we'll capture and upload snapshots in CI.
16
- docker:
17
- - image: circleci/ruby:latest-node-browsers
18
- <<: *default_steps
19
- ruby_25:
20
- docker:
21
- - image: circleci/ruby:2.5-node-browsers
22
- environment:
23
- PERCY_ENABLE: 0
24
- <<: *default_steps
25
- ruby_24:
26
- docker:
27
- - image: circleci/ruby:2.4-node-browsers
28
- environment:
29
- PERCY_ENABLE: 0
30
- <<: *default_steps
31
-
32
- workflows:
33
- version: 2
34
- test:
35
- jobs:
36
- - ruby_latest_with_percy
37
- - ruby_25
38
- - ruby_24
data/CHANGELOG.md DELETED
@@ -1 +0,0 @@
1
- See [releases](https://github.com/percy/percy-capybara/releases).
data/DEVELOPING.md DELETED
@@ -1,26 +0,0 @@
1
- # Developing percy-capybara
2
-
3
- You'll need:
4
- * [Ruby](https://www.ruby-lang.org)
5
- * [Bundler](https://bundler.io/)
6
- * [npm](https://www.npmjs.com/), to manage our dependency on [`@percy/agent`](https://www.npmjs.com/package/@percy/agent)
7
-
8
- To install dependencies:
9
- ```bash
10
- $ bundle install
11
- $ npm install
12
- ```
13
-
14
- To run our test suite and create snapshots:
15
- ```bash
16
- $ bundle exec rake snapshots
17
- ```
18
- (You'll need a `PERCY_TOKEN` in your environment for snapshots to be uploaded to Percy for diffing.)
19
-
20
- If you want to run the test suite without uploading snapshots, you can run:
21
- ```bash
22
- $ bundle exec rspec
23
- ```
24
-
25
- For instructions on releasing, and on updating the vendored version of `percy-agent.js` in this repository, please refer to the [RELEASING](RELEASING.md) doc.
26
-
data/RELEASING.md DELETED
@@ -1,23 +0,0 @@
1
- # Releasing
2
-
3
- 1. `git checkout master`
4
- 1. `git pull origin master`
5
- 1. `git checkout -b X.X.X`
6
- 1. Update version.rb file accordingly.
7
- 1. Commit and push the version update
8
- 1. Tag the release: `git tag vX.X.X`
9
- 1. Push changes: `git push --tags`
10
- 1. Ensure tests have passed on that tag
11
- 1. Open up a pull request titled with the new version number
12
- 1. Merge approved pull request
13
- 1. Draft and publish a [new release on github](https://github.com/percy/percy-capybara/releases)
14
- 1. Build and publish:
15
-
16
- ```bash
17
- bundle exec rake build
18
- gem push pkg/percy-capybara-X.XX.XX.gem
19
- ```
20
-
21
- * Announce the new release,
22
- making sure to say "thank you" to the contributors
23
- who helped shape this version!
data/lib/environment.rb DELETED
@@ -1,38 +0,0 @@
1
- require_relative './version'
2
-
3
- module Percy
4
- def self.client_info
5
- "percy-capybara/#{VERSION}"
6
- end
7
-
8
- def self.environment_info
9
- env_strings = [
10
- "rails/#{self._rails_version}",
11
- "sinatra/#{self._sinatra_version}",
12
- "capybara/#{self.capybara_version}",
13
- "ember-cli-rails/#{self._ember_cli_rails_version}",
14
- ].reject do |info|
15
- info =~ /\/$/ # reject if version is empty
16
- end
17
- env_strings.empty? ? 'unknown' : env_strings.join('; ')
18
- end
19
-
20
- def self.capybara_version
21
- Capybara::VERSION if defined? Capybara
22
- end
23
-
24
- def self._ember_cli_rails_version
25
- return unless defined? EmberCli
26
-
27
- require 'ember_cli/version'
28
- EmberCli::VERSION
29
- end
30
-
31
- def self._rails_version
32
- Rails.version if defined? Rails
33
- end
34
-
35
- def self._sinatra_version
36
- Sinatra::VERSION if defined? Sinatra
37
- end
38
- end
data/lib/percy.rb DELETED
@@ -1,143 +0,0 @@
1
- require 'logger'
2
- require 'net/http'
3
- require 'uri'
4
- require 'json'
5
- require 'environment'
6
-
7
- module Percy
8
- # Takes a snapshot of the given page HTML and its assets.
9
- #
10
- # See https://docs.percy.io/v1/docs/configuration for detailed documentation on
11
- # snapshot options.
12
- #
13
- # @param [Capybara::Session] page The Capybara page to snapshot.
14
- # @param [Hash] options
15
- # @option options [String] :name A unique name for the current page that identifies
16
- # it across builds. By default this is the URL of the page, but can be customized if the
17
- # URL does not entirely identify the current state.
18
- # @option options [Array(Number)] :widths Widths, in pixels, that you'd like to capture for
19
- # this snapshot.
20
- def self.snapshot(page, options = {})
21
- return unless self._is_agent_running?
22
-
23
- if !options.has_key?(:name)
24
- options[:name] = page.current_url
25
- end
26
-
27
- domSnapshot = self._make_dom_snapshot(page, self._keys_to_json(options))
28
- return unless domSnapshot
29
-
30
- body = {
31
- url: page.current_url,
32
- domSnapshot: domSnapshot,
33
- clientInfo: Percy.client_info,
34
- environmentInfo: Percy.environment_info,
35
- }
36
-
37
- body = body.merge(self._keys_to_json(options))
38
-
39
- if self._is_debug?
40
- self._logger.info { "passed snapshot options: #{options}" }
41
- self._logger.info { "snapshot object to POST: #{body}" }
42
- end
43
-
44
- self._post_snapshot_to_agent(body)
45
- end
46
-
47
- private
48
-
49
- AGENT_HOST = 'localhost'
50
- # Technically, the port is configurable when you run the agent. One day we might want
51
- # to make the port configurable in this SDK as well.
52
- AGENT_PORT = 5338
53
- AGENT_JS_PATH= '/percy-agent.js'
54
-
55
- def self._logger
56
- unless defined?(@logger)
57
- @logger = Logger.new(STDOUT)
58
- @logger.formatter = proc do |_severity, _datetime, _progname, msg|
59
- "[percy] #{msg} \n"
60
- end
61
- end
62
- return @logger
63
- end
64
-
65
- def self._get_agent_js
66
- begin
67
- return Net::HTTP.get(AGENT_HOST, AGENT_JS_PATH, AGENT_PORT)
68
- rescue => e
69
- self._logger.error { "Could not load #{AGENT_JS_PATH}. Error: #{e}" }
70
- return nil
71
- end
72
- end
73
-
74
- def self._make_dom_snapshot(page, options)
75
- agent_js = self._get_agent_js
76
- return unless agent_js
77
-
78
- begin
79
- page.execute_script(agent_js)
80
- dom_snapshot_js = "new window.PercyAgent({ handleAgentCommunication: false }).domSnapshot(document, #{options.to_json})"
81
-
82
- if self._is_capybara?
83
- dom_snapshot = page.evaluate_script(dom_snapshot_js)
84
- else
85
- dom_snapshot = page.execute_script(dom_snapshot_js)
86
- end
87
-
88
- return dom_snapshot
89
- rescue => e
90
- self._logger.error { "DOM snapshotting failed. Error: #{e}" }
91
- return nil
92
- end
93
- end
94
-
95
- def self._post_snapshot_to_agent(body)
96
- http = Net::HTTP.new(AGENT_HOST, AGENT_PORT)
97
- request = Net::HTTP::Post.new('/percy/snapshot', { 'Content-Type': 'application/json' })
98
- request.body = body.to_json
99
-
100
- begin
101
- response = http.request(request)
102
- rescue => e
103
- self._logger.error { "Percy rejected snapshot request. Error: #{e}" }
104
- end
105
- end
106
-
107
- def self._is_agent_running?
108
- begin
109
- Net::HTTP.get(AGENT_HOST, '/percy/healthcheck', AGENT_PORT)
110
- return true
111
- rescue => e
112
- if self._is_debug?
113
- self._logger.error { "Healthcheck failed, Percy is not running: #{e}" }
114
- end
115
-
116
- return false
117
- end
118
- end
119
-
120
- # For Ruby style, require snake_case args but transform them into camelCase for percy-agent.
121
- def self._keys_to_json(options)
122
- {
123
- enable_javascript: :enableJavaScript,
124
- min_height: :minHeight,
125
- percy_css: :percyCSS,
126
- request_headers: :requestHeaders,
127
- }.each do |ruby_key, json_key|
128
- if options.has_key? ruby_key
129
- options[json_key] = options[ruby_key]
130
- options.delete(ruby_key)
131
- end
132
- end
133
- return options
134
- end
135
-
136
- def self._is_debug?
137
- ENV['LOG_LEVEL'] == 'debug'
138
- end
139
-
140
- def self._is_capybara?
141
- Percy.capybara_version.length > 0
142
- end
143
- end