poltergeist 1.14.0 → 1.15.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
  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