poltergeist 1.3.0 → 1.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.md +68 -263
- data/lib/capybara/poltergeist.rb +1 -0
- data/lib/capybara/poltergeist/browser.rb +36 -3
- data/lib/capybara/poltergeist/client.rb +32 -31
- data/lib/capybara/poltergeist/client/agent.coffee +7 -6
- data/lib/capybara/poltergeist/client/browser.coffee +47 -13
- data/lib/capybara/poltergeist/client/compiled/agent.js +6 -24
- data/lib/capybara/poltergeist/client/compiled/browser.js +76 -39
- data/lib/capybara/poltergeist/client/compiled/main.js +0 -2
- data/lib/capybara/poltergeist/client/compiled/node.js +0 -4
- data/lib/capybara/poltergeist/client/compiled/web_page.js +42 -24
- data/lib/capybara/poltergeist/client/web_page.coffee +28 -8
- data/lib/capybara/poltergeist/driver.rb +31 -5
- data/lib/capybara/poltergeist/errors.rb +19 -19
- data/lib/capybara/poltergeist/json.rb +25 -0
- data/lib/capybara/poltergeist/node.rb +1 -1
- data/lib/capybara/poltergeist/version.rb +1 -1
- data/lib/capybara/poltergeist/web_socket_server.rb +13 -76
- metadata +47 -63
@@ -5,7 +5,6 @@ var Poltergeist, _ref,
|
|
5
5
|
Poltergeist = (function() {
|
6
6
|
function Poltergeist(port, width, height) {
|
7
7
|
var that;
|
8
|
-
|
9
8
|
this.browser = new Poltergeist.Browser(this, width, height);
|
10
9
|
this.connection = new Poltergeist.Connection(this, port);
|
11
10
|
that = this;
|
@@ -17,7 +16,6 @@ Poltergeist = (function() {
|
|
17
16
|
|
18
17
|
Poltergeist.prototype.runCommand = function(command) {
|
19
18
|
var error;
|
20
|
-
|
21
19
|
this.running = true;
|
22
20
|
try {
|
23
21
|
return this.browser.runCommand(command.name, command.args);
|
@@ -19,7 +19,6 @@ Poltergeist.Node = (function() {
|
|
19
19
|
_fn = function(name) {
|
20
20
|
return Node.prototype[name] = function() {
|
21
21
|
var args;
|
22
|
-
|
23
22
|
args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
|
24
23
|
return this.page.nodeCall(this.id, name, args);
|
25
24
|
};
|
@@ -31,7 +30,6 @@ Poltergeist.Node = (function() {
|
|
31
30
|
|
32
31
|
Node.prototype.mouseEventPosition = function() {
|
33
32
|
var middle, pos, viewport;
|
34
|
-
|
35
33
|
viewport = this.page.viewportSize();
|
36
34
|
pos = this.position();
|
37
35
|
middle = function(start, end, size) {
|
@@ -45,7 +43,6 @@ Poltergeist.Node = (function() {
|
|
45
43
|
|
46
44
|
Node.prototype.mouseEvent = function(name) {
|
47
45
|
var pos, test;
|
48
|
-
|
49
46
|
this.scrollIntoView();
|
50
47
|
pos = this.mouseEventPosition();
|
51
48
|
test = this.mouseEventTest(pos.x, pos.y);
|
@@ -59,7 +56,6 @@ Poltergeist.Node = (function() {
|
|
59
56
|
|
60
57
|
Node.prototype.dragTo = function(other) {
|
61
58
|
var otherPosition, position;
|
62
|
-
|
63
59
|
this.scrollIntoView();
|
64
60
|
position = this.mouseEventPosition();
|
65
61
|
otherPosition = other.mouseEventPosition();
|
@@ -6,7 +6,7 @@ Poltergeist.WebPage = (function() {
|
|
6
6
|
|
7
7
|
WebPage.CALLBACKS = ['onAlert', 'onConsoleMessage', 'onLoadFinished', 'onInitialized', 'onLoadStarted', 'onResourceRequested', 'onResourceReceived', 'onError', 'onNavigationRequested', 'onUrlChanged', 'onPageCreated'];
|
8
8
|
|
9
|
-
WebPage.DELEGATES = ['open', 'sendEvent', 'uploadFile', 'release', 'render'];
|
9
|
+
WebPage.DELEGATES = ['open', 'sendEvent', 'uploadFile', 'release', 'render', 'renderBase64'];
|
10
10
|
|
11
11
|
WebPage.COMMANDS = ['currentUrl', 'find', 'nodeCall', 'documentSize', 'beforeUpload', 'afterUpload'];
|
12
12
|
|
@@ -14,14 +14,13 @@ Poltergeist.WebPage = (function() {
|
|
14
14
|
|
15
15
|
function WebPage(_native) {
|
16
16
|
var callback, _i, _len, _ref;
|
17
|
-
|
18
17
|
this["native"] = _native;
|
19
18
|
this["native"] || (this["native"] = require('webpage').create());
|
20
|
-
this._source =
|
19
|
+
this._source = null;
|
21
20
|
this._errors = [];
|
22
21
|
this._networkTraffic = {};
|
22
|
+
this._temp_headers = {};
|
23
23
|
this.frames = [];
|
24
|
-
this.sub_pages = {};
|
25
24
|
_ref = WebPage.CALLBACKS;
|
26
25
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
27
26
|
callback = _ref[_i];
|
@@ -33,7 +32,6 @@ Poltergeist.WebPage = (function() {
|
|
33
32
|
_fn = function(command) {
|
34
33
|
return WebPage.prototype[command] = function() {
|
35
34
|
var args;
|
36
|
-
|
37
35
|
args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
|
38
36
|
return this.runCommand(command, args);
|
39
37
|
};
|
@@ -57,6 +55,7 @@ Poltergeist.WebPage = (function() {
|
|
57
55
|
WebPage.prototype.onInitializedNative = function() {
|
58
56
|
this._source = null;
|
59
57
|
this.injectAgent();
|
58
|
+
this.removeTempHeaders();
|
60
59
|
return this.setScrollPosition({
|
61
60
|
left: 0,
|
62
61
|
top: 0
|
@@ -65,7 +64,6 @@ Poltergeist.WebPage = (function() {
|
|
65
64
|
|
66
65
|
WebPage.prototype.injectAgent = function() {
|
67
66
|
var extension, _k, _len2, _ref2, _results;
|
68
|
-
|
69
67
|
if (this["native"].evaluate(function() {
|
70
68
|
return typeof __poltergeist;
|
71
69
|
}) === "undefined") {
|
@@ -106,7 +104,6 @@ Poltergeist.WebPage = (function() {
|
|
106
104
|
|
107
105
|
WebPage.prototype.onErrorNative = function(message, stack) {
|
108
106
|
var stackString;
|
109
|
-
|
110
107
|
stackString = message;
|
111
108
|
stack.forEach(function(frame) {
|
112
109
|
stackString += "\n";
|
@@ -135,7 +132,6 @@ Poltergeist.WebPage = (function() {
|
|
135
132
|
|
136
133
|
WebPage.prototype.onResourceReceivedNative = function(response) {
|
137
134
|
var _ref2;
|
138
|
-
|
139
135
|
if ((_ref2 = this._networkTraffic[response.id]) != null) {
|
140
136
|
_ref2.responseParts.push(response);
|
141
137
|
}
|
@@ -179,7 +175,6 @@ Poltergeist.WebPage = (function() {
|
|
179
175
|
|
180
176
|
WebPage.prototype.responseHeaders = function() {
|
181
177
|
var headers;
|
182
|
-
|
183
178
|
headers = {};
|
184
179
|
this._responseHeaders.forEach(function(item) {
|
185
180
|
return headers[item.name] = item.value;
|
@@ -219,14 +214,45 @@ Poltergeist.WebPage = (function() {
|
|
219
214
|
return this["native"].clipRect = rect;
|
220
215
|
};
|
221
216
|
|
217
|
+
WebPage.prototype.elementBounds = function(selector) {
|
218
|
+
return this["native"].evaluate(function(selector) {
|
219
|
+
return document.querySelector(selector).getBoundingClientRect();
|
220
|
+
}, selector);
|
221
|
+
};
|
222
|
+
|
222
223
|
WebPage.prototype.setUserAgent = function(userAgent) {
|
223
224
|
return this["native"].settings.userAgent = userAgent;
|
224
225
|
};
|
225
226
|
|
227
|
+
WebPage.prototype.getCustomHeaders = function() {
|
228
|
+
return this["native"].customHeaders;
|
229
|
+
};
|
230
|
+
|
226
231
|
WebPage.prototype.setCustomHeaders = function(headers) {
|
227
232
|
return this["native"].customHeaders = headers;
|
228
233
|
};
|
229
234
|
|
235
|
+
WebPage.prototype.addTempHeader = function(header) {
|
236
|
+
var name, value, _results;
|
237
|
+
_results = [];
|
238
|
+
for (name in header) {
|
239
|
+
value = header[name];
|
240
|
+
_results.push(this._temp_headers[name] = value);
|
241
|
+
}
|
242
|
+
return _results;
|
243
|
+
};
|
244
|
+
|
245
|
+
WebPage.prototype.removeTempHeaders = function() {
|
246
|
+
var allHeaders, name, value, _ref2;
|
247
|
+
allHeaders = this.getCustomHeaders();
|
248
|
+
_ref2 = this._temp_headers;
|
249
|
+
for (name in _ref2) {
|
250
|
+
value = _ref2[name];
|
251
|
+
delete allHeaders[name];
|
252
|
+
}
|
253
|
+
return this.setCustomHeaders(allHeaders);
|
254
|
+
};
|
255
|
+
|
230
256
|
WebPage.prototype.pushFrame = function(name) {
|
231
257
|
if (this["native"].switchToFrame(name)) {
|
232
258
|
this.frames.push(name);
|
@@ -236,6 +262,10 @@ Poltergeist.WebPage = (function() {
|
|
236
262
|
}
|
237
263
|
};
|
238
264
|
|
265
|
+
WebPage.prototype.pages = function() {
|
266
|
+
return this["native"].pagesWindowName;
|
267
|
+
};
|
268
|
+
|
239
269
|
WebPage.prototype.popFrame = function() {
|
240
270
|
this.frames.pop();
|
241
271
|
return this["native"].switchToParentFrame();
|
@@ -243,20 +273,14 @@ Poltergeist.WebPage = (function() {
|
|
243
273
|
|
244
274
|
WebPage.prototype.getPage = function(name) {
|
245
275
|
var page;
|
246
|
-
|
247
|
-
if (
|
248
|
-
return
|
249
|
-
} else {
|
250
|
-
page = this["native"].getPage(name);
|
251
|
-
if (page) {
|
252
|
-
return this.sub_pages[name] = new Poltergeist.WebPage(page);
|
253
|
-
}
|
276
|
+
page = this["native"].getPage(name);
|
277
|
+
if (page) {
|
278
|
+
return new Poltergeist.WebPage(page);
|
254
279
|
}
|
255
280
|
};
|
256
281
|
|
257
282
|
WebPage.prototype.dimensions = function() {
|
258
283
|
var scroll, viewport;
|
259
|
-
|
260
284
|
scroll = this.scrollPosition();
|
261
285
|
viewport = this.viewportSize();
|
262
286
|
return {
|
@@ -271,7 +295,6 @@ Poltergeist.WebPage = (function() {
|
|
271
295
|
|
272
296
|
WebPage.prototype.validatedDimensions = function() {
|
273
297
|
var dimensions, document;
|
274
|
-
|
275
298
|
dimensions = this.dimensions();
|
276
299
|
document = dimensions.document;
|
277
300
|
if (dimensions.right > document.width) {
|
@@ -300,7 +323,6 @@ Poltergeist.WebPage = (function() {
|
|
300
323
|
|
301
324
|
WebPage.prototype.evaluate = function() {
|
302
325
|
var args, fn;
|
303
|
-
|
304
326
|
fn = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
|
305
327
|
this.injectAgent();
|
306
328
|
return JSON.parse(this["native"].evaluate("function() { return PoltergeistAgent.stringify(" + (this.stringifyCall(fn, args)) + ") }"));
|
@@ -308,7 +330,6 @@ Poltergeist.WebPage = (function() {
|
|
308
330
|
|
309
331
|
WebPage.prototype.execute = function() {
|
310
332
|
var args, fn;
|
311
|
-
|
312
333
|
fn = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
|
313
334
|
return this["native"].evaluate("function() { " + (this.stringifyCall(fn, args)) + " }");
|
314
335
|
};
|
@@ -323,11 +344,9 @@ Poltergeist.WebPage = (function() {
|
|
323
344
|
|
324
345
|
WebPage.prototype.bindCallback = function(name) {
|
325
346
|
var that;
|
326
|
-
|
327
347
|
that = this;
|
328
348
|
return this["native"][name] = function() {
|
329
349
|
var result;
|
330
|
-
|
331
350
|
if (that[name + 'Native'] != null) {
|
332
351
|
result = that[name + 'Native'].apply(that, arguments);
|
333
352
|
}
|
@@ -339,7 +358,6 @@ Poltergeist.WebPage = (function() {
|
|
339
358
|
|
340
359
|
WebPage.prototype.runCommand = function(name, args) {
|
341
360
|
var result;
|
342
|
-
|
343
361
|
result = this.evaluate(function(name, args) {
|
344
362
|
return __poltergeist.externalCall(name, args);
|
345
363
|
}, name, args);
|
@@ -3,7 +3,7 @@ class Poltergeist.WebPage
|
|
3
3
|
'onLoadStarted', 'onResourceRequested', 'onResourceReceived',
|
4
4
|
'onError', 'onNavigationRequested', 'onUrlChanged', 'onPageCreated']
|
5
5
|
|
6
|
-
@DELEGATES = ['open', 'sendEvent', 'uploadFile', 'release', 'render']
|
6
|
+
@DELEGATES = ['open', 'sendEvent', 'uploadFile', 'release', 'render', 'renderBase64']
|
7
7
|
|
8
8
|
@COMMANDS = ['currentUrl', 'find', 'nodeCall', 'documentSize', 'beforeUpload', 'afterUpload']
|
9
9
|
|
@@ -12,11 +12,11 @@ class Poltergeist.WebPage
|
|
12
12
|
constructor: (@native) ->
|
13
13
|
@native or= require('webpage').create()
|
14
14
|
|
15
|
-
@_source =
|
15
|
+
@_source = null
|
16
16
|
@_errors = []
|
17
17
|
@_networkTraffic = {}
|
18
|
+
@_temp_headers = {}
|
18
19
|
@frames = []
|
19
|
-
@sub_pages = {}
|
20
20
|
|
21
21
|
for callback in WebPage.CALLBACKS
|
22
22
|
this.bindCallback(callback)
|
@@ -34,6 +34,7 @@ class Poltergeist.WebPage
|
|
34
34
|
onInitializedNative: ->
|
35
35
|
@_source = null
|
36
36
|
@injectAgent()
|
37
|
+
this.removeTempHeaders()
|
37
38
|
this.setScrollPosition(left: 0, top: 0)
|
38
39
|
|
39
40
|
injectAgent: ->
|
@@ -143,12 +144,31 @@ class Poltergeist.WebPage
|
|
143
144
|
setClipRect: (rect) ->
|
144
145
|
@native.clipRect = rect
|
145
146
|
|
147
|
+
elementBounds: (selector) ->
|
148
|
+
@native.evaluate(
|
149
|
+
(selector) -> document.querySelector(selector).getBoundingClientRect(),
|
150
|
+
selector
|
151
|
+
)
|
152
|
+
|
146
153
|
setUserAgent: (userAgent) ->
|
147
154
|
@native.settings.userAgent = userAgent
|
148
155
|
|
156
|
+
getCustomHeaders: ->
|
157
|
+
@native.customHeaders
|
158
|
+
|
149
159
|
setCustomHeaders: (headers) ->
|
150
160
|
@native.customHeaders = headers
|
151
161
|
|
162
|
+
addTempHeader: (header) ->
|
163
|
+
for name, value of header
|
164
|
+
@_temp_headers[name] = value
|
165
|
+
|
166
|
+
removeTempHeaders: ->
|
167
|
+
allHeaders = this.getCustomHeaders()
|
168
|
+
for name, value of @_temp_headers
|
169
|
+
delete allHeaders[name]
|
170
|
+
this.setCustomHeaders(allHeaders)
|
171
|
+
|
152
172
|
pushFrame: (name) ->
|
153
173
|
if @native.switchToFrame(name)
|
154
174
|
@frames.push(name)
|
@@ -156,16 +176,16 @@ class Poltergeist.WebPage
|
|
156
176
|
else
|
157
177
|
false
|
158
178
|
|
179
|
+
pages: ->
|
180
|
+
@native.pagesWindowName
|
181
|
+
|
159
182
|
popFrame: ->
|
160
183
|
@frames.pop()
|
161
184
|
@native.switchToParentFrame()
|
162
185
|
|
163
186
|
getPage: (name) ->
|
164
|
-
|
165
|
-
|
166
|
-
else
|
167
|
-
page = @native.getPage(name)
|
168
|
-
@sub_pages[name] = new Poltergeist.WebPage(page) if page
|
187
|
+
page = @native.getPage(name)
|
188
|
+
new Poltergeist.WebPage(page) if page
|
169
189
|
|
170
190
|
dimensions: ->
|
171
191
|
scroll = this.scrollPosition()
|
@@ -143,6 +143,10 @@ module Capybara::Poltergeist
|
|
143
143
|
browser.within_window(name, &block)
|
144
144
|
end
|
145
145
|
|
146
|
+
def window_handles
|
147
|
+
browser.window_handles
|
148
|
+
end
|
149
|
+
|
146
150
|
def reset!
|
147
151
|
browser.reset
|
148
152
|
@started = false
|
@@ -153,19 +157,40 @@ module Capybara::Poltergeist
|
|
153
157
|
end
|
154
158
|
alias_method :render, :save_screenshot
|
155
159
|
|
160
|
+
def render_base64(format = :png, options = {})
|
161
|
+
browser.render_base64(format, options)
|
162
|
+
end
|
163
|
+
|
156
164
|
def resize(width, height)
|
157
165
|
browser.resize(width, height)
|
158
166
|
end
|
159
167
|
alias_method :resize_window, :resize
|
160
168
|
|
169
|
+
def scroll_to(left, top)
|
170
|
+
browser.scroll_to(left, top)
|
171
|
+
end
|
172
|
+
|
161
173
|
def network_traffic
|
162
174
|
browser.network_traffic
|
163
175
|
end
|
164
176
|
|
177
|
+
def headers
|
178
|
+
browser.get_headers
|
179
|
+
end
|
180
|
+
|
165
181
|
def headers=(headers)
|
166
182
|
browser.set_headers(headers)
|
167
183
|
end
|
168
184
|
|
185
|
+
def add_headers(headers)
|
186
|
+
browser.add_headers(headers)
|
187
|
+
end
|
188
|
+
|
189
|
+
def add_header(name, value, options = {})
|
190
|
+
permanent = options.fetch(:permanent, true)
|
191
|
+
browser.add_header({ name => value }, permanent)
|
192
|
+
end
|
193
|
+
|
169
194
|
def response_headers
|
170
195
|
browser.response_headers
|
171
196
|
end
|
@@ -177,11 +202,12 @@ module Capybara::Poltergeist
|
|
177
202
|
def set_cookie(name, value, options = {})
|
178
203
|
options[:name] ||= name
|
179
204
|
options[:value] ||= value
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
205
|
+
options[:domain] ||= begin
|
206
|
+
if @started
|
207
|
+
URI.parse(browser.current_url).host
|
208
|
+
else
|
209
|
+
Capybara.app_host || "127.0.0.1"
|
210
|
+
end
|
185
211
|
end
|
186
212
|
|
187
213
|
browser.set_cookie(options)
|
@@ -20,7 +20,7 @@ module Capybara
|
|
20
20
|
end
|
21
21
|
|
22
22
|
def to_s
|
23
|
-
stack
|
23
|
+
[message, stack].join("\n")
|
24
24
|
end
|
25
25
|
end
|
26
26
|
|
@@ -140,28 +140,28 @@ module Capybara
|
|
140
140
|
end
|
141
141
|
|
142
142
|
class PhantomJSTooOld < Error
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
143
|
+
def self.===(other)
|
144
|
+
if Cliver::Dependency::VersionMismatch === other
|
145
|
+
warn "{name} exception has been deprecated in favor of using the " +
|
146
|
+
"cliver gem for command-line dependency detection. Please " +
|
147
|
+
"handle Cliver::Dependency::VersionMismatch instead."
|
148
|
+
true
|
149
|
+
else
|
150
|
+
super
|
151
|
+
end
|
151
152
|
end
|
152
153
|
end
|
153
154
|
|
154
155
|
class PhantomJSFailed < Error
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
"a Javascript REPL."
|
156
|
+
def self.===(other)
|
157
|
+
if Cliver::Dependency::NotMet === other
|
158
|
+
warn "{name} exception has been deprecated in favor of using the " +
|
159
|
+
"cliver gem for command-line dependency detection. Please " +
|
160
|
+
"handle Cliver::Dependency::NotMet instead."
|
161
|
+
true
|
162
|
+
else
|
163
|
+
super
|
164
|
+
end
|
165
165
|
end
|
166
166
|
end
|
167
167
|
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Capybara::Poltergeist
|
2
|
+
module JSON
|
3
|
+
def self.load(message)
|
4
|
+
if dumpy_multi_json?
|
5
|
+
MultiJson.load(message)
|
6
|
+
else
|
7
|
+
MultiJson.decode(message)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.dump(message)
|
12
|
+
if dumpy_multi_json?
|
13
|
+
MultiJson.dump(message)
|
14
|
+
else
|
15
|
+
MultiJson.encode(message)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def self.dumpy_multi_json?
|
22
|
+
MultiJson.respond_to?(:dump) && MultiJson.respond_to?(:load)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|