percy-capybara 3.2.0 → 4.0.0.pre.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (80) hide show
  1. checksums.yaml +5 -5
  2. data/.circleci/config.yml +39 -0
  3. data/.gitignore +1 -0
  4. data/DEVELOPING.md +26 -0
  5. data/README.md +2 -2
  6. data/lib/environment.rb +31 -0
  7. data/lib/percy.rb +119 -0
  8. data/lib/version.rb +3 -0
  9. data/package-lock.json +2155 -0
  10. data/package.json +6 -0
  11. data/percy-capybara.gemspec +3 -12
  12. data/spec/lib/percy/environment_spec.rb +31 -0
  13. data/spec/lib/percy/percy_spec.rb +55 -0
  14. data/spec/spec_helper.rb +4 -44
  15. metadata +17 -233
  16. data/.travis.yml +0 -17
  17. data/lib/percy/capybara.rb +0 -60
  18. data/lib/percy/capybara/anywhere.rb +0 -37
  19. data/lib/percy/capybara/client.rb +0 -127
  20. data/lib/percy/capybara/client/builds.rb +0 -81
  21. data/lib/percy/capybara/client/snapshots.rb +0 -66
  22. data/lib/percy/capybara/client/user_agent.rb +0 -37
  23. data/lib/percy/capybara/httpfetcher.rb +0 -36
  24. data/lib/percy/capybara/loaders/base_loader.rb +0 -161
  25. data/lib/percy/capybara/loaders/ember_cli_rails_loader.rb +0 -52
  26. data/lib/percy/capybara/loaders/filesystem_loader.rb +0 -37
  27. data/lib/percy/capybara/loaders/native_loader.rb +0 -287
  28. data/lib/percy/capybara/loaders/sprockets_loader.rb +0 -99
  29. data/lib/percy/capybara/rspec.rb +0 -8
  30. data/lib/percy/capybara/version.rb +0 -5
  31. data/spec/lib/percy/capybara/client/builds_spec.rb +0 -171
  32. data/spec/lib/percy/capybara/client/ember_test_data/ember-cli/admin/assets/percy-admin.svg +0 -34
  33. data/spec/lib/percy/capybara/client/ember_test_data/ember-cli/admin/index.html +0 -1
  34. data/spec/lib/percy/capybara/client/ember_test_data/ember-cli/admin/percy-admin-public.svg +0 -34
  35. data/spec/lib/percy/capybara/client/ember_test_data/ember-cli/frontend/assets/percy-frontend.svg +0 -34
  36. data/spec/lib/percy/capybara/client/ember_test_data/ember-cli/frontend/index.html +0 -1
  37. data/spec/lib/percy/capybara/client/ember_test_data/ember-cli/frontend/percy-frontend-public.svg +0 -34
  38. data/spec/lib/percy/capybara/client/rails_public_test_data/large-file-skipped.png +0 -0
  39. data/spec/lib/percy/capybara/client/rails_public_test_data/percy-from-public.svg +0 -34
  40. data/spec/lib/percy/capybara/client/rails_public_test_data/symlink_to_images +0 -1
  41. data/spec/lib/percy/capybara/client/snapshots_spec.rb +0 -97
  42. data/spec/lib/percy/capybara/client/symlink_test_data/test.png +0 -0
  43. data/spec/lib/percy/capybara/client/test_data/assets/css/digested-f3420c6aee71c137a3ca39727052811bae84b2f37d898f4db242e20656a1579e.css +0 -1
  44. data/spec/lib/percy/capybara/client/test_data/assets/images/large-file-skipped.png +0 -0
  45. data/spec/lib/percy/capybara/client/test_data/css/base.css +0 -1
  46. data/spec/lib/percy/capybara/client/test_data/css/digested.css +0 -1
  47. data/spec/lib/percy/capybara/client/test_data/css/font.css +0 -8
  48. data/spec/lib/percy/capybara/client/test_data/css/imports.css +0 -1
  49. data/spec/lib/percy/capybara/client/test_data/css/level0-imports.css +0 -2
  50. data/spec/lib/percy/capybara/client/test_data/css/level1-imports.css +0 -2
  51. data/spec/lib/percy/capybara/client/test_data/css/level2-imports.css +0 -1
  52. data/spec/lib/percy/capybara/client/test_data/css/simple-imports.css +0 -1
  53. data/spec/lib/percy/capybara/client/test_data/css/source.css.map +0 -2
  54. data/spec/lib/percy/capybara/client/test_data/iframe.html +0 -7
  55. data/spec/lib/percy/capybara/client/test_data/images/bg-relative-to-root.png +0 -0
  56. data/spec/lib/percy/capybara/client/test_data/images/bg-relative.png +0 -0
  57. data/spec/lib/percy/capybara/client/test_data/images/bg-stacked.png +0 -0
  58. data/spec/lib/percy/capybara/client/test_data/images/img-relative-to-root.png +0 -0
  59. data/spec/lib/percy/capybara/client/test_data/images/img-relative.png +0 -0
  60. data/spec/lib/percy/capybara/client/test_data/images/percy.svg +0 -34
  61. data/spec/lib/percy/capybara/client/test_data/images/srcset-base.png +0 -0
  62. data/spec/lib/percy/capybara/client/test_data/images/srcset-first.png +0 -0
  63. data/spec/lib/percy/capybara/client/test_data/images/srcset-second.png +0 -0
  64. data/spec/lib/percy/capybara/client/test_data/index.html +0 -1
  65. data/spec/lib/percy/capybara/client/test_data/js/base.js +0 -1
  66. data/spec/lib/percy/capybara/client/test_data/test-css.html +0 -20
  67. data/spec/lib/percy/capybara/client/test_data/test-font.html +0 -9
  68. data/spec/lib/percy/capybara/client/test_data/test-iframe.html +0 -8
  69. data/spec/lib/percy/capybara/client/test_data/test-images.html +0 -51
  70. data/spec/lib/percy/capybara/client/test_data/test-localtest-me-images.html +0 -8
  71. data/spec/lib/percy/capybara/client/user_agent_spec.rb +0 -45
  72. data/spec/lib/percy/capybara/client_spec.rb +0 -232
  73. data/spec/lib/percy/capybara/http_fetcher_spec.rb +0 -17
  74. data/spec/lib/percy/capybara/loaders/base_loader_spec.rb +0 -122
  75. data/spec/lib/percy/capybara/loaders/ember_cli_rails_loader_spec.rb +0 -86
  76. data/spec/lib/percy/capybara/loaders/filesystem_loader_spec.rb +0 -166
  77. data/spec/lib/percy/capybara/loaders/native_loader_spec.rb +0 -300
  78. data/spec/lib/percy/capybara/loaders/sprockets_loader_spec.rb +0 -119
  79. data/spec/lib/percy/capybara_spec.rb +0 -101
  80. data/spec/support/test_helpers.rb +0 -60
