cuprite 0.12 → 0.15.1
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/LICENSE +1 -1
- data/README.md +14 -12
- data/lib/capybara/cuprite/browser.rb +196 -155
- data/lib/capybara/cuprite/cookie.rb +32 -32
- data/lib/capybara/cuprite/driver.rb +335 -363
- data/lib/capybara/cuprite/errors.rb +9 -8
- data/lib/capybara/cuprite/javascripts/index.js +47 -27
- data/lib/capybara/cuprite/node.rb +218 -224
- data/lib/capybara/cuprite/options.rb +14 -0
- data/lib/capybara/cuprite/page.rb +148 -154
- data/lib/capybara/cuprite/version.rb +1 -1
- data/lib/capybara/cuprite.rb +3 -0
- metadata +19 -145
@@ -2,198 +2,192 @@
|
|
2
2
|
|
3
3
|
require "forwardable"
|
4
4
|
|
5
|
-
module Capybara
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
delegate %i[at_css at_xpath css xpath
|
12
|
-
current_url current_title body execution_id
|
13
|
-
evaluate evaluate_on evaluate_async execute] => :active_frame
|
14
|
-
|
15
|
-
def initialize(*args)
|
16
|
-
@frame_stack = []
|
17
|
-
@accept_modal = []
|
18
|
-
@modal_messages = []
|
19
|
-
super
|
5
|
+
module Capybara
|
6
|
+
module Cuprite
|
7
|
+
class ClosedPage
|
8
|
+
def closed?
|
9
|
+
true
|
10
|
+
end
|
20
11
|
end
|
21
12
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
end
|
13
|
+
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
|
26
16
|
|
27
|
-
|
28
|
-
|
29
|
-
|
17
|
+
extend Forwardable
|
18
|
+
delegate %i[at_css at_xpath css xpath
|
19
|
+
current_url current_title body execution_id execution_id!
|
20
|
+
evaluate evaluate_on evaluate_async execute] => :active_frame
|
30
21
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
22
|
+
def initialize(...)
|
23
|
+
@frame_stack = []
|
24
|
+
@accept_modal = []
|
25
|
+
@modal_messages = []
|
26
|
+
@modal_response = nil
|
27
|
+
super
|
28
|
+
end
|
36
29
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
end
|
30
|
+
def set(node, value)
|
31
|
+
object_id = command("DOM.resolveNode", nodeId: node.node_id).dig("object", "objectId")
|
32
|
+
evaluate("_cuprite.set(arguments[0], arguments[1])", { "objectId" => object_id }, value)
|
33
|
+
end
|
42
34
|
|
43
|
-
|
44
|
-
|
45
|
-
before_click(node, "click")
|
46
|
-
node.click(mode: :left, keys: keys)
|
35
|
+
def select(node, value)
|
36
|
+
evaluate_on(node: node, expression: "_cuprite.select(this, #{value})")
|
47
37
|
end
|
48
38
|
|
49
|
-
|
50
|
-
|
39
|
+
def trigger(node, event)
|
40
|
+
options = {}
|
41
|
+
options.merge!(wait: TRIGGER_CLICK_WAIT) if event.to_s == "click" && TRIGGER_CLICK_WAIT.positive?
|
42
|
+
evaluate_on(node: node, expression: %(_cuprite.trigger(this, "#{event}")), **options)
|
43
|
+
end
|
51
44
|
|
52
|
-
|
53
|
-
|
54
|
-
|
45
|
+
def hover(node)
|
46
|
+
evaluate_on(node: node, expression: "_cuprite.scrollIntoViewport(this)")
|
47
|
+
x, y = find_position(node)
|
48
|
+
command("Input.dispatchMouseEvent", type: "mouseMoved", x: x, y: y)
|
49
|
+
end
|
55
50
|
|
56
|
-
|
57
|
-
|
58
|
-
|
51
|
+
def send_keys(node, keys)
|
52
|
+
unless evaluate_on(node: node, expression: %(_cuprite.containsSelection(this)))
|
53
|
+
before_click(node, "click")
|
54
|
+
node.click(mode: :left, keys: keys)
|
55
|
+
end
|
59
56
|
|
60
|
-
|
61
|
-
|
62
|
-
@modal_response = modal_response
|
63
|
-
end
|
57
|
+
keyboard.type(keys)
|
58
|
+
end
|
64
59
|
|
65
|
-
|
66
|
-
|
67
|
-
|
60
|
+
def accept_confirm
|
61
|
+
@accept_modal << true
|
62
|
+
end
|
68
63
|
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
expect_text = options[:text]
|
73
|
-
expect_regexp = expect_text.is_a?(Regexp) ? expect_text : Regexp.escape(expect_text.to_s)
|
74
|
-
not_found_msg = "Unable to find modal dialog"
|
75
|
-
not_found_msg += " with #{expect_text}" if expect_text
|
64
|
+
def dismiss_confirm
|
65
|
+
@accept_modal << false
|
66
|
+
end
|
76
67
|
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
rescue Capybara::ModalNotFound => e
|
81
|
-
raise e, not_found_msg if Ferrum.timeout?(start, timeout)
|
82
|
-
sleep(MODAL_WAIT)
|
83
|
-
retry
|
68
|
+
def accept_prompt(modal_response)
|
69
|
+
@accept_modal << true
|
70
|
+
@modal_response = modal_response
|
84
71
|
end
|
85
72
|
|
86
|
-
|
87
|
-
|
73
|
+
def dismiss_prompt
|
74
|
+
@accept_modal << false
|
75
|
+
end
|
88
76
|
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
77
|
+
def find_modal(options)
|
78
|
+
start = Ferrum::Utils::ElapsedTime.monotonic_time
|
79
|
+
expect_text = options[:text]
|
80
|
+
expect_regexp = expect_text.is_a?(Regexp) ? expect_text : Regexp.escape(expect_text.to_s)
|
81
|
+
not_found_msg = "Unable to find modal dialog"
|
82
|
+
not_found_msg += " with #{expect_text}" if expect_text
|
83
|
+
wait = options.fetch(:wait, timeout)
|
84
|
+
|
85
|
+
begin
|
86
|
+
modal_text = @modal_messages.shift
|
87
|
+
raise Capybara::ModalNotFound if modal_text.nil? || (expect_text && !modal_text.match(expect_regexp))
|
88
|
+
rescue Capybara::ModalNotFound => e
|
89
|
+
raise e, not_found_msg if Ferrum::Utils::ElapsedTime.timeout?(start, wait)
|
90
|
+
|
91
|
+
sleep(MODAL_WAIT)
|
92
|
+
retry
|
93
|
+
end
|
94
94
|
|
95
|
-
|
96
|
-
|
95
|
+
modal_text
|
96
|
+
end
|
97
97
|
|
98
|
-
|
99
|
-
|
100
|
-
|
98
|
+
def reset_modals
|
99
|
+
@accept_modal = []
|
100
|
+
@modal_response = nil
|
101
|
+
@modal_messages = []
|
102
|
+
end
|
101
103
|
|
102
|
-
|
103
|
-
|
104
|
-
true
|
105
|
-
rescue Ferrum::JavaScriptError => e
|
106
|
-
raise MouseEventFailed.new(e.message) if e.class_name == "MouseEventFailed"
|
107
|
-
end
|
104
|
+
def before_click(node, name, _keys = [], offset = {})
|
105
|
+
evaluate_on(node: node, expression: "_cuprite.scrollIntoViewport(this)")
|
108
106
|
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
107
|
+
# If offset is given it may go outside of the element and likely error
|
108
|
+
# will be raised that we detected another element at this position.
|
109
|
+
return true if offset[:x] || offset[:y]
|
110
|
+
|
111
|
+
x, y = find_position(node, **offset)
|
112
|
+
evaluate_on(node: node, expression: "_cuprite.mouseEventTest(this, '#{name}', #{x}, #{y})")
|
113
|
+
true
|
114
|
+
rescue Ferrum::JavaScriptError => e
|
115
|
+
raise MouseEventFailed, e.message if e.class_name == "MouseEventFailed"
|
118
116
|
end
|
119
|
-
end
|
120
117
|
|
121
|
-
|
122
|
-
|
123
|
-
|
118
|
+
def switch_to_frame(handle)
|
119
|
+
case handle
|
120
|
+
when :parent
|
121
|
+
@frame_stack.pop
|
122
|
+
when :top
|
123
|
+
@frame_stack = []
|
124
|
+
else
|
125
|
+
@frame_stack << handle
|
126
|
+
inject_extensions
|
127
|
+
end
|
128
|
+
end
|
124
129
|
|
125
|
-
|
126
|
-
|
127
|
-
|
130
|
+
def frame_name
|
131
|
+
evaluate("window.name")
|
132
|
+
end
|
128
133
|
|
129
|
-
|
134
|
+
def title
|
135
|
+
active_frame.current_title
|
136
|
+
end
|
130
137
|
|
131
|
-
|
132
|
-
|
138
|
+
def closed?
|
139
|
+
false
|
140
|
+
end
|
133
141
|
|
134
|
-
|
135
|
-
!Array(@browser.url_blacklist).empty?
|
142
|
+
private
|
136
143
|
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
else
|
148
|
-
request.abort and next
|
149
|
-
end
|
150
|
-
elsif index + 1 < total
|
151
|
-
# There are other callbacks that may handle this request
|
152
|
-
next
|
153
|
-
else
|
154
|
-
# If there are no callbacks then just continue
|
155
|
-
request.continue
|
144
|
+
def prepare_page
|
145
|
+
super
|
146
|
+
|
147
|
+
width, height = @options.window_size
|
148
|
+
resize(width: width, height: height)
|
149
|
+
|
150
|
+
if @options.url_blacklist.any?
|
151
|
+
network.blacklist = @options.url_blacklist
|
152
|
+
elsif @options.url_whitelist.any?
|
153
|
+
network.whitelist = @options.url_whitelist
|
156
154
|
end
|
157
|
-
end
|
158
155
|
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
response = params["defaultPrompt"]
|
156
|
+
on("Page.javascriptDialogOpening") do |params|
|
157
|
+
accept_modal = @accept_modal.last
|
158
|
+
if [true, false].include?(accept_modal)
|
159
|
+
@accept_modal.pop
|
160
|
+
@modal_messages << params["message"]
|
161
|
+
options = { accept: accept_modal }
|
162
|
+
response = @modal_response || params["defaultPrompt"]
|
163
|
+
else
|
164
|
+
with_text = params["message"] ? "with text `#{params['message']}` " : ""
|
165
|
+
warn "Modal window #{with_text}has been opened, but you didn't wrap " \
|
166
|
+
"your code into (`accept_prompt` | `dismiss_prompt` | " \
|
167
|
+
"`accept_confirm` | `dismiss_confirm` | `accept_alert`), " \
|
168
|
+
"accepting by default"
|
169
|
+
options = { accept: true }
|
170
|
+
response = params["defaultPrompt"]
|
171
|
+
end
|
176
172
|
options.merge!(promptText: response) if response
|
177
173
|
command("Page.handleJavaScriptDialog", **options)
|
178
174
|
end
|
179
175
|
end
|
180
|
-
end
|
181
176
|
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
else
|
177
|
+
def find_position(node, **options)
|
178
|
+
node.find_position(**options)
|
179
|
+
rescue Ferrum::BrowserError => e
|
180
|
+
raise MouseEventFailed, "MouseEventFailed: click, none, 0, 0" if e.message == "Could not compute content quads."
|
181
|
+
|
188
182
|
raise
|
189
183
|
end
|
190
|
-
end
|
191
184
|
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
185
|
+
def active_frame
|
186
|
+
if @frame_stack.empty?
|
187
|
+
main_frame
|
188
|
+
else
|
189
|
+
@frames[@frame_stack.last]
|
190
|
+
end
|
197
191
|
end
|
198
192
|
end
|
199
193
|
end
|
data/lib/capybara/cuprite.rb
CHANGED
@@ -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,155 +1,23 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cuprite
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 0.15.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dmitry Vorotilin
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2024-06-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: capybara
|
15
|
-
requirement: !ruby/object:Gem::Requirement
|
16
|
-
requirements:
|
17
|
-
- - ">="
|
18
|
-
- !ruby/object:Gem::Version
|
19
|
-
version: '2.1'
|
20
|
-
- - "<"
|
21
|
-
- !ruby/object:Gem::Version
|
22
|
-
version: '4'
|
23
|
-
type: :runtime
|
24
|
-
prerelease: false
|
25
|
-
version_requirements: !ruby/object:Gem::Requirement
|
26
|
-
requirements:
|
27
|
-
- - ">="
|
28
|
-
- !ruby/object:Gem::Version
|
29
|
-
version: '2.1'
|
30
|
-
- - "<"
|
31
|
-
- !ruby/object:Gem::Version
|
32
|
-
version: '4'
|
33
|
-
- !ruby/object:Gem::Dependency
|
34
|
-
name: ferrum
|
35
|
-
requirement: !ruby/object:Gem::Requirement
|
36
|
-
requirements:
|
37
|
-
- - "~>"
|
38
|
-
- !ruby/object:Gem::Version
|
39
|
-
version: 0.10.0
|
40
|
-
type: :runtime
|
41
|
-
prerelease: false
|
42
|
-
version_requirements: !ruby/object:Gem::Requirement
|
43
|
-
requirements:
|
44
|
-
- - "~>"
|
45
|
-
- !ruby/object:Gem::Version
|
46
|
-
version: 0.10.0
|
47
|
-
- !ruby/object:Gem::Dependency
|
48
|
-
name: image_size
|
49
|
-
requirement: !ruby/object:Gem::Requirement
|
50
|
-
requirements:
|
51
|
-
- - "~>"
|
52
|
-
- !ruby/object:Gem::Version
|
53
|
-
version: '2.0'
|
54
|
-
type: :development
|
55
|
-
prerelease: false
|
56
|
-
version_requirements: !ruby/object:Gem::Requirement
|
57
|
-
requirements:
|
58
|
-
- - "~>"
|
59
|
-
- !ruby/object:Gem::Version
|
60
|
-
version: '2.0'
|
61
|
-
- !ruby/object:Gem::Dependency
|
62
|
-
name: pdf-reader
|
63
|
-
requirement: !ruby/object:Gem::Requirement
|
64
|
-
requirements:
|
65
|
-
- - "~>"
|
66
|
-
- !ruby/object:Gem::Version
|
67
|
-
version: '2.1'
|
68
|
-
type: :development
|
69
|
-
prerelease: false
|
70
|
-
version_requirements: !ruby/object:Gem::Requirement
|
71
|
-
requirements:
|
72
|
-
- - "~>"
|
73
|
-
- !ruby/object:Gem::Version
|
74
|
-
version: '2.1'
|
75
|
-
- !ruby/object:Gem::Dependency
|
76
|
-
name: rake
|
77
|
-
requirement: !ruby/object:Gem::Requirement
|
78
|
-
requirements:
|
79
|
-
- - "~>"
|
80
|
-
- !ruby/object:Gem::Version
|
81
|
-
version: '12.3'
|
82
|
-
type: :development
|
83
|
-
prerelease: false
|
84
|
-
version_requirements: !ruby/object:Gem::Requirement
|
85
|
-
requirements:
|
86
|
-
- - "~>"
|
87
|
-
- !ruby/object:Gem::Version
|
88
|
-
version: '12.3'
|
89
|
-
- !ruby/object:Gem::Dependency
|
90
|
-
name: rspec
|
91
|
-
requirement: !ruby/object:Gem::Requirement
|
92
|
-
requirements:
|
93
|
-
- - "~>"
|
94
|
-
- !ruby/object:Gem::Version
|
95
|
-
version: '3.7'
|
96
|
-
type: :development
|
97
|
-
prerelease: false
|
98
|
-
version_requirements: !ruby/object:Gem::Requirement
|
99
|
-
requirements:
|
100
|
-
- - "~>"
|
101
|
-
- !ruby/object:Gem::Version
|
102
|
-
version: '3.7'
|
103
|
-
- !ruby/object:Gem::Dependency
|
104
|
-
name: sinatra
|
105
|
-
requirement: !ruby/object:Gem::Requirement
|
106
|
-
requirements:
|
107
|
-
- - "~>"
|
108
|
-
- !ruby/object:Gem::Version
|
109
|
-
version: '2.0'
|
110
|
-
type: :development
|
111
|
-
prerelease: false
|
112
|
-
version_requirements: !ruby/object:Gem::Requirement
|
113
|
-
requirements:
|
114
|
-
- - "~>"
|
115
|
-
- !ruby/object:Gem::Version
|
116
|
-
version: '2.0'
|
117
|
-
- !ruby/object:Gem::Dependency
|
118
|
-
name: launchy
|
119
|
-
requirement: !ruby/object:Gem::Requirement
|
120
|
-
requirements:
|
121
|
-
- - "~>"
|
122
|
-
- !ruby/object:Gem::Version
|
123
|
-
version: '2.4'
|
124
|
-
type: :development
|
125
|
-
prerelease: false
|
126
|
-
version_requirements: !ruby/object:Gem::Requirement
|
127
|
-
requirements:
|
128
|
-
- - "~>"
|
129
|
-
- !ruby/object:Gem::Version
|
130
|
-
version: '2.4'
|
131
|
-
- !ruby/object:Gem::Dependency
|
132
|
-
name: byebug
|
133
|
-
requirement: !ruby/object:Gem::Requirement
|
134
|
-
requirements:
|
135
|
-
- - "~>"
|
136
|
-
- !ruby/object:Gem::Version
|
137
|
-
version: '10.0'
|
138
|
-
type: :development
|
139
|
-
prerelease: false
|
140
|
-
version_requirements: !ruby/object:Gem::Requirement
|
141
|
-
requirements:
|
142
|
-
- - "~>"
|
143
|
-
- !ruby/object:Gem::Version
|
144
|
-
version: '10.0'
|
145
|
-
- !ruby/object:Gem::Dependency
|
146
|
-
name: puma
|
147
15
|
requirement: !ruby/object:Gem::Requirement
|
148
16
|
requirements:
|
149
17
|
- - "~>"
|
150
18
|
- !ruby/object:Gem::Version
|
151
19
|
version: '3.0'
|
152
|
-
type: :
|
20
|
+
type: :runtime
|
153
21
|
prerelease: false
|
154
22
|
version_requirements: !ruby/object:Gem::Requirement
|
155
23
|
requirements:
|
@@ -157,19 +25,19 @@ dependencies:
|
|
157
25
|
- !ruby/object:Gem::Version
|
158
26
|
version: '3.0'
|
159
27
|
- !ruby/object:Gem::Dependency
|
160
|
-
name:
|
28
|
+
name: ferrum
|
161
29
|
requirement: !ruby/object:Gem::Requirement
|
162
30
|
requirements:
|
163
31
|
- - "~>"
|
164
32
|
- !ruby/object:Gem::Version
|
165
|
-
version:
|
166
|
-
type: :
|
33
|
+
version: 0.15.0
|
34
|
+
type: :runtime
|
167
35
|
prerelease: false
|
168
36
|
version_requirements: !ruby/object:Gem::Requirement
|
169
37
|
requirements:
|
170
38
|
- - "~>"
|
171
39
|
- !ruby/object:Gem::Version
|
172
|
-
version:
|
40
|
+
version: 0.15.0
|
173
41
|
description: Cuprite is a driver for Capybara that allows you to run your tests on
|
174
42
|
a headless Chrome browser
|
175
43
|
email:
|
@@ -187,13 +55,19 @@ files:
|
|
187
55
|
- lib/capybara/cuprite/errors.rb
|
188
56
|
- lib/capybara/cuprite/javascripts/index.js
|
189
57
|
- lib/capybara/cuprite/node.rb
|
58
|
+
- lib/capybara/cuprite/options.rb
|
190
59
|
- lib/capybara/cuprite/page.rb
|
191
60
|
- lib/capybara/cuprite/version.rb
|
192
61
|
homepage: https://github.com/rubycdp/cuprite
|
193
62
|
licenses:
|
194
63
|
- MIT
|
195
|
-
metadata:
|
196
|
-
|
64
|
+
metadata:
|
65
|
+
homepage_uri: https://cuprite.rubycdp.com/
|
66
|
+
bug_tracker_uri: https://github.com/rubycdp/cuprite/issues
|
67
|
+
documentation_uri: https://github.com/rubycdp/cuprite/blob/main/README.md
|
68
|
+
source_code_uri: https://github.com/rubycdp/cuprite
|
69
|
+
rubygems_mfa_required: 'true'
|
70
|
+
post_install_message:
|
197
71
|
rdoc_options: []
|
198
72
|
require_paths:
|
199
73
|
- lib
|
@@ -201,15 +75,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
201
75
|
requirements:
|
202
76
|
- - ">="
|
203
77
|
- !ruby/object:Gem::Version
|
204
|
-
version: 2.
|
78
|
+
version: 2.7.0
|
205
79
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
206
80
|
requirements:
|
207
81
|
- - ">="
|
208
82
|
- !ruby/object:Gem::Version
|
209
83
|
version: '0'
|
210
84
|
requirements: []
|
211
|
-
rubygems_version: 3.
|
212
|
-
signing_key:
|
85
|
+
rubygems_version: 3.5.11
|
86
|
+
signing_key:
|
213
87
|
specification_version: 4
|
214
88
|
summary: Headless Chrome driver for Capybara
|
215
89
|
test_files: []
|