apparition 0.4.0 → 0.5.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: 350a10ffb794579fb942f37a1739bf104b0230bd831945cbc22a20e2273927fd
4
- data.tar.gz: e0bbdc5f79d03fcdedabd5db29ff990ee57801087d9c33ef98e85f9de833be8d
3
+ metadata.gz: fbed62503718fca5fe4664a248445c8b222073b352e2afd1422eeb85cf7bbf40
4
+ data.tar.gz: 508d1a1883ccc043b26a617ce84bbfb30ed1a72eee407965b10a50a12e2a3a6d
5
5
  SHA512:
6
- metadata.gz: 313247fbbaccd8197d36ccd68adede1a33c944f46a5b30dce143606d4cc00bc61a3aab99ba35820dc6e2e3cbb7c09432084f221a36fee2f355fbd7d59639bb6f
7
- data.tar.gz: 73f91c766ab2bc02f2a58b07c95cce2a01bc71dff6ca8f6eb3374b36b5a8efbc73c95d26f48766e00d3fbd7f49003765b293af8725028afa64d798f2c5ebddb2
6
+ metadata.gz: 90fccfe118998a00935b4ff9c6637747a73ea917927e15db3bc29b6a02aa9ecd763bde7d8f65043b377e33c7357ff8fbe38f8064970e7e79de5aeac37bb6bcf2
7
+ data.tar.gz: 3e2220019a00bd43c8125c7ab6d75f6fb7b8b4430e57e28fe22dea73012b2b8c61fea655e1a455cb1dfa49d55cafadbf09ffc80621f1e43745c0791add88a5e1
data/README.md CHANGED
@@ -82,6 +82,29 @@ same as for `save_screenshot`.
82
82
  Sometimes its desirable to click a very specific area of the screen. You can accomplish this with
83
83
  `page.driver.click(x, y)`, where x and y are the screen coordinates.
84
84
 
