cuprite 0.18 → 0.20

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.
@@ -1,233 +1,35 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "forwardable"
3
+ require "capybara/cuprite/page/frames"
4
+ require "capybara/cuprite/page/modals"
4
5
 
5
6
  module Capybara
6
7
  module Cuprite
7
- class ClosedPage
8
- def closed?
9
- true
10
- end
11
- end
12
-
13
8
  class Page < Ferrum::Page
14
- MODAL_WAIT = ENV.fetch("CUPRITE_MODAL_WAIT", 0.05).to_f
15
- TRIGGER_CLICK_WAIT = ENV.fetch("CUPRITE_TRIGGER_CLICK_WAIT", 0.1).to_f
16
-
17
- extend Forwardable
9
+ EXTENSION_JS = File.read(Driver::EXTENSION).freeze
18
10
 
19
- delegate %i[at_css at_xpath css xpath
20
- current_url current_title body execution_id execution_id!
21
- evaluate evaluate_on evaluate_async execute] => :active_frame
11
+ include Frames
12
+ include Modals
22
13
 
23
- def initialize(...)
24
- @frame_stack = []
25
- @accept_modal = []
26
- @modal_messages = []
27
- @modal_response = nil
28
- @unhandled_modal_error = nil
14
+ def set_viewport(width: 0, height: 0, scale_factor: @options.scale_factor, mobile: @options.mobile)
29
15
  super
30
16
  end
31
17
 
32
- # Keep a handle to Ferrum's own implementation before overriding it
33
- # below, so answering a dialog (see `handle_javascript_dialog`) can
34
- # bypass our override.
35
- alias ferrum_command command
36
-
37
- # The `Page.javascriptDialogOpening` event is handled on Ferrum's
38
- # background CDP dispatcher thread, so raising there wouldn't reach
39
- # the caller and would permanently kill that thread instead. The
40
- # dialog is always accepted immediately from that thread, and the
41
- # error (if any) is stashed here to be raised from the main thread
42
- # the next time it makes a command round trip.
43
- def command(...)
44
- raise_pending_unhandled_modal_error! { super }
45
- end
46
-
47
- def set(node, value)
48
- object_id = command("DOM.resolveNode", nodeId: node.node_id).dig("object", "objectId")
49
- evaluate("_cuprite.set(arguments[0], arguments[1])", { "objectId" => object_id }, value)
50
- end
51
-
52
- def select(node, value)
53
- evaluate_on(node: node, expression: "_cuprite.select(this, #{value})")
54
- end
55
-
56
- def trigger(node, event)
57
- options = {}
58
- options.merge!(wait: TRIGGER_CLICK_WAIT) if event.to_s == "click" && TRIGGER_CLICK_WAIT.positive?
59
- evaluate_on(node: node, expression: %(_cuprite.trigger(this, "#{event}")), **options)
60
- end
61
-
62
- def hover(node)
63
- evaluate_on(node: node, expression: "_cuprite.scrollIntoViewport(this)")
64
- x, y = find_position(node)
65
- command("Input.dispatchMouseEvent", type: "mouseMoved", x: x, y: y)
66
- end
67
-
68
- def send_keys(node, keys)
69
- unless evaluate_on(node: node, expression: %(_cuprite.containsSelection(this)))
70
- before_click(node, "click")
71
- node.click(mode: :left, keys: keys)
72
- end
73
-
74
- keyboard.type(keys)
75
- end
76
-
77
- def accept_confirm
78
- @accept_modal << true
79
- end
80
-
81
- def dismiss_confirm
82
- @accept_modal << false
83
- end
84
-
85
- def accept_prompt(modal_response)
86
- @accept_modal << true
87
- @modal_response = modal_response
88
- end
89
-
90
- def dismiss_prompt
91
- @accept_modal << false
92
- end
93
-
94
- def find_modal(options)
95
- start = Ferrum::Utils::ElapsedTime.monotonic_time
96
- expect_text = options[:text]
97
- expect_regexp = expect_text.is_a?(Regexp) ? expect_text : Regexp.escape(expect_text.to_s)
98
- not_found_msg = "Unable to find modal dialog"
99
- not_found_msg += " with #{expect_text}" if expect_text
100
- wait = options.fetch(:wait, timeout)
101
-
102
- begin
103
- modal_text = @modal_messages.shift
104
- raise Capybara::ModalNotFound if modal_text.nil? || (expect_text && !modal_text.match(expect_regexp))
105
- rescue Capybara::ModalNotFound => e
106
- raise e, not_found_msg if Ferrum::Utils::ElapsedTime.timeout?(start, wait)
107
-
108
- sleep(MODAL_WAIT)
109
- retry
110
- end
111
-
112
- modal_text
113
- end
114
-
115
- def reset_modals
116
- @accept_modal = []
117
- @modal_response = nil
118
- @modal_messages = []
119
- @unhandled_modal_error = nil
120
- end
121
-
122
- def before_click(node, name, _keys = [], offset = {})
123
- evaluate_on(node: node, expression: "_cuprite.scrollIntoViewport(this)")
124
-
125
- # If offset is given it may go outside of the element and likely error
126
- # will be raised that we detected another element at this position.
127
- return true if offset[:x] || offset[:y]
128
-
129
- x, y = find_position(node, **offset)
130
- evaluate_on(node: node, expression: "_cuprite.mouseEventTest(this, '#{name}', #{x}, #{y})")
131
- true
132
- rescue Ferrum::JavaScriptError => e
133
- raise MouseEventFailed, e.message if e.class_name == "MouseEventFailed"
134
- end
135
-
136
- def switch_to_frame(handle)
137
- case handle
138
- when :parent
139
- @frame_stack.pop
140
- when :top
141
- @frame_stack = []
142
- else
143
- @frame_stack << handle
144
- end
145
- end
146
-
147
- def frame_name
148
- evaluate("window.name")
149
- end
150
-
151
- def title
152
- active_frame.current_title
153
- end
154
-
155
- def closed?
156
- false
157
- end
158
-
159
18
  private