@@ -1,161 +0,0 @@
1
- require 'pathname'
2
- require 'percy/capybara'
3
-
4
- module Percy
5
- module Capybara
6
- module Loaders
7
- class BaseLoader
8
- # Modified version of Diego Perini's URL regex. https://gist.github.com/dperini/729294
9
- URL_REGEX = Regexp.new(
10
- # protocol identifier
11
- '((?:https?:)?//)' \
12
- '(' +
13
- # IP address exclusion
14
- # private & local networks
15
- '(?!(?:10|127)(?:\\.\\d{1,3}){3})' \
16
- '(?!(?:169\\.254|192\\.168)(?:\\.\\d{1,3}){2})' \
17
- '(?!172\\.(?:1[6-9]|2\\d|3[0-1])(?:\\.\\d{1,3}){2})' +
18
- # IP address dotted notation octets
19
- # excludes loopback network 0.0.0.0
20
- # excludes reserved space >= 224.0.0.0
21
- # excludes network & broacast addresses
22
- # (first & last IP address of each class)
23
- '(?:[1-9]\\d?|1\\d\\d|2[01]\\d|22[0-3])' \
24
- '(?:\\.(?:1?\\d{1,2}|2[0-4]\\d|25[0-5])){2}' \
25
- '(?:\\.(?:[1-9]\\d?|1\\d\\d|2[0-4]\\d|25[0-4]))' \
26
- '|' +
27
- # host name
28
- '(?:(?:[a-z\\u00a1-\\uffff0-9]-*)*[a-z\\u00a1-\\uffff0-9]+)' +
29
- # domain name
30
- '(?:\\.(?:[a-z\\u00a1-\\uffff0-9]-*)*[a-z\\u00a1-\\uffff0-9]+)*' \
31
- ')' +
32
- # port number
33
- '(:\\d{2,5})?' +
34
- # resource path
35
- "(/[^\\s\"']*)?",
36
- )
37
-
38
- SKIP_RESOURCE_EXTENSIONS = [
39
- '.map', # Ignore source maps.
40
- '.gz', # Ignore gzipped files.
41
- ].freeze
42
-
43
- MAX_FILESIZE_BYTES = 15 * 1024**2 # 15 MB.
44
-
45
- attr_reader :page
46
-
47
- # @param [Capybara::Session] page The Capybara page.
48
- # @param [bool] include_iframes Include iframes in the snapshot
49
- def initialize(options = {})
50
- @page = options[:page]
51
- @include_iframes = options[:include_iframes] || false
52
- end
53
-
54
- def build_resources
55
- raise NotImplementedError, 'subclass must implement abstract method'
56
- end
57
-
58
- def snapshot_resources
59
- raise NotImplementedError, 'subclass must implement abstract method'
60
- end
61
-
62
- # @private
63
- def root_html_resource
64
- Percy::Client::Resource.new(
65
- current_path, is_root: true, mimetype: 'text/html', content: page.html,
66
- )
67
- end
68
-
69
- # Transformed version of the current URL to be a relative path.
70
- # This important because Rack::Test uses "www.example.com" as the actual current URL,
71
- # which would force Percy to actually render example.com instead of the page. By always
72
- # using a URL path as the resource URL, we guarantee that Percy will render what it's given.
73
- #
74
- # @private
75
- def current_path
76
- current_url = page.current_url
77
- url_match = URL_REGEX.match(current_url)
78
- return url_match[4] if url_match
79
-
80
- # Special case: prepend a slash to the path to force a valid URL for things like
81
- # "about:srcdoc" iframe srcdoc pages.
82
- current_url = "/#{current_url}" if current_url[0] != '/'
83
-
84
- current_url
85
- end
86
-
87
- # NOTES:
88
- # - Doesn't handle multiple iframes with the same URL (`src` attribute)
89
- # @private
90
- def iframes_resources
91
- return [] unless @include_iframes
92
-
93
- resources = []
94
-
95
- page.all(:css, 'iframe').each do |iframe_element|
96
- iframe_url = iframe_element[:src]
97
- root_page_host = page.current_host
98
- begin
99
- page.within_frame(iframe_element) do
100
- next unless page.current_host == root_page_host
101
- path = URI.parse(iframe_url).path
102
- content = page.html
103
- sha = Digest::SHA256.hexdigest(content)
104
- resources <<
105
- Percy::Client::Resource.new(
106
- path,
107
- content: content,
108
- sha: sha,
109
- mimetype: 'text/html',
110
- )
111
- end
112
- rescue StandardError => e
113
- # Skip frame not found errors. This library doesn't explicitly depend on Poltergeist,
114
- # so we check the string class name.
115
- raise e unless e.class.to_s == 'Capybara::Poltergeist::FrameNotFound' ||
116
- e.class.to_s == 'Capybara::Poltergeist::TimeoutError'
117
- end
118
- end
119
-
120
- resources
121
- rescue ::Capybara::NotSupportedByDriverError
122
- []
123
- end
124
-
125
- def _resources_from_dir(root_dir, base_url: '/')
126
- resources = []
127
-
128
- _find_files(root_dir).each do |path|
129
- # Skip certain extensions.
130
- next if SKIP_RESOURCE_EXTENSIONS.include?(File.extname(path))
131
- # Skip large files, these are hopefully downloads and not used in page rendering.
132
- next if File.size(path) > MAX_FILESIZE_BYTES
133
-
134
- # Replace the assets_dir with the base_url to generate the resource_url
135
- resource_url = _uri_join(base_url, path.sub(root_dir.to_s, ''))
136
-
137
- sha = Digest::SHA256.hexdigest(File.read(path))
138
-
139
- resources << Percy::Client::Resource.new(resource_url, sha: sha, path: path)
140
- end
141
-
142
- resources
143
- end
144
-
145
- # A simplified version of Find.find that only returns files and follows symlinks.
146
- def _find_files(*paths)
147
- paths.flatten.map do |path|
148
- path = Pathname.new(path)
149
- path.file? ? [path.to_s] : _find_files(path.children)
150
- end.flatten
151
- end
152
-
153
- def _uri_join(*paths)
154
- # We must swap File::SEPARATOR for '/' here because on Windows File.join
155
- # will use backslashes and this is a URL.
156
- File.join(paths).gsub(File::SEPARATOR, '/')
157
- end
158
- end
159
- end
160
- end
161
- end
@@ -1,52 +0,0 @@
1
- require 'percy/capybara/loaders/sprockets_loader'
2
- require 'set'
3
-
4
- module Percy
5
- module Capybara
6
- module Loaders
7
- class EmberCliRailsLoader < SprocketsLoader
8
- attr_reader :mounted_apps
9
-
10
- def initialize(mounted_apps, options = {})
11
- super(options)
12
-
13
- raise 'mounted_apps is required' unless mounted_apps
14
- @mounted_apps = mounted_apps
15
- end
16
-
17
- def build_resources
18
- resources = super # adds sprockets resources first
19
-
20
- sprockets_resource_urls = resources.collect(&:resource_url)
21
- loaded_resource_urls = Set.new(sprockets_resource_urls)
22
-
23
- @mounted_apps.map do |app_name, mount_path|
24
- # full path on disk to this ember app
25
- # e.g. /Users/djones/Code/rails-ember-app/tmp/ember-cli/apps/frontend
26
- dist_path = _dist_path_for_app(app_name)
27
-
28
- resources_from_dir = _resources_from_dir(dist_path, base_url: mount_path)
29
-
30
- resources_from_dir.each do |resource|
31
- # avoid loading in duplicate resource_urls
32
- next if loaded_resource_urls.include? resource.resource_url
33
-
34
- resources << resource
35
- loaded_resource_urls << resource.resource_url
36
- end
37
- end
38
-
39
- resources
40
- end
41
-
42
- def _dist_path_for_app(app_name)
43
- _ember_cli.apps[app_name].dist_path
44
- end
45
-
46
- def _ember_cli
47
- EmberCli if defined?(EmberCli)
48
- end
49
- end
50
- end
51
- end
52
- end
@@ -1,37 +0,0 @@
1
- require 'percy/capybara/loaders/base_loader'
2
- require 'digest'
3
- require 'find'
4
- require 'pathname'
5
-
6
- module Percy
7
- module Capybara
8
- module Loaders
9
- # Resource loader that looks for resources in the specified folder.
10
- class FilesystemLoader < BaseLoader
11
- def initialize(options = {})
12
- # @assets_dir should point to a _compiled_ static assets directory, not source assets.
13
- @assets_dir = options[:assets_dir]
14
- @base_url = options[:base_url] || '/'
15
-
16
- raise ArgumentError, 'assets_dir is required' if @assets_dir.nil? || @assets_dir == ''
17
- unless Pathname.new(@assets_dir).absolute?
18
- raise ArgumentError, "assets_dir needs to be an absolute path. Received: #{@assets_dir}"
19
- end
20
- unless Dir.exist?(@assets_dir)
21
- raise ArgumentError, "assets_dir provided was not found. Received: #{@assets_dir}"
22
- end
23
-
24
- super
25
- end
26
-
27
- def snapshot_resources
28
- [root_html_resource]
29
- end
30
-
31
- def build_resources
32
- _resources_from_dir(@assets_dir, base_url: @base_url)
33
- end
34
- end
35
- end
36
- end
37
- end
@@ -1,287 +0,0 @@
1
- require 'percy/capybara/loaders/base_loader'
2
- require 'digest'
3
- require 'uri'
4
-
5
- module Percy
6
- module Capybara
7
- module Loaders
8
- # Resource loader that uses the native Capybara browser interface to discover resources.
9
- # This loader uses JavaScript to discover page resources, so specs must be tagged with
10
- # "js: true" because the default Rack::Test driver does not support executing JavaScript.
11
- class NativeLoader < BaseLoader
12
- PATH_REGEX = /\A\/[^\\s\"']*/
13
- DATA_URL_REGEX = /\Adata:/
14
- LOCAL_HOSTNAMES = [
15
- 'localhost',
16
- '127.0.0.1',
17
- '0.0.0.0',
18
- ].freeze
19
-
20
- def initialize(options = {})
21
- super(options)
22
-
23
- @asset_hostnames = options[:asset_hostnames] || []
24
- @assets_from_stylesheets = options[:include_assets_from_stylesheets] || :all
25
- @assets_from_stylesheets = ->(_) { true } if @assets_from_stylesheets == :all
26
- end
27
-
28
- def snapshot_resources
29
- resources = []
30
- resources << root_html_resource
31
- resources += _get_css_resources
32
- resources += _get_image_resources
33
- resources += iframes_resources
34
- resources
35
- end
36
-
37
- def build_resources
38
- []
39
- end
40
-
41
- # @private
42
- def _get_css_resources
43
- resources = []
44
- # Find all CSS resources.
45
- # http://www.quirksmode.org/dom/w3c_css.html#access
46
- script = <<-JS
47
- function findStylesRecursively(stylesheet, css_urls) {
48
- if (stylesheet.href) { // Skip stylesheet without hrefs (inline stylesheets).
49
- css_urls.push(stylesheet.href);
50
-
51
- // Remote stylesheet rules cannot be accessed because of the same-origin policy.
52
- // Unfortunately, if you touch .cssRules in Selenium, it throws a JavascriptError
53
- // with 'The operation is insecure'. To work around this, skip reading rules of
54
- // remote stylesheets but still include them for fetching.
55
- //
56
- // TODO: If a remote stylesheet has an @import, it will be missing because we don't
57
- // notice it here. We could potentially recursively fetch remote imports in
58
- // ruby-land below.
59
- var parser = document.createElement('a');
60
- parser.href = stylesheet.href;
61
- if (parser.host != window.location.host) {
62
- return;
63
- }
64
- }
65
- for (var i = 0; i < stylesheet.cssRules.length; i++) {
66
- var rule = stylesheet.cssRules[i];
67
- // Depth-first search, handle recursive @imports.
68
- if (rule.styleSheet) {
69
- findStylesRecursively(rule.styleSheet, css_urls);
70
- }
71
- }
72
- }
73
-
74
- var css_urls = [];
75
- for (var i = 0; i < document.styleSheets.length; i++) {
76
- findStylesRecursively(document.styleSheets[i], css_urls);
77
- }
78
- return css_urls;
79
- JS
80
- resource_urls = _evaluate_script(page, script)
81
- urls_referred_by_css = []
82
-
83
- resource_urls.each do |url|
84
- next unless _should_include_url?(url)
85
- response = _fetch_resource_url(url)
86
- urls_referred_by_css.concat(_parse_urls_from_css(response.body))
87
- _absolute_url_to_relative!(url, _current_host_port)
88
- next unless response
89
- resources << Percy::Client::Resource.new(
90
- url, mimetype: 'text/css', content: response.body,
91
- )
92
- end
93
- @urls_referred_by_css = urls_referred_by_css
94
- resources
95
- end
96
- private :_get_css_resources
97
-
98
- # @private
99
- def _get_image_resources
100
- resources = []
101
- image_urls = Set.new
102
-
103
- # Find all image tags on the page.
104
- page.all('img').each do |image_element|
105
- srcs = []
106
- srcs << image_element[:src] unless image_element[:src].nil?
107
-
108
- srcset_raw_urls = image_element[:srcset] || ''
109
- temp_urls = srcset_raw_urls.split(',')
110
- temp_urls.each do |temp_url|
111
- srcs << temp_url.split(' ').first
112
- end
113
-
114
- srcs.each do |url|
115
- image_urls << url
116
- end
117
- end
118
-
119
- raw_image_urls = _evaluate_script(page, _find_all_css_loaded_background_image_js)
120
- raw_image_urls.each do |raw_image_url|
121
- temp_urls = raw_image_url.scan(/url\(["']?(.*?)["']?\)/)
122
- # background-image can accept multiple url()s, so temp_urls is an array of URLs.
123
- temp_urls.each do |temp_url|
124
- url = temp_url[0]
125
- image_urls << url
126
- end
127
- end
128
-
129
- if @assets_from_stylesheets && @assets_from_stylesheets != :none
130
- image_urls.merge(@urls_referred_by_css.select { |path| @assets_from_stylesheets[path] })
131
- end
132
-
133
- image_urls.each do |image_url|
134
- # If url references are blank, browsers will often fill them with the current page's
135
- # URL, which makes no sense and will never be renderable. Strip these.
136
- next if image_url == current_path \
137
- || image_url == page.current_url \
138
- || image_url.strip.empty?
139
-
140
- # Make the resource URL absolute to the current page. If it is already absolute, this
141
- # will have no effect.
142
- resource_url = URI.join(page.current_url, image_url).to_s
143
-
144
- # Skip duplicates.
145
- next if resources.find { |r| r.resource_url == resource_url }
146
-
147
- next unless _should_include_url?(resource_url)
148
-
149
- # Fetch the images.
150
- # TODO(fotinakis): this can be pretty inefficient for image-heavy pages because the
151
- # browser has already loaded them once and this fetch cannot easily leverage the
152
- # browser's cache. However, often these images are probably local resources served by a
153
- # development server, so it may not be so bad. Re-evaluate if this becomes an issue.
154
- response = _fetch_resource_url(resource_url)
155
- _absolute_url_to_relative!(resource_url, _current_host_port)
156
- next unless response
157
-
158
- resources << Percy::Client::Resource.new(
159
- resource_url, mimetype: response.content_type, content: response.body,
160
- )
161
- end
162
- resources
163
- end
164
- private :_get_image_resources
165
-
166
- # @private
167
- def _find_all_css_loaded_background_image_js
168
- <<-JS
169
- var raw_image_urls = [];
170
-
171
- var tags = document.getElementsByTagName('*');
172
- var el;
173
- var rawValue;
174
-
175
- for (var i = 0; i < tags.length; i++) {
176
- el = tags[i];
177
- if (el.currentStyle) {
178
- rawValue = el.currentStyle['backgroundImage'];
179
- } else if (window.getComputedStyle) {
180
- rawValue = window.getComputedStyle(el).getPropertyValue('background-image');
181
- }
182
- if (!rawValue || rawValue === "none") {
183
- continue;
184
- } else {
185
- raw_image_urls.push(rawValue);
186
- }
187
- }
188
- return raw_image_urls;
189
- JS
190
- end
191
-
192
- # @private
193
- def _parse_urls_from_css(css_content)
194
- css_content.scan(/url\(([^\)]+)\)/)
195
- .map { |i| _remove_quotes(i.first) }
196
- .select { |path| _should_include_url?(path) }
197
- .map { |path| _remove_hash_from_url(path) }
198
- end
199
-
200
- # @private
201
- def _remove_hash_from_url(string)
202
- if /^(?<url_base>.+)?\#[^#]+$/ =~ string
203
- if url_base.end_with?('?')
204
- url_base[0...-1]
205
- else
206
- url_base
207
- end
208
- else
209
- string
210
- end
211
- end
212
-
213
- # @private
214
- def _remove_quotes(string)
215
- if string.length >= 2 && (string[0] == string[-1]) && ['"', "'"].include?(string[0])
216
- string[1...-1]
217
- else
218
- string
219
- end
220
- end
221
-
222
- # @private
223
- def _fetch_resource_url(url)
224
- response = Percy::Capybara::HttpFetcher.fetch(url)
225
- unless response
226
- STDERR.puts '[percy] Warning: failed to fetch page resource, ' \
227
- "this might be a bug: #{url}"
228
- return nil
229
- end
230
- response
231
- end
232
- private :_fetch_resource_url
233
-
234
- # @private
235
- def _evaluate_script(page, script)
236
- script = <<-JS
237
- (function() {
238
- #{script}
239
- })();
240
- JS
241
- page.evaluate_script(script)
242
- end
243
- private :_evaluate_script
244
-
245
- # @private
246
- def _should_include_url?(url)
247
- # It is a URL or a path, but not a data URI.
248
- url_match = URL_REGEX.match(url)
249
- data_url_match = DATA_URL_REGEX.match(url)
250
- result = (url_match || PATH_REGEX.match(url)) && !data_url_match
251
-
252
- # Is not a remote URL.
253
- if url_match && !data_url_match
254
- host = url_match[2]
255
- result = asset_hostnames.include?(host) || _same_server?(url, _current_host_port)
256
- end
257
-
258
- !!result
259
- end
260
-
261
- # @private
262
- def _current_host_port
263
- url_match = URL_REGEX.match(page.current_url)
264
- url_match[1] + url_match[2] + (url_match[3] || '')
265
- end
266
- private :_current_host_port
267
-
268
- # @private
269
- def _same_server?(url, host_port)
270
- url.start_with?(host_port + '/') || url == host_port
271
- end
272
- private :_same_server?
273
-
274
- # @private
275
- def _absolute_url_to_relative!(url, host_port)
276
- url.gsub!(host_port + '/', '/') if url.start_with?(host_port + '/')
277
- end
278
- private :_absolute_url_to_relative!
279
-
280
- def asset_hostnames
281
- LOCAL_HOSTNAMES + @asset_hostnames
282
- end
283
- private :asset_hostnames
284
- end
285
- end
286
- end
287
- end