cuprite 0.15 → 0.16

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: '06038d0fa139b71bda9f95ce0d353bfbd0394ff6a09f95c8dc0acb4f0b7f86f9'
4
- data.tar.gz: 91a79735083b3949663d38d8ed1703c7955ada3ec2299830e7105348a72dd337
3
+ metadata.gz: 70fb54b637d782b831b70e9894f65d95deb839abca0dff8355245c1dfaf7f81e
4
+ data.tar.gz: f909e93716a7bffb69e35cf4dbc783c13e4acc9d13a226f2ee5d85d2c49cc427
5
5
  SHA512:
6
- metadata.gz: d1ab5955459610619f457b8ff7ac76fe761e003d20664da614f8b613da2849a65ba23c0c772753864321bf6b346a3e7d468da82dc55d816f33bbb7b13c6784ad
7
- data.tar.gz: e618d937daea3246787cef4084f07fd7a5b2109fd7e34ff0bfa7f3d7e954c3b258539338a52378e8f9a80d96e4a8d29de3041d568b5dac8850aba61abba614c4
6
+ metadata.gz: 521a59b3852efa9a3e770090e56bdcbc508da3465414bc2a72300f10757380103d9b6cb668a426d0af3173a89ad02f5cbf78666d9d33b19235d68f2e955182d4
7
+ data.tar.gz: dd50d8cd20886faa16e5372659c25792847286c954ea1c5a951b5a504d87cb06897e2e0bacd7d86457a6f72529054d99bc3773e163a06d926ef0c21a98cc7375
data/README.md CHANGED
@@ -4,9 +4,7 @@ Cuprite is a pure Ruby driver (read as _no_ Selenium/WebDriver/ChromeDriver
4
4
  dependency) for [Capybara](https://github.com/teamcapybara/capybara). It allows
5
5
  you to run Capybara tests on a headless Chrome or Chromium. Under the hood it
6
6
  uses [Ferrum](https://github.com/rubycdp/ferrum#index) which is high-level API
7
- to the browser by CDP protocol. The design of the driver is as close to
8
- [Poltergeist](https://github.com/teampoltergeist/poltergeist) as possible though
9
- it's not a goal.
7
+ to the browser by CDP protocol.
10
8
 
11
9
 
12
10
  ## Install
@@ -43,8 +41,7 @@ browser = page.driver.browser
43
41
  browser.mouse.move(x: 123, y: 456).down.up
44
42
  ```
45
43
 
46
- If you already have tests on Poltergeist then it should simply work, for
47
- Selenium you better check your code for `manage` calls because it works
44
+ For Selenium you better check your code for `manage` calls because it works
48
45
  differently in Cuprite, see the documentation below.
49
46
 
50
47
 
@@ -64,8 +61,8 @@ end
64
61
  `Cuprite`-specific options are:
65
62
 
66
63
  * options `Hash`
67
- * `:url_blacklist` (Array) - array of strings to match against requested URLs
68
- * `:url_whitelist` (Array) - array of strings to match against requested URLs
64
+ * `:url_blacklist` (Array) - array of regexes to match against requested URLs
65
+ * `:url_whitelist` (Array) - array of regexes to match against requested URLs
69
66
 
70
67
 
71
68
  ## Debugging
@@ -125,13 +122,17 @@ be automatically cleared at the end of the test.
125
122
 
126
123
  ## Network traffic
127
124
 
128
- * `page.driver.network_traffic` Inspect network traffic (loaded resources) on
129
- the current page. This returns an array of request objects.
125
+ * `page.driver.network_traffic` allows you to inspect network traffic (i.e., loaded resources) on the current page. It returns an array of `Ferrum::Network::Exchange` objects, each representing a network request/response exchange. You can query both the request and response details of each exchange.
130
126
 
131
127
  ```ruby
132
- page.driver.network_traffic # => [Request, ...]
133
- request = page.driver.network_traffic.first
134
- request.response
128
+ # Retrieve all network exchanges
129
+ network_traffic = page.driver.network_traffic
130
+
131
+ # Access the first exchange
132
+ first_exchange = network_traffic.first
133
+
134
+ # Inspect the response of the first request
135
+ response = first_exchange.response
135
136
  ```
136
137
 
137
138
  * `page.driver.wait_for_network_idle` Natively waits for network idle and if
@@ -186,27 +187,29 @@ Besides capybara screenshot method you can get image as Base64:
186
187
 
187
188
  ## Proxy
188
189
 
189
- * `page.driver.set_proxy(ip, port, type, user, password)`
190
+ * `page.driver.set_proxy(ip, port, user, password)`
190
191
 
191
192
 
192
- ## URL Blacklisting & Whitelisting
193
+ ## URL Blocklisting & Allowlisting
193
194
 
194
- Cuprite supports URL blacklisting, which allows you to prevent scripts from
195
+ Cuprite supports URL blocklisting, which allows you to prevent scripts from
195
196
  running on designated domains:
196
197
 
197
198
  ```ruby
198
- page.driver.browser.url_blacklist = %r{http://www.example.com}
199
+ page.driver.browser.url_blocklist = %r{http://www.example.com}
199
200
  ```
200
201
 
201
- and also URL whitelisting, which allows scripts to only run on designated
202
+ and also URL allowlisting, which allows scripts to only run on designated
202
203
  domains:
203
204
 
204
205
  ```ruby
205
- page.driver.browser.url_whitelist = %r{http://www.example.com}
206
+ page.driver.browser.url_allowlist = %r{http://www.example.com}
206
207
  ```
207
208
 
208
- If you are experiencing slower run times, consider creating a URL whitelist of
209
- domains that are essential or a blacklist of domains that are not essential,
209
+ For legacy support, `url_blacklist=` and `url_whitelist=` continue to work respectively.
210
+
211
+ If you are experiencing slower run times, consider creating a URL allowlist of
212
+ domains that are essential or a blocklist of domains that are not essential,
210
213
  such as ad networks or analytics, to your testing environment.
211
214
 
212
215
  ## License
@@ -11,50 +11,63 @@ module Capybara
11
11
  find_modal accept_confirm dismiss_confirm accept_prompt
12
12
  dismiss_prompt reset_modals] => :page
13
13
 
14
- attr_reader :url_blacklist, :url_whitelist
15
- alias url_blocklist url_blacklist
16
- alias url_allowlist url_whitelist
17
-
18
14
  def initialize(options = nil)
19
- options ||= {}
20
- @client = nil
21
- self.url_blacklist = options[:url_blacklist]
22
- self.url_whitelist = options[:url_whitelist]
23
-
24
15
  super
25
- @page = false
16
+
17
+ @options.url_blacklist = prepare_wildcards(options&.dig(:url_blacklist))
18
+ @options.url_whitelist = prepare_wildcards(options&.dig(:url_whitelist))
19
+
20
+ @page = nil
26
21
  end
27
22
 
28
- def timeout=(value)
23
+ def command(...)
29
24
  super
30
- @page.timeout = value unless @page.nil?
25
+ rescue Ferrum::DeadBrowserError
26
+ restart
27
+ raise
31
28
  end
32
29
 
33
30
  def page
34
- raise Ferrum::NoSuchPageError if @page.nil?
31
+ raise Ferrum::NoSuchPageError if @page&.closed?
35
32
 
36
33
  @page ||= attach_page
37
34
  end
38
35
 
39
36
  def reset
40
37
  super
41
- @page = attach_page
38
+ @options.reset_window_size
39
+ @page = nil
42
40
  end
43
41
 
44
42
  def quit
45
43
  super
46
- @page = false
44
+ @page = nil
47
45
  end
48
46
 
47
+ def resize(**options)
48
+ @options.window_size = [options[:width], options[:height]]
49
+ super
50
+ end
51
+
52
+ def url_whitelist
53
+ @options.url_whitelist
54
+ end
55
+ alias url_allowlist url_whitelist
56
+
49
57
  def url_whitelist=(patterns)
50
- @url_whitelist = prepare_wildcards(patterns)
51
- page.network.whitelist = @url_whitelist if @client && @url_whitelist.any?
58
+ @options.url_whitelist = prepare_wildcards(patterns)
59
+ page.network.whitelist = @options.url_whitelist if @client && @options.url_whitelist.any?
52
60
  end
53
61
  alias url_allowlist= url_whitelist=
54
62
 
63
+ def url_blacklist
64
+ @options.url_blacklist
65
+ end
66
+ alias url_blocklist url_blacklist
67
+
55
68
  def url_blacklist=(patterns)
56
- @url_blacklist = prepare_wildcards(patterns)
57
- page.network.blacklist = @url_blacklist if @client && @url_blacklist.any?
69
+ @options.url_blacklist = prepare_wildcards(patterns)
70
+ page.network.blacklist = @options.url_blacklist if @client && @options.url_blacklist.any?
58
71
  end
59
72
  alias url_blocklist= url_blacklist=
60
73
 
@@ -109,8 +122,13 @@ module Capybara
109
122
  target = targets[target_id]
110
123
  raise Ferrum::NoSuchPageError unless target
111
124
 
112
- @page = nil if @page.target_id == target.id
125
+ @page = ClosedPage.new if @page.target_id == target.id
113
126
  target.page.close
127
+ targets.delete(target_id) # page.close is async, delete target asap
128
+ end
129
+
130
+ def active_element
131
+ evaluate("document.activeElement")
114
132
  end
115
133
 
116
134
  def browser_error
@@ -121,24 +139,33 @@ module Capybara
121
139
  raise NotImplementedError
122
140
  end
123
141
 
124
- def drag(node, other, steps)
142
+ def drag(node, other, steps, delay = nil, scroll = true)
125
143
  x1, y1 = node.find_position
126
- x2, y2 = other.find_position
127
144
 
128
145
  mouse.move(x: x1, y: y1)
129
146
  mouse.down
147
+ sleep delay if delay
148
+
149
+ other.scroll_into_view if scroll
150
+
151
+ x2, y2 = other.find_position
130
152
  mouse.move(x: x2, y: y2, steps: steps)
153
+
131
154
  mouse.up
132
155
  end
133
156
 
134
- def drag_by(node, x, y, steps)
157
+ def drag_by(node, dx, dy, steps, delay = nil, scroll = true)
135
158
  x1, y1 = node.find_position
136
- x2 = x1 + x
137
- y2 = y1 + y
138
159
 
139
160
  mouse.move(x: x1, y: y1)
140
161
  mouse.down
141
- mouse.move(x: x2, y: y2, steps: steps)
162
+
163
+ sleep delay if delay
164
+
165
+ evaluate("window.scrollBy(#{dx}, #{dy})") if scroll # should be extracted to Mouse#scroll_by in ferrum
166
+
167
+ x2, y2 = node.find_position
168
+ mouse.move(x: x2 + dx, y: y2 + dy, steps: steps)
142
169
  mouse.up
143
170
  end
144
171
 
@@ -183,6 +210,10 @@ module Capybara
183
210
  evaluate_on(node: node, expression: "_cuprite.path(this)")
184
211
  end
185
212
 
213
+ def obscured?(node)
214
+ evaluate_on(node: node, expression: "_cuprite.isObscured(this)")
215
+ end
216
+
186
217
  def all_text(node)
187
218
  node.text
188
219
  end
@@ -224,10 +255,10 @@ module Capybara
224
255
  def attach_page(target_id = nil)
225
256
  target = targets[target_id] if target_id
226
257
  target ||= default_context.default_target
227
- return target.page if target.attached?
258
+ return target.page if target.connected?
228
259
 
229
260
  target.maybe_sleep_if_new_window
230
- target.page = Page.new(target.id, self)
261
+ target.page = Page.new(target.client, context_id: target.context_id, target_id: target.id)
231
262
  target.page
232
263
  end
233
264
  end
@@ -40,7 +40,7 @@ module Capybara
40
40
  end
41
41
 
42
42
  def expires
43
- Time.at(@attributes["expires"]) if (@attributes["expires"]).positive?
43
+ Time.at(@attributes["expires"]) if @attributes["expires"].positive?
44
44
  end
45
45
  end
46
46
  end
@@ -15,6 +15,7 @@ module Capybara
15
15
  delegate %i[restart quit status_code timeout timeout= current_url title body
16
16
  window_handles close_window switch_to_window within_window window_handle
17
17
  back forward refresh wait_for_reload viewport_size device_pixel_ratio] => :browser
18
+ delegate %i[send_keys] => :active_element
18
19
  alias html body
19
20
  alias current_window_handle window_handle
20
21
  alias go_back back
@@ -34,7 +35,11 @@ module Capybara
34
35
  @screen_size ||= DEFAULT_MAXIMIZE_SCREEN_SIZE
35
36
  @options[:save_path] ||= File.expand_path(Capybara.save_path) if Capybara.save_path
36
37
 
37
- ENV["FERRUM_DEBUG"] = "true" if ENV["CUPRITE_DEBUG"]
38
+ # It's set for debug() to make devtools tab open correctly.
39
+ @options[:browser_options] ||= {}
40
+ unless @options[:browser_options][:"remote-allow-origins"]
41
+ @options[:browser_options].merge!("remote-allow-origins": "*")
42
+ end
38
43
 
39
44
  super()
40
45
  end
@@ -64,6 +69,10 @@ module Capybara
64
69
  evaluate_script("document.title")
65
70
  end
66
71
 
72
+ def active_element
73
+ Node.new(self, browser.active_element)
74
+ end
75
+
67
76
  def find_xpath(selector)
68
77
  find(:xpath, selector)
69
78
  end
@@ -109,7 +118,7 @@ module Capybara
109
118
  def open_new_window
110
119
  target = browser.default_context.create_target
111
120
  target.maybe_sleep_if_new_window
112
- target.page = Page.new(target.id, browser)
121
+ target.page = Page.new(target.client, context_id: target.context_id, target_id: target.id)
113
122
  target.page
114
123
  end
115
124
 
@@ -242,7 +251,8 @@ module Capybara
242
251
 
243
252
  def remove_cookie(name, **options)
244
253
  options[:domain] = default_domain if options.empty?
245
- browser.cookies.remove(**options.merge(name: name))
254
+ options = options.merge(name: name)
255
+ browser.cookies.remove(**options)
246
256
  end
247
257
 
248
258
  def clear_cookies
@@ -265,7 +275,12 @@ module Capybara
265
275
  alias authorize basic_authorize
266
276
 
267
277
  def debug_url
268
- "http://#{browser.process.host}:#{browser.process.port}"
278
+ response = JSON.parse(Net::HTTP.get(URI(build_remote_debug_url(path: "/json"))))
279
+
280
+ devtools_frontend_path = response[0]&.[]("devtoolsFrontendUrl")
281
+ raise "Could not generate debug url for remote debugging session" unless devtools_frontend_path
282
+
283
+ build_remote_debug_url(path: devtools_frontend_path)
269
284
  end
270
285
 
271
286
  def debug(binding = nil)
@@ -363,6 +378,10 @@ module Capybara
363
378
 
364
379
  private
365
380
 
381
+ def build_remote_debug_url(path:)
382
+ "http://#{browser.process.host}:#{browser.process.port}#{path}"
383
+ end
384
+
366
385
  def default_domain
367
386
  if @started
368
387
  URI.parse(browser.current_url).host
@@ -84,7 +84,6 @@ class Cuprite {
84
84
  return true;
85
85
  }
86
86
 
87
-
88
87
  isDisabled(node) {
89
88
  let xpath = "parent::optgroup[@disabled] | \
90
89
  ancestor::select[@disabled] | \
@@ -116,6 +115,35 @@ class Cuprite {
116
115
  return `//${selectors.join("/")}`;
117
116
  }
118
117
 
118
+ /**
119
+ * Returns true if the node is obscured in the viewport.
120
+ *
121
+ * @param {Element} node
122
+ * @return {boolean} true if the node is obscured, false otherwise
123
+ */
124
+ isObscured(node) {
125
+ let win = window;
126
+ let rect = node.getBoundingClientRect();
127
+ let px = rect.left + rect.width / 2;
128
+ let py = rect.top + rect.height / 2;
129
+
130
+ while (win) {
131
+ let topNode = win.document.elementFromPoint(px, py);
132
+
133
+ if (node !== topNode && !node.contains(topNode)) return true;
134
+
135
+ node = win.frameElement;
136
+ if (!node) return false;
137
+
138
+ rect = node.getBoundingClientRect();
139
+ px = rect.left + px;
140
+ py = rect.top + py;
141
+ win = win.parent;
142
+ }
143
+
144
+ return false;
145
+ }
146
+
119
147
  set(node, value) {
120
148
  if (node.readOnly) return;
121
149
 
@@ -344,10 +372,24 @@ class Cuprite {
344
372
 
345
373
  _isInViewport(node) {
346
374
  let rect = node.getBoundingClientRect();
347
- return rect.top >= 0 &&
348
- rect.left >= 0 &&
349
- rect.bottom <= window.innerHeight &&
350
- rect.right <= window.innerWidth;
375
+
376
+ let inViewport = rect.top >= 0 &&
377
+ rect.left >= 0 &&
378
+ rect.bottom <= window.innerHeight &&
379
+ rect.right <= window.innerWidth;
380
+
381
+ if (inViewport) {
382
+ // check if obscured by another element
383
+ let x = rect.width/2;
384
+ let y = rect.height/2 ;
385
+
386
+ let px = rect.left + x,
387
+ py = rect.top + y,
388
+ e = document.elementFromPoint(px, py);
389
+ return node == e;
390
+ }
391
+
392
+ return false;
351
393
  }
352
394
 
353
395
  select(node, value) {
@@ -356,12 +398,13 @@ class Cuprite {
356
398
  } else if (value == false && !node.parentNode.multiple) {
357
399
  return false;
358
400
  } else {
359
- this.trigger(node.parentNode, "focus");
401
+ let parentNode = node.parentNode;
402
+ this.trigger(parentNode, "focus");
360
403
 
361
404
  node.selected = value;
362
405
  this.changed(node);
363
406
 
364
- this.trigger(node.parentNode, "blur");
407
+ this.trigger(parentNode, "blur");
365
408
  return true;
366
409
  }
367
410
  }
@@ -110,7 +110,7 @@ module Capybara
110
110
  command(:set, value.to_s)
111
111
  elsif self[:isContentEditable]
112
112
  command(:delete_text)
113
- send_keys(value.to_s)
113
+ click.type(value.to_s)
114
114
  end
115
115
  end
116
116
 
@@ -161,14 +161,16 @@ module Capybara
161
161
 
162
162
  def drag_to(other, **options)
163
163
  options[:steps] ||= 1
164
+ options[:scroll] = true unless options.key?(:scroll)
164
165
 
165
- command(:drag, other.node, options[:steps])
166
+ command(:drag, other.node, options[:steps], options[:delay], options[:scroll])
166
167
  end
167
168
 
168
169
  def drag_by(x, y, **options)
169
170
  options[:steps] ||= 1
171
+ options[:scroll] = true unless options.key?(:scroll)
170
172
 
171
- command(:drag_by, x, y, options[:steps])
173
+ command(:drag_by, x, y, options[:steps], options[:delay], options[:scroll])
172
174
  end
173
175
 
174
176
  def trigger(event)
@@ -211,6 +213,10 @@ module Capybara
211
213
  command(:path)
212
214
  end
213
215
 
216
+ def obscured?
217
+ command(:obscured?)
218
+ end
219
+
214
220
  def inspect
215
221
  %(#<#{self.class} @node=#{@node.inspect}>)
216
222
  end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ferrum
4
+ class Browser
5
+ class Options
6
+ attr_writer :window_size
7
+ attr_accessor :url_blacklist, :url_whitelist
8
+
9
+ def reset_window_size
10
+ @window_size = @options[:window_size]
11
+ end
12
+ end
13
+ end
14
+ end
@@ -4,6 +4,12 @@ require "forwardable"
4
4
 
5
5
  module Capybara
6
6
  module Cuprite
7
+ class ClosedPage
8
+ def closed?
9
+ true
10
+ end
11
+ end
12
+
7
13
  class Page < Ferrum::Page
8
14
  MODAL_WAIT = ENV.fetch("CUPRITE_MODAL_WAIT", 0.05).to_f
9
15
  TRIGGER_CLICK_WAIT = ENV.fetch("CUPRITE_TRIGGER_CLICK_WAIT", 0.1).to_f
@@ -13,7 +19,7 @@ module Capybara
13
19
  current_url current_title body execution_id execution_id!
14
20
  evaluate evaluate_on evaluate_async execute] => :active_frame
15
21
 
16
- def initialize(*args)
22
+ def initialize(...)
17
23
  @frame_stack = []
18
24
  @accept_modal = []
19
25
  @modal_messages = []
@@ -70,17 +76,17 @@ module Capybara
70
76
 
71
77
  def find_modal(options)
72
78
  start = Ferrum::Utils::ElapsedTime.monotonic_time
73
- timeout = options.fetch(:wait, browser.timeout)
74
79
  expect_text = options[:text]
75
80
  expect_regexp = expect_text.is_a?(Regexp) ? expect_text : Regexp.escape(expect_text.to_s)
76
81
  not_found_msg = "Unable to find modal dialog"
77
82
  not_found_msg += " with #{expect_text}" if expect_text
83
+ wait = options.fetch(:wait, timeout)
78
84
 
79
85
  begin
80
86
  modal_text = @modal_messages.shift
81
87
  raise Capybara::ModalNotFound if modal_text.nil? || (expect_text && !modal_text.match(expect_regexp))
82
88
  rescue Capybara::ModalNotFound => e
83
- raise e, not_found_msg if Ferrum::Utils::ElapsedTime.timeout?(start, timeout)
89
+ raise e, not_found_msg if Ferrum::Utils::ElapsedTime.timeout?(start, wait)
84
90
 
85
91
  sleep(MODAL_WAIT)
86
92
  retry
@@ -117,7 +123,6 @@ module Capybara
117
123
  @frame_stack = []
118
124
  else
119
125
  @frame_stack << handle
120
- inject_extensions
121
126
  end
122
127
  end
123
128
 
@@ -129,15 +134,22 @@ module Capybara
129
134
  active_frame.current_title
130
135
  end
131
136
 
137
+ def closed?
138
+ false
139
+ end
140
+
132
141
  private
133
142
 
134
143
  def prepare_page
135
144
  super
136
145
 
137
- if @browser.url_blacklist.any?
138
- network.blacklist = @browser.url_blacklist
139
- elsif @browser.url_whitelist.any?
140
- network.whitelist = @browser.url_whitelist
146
+ width, height = @options.window_size
147
+ resize(width: width, height: height)
148
+
149
+ if @options.url_blacklist.any?
150
+ network.blacklist = @options.url_blacklist
151
+ elsif @options.url_whitelist.any?
152
+ network.whitelist = @options.url_whitelist
141
153
  end
142
154
 
143
155
  on("Page.javascriptDialogOpening") do |params|
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Capybara
4
4
  module Cuprite
5
- VERSION = "0.15"
5
+ VERSION = "0.16"
6
6
  end
7
7
  end
@@ -1,10 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ ENV["FERRUM_DEBUG"] = "true" if ENV["CUPRITE_DEBUG"]
4
+
3
5
  require "ferrum"
4
6
  require "capybara"
5
7
  require "capybara/cuprite/driver"
6
8
  require "capybara/cuprite/browser"
7
9
  require "capybara/cuprite/page"
10
+ require "capybara/cuprite/options"
8
11
  require "capybara/cuprite/node"
9
12
  require "capybara/cuprite/errors"
10
13
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cuprite
3
3
  version: !ruby/object:Gem::Version
4
- version: '0.15'
4
+ version: '0.16'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dmitry Vorotilin
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-11-04 00:00:00.000000000 Z
11
+ date: 2025-05-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: capybara
@@ -30,14 +30,14 @@ dependencies:
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: 0.14.0
33
+ version: 0.16.0
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: 0.14.0
40
+ version: 0.16.0
41
41
  description: Cuprite is a driver for Capybara that allows you to run your tests on
42
42
  a headless Chrome browser
43
43
  email:
@@ -55,6 +55,7 @@ files:
55
55
  - lib/capybara/cuprite/errors.rb
56
56
  - lib/capybara/cuprite/javascripts/index.js
57
57
  - lib/capybara/cuprite/node.rb
58
+ - lib/capybara/cuprite/options.rb
58
59
  - lib/capybara/cuprite/page.rb
59
60
  - lib/capybara/cuprite/version.rb
60
61
  homepage: https://github.com/rubycdp/cuprite
@@ -81,7 +82,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
81
82
  - !ruby/object:Gem::Version
82
83
  version: '0'
83
84
  requirements: []
84
- rubygems_version: 3.4.13
85
+ rubygems_version: 3.5.22
85
86
  signing_key:
86
87
  specification_version: 4
87
88
  summary: Headless Chrome driver for Capybara