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 +4 -4
- data/README.md +6 -5
- data/lib/capybara/poltergeist/browser.rb +15 -14
- data/lib/capybara/poltergeist/client.rb +16 -8
- data/lib/capybara/poltergeist/client/browser.coffee +31 -13
- data/lib/capybara/poltergeist/client/cmd.coffee +11 -9
- data/lib/capybara/poltergeist/client/compiled/browser.js +41 -29
- data/lib/capybara/poltergeist/client/compiled/cmd.js +8 -8
- data/lib/capybara/poltergeist/client/compiled/connection.js +3 -2
- data/lib/capybara/poltergeist/client/compiled/main.js +20 -3
- data/lib/capybara/poltergeist/client/compiled/web_page.js +12 -10
- data/lib/capybara/poltergeist/client/connection.coffee +2 -2
- data/lib/capybara/poltergeist/client/main.coffee +8 -3
- data/lib/capybara/poltergeist/client/web_page.coffee +10 -9
- data/lib/capybara/poltergeist/driver.rb +19 -3
- data/lib/capybara/poltergeist/errors.rb +6 -0
- data/lib/capybara/poltergeist/server.rb +8 -3
- data/lib/capybara/poltergeist/utility.rb +13 -9
- data/lib/capybara/poltergeist/version.rb +1 -1
- data/lib/capybara/poltergeist/web_socket_server.rb +6 -5
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 83bb04d3f05ad64c5a1b5b213d89acce146434b3
|
4
|
+
data.tar.gz: 6b566336fff00fff1f62fe1161e55beb45e713ce
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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.
|
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
|
-
|
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
|
-
|
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 |
|
446
|
-
case
|
446
|
+
keys.map do |key_desc|
|
447
|
+
case key_desc
|
447
448
|
when Array
|
448
|
-
# [:Shift, "s"] => { modifier: "shift",
|
449
|
-
# [:Shift, "string"] => { modifier: "shift",
|
450
|
-
# [:Ctrl, :Left] => { modifier: "ctrl", key:
|
451
|
-
# [:Ctrl, :Shift, :Left] => { modifier: "ctrl,shift", key:
|
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 =
|
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
|
-
|
465
|
-
{ modifier: modifiers,
|
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(
|
469
|
+
key = KEY_ALIASES.fetch(key_desc, key_desc)
|
469
470
|
if match = key.to_s.match(/numpad(.)/)
|
470
|
-
res = {
|
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
|
-
|
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
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
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
|
-
|
360
|
-
|
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 = '
|
509
|
+
@currentPage.state = 'wait_for_loading'
|
504
510
|
@currentPage.goBack()
|
505
|
-
@
|
506
|
-
command.sendResponse(true)
|
511
|
+
@_waitForHistoryChange()
|
507
512
|
else
|
508
|
-
|
513
|
+
@current_command.sendResponse(false)
|
509
514
|
|
510
515
|
go_forward: ->
|
511
|
-
command = @current_command
|
512
516
|
if @currentPage.canGoForward
|
513
|
-
@currentPage.state = '
|
517
|
+
@currentPage.state = 'wait_for_loading'
|
514
518
|
@currentPage.goForward()
|
515
|
-
@
|
516
|
-
command.sendResponse(true)
|
519
|
+
@_waitForHistoryChange()
|
517
520
|
else
|
518
|
-
|
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
|
-
|
6
|
-
|
5
|
+
if !@_response_sent
|
6
|
+
errors = @browser.currentPage.errors
|
7
|
+
@browser.currentPage.clearErrors()
|
7
8
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
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
|
-
|
16
|
-
|
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(',')) :
|
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,
|
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
|
-
|
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
|
-
|
503
|
-
|
504
|
-
|
505
|
-
|
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
|
-
|
515
|
+
this.currentPage.sendEvent('keypress', key, null, null, current_modifier_code);
|
513
516
|
}
|
514
517
|
}
|
515
|
-
return
|
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 = '
|
700
|
+
this.currentPage.state = 'wait_for_loading';
|
700
701
|
this.currentPage.goBack();
|
701
|
-
return this.
|
702
|
-
return command.sendResponse(true);
|
703
|
-
});
|
702
|
+
return this._waitForHistoryChange();
|
704
703
|
} else {
|
705
|
-
return
|
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 = '
|
710
|
+
this.currentPage.state = 'wait_for_loading';
|
714
711
|
this.currentPage.goForward();
|
715
|
-
return this.
|
716
|
-
return command.sendResponse(true);
|
717
|
-
});
|
712
|
+
return this._waitForHistoryChange();
|
718
713
|
} else {
|
719
|
-
return
|
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
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
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://
|
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(
|
242
|
-
|
243
|
-
|
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(
|
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(
|
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
|
-
|
263
|
-
|
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(
|
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(
|
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
|
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: (
|
166
|
-
if (@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(
|
172
|
+
setTimeout (=> @_waitState_until(states, callback, timeout, timeout_callback)), 100
|
173
173
|
|
174
|
-
waitState: (
|
174
|
+
waitState: (states, callback, max_wait=0, timeout_callback) ->
|
175
175
|
# callback and timeout_callback will be called with this == the current page
|
176
|
-
|
177
|
-
|
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(
|
182
|
+
setTimeout (=> @_waitState_until(states, callback, timeout, timeout_callback)), 100
|
182
183
|
else
|
183
|
-
setTimeout (=> @waitState(
|
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(
|
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
|
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
|
@@ -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
|
-
|
8
|
-
|
9
|
-
|
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
|
@@ -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.
|
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-
|
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:
|
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.
|
276
|
+
rubygems_version: 2.6.11
|
277
277
|
signing_key:
|
278
278
|
specification_version: 4
|
279
279
|
summary: PhantomJS driver for Capybara
|