poltergeist 1.14.0 → 1.15.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
  SHA1:
3
- metadata.gz: dc319cb98595a9cedd482bffd3756720c4ed24b4
4
- data.tar.gz: a79f76c1344f910aac1aa9f38a0cb6fd40dfa075
3
+ metadata.gz: 83bb04d3f05ad64c5a1b5b213d89acce146434b3
4
+ data.tar.gz: 6b566336fff00fff1f62fe1161e55beb45e713ce
5
5
  SHA512:
6
- metadata.gz: f0c6a5e24513e4c34e755c2a4cee6191580648d98bea2ba26877b8d4267dafb75a6aedd0d61d49b767b02dd825cdbcbbd1a59d05a85fc35a3230aaf92eccadaa
7
- data.tar.gz: c634a8ee97d076785499dd803553174d1ed5932cede4f80bdc23dc11a364cec694d024a8e51bf10cf0155948ddc9a38515d5f43fbc7d3c1590ace315a88d3169
6
+ metadata.gz: 159c3e618bd128c033e6746738e725b6e4f7cd2be5a9b7da53455c09c58c6f48d98a2eaf4dd0087b355a6259489d419be989bb6df89f5c7d86485a33c7217de2
7
+ data.tar.gz: bd0c8a67bf6e392e2aff5e5a6cc0e65d818c173e1879d8d6dc1ffc282d4bcc48374fcf6943ff30283e981d6398489125bd7151f7ecf1e8ced971c445ec108dfc
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.13.0).](https://github.com/teampoltergeist/poltergeist/tree/v1.13.0)**
12
+ (1.15.0).](https://github.com/teampoltergeist/poltergeist/tree/v1.15.0)**
13
13
 
14
14
  ## Getting help ##
15
15
 
@@ -88,8 +88,9 @@ was 1.0.2, so you should use that if you still need Ruby 1.8 support.
88
88
  There are no special steps to take. You don't need Xvfb or any running X
89
89
  server at all.
90
90
 
91
- [Travis CI](https://travis-ci.org/), [CircleCI](https://circleci.com/)
92
- and [Codeship](https://codeship.com/) has PhantomJS pre-installed.
91
+ [Travis CI](https://travis-ci.org/), [CircleCI](https://circleci.com/),
92
+ [Codeship](https://codeship.com/) and [Semaphore](https://semaphoreci.com/)
93
+ have PhantomJS pre-installed.
93
94
 
94
95
  Depending on your tests, one thing that you may need is some fonts. If
95
96
  you're getting errors on a CI that don't occur during development then
@@ -280,8 +281,8 @@ end
280
281
  to be passed to PhantomJS, e.g. `['--load-images=no', '--ignore-ssl-errors=yes']`
281
282
  * `:extensions` (Array) - An array of JS files to be preloaded into
282
283
  the phantomjs browser. Useful for faking unsupported APIs.
283
- * `:port` (Fixnum) - The port which should be used to communicate
284
- with the PhantomJS process. Defaults to a random open port.
284
+ * `:port` (Fixnum) - The port which should be used to communicate with the PhantomJS process. Defaults to a random open port.
285
+ * `:host` (String) - The name or IP of the PhantomJS host. Default is '127.0.0.1'.
285
286
  * `:url_blacklist` (Array) - Default session url blacklist - expressed as an array of strings to match against requested URLs.
286
287
  * `:url_whitelist` (Array) - Default session url whitelist - expressed as an array of strings to match against requested URLs.
287
288
 
@@ -11,7 +11,8 @@ module Capybara::Poltergeist
11
11
  'Poltergeist.InvalidSelector' => InvalidSelector,
12
12
  'Poltergeist.StatusFailError' => StatusFailError,
13
13
  'Poltergeist.NoSuchWindowError' => NoSuchWindowError,
14
- 'Poltergeist.UnsupportedFeature' => UnsupportedFeature
14
+ 'Poltergeist.UnsupportedFeature' => UnsupportedFeature,
15
+ 'Poltergeist.KeyError' => KeyError,
15
16
  }
16
17
 
17
18
  attr_reader :server, :client, :logger
@@ -442,15 +443,15 @@ module Capybara::Poltergeist
442
443
  }
443
444
 
444
445
  def normalize_keys(keys)
445
- keys.map do |key|
446
- case key
446
+ keys.map do |key_desc|
447
+ case key_desc
447
448
  when Array
448
- # [:Shift, "s"] => { modifier: "shift", key: "S" }
449
- # [:Shift, "string"] => { modifier: "shift", key: "STRING" }
450
- # [:Ctrl, :Left] => { modifier: "ctrl", key: :Left }
451
- # [:Ctrl, :Shift, :Left] => { modifier: "ctrl,shift", key: :Left }
449
+ # [:Shift, "s"] => { modifier: "shift", keys: "S" }
450
+ # [:Shift, "string"] => { modifier: "shift", keys: "STRING" }
451
+ # [:Ctrl, :Left] => { modifier: "ctrl", key: 'Left' }
452
+ # [:Ctrl, :Shift, :Left] => { modifier: "ctrl,shift", key: 'Left' }
452
453
  # [:Ctrl, :Left, :Left] => { modifier: "ctrl", key: [:Left, :Left] }
453
- _keys = key.chunk {|k| k.is_a?(Symbol) && %w(shift ctrl control alt meta command).include?(k.to_s.downcase) }
454
+ _keys = key_desc.chunk {|k| k.is_a?(Symbol) && %w(shift ctrl control alt meta command).include?(k.to_s.downcase) }
454
455
  modifiers = if _keys.peek[0]
455
456
  _keys.next[1].map do |k|
456
457
  k = k.to_s.downcase
@@ -461,19 +462,19 @@ module Capybara::Poltergeist
461
462
  else
462
463
  ''
463
464
  end
464
- letter = normalize_keys(_keys.next[1].map {|k| k.is_a?(String) ? k.upcase : k })
465
- { modifier: modifiers, key: letter }
465
+ letters = normalize_keys(_keys.next[1].map {|k| k.is_a?(String) ? k.upcase : k })
466
+ { modifier: modifiers, keys: letters }
466
467
  when Symbol
467
468
  # Return a known sequence for PhantomJS
468
- key = KEY_ALIASES.fetch(key, key)
469
+ key = KEY_ALIASES.fetch(key_desc, key_desc)
469
470
  if match = key.to_s.match(/numpad(.)/)
470
- res = { key: match[1], modifier: 'keypad' }
471
+ res = { keys: match[1], modifier: 'keypad' }
471
472
  elsif key !~ /^[A-Z]/
472
- key = key.to_s.split('_').map{|e| e.capitalize}.join
473
+ key = key.to_s.split('_').map{ |e| e.capitalize }.join
473
474
  end
474
475
  res || { key: key }
475
476
  when String
476
- key # Plain string, nothing to do
477
+ key_desc # Plain string, nothing to do
477
478
  end
478
479
  end
479
480
  end
@@ -64,6 +64,7 @@ module Capybara::Poltergeist
64
64
 
65
65
  process_options = {}
66
66
  process_options[:pgroup] = true unless Capybara::Poltergeist.windows?
67
+ process_options[:out] = @write_io if Capybara::Poltergeist.mri?
67
68
 
68
69
  redirect_stdout do
69
70
  @pid = Process.spawn(*command.map(&:to_s), process_options)
@@ -91,6 +92,7 @@ module Capybara::Poltergeist
91
92
  parts << PHANTOMJS_SCRIPT
92
93
  parts << server.port
93
94
  parts.concat window_size
95
+ parts << server.host
94
96
  parts
95
97
  end
96
98
 
@@ -102,14 +104,20 @@ module Capybara::Poltergeist
102
104
  # lose all the output from child. Process.popen can be used here and seems
103
105
  # it works with JRuby but I've experienced strange mistakes on Rubinius.
104
106
  def redirect_stdout
105
- prev = STDOUT.dup
106
- $stdout = @write_io
107
- STDOUT.reopen(@write_io)
108
- yield
109
- ensure
110
- STDOUT.reopen(prev)
111
- $stdout = STDOUT
112
- prev.close
107
+ if Capybara::Poltergeist.mri?
108
+ yield
109
+ else
110
+ begin
111
+ prev = STDOUT.dup
112
+ $stdout = @write_io
113
+ STDOUT.reopen(@write_io)
114
+ yield
115
+ ensure
116
+ STDOUT.reopen(prev)
117
+ $stdout = STDOUT
118
+ prev.close
119
+ end
120
+ end
113
121
  end
114
122
 
115
123
  def kill_phantomjs
@@ -117,6 +117,8 @@ class Poltergeist.Browser
117
117
  resources = @openResourceRequests()
118
118
  msg = if resources.length
119
119
  "Timed out with the following resources still waiting #{resources.join(',')}"
120
+ else
121
+ "Timed out with no open resource requests"
120
122
  command.sendError(new Poltergeist.StatusFailError(url,msg))
121
123
  return
122
124
 
@@ -356,10 +358,14 @@ class Poltergeist.Browser
356
358
 
357
359
  _send_keys_with_modifiers: (keys, current_modifier_code = 0) ->
358
360
  for sequence in keys
359
- key = if sequence.key?
360
- @currentPage.keyCode(sequence.key) || sequence.key
361
+ if sequence.key?
362
+ if !(key=@currentPage.keyCode(sequence.key))
363
+ @current_command.sendError(new Poltergeist.KeyError("Unknown key: #{sequence.key}"))
364
+ return
365
+ else if sequence.keys?
366
+ key=sequence.keys
361
367
  else
362
- sequence
368
+ key=sequence
363
369
 
364
370
  if sequence.modifier?
365
371
  modifier_keys = @currentPage.keyModifierKeys(sequence.modifier)
@@ -369,6 +375,7 @@ class Poltergeist.Browser
369
375
  @currentPage.sendEvent('keyup', modifier_key) for modifier_key in modifier_keys
370
376
  else
371
377
  @currentPage.sendEvent('keypress', key, null, null, current_modifier_code)
378
+ return true
372
379
 
373
380
  render_base64: (format, { full = false, selector = null } = {})->
374
381
  window_scroll_position = @currentPage.native().evaluate("function(){ return [window.pageXOffset, window.pageYOffset] }")
@@ -498,24 +505,20 @@ class Poltergeist.Browser
498
505
  throw new Error('zomg')
499
506
 
500
507
  go_back: ->
501
- command = @current_command
502
508
  if @currentPage.canGoBack
503
- @currentPage.state = 'loading'
509
+ @currentPage.state = 'wait_for_loading'
504
510
  @currentPage.goBack()
505
- @currentPage.waitState 'default', ->
506
- command.sendResponse(true)
511
+ @_waitForHistoryChange()
507
512
  else
508
- command.sendResponse(false)
513
+ @current_command.sendResponse(false)
509
514
 
510
515
  go_forward: ->
511
- command = @current_command
512
516
  if @currentPage.canGoForward
513
- @currentPage.state = 'loading'
517
+ @currentPage.state = 'wait_for_loading'
514
518
  @currentPage.goForward()
515
- @currentPage.waitState 'default', ->
516
- command.sendResponse(true)
519
+ @_waitForHistoryChange()
517
520
  else
518
- command.sendResponse(false)
521
+ @current_command.sendResponse(false)
519
522
 
520
523
  set_url_whitelist: (wildcards...)->
521
524
  @currentPage.urlWhitelist = (@_wildcardToRegexp(wc) for wc in wildcards)
@@ -540,6 +543,21 @@ class Poltergeist.Browser
540
543
  @currentPage.clearMemoryCache()
541
544
  @current_command.sendResponse(true)
542
545
 
546
+ _waitForHistoryChange: ->
547
+ command = @current_command
548
+ @currentPage.waitState ['loading','default'], (cur_state) ->
549
+ if cur_state == 'loading'
550
+ # loading has started, wait for completion
551
+ @waitState 'default', ->
552
+ command.sendResponse(true)
553
+ else
554
+ # page has loaded
555
+ command.sendResponse(true)
556
+ , 0.5, ->
557
+ # if haven't moved to loading/default in time assume history API state change
558
+ @state = 'default'
559
+ command.sendResponse(true)
560
+
543
561
  _wildcardToRegexp: (wildcard)->
544
562
  wildcard = wildcard.replace(/[\-\[\]\/\{\}\(\)\+\.\\\^\$\|]/g, "\\$&")
545
563
  wildcard = wildcard.replace(/\*/g, ".*")
@@ -2,18 +2,20 @@ class Poltergeist.Cmd
2
2
  constructor: (@owner, @id, @name, @args)->
3
3
  @_response_sent = false
4
4
  sendResponse: (response) ->
5
- errors = @browser.currentPage.errors
6
- @browser.currentPage.clearErrors()
5
+ if !@_response_sent
6
+ errors = @browser.currentPage.errors
7
+ @browser.currentPage.clearErrors()
7
8
 
8
- if errors.length > 0 && @browser.js_errors
9
- @sendError(new Poltergeist.JavascriptError(errors))
10
- else
11
- @owner.sendResponse(@id, response) unless @_response_sent
12
- @_response_sent = true
9
+ if errors.length > 0 && @browser.js_errors
10
+ @sendError(new Poltergeist.JavascriptError(errors))
11
+ else
12
+ @owner.sendResponse(@id, response)
13
+ @_response_sent = true
13
14
 
14
15
  sendError: (errors) ->
15
- @owner.sendError(@id, errors) unless @_response_sent
16
- @_response_sent = true
16
+ if !@_response_sent
17
+ @owner.sendError(@id, errors)
18
+ @_response_sent = true
17
19
 
18
20
  run: (@browser) ->
19
21
  try
@@ -145,7 +145,7 @@ Poltergeist.Browser = (function() {
145
145
  }, max_wait, function() {
146
146
  var msg, resources;
147
147
  resources = this.openResourceRequests();
148
- msg = resources.length ? "Timed out with the following resources still waiting " + (resources.join(',')) : void 0;
148
+ msg = resources.length ? "Timed out with the following resources still waiting " + (resources.join(',')) : "Timed out with no open resource requests";
149
149
  return command.sendError(new Poltergeist.StatusFailError(url, msg));
150
150
  });
151
151
  }
@@ -483,14 +483,22 @@ Poltergeist.Browser = (function() {
483
483
  };
484
484
 
485
485
  Browser.prototype._send_keys_with_modifiers = function(keys, current_modifier_code) {
486
- var i, j, key, len, len1, modifier_code, modifier_key, modifier_keys, results, sequence;
486
+ var i, j, k, key, len, len1, len2, modifier_code, modifier_key, modifier_keys, sequence;
487
487
  if (current_modifier_code == null) {
488
488
  current_modifier_code = 0;
489
489
  }
490
- results = [];
491
490
  for (i = 0, len = keys.length; i < len; i++) {
492
491
  sequence = keys[i];
493
- key = sequence.key != null ? this.currentPage.keyCode(sequence.key) || sequence.key : sequence;
492
+ if (sequence.key != null) {
493
+ if (!(key = this.currentPage.keyCode(sequence.key))) {
494
+ this.current_command.sendError(new Poltergeist.KeyError("Unknown key: " + sequence.key));
495
+ return;
496
+ }
497
+ } else if (sequence.keys != null) {
498
+ key = sequence.keys;
499
+ } else {
500
+ key = sequence;
501
+ }
494
502
  if (sequence.modifier != null) {
495
503
  modifier_keys = this.currentPage.keyModifierKeys(sequence.modifier);
496
504
  modifier_code = this.currentPage.keyModifierCode(sequence.modifier) | current_modifier_code;
@@ -499,20 +507,15 @@ Poltergeist.Browser = (function() {
499
507
  this.currentPage.sendEvent('keydown', modifier_key);
500
508
  }
501
509
  this._send_keys_with_modifiers([].concat(key), modifier_code);
502
- results.push((function() {
503
- var k, len2, results1;
504
- results1 = [];
505
- for (k = 0, len2 = modifier_keys.length; k < len2; k++) {
506
- modifier_key = modifier_keys[k];
507
- results1.push(this.currentPage.sendEvent('keyup', modifier_key));
508
- }
509
- return results1;
510
- }).call(this));
510
+ for (k = 0, len2 = modifier_keys.length; k < len2; k++) {
511
+ modifier_key = modifier_keys[k];
512
+ this.currentPage.sendEvent('keyup', modifier_key);
513
+ }
511
514
  } else {
512
- results.push(this.currentPage.sendEvent('keypress', key, null, null, current_modifier_code));
515
+ this.currentPage.sendEvent('keypress', key, null, null, current_modifier_code);
513
516
  }
514
517
  }
515
- return results;
518
+ return true;
516
519
  };
517
520
 
518
521
  Browser.prototype.render_base64 = function(format, arg1) {
@@ -693,30 +696,22 @@ Poltergeist.Browser = (function() {
693
696
  };
694
697
 
695
698
  Browser.prototype.go_back = function() {
696
- var command;
697
- command = this.current_command;
698
699
  if (this.currentPage.canGoBack) {
699
- this.currentPage.state = 'loading';
700
+ this.currentPage.state = 'wait_for_loading';
700
701
  this.currentPage.goBack();
701
- return this.currentPage.waitState('default', function() {
702
- return command.sendResponse(true);
703
- });
702
+ return this._waitForHistoryChange();
704
703
  } else {
705
- return command.sendResponse(false);
704
+ return this.current_command.sendResponse(false);
706
705
  }
707
706
  };
708
707
 
709
708
  Browser.prototype.go_forward = function() {
710
- var command;
711
- command = this.current_command;
712
709
  if (this.currentPage.canGoForward) {
713
- this.currentPage.state = 'loading';
710
+ this.currentPage.state = 'wait_for_loading';
714
711
  this.currentPage.goForward();
715
- return this.currentPage.waitState('default', function() {
716
- return command.sendResponse(true);
717
- });
712
+ return this._waitForHistoryChange();
718
713
  } else {
719
- return command.sendResponse(false);
714
+ return this.current_command.sendResponse(false);
720
715
  }
721
716
  };
722
717
 
@@ -769,6 +764,23 @@ Poltergeist.Browser = (function() {
769
764
  return this.current_command.sendResponse(true);
770
765
  };
771
766
 
767
+ Browser.prototype._waitForHistoryChange = function() {
768
+ var command;
769
+ command = this.current_command;
770
+ return this.currentPage.waitState(['loading', 'default'], function(cur_state) {
771
+ if (cur_state === 'loading') {
772
+ return this.waitState('default', function() {
773
+ return command.sendResponse(true);
774
+ });
775
+ } else {
776
+ return command.sendResponse(true);
777
+ }
778
+ }, 0.5, function() {
779
+ this.state = 'default';
780
+ return command.sendResponse(true);
781
+ });
782
+ };
783
+
772
784
  Browser.prototype._wildcardToRegexp = function(wildcard) {
773
785
  wildcard = wildcard.replace(/[\-\[\]\/\{\}\(\)\+\.\\\^\$\|]/g, "\\$&");
774
786
  wildcard = wildcard.replace(/\*/g, ".*");
@@ -9,23 +9,23 @@ Poltergeist.Cmd = (function() {
9
9
 
10
10
  Cmd.prototype.sendResponse = function(response) {
11
11
  var errors;
12
- errors = this.browser.currentPage.errors;
13
- this.browser.currentPage.clearErrors();
14
- if (errors.length > 0 && this.browser.js_errors) {
15
- return this.sendError(new Poltergeist.JavascriptError(errors));
16
- } else {
17
- if (!this._response_sent) {
12
+ if (!this._response_sent) {
13
+ errors = this.browser.currentPage.errors;
14
+ this.browser.currentPage.clearErrors();
15
+ if (errors.length > 0 && this.browser.js_errors) {
16
+ return this.sendError(new Poltergeist.JavascriptError(errors));
17
+ } else {
18
18
  this.owner.sendResponse(this.id, response);
19
+ return this._response_sent = true;
19
20
  }
20
- return this._response_sent = true;
21
21
  }
22
22
  };
23
23
 
24
24
  Cmd.prototype.sendError = function(errors) {
25
25
  if (!this._response_sent) {
26
26
  this.owner.sendError(this.id, errors);
27
+ return this._response_sent = true;
27
28
  }
28
- return this._response_sent = true;
29
29
  };
30
30
 
31
31
  Cmd.prototype.run = function(browser) {
@@ -1,11 +1,12 @@
1
1
  var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
2
2
 
3
3
  Poltergeist.Connection = (function() {
4
- function Connection(owner, port) {
4
+ function Connection(owner, port, host) {
5
5
  this.owner = owner;
6
6
  this.port = port;
7
+ this.host = host != null ? host : "127.0.0.1";
7
8
  this.commandReceived = bind(this.commandReceived, this);
8
- this.socket = new WebSocket("ws://127.0.0.1:" + this.port + "/");
9
+ this.socket = new WebSocket("ws://" + this.host + ":" + this.port + "/");
9
10
  this.socket.onmessage = this.commandReceived;
10
11
  this.socket.onclose = function() {
11
12
  return phantom.exit();
@@ -3,9 +3,9 @@ var Poltergeist, system,
3
3
  hasProp = {}.hasOwnProperty;
4
4
 
5
5
  Poltergeist = (function() {
6
- function Poltergeist(port, width, height) {
6
+ function Poltergeist(port, width, height, host) {
7
7
  this.browser = new Poltergeist.Browser(width, height);
8
- this.connection = new Poltergeist.Connection(this, port);
8
+ this.connection = new Poltergeist.Connection(this, port, host);
9
9
  phantom.onError = (function(_this) {
10
10
  return function(message, stack) {
11
11
  return _this.onError(message, stack);
@@ -127,6 +127,23 @@ Poltergeist.MouseEventFailed = (function(superClass) {
127
127
 
128
128
  })(Poltergeist.Error);
129
129
 
130
+ Poltergeist.KeyError = (function(superClass) {
131
+ extend(KeyError, superClass);
132
+
133
+ function KeyError(message1) {
134
+ this.message = message1;
135
+ }
136
+
137
+ KeyError.prototype.name = "Poltergeist.KeyError";
138
+
139
+ KeyError.prototype.args = function() {
140
+ return [this.message];
141
+ };
142
+
143
+ return KeyError;
144
+
145
+ })(Poltergeist.Error);
146
+
130
147
  Poltergeist.JavascriptError = (function(superClass) {
131
148
  extend(JavascriptError, superClass);
132
149
 
@@ -226,4 +243,4 @@ phantom.injectJs(phantom.libraryPath + "/browser.js");
226
243
 
227
244
  system = require('system');
228
245
 
229
- new Poltergeist(system.args[1], system.args[2], system.args[3]);
246
+ new Poltergeist(system.args[1], system.args[2], system.args[3], system.args[4]);
@@ -238,41 +238,43 @@ Poltergeist.WebPage = (function() {
238
238
  return results;
239
239
  };
240
240
 
241
- WebPage.prototype._waitState_until = function(state, callback, timeout, timeout_callback) {
242
- if (this.state === state) {
243
- return callback.call(this);
241
+ WebPage.prototype._waitState_until = function(states, callback, timeout, timeout_callback) {
242
+ var ref2;
243
+ if ((ref2 = this.state, indexOf.call(states, ref2) >= 0)) {
244
+ return callback.call(this, this.state);
244
245
  } else {
245
246
  if (new Date().getTime() > timeout) {
246
247
  return timeout_callback.call(this);
247
248
  } else {
248
249
  return setTimeout(((function(_this) {
249
250
  return function() {
250
- return _this._waitState_until(state, callback, timeout, timeout_callback);
251
+ return _this._waitState_until(states, callback, timeout, timeout_callback);
251
252
  };
252
253
  })(this)), 100);
253
254
  }
254
255
  }
255
256
  };
256
257
 
257
- WebPage.prototype.waitState = function(state, callback, max_wait, timeout_callback) {
258
- var timeout;
258
+ WebPage.prototype.waitState = function(states, callback, max_wait, timeout_callback) {
259
+ var ref2, timeout;
259
260
  if (max_wait == null) {
260
261
  max_wait = 0;
261
262
  }
262
- if (this.state === state) {
263
- return callback.call(this);
263
+ states = [].concat(states);
264
+ if (ref2 = this.state, indexOf.call(states, ref2) >= 0) {
265
+ return callback.call(this, this.state);
264
266
  } else {
265
267
  if (max_wait !== 0) {
266
268
  timeout = new Date().getTime() + (max_wait * 1000);
267
269
  return setTimeout(((function(_this) {
268
270
  return function() {
269
- return _this._waitState_until(state, callback, timeout, timeout_callback);
271
+ return _this._waitState_until(states, callback, timeout, timeout_callback);
270
272
  };
271
273
  })(this)), 100);
272
274
  } else {
273
275
  return setTimeout(((function(_this) {
274
276
  return function() {
275
- return _this.waitState(state, callback);
277
+ return _this.waitState(states, callback);
276
278
  };
277
279
  })(this)), 100);
278
280
  }
@@ -1,6 +1,6 @@
1
1
  class Poltergeist.Connection
2
- constructor: (@owner, @port) ->
3
- @socket = new WebSocket "ws://127.0.0.1:#{@port}/"
2
+ constructor: (@owner, @port, @host = "127.0.0.1") ->
3
+ @socket = new WebSocket "ws://#{@host}:#{@port}/"
4
4
  @socket.onmessage = this.commandReceived
5
5
  @socket.onclose = -> phantom.exit()
6
6
 
@@ -1,7 +1,7 @@
1
1
  class Poltergeist
2
- constructor: (port, width, height) ->
2
+ constructor: (port, width, height, host) ->
3
3
  @browser = new Poltergeist.Browser(width, height)
4
- @connection = new Poltergeist.Connection(this, port)
4
+ @connection = new Poltergeist.Connection(this, port, host)
5
5
 
6
6
  phantom.onError = (message, stack) => @onError(message, stack)
7
7
 
@@ -50,6 +50,11 @@ class Poltergeist.MouseEventFailed extends Poltergeist.Error
50
50
  name: "Poltergeist.MouseEventFailed"
51
51
  args: -> [@eventName, @selector, @position]
52
52
 
53
+ class Poltergeist.KeyError extends Poltergeist.Error
54
+ constructor: (@message) ->
55
+ name: "Poltergeist.KeyError"
56
+ args: -> [@message]
57
+
53
58
  class Poltergeist.JavascriptError extends Poltergeist.Error
54
59
  constructor: (@errors) ->
55
60
  name: "Poltergeist.JavascriptError"
@@ -83,4 +88,4 @@ phantom.injectJs("#{phantom.libraryPath}/cmd.js")
83
88
  phantom.injectJs("#{phantom.libraryPath}/browser.js")
84
89
 
85
90
  system = require 'system'
86
- new Poltergeist(system.args[1], system.args[2], system.args[3])
91
+ new Poltergeist(system.args[1], system.args[2], system.args[3], system.args[4])
@@ -162,25 +162,26 @@ class Poltergeist.WebPage
162
162
  name = name.charAt(0).toUpperCase() + name.substring(1)
163
163
  this.keyCode(name)
164
164
 
165
- _waitState_until: (state, callback, timeout, timeout_callback) ->
166
- if (@state == state)
167
- callback.call(this)
165
+ _waitState_until: (states, callback, timeout, timeout_callback) ->
166
+ if (@state in states)
167
+ callback.call(this, @state)
168
168
  else
169
169
  if new Date().getTime() > timeout
170
170
  timeout_callback.call(this)
171
171
  else
172
- setTimeout (=> @_waitState_until(state, callback, timeout, timeout_callback)), 100
172
+ setTimeout (=> @_waitState_until(states, callback, timeout, timeout_callback)), 100
173
173
 
174
- waitState: (state, callback, max_wait=0, timeout_callback) ->
174
+ waitState: (states, callback, max_wait=0, timeout_callback) ->
175
175
  # callback and timeout_callback will be called with this == the current page
176
- if @state == state
177
- callback.call(this)
176
+ states = [].concat(states)
177
+ if @state in states
178
+ callback.call(this, @state)
178
179
  else
179
180
  if max_wait != 0
180
181
  timeout = new Date().getTime() + (max_wait*1000)
181
- setTimeout (=> @_waitState_until(state, callback, timeout, timeout_callback)), 100
182
+ setTimeout (=> @_waitState_until(states, callback, timeout, timeout_callback)), 100
182
183
  else
183
- setTimeout (=> @waitState(state, callback)), 100
184
+ setTimeout (=> @waitState(states, callback)), 100
184
185
 
185
186
  setHttpAuth: (user, password) ->
186
187
  this.native().settings.userName = user
@@ -37,7 +37,7 @@ module Capybara::Poltergeist
37
37
  end
38
38
 
39
39
  def server
40
- @server ||= Server.new(options[:port], options.fetch(:timeout) { DEFAULT_TIMEOUT })
40
+ @server ||= Server.new(options[:port], options.fetch(:timeout) { DEFAULT_TIMEOUT }, options[:host])
41
41
  end
42
42
 
43
43
  def client
@@ -272,7 +272,7 @@ module Capybara::Poltergeist
272
272
  if @started
273
273
  URI.parse(browser.current_url).host
274
274
  else
275
- URI.parse(Capybara.app_host || '').host || "127.0.0.1"
275
+ URI.parse(default_cookie_host).host || "127.0.0.1"
276
276
  end
277
277
  end
278
278
 
@@ -394,7 +394,7 @@ module Capybara::Poltergeist
394
394
 
395
395
  def find_modal(options)
396
396
  start_time = Time.now
397
- timeout_sec = options[:wait] || begin Capybara.default_max_wait_time rescue Capybara.default_wait_time end
397
+ timeout_sec = options.fetch(:wait) { session_wait_time }
398
398
  expect_text = options[:text]
399
399
  expect_regexp = expect_text.is_a?(Regexp) ? expect_text : Regexp.escape(expect_text.to_s)
400
400
  not_found_msg = 'Unable to find modal dialog'
@@ -411,6 +411,22 @@ module Capybara::Poltergeist
411
411
  modal_text
412
412
  end
413
413
 
414
+ def session_wait_time
415
+ if respond_to?(:session_options)
416
+ session_options.default_max_wait_time
417
+ else
418
+ begin Capybara.default_max_wait_time rescue Capybara.default_wait_time end
419
+ end
420
+ end
421
+
422
+ def default_cookie_host
423
+ if respond_to?(:session_options)
424
+ session_options.app_host
425
+ else
426
+ Capybara.app_host
427
+ end || ''
428
+ end
429
+
414
430
  def unwrap_script_result(arg)
415
431
  case arg
416
432
  when Array
@@ -154,6 +154,12 @@ module Capybara
154
154
  end
155
155
  end
156
156
 
157
+ class KeyError < ::ArgumentError
158
+ def initialize(response)
159
+ super(response["args"].first)
160
+ end
161
+ end
162
+
157
163
  class TimeoutError < Error
158
164
  def initialize(message)
159
165
  @message = message
@@ -1,10 +1,11 @@
1
1
  module Capybara::Poltergeist
2
2
  class Server
3
- attr_reader :socket, :fixed_port, :timeout
3
+ attr_reader :socket, :fixed_port, :timeout, :custom_host
4
4
 
5
- def initialize(fixed_port = nil, timeout = nil)
5
+ def initialize(fixed_port = nil, timeout = nil, custom_host = nil)
6
6
  @fixed_port = fixed_port
7
7
  @timeout = timeout
8
+ @custom_host = custom_host
8
9
  start
9
10
  end
10
11
 
@@ -12,12 +13,16 @@ module Capybara::Poltergeist
12
13
  @socket.port
13
14
  end
14
15
 
16
+ def host
17
+ @socket.host
18
+ end
19
+
15
20
  def timeout=(sec)
16
21
  @timeout = @socket.timeout = sec
17
22
  end
18
23
 
19
24
  def start
20
- @socket = WebSocketServer.new(fixed_port, timeout)
25
+ @socket = WebSocketServer.new(fixed_port, timeout, custom_host)
21
26
  end
22
27
 
23
28
  def stop
@@ -1,9 +1,13 @@
1
- module Capybara
2
- module Poltergeist
3
- class << self
4
- def windows?
5
- RbConfig::CONFIG["host_os"] =~ /mingw|mswin|cygwin/
6
- end
7
- end
8
- end
9
- end
1
+ module Capybara
2
+ module Poltergeist
3
+ class << self
4
+ def windows?
5
+ RbConfig::CONFIG["host_os"] =~ /mingw|mswin|cygwin/
6
+ end
7
+
8
+ def mri?
9
+ defined?(RUBY_ENGINE) && RUBY_ENGINE == "ruby"
10
+ end
11
+ end
12
+ end
13
+ end
@@ -1,5 +1,5 @@
1
1
  module Capybara
2
2
  module Poltergeist
3
- VERSION = "1.14.0"
3
+ VERSION = "1.15.0"
4
4
  end
5
5
  end
@@ -18,21 +18,22 @@ module Capybara::Poltergeist
18
18
 
19
19
  HOST = '127.0.0.1'
20
20
 
21
- attr_reader :port, :driver, :socket, :server
21
+ attr_reader :port, :driver, :socket, :server, :host
22
22
  attr_accessor :timeout
23
23
 
24
- def initialize(port = nil, timeout = nil)
24
+ def initialize(port = nil, timeout = nil, custom_host = nil)
25
25
  @timeout = timeout
26
- @server = start_server(port)
26
+ @server = start_server(port, custom_host)
27
27
  @receive_mutex = Mutex.new
28
28
  end
29
29
 
30
- def start_server(port)
30
+ def start_server(port, custom_host)
31
31
  time = Time.now
32
32
 
33
33
  begin
34
- TCPServer.open(HOST, port || 0).tap do |server|
34
+ TCPServer.open(custom_host || HOST, port || 0).tap do |server|
35
35
  @port = server.addr[1]
36
+ @host = server.addr[2]
36
37
  end
37
38
  rescue Errno::EADDRINUSE
38
39
  if (Time.now - time) < BIND_TIMEOUT
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: poltergeist
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.14.0
4
+ version: 1.15.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-03-16 00:00:00.000000000 Z
11
+ date: 2017-05-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: capybara
@@ -199,7 +199,7 @@ dependencies:
199
199
  - !ruby/object:Gem::Version
200
200
  version: 3.0.6
201
201
  - !ruby/object:Gem::Dependency
202
- name: erubis
202
+ name: erubi
203
203
  requirement: !ruby/object:Gem::Requirement
204
204
  requirements:
205
205
  - - ">="
@@ -273,7 +273,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
273
273
  version: '0'
274
274
  requirements: []
275
275
  rubyforge_project:
276
- rubygems_version: 2.5.2
276
+ rubygems_version: 2.6.11
277
277
  signing_key:
278
278
  specification_version: 4
279
279
  summary: PhantomJS driver for Capybara