poltergeist 1.17.0 → 1.18.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: 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