poltergeist 1.17.0 → 1.18.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: 06e484be00352d4b5c8134794b51783cd4358f6c8888ae35a4a0b396e33dd023
4
- data.tar.gz: 1dd2652dac23268d7ef3de4d30f0222e9c720491f1a3d4b83a37dc7aa0b07982
3
+ metadata.gz: b7f5bf350711720abecb06c20bab6cea6489844fc3cd60b89a19d89c64723b02
4
+ data.tar.gz: 10b8c208d718baecf0515a7e3add9d185f522e04ad62773c41dd562de8a8817f
5
5
  SHA512:
6
- metadata.gz: aa6b9d400580c3b99fe73523f330a1a222c30dd2679c376bbdf4a722e966dfef8367983657c68868ef67b0650928109881d7b3d4fb0dbdacc71aca8ab5f6e43f
7
- data.tar.gz: feb9e85896493c42f85332cdae4ad2ac570489069b7fefc9ec9c3d40efb4db94fbfe185f23163bf5512113fdeefeab67386ee238c32ff0082b951a50628ff39a
6
+ metadata.gz: 18313bbc53ca8455008626bb7d521ad1cdd3f66daefad18b859a2a4a2132e38b4f306f46bc8e4a5c8bb80bd2232b3e7693653d3d7be12d86c7470ec01319d63c
7
+ data.tar.gz: bc7d1dd21d97d69b2902e77a4cf175be3fbec635650d5879e240fe29ec90511e96200cced21dbc225d82babd8154aaa47b60653cc75b813a1692893c13bbca31
data/README.md CHANGED
@@ -9,7 +9,7 @@ provided by [PhantomJS](http://phantomjs.org/).
9
9
  **If you're viewing this at https://github.com/teampoltergeist/poltergeist,
10
10
  you're reading the documentation for the master branch.
11
11
  [View documentation for the latest release
12
- (1.17.0).](https://github.com/teampoltergeist/poltergeist/tree/v1.17.0)**
12
+ (1.18.0).](https://github.com/teampoltergeist/poltergeist/tree/v1.18.0)**
13
13
 
14
14
  ## Getting help ##
15
15
 
@@ -207,6 +207,10 @@ This way your temporary headers will be sent only for the initial request, and r
207
207
  subsequent request will only contain your permanent headers. If the temporary
208
208
  headers should not be sent on related 30x redirects, specify `permanent: :no_redirect`.
209
209
 
210
+ Headers set with any of these methods will be set within all windows in the
211
+ session, with the exception of temporary headers, which are only set within the
212
+ current window.
213
+
210
214
  ### Inspecting network traffic ###
211
215
 
212
216
  You can inspect the network traffic (i.e. what resources have been
@@ -294,6 +298,7 @@ end
294
298
  * `:host` (String) - The name or IP of the PhantomJS host. Default is '127.0.0.1'.
295
299
  * `:url_blacklist` (Array) - Default session url blacklist - expressed as an array of strings to match against requested URLs.
296
300
  * `:url_whitelist` (Array) - Default session url whitelist - expressed as an array of strings to match against requested URLs.
301
+ * `:page_settings` (Hash) - PhantomJS web page settings (http://phantomjs.org/api/webpage/property/settings.html).
297
302
 
298
303
  ### URL Blacklisting & Whitelisting ###
299
304
  Poltergeist supports URL blacklisting, which allows you
@@ -43,6 +43,10 @@ module Capybara::Poltergeist
43
43
  command 'current_url'
44
44
  end
45
45
 
46
+ def frame_url
47
+ command 'frame_url'
48
+ end
49
+
46
50
  def status_code
47
51
  command 'status_code'
48
52
  end
@@ -59,6 +63,10 @@ module Capybara::Poltergeist
59
63
  command 'title'
60
64
  end
61
65
 
66
+ def frame_title
67
+ command 'frame_title'
68
+ end
69
+
62
70
  def parents(page_id, id)
63
71
  command 'parents', page_id, id
64
72
  end
@@ -196,16 +204,16 @@ module Capybara::Poltergeist
196
204
  switch_to_window(original)
197
205
  end
198
206
 
199
- def click(page_id, id)
200
- command 'click', page_id, id
207
+ def click(page_id, id, keys=[], offset={})
208
+ command 'click', page_id, id, keys, offset
201
209
  end
202
210
 
203
- def right_click(page_id, id)
204
- command 'right_click', page_id, id
211
+ def right_click(page_id, id, keys=[], offset={})
212
+ command 'right_click', page_id, id, keys, offset
205
213
  end
206
214
 
207
- def double_click(page_id, id)
208
- command 'double_click', page_id, id
215
+ def double_click(page_id, id, keys=[], offset={})
216
+ command 'double_click', page_id, id, keys, offset
209
217
  end
210
218
 
211
219
  def hover(page_id, id)
@@ -346,6 +354,10 @@ module Capybara::Poltergeist
346
354
  command 'set_js_errors', !!val
347
355
  end
348
356
 
357
+ def page_settings=(settings)
358
+ command 'set_page_settings', settings
359
+ end
360
+
349
361
  def extensions=(names)
350
362
  @extensions = names
351
363
  Array(names).each do |name|
@@ -13,8 +13,8 @@ class PoltergeistAgent
13
13
  # Somehow PhantomJS returns all characters(brackets, etc) properly encoded
14
14
  # except whitespace character in pathname part of the location. This hack
15
15
  # is intended to fix this up.
16
- currentUrl: ->
17
- window.location.href.replace(/\ /g, '%20')
16
+ frameUrl: ->
17
+ window.location.href
18
18
 
19
19
  find: (method, selector, within = document) ->
20
20
  try
@@ -55,7 +55,9 @@ class PoltergeistAgent
55
55
  this.get(id).removeAttribute('_poltergeist_selected')
56
56
 
57
57
  clearLocalStorage: ->
58
- localStorage?.clear()
58
+ try
59
+ localStorage?.clear()
60
+ catch error
59
61
 
60
62
  wrapResults: (result, page_id)->
61
63
  @_visitedObjects ||= [];
@@ -250,12 +252,12 @@ class PoltergeistAgent.Node
250
252
  else if value == false && !@element.parentNode.multiple
251
253
  false
252
254
  else
253
- this.trigger('focus', @element.parentNode)
255
+ this.trigger('focus', {}, @element.parentNode)
254
256
 
255
257
  @element.selected = value
256
258
  this.changed()
257
259
 
258
- this.trigger('blur', @element.parentNode)
260
+ this.trigger('blur', {}, @element.parentNode)
259
261
  true
260
262
 
261
263
  tagName: ->
@@ -326,7 +328,7 @@ class PoltergeistAgent.Node
326
328
  offset
327
329
 
328
330
  position: ->
329
- # Elements inside an SVG return underfined for getClientRects???
331
+ # Elements inside an SVG return undefined for getClientRects???
330
332
  rect = @element.getClientRects()[0] || @element.getBoundingClientRect()
331
333
  throw new PoltergeistAgent.ObsoleteNode unless rect
332
334
  frameOffset = this.frameOffset()
@@ -342,12 +344,18 @@ class PoltergeistAgent.Node
342
344
 
343
345
  pos
344
346
 
345
- trigger: (name, element = @element) ->
347
+ trigger: (name, options = {}, element = @element) ->
346
348
  if Node.EVENTS.MOUSE.indexOf(name) != -1
347
349
  event = document.createEvent('MouseEvent')
348
350
  event.initMouseEvent(
349
- name, true, true, window, 0, 0, 0, 0, 0,
350
- false, false, false, false, 0, null
351
+ name, true, true, window, 0,
352
+ options['screenX'] || 0, options['screenY'] || 0,
353
+ options['clientX'] || 0, options['clientY'] || 0,
354
+ options['ctrlKey'] || false,
355
+ options['altKey'] || false,
356
+ options['shiftKey'] || false,
357
+ options['metaKey'] || false,
358
+ options['button'] || 0, null
351
359
  )
352
360
  else if Node.EVENTS.FOCUS.indexOf(name) != -1
353
361
  event = this.obtainEvent(name)
@@ -437,3 +445,4 @@ document.addEventListener(
437
445
  'DOMContentLoaded',
438
446
  -> console.log('__DOMContentLoaded')
439
447
  )
448
+ console.log('__DOMContentLoaded') if document.readyState == 'complete'
@@ -6,6 +6,7 @@ class Poltergeist.Browser
6
6
  @js_errors = true
7
7
  @_debug = false
8
8
  @_counter = 0
9
+ @_page_settings = null
9
10
 
10
11
  @processed_modal_messages = []
11
12
  @confirm_processes = []
@@ -18,11 +19,11 @@ class Poltergeist.Browser
18
19
 
19
20
  if @page?
20
21
  unless @page.closed
21
- @page.clearLocalStorage() if @page.currentUrl() != 'about:blank'
22
+ @page.clearLocalStorage() if @page.frameUrl() != 'about:blank'
22
23
  @page.close()
23
24
  phantom.clearCookies()
24
25
 
25
- @page = @currentPage = new Poltergeist.WebPage
26
+ @page = @currentPage = new Poltergeist.WebPage(null, @_page_settings)
26
27
  @page.setViewportSize(width: @width, height: @height)
27
28
  @page.handle = "#{@_counter++}"
28
29
  @pages.push(@page)
@@ -54,11 +55,13 @@ class Poltergeist.Browser
54
55
  return response
55
56
 
56
57
  page.onPageCreated = (newPage) =>
57
- _page = new Poltergeist.WebPage(newPage)
58
+ _page = new Poltergeist.WebPage(newPage, @_page_settings)
58
59
  _page.handle = "#{@_counter++}"
59
60
  _page.urlBlacklist = page.urlBlacklist
60
61
  _page.urlWhitelist = page.urlWhitelist
61
62
  _page.setViewportSize(page.viewportSize())
63
+ _page.setUserAgent(page.getUserAgent())
64
+ _page.setCustomHeaders(page.getPermanentCustomHeaders())
62
65
  @setupPageHandlers(_page)
63
66
  @pages.push(_page)
64
67
 
@@ -98,11 +101,10 @@ class Poltergeist.Browser
98
101
  @confirm_processes = []
99
102
  @prompt_responses = []
100
103
 
101
-
102
104
  # Prevent firing `page.onInitialized` event twice. Calling currentUrl
103
105
  # method before page is actually opened fires this event for the first time.
104
106
  # The second time will be in the right place after `page.open`
105
- prevUrl = if @currentPage.source is null then 'about:blank' else @currentPage.currentUrl()
107
+ prevUrl = if @currentPage.source? then @currentPage.currentUrl() else 'about:blank'
106
108
 
107
109
  @currentPage.open(url)
108
110
 
@@ -130,6 +132,9 @@ class Poltergeist.Browser
130
132
  current_url: ->
131
133
  @current_command.sendResponse @currentPage.currentUrl()
132
134
 
135
+ frame_url: ->
136
+ @current_command.sendResponse @currentPage.frameUrl()
137
+
133
138
  status_code: ->
134
139
  @current_command.sendResponse @currentPage.statusCode
135
140
 
@@ -142,6 +147,9 @@ class Poltergeist.Browser
142
147
  title: ->
143
148
  @current_command.sendResponse @currentPage.title()
144
149
 
150
+ frame_title: ->
151
+ @current_command.sendResponse @currentPage.frameTitle()
152
+
145
153
  find: (method, selector) ->
146
154
  @current_command.sendResponse(page_id: @currentPage.id, ids: @currentPage.find(method, selector))
147
155
 
@@ -231,8 +239,8 @@ class Poltergeist.Browser
231
239
  @currentPage.execute("function() { #{script} }", args...)
232
240
  @current_command.sendResponse(true)
233
241
 
234
- frameUrl: (frame_name) ->
235
- @currentPage.frameUrl(frame_name)
242
+ frameUrlFor: (frame_name) ->
243
+ @currentPage.frameUrlFor(frame_name)
236
244
 
237
245
  pushFrame: (command, name, timeout) ->
238
246
  if Array.isArray(name)
@@ -242,11 +250,12 @@ class Poltergeist.Browser
242
250
  frame.setAttribute('name', "_random_name_#{new Date().getTime()}")
243
251
  name = frame.getAttribute('name')
244
252
 
245
- frame_url = @frameUrl(name)
253
+ frame_url = @frameUrlFor(name)
246
254
  if frame_url in @currentPage.blockedUrls()
247
255
  command.sendResponse(true)
248
256
  else if @currentPage.pushFrame(name)
249
- if frame_url && (frame_url != 'about:blank') && (@currentPage.currentUrl() == 'about:blank')
257
+ # if frame_url && (frame_url != 'about:blank') && (@currentPage.currentUrl() == 'about:blank')
258
+ if frame_url && (frame_url != 'about:blank') && (@currentPage.frameUrl() == 'about:blank')
250
259
  @currentPage.state = 'awaiting_frame_load'
251
260
  @currentPage.waitState 'default', ->
252
261
  command.sendResponse(true)
@@ -302,14 +311,14 @@ class Poltergeist.Browser
302
311
  else
303
312
  @current_command.sendResponse(false)
304
313
 
305
- mouse_event: (page_id, id, name) ->
314
+ mouse_event: (page_id, id, name, keys=[], offset={}) ->
306
315
  # Get the node before changing state, in case there is an exception
307
316
  node = this.node(page_id, id)
308
317
  # If the event triggers onNavigationRequested, we will transition to the 'loading'
309
318
  # state and wait for onLoadFinished before sending a response.
310
319
  @currentPage.state = 'mouse_event'
311
320
 
312
- last_mouse_event = node.mouseEvent(name)
321
+ last_mouse_event = node.mouseEvent(name, keys, offset)
313
322
  event_page = @currentPage
314
323
  command = @current_command
315
324
 
@@ -323,14 +332,14 @@ class Poltergeist.Browser
323
332
  command.sendResponse(position: last_mouse_event)
324
333
  , 5
325
334
 
326
- click: (page_id, id) ->
327
- this.mouse_event page_id, id, 'click'
335
+ click: (page_id, id, keys, offset) ->
336
+ this.mouse_event page_id, id, 'click', keys, offset
328
337
 
329
- right_click: (page_id, id) ->
330
- this.mouse_event page_id, id, 'rightclick'
338
+ right_click: (page_id, id, keys, offset) ->
339
+ this.mouse_event page_id, id, 'rightclick', keys, offset
331
340
 
332
- double_click: (page_id, id) ->
333
- this.mouse_event page_id, id, 'doubleclick'
341
+ double_click: (page_id, id, keys, offset) ->
342
+ this.mouse_event page_id, id, 'doubleclick', keys, offset
334
343
 
335
344
  hover: (page_id, id) ->
336
345
  this.mouse_event page_id, id, 'mousemove'
@@ -458,22 +467,23 @@ class Poltergeist.Browser
458
467
  @current_command.sendResponse(@currentPage.getCustomHeaders())
459
468
 
460
469
  set_headers: (headers) ->
461
- # Workaround for https://code.google.com/p/phantomjs/issues/detail?id=745
462
- @currentPage.setUserAgent(headers['User-Agent']) if headers['User-Agent']
463
- @currentPage.setCustomHeaders(headers)
470
+ this.add_headers(headers, false, false)
471
+
472
+ add_headers: (headers, local = false, keepExisting = true) ->
473
+ pages = if local then [@currentPage] else @pages
474
+ pages.forEach (page) =>
475
+ allHeaders = if keepExisting then page.getCustomHeaders() else {}
476
+ for name, value of headers
477
+ allHeaders[name] = value
478
+ page.setUserAgent(allHeaders['User-Agent']) if allHeaders['User-Agent']
479
+ page.setCustomHeaders(allHeaders)
464
480
  @current_command.sendResponse(true)
465
481
 
466
- add_headers: (headers) ->
467
- allHeaders = @currentPage.getCustomHeaders()
468
- for name, value of headers
469
- allHeaders[name] = value
470
- this.set_headers(allHeaders)
471
-
472
482
  add_header: (header, { permanent = true }) ->
473
483
  unless permanent == true
474
484
  @currentPage.addTempHeader(header)
475
485
  @currentPage.addTempHeaderToRemoveOnRedirect(header) if permanent == "no_redirect"
476
- this.add_headers(header)
486
+ this.add_headers(header, permanent != true)
477
487
 
478
488
  response_headers: ->
479
489
  @current_command.sendResponse(@currentPage.responseHeaders())
@@ -511,6 +521,11 @@ class Poltergeist.Browser
511
521
  @_debug = value
512
522
  @current_command.sendResponse(true)
513
523
 
524
+ set_page_settings: (settings)->
525
+ @_page_settings = settings
526
+ @page.setSettings(@_page_settings)
527
+ @current_command.sendResponse(true)
528
+
514
529
  exit: ->
515
530
  phantom.exit()
516
531
 
@@ -25,8 +25,8 @@ PoltergeistAgent = (function() {
25
25
  }
26
26
  };
27
27
 
28
- PoltergeistAgent.prototype.currentUrl = function() {
29
- return window.location.href.replace(/\ /g, '%20');
28
+ PoltergeistAgent.prototype.frameUrl = function() {
29
+ return window.location.href;
30
30
  };
31
31
 
32
32
  PoltergeistAgent.prototype.find = function(method, selector, within) {
@@ -99,7 +99,12 @@ PoltergeistAgent = (function() {
99
99
  };
100
100
 
101
101
  PoltergeistAgent.prototype.clearLocalStorage = function() {
102
- return typeof localStorage !== "undefined" && localStorage !== null ? localStorage.clear() : void 0;
102
+ var error;
103
+ try {
104
+ return typeof localStorage !== "undefined" && localStorage !== null ? localStorage.clear() : void 0;
105
+ } catch (error1) {
106
+ error = error1;
107
+ }
103
108
  };
104
109
 
105
110
  PoltergeistAgent.prototype.wrapResults = function(result, page_id) {
@@ -388,10 +393,10 @@ PoltergeistAgent.Node = (function() {
388
393
  } else if (value === false && !this.element.parentNode.multiple) {
389
394
  return false;
390
395
  } else {
391
- this.trigger('focus', this.element.parentNode);
396
+ this.trigger('focus', {}, this.element.parentNode);
392
397
  this.element.selected = value;
393
398
  this.changed();
394
- this.trigger('blur', this.element.parentNode);
399
+ this.trigger('blur', {}, this.element.parentNode);
395
400
  return true;
396
401
  }
397
402
  };
@@ -497,14 +502,17 @@ PoltergeistAgent.Node = (function() {
497
502
  return pos;
498
503
  };
499
504
 
500
- Node.prototype.trigger = function(name, element) {
505
+ Node.prototype.trigger = function(name, options, element) {
501
506
  var event;
507
+ if (options == null) {
508
+ options = {};
509
+ }
502
510
  if (element == null) {
503
511
  element = this.element;
504
512
  }
505
513
  if (Node.EVENTS.MOUSE.indexOf(name) !== -1) {
506
514
  event = document.createEvent('MouseEvent');
507
- event.initMouseEvent(name, true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
515
+ event.initMouseEvent(name, true, true, window, 0, options['screenX'] || 0, options['screenY'] || 0, options['clientX'] || 0, options['clientY'] || 0, options['ctrlKey'] || false, options['altKey'] || false, options['shiftKey'] || false, options['metaKey'] || false, options['button'] || 0, null);
508
516
  } else if (Node.EVENTS.FOCUS.indexOf(name) !== -1) {
509
517
  event = this.obtainEvent(name);
510
518
  } else if (Node.EVENTS.FORM.indexOf(name) !== -1) {
@@ -614,3 +622,7 @@ window.__poltergeist = new PoltergeistAgent;
614
622
  document.addEventListener('DOMContentLoaded', function() {
615
623
  return console.log('__DOMContentLoaded');
616
624
  });
625
+
626
+ if (document.readyState === 'complete') {
627
+ console.log('__DOMContentLoaded');
628
+ }
@@ -9,6 +9,7 @@ Poltergeist.Browser = (function() {
9
9
  this.js_errors = true;
10
10
  this._debug = false;
11
11
  this._counter = 0;
12
+ this._page_settings = null;
12
13
  this.processed_modal_messages = [];
13
14
  this.confirm_processes = [];
14
15
  this.prompt_responses = [];
@@ -20,14 +21,14 @@ Poltergeist.Browser = (function() {
20
21
  ref = [0, []], this._counter = ref[0], this.pages = ref[1];
21
22
  if (this.page != null) {
22
23
  if (!this.page.closed) {
23
- if (this.page.currentUrl() !== 'about:blank') {
24
+ if (this.page.frameUrl() !== 'about:blank') {
24
25
  this.page.clearLocalStorage();
25
26
  }
26
27
  this.page.close();
27
28
  }
28
29
  phantom.clearCookies();
29
30
  }
30
- this.page = this.currentPage = new Poltergeist.WebPage;
31
+ this.page = this.currentPage = new Poltergeist.WebPage(null, this._page_settings);
31
32
  this.page.setViewportSize({
32
33
  width: this.width,
33
34
  height: this.height
@@ -71,11 +72,13 @@ Poltergeist.Browser = (function() {
71
72
  page.onPageCreated = (function(_this) {
72
73
  return function(newPage) {
73
74
  var _page;
74
- _page = new Poltergeist.WebPage(newPage);
75
+ _page = new Poltergeist.WebPage(newPage, _this._page_settings);
75
76
  _page.handle = "" + (_this._counter++);
76
77
  _page.urlBlacklist = page.urlBlacklist;
77
78
  _page.urlWhitelist = page.urlWhitelist;
78
79
  _page.setViewportSize(page.viewportSize());
80
+ _page.setUserAgent(page.getUserAgent());
81
+ _page.setCustomHeaders(page.getPermanentCustomHeaders());
79
82
  _this.setupPageHandlers(_page);
80
83
  return _this.pages.push(_page);
81
84
  };
@@ -129,7 +132,7 @@ Poltergeist.Browser = (function() {
129
132
  this.processed_modal_messages = [];
130
133
  this.confirm_processes = [];
131
134
  this.prompt_responses = [];
132
- prevUrl = this.currentPage.source === null ? 'about:blank' : this.currentPage.currentUrl();
135
+ prevUrl = this.currentPage.source != null ? this.currentPage.currentUrl() : 'about:blank';
133
136
  this.currentPage.open(url);
134
137
  if (/#/.test(url) && prevUrl.split('#')[0] === url.split('#')[0]) {
135
138
  this.currentPage.state = 'default';
@@ -160,6 +163,10 @@ Poltergeist.Browser = (function() {
160
163
  return this.current_command.sendResponse(this.currentPage.currentUrl());
161
164
  };
162
165
 
166
+ Browser.prototype.frame_url = function() {
167
+ return this.current_command.sendResponse(this.currentPage.frameUrl());
168
+ };
169
+
163
170
  Browser.prototype.status_code = function() {
164
171
  return this.current_command.sendResponse(this.currentPage.statusCode);
165
172
  };
@@ -176,6 +183,10 @@ Poltergeist.Browser = (function() {
176
183
  return this.current_command.sendResponse(this.currentPage.title());
177
184
  };
178
185
 
186
+ Browser.prototype.frame_title = function() {
187
+ return this.current_command.sendResponse(this.currentPage.frameTitle());
188
+ };
189
+
179
190
  Browser.prototype.find = function(method, selector) {
180
191
  return this.current_command.sendResponse({
181
192
  page_id: this.currentPage.id,
@@ -311,8 +322,8 @@ Poltergeist.Browser = (function() {
311
322
  return this.current_command.sendResponse(true);
312
323
  };
313
324
 
314
- Browser.prototype.frameUrl = function(frame_name) {
315
- return this.currentPage.frameUrl(frame_name);
325
+ Browser.prototype.frameUrlFor = function(frame_name) {
326
+ return this.currentPage.frameUrlFor(frame_name);
316
327
  };
317
328
 
318
329
  Browser.prototype.pushFrame = function(command, name, timeout) {
@@ -325,11 +336,11 @@ Poltergeist.Browser = (function() {
325
336
  name = frame.getAttribute('name');
326
337
  }
327
338
  }
328
- frame_url = this.frameUrl(name);
339
+ frame_url = this.frameUrlFor(name);
329
340
  if (indexOf.call(this.currentPage.blockedUrls(), frame_url) >= 0) {
330
341
  return command.sendResponse(true);
331
342
  } else if (this.currentPage.pushFrame(name)) {
332
- if (frame_url && (frame_url !== 'about:blank') && (this.currentPage.currentUrl() === 'about:blank')) {
343
+ if (frame_url && (frame_url !== 'about:blank') && (this.currentPage.frameUrl() === 'about:blank')) {
333
344
  this.currentPage.state = 'awaiting_frame_load';
334
345
  return this.currentPage.waitState('default', function() {
335
346
  return command.sendResponse(true);
@@ -421,11 +432,17 @@ Poltergeist.Browser = (function() {
421
432
  }
422
433
  };
423
434
 
424
- Browser.prototype.mouse_event = function(page_id, id, name) {
435
+ Browser.prototype.mouse_event = function(page_id, id, name, keys, offset) {
425
436
  var command, event_page, last_mouse_event, node;
437
+ if (keys == null) {
438
+ keys = [];
439
+ }
440
+ if (offset == null) {
441
+ offset = {};
442
+ }
426
443
  node = this.node(page_id, id);
427
444
  this.currentPage.state = 'mouse_event';
428
- last_mouse_event = node.mouseEvent(name);
445
+ last_mouse_event = node.mouseEvent(name, keys, offset);
429
446
  event_page = this.currentPage;
430
447
  command = this.current_command;
431
448
  return setTimeout(function() {
@@ -444,16 +461,16 @@ Poltergeist.Browser = (function() {
444
461
  }, 5);
445
462
  };
446
463
 
447
- Browser.prototype.click = function(page_id, id) {
448
- return this.mouse_event(page_id, id, 'click');
464
+ Browser.prototype.click = function(page_id, id, keys, offset) {
465
+ return this.mouse_event(page_id, id, 'click', keys, offset);
449
466
  };
450
467
 
451
- Browser.prototype.right_click = function(page_id, id) {
452
- return this.mouse_event(page_id, id, 'rightclick');
468
+ Browser.prototype.right_click = function(page_id, id, keys, offset) {
469
+ return this.mouse_event(page_id, id, 'rightclick', keys, offset);
453
470
  };
454
471
 
455
- Browser.prototype.double_click = function(page_id, id) {
456
- return this.mouse_event(page_id, id, 'doubleclick');
472
+ Browser.prototype.double_click = function(page_id, id, keys, offset) {
473
+ return this.mouse_event(page_id, id, 'doubleclick', keys, offset);
457
474
  };
458
475
 
459
476
  Browser.prototype.hover = function(page_id, id) {
@@ -643,21 +660,33 @@ Poltergeist.Browser = (function() {
643
660
  };
644
661
 
645
662
  Browser.prototype.set_headers = function(headers) {
646
- if (headers['User-Agent']) {
647
- this.currentPage.setUserAgent(headers['User-Agent']);
648
- }
649
- this.currentPage.setCustomHeaders(headers);
650
- return this.current_command.sendResponse(true);
663
+ return this.add_headers(headers, false, false);
651
664
  };
652
665
 
653
- Browser.prototype.add_headers = function(headers) {
654
- var allHeaders, name, value;
655
- allHeaders = this.currentPage.getCustomHeaders();
656
- for (name in headers) {
657
- value = headers[name];
658
- allHeaders[name] = value;
666
+ Browser.prototype.add_headers = function(headers, local, keepExisting) {
667
+ var pages;
668
+ if (local == null) {
669
+ local = false;
659
670
  }
660
- return this.set_headers(allHeaders);
671
+ if (keepExisting == null) {
672
+ keepExisting = true;
673
+ }
674
+ pages = local ? [this.currentPage] : this.pages;
675
+ pages.forEach((function(_this) {
676
+ return function(page) {
677
+ var allHeaders, name, value;
678
+ allHeaders = keepExisting ? page.getCustomHeaders() : {};
679
+ for (name in headers) {
680
+ value = headers[name];
681
+ allHeaders[name] = value;
682
+ }
683
+ if (allHeaders['User-Agent']) {
684
+ page.setUserAgent(allHeaders['User-Agent']);
685
+ }
686
+ return page.setCustomHeaders(allHeaders);
687
+ };
688
+ })(this));
689
+ return this.current_command.sendResponse(true);
661
690
  };
662
691
 
663
692
  Browser.prototype.add_header = function(header, arg1) {
@@ -669,7 +698,7 @@ Poltergeist.Browser = (function() {
669
698
  this.currentPage.addTempHeaderToRemoveOnRedirect(header);
670
699
  }
671
700
  }
672
- return this.add_headers(header);
701
+ return this.add_headers(header, permanent !== true);
673
702
  };
674
703
 
675
704
  Browser.prototype.response_headers = function() {
@@ -715,6 +744,12 @@ Poltergeist.Browser = (function() {
715
744
  return this.current_command.sendResponse(true);
716
745
  };
717
746
 
747
+ Browser.prototype.set_page_settings = function(settings) {
748
+ this._page_settings = settings;
749
+ this.page.setSettings(this._page_settings);
750
+ return this.current_command.sendResponse(true);
751
+ };
752
+
718
753
  Browser.prototype.exit = function() {
719
754
  return phantom.exit();
720
755
  };
@@ -27,8 +27,11 @@ Poltergeist.Node = (function() {
27
27
  fn(name);
28
28
  }
29
29
 
30
- Node.prototype.mouseEventPosition = function() {
31
- var area_offset, image, middle, pos, res, viewport;
30
+ Node.prototype.mouseEventPosition = function(offset) {
31
+ var area_offset, image, middle, pos, viewport;
32
+ if (offset == null) {
33
+ offset = {};
34
+ }
32
35
  viewport = this.page.viewportSize();
33
36
  if (image = this._getAreaImage()) {
34
37
  pos = image.position();
@@ -44,27 +47,51 @@ Poltergeist.Node = (function() {
44
47
  middle = function(start, end, size) {
45
48
  return start + ((Math.min(end, size) - start) / 2);
46
49
  };
47
- return res = {
48
- x: middle(pos.left, pos.right, viewport.width),
49
- y: middle(pos.top, pos.bottom, viewport.height)
50
- };
50
+ if ((offset['x'] != null) && (offset['y'] != null)) {
51
+ return {
52
+ x: pos.left + offset['x'],
53
+ y: pos.top + offset['y']
54
+ };
55
+ } else {
56
+ return {
57
+ x: middle(pos.left, pos.right, viewport.width),
58
+ y: middle(pos.top, pos.bottom, viewport.height)
59
+ };
60
+ }
51
61
  };
52
62
 
53
- Node.prototype.mouseEvent = function(name) {
54
- var area_image, pos, test;
63
+ Node.prototype.mouseEvent = function(name, keys, offset) {
64
+ var area_image, modifier_keys, modifiers_code, pos, scroll_pos, test;
55
65
  if (area_image = this._getAreaImage()) {
56
66
  area_image.scrollIntoView();
57
67
  } else {
58
68
  this.scrollIntoView();
59
69
  }
60
- pos = this.mouseEventPosition();
70
+ pos = this.mouseEventPosition(offset);
61
71
  test = this.mouseEventTest(pos.x, pos.y);
62
72
  if (test.status === 'success') {
73
+ modifier_keys = (keys || []).join(',').replace('control', 'ctrl');
74
+ modifiers_code = this.page.keyModifierCode(modifier_keys);
63
75
  if (name === 'rightclick') {
64
- this.page.mouseEvent('click', pos.x, pos.y, 'right');
65
- this.trigger('contextmenu');
76
+ this.page.mouseEvent('click', pos.x, pos.y, 'right', modifiers_code);
77
+ if (phantom.version.major === 2 && phantom.version.minor >= 1) {
78
+ this.page.sendEvent('contextmenu', pos.x, pos.y, 'right', modifiers_code);
79
+ } else {
80
+ scroll_pos = this.page.scrollPosition();
81
+ this.trigger('contextmenu', {
82
+ screenX: pos.x,
83
+ screenY: pos.y,
84
+ clientX: pos.x + scroll_pos['left'],
85
+ clientY: pos.y + scroll_pos['top'],
86
+ ctrlKey: modifier_keys.indexOf('ctrl') !== -1,
87
+ altKey: modifier_keys.indexOf('alt') !== -1,
88
+ metaKey: modifier_keys.indexOf('meta') !== -1,
89
+ shiftKey: modifier_keys.indexOf('shift') !== -1,
90
+ button: 2
91
+ });
92
+ }
66
93
  } else {
67
- this.page.mouseEvent(name, pos.x, pos.y);
94
+ this.page.mouseEvent(name, pos.x, pos.y, 'left', modifiers_code);
68
95
  }
69
96
  return pos;
70
97
  } else {
@@ -6,15 +6,15 @@ var bind = function(fn, me){ return function(){ return fn.apply(me, arguments);
6
6
  Poltergeist.WebPage = (function() {
7
7
  var command, delegate, fn1, fn2, i, j, len, len1, ref, ref1;
8
8
 
9
- WebPage.CALLBACKS = ['onConsoleMessage', 'onError', 'onLoadFinished', 'onInitialized', 'onLoadStarted', 'onResourceRequested', 'onResourceReceived', 'onResourceError', 'onNavigationRequested', 'onUrlChanged', 'onPageCreated', 'onClosing', 'onCallback'];
9
+ WebPage.CALLBACKS = ['onConsoleMessage', 'onError', 'onLoadFinished', 'onInitialized', 'onLoadStarted', 'onResourceRequested', 'onResourceReceived', 'onResourceError', 'onResourceTimeout', 'onNavigationRequested', 'onUrlChanged', 'onPageCreated', 'onClosing', 'onCallback'];
10
10
 
11
- WebPage.DELEGATES = ['open', 'sendEvent', 'uploadFile', 'render', 'close', 'renderBase64', 'goBack', 'goForward', 'reload'];
11
+ WebPage.DELEGATES = ['url', 'open', 'sendEvent', 'uploadFile', 'render', 'close', 'renderBase64', 'goBack', 'goForward', 'reload'];
12
12
 
13
- WebPage.COMMANDS = ['currentUrl', 'find', 'nodeCall', 'documentSize', 'beforeUpload', 'afterUpload', 'clearLocalStorage'];
13
+ WebPage.COMMANDS = ['find', 'nodeCall', 'documentSize', 'beforeUpload', 'afterUpload', 'clearLocalStorage'];
14
14
 
15
15
  WebPage.EXTENSIONS = [];
16
16
 
17
- function WebPage(_native) {
17
+ function WebPage(_native, settings) {
18
18
  var callback, i, len, ref;
19
19
  this._native = _native;
20
20
  this._checkForAsyncResult = bind(this._checkForAsyncResult, this);
@@ -34,6 +34,7 @@ Poltergeist.WebPage = (function() {
34
34
  this._tempHeadersToRemoveOnRedirect = {};
35
35
  this._asyncResults = {};
36
36
  this._asyncEvaluationId = 0;
37
+ this.setSettings(settings);
37
38
  ref = WebPage.CALLBACKS;
38
39
  for (i = 0, len = ref.length; i < len; i++) {
39
40
  callback = ref[i];
@@ -68,6 +69,19 @@ Poltergeist.WebPage = (function() {
68
69
  fn2(delegate);
69
70
  }
70
71
 
72
+ WebPage.prototype.setSettings = function(settings) {
73
+ var results, setting, value;
74
+ if (settings == null) {
75
+ settings = {};
76
+ }
77
+ results = [];
78
+ for (setting in settings) {
79
+ value = settings[setting];
80
+ results.push(this._native.settings[setting] = value);
81
+ }
82
+ return results;
83
+ };
84
+
71
85
  WebPage.prototype.onInitializedNative = function() {
72
86
  this.id += 1;
73
87
  this.source = null;
@@ -182,6 +196,10 @@ Poltergeist.WebPage = (function() {
182
196
  return true;
183
197
  };
184
198
 
199
+ WebPage.prototype.onResourceTimeoutNative = function(request) {
200
+ return console.log("Resource request timed out for " + request.url);
201
+ };
202
+
185
203
  WebPage.prototype.injectAgent = function() {
186
204
  var extension, k, len2, ref2;
187
205
  if (this["native"]().evaluate(function() {
@@ -366,10 +384,26 @@ Poltergeist.WebPage = (function() {
366
384
  };
367
385
 
368
386
  WebPage.prototype.title = function() {
387
+ return this["native"]().title;
388
+ };
389
+
390
+ WebPage.prototype.frameTitle = function() {
369
391
  return this["native"]().frameTitle;
370
392
  };
371
393
 
372
- WebPage.prototype.frameUrl = function(frameNameOrId) {
394
+ WebPage.prototype.currentUrl = function() {
395
+ return this["native"]().url;
396
+ };
397
+
398
+ WebPage.prototype.frameUrl = function() {
399
+ if (phantom.version.major > 2 || (phantom.version.major === 2 && phantom.version.minor >= 1)) {
400
+ return this["native"]().frameUrl;
401
+ } else {
402
+ return this.runCommand('frameUrl');
403
+ }
404
+ };
405
+
406
+ WebPage.prototype.frameUrlFor = function(frameNameOrId) {
373
407
  var query;
374
408
  query = function(frameNameOrId) {
375
409
  var ref2;
@@ -438,6 +472,10 @@ Poltergeist.WebPage = (function() {
438
472
  }, selector);
439
473
  };
440
474
 
475
+ WebPage.prototype.getUserAgent = function() {
476
+ return this["native"]().settings.userAgent;
477
+ };
478
+
441
479
  WebPage.prototype.setUserAgent = function(userAgent) {
442
480
  return this["native"]().settings.userAgent = userAgent;
443
481
  };
@@ -446,6 +484,22 @@ Poltergeist.WebPage = (function() {
446
484
  return this["native"]().customHeaders;
447
485
  };
448
486
 
487
+ WebPage.prototype.getPermanentCustomHeaders = function() {
488
+ var allHeaders, name, ref2, ref3, value;
489
+ allHeaders = this.getCustomHeaders();
490
+ ref2 = this._tempHeaders;
491
+ for (name in ref2) {
492
+ value = ref2[name];
493
+ delete allHeaders[name];
494
+ }
495
+ ref3 = this._tempHeadersToRemoveOnRedirect;
496
+ for (name in ref3) {
497
+ value = ref3[name];
498
+ delete allHeaders[name];
499
+ }
500
+ return allHeaders;
501
+ };
502
+
449
503
  WebPage.prototype.setCustomHeaders = function(headers) {
450
504
  return this["native"]().customHeaders = headers;
451
505
  };
@@ -561,12 +615,15 @@ Poltergeist.WebPage = (function() {
561
615
  return new Poltergeist.Node(this, id);
562
616
  };
563
617
 
564
- WebPage.prototype.mouseEvent = function(name, x, y, button) {
618
+ WebPage.prototype.mouseEvent = function(name, x, y, button, modifiers) {
565
619
  if (button == null) {
566
620
  button = 'left';
567
621
  }
622
+ if (modifiers == null) {
623
+ modifiers = 0;
624
+ }
568
625
  this.sendEvent('mousemove', x, y);
569
- return this.sendEvent(name, x, y, button);
626
+ return this.sendEvent(name, x, y, button, modifiers);
570
627
  };
571
628
 
572
629
  WebPage.prototype.evaluate = function() {
@@ -17,7 +17,7 @@ class Poltergeist.Node
17
17
  this.prototype[name] = (args...) ->
18
18
  @page.nodeCall(@id, name, args)
19
19
 
20
- mouseEventPosition: ->
20
+ mouseEventPosition: (offset = {})->
21
21
  viewport = @page.viewportSize()
22
22
 
23
23
  if image = @_getAreaImage()
@@ -34,25 +34,44 @@ class Poltergeist.Node
34
34
  middle = (start, end, size) ->
35
35
  start + ((Math.min(end, size) - start) / 2)
36
36
 
37
- res = {
37
+ if offset['x']? && offset['y']?
38
+ x: pos.left + offset['x'],
39
+ y: pos.top + offset['y']
40
+ else
38
41
  x: middle(pos.left, pos.right, viewport.width),
39
42
  y: middle(pos.top, pos.bottom, viewport.height)
40
- }
41
43
 
42
44
 
43
- mouseEvent: (name) ->
45
+ mouseEvent: (name, keys, offset) ->
44
46
  if area_image = @_getAreaImage()
45
47
  area_image.scrollIntoView()
46
48
  else
47
49
  @scrollIntoView()
48
- pos = this.mouseEventPosition()
50
+ pos = this.mouseEventPosition(offset)
49
51
  test = this.mouseEventTest(pos.x, pos.y)
50
52
  if test.status == 'success'
53
+ modifier_keys = (keys || []).join(',').replace('control', 'ctrl')
54
+ modifiers_code = @page.keyModifierCode(modifier_keys)
51
55
  if name == 'rightclick'
52
- @page.mouseEvent('click', pos.x, pos.y, 'right')
53
- this.trigger('contextmenu')
56
+ @page.mouseEvent('click', pos.x, pos.y, 'right', modifiers_code)
57
+ if phantom.version.major == 2 && phantom.version.minor >= 1
58
+ @page.sendEvent('contextmenu', pos.x, pos.y, 'right', modifiers_code)
59
+ else
60
+ scroll_pos = @page.scrollPosition()
61
+ @trigger('contextmenu',
62
+ screenX: pos.x
63
+ screenY: pos.y
64
+ clientX: pos.x + scroll_pos['left']
65
+ clientY: pos.y + scroll_pos['top']
66
+ ctrlKey: modifier_keys.indexOf('ctrl') != -1
67
+ altKey: modifier_keys.indexOf('alt') != -1
68
+ metaKey: modifier_keys.indexOf('meta') != -1
69
+ shiftKey: modifier_keys.indexOf('shift') != -1
70
+ button: 2
71
+ )
54
72
  else
55
- @page.mouseEvent(name, pos.x, pos.y)
73
+ @page.mouseEvent(name, pos.x, pos.y, 'left', modifiers_code)
74
+
56
75
  pos
57
76
  else
58
77
  throw new Poltergeist.MouseEventFailed(name, test.selector, pos)
@@ -1,19 +1,20 @@
1
1
  class Poltergeist.WebPage
2
2
  @CALLBACKS = ['onConsoleMessage','onError',
3
3
  'onLoadFinished', 'onInitialized', 'onLoadStarted',
4
- 'onResourceRequested', 'onResourceReceived', 'onResourceError',
4
+ 'onResourceRequested', 'onResourceReceived', 'onResourceError', 'onResourceTimeout',
5
5
  'onNavigationRequested', 'onUrlChanged', 'onPageCreated',
6
6
  'onClosing', 'onCallback']
7
7
 
8
- @DELEGATES = ['open', 'sendEvent', 'uploadFile', 'render', 'close',
8
+ @DELEGATES = ['url', 'open', 'sendEvent', 'uploadFile', 'render', 'close',
9
9
  'renderBase64', 'goBack', 'goForward', 'reload']
10
10
 
11
- @COMMANDS = ['currentUrl', 'find', 'nodeCall', 'documentSize',
11
+ # @COMMANDS = ['currentUrl', 'find', 'nodeCall', 'documentSize',
12
+ @COMMANDS = ['find', 'nodeCall', 'documentSize',
12
13
  'beforeUpload', 'afterUpload', 'clearLocalStorage']
13
14
 
14
15
  @EXTENSIONS = []
15
16
 
16
- constructor: (@_native) ->
17
+ constructor: (@_native, settings) ->
17
18
  @_native or= require('webpage').create()
18
19
 
19
20
  @id = 0
@@ -32,6 +33,8 @@ class Poltergeist.WebPage
32
33
  @_asyncResults = {}
33
34
  @_asyncEvaluationId = 0
34
35
 
36
+ @setSettings(settings)
37
+
35
38
  for callback in WebPage.CALLBACKS
36
39
  this.bindCallback(callback)
37
40
 
@@ -48,6 +51,9 @@ class Poltergeist.WebPage
48
51
  this.prototype[delegate] =
49
52
  -> @_native[delegate].apply(@_native, arguments)
50
53
 
54
+ setSettings: (settings = {})->
55
+ @_native.settings[setting] = value for setting, value of settings
56
+
51
57
  onInitializedNative: ->
52
58
  @id += 1
53
59
  @source = null
@@ -134,6 +140,9 @@ class Poltergeist.WebPage
134
140
  delete @_requestedResources[errorResponse.id]
135
141
  return true
136
142
 
143
+ onResourceTimeoutNative: (request) ->
144
+ console.log "Resource request timed out for #{request.url}"
145
+
137
146
  injectAgent: ->
138
147
  if this.native().evaluate(-> typeof __poltergeist) == "undefined"
139
148
  this.native().injectJs "#{phantom.libraryPath}/agent.js"
@@ -221,9 +230,21 @@ class Poltergeist.WebPage
221
230
  this.native().frameContent
222
231
 
223
232
  title: ->
233
+ this.native().title
234
+
235
+ frameTitle: ->
224
236
  this.native().frameTitle
225
237
 
226
- frameUrl: (frameNameOrId) ->
238
+ currentUrl: ->
239
+ @native().url
240
+
241
+ frameUrl: ->
242
+ if phantom.version.major > 2 || (phantom.version.major == 2 && phantom.version.minor >= 1)
243
+ @native().frameUrl
244
+ else
245
+ @runCommand('frameUrl')
246
+
247
+ frameUrlFor: (frameNameOrId) ->
227
248
  query = (frameNameOrId) ->
228
249
  document.querySelector("iframe[name='#{frameNameOrId}'], iframe[id='#{frameNameOrId}']")?.src
229
250
  this.evaluate(query, frameNameOrId)
@@ -275,12 +296,23 @@ class Poltergeist.WebPage
275
296
  , selector
276
297
  )
277
298
 
299
+ getUserAgent: ->
300
+ this.native().settings.userAgent
301
+
278
302
  setUserAgent: (userAgent) ->
279
303
  this.native().settings.userAgent = userAgent
280
304
 
281
305
  getCustomHeaders: ->
282
306
  this.native().customHeaders
283
307
 
308
+ getPermanentCustomHeaders: ->
309
+ allHeaders = @getCustomHeaders()
310
+ for name, value of @_tempHeaders
311
+ delete allHeaders[name]
312
+ for name, value of @_tempHeadersToRemoveOnRedirect
313
+ delete allHeaders[name]
314
+ allHeaders
315
+
284
316
  setCustomHeaders: (headers) ->
285
317
  this.native().customHeaders = headers
286
318
 
@@ -354,9 +386,9 @@ class Poltergeist.WebPage
354
386
 
355
387
  # Before each mouse event we make sure that the mouse is moved to where the
356
388
  # event will take place. This deals with e.g. :hover changes.
357
- mouseEvent: (name, x, y, button = 'left') ->
389
+ mouseEvent: (name, x, y, button = 'left', modifiers = 0) ->
358
390
  this.sendEvent('mousemove', x, y)
359
- this.sendEvent(name, x, y, button)
391
+ this.sendEvent(name, x, y, button, modifiers)
360
392
 
361
393
  evaluate: (fn, args...) ->
362
394
  this.injectAgent()
@@ -30,6 +30,7 @@ module Capybara::Poltergeist
30
30
  browser.debug = true if options[:debug]
31
31
  browser.url_blacklist = options[:url_blacklist] if options.key?(:url_blacklist)
32
32
  browser.url_whitelist = options[:url_whitelist] if options.key?(:url_whitelist)
33
+ browser.page_settings = options[:page_settings] if options.key?(:page_settings)
33
34
  browser
34
35
  end
35
36
  end
@@ -100,7 +101,15 @@ module Capybara::Poltergeist
100
101
  end
101
102
 
102
103
  def current_url
103
- browser.current_url
104
+ if Capybara::VERSION.to_f < 3.0
105
+ frame_url
106
+ else
107
+ browser.current_url.gsub(' ', '%20') # PhantomJS < 2.1 doesn't escape spaces
108
+ end
109
+ end
110
+
111
+ def frame_url
112
+ browser.frame_url.gsub(' ', '%20') # PhantomJS < 2.1 doesn't escape spaces
104
113
  end
105
114
 
106
115
  def status_code
@@ -117,7 +126,15 @@ module Capybara::Poltergeist
117
126
  end
118
127
 
119
128
  def title
120
- browser.title
129
+ if Capybara::VERSION.to_f < 3.0
130
+ frame_title
131
+ else
132
+ browser.title
133
+ end
134
+ end
135
+
136
+ def frame_title
137
+ browser.frame_title
121
138
  end
122
139
 
123
140
  def find(method, selector)
@@ -49,7 +49,15 @@ module Capybara::Poltergeist
49
49
  end
50
50
 
51
51
  def visible_text
52
- filter_text command(:visible_text)
52
+ if Capybara::VERSION.to_f < 3.0
53
+ filter_text command(:visible_text)
54
+ else
55
+ command(:visible_text).to_s
56
+ .gsub(/\A[[:space:]&&[^\u00a0]]+/, "")
57
+ .gsub(/[[:space:]&&[^\u00a0]]+\z/, "")
58
+ .gsub(/\n+/, "\n")
59
+ .tr("\u00a0", ' ')
60
+ end
53
61
  end
54
62
 
55
63
  def property(name)
@@ -79,7 +87,9 @@ module Capybara::Poltergeist
79
87
  command :value
80
88
  end
81
89
 
82
- def set(value)
90
+ def set(value, options = {})
91
+ warn "Options passed to Node#set but Poltergeist doesn't currently support any - ignoring" unless options.empty?
92
+
83
93
  if tag_name == 'input'
84
94
  case self[:type]
85
95
  when 'radio'
@@ -129,16 +139,16 @@ module Capybara::Poltergeist
129
139
  command :disabled?
130
140
  end
131
141
 
132
- def click
133
- command :click
142
+ def click(keys=[], offset={})
143
+ command :click, keys, offset
134
144
  end
135
145
 
136
- def right_click
137
- command :right_click
146
+ def right_click(keys=[], offset={})
147
+ command :right_click, keys, offset
138
148
  end
139
149
 
140
- def double_click
141
- command :double_click
150
+ def double_click(keys=[], offset={})
151
+ command :double_click, keys, offset
142
152
  end
143
153
 
144
154
  def hover
@@ -182,8 +192,16 @@ module Capybara::Poltergeist
182
192
 
183
193
  private
184
194
 
185
- def filter_text(text)
186
- Capybara::Helpers.normalize_whitespace(text.to_s)
195
+ def filter_text(text, visible = true)
196
+ if Capybara::VERSION.to_f < 3
197
+ Capybara::Helpers.normalize_whitespace(text.to_s)
198
+ else
199
+ text.gsub(/[\u200b\u200e\u200f]/, '')
200
+ .gsub(/[\ \n\f\t\v\u2028\u2029]+/, ' ')
201
+ .gsub(/\A[[:space:]&&[^\u00a0]]+/, "")
202
+ .gsub(/[[:space:]&&[^\u00a0]]+\z/, "")
203
+ .tr("\u00a0", ' ')
204
+ end
187
205
  end
188
206
  end
189
207
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Capybara
4
4
  module Poltergeist
5
- VERSION = "1.17.0"
5
+ VERSION = "1.18.0"
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,29 +1,35 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: poltergeist
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.17.0
4
+ version: 1.18.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jon Leighton
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-12-12 00:00:00.000000000 Z
11
+ date: 2018-05-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: capybara
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - "~>"
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
19
  version: '2.1'
20
+ - - "<"
21
+ - !ruby/object:Gem::Version
22
+ version: '4'
20
23
  type: :runtime
21
24
  prerelease: false
22
25
  version_requirements: !ruby/object:Gem::Requirement
23
26
  requirements:
24
- - - "~>"
27
+ - - ">="
25
28
  - !ruby/object:Gem::Version
26
29
  version: '2.1'
30
+ - - "<"
31
+ - !ruby/object:Gem::Version
32
+ version: '4'
27
33
  - !ruby/object:Gem::Dependency
28
34
  name: websocket-driver
29
35
  requirement: !ruby/object:Gem::Requirement
@@ -273,7 +279,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
273
279
  version: '0'
274
280
  requirements: []
275
281
  rubyforge_project:
276
- rubygems_version: 2.7.0
282
+ rubygems_version: 2.7.6
277
283
  signing_key:
278
284
  specification_version: 4
279
285
  summary: PhantomJS driver for Capybara