poltergeist 1.1.2 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +50 -21
- data/lib/capybara/poltergeist.rb +1 -0
- data/lib/capybara/poltergeist/browser.rb +39 -15
- data/lib/capybara/poltergeist/client.rb +11 -7
- data/lib/capybara/poltergeist/client/agent.coffee +104 -19
- data/lib/capybara/poltergeist/client/browser.coffee +34 -18
- data/lib/capybara/poltergeist/client/compiled/agent.js +154 -26
- data/lib/capybara/poltergeist/client/compiled/browser.js +54 -22
- data/lib/capybara/poltergeist/client/compiled/connection.js +0 -2
- data/lib/capybara/poltergeist/client/compiled/main.js +32 -15
- data/lib/capybara/poltergeist/client/compiled/node.js +13 -19
- data/lib/capybara/poltergeist/client/compiled/web_page.js +19 -5
- data/lib/capybara/poltergeist/client/main.coffee +9 -4
- data/lib/capybara/poltergeist/client/node.coffee +11 -19
- data/lib/capybara/poltergeist/client/web_page.coffee +4 -5
- data/lib/capybara/poltergeist/driver.rb +15 -3
- data/lib/capybara/poltergeist/errors.rb +20 -5
- data/lib/capybara/poltergeist/node.rb +32 -6
- data/lib/capybara/poltergeist/utility.rb +9 -0
- data/lib/capybara/poltergeist/version.rb +1 -1
- metadata +14 -7
@@ -1,12 +1,10 @@
|
|
1
1
|
var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
|
2
2
|
|
3
3
|
Poltergeist.Connection = (function() {
|
4
|
-
|
5
4
|
function Connection(owner, port) {
|
6
5
|
this.owner = owner;
|
7
6
|
this.port = port;
|
8
7
|
this.commandReceived = __bind(this.commandReceived, this);
|
9
|
-
|
10
8
|
this.socket = new WebSocket("ws://127.0.0.1:" + this.port + "/");
|
11
9
|
this.socket.onmessage = this.commandReceived;
|
12
10
|
this.socket.onclose = function() {
|
@@ -1,11 +1,11 @@
|
|
1
|
-
var Poltergeist,
|
1
|
+
var Poltergeist, _ref,
|
2
2
|
__hasProp = {}.hasOwnProperty,
|
3
3
|
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
|
4
4
|
|
5
5
|
Poltergeist = (function() {
|
6
|
-
|
7
6
|
function Poltergeist(port, width, height) {
|
8
7
|
var that;
|
8
|
+
|
9
9
|
this.browser = new Poltergeist.Browser(this, width, height);
|
10
10
|
this.connection = new Poltergeist.Connection(this, port);
|
11
11
|
that = this;
|
@@ -16,10 +16,13 @@ Poltergeist = (function() {
|
|
16
16
|
}
|
17
17
|
|
18
18
|
Poltergeist.prototype.runCommand = function(command) {
|
19
|
+
var error;
|
20
|
+
|
19
21
|
this.running = true;
|
20
22
|
try {
|
21
23
|
return this.browser[command.name].apply(this.browser, command.args);
|
22
|
-
} catch (
|
24
|
+
} catch (_error) {
|
25
|
+
error = _error;
|
23
26
|
if (error instanceof Poltergeist.Error) {
|
24
27
|
return this.sendError(error);
|
25
28
|
} else {
|
@@ -57,7 +60,6 @@ Poltergeist = (function() {
|
|
57
60
|
window.Poltergeist = Poltergeist;
|
58
61
|
|
59
62
|
Poltergeist.Error = (function() {
|
60
|
-
|
61
63
|
function Error() {}
|
62
64
|
|
63
65
|
return Error;
|
@@ -65,11 +67,11 @@ Poltergeist.Error = (function() {
|
|
65
67
|
})();
|
66
68
|
|
67
69
|
Poltergeist.ObsoleteNode = (function(_super) {
|
68
|
-
|
69
70
|
__extends(ObsoleteNode, _super);
|
70
71
|
|
71
72
|
function ObsoleteNode() {
|
72
|
-
|
73
|
+
_ref = ObsoleteNode.__super__.constructor.apply(this, arguments);
|
74
|
+
return _ref;
|
73
75
|
}
|
74
76
|
|
75
77
|
ObsoleteNode.prototype.name = "Poltergeist.ObsoleteNode";
|
@@ -86,27 +88,43 @@ Poltergeist.ObsoleteNode = (function(_super) {
|
|
86
88
|
|
87
89
|
})(Poltergeist.Error);
|
88
90
|
|
89
|
-
Poltergeist.
|
91
|
+
Poltergeist.FrameNotFound = (function(_super) {
|
92
|
+
__extends(FrameNotFound, _super);
|
93
|
+
|
94
|
+
function FrameNotFound(frameName) {
|
95
|
+
this.frameName = frameName;
|
96
|
+
}
|
90
97
|
|
91
|
-
|
98
|
+
FrameNotFound.prototype.name = "Poltergeist.FrameNotFound";
|
92
99
|
|
93
|
-
function
|
100
|
+
FrameNotFound.prototype.args = function() {
|
101
|
+
return [this.frameName];
|
102
|
+
};
|
103
|
+
|
104
|
+
return FrameNotFound;
|
105
|
+
|
106
|
+
})(Poltergeist.Error);
|
107
|
+
|
108
|
+
Poltergeist.MouseEventFailed = (function(_super) {
|
109
|
+
__extends(MouseEventFailed, _super);
|
110
|
+
|
111
|
+
function MouseEventFailed(eventName, selector, position) {
|
112
|
+
this.eventName = eventName;
|
94
113
|
this.selector = selector;
|
95
114
|
this.position = position;
|
96
115
|
}
|
97
116
|
|
98
|
-
|
117
|
+
MouseEventFailed.prototype.name = "Poltergeist.MouseEventFailed";
|
99
118
|
|
100
|
-
|
101
|
-
return [this.selector, this.position];
|
119
|
+
MouseEventFailed.prototype.args = function() {
|
120
|
+
return [this.eventName, this.selector, this.position];
|
102
121
|
};
|
103
122
|
|
104
|
-
return
|
123
|
+
return MouseEventFailed;
|
105
124
|
|
106
125
|
})(Poltergeist.Error);
|
107
126
|
|
108
127
|
Poltergeist.JavascriptError = (function(_super) {
|
109
|
-
|
110
128
|
__extends(JavascriptError, _super);
|
111
129
|
|
112
130
|
function JavascriptError(errors) {
|
@@ -124,7 +142,6 @@ Poltergeist.JavascriptError = (function(_super) {
|
|
124
142
|
})(Poltergeist.Error);
|
125
143
|
|
126
144
|
Poltergeist.BrowserError = (function(_super) {
|
127
|
-
|
128
145
|
__extends(BrowserError, _super);
|
129
146
|
|
130
147
|
function BrowserError(message, stack) {
|
@@ -4,7 +4,7 @@ Poltergeist.Node = (function() {
|
|
4
4
|
var name, _fn, _i, _len, _ref,
|
5
5
|
_this = this;
|
6
6
|
|
7
|
-
Node.DELEGATES = ['
|
7
|
+
Node.DELEGATES = ['allText', 'visibleText', 'getAttribute', 'value', 'set', 'setAttribute', 'isObsolete', 'removeAttribute', 'isMultiple', 'select', 'tagName', 'find', 'isVisible', 'position', 'trigger', 'parentId', 'mouseEventTest', 'scrollIntoView', 'isDOMEqual', 'isDisabled'];
|
8
8
|
|
9
9
|
function Node(page, id) {
|
10
10
|
this.page = page;
|
@@ -19,6 +19,7 @@ Poltergeist.Node = (function() {
|
|
19
19
|
_fn = function(name) {
|
20
20
|
return Node.prototype[name] = function() {
|
21
21
|
var args;
|
22
|
+
|
22
23
|
args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
|
23
24
|
return this.page.nodeCall(this.id, name, args);
|
24
25
|
};
|
@@ -28,8 +29,9 @@ Poltergeist.Node = (function() {
|
|
28
29
|
_fn(name);
|
29
30
|
}
|
30
31
|
|
31
|
-
Node.prototype.
|
32
|
+
Node.prototype.mouseEventPosition = function() {
|
32
33
|
var middle, pos, viewport;
|
34
|
+
|
33
35
|
viewport = this.page.viewportSize();
|
34
36
|
pos = this.position();
|
35
37
|
middle = function(start, end, size) {
|
@@ -41,27 +43,26 @@ Poltergeist.Node = (function() {
|
|
41
43
|
};
|
42
44
|
};
|
43
45
|
|
44
|
-
Node.prototype.
|
46
|
+
Node.prototype.mouseEvent = function(name) {
|
45
47
|
var pos, test;
|
46
|
-
|
47
|
-
event = 'click';
|
48
|
-
}
|
48
|
+
|
49
49
|
this.scrollIntoView();
|
50
|
-
pos = this.
|
51
|
-
test = this.
|
50
|
+
pos = this.mouseEventPosition();
|
51
|
+
test = this.mouseEventTest(pos.x, pos.y);
|
52
52
|
if (test.status === 'success') {
|
53
|
-
this.page.mouseEvent(
|
53
|
+
this.page.mouseEvent(name, pos.x, pos.y);
|
54
54
|
return pos;
|
55
55
|
} else {
|
56
|
-
throw new Poltergeist.
|
56
|
+
throw new Poltergeist.MouseEventFailed(name, test.selector, pos);
|
57
57
|
}
|
58
58
|
};
|
59
59
|
|
60
60
|
Node.prototype.dragTo = function(other) {
|
61
61
|
var otherPosition, position;
|
62
|
+
|
62
63
|
this.scrollIntoView();
|
63
|
-
position = this.
|
64
|
-
otherPosition = other.
|
64
|
+
position = this.mouseEventPosition();
|
65
|
+
otherPosition = other.mouseEventPosition();
|
65
66
|
this.page.mouseEvent('mousedown', position.x, position.y);
|
66
67
|
return this.page.mouseEvent('mouseup', otherPosition.x, otherPosition.y);
|
67
68
|
};
|
@@ -70,13 +71,6 @@ Poltergeist.Node = (function() {
|
|
70
71
|
return this.page === other.page && this.isDOMEqual(other.id);
|
71
72
|
};
|
72
73
|
|
73
|
-
Node.prototype.set = function(value) {
|
74
|
-
this.focusAndHighlight();
|
75
|
-
this.page.sendEvent('keypress', 16777219);
|
76
|
-
this.page.sendEvent('keypress', value.toString());
|
77
|
-
return this.blur();
|
78
|
-
};
|
79
|
-
|
80
74
|
return Node;
|
81
75
|
|
82
76
|
}).call(this);
|
@@ -14,6 +14,7 @@ Poltergeist.WebPage = (function() {
|
|
14
14
|
|
15
15
|
function WebPage(_native) {
|
16
16
|
var callback, _i, _len, _ref;
|
17
|
+
|
17
18
|
this["native"] = _native;
|
18
19
|
this["native"] || (this["native"] = require('webpage').create());
|
19
20
|
this._source = "";
|
@@ -32,6 +33,7 @@ Poltergeist.WebPage = (function() {
|
|
32
33
|
_fn = function(command) {
|
33
34
|
return WebPage.prototype[command] = function() {
|
34
35
|
var args;
|
36
|
+
|
35
37
|
args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
|
36
38
|
return this.runCommand(command, args);
|
37
39
|
};
|
@@ -63,6 +65,7 @@ Poltergeist.WebPage = (function() {
|
|
63
65
|
|
64
66
|
WebPage.prototype.injectAgent = function() {
|
65
67
|
var extension, _k, _len2, _ref2, _results;
|
68
|
+
|
66
69
|
if (this["native"].evaluate(function() {
|
67
70
|
return typeof __poltergeist;
|
68
71
|
}) === "undefined") {
|
@@ -103,6 +106,7 @@ Poltergeist.WebPage = (function() {
|
|
103
106
|
|
104
107
|
WebPage.prototype.onErrorNative = function(message, stack) {
|
105
108
|
var stackString;
|
109
|
+
|
106
110
|
stackString = message;
|
107
111
|
stack.forEach(function(frame) {
|
108
112
|
stackString += "\n";
|
@@ -131,6 +135,7 @@ Poltergeist.WebPage = (function() {
|
|
131
135
|
|
132
136
|
WebPage.prototype.onResourceReceivedNative = function(response) {
|
133
137
|
var _ref2;
|
138
|
+
|
134
139
|
if ((_ref2 = this._networkTraffic[response.id]) != null) {
|
135
140
|
_ref2.responseParts.push(response);
|
136
141
|
}
|
@@ -156,6 +161,10 @@ Poltergeist.WebPage = (function() {
|
|
156
161
|
return this._source;
|
157
162
|
};
|
158
163
|
|
164
|
+
WebPage.prototype.title = function() {
|
165
|
+
return this["native"].frameTitle;
|
166
|
+
};
|
167
|
+
|
159
168
|
WebPage.prototype.errors = function() {
|
160
169
|
return this._errors;
|
161
170
|
};
|
@@ -170,6 +179,7 @@ Poltergeist.WebPage = (function() {
|
|
170
179
|
|
171
180
|
WebPage.prototype.responseHeaders = function() {
|
172
181
|
var headers;
|
182
|
+
|
173
183
|
headers = {};
|
174
184
|
this._responseHeaders.forEach(function(item) {
|
175
185
|
return headers[item.name] = item.value;
|
@@ -228,15 +238,12 @@ Poltergeist.WebPage = (function() {
|
|
228
238
|
|
229
239
|
WebPage.prototype.popFrame = function() {
|
230
240
|
this.frames.pop();
|
231
|
-
|
232
|
-
return this["native"].switchToMainFrame();
|
233
|
-
} else {
|
234
|
-
return this["native"].switchToFrame(this.frames[this.frames.length - 1]);
|
235
|
-
}
|
241
|
+
return this["native"].switchToParentFrame();
|
236
242
|
};
|
237
243
|
|
238
244
|
WebPage.prototype.getPage = function(name) {
|
239
245
|
var page;
|
246
|
+
|
240
247
|
if (this.sub_pages[name]) {
|
241
248
|
return this.sub_pages[name];
|
242
249
|
} else {
|
@@ -249,6 +256,7 @@ Poltergeist.WebPage = (function() {
|
|
249
256
|
|
250
257
|
WebPage.prototype.dimensions = function() {
|
251
258
|
var scroll, viewport;
|
259
|
+
|
252
260
|
scroll = this.scrollPosition();
|
253
261
|
viewport = this.viewportSize();
|
254
262
|
return {
|
@@ -263,6 +271,7 @@ Poltergeist.WebPage = (function() {
|
|
263
271
|
|
264
272
|
WebPage.prototype.validatedDimensions = function() {
|
265
273
|
var dimensions, document;
|
274
|
+
|
266
275
|
dimensions = this.dimensions();
|
267
276
|
document = dimensions.document;
|
268
277
|
if (dimensions.right > document.width) {
|
@@ -291,6 +300,7 @@ Poltergeist.WebPage = (function() {
|
|
291
300
|
|
292
301
|
WebPage.prototype.evaluate = function() {
|
293
302
|
var args, fn;
|
303
|
+
|
294
304
|
fn = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
|
295
305
|
this.injectAgent();
|
296
306
|
return JSON.parse(this["native"].evaluate("function() { return PoltergeistAgent.stringify(" + (this.stringifyCall(fn, args)) + ") }"));
|
@@ -298,6 +308,7 @@ Poltergeist.WebPage = (function() {
|
|
298
308
|
|
299
309
|
WebPage.prototype.execute = function() {
|
300
310
|
var args, fn;
|
311
|
+
|
301
312
|
fn = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
|
302
313
|
return this["native"].evaluate("function() { " + (this.stringifyCall(fn, args)) + " }");
|
303
314
|
};
|
@@ -312,9 +323,11 @@ Poltergeist.WebPage = (function() {
|
|
312
323
|
|
313
324
|
WebPage.prototype.bindCallback = function(name) {
|
314
325
|
var that;
|
326
|
+
|
315
327
|
that = this;
|
316
328
|
return this["native"][name] = function() {
|
317
329
|
var result;
|
330
|
+
|
318
331
|
if (that[name + 'Native'] != null) {
|
319
332
|
result = that[name + 'Native'].apply(that, arguments);
|
320
333
|
}
|
@@ -326,6 +339,7 @@ Poltergeist.WebPage = (function() {
|
|
326
339
|
|
327
340
|
WebPage.prototype.runCommand = function(name, args) {
|
328
341
|
var result;
|
342
|
+
|
329
343
|
result = this.evaluate(function(name, args) {
|
330
344
|
return __poltergeist.externalCall(name, args);
|
331
345
|
}, name, args);
|
@@ -50,10 +50,15 @@ class Poltergeist.ObsoleteNode extends Poltergeist.Error
|
|
50
50
|
args: -> []
|
51
51
|
toString: -> this.name
|
52
52
|
|
53
|
-
class Poltergeist.
|
54
|
-
constructor: (@
|
55
|
-
name: "Poltergeist.
|
56
|
-
args: -> [@
|
53
|
+
class Poltergeist.FrameNotFound extends Poltergeist.Error
|
54
|
+
constructor: (@frameName) ->
|
55
|
+
name: "Poltergeist.FrameNotFound"
|
56
|
+
args: -> [@frameName]
|
57
|
+
|
58
|
+
class Poltergeist.MouseEventFailed extends Poltergeist.Error
|
59
|
+
constructor: (@eventName, @selector, @position) ->
|
60
|
+
name: "Poltergeist.MouseEventFailed"
|
61
|
+
args: -> [@eventName, @selector, @position]
|
57
62
|
|
58
63
|
class Poltergeist.JavascriptError extends Poltergeist.Error
|
59
64
|
constructor: (@errors) ->
|
@@ -1,10 +1,10 @@
|
|
1
1
|
# Proxy object for forwarding method calls to the node object inside the page.
|
2
2
|
|
3
3
|
class Poltergeist.Node
|
4
|
-
@DELEGATES = ['
|
4
|
+
@DELEGATES = ['allText', 'visibleText', 'getAttribute', 'value', 'set', 'setAttribute', 'isObsolete',
|
5
5
|
'removeAttribute', 'isMultiple', 'select', 'tagName', 'find',
|
6
|
-
'isVisible', 'position', 'trigger', 'parentId', '
|
7
|
-
'scrollIntoView', 'isDOMEqual', '
|
6
|
+
'isVisible', 'position', 'trigger', 'parentId', 'mouseEventTest',
|
7
|
+
'scrollIntoView', 'isDOMEqual', 'isDisabled']
|
8
8
|
|
9
9
|
constructor: (@page, @id) ->
|
10
10
|
|
@@ -16,7 +16,7 @@ class Poltergeist.Node
|
|
16
16
|
this.prototype[name] = (args...) ->
|
17
17
|
@page.nodeCall(@id, name, args)
|
18
18
|
|
19
|
-
|
19
|
+
mouseEventPosition: ->
|
20
20
|
viewport = @page.viewportSize()
|
21
21
|
pos = this.position()
|
22
22
|
|
@@ -28,34 +28,26 @@ class Poltergeist.Node
|
|
28
28
|
y: middle(pos.top, pos.bottom, viewport.height)
|
29
29
|
}
|
30
30
|
|
31
|
-
|
31
|
+
mouseEvent: (name) ->
|
32
32
|
this.scrollIntoView()
|
33
33
|
|
34
|
-
pos = this.
|
35
|
-
test = this.
|
34
|
+
pos = this.mouseEventPosition()
|
35
|
+
test = this.mouseEventTest(pos.x, pos.y)
|
36
36
|
|
37
37
|
if test.status == 'success'
|
38
|
-
@page.mouseEvent(
|
38
|
+
@page.mouseEvent(name, pos.x, pos.y)
|
39
39
|
pos
|
40
40
|
else
|
41
|
-
throw new Poltergeist.
|
41
|
+
throw new Poltergeist.MouseEventFailed(name, test.selector, pos)
|
42
42
|
|
43
43
|
dragTo: (other) ->
|
44
44
|
this.scrollIntoView()
|
45
45
|
|
46
|
-
position = this.
|
47
|
-
otherPosition = other.
|
46
|
+
position = this.mouseEventPosition()
|
47
|
+
otherPosition = other.mouseEventPosition()
|
48
48
|
|
49
49
|
@page.mouseEvent('mousedown', position.x, position.y)
|
50
50
|
@page.mouseEvent('mouseup', otherPosition.x, otherPosition.y)
|
51
51
|
|
52
52
|
isEqual: (other) ->
|
53
53
|
@page == other.page && this.isDOMEqual(other.id)
|
54
|
-
|
55
|
-
set: (value) ->
|
56
|
-
this.focusAndHighlight()
|
57
|
-
# Sending backspace to clear the input
|
58
|
-
# keycode from: https://github.com/ariya/phantomjs/commit/cab2635e66d74b7e665c44400b8b20a8f225153a#L0R370
|
59
|
-
@page.sendEvent('keypress', 16777219)
|
60
|
-
@page.sendEvent('keypress', value.toString())
|
61
|
-
this.blur()
|
@@ -101,6 +101,9 @@ class Poltergeist.WebPage
|
|
101
101
|
source: ->
|
102
102
|
@_source
|
103
103
|
|
104
|
+
title: ->
|
105
|
+
@native.frameTitle
|
106
|
+
|
104
107
|
errors: ->
|
105
108
|
@_errors
|
106
109
|
|
@@ -155,11 +158,7 @@ class Poltergeist.WebPage
|
|
155
158
|
|
156
159
|
popFrame: ->
|
157
160
|
@frames.pop()
|
158
|
-
|
159
|
-
if @frames.length == 0
|
160
|
-
@native.switchToMainFrame()
|
161
|
-
else
|
162
|
-
@native.switchToFrame(@frames[@frames.length - 1])
|
161
|
+
@native.switchToParentFrame()
|
163
162
|
|
164
163
|
getPage: (name) ->
|
165
164
|
if @sub_pages[name]
|
@@ -106,8 +106,20 @@ module Capybara::Poltergeist
|
|
106
106
|
browser.source.to_s
|
107
107
|
end
|
108
108
|
|
109
|
-
def
|
110
|
-
browser.
|
109
|
+
def title
|
110
|
+
browser.title
|
111
|
+
end
|
112
|
+
|
113
|
+
def find(method, selector)
|
114
|
+
browser.find(method, selector).map { |page_id, id| Capybara::Poltergeist::Node.new(self, page_id, id) }
|
115
|
+
end
|
116
|
+
|
117
|
+
def find_xpath(selector)
|
118
|
+
find :xpath, selector
|
119
|
+
end
|
120
|
+
|
121
|
+
def find_css(selector)
|
122
|
+
find :css, selector
|
111
123
|
end
|
112
124
|
|
113
125
|
def click(x, y)
|
@@ -199,7 +211,7 @@ module Capybara::Poltergeist
|
|
199
211
|
end
|
200
212
|
|
201
213
|
def invalid_element_errors
|
202
|
-
[Capybara::Poltergeist::ObsoleteNode, Capybara::Poltergeist::
|
214
|
+
[Capybara::Poltergeist::ObsoleteNode, Capybara::Poltergeist::MouseEventFailed]
|
203
215
|
end
|
204
216
|
end
|
205
217
|
end
|