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
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 138fab423026ba9b7e93b02a3dbbd4a4e438dfbf8bcf48500126dc9251dabd0d
|
4
|
+
data.tar.gz: af667994c4bf65674368b6e1e0a7e0a7d29ba4adf2a2d161eeb8dd1b16d98a45
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0e1f58fcdf5b3942bb219462ffd72e9f961747c0334c9fad0103e79cd0ff0dc3318a6c80988f5be0f045a1fc40d7c2695630b458ab79328accc0a3d17996a400
|
7
|
+
data.tar.gz: 4470dcb096886417f7d4b7ddcd0842f5be59d6a574173b3cda69c0878ad27047b9927696b4e7939579fadc90bbddcee6137fa6b91871f1ad7b2c746e3ba73c20
|
data/README.md
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'capybara/apparition/errors'
|
4
|
-
require 'capybara/apparition/dev_tools_protocol/target_manager'
|
5
4
|
require 'capybara/apparition/page'
|
6
5
|
require 'capybara/apparition/console'
|
6
|
+
require 'capybara/apparition/dev_tools_protocol/session'
|
7
7
|
require 'capybara/apparition/browser/header'
|
8
8
|
require 'capybara/apparition/browser/window'
|
9
9
|
require 'capybara/apparition/browser/render'
|
@@ -30,7 +30,7 @@ module Capybara::Apparition
|
|
30
30
|
def initialize(client, logger = nil)
|
31
31
|
@client = client
|
32
32
|
@current_page_handle = nil
|
33
|
-
@
|
33
|
+
@pages = {}
|
34
34
|
@context_id = nil
|
35
35
|
@js_errors = true
|
36
36
|
@ignore_https_errors = false
|
@@ -41,11 +41,8 @@ module Capybara::Apparition
|
|
41
41
|
initialize_handlers
|
42
42
|
|
43
43
|
command('Target.setDiscoverTargets', discover: true)
|
44
|
-
|
45
|
-
|
46
|
-
sleep 0.1
|
47
|
-
end
|
48
|
-
@context_id = current_target.context_id
|
44
|
+
yield self if block_given?
|
45
|
+
reset
|
49
46
|
end
|
50
47
|
|
51
48
|
def restart
|
@@ -81,34 +78,83 @@ module Capybara::Apparition
|
|
81
78
|
include Auth
|
82
79
|
|
83
80
|
def reset
|
84
|
-
current_page_targets = @targets.of_type('page').values
|
85
|
-
|
86
81
|
new_context_id = command('Target.createBrowserContext')['browserContextId']
|
87
|
-
|
82
|
+
# current_pages = @pages.keys
|
88
83
|
|
89
|
-
|
84
|
+
new_target_response = client.send_cmd('Target.createTarget', url: 'about:blank', browserContextId: new_context_id)
|
85
|
+
@pages.each do |id, page|
|
90
86
|
begin
|
91
|
-
client.send_cmd('Target.disposeBrowserContext', browserContextId:
|
87
|
+
client.send_cmd('Target.disposeBrowserContext', browserContextId: page.browser_context_id).discard_result
|
92
88
|
rescue WrongWorld
|
93
89
|
puts 'Unknown browserContextId'
|
94
90
|
end
|
95
|
-
@
|
91
|
+
@pages.delete(id)
|
96
92
|
end
|
97
93
|
|
98
94
|
new_target_id = new_target_response['targetId']
|
99
95
|
|
96
|
+
session_id = command('Target.attachToTarget', targetId: new_target_id)['sessionId']
|
97
|
+
session = Capybara::Apparition::DevToolsProtocol::Session.new(self, client, session_id)
|
98
|
+
|
99
|
+
@pages[new_target_id] = Page.create(self, session, new_target_id, new_context_id,
|
100
|
+
ignore_https_errors: ignore_https_errors,
|
101
|
+
js_errors: js_errors, extensions: @extensions,
|
102
|
+
url_blacklist: @url_blacklist,
|
103
|
+
url_whitelist: @url_whitelist) # .inherit(@info.delete('inherit'))
|
104
|
+
@pages[new_target_id].send(:main_frame).loaded!
|
105
|
+
|
100
106
|
timer = Capybara::Helpers.timer(expire_in: 10)
|
101
|
-
until @
|
107
|
+
until @pages[new_target_id].usable?
|
102
108
|
if timer.expired?
|
103
109
|
puts 'Timedout waiting for reset'
|
104
110
|
raise TimeoutError.new('reset')
|
105
111
|
end
|
106
112
|
sleep 0.01
|
107
113
|
end
|
114
|
+
console.clear
|
108
115
|
@current_page_handle = new_target_id
|
109
116
|
true
|
110
117
|
end
|
111
118
|
|
119
|
+
def refresh_pages(opener:)
|
120
|
+
new_pages = command('Target.getTargets')['targetInfos'].select do |ti|
|
121
|
+
(ti['openerId'] == opener.target_id) && (ti['type'] == 'page') && (ti['attached'] == false)
|
122
|
+
end
|
123
|
+
sessions = new_pages.map do |page|
|
124
|
+
target_id = page['targetId']
|
125
|
+
session_result = client.send_cmd('Target.attachToTarget', targetId: target_id)
|
126
|
+
[target_id, session_result]
|
127
|
+
end
|
128
|
+
|
129
|
+
sessions = sessions.map do |(target_id, session_result)|
|
130
|
+
session = Capybara::Apparition::DevToolsProtocol::Session.new(self, client, session_result.result['sessionId'])
|
131
|
+
[target_id, session]
|
132
|
+
end
|
133
|
+
|
134
|
+
sessions.each do |(_target_id, session)|
|
135
|
+
session.async_commands 'Page.enable', 'Network.enable', 'Runtime.enable', 'Security.enable', 'DOM.enable'
|
136
|
+
end
|
137
|
+
|
138
|
+
# sessions.each do |(target_id, session_result)|
|
139
|
+
# session = Capybara::Apparition::DevToolsProtocol::Session.new(self, client, session_result.result['sessionId'])
|
140
|
+
sessions.each do |(target_id, session)|
|
141
|
+
page_options = { ignore_https_errors: ignore_https_errors, js_errors: js_errors,
|
142
|
+
url_blacklist: @url_blacklist, url_whitelist: @url_whitelist }
|
143
|
+
new_page = Page.create(self, session, target_id, opener.browser_context_id, page_options).inherit(opener)
|
144
|
+
@pages[target_id] = new_page
|
145
|
+
end
|
146
|
+
|
147
|
+
# new_pages.each do |page|
|
148
|
+
# target_id = page['targetId']
|
149
|
+
# session_id = command('Target.attachToTarget', targetId: target_id)['sessionId']
|
150
|
+
# session = Capybara::Apparition::DevToolsProtocol::Session.new(self, client, session_id)
|
151
|
+
# page_options = { ignore_https_errors: ignore_https_errors, js_errors: js_errors,
|
152
|
+
# url_blacklist: @url_blacklist, url_whitelist: @url_whitelist }
|
153
|
+
# new_page = Page.create(self, session, page['targetId'], opener.browser_context_id, page_options).inherit(opener)
|
154
|
+
# @pages[target_id] = new_page
|
155
|
+
# end
|
156
|
+
end
|
157
|
+
|
112
158
|
def resize(width, height, screen: nil)
|
113
159
|
current_page.set_viewport width: width, height: height, screen: screen
|
114
160
|
end
|
@@ -127,20 +173,22 @@ module Capybara::Apparition
|
|
127
173
|
def extensions=(filenames)
|
128
174
|
@extensions = filenames
|
129
175
|
Array(filenames).each do |name|
|
130
|
-
|
131
|
-
current_page.command('Page.addScriptToEvaluateOnNewDocument', source: File.read(name))
|
132
|
-
rescue Errno::ENOENT
|
133
|
-
raise ::Capybara::Apparition::BrowserError.new('name' => "Unable to load extension: #{name}", 'args' => nil)
|
134
|
-
end
|
176
|
+
current_page(allow_nil: true)&.add_extension(name)
|
135
177
|
end
|
136
178
|
end
|
137
179
|
|
138
180
|
def url_whitelist=(whitelist)
|
139
|
-
|
181
|
+
@url_whitelist = whitelist
|
182
|
+
@pages.each do |_id, page|
|
183
|
+
page.url_whitelist = whitelist
|
184
|
+
end
|
140
185
|
end
|
141
186
|
|
142
187
|
def url_blacklist=(blacklist)
|
143
|
-
|
188
|
+
@url_blacklist = blacklist
|
189
|
+
@pages.each do |_id, page|
|
190
|
+
page.url_blacklist = blacklist
|
191
|
+
end
|
144
192
|
end
|
145
193
|
|
146
194
|
attr_writer :debug
|
@@ -166,8 +214,14 @@ module Capybara::Apparition
|
|
166
214
|
raise
|
167
215
|
end
|
168
216
|
|
169
|
-
def current_page
|
170
|
-
|
217
|
+
def current_page(allow_nil: false)
|
218
|
+
@pages[@current_page_handle] || begin
|
219
|
+
puts "No current page: #{@current_page_handle} : #{caller}" if ENV['DEBUG']
|
220
|
+
@current_page_handle = nil
|
221
|
+
raise NoSuchWindowError unless allow_nil
|
222
|
+
|
223
|
+
@current_page_handle
|
224
|
+
end
|
171
225
|
end
|
172
226
|
|
173
227
|
def console_messages(type = nil)
|
@@ -176,15 +230,6 @@ module Capybara::Apparition
|
|
176
230
|
|
177
231
|
private
|
178
232
|
|
179
|
-
def current_target
|
180
|
-
@targets.get(@current_page_handle) || begin
|
181
|
-
puts "No current page: #{@current_page_handle}"
|
182
|
-
puts caller
|
183
|
-
@current_page_handle = nil
|
184
|
-
raise NoSuchWindowError
|
185
|
-
end
|
186
|
-
end
|
187
|
-
|
188
233
|
def log(message)
|
189
234
|
@logger&.puts message if ENV['DEBUG']
|
190
235
|
end
|
@@ -256,35 +301,36 @@ module Capybara::Apparition
|
|
256
301
|
# end
|
257
302
|
|
258
303
|
def initialize_handlers
|
259
|
-
@client.on 'Target.targetCreated' do |info|
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
end
|
304
|
+
# @client.on 'Target.targetCreated' do |info|
|
305
|
+
# byebug
|
306
|
+
# puts "Target Created Info: #{info}" if ENV['DEBUG']
|
307
|
+
# target_info = info['targetInfo']
|
308
|
+
# if !@pages.key?(target_info['targetId'])
|
309
|
+
# @pages.add(target_info['targetId'], target_info)
|
310
|
+
# puts "**** Target Added #{info}" if ENV['DEBUG']
|
311
|
+
# elsif ENV['DEBUG']
|
312
|
+
# puts "Target already existed #{info}"
|
313
|
+
# end
|
314
|
+
# @current_page_handle ||= target_info['targetId'] if target_info['type'] == 'page'
|
315
|
+
# end
|
271
316
|
|
272
317
|
@client.on 'Target.targetDestroyed' do |info|
|
273
318
|
puts "**** Target Destroyed Info: #{info}" if ENV['DEBUG']
|
274
|
-
@
|
319
|
+
@pages.delete(info['targetId'])
|
275
320
|
end
|
276
321
|
|
277
|
-
@client.on 'Target.targetInfoChanged' do |info|
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
end
|
322
|
+
# @client.on 'Target.targetInfoChanged' do |info|
|
323
|
+
# byebug
|
324
|
+
# puts "**** Target Info Changed: #{info}" if ENV['DEBUG']
|
325
|
+
# target_info = info['targetInfo']
|
326
|
+
# page = @pages[target_info['targetId']]
|
327
|
+
# if page
|
328
|
+
# page.update(target_info)
|
329
|
+
# else
|
330
|
+
# puts '****No target for the info change- creating****' if ENV['DEBUG']
|
331
|
+
# @pages.add(target_info['targetId'], target_info)
|
332
|
+
# end
|
333
|
+
# end
|
288
334
|
end
|
289
335
|
end
|
290
336
|
end
|
@@ -8,7 +8,7 @@ module Capybara::Apparition
|
|
8
8
|
end
|
9
9
|
|
10
10
|
def headers=(headers)
|
11
|
-
@
|
11
|
+
@pages.each do |_id, page|
|
12
12
|
page.perm_headers = headers.dup
|
13
13
|
page.temp_headers = {}
|
14
14
|
page.temp_no_redirect_headers = {}
|
@@ -23,7 +23,7 @@ module Capybara::Apparition
|
|
23
23
|
|
24
24
|
def add_header(header, permanent: true, **_options)
|
25
25
|
if permanent == true
|
26
|
-
@
|
26
|
+
@pages.each do |_id, page|
|
27
27
|
page.perm_headers.merge! header
|
28
28
|
page.update_headers
|
29
29
|
end
|
@@ -3,64 +3,64 @@
|
|
3
3
|
module Capybara::Apparition
|
4
4
|
class Browser
|
5
5
|
module Window
|
6
|
-
def
|
6
|
+
def current_window_handle
|
7
7
|
@current_page_handle
|
8
8
|
end
|
9
9
|
|
10
10
|
def window_handles
|
11
|
-
@
|
11
|
+
@pages.keys
|
12
12
|
end
|
13
13
|
|
14
14
|
def switch_to_window(handle)
|
15
|
-
|
16
|
-
|
15
|
+
page = @pages[handle]
|
16
|
+
unless page
|
17
|
+
page = @pages[find_window_handle(handle)]
|
18
|
+
warn 'Finding window by name, title, or url is deprecated, please use a block/proc ' \
|
19
|
+
'with Session#within_window/Session#switch_to_window instead.'
|
20
|
+
end
|
21
|
+
raise NoSuchWindowError unless page
|
17
22
|
|
18
|
-
|
19
|
-
@current_page_handle =
|
23
|
+
page.wait_for_loaded
|
24
|
+
@current_page_handle = page.target_id
|
20
25
|
end
|
21
26
|
|
22
27
|
def open_new_window
|
23
|
-
context_id =
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
28
|
+
context_id = current_page.browser_context_id
|
29
|
+
target_id = command('Target.createTarget', url: 'about:blank', browserContextId: context_id)['targetId']
|
30
|
+
session_id = command('Target.attachToTarget', targetId: target_id)['sessionId']
|
31
|
+
session = Capybara::Apparition::DevToolsProtocol::Session.new(self, client, session_id)
|
32
|
+
@pages[target_id] = Page.create(self, session, target_id, context_id,
|
33
|
+
ignore_https_errors: ignore_https_errors,
|
34
|
+
js_errors: js_errors,
|
35
|
+
url_whitelist: @url_whitelist,
|
36
|
+
extensions: @extensions,
|
37
|
+
url_blacklist: @url_blacklist).inherit(current_page(allow_nil: true))
|
38
|
+
@pages[target_id].send(:main_frame).loaded!
|
34
39
|
target_id
|
35
40
|
end
|
36
41
|
|
37
42
|
def close_window(handle)
|
38
43
|
@current_page_handle = nil if @current_page_handle == handle
|
39
|
-
|
40
|
-
warn 'Window was already closed unexpectedly' if win_target.nil?
|
41
|
-
win_target&.close
|
42
|
-
end
|
44
|
+
page = @pages.delete(handle)
|
43
45
|
|
44
|
-
|
45
|
-
|
46
|
-
handle = find_window_handle(locator)
|
47
|
-
switch_to_window(handle)
|
48
|
-
yield
|
49
|
-
ensure
|
50
|
-
switch_to_window(original)
|
46
|
+
warn 'Window was already closed unexpectedly' unless page
|
47
|
+
command('Target.closeTarget', targetId: handle)
|
51
48
|
end
|
52
49
|
end
|
53
50
|
|
54
51
|
private
|
55
52
|
|
56
53
|
def find_window_handle(locator)
|
54
|
+
original = current_window_handle
|
57
55
|
return locator if window_handles.include? locator
|
58
56
|
|
59
57
|
window_handles.each do |handle|
|
60
58
|
switch_to_window(handle)
|
61
|
-
return handle if evaluate('window.name')
|
59
|
+
return handle if evaluate('[window.name, document.title, window.location.href]').include? locator
|
62
60
|
end
|
63
61
|
raise NoSuchWindowError
|
62
|
+
ensure
|
63
|
+
switch_to_window(original) if original
|
64
64
|
end
|
65
65
|
end
|
66
66
|
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Capybara::Apparition
|
4
|
+
class Configuration
|
5
|
+
class << self
|
6
|
+
private # rubocop:disable Layout/IndentationWidth
|
7
|
+
|
8
|
+
def instance
|
9
|
+
@instance ||= new
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.to_hash
|
14
|
+
instance.freeze.to_hash
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.modify
|
18
|
+
raise 'All configuration must take place before the driver starts' if instance.frozen?
|
19
|
+
end
|
20
|
+
|
21
|
+
attr_accessor :allowed_urls
|
22
|
+
attr_writer :block_unknown_urls
|
23
|
+
attr_accessor :blocked_urls
|
24
|
+
attr_accessor :debug
|
25
|
+
attr_writer :ignore_ssl_errors
|
26
|
+
attr_accessor :proxy
|
27
|
+
attr_accessor :stderr
|
28
|
+
attr_accessor :timeout
|
29
|
+
attr_writer :skip_image_loading
|
30
|
+
attr_accessor :raise_javascript_errors
|
31
|
+
|
32
|
+
def initialize
|
33
|
+
@allowed_urls = []
|
34
|
+
@blocked_urls = []
|
35
|
+
@block_unknown_urls = false
|
36
|
+
@debug = false
|
37
|
+
@ignore_ssl_errors = false
|
38
|
+
@proxy = nil
|
39
|
+
@skip_image_loading = false
|
40
|
+
@stderr = $stderr
|
41
|
+
@timeout = -1
|
42
|
+
@raise_javascript_errors = false
|
43
|
+
end
|
44
|
+
|
45
|
+
def allow_url(url)
|
46
|
+
@allowed_urls << url
|
47
|
+
end
|
48
|
+
|
49
|
+
def block_url(url)
|
50
|
+
@blocked_urls << url
|
51
|
+
end
|
52
|
+
|
53
|
+
def block_unknown_urls
|
54
|
+
@block_unknown_urls = true
|
55
|
+
end
|
56
|
+
|
57
|
+
def block_unknown_urls?
|
58
|
+
@block_unknown_urls
|
59
|
+
end
|
60
|
+
|
61
|
+
def allow_unknown_urls
|
62
|
+
allow_url('*')
|
63
|
+
end
|
64
|
+
|
65
|
+
def ignore_ssl_errors
|
66
|
+
@ignore_ssl_errors = true
|
67
|
+
end
|
68
|
+
|
69
|
+
def ignore_ssl_errors?
|
70
|
+
@ignore_ssl_errors
|
71
|
+
end
|
72
|
+
|
73
|
+
def skip_image_loading
|
74
|
+
@skip_image_loading = true
|
75
|
+
end
|
76
|
+
|
77
|
+
def skip_image_loading?
|
78
|
+
@skip_image_loading
|
79
|
+
end
|
80
|
+
|
81
|
+
def use_proxy(proxy)
|
82
|
+
@proxy = proxy
|
83
|
+
end
|
84
|
+
|
85
|
+
def to_hash
|
86
|
+
{
|
87
|
+
url_whitelist: allowed_urls,
|
88
|
+
block_unknown_urls: block_unknown_urls?,
|
89
|
+
url_blacklist: blocked_urls,
|
90
|
+
debug: debug,
|
91
|
+
ignore_ssl_errors: ignore_ssl_errors?,
|
92
|
+
proxy: proxy,
|
93
|
+
skip_image_loading: skip_image_loading?,
|
94
|
+
stderr: stderr,
|
95
|
+
timeout: timeout,
|
96
|
+
js_errors: raise_javascript_errors
|
97
|
+
}
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|