apparition 0.1.0 → 0.2.0
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 +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();
|