poltergeist 0.3.0 → 0.4.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.
- data/README.md +66 -35
- data/lib/capybara/poltergeist/browser.rb +1 -1
- data/lib/capybara/poltergeist/client.rb +24 -6
- data/lib/capybara/poltergeist/client/agent.coffee +5 -12
- data/lib/capybara/poltergeist/client/browser.coffee +15 -14
- data/lib/capybara/poltergeist/client/compiled/agent.js +12 -16
- data/lib/capybara/poltergeist/client/compiled/browser.js +13 -13
- data/lib/capybara/poltergeist/client/compiled/main.js +0 -4
- data/lib/capybara/poltergeist/client/compiled/node.js +20 -25
- data/lib/capybara/poltergeist/client/compiled/web_page.js +1 -2
- data/lib/capybara/poltergeist/client/main.coffee +0 -4
- data/lib/capybara/poltergeist/client/node.coffee +24 -18
- data/lib/capybara/poltergeist/client/web_page.coffee +0 -1
- data/lib/capybara/poltergeist/errors.rb +12 -0
- data/lib/capybara/poltergeist/version.rb +1 -1
- metadata +22 -22
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# Poltergeist - A PhantomJS driver for Capybara #
|
2
2
|
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.4.0
|
4
4
|
|
5
5
|
[](http://travis-ci.org/jonleighton/poltergeist)
|
6
6
|
|
@@ -12,8 +12,32 @@ provided by [PhantomJS](http://www.phantomjs.org/).
|
|
12
12
|
|
13
13
|
Add `poltergeist` to your Gemfile, and add in your test setup add:
|
14
14
|
|
15
|
-
|
16
|
-
|
15
|
+
``` ruby
|
16
|
+
require 'capybara/poltergeist'
|
17
|
+
Capybara.javascript_driver = :poltergeist
|
18
|
+
```
|
19
|
+
|
20
|
+
## Important note about Rack versions < 1.3.0 ##
|
21
|
+
|
22
|
+
Prior to version 1.3.0, the Rack handlers for Mongrel and Thin wrap your
|
23
|
+
app in the `Rack::Chunked` middleware so that it uses
|
24
|
+
`Transfer-Encoding: chunked`
|
25
|
+
([commit](https://github.com/rack/rack/commit/50cdd0bf000a9ffb3eb3760fda2ff3e1ad18f3a7)).
|
26
|
+
This has been observed to cause problems,
|
27
|
+
probably due to race conditions in Qt's HTTP handling code, so you are
|
28
|
+
recommended to avoid this by specifying your own server setup for
|
29
|
+
Capybara:
|
30
|
+
|
31
|
+
``` ruby
|
32
|
+
Capybara.server do |app, port|
|
33
|
+
require 'rack/handler/thin'
|
34
|
+
Thin::Logging.silent = true
|
35
|
+
Thin::Server.new('0.0.0.0', port, app).start
|
36
|
+
end
|
37
|
+
```
|
38
|
+
|
39
|
+
If you're using Rails 3.0, this affects you. If you're using Rails 3.1+,
|
40
|
+
this doesn't affect you.
|
17
41
|
|
18
42
|
## Installing PhantomJS ##
|
19
43
|
|
@@ -32,9 +56,7 @@ the relationship between `bin/phantomjs` and `lib/`. This is because the
|
|
32
56
|
`bin/phantomjs` binary looks in `../lib/` for its library files. So the
|
33
57
|
best thing to do is to link (rather than copy) it into your `PATH`:
|
34
58
|
|
35
|
-
|
36
|
-
ln -s /path/to/phantomjs/bin/phantomjs /usr/local/bin/phantomjs
|
37
|
-
```
|
59
|
+
ln -s /path/to/phantomjs/bin/phantomjs /usr/local/bin/phantomjs
|
38
60
|
|
39
61
|
### Compiling PhantomJS ###
|
40
62
|
|
@@ -53,7 +75,8 @@ you should copy (or link) the `bin/phantomjs` binary into your `PATH`.
|
|
53
75
|
|
54
76
|
## Running on a CI ##
|
55
77
|
|
56
|
-
Currently PhantomJS is not 'truly headless'
|
78
|
+
Currently PhantomJS is not yet 'truly headless' (but that's planned for the future),
|
79
|
+
so to run it on a continuous integration
|
57
80
|
server you will need to install [Xvfb](http://en.wikipedia.org/wiki/Xvfb).
|
58
81
|
|
59
82
|
### On any generic server ###
|
@@ -98,16 +121,18 @@ size to 1024x768 by default, but you can set this yourself with `page.driver.res
|
|
98
121
|
You can customize the way that Capybara sets up Poltegeist via the following code in your
|
99
122
|
test setup:
|
100
123
|
|
101
|
-
|
102
|
-
|
103
|
-
|
124
|
+
``` ruby
|
125
|
+
Capybara.register_driver :poltergeist do |app|
|
126
|
+
Capybara::Poltergeist::Driver.new(app, options)
|
127
|
+
end
|
128
|
+
```
|
104
129
|
|
105
130
|
`options` is a hash of options. The following options are supported:
|
106
131
|
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
132
|
+
* `:phantomjs` (String) - A custom path to the phantomjs executable
|
133
|
+
* `:debug` (Boolean) - When true, debug output is logged to `STDERR`
|
134
|
+
* `:logger` (Object responding to `puts`) - When present, debug output is written to this object
|
135
|
+
* `:timeout` (Numeric) - The number of seconds we'll wait for a response
|
111
136
|
when communicating with PhantomJS. `nil` means wait forever. Default
|
112
137
|
is 30.
|
113
138
|
|
@@ -117,22 +142,19 @@ Please file bug reports on Github and include example code to reproduce the prob
|
|
117
142
|
possible. (Tests are even better.) Please also provide the output with
|
118
143
|
`:debug` turned on, and screenshots if you think it's relevant.
|
119
144
|
|
120
|
-
##
|
145
|
+
## Differences from [capybara-webkit](https://github.com/thoughtbot/capybara-webkit) ##
|
121
146
|
|
122
|
-
|
147
|
+
Poltergeist is similar to capybara-webkit, but here are the key
|
148
|
+
differences:
|
123
149
|
|
124
|
-
|
125
|
-
|
126
|
-
|
150
|
+
* It's more hackable. Poltergeist is written in Ruby + CoffeeScript.
|
151
|
+
We only have to worry about C++ when dealing with issues in
|
152
|
+
PhantomJS itself. In contrast, the majority of capybara-webkit is
|
153
|
+
written in C++.
|
127
154
|
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
browser.
|
132
|
-
|
133
|
-
I also find it more pleasant to hack in CoffeeScript than C++,
|
134
|
-
particularly as my C++ experience only goes as far as trying to make
|
135
|
-
PhantomJS/Qt/WebKit work with Poltergeist :)
|
155
|
+
* We're able to tap into the PhantomJS community. When PhantomJS
|
156
|
+
improves, Poltergeist improves. User's don't have to install Qt
|
157
|
+
because self-contained PhantomJS binary packages are available.
|
136
158
|
|
137
159
|
## Hacking ##
|
138
160
|
|
@@ -142,11 +164,6 @@ anyone who does a few good pull requests.
|
|
142
164
|
To get setup, run `bundle install`. You can run the full test suite with
|
143
165
|
`rspec spec/` or `rake`.
|
144
166
|
|
145
|
-
I previously set up the repository on [Travis CI](http://travis-ci.org/)
|
146
|
-
but unfortunately given they need a custom-built Qt+PhantomJS in order
|
147
|
-
to pass, it can't be used for now. When static Linux PhantomJS builds
|
148
|
-
are working this can be revisited.
|
149
|
-
|
150
167
|
While PhantomJS is capable of compiling and running CoffeeScript code
|
151
168
|
directly, I prefer to compile the code myself and distribute that (it
|
152
169
|
makes debugging easier). Running `rake autocompile` will watch the
|
@@ -155,7 +172,21 @@ makes debugging easier). Running `rake autocompile` will watch the
|
|
155
172
|
|
156
173
|
## Changes ##
|
157
174
|
|
158
|
-
### 0.
|
175
|
+
### 0.4.0 ###
|
176
|
+
|
177
|
+
* Element click position is now calculated using the native
|
178
|
+
`getBoundingClientRect()` method, which will be faster and less
|
179
|
+
buggy.
|
180
|
+
|
181
|
+
* Handle `window.confirm()`. Always returns true, which is the same
|
182
|
+
as capybara-webkit. [Issue #10]
|
183
|
+
|
184
|
+
* Handle `window.prompt()`. Returns the default value, if present, or
|
185
|
+
null.
|
186
|
+
|
187
|
+
* Fix bug with page Javascript page loading causing problems. [Issue #19]
|
188
|
+
|
189
|
+
### 0.3.0 ###
|
159
190
|
|
160
191
|
* There was a bad bug to do with clicking elements in a page where the
|
161
192
|
page is smaller than the window. The incorrect position would be
|
@@ -175,11 +206,11 @@ makes debugging easier). Running `rake autocompile` will watch the
|
|
175
206
|
* Added the `:timeout` option to configure the timeout when talking to
|
176
207
|
PhantomJS.
|
177
208
|
|
178
|
-
### 0.2 ###
|
209
|
+
### 0.2.0 ###
|
179
210
|
|
180
211
|
* First version considered 'ready', hopefully fewer problems.
|
181
212
|
|
182
|
-
### 0.1 ###
|
213
|
+
### 0.1.0 ###
|
183
214
|
|
184
215
|
* First version, various problems.
|
185
216
|
|
@@ -9,7 +9,7 @@ module Capybara::Poltergeist
|
|
9
9
|
def initialize(options = {})
|
10
10
|
@options = options
|
11
11
|
@server = Server.new(options.fetch(:timeout, DEFAULT_TIMEOUT))
|
12
|
-
@client = Client.
|
12
|
+
@client = Client.start(server.port, options[:phantomjs])
|
13
13
|
end
|
14
14
|
|
15
15
|
def timeout
|
@@ -2,29 +2,47 @@ require 'sfl'
|
|
2
2
|
|
3
3
|
module Capybara::Poltergeist
|
4
4
|
class Client
|
5
|
-
|
5
|
+
PHANTOMJS_SCRIPT = File.expand_path('../client/compiled/main.js', __FILE__)
|
6
|
+
PHANTOMJS_VERSION = "1.4.1"
|
6
7
|
|
7
|
-
attr_reader :
|
8
|
+
attr_reader :pid, :port, :path
|
9
|
+
|
10
|
+
def self.start(*args)
|
11
|
+
client = new(*args)
|
12
|
+
client.start
|
13
|
+
client
|
14
|
+
end
|
8
15
|
|
9
16
|
def initialize(port, path = nil)
|
10
17
|
@port = port
|
11
18
|
@path = path || 'phantomjs'
|
12
|
-
|
13
|
-
start
|
14
19
|
at_exit { stop }
|
15
20
|
end
|
16
21
|
|
17
22
|
def start
|
18
|
-
|
23
|
+
check_phantomjs_version
|
24
|
+
@pid = Kernel.spawn("#{path} #{PHANTOMJS_SCRIPT} #{port}")
|
19
25
|
end
|
20
26
|
|
21
27
|
def stop
|
22
|
-
Process.kill('TERM', pid)
|
28
|
+
Process.kill('TERM', pid) if pid
|
23
29
|
end
|
24
30
|
|
25
31
|
def restart
|
26
32
|
stop
|
27
33
|
start
|
28
34
|
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def check_phantomjs_version
|
39
|
+
return if @phantomjs_version_checked
|
40
|
+
|
41
|
+
version = `#{path} --version`.chomp
|
42
|
+
if version < PHANTOMJS_VERSION
|
43
|
+
raise PhantomJSTooOld.new(version)
|
44
|
+
end
|
45
|
+
@phantomjs_version_checked = true
|
46
|
+
end
|
29
47
|
end
|
30
48
|
end
|
@@ -151,18 +151,8 @@ class PoltergeistAgent.Node
|
|
151
151
|
true
|
152
152
|
|
153
153
|
position: ->
|
154
|
-
|
155
|
-
|
156
|
-
y = element.offsetTop
|
157
|
-
|
158
|
-
if element.offsetParent
|
159
|
-
parentPos = pos(element.offsetParent)
|
160
|
-
|
161
|
-
x += parentPos.x
|
162
|
-
y += parentPos.y
|
163
|
-
|
164
|
-
{ x: x, y: y }
|
165
|
-
pos @element
|
154
|
+
rect = @element.getBoundingClientRect()
|
155
|
+
{ top: rect.top, left: rect.left }
|
166
156
|
|
167
157
|
trigger: (name) ->
|
168
158
|
if Node.EVENTS.MOUSE.indexOf(name) != -1
|
@@ -185,3 +175,6 @@ document.addEventListener(
|
|
185
175
|
'DOMContentLoaded',
|
186
176
|
-> console.log('__DOMContentLoaded')
|
187
177
|
)
|
178
|
+
|
179
|
+
window.confirm = (message) -> true
|
180
|
+
window.prompt = (message, _default) -> _default or null
|
@@ -1,19 +1,23 @@
|
|
1
1
|
class Poltergeist.Browser
|
2
2
|
constructor: (@owner) ->
|
3
|
-
@
|
3
|
+
@state = 'default'
|
4
4
|
this.resetPage()
|
5
5
|
|
6
6
|
resetPage: ->
|
7
7
|
@page.release() if @page?
|
8
8
|
|
9
9
|
@page = new Poltergeist.WebPage
|
10
|
+
|
11
|
+
@page.onLoadStarted = =>
|
12
|
+
@state = 'loading' if @state == 'clicked'
|
13
|
+
|
10
14
|
@page.onLoadFinished = (status) =>
|
11
|
-
if @
|
15
|
+
if @state == 'loading'
|
12
16
|
@owner.sendResponse(status)
|
13
|
-
@
|
17
|
+
@state = 'default'
|
14
18
|
|
15
19
|
visit: (url) ->
|
16
|
-
@
|
20
|
+
@state = 'loading'
|
17
21
|
@page.open(url)
|
18
22
|
|
19
23
|
current_url: ->
|
@@ -73,7 +77,7 @@ class Poltergeist.Browser
|
|
73
77
|
@owner.sendResponse @page.get(id).isVisible()
|
74
78
|
|
75
79
|
evaluate: (script) ->
|
76
|
-
@owner.sendResponse @page.evaluate("function() { return #{script} }")
|
80
|
+
@owner.sendResponse JSON.parse(@page.evaluate("function() { return JSON.stringify(#{script}) }"))
|
77
81
|
|
78
82
|
execute: (script) ->
|
79
83
|
@page.execute("function() { #{script} }")
|
@@ -88,13 +92,9 @@ class Poltergeist.Browser
|
|
88
92
|
@owner.sendResponse(true)
|
89
93
|
|
90
94
|
click: (id) ->
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
# a response here, because the response will be sent once the page has loaded.
|
95
|
-
@page.onLoadStarted = =>
|
96
|
-
@awaiting_response = true
|
97
|
-
load_detected = true
|
95
|
+
# If the click event triggers onLoadStarted, we will transition to the 'loading'
|
96
|
+
# state and wait for onLoadFinished before sending a response.
|
97
|
+
@state = 'clicked'
|
98
98
|
|
99
99
|
@page.get(id).click()
|
100
100
|
|
@@ -102,8 +102,9 @@ class Poltergeist.Browser
|
|
102
102
|
# callback can (possibly) fire, before we decide whether to send a response.
|
103
103
|
setTimeout(
|
104
104
|
=>
|
105
|
-
@
|
106
|
-
|
105
|
+
if @state == 'clicked'
|
106
|
+
@state = 'default'
|
107
|
+
@owner.sendResponse(true)
|
107
108
|
,
|
108
109
|
10
|
109
110
|
)
|
@@ -177,22 +177,12 @@ PoltergeistAgent.Node = (function() {
|
|
177
177
|
}
|
178
178
|
};
|
179
179
|
Node.prototype.position = function() {
|
180
|
-
var
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
if (element.offsetParent) {
|
186
|
-
parentPos = pos(element.offsetParent);
|
187
|
-
x += parentPos.x;
|
188
|
-
y += parentPos.y;
|
189
|
-
}
|
190
|
-
return {
|
191
|
-
x: x,
|
192
|
-
y: y
|
193
|
-
};
|
180
|
+
var rect;
|
181
|
+
rect = this.element.getBoundingClientRect();
|
182
|
+
return {
|
183
|
+
top: rect.top,
|
184
|
+
left: rect.left
|
194
185
|
};
|
195
|
-
return pos(this.element);
|
196
186
|
};
|
197
187
|
Node.prototype.trigger = function(name) {
|
198
188
|
var event;
|
@@ -212,4 +202,10 @@ PoltergeistAgent.Node = (function() {
|
|
212
202
|
window.__poltergeist = new PoltergeistAgent;
|
213
203
|
document.addEventListener('DOMContentLoaded', function() {
|
214
204
|
return console.log('__DOMContentLoaded');
|
215
|
-
});
|
205
|
+
});
|
206
|
+
window.confirm = function(message) {
|
207
|
+
return true;
|
208
|
+
};
|
209
|
+
window.prompt = function(message, _default) {
|
210
|
+
return _default || null;
|
211
|
+
};
|
@@ -2,7 +2,7 @@ var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments)
|
|
2
2
|
Poltergeist.Browser = (function() {
|
3
3
|
function Browser(owner) {
|
4
4
|
this.owner = owner;
|
5
|
-
this.
|
5
|
+
this.state = 'default';
|
6
6
|
this.resetPage();
|
7
7
|
}
|
8
8
|
Browser.prototype.resetPage = function() {
|
@@ -10,15 +10,20 @@ Poltergeist.Browser = (function() {
|
|
10
10
|
this.page.release();
|
11
11
|
}
|
12
12
|
this.page = new Poltergeist.WebPage;
|
13
|
+
this.page.onLoadStarted = __bind(function() {
|
14
|
+
if (this.state === 'clicked') {
|
15
|
+
return this.state = 'loading';
|
16
|
+
}
|
17
|
+
}, this);
|
13
18
|
return this.page.onLoadFinished = __bind(function(status) {
|
14
|
-
if (this.
|
19
|
+
if (this.state === 'loading') {
|
15
20
|
this.owner.sendResponse(status);
|
16
|
-
return this.
|
21
|
+
return this.state = 'default';
|
17
22
|
}
|
18
23
|
}, this);
|
19
24
|
};
|
20
25
|
Browser.prototype.visit = function(url) {
|
21
|
-
this.
|
26
|
+
this.state = 'loading';
|
22
27
|
return this.page.open(url);
|
23
28
|
};
|
24
29
|
Browser.prototype.current_url = function() {
|
@@ -71,7 +76,7 @@ Poltergeist.Browser = (function() {
|
|
71
76
|
return this.owner.sendResponse(this.page.get(id).isVisible());
|
72
77
|
};
|
73
78
|
Browser.prototype.evaluate = function(script) {
|
74
|
-
return this.owner.sendResponse(this.page.evaluate("function() { return " + script + " }"));
|
79
|
+
return this.owner.sendResponse(JSON.parse(this.page.evaluate("function() { return JSON.stringify(" + script + ") }")));
|
75
80
|
};
|
76
81
|
Browser.prototype.execute = function(script) {
|
77
82
|
this.page.execute("function() { " + script + " }");
|
@@ -86,16 +91,11 @@ Poltergeist.Browser = (function() {
|
|
86
91
|
return this.owner.sendResponse(true);
|
87
92
|
};
|
88
93
|
Browser.prototype.click = function(id) {
|
89
|
-
|
90
|
-
load_detected = false;
|
91
|
-
this.page.onLoadStarted = __bind(function() {
|
92
|
-
this.awaiting_response = true;
|
93
|
-
return load_detected = true;
|
94
|
-
}, this);
|
94
|
+
this.state = 'clicked';
|
95
95
|
this.page.get(id).click();
|
96
96
|
return setTimeout(__bind(function() {
|
97
|
-
this.
|
98
|
-
|
97
|
+
if (this.state === 'clicked') {
|
98
|
+
this.state = 'default';
|
99
99
|
return this.owner.sendResponse(true);
|
100
100
|
}
|
101
101
|
}, this), 10);
|
@@ -1,8 +1,4 @@
|
|
1
1
|
var Poltergeist;
|
2
|
-
if (("" + phantom.version.major + "." + phantom.version.minor + "." + phantom.version.patch) < "1.4.1") {
|
3
|
-
console.log("Poltergeist requires a PhantomJS version of at least 1.4.1");
|
4
|
-
phantom.exit(1);
|
5
|
-
}
|
6
2
|
Poltergeist = (function() {
|
7
3
|
function Poltergeist(port) {
|
8
4
|
this.browser = new Poltergeist.Browser(this);
|
@@ -29,7 +29,7 @@ Poltergeist.Node = (function() {
|
|
29
29
|
_fn(name);
|
30
30
|
}
|
31
31
|
Node.prototype.scrollIntoView = function() {
|
32
|
-
var dimensions, document, pos, scroll, viewport
|
32
|
+
var adjust, dimensions, document, pos, scroll, viewport;
|
33
33
|
dimensions = this.page.validatedDimensions();
|
34
34
|
document = dimensions.document;
|
35
35
|
viewport = dimensions.viewport;
|
@@ -38,38 +38,33 @@ Poltergeist.Node = (function() {
|
|
38
38
|
left: dimensions.left,
|
39
39
|
top: dimensions.top
|
40
40
|
};
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
41
|
+
adjust = function(coord, measurement) {
|
42
|
+
if (pos[coord] < 0) {
|
43
|
+
return scroll[coord] = Math.max(0, scroll[coord] + pos[coord] - (viewport[measurement] / 2));
|
44
|
+
} else if (pos[coord] >= viewport[measurement]) {
|
45
|
+
return scroll[coord] = Math.min(document[measurement] - viewport[measurement], scroll[coord] + pos[coord] - viewport[measurement] + (viewport[measurement] / 2));
|
46
|
+
}
|
47
|
+
};
|
48
|
+
adjust('left', 'width');
|
49
|
+
adjust('top', 'height');
|
47
50
|
if (scroll.left !== dimensions.left || scroll.top !== dimensions.top) {
|
48
51
|
this.page.setScrollPosition(scroll);
|
52
|
+
pos = this.position();
|
49
53
|
}
|
50
|
-
return
|
51
|
-
position: this.relativePosition(pos, scroll),
|
52
|
-
scroll: scroll
|
53
|
-
};
|
54
|
-
};
|
55
|
-
Node.prototype.relativePosition = function(position, scroll) {
|
56
|
-
return {
|
57
|
-
x: position.x - scroll.left,
|
58
|
-
y: position.y - scroll.top
|
59
|
-
};
|
54
|
+
return pos;
|
60
55
|
};
|
61
56
|
Node.prototype.click = function() {
|
62
57
|
var position;
|
63
|
-
position = this.scrollIntoView()
|
64
|
-
return this.page.sendEvent('click', position.
|
58
|
+
position = this.scrollIntoView();
|
59
|
+
return this.page.sendEvent('click', position.left, position.top);
|
65
60
|
};
|
66
61
|
Node.prototype.dragTo = function(other) {
|
67
|
-
var otherPosition, position
|
68
|
-
|
69
|
-
otherPosition =
|
70
|
-
this.page.sendEvent('mousedown', position.
|
71
|
-
this.page.sendEvent('mousemove', otherPosition.
|
72
|
-
return this.page.sendEvent('mouseup', otherPosition.
|
62
|
+
var otherPosition, position;
|
63
|
+
position = this.scrollIntoView();
|
64
|
+
otherPosition = other.position();
|
65
|
+
this.page.sendEvent('mousedown', position.left, position.top);
|
66
|
+
this.page.sendEvent('mousemove', otherPosition.left, otherPosition.top);
|
67
|
+
return this.page.sendEvent('mouseup', otherPosition.left, otherPosition.top);
|
73
68
|
};
|
74
69
|
return Node;
|
75
70
|
}).call(this);
|
@@ -107,10 +107,9 @@ Poltergeist.WebPage = (function() {
|
|
107
107
|
};
|
108
108
|
};
|
109
109
|
WebPage.prototype.validatedDimensions = function() {
|
110
|
-
var
|
110
|
+
var dimensions, document, orig_left, orig_top;
|
111
111
|
dimensions = this.dimensions();
|
112
112
|
document = dimensions.document;
|
113
|
-
changed = false;
|
114
113
|
orig_left = dimensions.left;
|
115
114
|
orig_top = dimensions.top;
|
116
115
|
if (dimensions.right > document.width) {
|
@@ -1,7 +1,3 @@
|
|
1
|
-
if "#{phantom.version.major}.#{phantom.version.minor}.#{phantom.version.patch}" < "1.4.1"
|
2
|
-
console.log "Poltergeist requires a PhantomJS version of at least 1.4.1"
|
3
|
-
phantom.exit(1)
|
4
|
-
|
5
1
|
class Poltergeist
|
6
2
|
constructor: (port) ->
|
7
3
|
@browser = new Poltergeist.Browser(this)
|
@@ -28,30 +28,36 @@ class Poltergeist.Node
|
|
28
28
|
|
29
29
|
scroll = { left: dimensions.left, top: dimensions.top }
|
30
30
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
31
|
+
adjust = (coord, measurement) ->
|
32
|
+
if pos[coord] < 0
|
33
|
+
scroll[coord] = Math.max(
|
34
|
+
0,
|
35
|
+
scroll[coord] + pos[coord] - (viewport[measurement] / 2)
|
36
|
+
)
|
37
|
+
|
38
|
+
else if pos[coord] >= viewport[measurement]
|
39
|
+
scroll[coord] = Math.min(
|
40
|
+
document[measurement] - viewport[measurement],
|
41
|
+
scroll[coord] + pos[coord] - viewport[measurement] + (viewport[measurement] / 2)
|
42
|
+
)
|
43
|
+
|
44
|
+
adjust('left', 'width')
|
45
|
+
adjust('top', 'height')
|
36
46
|
|
37
47
|
if scroll.left != dimensions.left || scroll.top != dimensions.top
|
38
48
|
@page.setScrollPosition(scroll)
|
49
|
+
pos = this.position()
|
39
50
|
|
40
|
-
|
41
|
-
scroll: scroll
|
42
|
-
|
43
|
-
relativePosition: (position, scroll) ->
|
44
|
-
x: position.x - scroll.left
|
45
|
-
y: position.y - scroll.top
|
51
|
+
pos
|
46
52
|
|
47
53
|
click: ->
|
48
|
-
position = this.scrollIntoView()
|
49
|
-
@page.sendEvent('click', position.
|
54
|
+
position = this.scrollIntoView()
|
55
|
+
@page.sendEvent('click', position.left, position.top)
|
50
56
|
|
51
57
|
dragTo: (other) ->
|
52
|
-
|
53
|
-
otherPosition
|
58
|
+
position = this.scrollIntoView()
|
59
|
+
otherPosition = other.position()
|
54
60
|
|
55
|
-
@page.sendEvent('mousedown', position.
|
56
|
-
@page.sendEvent('mousemove', otherPosition.
|
57
|
-
@page.sendEvent('mouseup', otherPosition.
|
61
|
+
@page.sendEvent('mousedown', position.left, position.top)
|
62
|
+
@page.sendEvent('mousemove', otherPosition.left, otherPosition.top)
|
63
|
+
@page.sendEvent('mouseup', otherPosition.left, otherPosition.top)
|
@@ -42,5 +42,17 @@ module Capybara
|
|
42
42
|
"The PhantomJS client died while processing #{@message}"
|
43
43
|
end
|
44
44
|
end
|
45
|
+
|
46
|
+
class PhantomJSTooOld < Error
|
47
|
+
attr_reader :version
|
48
|
+
|
49
|
+
def initialize(version)
|
50
|
+
@version = version
|
51
|
+
end
|
52
|
+
|
53
|
+
def message
|
54
|
+
"PhantomJS version #{version} is too old. You must use at least version #{Client::PHANTOMJS_VERSION}"
|
55
|
+
end
|
56
|
+
end
|
45
57
|
end
|
46
58
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: poltergeist
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-02-18 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: capybara
|
16
|
-
requirement: &
|
16
|
+
requirement: &16526020 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ~>
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: '1.0'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *16526020
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: json
|
27
|
-
requirement: &
|
27
|
+
requirement: &16525520 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ~>
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
version: '1.6'
|
33
33
|
type: :runtime
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *16525520
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: sfl
|
38
|
-
requirement: &
|
38
|
+
requirement: &16525060 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ~>
|
@@ -43,10 +43,10 @@ dependencies:
|
|
43
43
|
version: '2.0'
|
44
44
|
type: :runtime
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *16525060
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: http_parser.rb
|
49
|
-
requirement: &
|
49
|
+
requirement: &16524600 !ruby/object:Gem::Requirement
|
50
50
|
none: false
|
51
51
|
requirements:
|
52
52
|
- - ~>
|
@@ -54,10 +54,10 @@ dependencies:
|
|
54
54
|
version: 0.5.3
|
55
55
|
type: :runtime
|
56
56
|
prerelease: false
|
57
|
-
version_requirements: *
|
57
|
+
version_requirements: *16524600
|
58
58
|
- !ruby/object:Gem::Dependency
|
59
59
|
name: faye-websocket
|
60
|
-
requirement: &
|
60
|
+
requirement: &16524140 !ruby/object:Gem::Requirement
|
61
61
|
none: false
|
62
62
|
requirements:
|
63
63
|
- - ~>
|
@@ -65,21 +65,21 @@ dependencies:
|
|
65
65
|
version: 0.2.0
|
66
66
|
type: :runtime
|
67
67
|
prerelease: false
|
68
|
-
version_requirements: *
|
68
|
+
version_requirements: *16524140
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: rspec
|
71
|
-
requirement: &
|
71
|
+
requirement: &16523680 !ruby/object:Gem::Requirement
|
72
72
|
none: false
|
73
73
|
requirements:
|
74
74
|
- - ~>
|
75
75
|
- !ruby/object:Gem::Version
|
76
|
-
version: 2.
|
76
|
+
version: 2.8.0
|
77
77
|
type: :development
|
78
78
|
prerelease: false
|
79
|
-
version_requirements: *
|
79
|
+
version_requirements: *16523680
|
80
80
|
- !ruby/object:Gem::Dependency
|
81
81
|
name: sinatra
|
82
|
-
requirement: &
|
82
|
+
requirement: &16523220 !ruby/object:Gem::Requirement
|
83
83
|
none: false
|
84
84
|
requirements:
|
85
85
|
- - ~>
|
@@ -87,10 +87,10 @@ dependencies:
|
|
87
87
|
version: '1.0'
|
88
88
|
type: :development
|
89
89
|
prerelease: false
|
90
|
-
version_requirements: *
|
90
|
+
version_requirements: *16523220
|
91
91
|
- !ruby/object:Gem::Dependency
|
92
92
|
name: rake
|
93
|
-
requirement: &
|
93
|
+
requirement: &16522760 !ruby/object:Gem::Requirement
|
94
94
|
none: false
|
95
95
|
requirements:
|
96
96
|
- - ~>
|
@@ -98,10 +98,10 @@ dependencies:
|
|
98
98
|
version: 0.9.2
|
99
99
|
type: :development
|
100
100
|
prerelease: false
|
101
|
-
version_requirements: *
|
101
|
+
version_requirements: *16522760
|
102
102
|
- !ruby/object:Gem::Dependency
|
103
103
|
name: image_size
|
104
|
-
requirement: &
|
104
|
+
requirement: &16522300 !ruby/object:Gem::Requirement
|
105
105
|
none: false
|
106
106
|
requirements:
|
107
107
|
- - ~>
|
@@ -109,7 +109,7 @@ dependencies:
|
|
109
109
|
version: '1.0'
|
110
110
|
type: :development
|
111
111
|
prerelease: false
|
112
|
-
version_requirements: *
|
112
|
+
version_requirements: *16522300
|
113
113
|
description: PhantomJS driver for Capybara
|
114
114
|
email:
|
115
115
|
- j@jonathanleighton.com
|
@@ -160,7 +160,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
160
160
|
version: '0'
|
161
161
|
requirements: []
|
162
162
|
rubyforge_project:
|
163
|
-
rubygems_version: 1.8.
|
163
|
+
rubygems_version: 1.8.15
|
164
164
|
signing_key:
|
165
165
|
specification_version: 3
|
166
166
|
summary: PhantomJS driver for Capybara
|