160
19
 
161
- def raise_pending_unhandled_modal_error!
162
- error = @unhandled_modal_error
163
- @unhandled_modal_error = nil
164
- raise error if error
165
-
166
- yield
167
- ensure
168
- error = @unhandled_modal_error
169
- @unhandled_modal_error = nil
170
- raise error if error
171
- end
172
-
173
20
  def prepare_page
174
21
  super
22
+ execute(EXTENSION_JS)
175
23
 
176
24
  width, height = @options.window_size
177
- resize(width: width, height: height)
25
+ width && height ? resize(width: width, height: height) : set_viewport
26
+ command("Network.setUserAgentOverride", userAgent: default_user_agent) if @options.device_user_agent
178
27
 
179
28
  if @options.url_blacklist.any?
180
29
  network.blacklist = @options.url_blacklist
181
30
  elsif @options.url_whitelist.any?
182
31
  network.whitelist = @options.url_whitelist
183
32
  end
184
-
185
- on("Page.javascriptDialogOpening") do |params|
186
- accept_modal = @accept_modal.last
187
- unhandled_modal_error = nil
188
-
189
- if [true, false].include?(accept_modal)
190
- @accept_modal.pop
191
- @modal_messages << params["message"]
192
- options = { accept: accept_modal }
193
- response = @modal_response || params["defaultPrompt"]
194
- else
195
- with_text = params["message"] ? "with text `#{params['message']}` " : ""
196
- message = "Modal window #{with_text}has been opened, but you didn't wrap " \
197
- "your code into (`accept_prompt` | `dismiss_prompt` | " \
198
- "`accept_confirm` | `dismiss_confirm` | `accept_alert`), " \
199
- "accepting by default"
200
-
201
- if @options.raise_on_unhandled_modal
202
- unhandled_modal_error = UnhandledModalError.new(message)
203
- else
204
- warn message
205
- end
206
-
207
- options = { accept: true }
208
- response = params["defaultPrompt"]
209
- end
210
- options.merge!(promptText: response) if response
211
- ferrum_command("Page.handleJavaScriptDialog", **options)
212
-
213
- @unhandled_modal_error = unhandled_modal_error if unhandled_modal_error
214
- end
215
- end
216
-
217
- def find_position(node, **options)
218
- node.find_position(**options)
219
- rescue Ferrum::BrowserError => e
220
- raise MouseEventFailed, "MouseEventFailed: click, none, 0, 0" if e.message == "Could not compute content quads."
221
-
222
- raise
223
- end
224
-
225
- def active_frame
226
- if @frame_stack.empty?
227
- main_frame
228
- else
229
- @frames[@frame_stack.last]
230
- end
231
33
  end
