Skip to content
This repository has been archived by the owner on Nov 27, 2020. It is now read-only.

Commit

Permalink
Fix #25. Possible 'race condition' when node becomes obsolete.
Browse files Browse the repository at this point in the history
  • Loading branch information
jonleighton committed Feb 24, 2012
1 parent fc88a85 commit 3011b27
Show file tree
Hide file tree
Showing 6 changed files with 58 additions and 19 deletions.
10 changes: 10 additions & 0 deletions lib/capybara/poltergeist/client/agent.coffee
Expand Up @@ -7,6 +7,12 @@ class PoltergeistAgent
@windows = []
this.pushWindow(window)

externalCall: (name, arguments) ->
try
{ value: this[name].apply(this, arguments) }
catch error
{ error: error.toString() }

pushWindow: (new_window) ->
@windows.push(new_window)

Expand Down Expand Up @@ -51,8 +57,12 @@ class PoltergeistAgent

nodeCall: (id, name, arguments) ->
node = this.get(id)
throw new PoltergeistAgent.ObsoleteNode if node.isObsolete()
node[name].apply(node, arguments)

class PoltergeistAgent.ObsoleteNode
toString: -> "PoltergeistAgent.ObsoleteNode"

class PoltergeistAgent.Node
@EVENTS = {
FOCUS: ['blur', 'focus', 'focusin', 'focusout'],
Expand Down
21 changes: 21 additions & 0 deletions lib/capybara/poltergeist/client/compiled/agent.js
Expand Up @@ -7,6 +7,17 @@ PoltergeistAgent = (function() {
this.windows = [];
this.pushWindow(window);
}
PoltergeistAgent.prototype.externalCall = function(name, arguments) {
try {
return {
value: this[name].apply(this, arguments)
};
} catch (error) {
return {
error: error.toString()
};
}
};
PoltergeistAgent.prototype.pushWindow = function(new_window) {
this.windows.push(new_window);
this.window = new_window;
Expand Down Expand Up @@ -53,10 +64,20 @@ PoltergeistAgent = (function() {
PoltergeistAgent.prototype.nodeCall = function(id, name, arguments) {
var node;
node = this.get(id);
if (node.isObsolete()) {
throw new PoltergeistAgent.ObsoleteNode;
}
return node[name].apply(node, arguments);
};
return PoltergeistAgent;
})();
PoltergeistAgent.ObsoleteNode = (function() {
function ObsoleteNode() {}
ObsoleteNode.prototype.toString = function() {
return "PoltergeistAgent.ObsoleteNode";
};
return ObsoleteNode;
})();
PoltergeistAgent.Node = (function() {
Node.EVENTS = {
FOCUS: ['blur', 'focus', 'focusin', 'focusout'],
Expand Down
9 changes: 1 addition & 8 deletions lib/capybara/poltergeist/client/compiled/node.js
Expand Up @@ -9,19 +9,12 @@ Poltergeist.Node = (function() {
Node.prototype.parent = function() {
return new Poltergeist.Node(this.page, this.parentId());
};
Node.prototype.isObsolete = function() {
return this.page.nodeCall(this.id, 'isObsolete');
};
_ref = Node.DELEGATES;
_fn = __bind(function(name) {
return this.prototype[name] = function() {
var arguments, _ref2;
_ref2 = arguments, arguments = 1 <= _ref2.length ? __slice.call(_ref2, 0) : [];
if (this.isObsolete()) {
throw new Poltergeist.ObsoleteNode;
} else {
return this.page.nodeCall(this.id, name, arguments);
}
return this.page.nodeCall(this.id, name, arguments);
};
}, Node);
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
Expand Down
16 changes: 14 additions & 2 deletions lib/capybara/poltergeist/client/compiled/web_page.js
Expand Up @@ -163,9 +163,21 @@ Poltergeist.WebPage = (function() {
};
};
WebPage.prototype.runCommand = function(name, arguments) {
return this.evaluate(function(name, arguments) {
return __poltergeist[name].apply(__poltergeist, arguments);
var result;
result = this.evaluate(function(name, arguments) {
return __poltergeist.externalCall(name, arguments);
}, name, arguments);
if (result.error) {
switch (result.error) {
case "PoltergeistAgent.ObsoleteNode":
throw new Poltergeist.ObsoleteNode;
break;
default:
throw result.error;
}
} else {
return result.value;
}
};
return WebPage;
}).call(this);
8 changes: 1 addition & 7 deletions lib/capybara/poltergeist/client/node.coffee
Expand Up @@ -9,16 +9,10 @@ class Poltergeist.Node
parent: ->
new Poltergeist.Node(@page, this.parentId())

isObsolete: ->
@page.nodeCall(@id, 'isObsolete')

for name in @DELEGATES
do (name) =>
this.prototype[name] = (arguments...) ->
if this.isObsolete()
throw new Poltergeist.ObsoleteNode
else
@page.nodeCall(@id, name, arguments)
@page.nodeCall(@id, name, arguments)

scrollIntoView: ->
dimensions = @page.validatedDimensions()
Expand Down
13 changes: 11 additions & 2 deletions lib/capybara/poltergeist/client/web_page.coffee
Expand Up @@ -129,7 +129,16 @@ class Poltergeist.WebPage
that[name].apply(that, arguments)

runCommand: (name, arguments) ->
this.evaluate(
(name, arguments) -> __poltergeist[name].apply(__poltergeist, arguments),
result = this.evaluate(
(name, arguments) -> __poltergeist.externalCall(name, arguments),
name, arguments
)

if result.error
switch result.error
when "PoltergeistAgent.ObsoleteNode"
throw new Poltergeist.ObsoleteNode
else
throw result.error
else
result.value

1 comment on commit 3011b27

@jonleighton
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Referenced wrong bug in commit message. Should have been #30.

Please sign in to comment.