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 +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
|