apparition 0.0.3 → 0.0.4
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 +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
|
- - ">="
|