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 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