cuprite 0.6.0 → 0.7.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/README.md +100 -67
- data/lib/capybara/cuprite/browser.rb +66 -224
- data/lib/capybara/cuprite/driver.rb +101 -48
- data/lib/capybara/cuprite/errors.rb +1 -64
- data/lib/capybara/cuprite/{browser/javascripts → javascripts}/index.js +26 -20
- data/lib/capybara/cuprite/node.rb +37 -31
- data/lib/capybara/cuprite/page.rb +166 -0
- data/lib/capybara/cuprite/version.rb +1 -1
- data/lib/capybara/cuprite.rb +8 -21
- metadata +8 -42
- data/lib/capybara/cuprite/browser/client.rb +0 -74
- data/lib/capybara/cuprite/browser/dom.rb +0 -50
- data/lib/capybara/cuprite/browser/frame.rb +0 -115
- data/lib/capybara/cuprite/browser/input.json +0 -1341
- data/lib/capybara/cuprite/browser/input.rb +0 -200
- data/lib/capybara/cuprite/browser/net.rb +0 -90
- data/lib/capybara/cuprite/browser/page.rb +0 -378
- data/lib/capybara/cuprite/browser/process.rb +0 -223
- data/lib/capybara/cuprite/browser/runtime.rb +0 -182
- data/lib/capybara/cuprite/browser/targets.rb +0 -129
- data/lib/capybara/cuprite/browser/web_socket.rb +0 -69
- data/lib/capybara/cuprite/network/error.rb +0 -25
- data/lib/capybara/cuprite/network/request.rb +0 -33
- data/lib/capybara/cuprite/network/response.rb +0 -44
@@ -1,21 +1,31 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "uri"
|
4
|
-
|
5
4
|
require "forwardable"
|
6
5
|
|
7
6
|
module Capybara::Cuprite
|
8
7
|
class Driver < Capybara::Driver::Base
|
8
|
+
DEFAULT_MAXIMIZE_SCREEN_SIZE = [1366, 768].freeze
|
9
|
+
EXTENSION = File.expand_path("javascripts/index.js", __dir__)
|
10
|
+
|
9
11
|
extend Forwardable
|
10
12
|
|
11
13
|
delegate %i(restart quit status_code timeout timeout=) => :browser
|
12
14
|
|
13
|
-
attr_reader :app, :options
|
15
|
+
attr_reader :app, :options, :screen_size
|
14
16
|
|
15
17
|
def initialize(app, options = {})
|
16
18
|
@app = app
|
17
|
-
@options = options
|
19
|
+
@options = options.dup
|
18
20
|
@started = false
|
21
|
+
|
22
|
+
@options[:extensions] ||= []
|
23
|
+
@options[:extensions] << EXTENSION
|
24
|
+
|
25
|
+
@screen_size = @options.delete(:screen_size)
|
26
|
+
@screen_size ||= DEFAULT_MAXIMIZE_SCREEN_SIZE
|
27
|
+
|
28
|
+
@options[:save_path] = Capybara.save_path.to_s if Capybara.save_path
|
19
29
|
end
|
20
30
|
|
21
31
|
def needs_server?
|
@@ -23,7 +33,7 @@ module Capybara::Cuprite
|
|
23
33
|
end
|
24
34
|
|
25
35
|
def browser
|
26
|
-
@browser ||= Browser.
|
36
|
+
@browser ||= Browser.new(@options)
|
27
37
|
end
|
28
38
|
|
29
39
|
def visit(url)
|
@@ -64,20 +74,20 @@ module Capybara::Cuprite
|
|
64
74
|
browser.frame_title
|
65
75
|
end
|
66
76
|
|
67
|
-
def find(method, selector)
|
68
|
-
browser.find(method, selector).map { |target_id, node| Node.new(self, target_id, node) }
|
69
|
-
end
|
70
|
-
|
71
77
|
def find_xpath(selector)
|
72
|
-
find
|
78
|
+
find(:xpath, selector)
|
73
79
|
end
|
74
80
|
|
75
81
|
def find_css(selector)
|
76
|
-
find
|
82
|
+
find(:css, selector)
|
83
|
+
end
|
84
|
+
|
85
|
+
def find(method, selector)
|
86
|
+
browser.find(method, selector).map { |native| Node.new(self, native) }
|
77
87
|
end
|
78
88
|
|
79
89
|
def click(x, y)
|
80
|
-
browser.
|
90
|
+
browser.mouse.click(x: x, y: y)
|
81
91
|
end
|
82
92
|
|
83
93
|
def evaluate_script(script, *args)
|
@@ -96,7 +106,14 @@ module Capybara::Cuprite
|
|
96
106
|
end
|
97
107
|
|
98
108
|
def switch_to_frame(locator)
|
99
|
-
|
109
|
+
handle = case locator
|
110
|
+
when Capybara::Node::Element
|
111
|
+
locator.native.description["frameId"]
|
112
|
+
when :parent, :top
|
113
|
+
locator
|
114
|
+
end
|
115
|
+
|
116
|
+
browser.switch_to_frame(handle)
|
100
117
|
end
|
101
118
|
|
102
119
|
def current_window_handle
|
@@ -124,31 +141,47 @@ module Capybara::Cuprite
|
|
124
141
|
end
|
125
142
|
|
126
143
|
def no_such_window_error
|
127
|
-
NoSuchWindowError
|
144
|
+
Ferrum::NoSuchWindowError
|
128
145
|
end
|
129
146
|
|
130
147
|
def reset!
|
131
|
-
|
148
|
+
@zoom_factor = nil
|
149
|
+
@paper_size = nil
|
132
150
|
browser.url_blacklist = @options[:url_blacklist]
|
133
151
|
browser.url_whitelist = @options[:url_whitelist]
|
152
|
+
browser.reset
|
134
153
|
@started = false
|
135
154
|
end
|
136
155
|
|
137
156
|
def save_screenshot(path, options = {})
|
138
|
-
|
157
|
+
options[:scale] = @zoom_factor if @zoom_factor
|
158
|
+
|
159
|
+
if pdf?(path, options)
|
160
|
+
options[:paperWidth] = @paper_size[:width].to_f if @paper_size
|
161
|
+
options[:paperHeight] = @paper_size[:height].to_f if @paper_size
|
162
|
+
browser.pdf(path: path, **options)
|
163
|
+
else
|
164
|
+
browser.screenshot(path: path, **options)
|
165
|
+
end
|
139
166
|
end
|
140
167
|
alias_method :render, :save_screenshot
|
141
168
|
|
142
169
|
def render_base64(format = :png, options = {})
|
143
|
-
|
170
|
+
if pdf?(nil, options)
|
171
|
+
options[:paperWidth] = @paper_size[:width].to_f if @paper_size
|
172
|
+
options[:paperHeight] = @paper_size[:height].to_f if @paper_size
|
173
|
+
browser.pdf(encoding: :base64, **options)
|
174
|
+
else
|
175
|
+
browser.screenshot(format: format, encoding: :base64, **options)
|
176
|
+
end
|
144
177
|
end
|
145
178
|
|
146
|
-
def
|
147
|
-
|
179
|
+
def zoom_factor=(value)
|
180
|
+
@zoom_factor = value.to_f
|
148
181
|
end
|
149
182
|
|
150
|
-
def
|
151
|
-
|
183
|
+
def paper_size=(value)
|
184
|
+
@paper_size = value
|
152
185
|
end
|
153
186
|
|
154
187
|
def resize(width, height)
|
@@ -179,15 +212,25 @@ module Capybara::Cuprite
|
|
179
212
|
end
|
180
213
|
|
181
214
|
def scroll_to(left, top)
|
182
|
-
browser.scroll_to(left, top)
|
215
|
+
browser.mouse.scroll_to(left, top)
|
183
216
|
end
|
184
217
|
|
185
218
|
def network_traffic(type = nil)
|
186
|
-
browser.
|
219
|
+
traffic = browser.network.traffic
|
220
|
+
|
221
|
+
case type.to_s
|
222
|
+
when "all"
|
223
|
+
traffic
|
224
|
+
when "blocked"
|
225
|
+
traffic.select(&:blocked?)
|
226
|
+
else
|
227
|
+
# when request isn't blocked
|
228
|
+
traffic.reject(&:blocked?)
|
229
|
+
end
|
187
230
|
end
|
188
231
|
|
189
232
|
def clear_network_traffic
|
190
|
-
browser.
|
233
|
+
browser.network.clear(:traffic)
|
191
234
|
end
|
192
235
|
|
193
236
|
def set_proxy(ip, port, type = nil, user = nil, password = nil, bypass = nil)
|
@@ -195,31 +238,31 @@ module Capybara::Cuprite
|
|
195
238
|
server = type ? "#{type}=#{ip}:#{port}" : "#{ip}:#{port}"
|
196
239
|
@options[:browser_options].merge!("proxy-server" => server)
|
197
240
|
@options[:browser_options].merge!("proxy-bypass-list" => bypass) if bypass
|
198
|
-
browser.
|
241
|
+
browser.network.authorize(type: :proxy, user: user, password: password)
|
199
242
|
end
|
200
243
|
|
201
244
|
def headers
|
202
|
-
browser.headers
|
245
|
+
browser.headers.get
|
203
246
|
end
|
204
247
|
|
205
248
|
def headers=(headers)
|
206
|
-
browser.headers
|
249
|
+
browser.headers.set(headers)
|
207
250
|
end
|
208
251
|
|
209
252
|
def add_headers(headers)
|
210
|
-
browser.
|
253
|
+
browser.headers.add(headers)
|
211
254
|
end
|
212
255
|
|
213
256
|
def add_header(name, value, permanent: true)
|
214
|
-
browser.
|
257
|
+
browser.headers.add({ name => value }, permanent: permanent)
|
215
258
|
end
|
216
259
|
|
217
260
|
def response_headers
|
218
|
-
browser.
|
261
|
+
browser.network.response&.headers
|
219
262
|
end
|
220
263
|
|
221
264
|
def cookies
|
222
|
-
browser.cookies
|
265
|
+
browser.cookies.all
|
223
266
|
end
|
224
267
|
|
225
268
|
def set_cookie(name, value, options = {})
|
@@ -227,31 +270,37 @@ module Capybara::Cuprite
|
|
227
270
|
options[:name] ||= name
|
228
271
|
options[:value] ||= value
|
229
272
|
options[:domain] ||= default_domain
|
230
|
-
|
231
|
-
expires = options.delete(:expires).to_i
|
232
|
-
options[:expires] = expires if expires > 0
|
233
|
-
|
234
|
-
browser.set_cookie(options)
|
273
|
+
browser.cookies.set(**options)
|
235
274
|
end
|
236
275
|
|
237
276
|
def remove_cookie(name, **options)
|
238
277
|
options[:domain] = default_domain if options.empty?
|
239
|
-
browser.
|
278
|
+
browser.cookies.remove(**options.merge(name: name))
|
240
279
|
end
|
241
280
|
|
242
281
|
def clear_cookies
|
243
|
-
browser.
|
282
|
+
browser.cookies.clear
|
244
283
|
end
|
245
284
|
|
246
285
|
def clear_memory_cache
|
247
|
-
browser.
|
286
|
+
browser.network.clear(:cache)
|
248
287
|
end
|
249
288
|
|
250
289
|
def basic_authorize(user, password)
|
251
|
-
browser.authorize(user, password)
|
290
|
+
browser.network.authorize(user: user, password: password)
|
252
291
|
end
|
253
292
|
alias_method :authorize, :basic_authorize
|
254
293
|
|
294
|
+
def debug
|
295
|
+
if @options[:inspector]
|
296
|
+
Process.spawn(browser.process.path, "http://#{browser.process.host}:#{browser.process.port}")
|
297
|
+
pause
|
298
|
+
else
|
299
|
+
raise Error, "To use the remote debugging, you have to launch " \
|
300
|
+
"the driver with `inspector: true` configuration option"
|
301
|
+
end
|
302
|
+
end
|
303
|
+
|
255
304
|
def pause
|
256
305
|
# STDIN is not necessarily connected to a keyboard. It might even be closed.
|
257
306
|
# So we need a method other than keypress to continue.
|
@@ -284,15 +333,17 @@ module Capybara::Cuprite
|
|
284
333
|
end
|
285
334
|
|
286
335
|
def invalid_element_errors
|
287
|
-
[Capybara::Cuprite::ObsoleteNode,
|
336
|
+
[Capybara::Cuprite::ObsoleteNode,
|
337
|
+
Capybara::Cuprite::MouseEventFailed,
|
338
|
+
Ferrum::NoExecutionContextError]
|
288
339
|
end
|
289
340
|
|
290
341
|
def go_back
|
291
|
-
browser.
|
342
|
+
browser.back
|
292
343
|
end
|
293
344
|
|
294
345
|
def go_forward
|
295
|
-
browser.
|
346
|
+
browser.forward
|
296
347
|
end
|
297
348
|
|
298
349
|
def refresh
|
@@ -336,11 +387,7 @@ module Capybara::Cuprite
|
|
336
387
|
end
|
337
388
|
|
338
389
|
def native_args(args)
|
339
|
-
args.map { |arg| arg.is_a?(Capybara::Cuprite::Node) ? arg.
|
340
|
-
end
|
341
|
-
|
342
|
-
def screen_size
|
343
|
-
@options[:screen_size] || [1366, 768]
|
390
|
+
args.map { |arg| arg.is_a?(Capybara::Cuprite::Node) ? arg.node : arg }
|
344
391
|
end
|
345
392
|
|
346
393
|
def session_wait_time
|
@@ -368,11 +415,17 @@ module Capybara::Cuprite
|
|
368
415
|
when Array
|
369
416
|
arg.map { |e| unwrap_script_result(e) }
|
370
417
|
when Hash
|
371
|
-
return Capybara::Cuprite::Node.new(self, arg["target_id"], arg["node"]) if arg["target_id"]
|
372
418
|
arg.each { |k, v| arg[k] = unwrap_script_result(v) }
|
419
|
+
when Ferrum::Node
|
420
|
+
Node.new(self, arg)
|
373
421
|
else
|
374
422
|
arg
|
375
423
|
end
|
376
424
|
end
|
425
|
+
|
426
|
+
def pdf?(path, options)
|
427
|
+
(path && File.extname(path).delete(".") == "pdf") ||
|
428
|
+
options[:format].to_s == "pdf"
|
429
|
+
end
|
377
430
|
end
|
378
431
|
end
|
@@ -3,7 +3,6 @@
|
|
3
3
|
module Capybara
|
4
4
|
module Cuprite
|
5
5
|
class Error < StandardError; end
|
6
|
-
class NoSuchWindowError < Error; end
|
7
6
|
|
8
7
|
class ClientError < Error
|
9
8
|
attr_reader :response
|
@@ -13,45 +12,6 @@ module Capybara
|
|
13
12
|
end
|
14
13
|
end
|
15
14
|
|
16
|
-
class BrowserError < ClientError
|
17
|
-
def code
|
18
|
-
response["code"]
|
19
|
-
end
|
20
|
-
|
21
|
-
def data
|
22
|
-
response["data"]
|
23
|
-
end
|
24
|
-
|
25
|
-
def message
|
26
|
-
response["message"]
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
class JavaScriptError < ClientError
|
31
|
-
attr_reader :class_name, :message
|
32
|
-
|
33
|
-
def initialize(response)
|
34
|
-
super
|
35
|
-
@class_name, @message = response.values_at("className", "description")
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
class StatusFailError < ClientError
|
40
|
-
def message
|
41
|
-
"Request to #{response["url"]} failed to reach server, check DNS and/or server status"
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
class FrameNotFound < ClientError
|
46
|
-
def name
|
47
|
-
response["args"].first
|
48
|
-
end
|
49
|
-
|
50
|
-
def message
|
51
|
-
"The frame "#{name}" was not found."
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
15
|
class InvalidSelector < ClientError
|
56
16
|
def initialize(response, method, selector)
|
57
17
|
super(response)
|
@@ -82,16 +42,14 @@ module Capybara
|
|
82
42
|
end
|
83
43
|
end
|
84
44
|
|
85
|
-
class
|
45
|
+
class ObsoleteNode < ClientError
|
86
46
|
attr_reader :node
|
87
47
|
|
88
48
|
def initialize(node, response)
|
89
49
|
@node = node
|
90
50
|
super(response)
|
91
51
|
end
|
92
|
-
end
|
93
52
|
|
94
|
-
class ObsoleteNode < NodeError
|
95
53
|
def message
|
96
54
|
"The element you are trying to interact with is either not part of the DOM, or is " \
|
97
55
|
"not currently visible on the page (perhaps display: none is set). " \
|
@@ -100,26 +58,5 @@ module Capybara
|
|
100
58
|
"new element."
|
101
59
|
end
|
102
60
|
end
|
103
|
-
|
104
|
-
class TimeoutError < Error
|
105
|
-
def message
|
106
|
-
"Timed out waiting for response. It's possible that this happened " \
|
107
|
-
"because something took a very long time (for example a page load " \
|
108
|
-
"was slow). If so, setting the Cuprite :timeout option to a higher " \
|
109
|
-
"value might help."
|
110
|
-
end
|
111
|
-
end
|
112
|
-
|
113
|
-
class ScriptTimeoutError < Error
|
114
|
-
def message
|
115
|
-
"Timed out waiting for evaluated script to resturn a value"
|
116
|
-
end
|
117
|
-
end
|
118
|
-
|
119
|
-
class DeadBrowser < Error
|
120
|
-
def initialize(message = "Chrome is dead")
|
121
|
-
super
|
122
|
-
end
|
123
|
-
end
|
124
61
|
end
|
125
62
|
end
|
@@ -123,13 +123,17 @@ class Cuprite {
|
|
123
123
|
value = value.substr(0, node.maxLength);
|
124
124
|
}
|
125
125
|
|
126
|
+
let valueBefore = node.value;
|
127
|
+
|
126
128
|
this.trigger(node, "focus");
|
127
129
|
this.setValue(node, "");
|
128
130
|
|
129
131
|
if (node.type == "number" || node.type == "date") {
|
130
132
|
this.setValue(node, value);
|
133
|
+
this.input(node);
|
131
134
|
} else if (node.type == "time") {
|
132
135
|
this.setValue(node, new Date(value).toTimeString().split(" ")[0]);
|
136
|
+
this.input(node);
|
133
137
|
} else if (node.type == "datetime-local") {
|
134
138
|
value = new Date(value);
|
135
139
|
let year = value.getFullYear();
|
@@ -139,20 +143,29 @@ class Cuprite {
|
|
139
143
|
let min = ("0" + value.getMinutes()).slice(-2);
|
140
144
|
let sec = ("0" + value.getSeconds()).slice(-2);
|
141
145
|
this.setValue(node, `${year}-${month}-${date}T${hour}:${min}:${sec}`);
|
146
|
+
this.input(node);
|
142
147
|
} else {
|
143
148
|
for (let i = 0; i < value.length; i++) {
|
144
149
|
let char = value[i];
|
145
150
|
let keyCode = this.characterToKeyCode(char);
|
146
|
-
|
147
|
-
|
151
|
+
// call the following functions in order, if one returns false (preventDefault),
|
152
|
+
// stop the call chain
|
153
|
+
[
|
154
|
+
() => this.keyupdowned(node, "keydown", keyCode),
|
155
|
+
() => this.keypressed(node, false, false, false, false, char.charCodeAt(0), char.charCodeAt(0)),
|
156
|
+
() => {
|
157
|
+
this.setValue(node, node.value + char)
|
158
|
+
this.input(node)
|
159
|
+
}
|
160
|
+
].some(fn => fn())
|
148
161
|
|
149
|
-
this.keypressed(node, false, false, false, false, char.charCodeAt(0), char.charCodeAt(0));
|
150
162
|
this.keyupdowned(node, "keyup", keyCode);
|
151
163
|
}
|
152
164
|
}
|
153
165
|
|
154
|
-
|
155
|
-
|
166
|
+
if (valueBefore !== node.value) {
|
167
|
+
this.changed(node);
|
168
|
+
}
|
156
169
|
this.trigger(node, "blur");
|
157
170
|
}
|
158
171
|
|
@@ -172,14 +185,20 @@ class Cuprite {
|
|
172
185
|
node.dispatchEvent(event);
|
173
186
|
}
|
174
187
|
|
188
|
+
/**
|
189
|
+
* @return {boolean} false when an event handler called preventDefault()
|
190
|
+
*/
|
175
191
|
keyupdowned(node, eventName, keyCode) {
|
176
192
|
let event = document.createEvent("UIEvents");
|
177
193
|
event.initEvent(eventName, true, true);
|
178
194
|
event.keyCode = keyCode;
|
179
195
|
event.charCode = 0;
|
180
|
-
node.dispatchEvent(event);
|
196
|
+
return !node.dispatchEvent(event);
|
181
197
|
}
|
182
198
|
|
199
|
+
/**
|
200
|
+
* @return {boolean} false when an event handler called preventDefault()
|
201
|
+
*/
|
183
202
|
keypressed(node, altKey, ctrlKey, shiftKey, metaKey, keyCode, charCode) {
|
184
203
|
event = document.createEvent("UIEvents");
|
185
204
|
event.initEvent("keypress", true, true);
|
@@ -190,7 +209,7 @@ class Cuprite {
|
|
190
209
|
event.metaKey = metaKey;
|
191
210
|
event.keyCode = keyCode;
|
192
211
|
event.charCode = charCode;
|
193
|
-
node.dispatchEvent(event);
|
212
|
+
return !node.dispatchEvent(event);
|
194
213
|
}
|
195
214
|
|
196
215
|
characterToKeyCode(char) {
|
@@ -450,19 +469,6 @@ class Cuprite {
|
|
450
469
|
return node.contains(selectedNode);
|
451
470
|
}
|
452
471
|
|
453
|
-
isCyclic(object) {
|
454
|
-
if (Array.isArray(object) && object.every(n => n instanceof Node)) {
|
455
|
-
return false;
|
456
|
-
}
|
457
|
-
|
458
|
-
try {
|
459
|
-
this._json.stringify(object);
|
460
|
-
return false;
|
461
|
-
} catch (e) {
|
462
|
-
return true;
|
463
|
-
}
|
464
|
-
}
|
465
|
-
|
466
472
|
// This command is purely for testing error handling
|
467
473
|
browserError() {
|
468
474
|
throw new Error("zomg");
|
@@ -1,24 +1,27 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "forwardable"
|
4
|
+
|
3
5
|
module Capybara::Cuprite
|
4
6
|
class Node < Capybara::Driver::Node
|
5
|
-
attr_reader :
|
7
|
+
attr_reader :node
|
6
8
|
|
7
|
-
|
8
|
-
super(driver, self)
|
9
|
-
@target_id, @node = target_id, node
|
10
|
-
end
|
9
|
+
extend Forwardable
|
11
10
|
|
12
|
-
|
13
|
-
|
11
|
+
delegate %i(description) => :node
|
12
|
+
delegate %i(browser) => :driver
|
13
|
+
|
14
|
+
def initialize(driver, node)
|
15
|
+
super(driver, self)
|
16
|
+
@node = node
|
14
17
|
end
|
15
18
|
|
16
19
|
def command(name, *args)
|
17
|
-
browser.send(name,
|
18
|
-
rescue
|
20
|
+
browser.send(name, node, *args)
|
21
|
+
rescue Ferrum::NodeNotFoundError => e
|
22
|
+
raise ObsoleteNode.new(self, e.response)
|
23
|
+
rescue Ferrum::BrowserError => e
|
19
24
|
case e.message
|
20
|
-
when "No node with given id found"
|
21
|
-
raise ObsoleteNode.new(self, e.response)
|
22
25
|
when "Cuprite.MouseEventFailed"
|
23
26
|
raise MouseEventFailed.new(self, e.response)
|
24
27
|
else
|
@@ -28,13 +31,7 @@ module Capybara::Cuprite
|
|
28
31
|
|
29
32
|
def parents
|
30
33
|
command(:parents).map do |parent|
|
31
|
-
self.class.new(driver, parent
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
def find(method, selector)
|
36
|
-
command(:find_within, method, selector).map do |node|
|
37
|
-
self.class.new(driver, @target_id, node)
|
34
|
+
self.class.new(driver, parent)
|
38
35
|
end
|
39
36
|
end
|
40
37
|
|
@@ -46,6 +43,12 @@ module Capybara::Cuprite
|
|
46
43
|
find(:css, selector)
|
47
44
|
end
|
48
45
|
|
46
|
+
def find(method, selector)
|
47
|
+
command(:find_within, method, selector).map do |node|
|
48
|
+
self.class.new(driver, node)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
49
52
|
def all_text
|
50
53
|
filter_text(command(:all_text))
|
51
54
|
end
|
@@ -69,7 +72,8 @@ module Capybara::Cuprite
|
|
69
72
|
def [](name)
|
70
73
|
# Although the attribute matters, the property is consistent. Return that in
|
71
74
|
# preference to the attribute for links and images.
|
72
|
-
if (
|
75
|
+
if (tag_name == "img" && name == "src") ||
|
76
|
+
(tag_name == "a" && name == "href")
|
73
77
|
# if attribute exists get the property
|
74
78
|
return command(:attribute, name) && command(:property, name)
|
75
79
|
end
|
@@ -121,7 +125,7 @@ module Capybara::Cuprite
|
|
121
125
|
end
|
122
126
|
|
123
127
|
def tag_name
|
124
|
-
@tag_name ||=
|
128
|
+
@tag_name ||= description["nodeName"].downcase
|
125
129
|
end
|
126
130
|
|
127
131
|
def visible?
|
@@ -141,15 +145,15 @@ module Capybara::Cuprite
|
|
141
145
|
end
|
142
146
|
|
143
147
|
def click(keys = [], offset = {})
|
144
|
-
|
148
|
+
prepare_and_click(:left, __method__, keys, offset)
|
145
149
|
end
|
146
150
|
|
147
151
|
def right_click(keys = [], offset = {})
|
148
|
-
|
152
|
+
prepare_and_click(:right, __method__, keys, offset)
|
149
153
|
end
|
150
154
|
|
151
155
|
def double_click(keys = [], offset = {})
|
152
|
-
|
156
|
+
prepare_and_click(:double, __method__, keys, offset)
|
153
157
|
end
|
154
158
|
|
155
159
|
def hover
|
@@ -157,7 +161,7 @@ module Capybara::Cuprite
|
|
157
161
|
end
|
158
162
|
|
159
163
|
def drag_to(other)
|
160
|
-
command(:drag, other
|
164
|
+
command(:drag, other)
|
161
165
|
end
|
162
166
|
|
163
167
|
def drag_by(x, y)
|
@@ -192,10 +196,7 @@ module Capybara::Cuprite
|
|
192
196
|
end
|
193
197
|
|
194
198
|
def ==(other)
|
195
|
-
|
196
|
-
# never returns same nodeId sending 0. In other words frontend is
|
197
|
-
# responsible for keeping track of node ids.
|
198
|
-
@target_id == other.target_id && @node["backendNodeId"] == other.node["backendNodeId"]
|
199
|
+
node == other.native.node
|
199
200
|
end
|
200
201
|
|
201
202
|
def send_keys(*keys)
|
@@ -208,7 +209,7 @@ module Capybara::Cuprite
|
|
208
209
|
end
|
209
210
|
|
210
211
|
def inspect
|
211
|
-
%(#<#{self.class} @
|
212
|
+
%(#<#{self.class} @node=#{@node.inspect}>)
|
212
213
|
end
|
213
214
|
|
214
215
|
# @api private
|
@@ -218,12 +219,17 @@ module Capybara::Cuprite
|
|
218
219
|
|
219
220
|
# @api private
|
220
221
|
def as_json(*)
|
221
|
-
# FIXME: Where this method
|
222
|
-
{ ELEMENT: {
|
222
|
+
# FIXME: Where is this method used and why attr is called id?
|
223
|
+
{ ELEMENT: { node: node, id: node.node_id } }
|
223
224
|
end
|
224
225
|
|
225
226
|
private
|
226
227
|
|
228
|
+
def prepare_and_click(mode, name, keys, offset)
|
229
|
+
command(:before_click, name, keys, offset)
|
230
|
+
node.click(mode: mode, keys: keys, offset: offset)
|
231
|
+
end
|
232
|
+
|
227
233
|
def filter_text(text)
|
228
234
|
if Capybara::VERSION.to_f < 3
|
229
235
|
Capybara::Helpers.normalize_whitespace(text.to_s)
|