apparition 0.0.3 → 0.0.4
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 +16 -84
- data/lib/capybara/apparition/console.rb +23 -0
- data/lib/capybara/apparition/cookie.rb +5 -0
- data/lib/capybara/apparition/driver.rb +54 -9
- data/lib/capybara/apparition/errors.rb +2 -0
- data/lib/capybara/apparition/keyboard.rb +1 -0
- data/lib/capybara/apparition/node.rb +16 -10
- data/lib/capybara/apparition/page.rb +6 -5
- data/lib/capybara/apparition/version.rb +1 -1
- data/lib/capybara/apparition.rb +2 -0
- metadata +18 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 69753c37a3e00ce9d57e86847601bef5e39a820ebef96db2c4ad7a6cb922f341
|
4
|
+
data.tar.gz: 486caf74087a17e078b39e4960a0c707b090142f1831d12b9755ad8b2cbb0596
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2f512ba7bbaca565d304a2ac0ede0d1c2b41fd3dc38d7f00b8dbe30b75bba2bbf3c35d7bcea2b00a17bdcbdb9d1702c27efcdfb9ef082b75de3988e7e48664c6
|
7
|
+
data.tar.gz: e01438d8900cd67015e0b473e7f710528ac1d8d4597cb8d0f47c97a1971a914b63cb52013bc1958d46621be58123105e1ed1f3d8f9e033ca0d908490fb152f8f
|
data/README.md
CHANGED
@@ -51,7 +51,7 @@ Apparition supports all Capybara features, and the following extended features:
|
|
51
51
|
* `page.driver.render_base64(format, options)`
|
52
52
|
* `page.driver.scroll_to(left, top)`
|
53
53
|
* `page.driver.basic_authorize(user, password)`
|
54
|
-
* `page.driver.set_proxy(
|
54
|
+
* `page.driver.set_proxy(host, port, type, user, password, bypass: [bypass list passed to chrome])`
|
55
55
|
* cookie handling
|
56
56
|
* extra headers
|
57
57
|
|
@@ -3,21 +3,31 @@
|
|
3
3
|
require 'capybara/apparition/errors'
|
4
4
|
require 'capybara/apparition/dev_tools_protocol/target_manager'
|
5
5
|
require 'capybara/apparition/page'
|
6
|
+
require 'capybara/apparition/console'
|
6
7
|
require 'json'
|
7
8
|
require 'time'
|
8
9
|
|
9
10
|
module Capybara::Apparition
|
10
11
|
class Browser
|
11
|
-
attr_reader :client, :
|
12
|
+
attr_reader :client, :paper_size, :zoom_factor, :console
|
13
|
+
extend Forwardable
|
14
|
+
|
15
|
+
delegate %i[visit current_url status_code
|
16
|
+
title frame_title frame_url
|
17
|
+
find scroll_to clear_network_traffic
|
18
|
+
evaluate evaluate_async execute
|
19
|
+
fullscreen maximize
|
20
|
+
response_headers
|
21
|
+
go_back go_forward refresh] => :current_page
|
12
22
|
|
13
23
|
def initialize(client, logger = nil)
|
14
24
|
@client = client
|
15
|
-
@logger = logger
|
16
25
|
@current_page_handle = nil
|
17
26
|
@targets = Capybara::Apparition::DevToolsProtocol::TargetManager.new
|
18
27
|
@context_id = nil
|
19
28
|
@js_errors = true
|
20
29
|
@ignore_https_errors = false
|
30
|
+
@console = Console.new(logger)
|
21
31
|
|
22
32
|
initialize_handlers
|
23
33
|
|
@@ -39,18 +49,6 @@ module Capybara::Apparition
|
|
39
49
|
current_page.clear_network_traffic
|
40
50
|
end
|
41
51
|
|
42
|
-
def visit(url)
|
43
|
-
current_page.visit url
|
44
|
-
end
|
45
|
-
|
46
|
-
def current_url
|
47
|
-
current_page.current_url
|
48
|
-
end
|
49
|
-
|
50
|
-
def status_code
|
51
|
-
current_page.status_code
|
52
|
-
end
|
53
|
-
|
54
52
|
def body
|
55
53
|
current_page.content
|
56
54
|
end
|
@@ -60,40 +58,10 @@ module Capybara::Apparition
|
|
60
58
|
# command 'source'
|
61
59
|
end
|
62
60
|
|
63
|
-
def title
|
64
|
-
# Updated info doesn't have correct title when changed programmatically
|
65
|
-
# current_target.title
|
66
|
-
current_page.title
|
67
|
-
end
|
68
|
-
|
69
|
-
def frame_title
|
70
|
-
current_page.frame_title
|
71
|
-
end
|
72
|
-
|
73
|
-
def frame_url
|
74
|
-
current_page.frame_url
|
75
|
-
end
|
76
|
-
|
77
|
-
def find(method, selector)
|
78
|
-
current_page.find(method, selector)
|
79
|
-
end
|
80
|
-
|
81
61
|
def click_coordinates(x, y)
|
82
62
|
current_page.click_at(x, y)
|
83
63
|
end
|
84
64
|
|
85
|
-
def evaluate(script, *args)
|
86
|
-
current_page.evaluate(script, *args)
|
87
|
-
end
|
88
|
-
|
89
|
-
def evaluate_async(script, wait_time, *args)
|
90
|
-
current_page.evaluate_async(script, wait_time, *args)
|
91
|
-
end
|
92
|
-
|
93
|
-
def execute(script, *args)
|
94
|
-
current_page.execute(script, *args)
|
95
|
-
end
|
96
|
-
|
97
65
|
def switch_to_frame(frame)
|
98
66
|
case frame
|
99
67
|
when Capybara::Node::Base
|
@@ -166,10 +134,6 @@ module Capybara::Apparition
|
|
166
134
|
true
|
167
135
|
end
|
168
136
|
|
169
|
-
def scroll_to(left, top)
|
170
|
-
current_page.scroll_to(left, top)
|
171
|
-
end
|
172
|
-
|
173
137
|
def render(path, options = {})
|
174
138
|
check_render_options!(options, path)
|
175
139
|
img_data = current_page.render(options)
|
@@ -197,14 +161,6 @@ module Capybara::Apparition
|
|
197
161
|
current_page.set_viewport width: width, height: height, screen: screen
|
198
162
|
end
|
199
163
|
|
200
|
-
def fullscreen
|
201
|
-
current_page.fullscreen
|
202
|
-
end
|
203
|
-
|
204
|
-
def maximize
|
205
|
-
current_page.maximize
|
206
|
-
end
|
207
|
-
|
208
164
|
def network_traffic(type = nil)
|
209
165
|
case type
|
210
166
|
when :blocked
|
@@ -214,18 +170,6 @@ module Capybara::Apparition
|
|
214
170
|
end
|
215
171
|
end
|
216
172
|
|
217
|
-
def clear_network_traffic
|
218
|
-
current_page.clear_network_traffic
|
219
|
-
end
|
220
|
-
|
221
|
-
def set_proxy(ip, port, type, user, password)
|
222
|
-
args = [ip, port, type]
|
223
|
-
args << user if user
|
224
|
-
args << password if password
|
225
|
-
# TODO: Implement via CDP if possible
|
226
|
-
# command('set_proxy', *args)
|
227
|
-
end
|
228
|
-
|
229
173
|
def headers
|
230
174
|
current_page.extra_headers
|
231
175
|
end
|
@@ -260,10 +204,6 @@ module Capybara::Apparition
|
|
260
204
|
end
|
261
205
|
end
|
262
206
|
|
263
|
-
def response_headers
|
264
|
-
current_page.response_headers
|
265
|
-
end
|
266
|
-
|
267
207
|
def cookies
|
268
208
|
current_page.command('Network.getCookies')['cookies'].each_with_object({}) do |c, h|
|
269
209
|
h[c['name']] = Cookie.new(c)
|
@@ -343,18 +283,6 @@ module Capybara::Apparition
|
|
343
283
|
raise
|
344
284
|
end
|
345
285
|
|
346
|
-
def go_back
|
347
|
-
current_page.go_back
|
348
|
-
end
|
349
|
-
|
350
|
-
def go_forward
|
351
|
-
current_page.go_forward
|
352
|
-
end
|
353
|
-
|
354
|
-
def refresh
|
355
|
-
current_page.refresh
|
356
|
-
end
|
357
|
-
|
358
286
|
def accept_alert
|
359
287
|
current_page.add_modal(alert: true)
|
360
288
|
end
|
@@ -383,6 +311,10 @@ module Capybara::Apparition
|
|
383
311
|
current_target.page
|
384
312
|
end
|
385
313
|
|
314
|
+
def console_messages
|
315
|
+
console.messages
|
316
|
+
end
|
317
|
+
|
386
318
|
private
|
387
319
|
|
388
320
|
def current_target
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Capybara::Apparition
|
4
|
+
class Console
|
5
|
+
def initialize(logger = nil)
|
6
|
+
@logger = logger
|
7
|
+
@messages = []
|
8
|
+
end
|
9
|
+
|
10
|
+
def log(type, message)
|
11
|
+
@messages << OpenStruct.new(type: type, message: message)
|
12
|
+
@logger&.puts message
|
13
|
+
end
|
14
|
+
|
15
|
+
def clear
|
16
|
+
@messages.clear
|
17
|
+
end
|
18
|
+
|
19
|
+
def messages
|
20
|
+
@messages
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -22,7 +22,8 @@ module Capybara::Apparition
|
|
22
22
|
headers headers= add_headers
|
23
23
|
cookies remove_cookie clear_cookies cookies_enabled=
|
24
24
|
clear_memory_cache
|
25
|
-
go_back go_forward refresh
|
25
|
+
go_back go_forward refresh
|
26
|
+
console_messages] => :browser
|
26
27
|
|
27
28
|
def initialize(app, options = {})
|
28
29
|
@app = app
|
@@ -37,9 +38,9 @@ module Capybara::Apparition
|
|
37
38
|
true
|
38
39
|
end
|
39
40
|
|
40
|
-
def chrome_url
|
41
|
-
|
42
|
-
end
|
41
|
+
# def chrome_url
|
42
|
+
# 'ws://localhost:9223'
|
43
|
+
# end
|
43
44
|
|
44
45
|
def browser
|
45
46
|
@browser ||= begin
|
@@ -64,6 +65,7 @@ module Capybara::Apparition
|
|
64
65
|
browser_options['remote-debugging-port'] = options[:port] || 0
|
65
66
|
browser_options['remote-debugging-address'] = options[:host] if options[:host]
|
66
67
|
browser_options['window-size'] = options[:window_size].join(',') if options[:window_size]
|
68
|
+
browser_options.merge! @options[:browser] if @options[:browser]
|
67
69
|
@launcher ||= Browser::Launcher.start(
|
68
70
|
headless: options[:headless] != false,
|
69
71
|
browser: browser_options
|
@@ -194,13 +196,19 @@ module Capybara::Apparition
|
|
194
196
|
end
|
195
197
|
end
|
196
198
|
|
197
|
-
def set_proxy(
|
198
|
-
|
199
|
+
def set_proxy(host, port, type = nil, user = nil, password = nil, bypass: [])
|
200
|
+
# TODO: Look at implementing via the CDP Fetch domain
|
201
|
+
raise ArgumentError, "Proxy auth is not yet implented" if user || password
|
202
|
+
@options[:browser] ||= {}
|
203
|
+
@options[:browser].merge!("proxy-server" => "#{type+"=" if type}#{host}:#{port}")
|
204
|
+
bypass = Array(bypass).join(';')
|
205
|
+
@options[:browser].merge!("proxy-bypass-list" => bypass) unless bypass.empty?
|
199
206
|
end
|
200
207
|
|
201
208
|
def add_header(name, value, options = {})
|
202
209
|
browser.add_header({ name => value }, { permanent: true }.merge(options))
|
203
210
|
end
|
211
|
+
alias_method :header, :add_header
|
204
212
|
|
205
213
|
def response_headers
|
206
214
|
browser.response_headers.each_with_object({}) do |(key, value), hsh|
|
@@ -208,7 +216,9 @@ module Capybara::Apparition
|
|
208
216
|
end
|
209
217
|
end
|
210
218
|
|
211
|
-
def set_cookie(name, value, options = {})
|
219
|
+
def set_cookie(name, value=nil, options = {})
|
220
|
+
name, value, options = parse_raw_cookie(name) if value.nil?
|
221
|
+
|
212
222
|
options[:name] ||= name
|
213
223
|
options[:value] ||= value
|
214
224
|
options[:domain] ||= begin
|
@@ -227,6 +237,7 @@ module Capybara::Apparition
|
|
227
237
|
# credentials = ["#{user}:#{password}"].pack('m*').strip
|
228
238
|
# add_header('Authorization', "Basic #{credentials}")
|
229
239
|
end
|
240
|
+
alias_method :authenticate, :basic_authorize
|
230
241
|
|
231
242
|
def debug
|
232
243
|
if @options[:inspector]
|
@@ -324,8 +335,41 @@ module Capybara::Apparition
|
|
324
335
|
client.timeout = sec
|
325
336
|
end
|
326
337
|
|
338
|
+
def within_frame(frame_selector)
|
339
|
+
warn "Driver#within_frame is deprecated, please use Session#within_frame"
|
340
|
+
|
341
|
+
frame = case frame_selector
|
342
|
+
when Capybara::Apparition::Node
|
343
|
+
frame_selector
|
344
|
+
when Integer
|
345
|
+
find_css('iframe')[frame_selector]
|
346
|
+
when String
|
347
|
+
find_css("iframe[name='#{frame_selector}']")[0]
|
348
|
+
else
|
349
|
+
raise TypeError, 'Unknown frame selector'
|
350
|
+
command("FrameFocus")
|
351
|
+
end
|
352
|
+
|
353
|
+
switch_to_frame(frame)
|
354
|
+
begin
|
355
|
+
yield
|
356
|
+
ensure
|
357
|
+
switch_to_frame(:parent)
|
358
|
+
end
|
359
|
+
end
|
360
|
+
|
327
361
|
private
|
328
362
|
|
363
|
+
def parse_raw_cookie(raw)
|
364
|
+
parts = raw.split(/;\s*/)
|
365
|
+
name, value = parts[0].split('=', 2)
|
366
|
+
options = parts[1..-1].each_with_object({}) do |part, opts|
|
367
|
+
name, value = part.split('=', 2)
|
368
|
+
opts[name.to_sym] = value
|
369
|
+
end
|
370
|
+
[name, value, options]
|
371
|
+
end
|
372
|
+
|
329
373
|
def screen_size
|
330
374
|
options[:screen_size] || [1366, 768]
|
331
375
|
end
|
@@ -341,8 +385,9 @@ module Capybara::Apparition
|
|
341
385
|
raise Capybara::ModalNotFound if modal_text.nil? || (expect_text && !modal_text.match(expect_regexp))
|
342
386
|
rescue Capybara::ModalNotFound => e
|
343
387
|
if timer.expired?
|
344
|
-
raise e, 'Unable to find modal dialog'
|
345
|
-
|
388
|
+
raise e, 'Timed out waiting for modal dialog. Unable to find modal dialog.' if !found_text
|
389
|
+
raise e, 'Unable to find modal dialog' \
|
390
|
+
"#{" with #{expect_text}" if expect_text}" \
|
346
391
|
"#{", did find modal with #{found_text}" if found_text}"
|
347
392
|
end
|
348
393
|
sleep(0.05)
|
@@ -128,12 +128,14 @@ module Capybara
|
|
128
128
|
'new element.'
|
129
129
|
end
|
130
130
|
end
|
131
|
+
NodeNotAttachedError = ObsoleteNode
|
131
132
|
|
132
133
|
class WrongWorld < ObsoleteNode
|
133
134
|
def message
|
134
135
|
'The element you are trying to access is not from the current page'
|
135
136
|
end
|
136
137
|
end
|
138
|
+
NodeNotAttachedError = ObsoleteNode
|
137
139
|
|
138
140
|
class UnsupportedFeature < ClientError
|
139
141
|
def name
|
@@ -186,6 +186,7 @@ module Capybara::Apparition
|
|
186
186
|
'abort': { 'keyCode': 3, 'code': 'Abort', 'key': 'Cancel' },
|
187
187
|
'help': { 'keyCode': 6, 'code': 'Help', 'key': 'Help' },
|
188
188
|
'backspace': { 'keyCode': 8, 'code': 'Backspace', 'key': 'Backspace' },
|
189
|
+
"\b": { 'keyCode': 8, 'code': 'Backspace', 'key': 'Backspace' },
|
189
190
|
'tab': { 'keyCode': 9, 'code': 'Tab', 'key': 'Tab' },
|
190
191
|
'enter': { 'keyCode': 13, 'code': 'Enter', 'key': 'Enter', 'text': "\r" },
|
191
192
|
"\r": { 'keyCode': 13, 'code': 'Enter', 'key': 'Enter', 'text': "\r" },
|
@@ -64,6 +64,11 @@ module Capybara::Apparition
|
|
64
64
|
.tr("\u00a0", ' ')
|
65
65
|
end
|
66
66
|
|
67
|
+
def text # capybara-webkit method
|
68
|
+
warn "Node#text is deprecated, please use Node#visible_text instead"
|
69
|
+
visible_text
|
70
|
+
end
|
71
|
+
|
67
72
|
def property(name)
|
68
73
|
evaluate_on('function(name){ return this[name] }', value: name)
|
69
74
|
end
|
@@ -161,8 +166,11 @@ module Capybara::Apparition
|
|
161
166
|
|
162
167
|
@page.mouse.click_at pos.merge(button: button, count: count, modifiers: keys)
|
163
168
|
if ENV['DEBUG']
|
164
|
-
|
165
|
-
|
169
|
+
begin
|
170
|
+
new_pos = element_click_pos(options)
|
171
|
+
puts "Element moved from #{pos} to #{new_pos}" unless pos == new_pos
|
172
|
+
rescue WrongWorld
|
173
|
+
end
|
166
174
|
end
|
167
175
|
# Wait a short time to see if click triggers page load
|
168
176
|
sleep 0.05
|
@@ -430,7 +438,11 @@ module Capybara::Apparition
|
|
430
438
|
# Clear field by JavaScript assignment of the value property.
|
431
439
|
# Script can change a readonly element which user input cannot, so
|
432
440
|
# don't execute if readonly.
|
433
|
-
driver.execute_script
|
441
|
+
driver.execute_script <<~JS, self unless clear == :none
|
442
|
+
if (!arguments[0].readOnly) {
|
443
|
+
arguments[0].value = ''
|
444
|
+
}
|
445
|
+
JS
|
434
446
|
send_keys(value)
|
435
447
|
end
|
436
448
|
end
|
@@ -706,13 +718,7 @@ module Capybara::Apparition
|
|
706
718
|
GET_VALUE_JS = <<~JS
|
707
719
|
function(){
|
708
720
|
if ((this.tagName == 'SELECT') && this.multiple){
|
709
|
-
|
710
|
-
for (let option of this.children) {
|
711
|
-
if (option.selected) {
|
712
|
-
selected.push(option.value);
|
713
|
-
}
|
714
|
-
}
|
715
|
-
return selected;
|
721
|
+
return Array.from(this.querySelectorAll("option:checked"),e=>e.value);
|
716
722
|
} else {
|
717
723
|
return this.value;
|
718
724
|
}
|
@@ -339,8 +339,8 @@ module Capybara::Apparition
|
|
339
339
|
|
340
340
|
def update_headers(async: false)
|
341
341
|
method = async ? :async_command : :command
|
342
|
-
if extra_headers
|
343
|
-
send(method, 'Network.setUserAgentOverride', userAgent:
|
342
|
+
if (ua = extra_headers.find { |k, _v| k=~/^User-Agent$/i })
|
343
|
+
send(method, 'Network.setUserAgentOverride', userAgent: ua[1])
|
344
344
|
end
|
345
345
|
send(method, 'Network.setExtraHTTPHeaders', headers: extra_headers)
|
346
346
|
setup_network_interception
|
@@ -526,9 +526,8 @@ module Capybara::Apparition
|
|
526
526
|
end
|
527
527
|
|
528
528
|
@session.on 'Runtime.consoleAPICalled' do |params|
|
529
|
-
@browser.
|
530
|
-
|
531
|
-
)
|
529
|
+
@browser.console.log(params['type'],
|
530
|
+
"#{params['args'].map { |arg| arg['description'] || arg['value'] }.join(' ')}")
|
532
531
|
end
|
533
532
|
|
534
533
|
# @session.on 'Security.certificateError' do |params|
|
@@ -603,7 +602,9 @@ module Capybara::Apparition
|
|
603
602
|
entry = history['entries'][history['currentIndex'] + delta]
|
604
603
|
return nil unless entry
|
605
604
|
|
605
|
+
main_frame.loading(-1)
|
606
606
|
command('Page.navigateToHistoryEntry', entryId: entry['id'])
|
607
|
+
wait_for_loaded
|
607
608
|
end
|
608
609
|
|
609
610
|
def _execute_script(script, *args)
|
data/lib/capybara/apparition.rb
CHANGED
metadata
CHANGED
@@ -1,15 +1,29 @@
|
|
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.4
|
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-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: backports
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
13
27
|
- !ruby/object:Gem::Dependency
|
14
28
|
name: capybara
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -197,6 +211,7 @@ files:
|
|
197
211
|
- lib/capybara/apparition.rb
|
198
212
|
- lib/capybara/apparition/browser.rb
|
199
213
|
- lib/capybara/apparition/chrome_client.rb
|
214
|
+
- lib/capybara/apparition/console.rb
|
200
215
|
- lib/capybara/apparition/cookie.rb
|
201
216
|
- lib/capybara/apparition/dev_tools_protocol/session.rb
|
202
217
|
- lib/capybara/apparition/dev_tools_protocol/target.rb
|
@@ -232,7 +247,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
232
247
|
requirements:
|
233
248
|
- - ">="
|
234
249
|
- !ruby/object:Gem::Version
|
235
|
-
version: 2.
|
250
|
+
version: 2.3.0
|
236
251
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
237
252
|
requirements:
|
238
253
|
- - ">="
|