apparition 0.0.4 → 0.0.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +2 -2
- data/lib/capybara/apparition/browser.rb +30 -8
- data/lib/capybara/apparition/console.rb +7 -5
- data/lib/capybara/apparition/cookie.rb +4 -3
- data/lib/capybara/apparition/cookie_jar.rb +41 -0
- data/lib/capybara/apparition/dev_tools_protocol/session.rb +17 -2
- data/lib/capybara/apparition/driver.rb +28 -14
- data/lib/capybara/apparition/{chrome_client.rb → driver/chrome_client.rb} +2 -2
- data/lib/capybara/apparition/{launcher.rb → driver/launcher.rb} +0 -0
- data/lib/capybara/apparition/{response.rb → driver/response.rb} +0 -0
- data/lib/capybara/apparition/{web_socket_client.rb → driver/web_socket_client.rb} +0 -0
- data/lib/capybara/apparition/errors.rb +0 -1
- data/lib/capybara/apparition/node.rb +43 -53
- data/lib/capybara/apparition/page.rb +142 -52
- data/lib/capybara/apparition/{frame.rb → page/frame.rb} +0 -0
- data/lib/capybara/apparition/{frame_manager.rb → page/frame_manager.rb} +1 -1
- data/lib/capybara/apparition/{keyboard.rb → page/keyboard.rb} +0 -0
- data/lib/capybara/apparition/{mouse.rb → page/mouse.rb} +11 -9
- data/lib/capybara/apparition/version.rb +1 -1
- metadata +25 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2df57d16d5cfa6f966f3b8de2146a63ca23877e4dddc2f81a12170ae37f5ec5d
|
4
|
+
data.tar.gz: b7b06eacc056f6b627b31ad091a7db9af5508b3f14ae69e7d9f1bedce6e8e63a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fd65552a378369a1d27852736c1cf2e1c51fb852a2c3e7c90b7c536f58608846bec86b471f009ef6eb9f9cbb803773d99c8af9b01575a0e5b2de953f1e0093f2
|
7
|
+
data.tar.gz: 77f8e17427d5621179b1707182e6df8bf3fc2bc52cb9f5f25e42ed31c6db945bd28b00c8f20ea09c2cf55e76476cf0fe467fd0b5aa8eece8f13a08611d9408e5
|
data/README.md
CHANGED
@@ -5,7 +5,7 @@
|
|
5
5
|
Apparition is a driver for [Capybara](https://github.com/jnicklas/capybara). It allows you to
|
6
6
|
run your Capybara tests in the Chrome browser via CDP (no selenium or chromedriver needed) in a headless or
|
7
7
|
headed configuration. It started as a fork of Poltergeist and attempts to maintain as much compatibility
|
8
|
-
with the Poltergeist API as possible
|
8
|
+
with the Poltergeist API as possible. Implementing the `capybara-webkit` specific driver methods has also begun.
|
9
9
|
|
10
10
|
## Getting help ##
|
11
11
|
|
@@ -217,7 +217,7 @@ Include as much information as possible. For example:
|
|
217
217
|
|
218
218
|
* Specific steps to reproduce where possible (failing tests are even
|
219
219
|
better)
|
220
|
-
* The output obtained from running Apparition with `:debug` turned on
|
220
|
+
* The output obtained from running Apparition with `:debug` turned on or ENV['DEBUG'] set
|
221
221
|
* Screenshots
|
222
222
|
* Stack traces if there are any Ruby on JavaScript exceptions generated
|
223
223
|
* The Apparition, Capybara, and Chrome version numbers used
|
@@ -9,7 +9,7 @@ require 'time'
|
|
9
9
|
|
10
10
|
module Capybara::Apparition
|
11
11
|
class Browser
|
12
|
-
attr_reader :client, :paper_size, :zoom_factor, :console
|
12
|
+
attr_reader :client, :paper_size, :zoom_factor, :console, :proxy_auth
|
13
13
|
extend Forwardable
|
14
14
|
|
15
15
|
delegate %i[visit current_url status_code
|
@@ -27,7 +27,9 @@ module Capybara::Apparition
|
|
27
27
|
@context_id = nil
|
28
28
|
@js_errors = true
|
29
29
|
@ignore_https_errors = false
|
30
|
+
@logger = logger
|
30
31
|
@console = Console.new(logger)
|
32
|
+
@proxy_auth = nil
|
31
33
|
|
32
34
|
initialize_handlers
|
33
35
|
|
@@ -102,7 +104,7 @@ module Capybara::Apparition
|
|
102
104
|
def close_window(handle)
|
103
105
|
@current_page_handle = nil if @current_page_handle == handle
|
104
106
|
win_target = @targets.delete(handle)
|
105
|
-
warn
|
107
|
+
warn 'Window was already closed unexpectedly' if win_target.nil?
|
106
108
|
win_target&.close
|
107
109
|
end
|
108
110
|
|
@@ -205,9 +207,21 @@ module Capybara::Apparition
|
|
205
207
|
end
|
206
208
|
|
207
209
|
def cookies
|
208
|
-
|
209
|
-
|
210
|
-
|
210
|
+
CookieJar.new(
|
211
|
+
# current_page.command('Network.getCookies')['cookies'].map { |c| Cookie.new(c) }
|
212
|
+
self
|
213
|
+
)
|
214
|
+
end
|
215
|
+
|
216
|
+
def all_cookies
|
217
|
+
CookieJar.new(
|
218
|
+
# current_page.command('Network.getAllCookies')['cookies'].map { |c| Cookie.new(c) }
|
219
|
+
self
|
220
|
+
)
|
221
|
+
end
|
222
|
+
|
223
|
+
def get_raw_cookies
|
224
|
+
current_page.command('Network.getAllCookies')['cookies'].map { |c| Cookie.new(c) }
|
211
225
|
end
|
212
226
|
|
213
227
|
def set_cookie(cookie)
|
@@ -231,6 +245,14 @@ module Capybara::Apparition
|
|
231
245
|
current_page.command('Emulation.setDocumentCookieDisabled', disabled: !flag)
|
232
246
|
end
|
233
247
|
|
248
|
+
def set_proxy_auth(user, password)
|
249
|
+
@proxy_auth = if user.nil? && password.nil?
|
250
|
+
nil
|
251
|
+
else
|
252
|
+
{ username: user, password: password }
|
253
|
+
end
|
254
|
+
end
|
255
|
+
|
234
256
|
def set_http_auth(user = nil, password = nil)
|
235
257
|
current_page.credentials = if user.nil? && password.nil?
|
236
258
|
nil
|
@@ -311,8 +333,8 @@ module Capybara::Apparition
|
|
311
333
|
current_target.page
|
312
334
|
end
|
313
335
|
|
314
|
-
def console_messages
|
315
|
-
console.messages
|
336
|
+
def console_messages(type = nil)
|
337
|
+
console.messages(type)
|
316
338
|
end
|
317
339
|
|
318
340
|
private
|
@@ -326,7 +348,7 @@ module Capybara::Apparition
|
|
326
348
|
end
|
327
349
|
|
328
350
|
def log(message)
|
329
|
-
logger&.puts message if ENV['DEBUG']
|
351
|
+
@logger&.puts message if ENV['DEBUG']
|
330
352
|
end
|
331
353
|
|
332
354
|
def check_render_options!(options, path = nil)
|
@@ -7,17 +7,19 @@ module Capybara::Apparition
|
|
7
7
|
@messages = []
|
8
8
|
end
|
9
9
|
|
10
|
-
def log(type, message)
|
11
|
-
@messages << OpenStruct.new(type: type, message: message)
|
12
|
-
@logger&.puts message
|
10
|
+
def log(type, message, **options)
|
11
|
+
@messages << OpenStruct.new(type: type, message: message, **options)
|
12
|
+
@logger&.puts "#{type}: #{message}"
|
13
13
|
end
|
14
14
|
|
15
15
|
def clear
|
16
16
|
@messages.clear
|
17
17
|
end
|
18
18
|
|
19
|
-
def messages
|
20
|
-
@messages
|
19
|
+
def messages(type = nil)
|
20
|
+
return @messages if type.nil?
|
21
|
+
|
22
|
+
@messages.select { |msg| msg.type == type }
|
21
23
|
end
|
22
24
|
end
|
23
25
|
end
|
@@ -48,9 +48,10 @@ module Capybara::Apparition
|
|
48
48
|
Time.at @attributes['expires'] unless [nil, 0, -1].include? @attributes['expires']
|
49
49
|
end
|
50
50
|
|
51
|
-
def ==(
|
52
|
-
return super unless
|
53
|
-
|
51
|
+
def ==(other)
|
52
|
+
return super unless other.is_a? String
|
53
|
+
|
54
|
+
value == other
|
54
55
|
end
|
55
56
|
end
|
56
57
|
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'capybara/apparition/cookie'
|
4
|
+
|
5
|
+
module Capybara::Apparition
|
6
|
+
class CookieJar
|
7
|
+
def initialize(browser)
|
8
|
+
@browser = browser
|
9
|
+
end
|
10
|
+
|
11
|
+
# def find(name, domain = nil, path = '/')
|
12
|
+
def find(name, domain = URI.parse(@browser.current_url).host, path = URI.parse(@browser.current_url).path)
|
13
|
+
# sort by path length because more specific take precendence
|
14
|
+
cookies.sort_by { |c| -c.path.length }.find do |cookie|
|
15
|
+
cookie.name.casecmp(name).zero? &&
|
16
|
+
(domain.nil? || match_domain?(cookie, domain)) &&
|
17
|
+
(path.nil? || match_path?(cookie, path))
|
18
|
+
end
|
19
|
+
end
|
20
|
+
alias_method :[], :find
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def match_domain?(cookie, domain)
|
25
|
+
domain = '.' + domain
|
26
|
+
cookie_domain = cookie.domain
|
27
|
+
cookie_domain = '.' + cookie_domain unless cookie_domain.start_with?('.')
|
28
|
+
# cookie_domain.downcase.end_with? domain.downcase
|
29
|
+
domain.downcase.end_with? cookie_domain.downcase
|
30
|
+
end
|
31
|
+
|
32
|
+
def match_path?(cookie, path)
|
33
|
+
# cookie.path.start_with? path
|
34
|
+
path.start_with? cookie.path
|
35
|
+
end
|
36
|
+
|
37
|
+
def cookies
|
38
|
+
@browser.get_raw_cookies
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -14,16 +14,31 @@ module Capybara::Apparition
|
|
14
14
|
end
|
15
15
|
|
16
16
|
def command(name, **params)
|
17
|
-
|
17
|
+
send_cmd(name, params).result
|
18
|
+
end
|
19
|
+
|
20
|
+
def commands(*names)
|
21
|
+
responses = names.map { |name| send_cmd(name) }
|
22
|
+
responses.map(&:result)
|
18
23
|
end
|
19
24
|
|
20
25
|
def async_command(name, **params)
|
21
|
-
|
26
|
+
send_cmd(name, params).discard_result
|
27
|
+
end
|
28
|
+
|
29
|
+
def async_commands(*names)
|
30
|
+
names.map { |name| async_command(name) }
|
22
31
|
end
|
23
32
|
|
24
33
|
def on(event_name, &block)
|
25
34
|
connection.on(event_name, @session_id, &block)
|
26
35
|
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def send_cmd(name, **params)
|
40
|
+
@browser.command_for_session(@session_id, name, params)
|
41
|
+
end
|
27
42
|
end
|
28
43
|
end
|
29
44
|
end
|
@@ -2,8 +2,8 @@
|
|
2
2
|
|
3
3
|
require 'uri'
|
4
4
|
require 'forwardable'
|
5
|
-
require 'capybara/apparition/chrome_client'
|
6
|
-
require 'capybara/apparition/launcher'
|
5
|
+
require 'capybara/apparition/driver/chrome_client'
|
6
|
+
require 'capybara/apparition/driver/launcher'
|
7
7
|
|
8
8
|
module Capybara::Apparition
|
9
9
|
class Driver < Capybara::Driver::Base
|
@@ -20,7 +20,7 @@ module Capybara::Apparition
|
|
20
20
|
scroll_to
|
21
21
|
network_traffic clear_network_traffic
|
22
22
|
headers headers= add_headers
|
23
|
-
cookies remove_cookie clear_cookies cookies_enabled=
|
23
|
+
cookies all_cookies remove_cookie clear_cookies cookies_enabled=
|
24
24
|
clear_memory_cache
|
25
25
|
go_back go_forward refresh
|
26
26
|
console_messages] => :browser
|
@@ -196,13 +196,20 @@ module Capybara::Apparition
|
|
196
196
|
end
|
197
197
|
end
|
198
198
|
|
199
|
-
def set_proxy(host, port, type = nil,
|
200
|
-
|
201
|
-
|
199
|
+
def set_proxy(host, port, type = nil, user_ = nil, password_ = nil, user: nil, password: nil, bypass: [])
|
200
|
+
if user_ || password_
|
201
|
+
warn '#set_proxy: Passing `user` and `password` as positional arguments is deprecated. ' \
|
202
|
+
'Please pass as keyword arguments.'
|
203
|
+
user ||= user_
|
204
|
+
password ||= password_
|
205
|
+
end
|
206
|
+
|
207
|
+
# TODO: Look at implementing via the CDP Fetch domain when available
|
202
208
|
@options[:browser] ||= {}
|
203
|
-
@options[:browser]
|
209
|
+
@options[:browser]['proxy-server'] = "#{type + '=' if type}#{host}:#{port}"
|
204
210
|
bypass = Array(bypass).join(';')
|
205
|
-
@options[:browser]
|
211
|
+
@options[:browser]['proxy-bypass-list'] = bypass unless bypass.empty?
|
212
|
+
browser.set_proxy_auth(user, password) if user || password
|
206
213
|
end
|
207
214
|
|
208
215
|
def add_header(name, value, options = {})
|
@@ -216,7 +223,7 @@ module Capybara::Apparition
|
|
216
223
|
end
|
217
224
|
end
|
218
225
|
|
219
|
-
def set_cookie(name, value=nil, options = {})
|
226
|
+
def set_cookie(name, value = nil, options = {})
|
220
227
|
name, value, options = parse_raw_cookie(name) if value.nil?
|
221
228
|
|
222
229
|
options[:name] ||= name
|
@@ -232,10 +239,12 @@ module Capybara::Apparition
|
|
232
239
|
browser.set_cookie(options)
|
233
240
|
end
|
234
241
|
|
242
|
+
def proxy_authorize(user = nil, password = nil)
|
243
|
+
browser.set_proxy_aauth(user, password)
|
244
|
+
end
|
245
|
+
|
235
246
|
def basic_authorize(user = nil, password = nil)
|
236
247
|
browser.set_http_auth(user, password)
|
237
|
-
# credentials = ["#{user}:#{password}"].pack('m*').strip
|
238
|
-
# add_header('Authorization', "Basic #{credentials}")
|
239
248
|
end
|
240
249
|
alias_method :authenticate, :basic_authorize
|
241
250
|
|
@@ -336,7 +345,7 @@ module Capybara::Apparition
|
|
336
345
|
end
|
337
346
|
|
338
347
|
def within_frame(frame_selector)
|
339
|
-
warn
|
348
|
+
warn 'Driver#within_frame is deprecated, please use Session#within_frame'
|
340
349
|
|
341
350
|
frame = case frame_selector
|
342
351
|
when Capybara::Apparition::Node
|
@@ -347,7 +356,7 @@ module Capybara::Apparition
|
|
347
356
|
find_css("iframe[name='#{frame_selector}']")[0]
|
348
357
|
else
|
349
358
|
raise TypeError, 'Unknown frame selector'
|
350
|
-
command(
|
359
|
+
# command('FrameFocus')
|
351
360
|
end
|
352
361
|
|
353
362
|
switch_to_frame(frame)
|
@@ -358,6 +367,10 @@ module Capybara::Apparition
|
|
358
367
|
end
|
359
368
|
end
|
360
369
|
|
370
|
+
def error_messages
|
371
|
+
console_messages('error')
|
372
|
+
end
|
373
|
+
|
361
374
|
private
|
362
375
|
|
363
376
|
def parse_raw_cookie(raw)
|
@@ -385,7 +398,8 @@ module Capybara::Apparition
|
|
385
398
|
raise Capybara::ModalNotFound if modal_text.nil? || (expect_text && !modal_text.match(expect_regexp))
|
386
399
|
rescue Capybara::ModalNotFound => e
|
387
400
|
if timer.expired?
|
388
|
-
raise e, 'Timed out waiting for modal dialog. Unable to find modal dialog.'
|
401
|
+
raise e, 'Timed out waiting for modal dialog. Unable to find modal dialog.' unless found_text
|
402
|
+
|
389
403
|
raise e, 'Unable to find modal dialog' \
|
390
404
|
"#{" with #{expect_text}" if expect_text}" \
|
391
405
|
"#{", did find modal with #{found_text}" if found_text}"
|
@@ -1,8 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'capybara/apparition/errors'
|
4
|
-
require 'capybara/apparition/web_socket_client'
|
5
|
-
require 'capybara/apparition/response'
|
4
|
+
require 'capybara/apparition/driver/web_socket_client'
|
5
|
+
require 'capybara/apparition/driver/response'
|
6
6
|
|
7
7
|
module Capybara::Apparition
|
8
8
|
class ChromeClient
|
File without changes
|
File without changes
|
File without changes
|
@@ -46,7 +46,7 @@ module Capybara::Apparition
|
|
46
46
|
end
|
47
47
|
|
48
48
|
def all_text
|
49
|
-
text = evaluate_on('
|
49
|
+
text = evaluate_on('() => this.textContent')
|
50
50
|
text.to_s.gsub(/[\u200b\u200e\u200f]/, '')
|
51
51
|
.gsub(/[\ \n\f\t\v\u2028\u2029]+/, ' ')
|
52
52
|
.gsub(/\A[[:space:]&&[^\u00a0]]+/, '')
|
@@ -64,20 +64,21 @@ module Capybara::Apparition
|
|
64
64
|
.tr("\u00a0", ' ')
|
65
65
|
end
|
66
66
|
|
67
|
-
|
68
|
-
|
67
|
+
# capybara-webkit method
|
68
|
+
def text
|
69
|
+
warn 'Node#text is deprecated, please use Node#visible_text instead'
|
69
70
|
visible_text
|
70
71
|
end
|
71
72
|
|
72
73
|
def property(name)
|
73
|
-
evaluate_on('
|
74
|
+
evaluate_on('name => this[name]', value: name)
|
74
75
|
end
|
75
76
|
|
76
77
|
def attribute(name)
|
77
78
|
if %w[checked selected].include?(name.to_s)
|
78
79
|
property(name)
|
79
80
|
else
|
80
|
-
evaluate_on('
|
81
|
+
evaluate_on('name => this.getAttribute(name)', value: name)
|
81
82
|
end
|
82
83
|
end
|
83
84
|
|
@@ -95,6 +96,10 @@ module Capybara::Apparition
|
|
95
96
|
evaluate_on GET_VALUE_JS
|
96
97
|
end
|
97
98
|
|
99
|
+
def style(styles)
|
100
|
+
evaluate_on GET_STYLES_JS, value: styles
|
101
|
+
end
|
102
|
+
|
98
103
|
def set(value, **_options)
|
99
104
|
if tag_name == 'input'
|
100
105
|
case self[:type]
|
@@ -137,7 +142,7 @@ module Capybara::Apparition
|
|
137
142
|
end
|
138
143
|
|
139
144
|
def tag_name
|
140
|
-
@tag_name ||= evaluate_on('
|
145
|
+
@tag_name ||= evaluate_on('() => this.tagName').downcase
|
141
146
|
end
|
142
147
|
|
143
148
|
def visible?
|
@@ -169,7 +174,7 @@ module Capybara::Apparition
|
|
169
174
|
begin
|
170
175
|
new_pos = element_click_pos(options)
|
171
176
|
puts "Element moved from #{pos} to #{new_pos}" unless pos == new_pos
|
172
|
-
rescue WrongWorld
|
177
|
+
rescue WrongWorld # rubocop:disable Lint/HandleExceptions
|
173
178
|
end
|
174
179
|
end
|
175
180
|
# Wait a short time to see if click triggers page load
|
@@ -204,19 +209,25 @@ module Capybara::Apparition
|
|
204
209
|
mouseenter: ['MouseEvent'],
|
205
210
|
mouseleave: ['MouseEvent'],
|
206
211
|
mousemove: ['MouseEvent', { bubbles: true, cancelable: true }],
|
207
|
-
|
212
|
+
mouseover: ['MouseEvent', { bubbles: true, cancelable: true }],
|
213
|
+
mouseout: ['MouseEvent', { bubbles: true, cancelable: true }],
|
214
|
+
context_menu: ['MouseEvent', { bubble: true, cancelable: true }],
|
215
|
+
submit: ['Event', { bubbles: true, cancelable: true }],
|
216
|
+
change: ['Event', { bubbles: true, cacnelable: false }],
|
217
|
+
input: ['InputEvent', { bubbles: true, cacnelable: false }],
|
218
|
+
wheel: ['WheelEvent', { bubbles: true, cancelable: true }]
|
208
219
|
}.freeze
|
209
220
|
|
210
|
-
def trigger(name, **options)
|
211
|
-
raise ArgumentError, 'Unknown event' unless EVENTS.key?(name.to_sym)
|
221
|
+
def trigger(name, event_type = nil, **options)
|
222
|
+
raise ArgumentError, 'Unknown event' unless EVENTS.key?(name.to_sym) || event_type
|
212
223
|
|
213
|
-
event_type, opts = *EVENTS[name.to_sym], {}
|
224
|
+
event_type, opts = *EVENTS[name.to_sym], {} if event_type.nil?
|
214
225
|
|
215
226
|
evaluate_on DISPATCH_EVENT_JS, { value: event_type }, { value: name }, value: opts.merge(options)
|
216
227
|
end
|
217
228
|
|
218
229
|
def ==(other)
|
219
|
-
evaluate_on('
|
230
|
+
evaluate_on('el => this == el', objectId: other.id)
|
220
231
|
rescue ObsoleteNode
|
221
232
|
false
|
222
233
|
end
|
@@ -328,8 +339,9 @@ module Capybara::Apparition
|
|
328
339
|
|
329
340
|
def scroll_by(x, y)
|
330
341
|
evaluate_on <<~JS, { value: x }, value: y
|
331
|
-
|
342
|
+
(x, y) => this.scrollBy(x,y)
|
332
343
|
JS
|
344
|
+
self
|
333
345
|
end
|
334
346
|
|
335
347
|
def scroll_to(element, location, position = nil)
|
@@ -350,7 +362,7 @@ module Capybara::Apparition
|
|
350
362
|
obsolete_checked_function = <<~JS
|
351
363
|
function(){
|
352
364
|
if (!this.ownerDocument.contains(this)) { throw 'ObsoleteNode' };
|
353
|
-
|
365
|
+
return (#{page_function.strip}).apply(this, arguments);
|
354
366
|
}
|
355
367
|
JS
|
356
368
|
response = @page.command('Runtime.callFunctionOn',
|
@@ -371,7 +383,7 @@ module Capybara::Apparition
|
|
371
383
|
private
|
372
384
|
|
373
385
|
def in_view_bounding_rect
|
374
|
-
evaluate_on('
|
386
|
+
evaluate_on('() => this.scrollIntoViewIfNeeded()')
|
375
387
|
result = evaluate_on GET_BOUNDING_CLIENT_RECT_JS
|
376
388
|
result = result['model'] if result && result['model']
|
377
389
|
result
|
@@ -422,7 +434,7 @@ module Capybara::Apparition
|
|
422
434
|
value = value.to_s
|
423
435
|
if value.empty? && clear.nil?
|
424
436
|
evaluate_on <<~JS
|
425
|
-
|
437
|
+
() => {
|
426
438
|
this.focus();
|
427
439
|
this.value = '';
|
428
440
|
this.dispatchEvent(new Event('change', { bubbles: true }));
|
@@ -479,7 +491,7 @@ module Capybara::Apparition
|
|
479
491
|
|
480
492
|
def update_value_js(value)
|
481
493
|
evaluate_on(<<~JS, value: value)
|
482
|
-
|
494
|
+
value => {
|
483
495
|
if (document.activeElement !== this){
|
484
496
|
this.focus();
|
485
497
|
}
|
@@ -503,7 +515,7 @@ module Capybara::Apparition
|
|
503
515
|
hit_node = Capybara::Apparition::Node.new(driver, @page, r_o['objectId'])
|
504
516
|
result = begin
|
505
517
|
evaluate_on(<<~JS, objectId: hit_node.id)
|
506
|
-
|
518
|
+
(hit_node) => {
|
507
519
|
if ((hit_node == this) || this.contains(hit_node))
|
508
520
|
return { status: 'success' };
|
509
521
|
return { status: 'failure' };
|
@@ -513,38 +525,6 @@ module Capybara::Apparition
|
|
513
525
|
{ 'status': 'failure' }
|
514
526
|
end
|
515
527
|
OpenStruct.new(success: result['status'] == 'success', selector: r_o['description'])
|
516
|
-
|
517
|
-
# frame_offset = @page.current_frame_offset
|
518
|
-
# # return { status: 'failure' } if x < 0 || y < 0
|
519
|
-
# result = evaluate_on(<<~JS, { value: x - frame_offset[:x] }, value: y - frame_offset[:y])
|
520
|
-
# function(x,y){
|
521
|
-
# const hit_node = document.elementFromPoint(x,y);
|
522
|
-
# if ((hit_node == this) || this.contains(hit_node))
|
523
|
-
# return { status: 'success' };
|
524
|
-
#
|
525
|
-
# const getSelector = function(element){
|
526
|
-
# if (element == null)
|
527
|
-
# return 'Element out of bounds';
|
528
|
-
#
|
529
|
-
# let selector = '';
|
530
|
-
# if (element.tagName != 'HTML')
|
531
|
-
# selector = getSelector(element.parentNode) + ' ';
|
532
|
-
# selector += element.tagName.toLowerCase();
|
533
|
-
# if (element.id)
|
534
|
-
# selector += `#${element.id}`;
|
535
|
-
#
|
536
|
-
# for (let className of element.classList){
|
537
|
-
# if (className != '')
|
538
|
-
# selector += `.${className}`;
|
539
|
-
# }
|
540
|
-
# return selector;
|
541
|
-
# }
|
542
|
-
#
|
543
|
-
# return { status: 'failure', selector: getSelector(hit_node) };
|
544
|
-
# }
|
545
|
-
# JS
|
546
|
-
#
|
547
|
-
# OpenStruct.new(success: result['status'] == 'success', selector: result['selector'])
|
548
528
|
end
|
549
529
|
|
550
530
|
def scroll_element_to_location(element, location)
|
@@ -558,7 +538,7 @@ module Capybara::Apparition
|
|
558
538
|
else
|
559
539
|
raise ArgumentError, "Invalid scroll_to location: #{location}"
|
560
540
|
end
|
561
|
-
element.evaluate_on "
|
541
|
+
element.evaluate_on "() => this.scrollIntoView(#{scroll_opts})"
|
562
542
|
end
|
563
543
|
|
564
544
|
def scroll_to_location(location)
|
@@ -570,12 +550,12 @@ module Capybara::Apparition
|
|
570
550
|
when :center
|
571
551
|
'(this.scrollHeight - this.clientHeight)/2'
|
572
552
|
end
|
573
|
-
evaluate_on "
|
553
|
+
evaluate_on "() => this.scrollTo(0, #{scroll_y})"
|
574
554
|
end
|
575
555
|
|
576
556
|
def scroll_to_coords(x, y)
|
577
557
|
evaluate_on <<~JS, { value: x }, value: y
|
578
|
-
|
558
|
+
(x,y) => this.scrollTo(x,y)
|
579
559
|
JS
|
580
560
|
end
|
581
561
|
|
@@ -831,5 +811,15 @@ module Capybara::Apparition
|
|
831
811
|
this.dispatchEvent(event);
|
832
812
|
}
|
833
813
|
JS
|
814
|
+
|
815
|
+
GET_STYLES_JS = <<~JS
|
816
|
+
function(styles){
|
817
|
+
style = window.getComputedStyle(this);
|
818
|
+
return styles.reduce((res,name) => {
|
819
|
+
res[name] = style[name];
|
820
|
+
return res;
|
821
|
+
}, {})
|
822
|
+
}
|
823
|
+
JS
|
834
824
|
end
|
835
825
|
end
|
@@ -1,8 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'capybara/apparition/frame_manager'
|
4
|
-
require 'capybara/apparition/mouse'
|
5
|
-
require 'capybara/apparition/keyboard'
|
3
|
+
require 'capybara/apparition/page/frame_manager'
|
4
|
+
require 'capybara/apparition/page/mouse'
|
5
|
+
require 'capybara/apparition/page/keyboard'
|
6
6
|
|
7
7
|
module Capybara::Apparition
|
8
8
|
class Page
|
@@ -20,12 +20,13 @@ module Capybara::Apparition
|
|
20
20
|
|
21
21
|
page = Page.new(browser, session, id, ignore_https_errors, screenshot_task_queue, js_errors)
|
22
22
|
|
23
|
-
session.
|
24
|
-
session.command '
|
25
|
-
session.command '
|
23
|
+
session.async_commands 'Network.enable', 'Runtime.enable', 'Security.enable', 'DOM.enable'
|
24
|
+
# session.command 'Network.enable'
|
25
|
+
# session.command 'Runtime.enable'
|
26
|
+
# session.command 'Security.enable'
|
26
27
|
# session.command 'Security.setOverrideCertificateErrors', override: true if ignore_https_errors
|
27
28
|
session.command 'Security.setIgnoreCertificateErrors', ignore: !!ignore_https_errors
|
28
|
-
session.command 'DOM.enable'
|
29
|
+
# session.command 'DOM.enable'
|
29
30
|
# session.command 'Log.enable'
|
30
31
|
if Capybara.save_path
|
31
32
|
session.command 'Page.setDownloadBehavior', behavior: 'allow', downloadPath: Capybara.save_path
|
@@ -46,18 +47,26 @@ module Capybara::Apparition
|
|
46
47
|
@status_code = 0
|
47
48
|
@url_blacklist = []
|
48
49
|
@url_whitelist = []
|
50
|
+
@credentials = nil
|
49
51
|
@auth_attempts = []
|
52
|
+
@proxy_credentials = nil
|
53
|
+
@proxy_auth_attempts = []
|
50
54
|
@perm_headers = {}
|
51
55
|
@temp_headers = {}
|
52
56
|
@temp_no_redirect_headers = {}
|
53
57
|
@viewport_size = nil
|
54
58
|
@network_traffic = []
|
55
59
|
@open_resource_requests = {}
|
60
|
+
@raise_js_errors = js_errors
|
56
61
|
@js_error = nil
|
62
|
+
@modal_mutex = Mutex.new
|
63
|
+
@modal_closed = ConditionVariable.new
|
57
64
|
|
58
65
|
register_event_handlers
|
59
66
|
|
60
|
-
register_js_error_handler if js_errors
|
67
|
+
register_js_error_handler # if js_errors
|
68
|
+
|
69
|
+
setup_network_interception if browser.proxy_auth
|
61
70
|
end
|
62
71
|
|
63
72
|
def usable?
|
@@ -70,6 +79,7 @@ module Capybara::Apparition
|
|
70
79
|
@response_headers = {}
|
71
80
|
@status_code = 0
|
72
81
|
@auth_attempts = []
|
82
|
+
@proxy_auth_attempts = []
|
73
83
|
@perm_headers = {}
|
74
84
|
end
|
75
85
|
|
@@ -78,6 +88,11 @@ module Capybara::Apparition
|
|
78
88
|
@modals.push(modal_response)
|
79
89
|
end
|
80
90
|
|
91
|
+
def proxy_credentials=(creds)
|
92
|
+
@proxy_credentials = creds
|
93
|
+
setup_network_interception
|
94
|
+
end
|
95
|
+
|
81
96
|
def credentials=(creds)
|
82
97
|
@credentials = creds
|
83
98
|
setup_network_interception
|
@@ -151,7 +166,6 @@ module Capybara::Apparition
|
|
151
166
|
# Wait for the frame creation messages to be processed
|
152
167
|
if timer.expired?
|
153
168
|
puts 'Timed out waiting from frame to be ready'
|
154
|
-
# byebug
|
155
169
|
raise TimeoutError.new('push_frame')
|
156
170
|
end
|
157
171
|
sleep 0.1
|
@@ -181,25 +195,41 @@ module Capybara::Apparition
|
|
181
195
|
|
182
196
|
def execute(script, *args)
|
183
197
|
wait_for_loaded
|
184
|
-
_execute_script
|
198
|
+
_execute_script <<~JS, *args
|
199
|
+
function(){
|
200
|
+
#{script}
|
201
|
+
}
|
202
|
+
JS
|
185
203
|
nil
|
186
204
|
end
|
187
205
|
|
188
206
|
def evaluate(script, *args)
|
189
207
|
wait_for_loaded
|
190
|
-
_execute_script
|
208
|
+
_execute_script <<~JS, *args
|
209
|
+
function(){
|
210
|
+
let apparitionId=0;
|
211
|
+
return (function ider(obj){
|
212
|
+
if (obj && (typeof obj == 'object') && !obj.apparitionId){
|
213
|
+
obj.apparitionId = ++apparitionId;
|
214
|
+
Reflect.ownKeys(obj).forEach(key => ider(obj[key]))
|
215
|
+
}
|
216
|
+
return obj;
|
217
|
+
})((function(){ return #{script} }).apply(this, arguments))
|
218
|
+
}
|
219
|
+
JS
|
191
220
|
end
|
192
221
|
|
193
222
|
def evaluate_async(script, _wait_time, *args)
|
194
223
|
wait_for_loaded
|
195
|
-
_execute_script
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
224
|
+
_execute_script <<~JS, *args
|
225
|
+
function(){
|
226
|
+
var args = Array.prototype.slice.call(arguments);
|
227
|
+
return new Promise((resolve, reject)=>{
|
228
|
+
args.push(resolve);
|
229
|
+
(function(){ #{script} }).apply(this, args);
|
230
|
+
});
|
231
|
+
}
|
232
|
+
JS
|
203
233
|
end
|
204
234
|
|
205
235
|
def refresh
|
@@ -288,9 +318,15 @@ module Capybara::Apparition
|
|
288
318
|
wait_for_loaded
|
289
319
|
@viewport_size = { width: width, height: height }
|
290
320
|
result = @browser.command('Browser.getWindowForTarget', targetId: @target_id)
|
291
|
-
|
292
|
-
|
293
|
-
|
321
|
+
begin
|
322
|
+
@browser.command('Browser.setWindowBounds',
|
323
|
+
windowId: result['windowId'],
|
324
|
+
bounds: { width: width, height: height })
|
325
|
+
rescue WrongWorld # TODO: Fix Error naming here
|
326
|
+
@browser.command('Browser.setWindowBounds', windowId: result['windowId'], bounds: { windowState: 'normal' })
|
327
|
+
retry
|
328
|
+
end
|
329
|
+
|
294
330
|
metrics = {
|
295
331
|
mobile: false,
|
296
332
|
width: width,
|
@@ -339,7 +375,7 @@ module Capybara::Apparition
|
|
339
375
|
|
340
376
|
def update_headers(async: false)
|
341
377
|
method = async ? :async_command : :command
|
342
|
-
if (ua = extra_headers.find { |k, _v| k
|
378
|
+
if (ua = extra_headers.find { |k, _v| k =~ /^User-Agent$/i })
|
343
379
|
send(method, 'Network.setUserAgentOverride', userAgent: ua[1])
|
344
380
|
end
|
345
381
|
send(method, 'Network.setExtraHTTPHeaders', headers: extra_headers)
|
@@ -378,23 +414,14 @@ module Capybara::Apparition
|
|
378
414
|
def register_event_handlers
|
379
415
|
@session.on 'Page.javascriptDialogOpening' do |params|
|
380
416
|
type = params['type'].to_sym
|
381
|
-
accept =
|
382
|
-
|
383
|
-
else
|
384
|
-
response = @modals.pop
|
385
|
-
if !response&.key?(type)
|
386
|
-
handle_unexpected_modal(type)
|
387
|
-
else
|
388
|
-
@modal_messages.push(params['message'])
|
389
|
-
response[type]
|
390
|
-
end
|
391
|
-
end
|
417
|
+
accept = accept_modal?(type, message: params['message'], manual: params['hasBrowserHandler'])
|
418
|
+
next if accept.nil?
|
392
419
|
|
393
420
|
if type == :prompt
|
394
421
|
case accept
|
395
422
|
when false
|
396
423
|
async_command('Page.handleJavaScriptDialog', accept: false)
|
397
|
-
when
|
424
|
+
when true
|
398
425
|
async_command('Page.handleJavaScriptDialog', accept: true, promptText: params['defaultPrompt'])
|
399
426
|
else
|
400
427
|
async_command('Page.handleJavaScriptDialog', accept: true, promptText: accept)
|
@@ -404,6 +431,12 @@ module Capybara::Apparition
|
|
404
431
|
end
|
405
432
|
end
|
406
433
|
|
434
|
+
@session.on 'Page.javascriptDialogClosed' do
|
435
|
+
@modal_mutex.synchronize do
|
436
|
+
@modal_closed.signal
|
437
|
+
end
|
438
|
+
end
|
439
|
+
|
407
440
|
@session.on 'Page.windowOpen' do |params|
|
408
441
|
puts "**** windowOpen was called with: #{params}" if ENV['DEBUG']
|
409
442
|
# TODO: find a better way to handle this
|
@@ -474,7 +507,6 @@ module Capybara::Apparition
|
|
474
507
|
puts "unknown frame for context #{frame_id}"
|
475
508
|
end
|
476
509
|
end
|
477
|
-
# command 'Network.setRequestInterception', patterns: [{urlPattern: '*'}]
|
478
510
|
end
|
479
511
|
|
480
512
|
@session.on 'Runtime.executionContextDestroyed' do |params|
|
@@ -519,15 +551,24 @@ module Capybara::Apparition
|
|
519
551
|
@session.on 'Network.requestIntercepted' do |params|
|
520
552
|
request, interception_id = *params.values_at('request', 'interceptionId')
|
521
553
|
if params['authChallenge']
|
522
|
-
|
554
|
+
if params['authChallenge']['source'] == 'Proxy'
|
555
|
+
handle_proxy_auth(interception_id)
|
556
|
+
else
|
557
|
+
handle_user_auth(interception_id)
|
558
|
+
end
|
523
559
|
else
|
524
560
|
process_intercepted_request(interception_id, request, params['isNavigationRequest'])
|
525
561
|
end
|
526
562
|
end
|
527
563
|
|
528
564
|
@session.on 'Runtime.consoleAPICalled' do |params|
|
565
|
+
# {"type"=>"log", "args"=>[{"type"=>"string", "value"=>"hello"}], "executionContextId"=>2, "timestamp"=>1548722854903.285, "stackTrace"=>{"callFrames"=>[{"functionName"=>"", "scriptId"=>"15", "url"=>"http://127.0.0.1:53977/", "lineNumber"=>6, "columnNumber"=>22}]}}
|
566
|
+
details = params.dig('stackTrace', 'callFrames')&.first
|
529
567
|
@browser.console.log(params['type'],
|
530
|
-
|
568
|
+
params['args'].map { |arg| arg['description'] || arg['value'] }.join(' ').to_s,
|
569
|
+
source: details['url'].empty? ? nil : details['url'],
|
570
|
+
line_number: details['lineNumber'].zero? ? nil : details['lineNumber'],
|
571
|
+
columnNumber: details['columnNumber'].zero? ? nil : details['columnNumber'])
|
531
572
|
end
|
532
573
|
|
533
574
|
# @session.on 'Security.certificateError' do |params|
|
@@ -544,7 +585,14 @@ module Capybara::Apparition
|
|
544
585
|
|
545
586
|
def register_js_error_handler
|
546
587
|
@session.on 'Runtime.exceptionThrown' do |params|
|
547
|
-
@js_error ||= params.dig('exceptionDetails', 'exception', 'description')
|
588
|
+
@js_error ||= params.dig('exceptionDetails', 'exception', 'description') if @raise_js_errors
|
589
|
+
|
590
|
+
details = params.dig('exceptionDetails', 'stackTrace', 'callFrames')&.first
|
591
|
+
@browser.console.log('error',
|
592
|
+
params.dig('exceptionDetails', 'exception', 'description'),
|
593
|
+
source: details['url'].empty? ? nil : details['url'],
|
594
|
+
line_number: details['lineNumber'].zero? ? nil : details['lineNumber'],
|
595
|
+
columnNumber: details['columnNumber'].zero? ? nil : details['columnNumber'])
|
548
596
|
end
|
549
597
|
end
|
550
598
|
|
@@ -607,6 +655,20 @@ module Capybara::Apparition
|
|
607
655
|
wait_for_loaded
|
608
656
|
end
|
609
657
|
|
658
|
+
def accept_modal?(type, message:, manual:)
|
659
|
+
if type == :beforeunload
|
660
|
+
true
|
661
|
+
else
|
662
|
+
response = @modals.pop
|
663
|
+
if !response&.key?(type)
|
664
|
+
manual ? manual_unexpected_modal(type) : auto_unexpected_modal(type)
|
665
|
+
else
|
666
|
+
@modal_messages.push(message)
|
667
|
+
response[type].nil? ? true : response[type]
|
668
|
+
end
|
669
|
+
end
|
670
|
+
end
|
671
|
+
|
610
672
|
def _execute_script(script, *args)
|
611
673
|
args = args.map do |arg|
|
612
674
|
if arg.is_a? Capybara::Apparition::Node
|
@@ -658,26 +720,48 @@ module Capybara::Apparition
|
|
658
720
|
decode_result(result)
|
659
721
|
end
|
660
722
|
|
661
|
-
def
|
723
|
+
def manual_unexpected_modal(type)
|
724
|
+
warn "An unexpected #{type} modal has opened - please close"
|
725
|
+
@modal_mutex.synchronize do
|
726
|
+
@modal_closed.wait(@modal_mutex)
|
727
|
+
end
|
728
|
+
nil
|
729
|
+
end
|
730
|
+
|
731
|
+
def auto_unexpected_modal(type)
|
662
732
|
case type
|
663
733
|
when :prompt
|
664
734
|
warn 'Unexpected prompt modal - accepting with the default value.' \
|
665
|
-
'
|
666
|
-
nil
|
735
|
+
'You should be using `accept_prompt` or `dismiss_prompt`.'
|
667
736
|
when :confirm
|
668
737
|
warn 'Unexpected confirm modal - accepting.' \
|
669
|
-
'
|
670
|
-
true
|
738
|
+
'You should be using `accept_confirm` or `dismiss_confirm`.'
|
671
739
|
else
|
672
|
-
|
740
|
+
warn 'Unexpected alert modal - clearing.' \
|
741
|
+
'You should be using `accept_alert`.'
|
673
742
|
end
|
743
|
+
true
|
674
744
|
end
|
675
745
|
|
676
|
-
def
|
746
|
+
def handle_proxy_auth(interception_id)
|
747
|
+
credentials_response = if @proxy_auth_attempts.include?(interception_id)
|
748
|
+
puts 'Cancelling proxy auth' if ENV['DEBUG']
|
749
|
+
{ response: 'CancelAuth' }
|
750
|
+
else
|
751
|
+
puts 'Replying with proxy auth credentials' if ENV['DEBUG']
|
752
|
+
@proxy_auth_attempts.push(interception_id)
|
753
|
+
{ response: 'ProvideCredentials' }.merge(@browser.proxy_auth || {})
|
754
|
+
end
|
755
|
+
continue_request(interception_id, authChallengeResponse: credentials_response)
|
756
|
+
end
|
757
|
+
|
758
|
+
def handle_user_auth(interception_id)
|
677
759
|
credentials_response = if @auth_attempts.include?(interception_id)
|
760
|
+
puts 'Cancelling auth' if ENV['DEBUG']
|
678
761
|
{ response: 'CancelAuth' }
|
679
762
|
else
|
680
763
|
@auth_attempts.push(interception_id)
|
764
|
+
puts 'Replying with auth credentials' if ENV['DEBUG']
|
681
765
|
{ response: 'ProvideCredentials' }.merge(@credentials || {})
|
682
766
|
end
|
683
767
|
continue_request(interception_id, authChallengeResponse: credentials_response)
|
@@ -690,7 +774,7 @@ module Capybara::Apparition
|
|
690
774
|
objectId: result['objectId'],
|
691
775
|
ownProperties: true)
|
692
776
|
|
693
|
-
properties = remote_object['result']
|
777
|
+
properties = remote_object['result'].reject { |prop| prop['name'] == 'apparitionId' }
|
694
778
|
results = []
|
695
779
|
|
696
780
|
properties.each do |property|
|
@@ -714,16 +798,22 @@ module Capybara::Apparition
|
|
714
798
|
remote_object = command('Runtime.getProperties',
|
715
799
|
objectId: result['objectId'],
|
716
800
|
ownProperties: true)
|
717
|
-
|
718
|
-
|
719
|
-
|
801
|
+
|
802
|
+
# stable_id went away in Chrome 72 - we add our own id in evaluate
|
803
|
+
# stable_id = remote_object['internalProperties']
|
804
|
+
# &.find { |prop| prop['name'] == '[[StableObjectId]]' }
|
805
|
+
# &.dig('value', 'value')
|
806
|
+
|
720
807
|
# We could actually return cyclic objects here but Capybara would need to be updated to support
|
721
|
-
# return object_cache[stable_id] if object_cache.key?(stable_id)
|
808
|
+
# return object_cache[stable_id] if object_cache.key?(stable_id) # and update the cache to be a hash
|
722
809
|
|
810
|
+
stable_id = remote_object['result']
|
811
|
+
&.find { |prop| prop['name'] == 'apparitionId'}
|
812
|
+
&.dig('value', 'value')
|
723
813
|
return '(cyclic structure)' if object_cache.key?(stable_id)
|
724
814
|
|
725
815
|
object_cache[stable_id] = {}
|
726
|
-
properties = remote_object['result']
|
816
|
+
properties = remote_object['result'].reject { |prop| prop['name'] == "apparitionId"}
|
727
817
|
|
728
818
|
return properties.each_with_object(object_cache[stable_id]) do |property, memo|
|
729
819
|
if property['enumerable']
|
File without changes
|
File without changes
|
@@ -10,10 +10,12 @@ module Capybara::Apparition
|
|
10
10
|
|
11
11
|
def click_at(x:, y:, button: 'left', count: 1, modifiers: [])
|
12
12
|
move_to x: x, y: y
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
13
|
+
count.times do |num|
|
14
|
+
@keyboard.with_keys(modifiers) do
|
15
|
+
mouse_params = { x: x, y: y, button: button, count: num+1 }
|
16
|
+
down mouse_params
|
17
|
+
up mouse_params
|
18
|
+
end
|
17
19
|
end
|
18
20
|
self
|
19
21
|
end
|
@@ -24,21 +26,21 @@ module Capybara::Apparition
|
|
24
26
|
self
|
25
27
|
end
|
26
28
|
|
27
|
-
def down(**options)
|
28
|
-
options = @current_pos.merge(options)
|
29
|
+
def down(button: 'left', **options)
|
30
|
+
options = @current_pos.merge(button: button).merge(options)
|
29
31
|
mouse_event('mousePressed', options)
|
30
32
|
self
|
31
33
|
end
|
32
34
|
|
33
|
-
def up(**options)
|
34
|
-
options = @current_pos.merge(options)
|
35
|
+
def up(button: 'left', **options)
|
36
|
+
options = @current_pos.merge(button: button).merge(options)
|
35
37
|
mouse_event('mouseReleased', options)
|
36
38
|
self
|
37
39
|
end
|
38
40
|
|
39
41
|
private
|
40
42
|
|
41
|
-
def mouse_event(type, x:, y:, button: '
|
43
|
+
def mouse_event(type, x:, y:, button: 'none', count: 1)
|
42
44
|
@page.command('Input.dispatchMouseEvent',
|
43
45
|
type: type,
|
44
46
|
button: button,
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: apparition
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Thomas Walpole
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-01-
|
11
|
+
date: 2019-01-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: backports
|
@@ -184,6 +184,20 @@ dependencies:
|
|
184
184
|
- - "~>"
|
185
185
|
- !ruby/object:Gem::Version
|
186
186
|
version: '3.6'
|
187
|
+
- !ruby/object:Gem::Dependency
|
188
|
+
name: selenium-webdriver
|
189
|
+
requirement: !ruby/object:Gem::Requirement
|
190
|
+
requirements:
|
191
|
+
- - ">="
|
192
|
+
- !ruby/object:Gem::Version
|
193
|
+
version: '0'
|
194
|
+
type: :development
|
195
|
+
prerelease: false
|
196
|
+
version_requirements: !ruby/object:Gem::Requirement
|
197
|
+
requirements:
|
198
|
+
- - ">="
|
199
|
+
- !ruby/object:Gem::Version
|
200
|
+
version: '0'
|
187
201
|
- !ruby/object:Gem::Dependency
|
188
202
|
name: sinatra
|
189
203
|
requirement: !ruby/object:Gem::Requirement
|
@@ -210,20 +224,19 @@ files:
|
|
210
224
|
- README.md
|
211
225
|
- lib/capybara/apparition.rb
|
212
226
|
- lib/capybara/apparition/browser.rb
|
213
|
-
- lib/capybara/apparition/chrome_client.rb
|
214
227
|
- lib/capybara/apparition/console.rb
|
215
228
|
- lib/capybara/apparition/cookie.rb
|
229
|
+
- lib/capybara/apparition/cookie_jar.rb
|
216
230
|
- lib/capybara/apparition/dev_tools_protocol/session.rb
|
217
231
|
- lib/capybara/apparition/dev_tools_protocol/target.rb
|
218
232
|
- lib/capybara/apparition/dev_tools_protocol/target_manager.rb
|
219
233
|
- lib/capybara/apparition/driver.rb
|
234
|
+
- lib/capybara/apparition/driver/chrome_client.rb
|
235
|
+
- lib/capybara/apparition/driver/launcher.rb
|
236
|
+
- lib/capybara/apparition/driver/response.rb
|
237
|
+
- lib/capybara/apparition/driver/web_socket_client.rb
|
220
238
|
- lib/capybara/apparition/errors.rb
|
221
|
-
- lib/capybara/apparition/frame.rb
|
222
|
-
- lib/capybara/apparition/frame_manager.rb
|
223
239
|
- lib/capybara/apparition/inspector.rb
|
224
|
-
- lib/capybara/apparition/keyboard.rb
|
225
|
-
- lib/capybara/apparition/launcher.rb
|
226
|
-
- lib/capybara/apparition/mouse.rb
|
227
240
|
- lib/capybara/apparition/network_traffic.rb
|
228
241
|
- lib/capybara/apparition/network_traffic/error.rb
|
229
242
|
- lib/capybara/apparition/network_traffic/request.rb
|
@@ -231,10 +244,12 @@ files:
|
|
231
244
|
- lib/capybara/apparition/node.rb
|
232
245
|
- lib/capybara/apparition/node/drag.rb
|
233
246
|
- lib/capybara/apparition/page.rb
|
234
|
-
- lib/capybara/apparition/
|
247
|
+
- lib/capybara/apparition/page/frame.rb
|
248
|
+
- lib/capybara/apparition/page/frame_manager.rb
|
249
|
+
- lib/capybara/apparition/page/keyboard.rb
|
250
|
+
- lib/capybara/apparition/page/mouse.rb
|
235
251
|
- lib/capybara/apparition/utility.rb
|
236
252
|
- lib/capybara/apparition/version.rb
|
237
|
-
- lib/capybara/apparition/web_socket_client.rb
|
238
253
|
homepage: https://github.com/twalpole/apparition
|
239
254
|
licenses:
|
240
255
|
- MIT
|