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.
- checksums.yaml +4 -4
- data/README.md +69 -37
- data/lib/capybara/cuprite/browser/deprecations.rb +26 -0
- data/lib/capybara/cuprite/browser/extensions.rb +59 -0
- data/lib/capybara/cuprite/browser.rb +28 -231
- data/lib/capybara/cuprite/deprecation.rb +13 -0
- data/lib/capybara/cuprite/devices.rb +188 -0
- data/lib/capybara/cuprite/driver/deprecations.rb +198 -0
- data/lib/capybara/cuprite/driver/extensions.rb +13 -0
- data/lib/capybara/cuprite/driver.rb +68 -201
- data/lib/capybara/cuprite/finder.rb +22 -0
- data/lib/capybara/cuprite/javascripts/drag.js +100 -103
- data/lib/capybara/cuprite/javascripts/index.js +511 -489
- data/lib/capybara/cuprite/node/deprecations.rb +43 -0
- data/lib/capybara/cuprite/node/extensions.rb +27 -0
- data/lib/capybara/cuprite/node.rb +140 -116
- data/lib/capybara/cuprite/options.rb +19 -0
- data/lib/capybara/cuprite/page/frames.rb +47 -0
- data/lib/capybara/cuprite/page/modals.rb +118 -0
- data/lib/capybara/cuprite/page.rb +9 -207
- data/lib/capybara/cuprite/version.rb +1 -1
- data/lib/capybara/cuprite.rb +1 -0
- metadata +16 -6
- data/lib/capybara/cuprite/cookie.rb +0 -47
|
@@ -1,233 +1,35 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "
|
|
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
|
-
|
|
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
|
-
|
|
20
|
-
|
|
21
|
-
evaluate evaluate_on evaluate_async execute] => :active_frame
|
|
11
|
+
include Frames
|
|
12
|
+
include Modals
|
|
22
13
|
|
|
23
|
-
def
|
|
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
|
data/lib/capybara/cuprite.rb
CHANGED
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.
|
|
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-
|
|
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.
|
|
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.
|
|
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/
|
|
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.
|
|
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
|