232
34
  end
233
35
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Capybara
4
4
  module Cuprite
5
- VERSION = "0.18"
5
+ VERSION = "0.20"
6
6
  end
7
7
  end
@@ -8,6 +8,7 @@ require "capybara/cuprite/driver"
8
8
  require "capybara/cuprite/browser"
9
9
  require "capybara/cuprite/page"
10
10
  require "capybara/cuprite/options"
11
+ require "capybara/cuprite/devices"
11
12
  require "capybara/cuprite/node"
12
13
  require "capybara/cuprite/errors"
13
14
 
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.18'
4
+ version: '0.20'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dmitry Vorotilin
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-09-03 00:00:00.000000000 Z
11
+ date: 2026-10-30 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.18.0
33
+ version: 0.20.1
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.18.0
40
+ version: 0.20.1
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:
@@ -50,14 +50,24 @@ files:
50
50
  - README.md
51
51
  - lib/capybara/cuprite.rb
52
52
  - lib/capybara/cuprite/browser.rb
53
- - lib/capybara/cuprite/cookie.rb
53
+ - lib/capybara/cuprite/browser/deprecations.rb
54
+ - lib/capybara/cuprite/browser/extensions.rb
55
+ - lib/capybara/cuprite/deprecation.rb
56
+ - lib/capybara/cuprite/devices.rb
54
57
  - lib/capybara/cuprite/driver.rb
58
+ - lib/capybara/cuprite/driver/deprecations.rb
59
+ - lib/capybara/cuprite/driver/extensions.rb
55
60
  - lib/capybara/cuprite/errors.rb
61
+ - lib/capybara/cuprite/finder.rb
56
62
  - lib/capybara/cuprite/javascripts/drag.js
57
63
  - lib/capybara/cuprite/javascripts/index.js
58
64
  - lib/capybara/cuprite/node.rb
65
+ - lib/capybara/cuprite/node/deprecations.rb
66
+ - lib/capybara/cuprite/node/extensions.rb
59
67
  - lib/capybara/cuprite/options.rb
60
68
  - lib/capybara/cuprite/page.rb
69
+ - lib/capybara/cuprite/page/frames.rb
70
+ - lib/capybara/cuprite/page/modals.rb
61
71
  - lib/capybara/cuprite/version.rb
62
72
  homepage: https://github.com/rubycdp/cuprite
63
73
  licenses:
@@ -76,7 +86,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
76
86
  requirements:
77
87
  - - ">="
78
88
  - !ruby/object:Gem::Version
79
- version: '3.1'
89
+ version: '3.2'
80
90
  required_rubygems_version: !ruby/object:Gem::Requirement
81
91
  requirements:
82
92
  - - ">="
@@ -1,47 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Capybara
4
- module Cuprite
5
- class Cookie
6
- def initialize(attributes)
7
- @attributes = attributes
8
- end
9
-
10
- def name
11
- @attributes["name"]
12
- end
13
-
14
- def value
15
- @attributes["value"]
16
- end
17
-
18
- def domain
19
- @attributes["domain"]
20
- end
21
-
22
- def path
23
- @attributes["path"]
24
- end
25
-
26
- def size
27
- @attributes["size"]
28
- end
29
-
30
- def secure?
31
- @attributes["secure"]
32
- end
33
-
34
- def httponly?
35
- @attributes["httpOnly"]
36
- end
37
-
38
- def session?
39
- @attributes["session"]
40
- end
41
-
42
- def expires
43
- Time.at(@attributes["expires"]) if @attributes["expires"].positive?
44
- end
45
- end
46
- end
47
- end