85
+ ### Remote debugging (not yet implemented) ###
86
+
87
+ If you use the `:inspector => true` option (see below), remote debugging
88
+ will be enabled.
89
+
90
+ When this option is enabled, you can insert `page.driver.debug` into
91
+ your tests to pause the test and launch a browser which gives you the
92
+ WebKit inspector to view your test run with.
93
+
94
+ You can register this debugger driver with a different name and set it
95
+ as the current javascript driver. By example, in your helper file:
96
+
97
+ ```ruby
98
+ Capybara.register_driver :apparition_debug do |app|
99
+ Capybara::Apparition::Driver.new(app, :inspector => true)
100
+ end
101
+ # Capybara.javascript_driver = :apparition
102
+ Capybara.javascript_driver = :apparition_debug
103
+ ```
104
+
105
+ [Read more
106
+ here](https://www.jonathanleighton.com/articles/2012/poltergeist-0-6-0/)
107
+
85
108
  ### Manipulating request headers ###
86
109
 
87
110
  You can manipulate HTTP request headers with these methods:
@@ -152,7 +152,7 @@ module Capybara::Apparition
152
152
  current_page.command('Network.clearBrowserCache')
153
153
  end
154
154
 
155
- def command(name, params = {})
155
+ def command(name, **params)
156
156
  result = client.send_cmd(name, params).result
157
157
  log result
158
158
 
@@ -19,7 +19,7 @@ module Capybara::Apparition
19
19
  def set_cookie(cookie)
20
20
  cookie[:expires] = cookie[:expires].to_i if cookie[:expires]
21
21
 
22
- current_page.command('Network.setCookie', cookie)
22
+ current_page.command('Network.setCookie', **cookie)
23
23
  end
24
24
 
25
25
  def remove_cookie(name)
@@ -67,7 +67,13 @@ module Capybara::Apparition
67
67
  end
68
68
 
69
69
  sessions.each do |(target_id, session)|
70
- new_page = Page.create(@browser, session, target_id, opener.browser_context_id, page_options).inherit(opener)
70
+ new_page = Page.create(
71
+ @browser,
72
+ session,
73
+ target_id,
74
+ opener.browser_context_id,
75
+ **page_options
76
+ ).inherit(opener)
71
77
  @pages[target_id] = new_page
72
78
  end
73
79
  end
@@ -22,7 +22,7 @@ module Capybara::Apparition
22
22
  end
23
23
 
24
24
  def async_command(name, **params)
25
- send_cmd(name, params).discard_result
25
+ send_cmd(name, **params).discard_result
26
26
  end
27
27
 
28
28
  def async_commands(*names)
@@ -216,7 +216,7 @@ module Capybara::Apparition
216
216
  end
217
217
 
218
218
  def add_header(name, value, options = {})
219
- browser.add_header({ name => value }, { permanent: true }.merge(options))
219
+ browser.add_header({ name => value }, **{ permanent: true }.merge(options))
220
220
  end
221
221
  alias_method :header, :add_header
222
222
 
@@ -295,7 +295,7 @@ module Capybara::Apparition
295
295
  begin
296
296
  input = read.read_nonblock(80) # clear out the read buffer
297
297
  puts unless input&.end_with?("\n")
298
- rescue EOFError, IO::WaitReadable # rubocop:disable Lint/HandleExceptions
298
+ rescue EOFError, IO::WaitReadable # rubocop:disable Lint/SuppressedException
299
299
  # Ignore problems reading from STDIN.
300
300
  end
301
301
  end
@@ -208,7 +208,7 @@ module Capybara::Apparition
208
208
  puts "Calling handler for #{event_name}" if ENV['DEBUG'] == 'V'
209
209
  # TODO: Update this to use transform_keys when we dump Ruby 2.4
210
210
  # handler.call(event['params'].transform_keys(&method(:snake_sym)))
211
- handler.call(event['params'].each_with_object({}) { |(k, v), hash| hash[snake_sym(k)] = v })
211
+ handler.call(**event['params'].each_with_object({}) { |(k, v), hash| hash[snake_sym(k)] = v })
212
212
  end
213
213
  end
214
214
 
@@ -226,7 +226,7 @@ module Capybara::Apparition
226
226
  @listener = Thread.new do
227
227
  begin
228
228
  listen
229
- rescue EOFError # rubocop:disable Lint/HandleExceptions
229
+ rescue EOFError # rubocop:disable Lint/SuppressedException
230
230
  end
231
231
  end
232
232
  # @listener.abort_on_exception = true
@@ -7,8 +7,8 @@ module Capybara::Apparition
7
7
  class Launcher
8
8
  KILL_TIMEOUT = 5
9
9
 
10
- def self.start(*args)
11
- new(*args).tap(&:start)
10
+ def self.start(*args, **options)
11
+ new(*args, **options).tap(&:start)
12
12
  end
13
13
 
14
14
  def self.process_killer(pid)
@@ -29,7 +29,7 @@ module Capybara::Apparition
29
29
  break
30
30
  end
31
31
  end
32
- rescue Errno::ESRCH, Errno::ECHILD # rubocop:disable Lint/HandleExceptions
32
+ rescue Errno::ESRCH, Errno::ECHILD # rubocop:disable Lint/SuppressedException
33
33
  end
34
34
  end
35
35
  end
@@ -132,8 +132,10 @@ module Capybara::Apparition
132
132
  set_datetime_local(value)
133
133
  when 'color'
134
134
  set_color(value)
135
+ when 'range'
136
+ set_range(value)
135
137
  else
136
- set_text(value.to_s, { delay: 0 }.merge(options))
138
+ set_text(value.to_s, **{ delay: 0 }.merge(options))
137
139
  end
138
140
  elsif tag_name == 'textarea'
139
141
  set_text(value.to_s)
@@ -172,12 +174,12 @@ module Capybara::Apparition
172
174
  pos = visible_center(allow_scroll: false)
173
175
  return true if pos.nil?
174
176
 
175
- hit_node = @page.element_from_point(pos)
177
+ hit_node = @page.element_from_point(**pos)
176
178
  return true if hit_node.nil?
177
179
 
178
180
  begin
179
181
  return evaluate_on('el => !this.contains(el)', objectId: hit_node['objectId'])
180
- rescue WrongWorld # rubocop:disable Lint/HandleExceptions
182
+ rescue WrongWorld # rubocop:disable Lint/SuppressedException
181
183
  end
182
184
 
183
185
  true
@@ -196,22 +198,22 @@ module Capybara::Apparition
196
198
  end
197
199
 
198
200
  def click(keys = [], button: 'left', count: 1, **options)
199
- pos = element_click_pos(options)
201
+ pos = element_click_pos(**options)
200
202
  raise ::Capybara::Apparition::MouseEventImpossible.new(self, 'args' => ['click']) if pos.nil?
201
203
 
202
- test = mouse_event_test(pos)
204
+ test = mouse_event_test(**pos)
203
205
  raise ::Capybara::Apparition::MouseEventImpossible.new(self, 'args' => ['click']) if test.nil?
204
206
 
205
207
  unless options[:x] && options[:y]
206
208
  raise ::Capybara::Apparition::MouseEventFailed.new(self, 'args' => ['click', test.selector, pos]) unless test.success
207
209
  end
208
210
 
209
- @page.mouse.click_at pos.merge(button: button, count: count, modifiers: keys)
211
+ @page.mouse.click_at(**pos.merge(button: button, count: count, modifiers: keys))
210
212
  if ENV['DEBUG']
211
213
  begin
212
- new_pos = element_click_pos(options)
214
+ new_pos = element_click_pos(**options)
213
215
  puts "Element moved from #{pos} to #{new_pos}" unless pos == new_pos
214
- rescue WrongWorld # rubocop:disable Lint/HandleExceptions
216
+ rescue WrongWorld # rubocop:disable Lint/SuppressedException
215
217
  end
216
218
  end
217
219
  # Wait a short time to see if click triggers page load
@@ -231,7 +233,7 @@ module Capybara::Apparition
231
233
  pos = visible_center
232
234
  raise ::Capybara::Apparition::MouseEventImpossible.new(self, 'args' => ['hover']) if pos.nil?
233
235
 
234
- @page.mouse.move_to(pos)
236
+ @page.mouse.move_to(**pos)
235
237
  end
236
238
 
237
239
  EVENTS = {
@@ -534,6 +536,10 @@ module Capybara::Apparition
534
536
  update_value_js(value.to_s)
535
537
  end
536
538
 
539
+ def set_range(value)
540
+ update_value_js(value.to_s)
541
+ end
542
+
537
543
  def update_value_js(value)
538
544
  evaluate_on(<<~JS, value: value)
539
545
  value => {
@@ -759,7 +765,7 @@ module Capybara::Apparition
759
765
  # if an area element, check visibility of relevant image
760
766
  VISIBLE_JS = <<~JS
761
767
  function(){
762
- el = this;
768
+ let el = this;
763
769
  if (el.tagName == 'AREA'){
764
770
  const map_name = document.evaluate('./ancestor::map/@name', el, null, XPathResult.STRING_TYPE, null).stringValue;
765
771
  el = document.querySelector(`img[usemap='#${map_name}']`);
@@ -2,26 +2,30 @@
2
2
 
3
3
  module Capybara::Apparition
4
4
  module Drag
5
- def drag_to(other, delay: 0.1, html5: nil)
5
+ def drag_to(other, delay: 0.1, html5: nil, drop_modifiers: [])
6
+ drop_modifiers = Array(drop_modifiers)
7
+
6
8
  driver.execute_script MOUSEDOWN_TRACKER
7
9
  scroll_if_needed
8
10
  m = @page.mouse
9
- m.move_to(visible_center)
11
+ m.move_to(**visible_center)
10
12
  sleep delay
11
13
  m.down
12
14
  html5 = !driver.evaluate_script(LEGACY_DRAG_CHECK, self) if html5.nil?
13
15
  if html5
14
- driver.execute_script HTML5_DRAG_DROP_SCRIPT, self, other, delay
15
- m.up(other.visible_center)
16
+ driver.execute_script HTML5_DRAG_DROP_SCRIPT, self, other, delay, drop_modifiers
17
+ m.up(**other.visible_center)
16
18
  else
17
- begin
18
- other.scroll_if_needed
19
- sleep delay
20
- m.move_to(other.visible_center)
21
- sleep delay
22
- ensure
23
- m.up
24
- sleep delay
19
+ @page.keyboard.with_keys(drop_modifiers) do
20
+ begin
21
+ other.scroll_if_needed
22
+ sleep delay
23
+ m.move_to(**other.visible_center)
24
+ sleep delay
25
+ ensure
26
+ m.up
27
+ sleep delay
28
+ end
25
29
  end
26
30
  end
27
31
  end
@@ -31,11 +35,11 @@ module Capybara::Apparition
31
35
  raise ::Capybara::Apparition::MouseEventImpossible.new(self, 'args' => ['hover']) if pos.nil?
32
36
 
33
37
  other_pos = { x: pos[:x] + x, y: pos[:y] + y }
34
- raise ::Capybara::Apparition::MouseEventFailed.new(self, 'args' => ['drag', test['selector'], pos]) unless mouse_event_test?(pos)
38
+ raise ::Capybara::Apparition::MouseEventFailed.new(self, 'args' => ['drag', test['selector'], pos]) unless mouse_event_test?(**pos)
35
39
 
36
- @page.mouse.move_to(pos).down
40
+ @page.mouse.move_to(**pos).down
37
41
  sleep delay
38
- @page.mouse.move_to(other_pos)
42
+ @page.mouse.move_to(**other_pos)
39
43
  sleep delay
40
44
  @page.mouse.up
41
45
  end
@@ -125,9 +129,15 @@ module Capybara::Apparition
125
129
  JS
126
130
 
127
131
  HTML5_DRAG_DROP_SCRIPT = <<~JS
128
- var source = arguments[0];
129
- var target = arguments[1];
130
- var step_delay = arguments[2] * 1000;
132
+ let source = arguments[0];
133
+ const target = arguments[1];
134
+ const step_delay = arguments[2] * 1000;
135
+ const drop_modifiers = arguments[3];
136
+ const key_aliases = {
137
+ 'cmd': 'meta',
138
+ 'command': 'meta',
139
+ 'control': 'ctrl',
140
+ };
131
141
 
132
142
  function rectCenter(rect){
133
143
  return new DOMPoint(
@@ -181,6 +191,9 @@ module Capybara::Apparition
181
191
  let targetRect = target.getBoundingClientRect(),
182
192
  sourceCenter = rectCenter(source.getBoundingClientRect());
183
193
 
194
+ drop_modifiers.map(key => key_aliases[key] || key)
195
+ .forEach(key => opts[key + 'Key'] = true);
196
+
184
197
  // fire 2 dragover events to simulate dragging with a direction
185
198
  let entryPoint = pointOnRect(sourceCenter, targetRect);
186
199
  let dragOverOpts = Object.assign({clientX: entryPoint.x, clientY: entryPoint.y}, opts);
@@ -196,26 +209,27 @@ module Capybara::Apparition
196
209
  dragOverOpts = Object.assign({clientX: targetCenter.x, clientY: targetCenter.y}, opts);
197
210
  dragOverEvent = new DragEvent('dragover', dragOverOpts);
198
211
  target.dispatchEvent(dragOverEvent);
199
- setTimeout(resolve, step_delay, dragOverEvent.defaultPrevented);
212
+ setTimeout(resolve, step_delay, { drop: dragOverEvent.defaultPrevented, opts: dragOverOpts});
200
213
  })
201
214
  }
202
215
 
203
- function dragLeave(drop) {
216
+ function dragLeave({ drop, opts: dragOverOpts }) {
204
217
  return new Promise( resolve => {
205
- var dragLeaveEvent = new DragEvent('dragleave', opts);
218
+ var dragLeaveOptions = { ...opts, ...dragOverOpts };
219
+ var dragLeaveEvent = new DragEvent('dragleave', dragLeaveOptions);
206
220
  target.dispatchEvent(dragLeaveEvent);
207
221
  if (drop) {
208
- var dropEvent = new DragEvent('drop', opts);
222
+ var dropEvent = new DragEvent('drop', dragLeaveOptions);
209
223
  target.dispatchEvent(dropEvent);
210
224
  }
211
- var dragEndEvent = new DragEvent('dragend', opts);
225
+ var dragEndEvent = new DragEvent('dragend', dragLeaveOptions);
212
226
  source.dispatchEvent(dragEndEvent);
213
227
  setTimeout(resolve, step_delay);
214
228
  })
215
229
  }
216
230
 
217
- var dt = new DataTransfer();
218
- var opts = { cancelable: true, bubbles: true, dataTransfer: dt };
231
+ const dt = new DataTransfer();
232
+ const opts = { cancelable: true, bubbles: true, dataTransfer: dt };
219
233
 
220
234
  while (source && !source.draggable) {
221
235
  source = source.parentElement;
@@ -22,7 +22,7 @@ module Capybara::Apparition
22
22
  # Provides a lot of info - but huge overhead
23
23
  # session.command 'Page.setLifecycleEventsEnabled', enabled: true
24
24
 
25
- page = Page.new(browser, session, id, browser_context_id, options)
25
+ page = Page.new(browser, session, id, browser_context_id, **options)
26
26
 
27
27
  session.async_commands 'Network.enable', 'Runtime.enable', 'Security.enable', 'DOM.enable'
28
28
  session.async_command 'Security.setIgnoreCertificateErrors', ignore: !!ignore_https_errors
@@ -150,7 +150,7 @@ module Capybara::Apparition
150
150
  params[:paperWidth] = @browser.paper_size[:width].to_f
151
151
  params[:paperHeight] = @browser.paper_size[:height].to_f
152
152
  end
153
- command('Page.printToPDF', params)
153
+ command('Page.printToPDF', **params)
154
154
  else
155
155
  clip_options = if options[:selector]
156
156
  pos = evaluate("document.querySelector('#{options.delete(:selector)}').getBoundingClientRect().toJSON();")
@@ -165,7 +165,7 @@ module Capybara::Apparition
165
165
  JS
166
166
  end
167
167
  options[:clip] = { x: 0, y: 0, scale: scale }.merge(clip_options)
168
- command('Page.captureScreenshot', options)
168
+ command('Page.captureScreenshot', **options)
169
169
  end['data']
170
170
  end
171
171
 
@@ -284,7 +284,7 @@ module Capybara::Apparition
284
284
  @status_code = 0
285
285
  navigate_opts = { url: url, transitionType: 'reload' }
286
286
  navigate_opts[:referrer] = extra_headers['Referer'] if extra_headers['Referer']
287
- response = command('Page.navigate', navigate_opts)
287
+ response = command('Page.navigate', **navigate_opts)
288
288
  raise StatusFailError, 'args' => [url, response['errorText']] if response['errorText']
289
289
 
290
290
  main_frame.loading(response['loaderId'])
@@ -335,7 +335,7 @@ module Capybara::Apparition
335
335
  }
336
336
  metrics[:screenWidth], metrics[:screenHeight] = *screen if screen
337
337
 
338
- command('Emulation.setDeviceMetricsOverride', metrics)
338
+ command('Emulation.setDeviceMetricsOverride', **metrics)
339
339
  end
340
340
 
341
341
  def fullscreen
@@ -366,7 +366,7 @@ module Capybara::Apparition
366
366
  end
367
367
 
368
368
  def async_command(name, **params)
369
- @browser.command_for_session(@session.session_id, name, params).discard_result
369
+ @browser.command_for_session(@session.session_id, name, **params).discard_result
370
370
  end
371
371
 
372
372
  def extra_headers
@@ -386,7 +386,7 @@ module Capybara::Apparition
386
386
  if page
387
387
  self.url_whitelist = page.url_whitelist.dup
388
388
  self.url_blacklist = page.url_blacklist.dup
389
- set_viewport(page.viewport_size) if page.viewport_size
389
+ set_viewport(**page.viewport_size) if page.viewport_size
390
390
  end
391
391
  self
392
392
  end
@@ -330,6 +330,7 @@ module Capybara::Apparition
330
330
  'z': { 'keyCode': 90, 'code': 'KeyZ', 'shiftKey': 'Z', 'key': 'z' },
331
331
  'meta': { 'keyCode': 91, 'key': 'Meta', 'code': 'MetaLeft' },
332
332
  'command': { 'keyCode': 91, 'key': 'Meta', 'code': 'MetaLeft' },
333
+ 'cmd': { 'keyCode': 91, 'key': 'Meta', 'code': 'MetaLeft' },
333
334
  '*': { 'keyCode': 106, 'key': '*', 'code': 'NumpadMultiply', 'location': 3 },
334
335
  '+': { 'keyCode': 107, 'key': '+', 'code': 'NumpadAdd', 'location': 3 },
335
336
  '-': { 'keyCode': 109, 'key': '-', 'code': 'NumpadSubtract', 'location': 3 },
@@ -14,8 +14,8 @@ module Capybara::Apparition
14
14
  count.times do |num|
15
15
  @keyboard.with_keys(modifiers) do
16
16
  mouse_params = { x: x, y: y, button: button, count: num + 1 }
17
- down mouse_params
18
- up mouse_params
17
+ down(**mouse_params)
18
+ up(**mouse_params)
19
19
  end
20
20
  end
21
21
  self
@@ -29,7 +29,7 @@ module Capybara::Apparition
29
29
 
30
30
  def down(button: 'left', **options)
31
31
  options = @current_pos.merge(button: button).merge(options)
32
- mouse_event('mousePressed', options)
32
+ mouse_event('mousePressed', **options)
33
33
  @current_buttons |= BUTTONS[button.to_sym]
34
34
  self
35
35
  end
@@ -37,7 +37,7 @@ module Capybara::Apparition
37
37
  def up(button: 'left', **options)
38
38
  options = @current_pos.merge(button: button).merge(options)
39
39
  @current_buttons &= ~BUTTONS[button.to_sym]
40
- mouse_event('mouseReleased', options)
40
+ mouse_event('mouseReleased', **options)
41
41
  self
42
42
  end
43
43
 
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Capybara
4
4
  module Apparition
5
- VERSION = '0.4.0'
5
+ VERSION = '0.5.0'
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: apparition
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.5.0
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-08-15 00:00:00.000000000 Z
11
+ date: 2020-01-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: capybara
@@ -291,7 +291,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
291
291
  - !ruby/object:Gem::Version
292
292
  version: '0'
293
293
  requirements: []
294
- rubygems_version: 3.0.3
294
+ rubygems_version: 3.1.2
295
295
  signing_key:
296
296
  specification_version: 4
297
297
  summary: Chrome driver using CDP for Capybara