apparition 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b51cb57f961f9825c56ce38377bbf4fd5477a5cdad6d75a2dac1aab827b81561
4
- data.tar.gz: 29e9b0c81cdcd3be2820a8d9a2719708750d3099f56a6c403c474a77bb254bce
3
+ metadata.gz: 138fab423026ba9b7e93b02a3dbbd4a4e438dfbf8bcf48500126dc9251dabd0d
4
+ data.tar.gz: af667994c4bf65674368b6e1e0a7e0a7d29ba4adf2a2d161eeb8dd1b16d98a45
5
5
  SHA512:
6
- metadata.gz: 95be5f025a29554e4909b5e4500d2694f580b20ee92b9cf555c7fcf2a9bc1962871d95c81730d9800a55d8cc38f99656713f88cd10f0f7bd8e880083819c0edc
7
- data.tar.gz: 34c0d53702b1b0be001cd65ebf0bfcb17ab6d3e86505851a23bbe39bd9bd80d4c0cb6d3d95a990804bd3ee123090ebce155892ddadd2ab4484782219ad0535b3
6
+ metadata.gz: 0e1f58fcdf5b3942bb219462ffd72e9f961747c0334c9fad0103e79cd0ff0dc3318a6c80988f5be0f045a1fc40d7c2695630b458ab79328accc0a3d17996a400
7
+ data.tar.gz: 4470dcb096886417f7d4b7ddcd0842f5be59d6a574173b3cda69c0878ad27047b9927696b4e7939579fadc90bbddcee6137fa6b91871f1ad7b2c746e3ba73c20
data/README.md CHANGED
@@ -27,7 +27,7 @@ gem 'apparition'
27
27
  or
28
28
 
29
29
  ``` ruby
30
- gem apparition', github: 'twalpole/apparition'
30
+ gem 'apparition', github: 'twalpole/apparition'
31
31
  ```
32
32
 
33
33
  to your Gemfile and run `bundle install`.
@@ -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
- @targets = Capybara::Apparition::DevToolsProtocol::TargetManager.new(self)
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
- while @current_page_handle.nil?
45
- puts 'waiting for target...'
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
- new_target_response = client.send_cmd('Target.createTarget', url: 'about:blank', browserContextId: new_context_id)
82
+ # current_pages = @pages.keys
88
83
 
89
- current_page_targets.each do |target|
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: target.context_id).discard_result
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
- @targets.delete(target.id)
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 @targets.get(new_target_id)&.page&.usable?
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
- begin
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
- current_page&.url_whitelist = whitelist
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
- current_page&.url_blacklist = blacklist
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
- current_target.page
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
- puts "Target Created Info: #{info}" if ENV['DEBUG']
261
- target_info = info['targetInfo']
262
- if !@targets.target?(target_info['targetId'])
263
- # @targets.add(target_info['targetId'], DevToolsProtocol::Target.new(self, target_info))
264
- @targets.add(target_info['targetId'], target_info)
265
- puts "**** Target Added #{info}" if ENV['DEBUG']
266
- elsif ENV['DEBUG']
267
- puts "Target already existed #{info}"
268
- end
269
- @current_page_handle ||= target_info['targetId'] if target_info['type'] == 'page'
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
- @targets.delete(info['targetId'])
319
+ @pages.delete(info['targetId'])
275
320
  end
276
321
 
277
- @client.on 'Target.targetInfoChanged' do |info|
278
- puts "**** Target Info Changed: #{info}" if ENV['DEBUG']
279
- target_info = info['targetInfo']
280
- target = @targets.get(target_info['targetId'])
281
- if target
282
- target.update(target_info)
283
- else
284
- puts '****No target for the info change- creating****' if ENV['DEBUG']
285
- @targets.add(target_info['targetId'], target_info)
286
- end
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
- @targets.pages.each do |page|
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
- @targets.pages.each do |page|
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 window_handle
6
+ def current_window_handle
7
7
  @current_page_handle
8
8
  end
9
9
 
10
10
  def window_handles
11
- @targets.window_handles
11
+ @pages.keys
12
12
  end
13
13
 
14
14
  def switch_to_window(handle)
15
- target = @targets.get(handle)
16
- raise NoSuchWindowError unless target&.page
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
- target.page.wait_for_loaded
19
- @current_page_handle = 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 = current_target.context_id
24
- info = command('Target.createTarget', url: 'about:blank', browserContextId: context_id)
25
- target_id = info['targetId']
26
- target = DevToolsProtocol::Target.new(self, info.merge('type' => 'page', 'inherit' => current_page))
27
- target.page # Ensure page object construction happens
28
- begin
29
- puts "Adding #{target_id} - #{target.info}" if ENV['DEBUG']
30
- @targets.add(target_id, target)
31
- rescue ArgumentError
32
- puts 'Target already existed' if ENV['DEBUG']
33
- end
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
- win_target = @targets.delete(handle)
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
- def within_window(locator)
45
- original = window_handle
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') == locator
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