apparition 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/lib/capybara/apparition/browser.rb +102 -56
- data/lib/capybara/apparition/browser/header.rb +2 -2
- data/lib/capybara/apparition/browser/window.rb +29 -29
- data/lib/capybara/apparition/configuration.rb +100 -0
- data/lib/capybara/apparition/dev_tools_protocol/remote_object.rb +19 -7
- data/lib/capybara/apparition/dev_tools_protocol/session.rb +2 -3
- data/lib/capybara/apparition/driver.rb +95 -21
- data/lib/capybara/apparition/driver/chrome_client.rb +3 -3
- data/lib/capybara/apparition/driver/launcher.rb +27 -15
- data/lib/capybara/apparition/driver/response.rb +1 -1
- data/lib/capybara/apparition/errors.rb +3 -3
- data/lib/capybara/apparition/node.rb +44 -3
- data/lib/capybara/apparition/node/drag.rb +65 -0
- data/lib/capybara/apparition/page.rb +55 -37
- data/lib/capybara/apparition/page/frame.rb +3 -0
- data/lib/capybara/apparition/page/frame_manager.rb +1 -1
- data/lib/capybara/apparition/page/keyboard.rb +8 -1
- data/lib/capybara/apparition/utility.rb +1 -1
- data/lib/capybara/apparition/version.rb +1 -1
- metadata +5 -6
- data/lib/capybara/apparition/dev_tools_protocol/target.rb +0 -64
- data/lib/capybara/apparition/dev_tools_protocol/target_manager.rb +0 -48
@@ -19,13 +19,16 @@ module Capybara::Apparition
|
|
19
19
|
def cyclic_checked_value(object_cache)
|
20
20
|
if object?
|
21
21
|
if array?
|
22
|
-
extract_properties_array(get_remote_object(
|
22
|
+
extract_properties_array(get_remote_object(id), object_cache)
|
23
23
|
elsif node?
|
24
24
|
params
|
25
|
-
elsif
|
26
|
-
|
25
|
+
elsif date?
|
26
|
+
res = get_date_string(id)
|
27
|
+
DateTime.parse(res)
|
28
|
+
elsif object_class? || css_style?
|
29
|
+
extract_properties_object(get_remote_object(id), object_cache)
|
27
30
|
elsif window_class?
|
28
|
-
{ object_id:
|
31
|
+
{ object_id: id }
|
29
32
|
else
|
30
33
|
params['value']
|
31
34
|
end
|
@@ -38,13 +41,15 @@ module Capybara::Apparition
|
|
38
41
|
|
39
42
|
def object?; type == 'object' end
|
40
43
|
def array?; subtype == 'array' end
|
44
|
+
def date?; subtype == 'date' end
|
41
45
|
def node?; subtype == 'node' end
|
42
46
|
def object_class?; classname == 'Object' end
|
47
|
+
def css_style?; classname == 'CSSStyleDeclaration' end
|
43
48
|
def window_class?; classname == 'Window' end
|
44
49
|
|
45
50
|
def type; params['type'] end
|
46
51
|
def subtype; params['subtype'] end
|
47
|
-
def
|
52
|
+
def id; params['objectId'] end
|
48
53
|
def classname; params['className'] end
|
49
54
|
|
50
55
|
def extract_properties_array(properties, object_cache)
|
@@ -80,8 +85,15 @@ module Capybara::Apparition
|
|
80
85
|
end
|
81
86
|
end
|
82
87
|
|
83
|
-
def get_remote_object(id)
|
84
|
-
@page.command('Runtime.getProperties', objectId: id, ownProperties:
|
88
|
+
def get_remote_object(id, own_props = true)
|
89
|
+
@page.command('Runtime.getProperties', objectId: id, ownProperties: own_props)['result']
|
90
|
+
end
|
91
|
+
|
92
|
+
def get_date_string(id)
|
93
|
+
@page.command('Runtime.callFunctionOn',
|
94
|
+
functionDeclaration: 'function(){ return this.toUTCString() }',
|
95
|
+
objectId: id,
|
96
|
+
returnByValue: true).dig('result', 'value')
|
85
97
|
end
|
86
98
|
end
|
87
99
|
end
|
@@ -3,12 +3,11 @@
|
|
3
3
|
module Capybara::Apparition
|
4
4
|
module DevToolsProtocol
|
5
5
|
class Session
|
6
|
-
attr_reader :browser, :connection, :
|
6
|
+
attr_reader :browser, :connection, :session_id
|
7
7
|
|
8
|
-
def initialize(browser, connection,
|
8
|
+
def initialize(browser, connection, session_id)
|
9
9
|
@browser = browser
|
10
10
|
@connection = connection
|
11
|
-
@target_id = target_id
|
12
11
|
@session_id = session_id
|
13
12
|
@handlers = []
|
14
13
|
end
|
@@ -4,6 +4,7 @@ require 'uri'
|
|
4
4
|
require 'forwardable'
|
5
5
|
require 'capybara/apparition/driver/chrome_client'
|
6
6
|
require 'capybara/apparition/driver/launcher'
|
7
|
+
require 'capybara/apparition/configuration'
|
7
8
|
|
8
9
|
module Capybara::Apparition
|
9
10
|
class Driver < Capybara::Driver::Base
|
@@ -15,7 +16,7 @@ module Capybara::Apparition
|
|
15
16
|
|
16
17
|
delegate %i[restart current_url status_code body
|
17
18
|
title frame_title frame_url switch_to_frame
|
18
|
-
window_handles close_window
|
19
|
+
window_handles close_window switch_to_window
|
19
20
|
paper_size= zoom_factor=
|
20
21
|
scroll_to
|
21
22
|
network_traffic clear_network_traffic
|
@@ -32,6 +33,7 @@ module Capybara::Apparition
|
|
32
33
|
@browser = nil
|
33
34
|
@inspector = nil
|
34
35
|
@client = nil
|
36
|
+
@launcher = nil
|
35
37
|
@started = false
|
36
38
|
end
|
37
39
|
|
@@ -45,14 +47,14 @@ module Capybara::Apparition
|
|
45
47
|
|
46
48
|
def browser
|
47
49
|
@browser ||= begin
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
50
|
+
Browser.new(client, browser_logger) do |browser|
|
51
|
+
browser.js_errors = options.fetch(:js_errors, true)
|
52
|
+
browser.ignore_https_errors = options.fetch(:ignore_https_errors, false)
|
53
|
+
browser.extensions = options.fetch(:extensions, [])
|
54
|
+
browser.debug = options.fetch(:debug, false)
|
55
|
+
browser.url_blacklist = options[:url_blacklist] || []
|
56
|
+
browser.url_whitelist = options[:url_whitelist] || []
|
57
|
+
end
|
56
58
|
end
|
57
59
|
end
|
58
60
|
|
@@ -114,20 +116,26 @@ module Capybara::Apparition
|
|
114
116
|
end
|
115
117
|
|
116
118
|
def evaluate_script(script, *args)
|
117
|
-
|
119
|
+
retry_if_wrong_world do
|
120
|
+
unwrap_script_result(browser.evaluate(script, *native_args(args)))
|
121
|
+
end
|
118
122
|
end
|
119
123
|
|
120
124
|
def evaluate_async_script(script, *args)
|
121
|
-
|
125
|
+
retry_if_wrong_world do
|
126
|
+
unwrap_script_result(browser.evaluate_async(script, session_wait_time, *native_args(args)))
|
127
|
+
end
|
122
128
|
end
|
123
129
|
|
124
130
|
def execute_script(script, *args)
|
125
|
-
|
131
|
+
retry_if_wrong_world do
|
132
|
+
browser.execute(script, *native_args(args))
|
133
|
+
end
|
126
134
|
nil
|
127
135
|
end
|
128
136
|
|
129
137
|
def current_window_handle
|
130
|
-
browser.
|
138
|
+
browser.current_window_handle
|
131
139
|
end
|
132
140
|
|
133
141
|
def no_such_window_error
|
@@ -158,28 +166,33 @@ module Capybara::Apparition
|
|
158
166
|
def resize(width, height)
|
159
167
|
browser.resize(width, height, screen: options[:screen_size])
|
160
168
|
end
|
161
|
-
|
169
|
+
|
170
|
+
def resize_window(width, height)
|
171
|
+
warn '[DEPRECATION] Capybara::Apparition::Driver#resize_window ' \
|
172
|
+
'is deprecated. Please use Capybara::Window#resize_to instead.'
|
173
|
+
resize(width, height)
|
174
|
+
end
|
162
175
|
|
163
176
|
def resize_window_to(handle, width, height)
|
164
|
-
|
177
|
+
_within_window(handle) do
|
165
178
|
resize(width, height)
|
166
179
|
end
|
167
180
|
end
|
168
181
|
|
169
182
|
def maximize_window(handle)
|
170
|
-
|
183
|
+
_within_window(handle) do
|
171
184
|
browser.maximize
|
172
185
|
end
|
173
186
|
end
|
174
187
|
|
175
188
|
def fullscreen_window(handle)
|
176
|
-
|
189
|
+
_within_window(handle) do
|
177
190
|
browser.fullscreen
|
178
191
|
end
|
179
192
|
end
|
180
193
|
|
181
194
|
def window_size(handle)
|
182
|
-
|
195
|
+
_within_window(handle) do
|
183
196
|
evaluate_script('[window.innerWidth, window.innerHeight]')
|
184
197
|
end
|
185
198
|
end
|
@@ -266,12 +279,12 @@ module Capybara::Apparition
|
|
266
279
|
write.close
|
267
280
|
end
|
268
281
|
|
269
|
-
STDERR.puts "Apparition execution paused. Press enter (or run 'kill -CONT #{Process.pid}') to continue."
|
282
|
+
STDERR.puts "Apparition execution paused. Press enter (or run 'kill -CONT #{Process.pid}') to continue." # rubocop:disable Style/StderrPuts
|
270
283
|
|
271
284
|
signal = false
|
272
285
|
old_trap = trap('SIGCONT') do
|
273
286
|
signal = true
|
274
|
-
STDERR.puts "\nSignal SIGCONT received"
|
287
|
+
STDERR.puts "\nSignal SIGCONT received" # rubocop:disable Style/StderrPuts
|
275
288
|
end
|
276
289
|
# wait for data on STDIN or signal SIGCONT received
|
277
290
|
keyboard = IO.select([read], nil, nil, 1) until keyboard || signal
|
@@ -286,7 +299,7 @@ module Capybara::Apparition
|
|
286
299
|
end
|
287
300
|
ensure
|
288
301
|
trap('SIGCONT', old_trap) # Restore the previous signal handler, if there was one.
|
289
|
-
STDERR.puts 'Continuing'
|
302
|
+
STDERR.puts 'Continuing' # rubocop:disable Style/StderrPuts
|
290
303
|
end
|
291
304
|
|
292
305
|
def wait?
|
@@ -336,8 +349,53 @@ module Capybara::Apparition
|
|
336
349
|
console_messages('error')
|
337
350
|
end
|
338
351
|
|
352
|
+
def within_window(selector, &block)
|
353
|
+
warn 'Driver#within_window is deprecated, please switch to using Session#within_window instead.'
|
354
|
+
_within_window(selector, &block)
|
355
|
+
orig_window = current_window_handle
|
356
|
+
switch_to_window(selector)
|
357
|
+
begin
|
358
|
+
yield
|
359
|
+
ensure
|
360
|
+
switch_to_window(orig_window)
|
361
|
+
end
|
362
|
+
end
|
363
|
+
|
364
|
+
def version
|
365
|
+
chrome_version = browser.command('Browser.getVersion')
|
366
|
+
format(VERSION_STRING,
|
367
|
+
capybara: Capybara::VERSION,
|
368
|
+
apparition: Capybara::Apparition::VERSION,
|
369
|
+
chrome: chrome_version['product'])
|
370
|
+
end
|
371
|
+
|
372
|
+
def open_new_window
|
373
|
+
# needed because Capybara does arity detection on this method
|
374
|
+
browser.open_new_window
|
375
|
+
end
|
376
|
+
|
339
377
|
private
|
340
378
|
|
379
|
+
def retry_if_wrong_world
|
380
|
+
timer = Capybara::Helpers.timer(expire_in: session_wait_time)
|
381
|
+
begin
|
382
|
+
yield
|
383
|
+
rescue WrongWorld
|
384
|
+
retry unless timer.expired?
|
385
|
+
raise
|
386
|
+
end
|
387
|
+
end
|
388
|
+
|
389
|
+
def _within_window(selector)
|
390
|
+
orig_window = current_window_handle
|
391
|
+
switch_to_window(selector)
|
392
|
+
begin
|
393
|
+
yield
|
394
|
+
ensure
|
395
|
+
switch_to_window(orig_window)
|
396
|
+
end
|
397
|
+
end
|
398
|
+
|
341
399
|
def browser_options
|
342
400
|
@options[:browser_options]
|
343
401
|
end
|
@@ -363,7 +421,16 @@ module Capybara::Apparition
|
|
363
421
|
if @options[:skip_image_loading]
|
364
422
|
browser_options['blink-settings'] = [browser_options['blink-settings'], 'imagesEnabled=false'].compact.join(',')
|
365
423
|
end
|
424
|
+
|
366
425
|
@options[:browser_options] = browser_options
|
426
|
+
process_cw_options(@options[:cw_options])
|
427
|
+
end
|
428
|
+
|
429
|
+
def process_cw_options(cw_options)
|
430
|
+
return if cw_options.nil?
|
431
|
+
|
432
|
+
(options[:url_blacklist] ||= []).concat cw_options[:url_blacklist]
|
433
|
+
options[:js_errors] ||= cw_options[:js_errors]
|
367
434
|
end
|
368
435
|
|
369
436
|
def process_browser_options(options)
|
@@ -464,5 +531,12 @@ module Capybara::Apparition
|
|
464
531
|
arg
|
465
532
|
end
|
466
533
|
end
|
534
|
+
|
535
|
+
VERSION_STRING = <<~VERSION
|
536
|
+
Versions in use:
|
537
|
+
Capybara: %<capybara>s
|
538
|
+
Apparition: %<apparition>s
|
539
|
+
Chrome: %<chrome>s
|
540
|
+
VERSION
|
467
541
|
end
|
468
542
|
end
|
@@ -92,7 +92,7 @@ module Capybara::Apparition
|
|
92
92
|
def send_msg(command, params)
|
93
93
|
msg_id, msg = generate_msg(command, params)
|
94
94
|
@send_mutex.synchronize do
|
95
|
-
puts "#{Time.now.to_i}: sending msg: #{msg}" if ENV['DEBUG']
|
95
|
+
puts "#{Time.now.to_i}: sending msg: #{msg}" if ENV['DEBUG'] == 'V'
|
96
96
|
@ws.send_msg(msg)
|
97
97
|
end
|
98
98
|
msg_id
|
@@ -141,7 +141,7 @@ module Capybara::Apparition
|
|
141
141
|
|
142
142
|
def read_msg
|
143
143
|
msg = JSON.parse(@ws.read_msg)
|
144
|
-
puts "#{Time.now.to_i}: got msg: #{msg}" if ENV['DEBUG']
|
144
|
+
puts "#{Time.now.to_i}: got msg: #{msg}" if ENV['DEBUG'] == 'V'
|
145
145
|
# Check if it's an event and push on event queue
|
146
146
|
@events.push msg.dup if msg['method']
|
147
147
|
|
@@ -162,7 +162,7 @@ module Capybara::Apparition
|
|
162
162
|
@msg_mutex.synchronize do
|
163
163
|
@message_available.wait(@msg_mutex, 0.1)
|
164
164
|
(@responses.keys & @async_ids).each do |msg_id|
|
165
|
-
puts "Cleaning up response for #{msg_id}" if ENV['DEBUG'] == '
|
165
|
+
puts "Cleaning up response for #{msg_id}" if ENV['DEBUG'] == 'V'
|
166
166
|
@responses.delete(msg_id)
|
167
167
|
@async_ids.delete(msg_id)
|
168
168
|
end
|
@@ -3,7 +3,7 @@
|
|
3
3
|
module Capybara::Apparition
|
4
4
|
class Browser
|
5
5
|
class Launcher
|
6
|
-
KILL_TIMEOUT =
|
6
|
+
KILL_TIMEOUT = 5
|
7
7
|
|
8
8
|
def self.start(*args)
|
9
9
|
new(*args).tap(&:start)
|
@@ -12,10 +12,11 @@ module Capybara::Apparition
|
|
12
12
|
def self.process_killer(pid)
|
13
13
|
proc do
|
14
14
|
begin
|
15
|
+
sleep 1
|
15
16
|
if Capybara::Apparition.windows?
|
16
17
|
::Process.kill('KILL', pid)
|
17
18
|
else
|
18
|
-
::Process.kill('
|
19
|
+
::Process.kill('USR1', pid)
|
19
20
|
timer = Capybara::Helpers.timer(expire_in: KILL_TIMEOUT)
|
20
21
|
while ::Process.wait(pid, ::Process::WNOHANG).nil?
|
21
22
|
sleep 0.05
|
@@ -137,7 +138,7 @@ module Capybara::Apparition
|
|
137
138
|
when /darwin|mac os/
|
138
139
|
macosx_path
|
139
140
|
when /linux|solaris|bsd/
|
140
|
-
|
141
|
+
linux_path
|
141
142
|
else
|
142
143
|
raise ArgumentError, "unknown os: #{host_os.inspect}"
|
143
144
|
end
|
@@ -148,26 +149,36 @@ module Capybara::Apparition
|
|
148
149
|
end
|
149
150
|
|
150
151
|
def windows_path
|
151
|
-
|
152
|
+
envs = %w[LOCALAPPDATA PROGRAMFILES PROGRAMFILES(X86)]
|
153
|
+
directories = %w[\\Google\\Chrome\\Application \\Chromium\\Application]
|
154
|
+
files = %w[chrome.exe]
|
155
|
+
|
156
|
+
directories.product(envs, files).lazy.map { |(dir, env, file)| "#{ENV[env]}\\#{dir}\\#{file}" }
|
157
|
+
.find { |f| File.exist?(f) } || find_first_binary(*files)
|
152
158
|
end
|
153
159
|
|
154
160
|
def macosx_path
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
161
|
+
directories = ['', File.expand_path('~')]
|
162
|
+
files = ['/Applications/Google Chrome.app/Contents/MacOS/Google Chrome',
|
163
|
+
'/Applications/Chromium.app/Contents/MacOS/Chromium']
|
164
|
+
directories.product(files).map(&:join).find { |f| File.exist?(f) } ||
|
165
|
+
find_first_binary('Google Chrome', 'Chromium')
|
166
|
+
end
|
167
|
+
|
168
|
+
def linux_path
|
169
|
+
directories = %w[/usr/local/sbin /usr/local/bin /usr/sbin /usr/bin /sbin /bin /opt/google/chrome]
|
170
|
+
files = %w[google-chrome chrome chromium chromium-browser]
|
171
|
+
|
172
|
+
directories.product(files).map { |p| p.join('/') }.find { |f| File.exist?(f) } ||
|
173
|
+
find_first_binary(*files)
|
159
174
|
end
|
160
175
|
|
161
176
|
def find_first_binary(*binaries)
|
162
177
|
paths = ENV['PATH'].split(File::PATH_SEPARATOR)
|
163
178
|
|
164
|
-
binaries.
|
165
|
-
|
166
|
-
|
167
|
-
exe = Dir.glob(full_path).find { |f| File.executable?(f) }
|
168
|
-
return exe if exe
|
169
|
-
end
|
170
|
-
end
|
179
|
+
binaries.product(paths).lazy.map do |(binary, path)|
|
180
|
+
Dir.glob(File.join(path, binary)).find { |f| File.executable?(f) }
|
181
|
+
end.reject(&:nil?).first
|
171
182
|
end
|
172
183
|
|
173
184
|
# Chromium command line options
|
@@ -187,6 +198,7 @@ module Capybara::Apparition
|
|
187
198
|
disable-prompt-on-repost
|
188
199
|
disable-sync
|
189
200
|
disable-translate
|
201
|
+
disable-session-crashed-bubble
|
190
202
|
metrics-recording-only
|
191
203
|
no-first-run
|
192
204
|
safebrowsing-disable-auto-update
|
@@ -15,7 +15,7 @@ module Capybara::Apparition
|
|
15
15
|
handle_error(resp['error']) if resp['error']
|
16
16
|
resp
|
17
17
|
end.last
|
18
|
-
puts "Processed msg: #{@msg_ids.last} in #{Time.now - @send_time} seconds" if ENV['DEBUG']
|
18
|
+
puts "Processed msg: #{@msg_ids.last} in #{Time.now - @send_time} seconds" if ENV['DEBUG'] == 'V'
|
19
19
|
|
20
20
|
response['result']
|
21
21
|
end
|
@@ -45,7 +45,7 @@ module Capybara
|
|
45
45
|
end
|
46
46
|
|
47
47
|
def message
|
48
|
-
'There was an error inside
|
48
|
+
'There was an error inside Apparition. ' \
|
49
49
|
'If this is the error returned, and not the cause of a more detailed error response, ' \
|
50
50
|
'this is probably a bug, so please report it. ' \
|
51
51
|
"\n\n#{name}: #{error_parameters}"
|
@@ -57,7 +57,7 @@ module Capybara
|
|
57
57
|
# response['args'].first.map { |data| JSErrorItem.new(data['message'], data['stack']) }
|
58
58
|
# end
|
59
59
|
def javascript_errors
|
60
|
-
[response]
|
60
|
+
[message: response]
|
61
61
|
end
|
62
62
|
|
63
63
|
def message
|
@@ -65,7 +65,7 @@ module Capybara
|
|
65
65
|
"If you don't care about these errors, you can ignore them by " \
|
66
66
|
'setting js_errors: false in your Apparition configuration (see ' \
|
67
67
|
'documentation for details).' \
|
68
|
-
"\n\n#{javascript_errors.map
|
68
|
+
"\n\n#{javascript_errors.map { |err| err[:message] }.join("\n")}"
|
69
69
|
end
|
70
70
|
end
|
71
71
|
|
@@ -33,9 +33,9 @@ module Capybara::Apparition
|
|
33
33
|
Capybara::Apparition::Node.new(driver, @page, r_o['objectId'])
|
34
34
|
end
|
35
35
|
rescue ::Capybara::Apparition::BrowserError => e
|
36
|
-
raise unless
|
36
|
+
raise unless /is not a valid (XPath expression|selector)/.match? e.name
|
37
37
|
|
38
|
-
raise Capybara::Apparition::InvalidSelector, [method, selector]
|
38
|
+
raise Capybara::Apparition::InvalidSelector, 'args' => [method, selector]
|
39
39
|
end
|
40
40
|
|
41
41
|
def find_xpath(selector)
|
@@ -71,6 +71,18 @@ module Capybara::Apparition
|
|
71
71
|
visible_text
|
72
72
|
end
|
73
73
|
|
74
|
+
# capybara-webkit method
|
75
|
+
def inner_html
|
76
|
+
self[:innerHTML]
|
77
|
+
end
|
78
|
+
|
79
|
+
# capybara-webkit method
|
80
|
+
def inner_html=(value)
|
81
|
+
driver.execute_script <<~JS, self, value
|
82
|
+
arguments[0].innerHTML = arguments[1]
|
83
|
+
JS
|
84
|
+
end
|
85
|
+
|
74
86
|
def property(name)
|
75
87
|
evaluate_on('name => this[name]', value: name)
|
76
88
|
end
|
@@ -118,10 +130,13 @@ module Capybara::Apparition
|
|
118
130
|
when 'datetime-local'
|
119
131
|
set_datetime_local(value)
|
120
132
|
else
|
121
|
-
set_text(value.to_s, delay:
|
133
|
+
set_text(value.to_s, { delay: 0 }.merge(options))
|
122
134
|
end
|
123
135
|
elsif tag_name == 'textarea'
|
124
136
|
set_text(value.to_s)
|
137
|
+
elsif tag_name == 'select'
|
138
|
+
warn "Setting the value of a select element via 'set' is deprecated, please use 'select' or 'select_option'."
|
139
|
+
evaluate_on '()=>{ this.value = arguments[0] }', value: value.to_s
|
125
140
|
elsif self[:isContentEditable]
|
126
141
|
delete_text
|
127
142
|
send_keys(value.to_s, delay: options.fetch(:delay, 0))
|
@@ -150,6 +165,10 @@ module Capybara::Apparition
|
|
150
165
|
evaluate_on VISIBLE_JS
|
151
166
|
end
|
152
167
|
|
168
|
+
def obscured?(x: nil, y: nil)
|
169
|
+
evaluate_on(OBSCURED_JS) == true
|
170
|
+
end
|
171
|
+
|
153
172
|
def checked?
|
154
173
|
self[:checked]
|
155
174
|
end
|
@@ -227,6 +246,10 @@ module Capybara::Apparition
|
|
227
246
|
evaluate_on DISPATCH_EVENT_JS, { value: event_type }, { value: name }, value: opts.merge(options)
|
228
247
|
end
|
229
248
|
|
249
|
+
def submit
|
250
|
+
evaluate_on '()=>{ this.submit() }'
|
251
|
+
end
|
252
|
+
|
230
253
|
def ==(other)
|
231
254
|
evaluate_on('el => this == el', objectId: other.id)
|
232
255
|
rescue ObsoleteNode
|
@@ -710,6 +733,24 @@ module Capybara::Apparition
|
|
710
733
|
}
|
711
734
|
JS
|
712
735
|
|
736
|
+
OBSCURED_JS = <<~JS
|
737
|
+
function(x, y) {
|
738
|
+
var box = this.getBoundingClientRect();
|
739
|
+
if (x == null) x = box.width/2;
|
740
|
+
if (y == null) y = box.height/2 ;
|
741
|
+
|
742
|
+
var px = box.left + x,
|
743
|
+
py = box.top + y,
|
744
|
+
e = document.elementFromPoint(px, py);
|
745
|
+
|
746
|
+
if (!this.contains(e))
|
747
|
+
return true;
|
748
|
+
|
749
|
+
return { x: px, y: py };
|
750
|
+
}
|
751
|
+
JS
|
752
|
+
|
753
|
+
|
713
754
|
DELETE_TEXT_JS = <<~JS
|
714
755
|
function(){
|
715
756
|
range = document.createRange();
|