Support Capybara 2.11

* Update versions being tested against
* Implement missing APIs from newer versions
This commit is contained in:
Thomas Walpole 2017-01-03 16:33:42 -08:00 committed by Joe Ferris
parent b22df5fe67
commit 43ebe80704
19 changed files with 270 additions and 90 deletions

View File

@ -25,18 +25,18 @@ addons:
matrix: matrix:
include: include:
- rvm: 1.9.3 - rvm: 1.9.3
gemfile: gemfiles/2.6.gemfile gemfile: gemfiles/2.7.gemfile
env: QMAKE=/usr/lib/x86_64-linux-gnu/qt4/bin/qmake env: QMAKE=/usr/lib/x86_64-linux-gnu/qt4/bin/qmake
- rvm: 1.9.3 - rvm: 1.9.3
gemfile: gemfiles/2.5.gemfile gemfile: gemfiles/2.11.gemfile
env: QMAKE=/usr/lib/x86_64-linux-gnu/qt4/bin/qmake env: QMAKE=/usr/lib/x86_64-linux-gnu/qt4/bin/qmake
- rvm: 2.3.1 - rvm: 2.3.1
gemfile: gemfiles/master.gemfile gemfile: gemfiles/master.gemfile
allow_failures: allow_failures:
- gemfile: gemfiles/master.gemfile - gemfile: gemfiles/master.gemfile
gemfile: gemfile:
- gemfiles/2.6.gemfile - gemfiles/2.7.gemfile
- gemfiles/2.5.gemfile - gemfiles/2.11.gemfile
before_install: before_install:
- gem install bundler - gem install bundler
install: bundle install: bundle

View File

@ -1,9 +1,13 @@
appraise "2.6" do
gem "capybara", "~> 2.6.0"
end
appraise "2.7" do appraise "2.7" do
gem "capybara", "~> 2.7.0" gem "capybara", "~> 2.7.0"
gem 'addressable', '< 2.5.0', :platforms=>[:ruby_19, :jruby_19] # 2.5 requires public_suffix which requires ruby 2.0
gem 'nokogiri', '< 1.7.0', :platforms=>[:ruby_19, :jruby_19] # 1.7.0 requires ruby 2.1+
end
appraise "2.11" do
gem "capybara", "~> 2.11.0"
gem 'addressable', '< 2.5.0', :platforms=>[:ruby_19, :jruby_19] # 2.5 requires public_suffix which requires ruby 2.0
gem 'nokogiri', '< 1.7.0', :platforms=>[:ruby_19, :jruby_19] # 1.7.0 requires ruby 2.1+
end end
appraise "master" do appraise "master" do

View File

@ -2,70 +2,63 @@ PATH
remote: . remote: .
specs: specs:
capybara-webkit (1.11.1) capybara-webkit (1.11.1)
capybara (>= 2.3.0, < 2.8.0) capybara (>= 2.3.0, < 2.13.0)
json json
GEM GEM
remote: https://rubygems.org/ remote: https://rubygems.org/
specs: specs:
addressable (2.3.6) addressable (2.5.0)
appraisal (0.4.0) public_suffix (~> 2.0, >= 2.0.2)
appraisal (0.4.1)
bundler bundler
rake rake
capybara (2.5.0) capybara (2.11.0)
addressable
mime-types (>= 1.16) mime-types (>= 1.16)
nokogiri (>= 1.3.3) nokogiri (>= 1.3.3)
rack (>= 1.0.0) rack (>= 1.0.0)
rack-test (>= 0.5.4) rack-test (>= 0.5.4)
xpath (~> 2.0) xpath (~> 2.0)
childprocess (0.5.5) diff-lcs (1.2.5)
ffi (~> 1.0, >= 1.0.11) ffi (1.9.14-java)
diff-lcs (1.2.4)
ffi (1.9.8)
ffi (1.9.8-java)
ffi (1.9.8-x86-mingw32)
json (1.8.3) json (1.8.3)
launchy (2.4.2) json (1.8.3-java)
launchy (2.4.3)
addressable (~> 2.3) addressable (~> 2.3)
launchy (2.4.2-java) launchy (2.4.3-java)
addressable (~> 2.3) addressable (~> 2.3)
spoon (~> 0.0.1) spoon (~> 0.0.1)
mime-types (2.6.1) mime-types (2.99.3)
mini_magick (3.2.1) mini_magick (4.6.0)
subexec (~> 0.0.4) mini_portile2 (2.1.0)
mini_portile2 (2.0.0) nokogiri (1.7.0.1)
multi_json (1.11.0) mini_portile2 (~> 2.1.0)
nokogiri (1.6.7.2) nokogiri (1.7.0.1-java)
mini_portile2 (~> 2.0.0.rc2) nokogiri (1.7.0.1-x86-mingw32)
rack (1.6.4) mini_portile2 (~> 2.1.0)
rack-protection (1.3.2) public_suffix (2.0.5)
rack (1.6.5)
rack-protection (1.5.3)
rack rack
rack-test (0.6.3) rack-test (0.6.3)
rack (>= 1.0) rack (>= 1.0)
rake (0.9.2) rake (11.3.0)
rspec (2.14.1) rspec (2.99.0)
rspec-core (~> 2.14.0) rspec-core (~> 2.99.0)
rspec-expectations (~> 2.14.0) rspec-expectations (~> 2.99.0)
rspec-mocks (~> 2.14.0) rspec-mocks (~> 2.99.0)
rspec-core (2.14.4) rspec-core (2.99.2)
rspec-expectations (2.14.1) rspec-expectations (2.99.2)
diff-lcs (>= 1.1.3, < 2.0) diff-lcs (>= 1.1.3, < 2.0)
rspec-mocks (2.14.3) rspec-mocks (2.99.4)
rubyzip (1.1.7) sinatra (1.4.7)
selenium-webdriver (2.45.0) rack (~> 1.5)
childprocess (~> 0.5) rack-protection (~> 1.4)
multi_json (~> 1.0) tilt (>= 1.3, < 3)
rubyzip (~> 1.0) spoon (0.0.6)
websocket (~> 1.0)
sinatra (1.3.5)
rack (~> 1.4)
rack-protection (~> 1.3)
tilt (~> 1.3, >= 1.3.3)
spoon (0.0.4)
ffi ffi
subexec (0.0.4) tilt (2.0.5)
tilt (1.3.3)
websocket (1.2.1)
xpath (2.0.0) xpath (2.0.0)
nokogiri (~> 1.3) nokogiri (~> 1.3)
@ -77,13 +70,13 @@ PLATFORMS
DEPENDENCIES DEPENDENCIES
appraisal (~> 0.4.0) appraisal (~> 0.4.0)
capybara-webkit! capybara-webkit!
json (< 2.0)
launchy launchy
mime-types (< 3.0) mime-types (< 3.0)
mini_magick mini_magick
rake rake (< 12.0.0)
rspec (~> 2.14.0) rspec (~> 2.14)
selenium-webdriver
sinatra sinatra
BUNDLED WITH BUNDLED WITH
1.11.2 1.13.6

View File

@ -21,16 +21,15 @@ Gem::Specification.new do |s|
s.requirements << "Qt >= 4.8" s.requirements << "Qt >= 4.8"
s.add_runtime_dependency("capybara", ">= 2.3.0", "< 2.8.0") s.add_runtime_dependency("capybara", ">= 2.3.0", "< 2.13.0")
s.add_runtime_dependency("json") s.add_runtime_dependency("json")
s.add_development_dependency("rspec", "~> 2.14.0") s.add_development_dependency("rspec", "~> 2.14")
# Sinatra is used by Capybara's TestApp # Sinatra is used by Capybara's TestApp
s.add_development_dependency("sinatra") s.add_development_dependency("sinatra")
s.add_development_dependency("mini_magick") s.add_development_dependency("mini_magick")
s.add_development_dependency("rake") s.add_development_dependency("rake", "< 12.0.0")
s.add_development_dependency("appraisal", "~> 0.4.0") s.add_development_dependency("appraisal", "~> 0.4.0")
s.add_development_dependency("selenium-webdriver")
s.add_development_dependency("launchy") s.add_development_dependency("launchy")
end end

View File

@ -4,7 +4,8 @@ source "https://rubygems.org"
gem "mime-types", "< 3.0", :platforms=>[:ruby_19, :jruby_19] gem "mime-types", "< 3.0", :platforms=>[:ruby_19, :jruby_19]
gem "json", "< 2.0", :platforms=>[:ruby_19, :jruby_19] gem "json", "< 2.0", :platforms=>[:ruby_19, :jruby_19]
gem "capybara", "~> 2.11.0"
gem "capybara", "~> 2.6.0" gem "addressable", "< 2.5.0", :platforms=>[:ruby_19, :jruby_19]
gem "nokogiri", "< 1.7.0", :platforms=>[:ruby_19, :jruby_19]
gemspec :path=>"../" gemspec :path=>"../"

View File

@ -4,7 +4,8 @@ source "https://rubygems.org"
gem "mime-types", "< 3.0", :platforms=>[:ruby_19, :jruby_19] gem "mime-types", "< 3.0", :platforms=>[:ruby_19, :jruby_19]
gem "json", "< 2.0", :platforms=>[:ruby_19, :jruby_19] gem "json", "< 2.0", :platforms=>[:ruby_19, :jruby_19]
gem "capybara", "~> 2.7.0" gem "capybara", "~> 2.7.0"
gem "addressable", "< 2.5.0", :platforms=>[:ruby_19, :jruby_19]
gem "nokogiri", "< 1.7.0", :platforms=>[:ruby_19, :jruby_19]
gemspec :path=>"../" gemspec :path=>"../"

View File

@ -4,7 +4,6 @@ source "https://rubygems.org"
gem "mime-types", "< 3.0", :platforms=>[:ruby_19, :jruby_19] gem "mime-types", "< 3.0", :platforms=>[:ruby_19, :jruby_19]
gem "json", "< 2.0", :platforms=>[:ruby_19, :jruby_19] gem "json", "< 2.0", :platforms=>[:ruby_19, :jruby_19]
gem "capybara", :github=>"jnicklas/capybara" gem "capybara", :github=>"jnicklas/capybara"
gemspec :path=>"../" gemspec :path=>"../"

View File

@ -223,13 +223,13 @@ https://github.com/thoughtbot/capybara-webkit/wiki/Reporting-Crashes
MESSAGE MESSAGE
end end
def evaluate_script(script) def evaluate_script(script, *args)
json = command('Evaluate', script) json = command('Evaluate', script, args.to_json)
JSON.parse("[#{json}]").first JSON.parse("[#{json}]").first
end end
def execute_script(script) def execute_script(script, *args)
command('Execute', script) command('Execute', script, args.to_json)
end end
def render(path, width, height) def render(path, width, height)

View File

@ -76,13 +76,18 @@ module Capybara::Webkit
@browser.title @browser.title
end end
def execute_script(script) def execute_script(script, *args)
value = @browser.execute_script script value = @browser.execute_script(script, *encode_args(args))
value.empty? ? nil : value
if value.empty?
nil
else
value
end
end end
def evaluate_script(script) def evaluate_script(script, *args)
@browser.evaluate_script script @browser.evaluate_script(script, *encode_args(args))
end end
def console_messages def console_messages
@ -144,6 +149,21 @@ module Capybara::Webkit
end end
end end
def switch_to_frame(frame)
case frame
when :top
begin
loop { @browser.frame_focus }
rescue Capybara::Webkit::InvalidResponseError => e
raise unless e.message =~ /Already at parent frame/
end
when :parent
@browser.frame_focus
else
@browser.frame_focus(frame)
end
end
def within_window(selector) def within_window(selector)
current_window = current_window_handle current_window = current_window_handle
switch_to_window(selector) switch_to_window(selector)
@ -391,5 +411,15 @@ module Capybara::Webkit
"This option is global and can be configured once" \ "This option is global and can be configured once" \
" (not in a `before` or `setup` block)." " (not in a `before` or `setup` block)."
end end
def encode_args(args)
args.map do |arg|
if arg.is_a?(Capybara::Webkit::Node)
{ ELEMENT: arg.native }.to_json
else
arg.to_json
end
end
end
end end
end end

View File

@ -114,11 +114,13 @@ module Capybara::Webkit
end end
def disabled? def disabled?
if %w(option optgroup).include? tag_name xpath = "parent::optgroup[@disabled] | " \
self['disabled'] || find_xpath("parent::*")[0].disabled? "ancestor::select[@disabled] | " \
else "parent::fieldset[@disabled] | " \
self['disabled'] "ancestor::*[not(self::legend) or " \
end "preceding-sibling::legend][parent::fieldset[@disabled]]"
self["disabled"] || !find_xpath(xpath).empty?
end end
def path def path

View File

@ -62,12 +62,25 @@ describe Capybara::Webkit::Driver do
</head> </head>
<body> <body>
<script type="text/javascript"> <script type="text/javascript">
document.write("<p id='farewell'>goodbye</p>"); document.write("<p id='farewell'>goodbye</p><iframe id='g' src='/iframe2'></iframe>");
</script> </script>
</body> </body>
</html> </html>
HTML HTML
end end
get '/iframe2' do
<<-HTML
<html>
<head>
<title>Frame 2</title>
</head>
<body>
<div>In frame 2</div>
</body>
</html>
HTML
end
end end
end end
@ -95,6 +108,37 @@ describe Capybara::Webkit::Driver do
end end
end end
it "switches to frame by element" do
frame = driver.find_xpath('//iframe').first
element = double(Capybara::Node::Base, base: frame)
driver.switch_to_frame(element)
driver.find_xpath("//*[contains(., 'goodbye')]").should_not be_empty
driver.switch_to_frame(:parent)
end
it "can switch back to the parent frame" do
frame = driver.find_xpath('//iframe').first
element = double(Capybara::Node::Base, base: frame)
driver.switch_to_frame(element)
driver.switch_to_frame(:parent)
driver.find_xpath("//*[contains(., 'greeting')]").should_not be_empty
driver.find_xpath("//*[contains(., 'goodbye')]").should be_empty
end
it "can switch to the top frame" do
frame = driver.find_xpath('//iframe').first
element = double(Capybara::Node::Base, base: frame)
driver.switch_to_frame(element)
frame2 = driver.find_xpath('//iframe[@id="g"]').first
element2 = double(Capybara::Node::Base, base: frame2)
driver.switch_to_frame(element2)
driver.find_xpath("//div[contains(., 'In frame 2')]").should_not be_empty
driver.switch_to_frame(:top)
driver.find_xpath("//*[contains(., 'greeting')]").should_not be_empty
driver.find_xpath("//*[contains(., 'goodbye')]").should be_empty
driver.find_xpath("//div[contains(., 'In frame 2')]").should be_empty
end
it "raises error for missing frame by index" do it "raises error for missing frame by index" do
expect { driver.within_frame(1) { } }. expect { driver.within_frame(1) { } }.
to raise_error(Capybara::Webkit::InvalidResponseError) to raise_error(Capybara::Webkit::InvalidResponseError)
@ -528,6 +572,38 @@ describe Capybara::Webkit::Driver do
to raise_error(Capybara::Webkit::InvalidResponseError) to raise_error(Capybara::Webkit::InvalidResponseError)
end end
it "passes arguments to executed Javascript" do
driver.execute_script(%<document.getElementById('greeting').innerHTML = arguments[0]>, "My argument")
driver.find_xpath("//p[contains(., 'My argument')]").should_not be_empty
end
it "passes multiple arguments to executed Javascript" do
driver.execute_script(
%<document.getElementById('greeting').innerHTML = arguments[0] + arguments[1] + arguments[2].color>,
"random", 4, {color: 'red'})
driver.find_xpath("//p[contains(., 'random4red')]").should_not be_empty
end
it "passes page elements to executed Javascript" do
greeting = driver.find_xpath("//p[@id='greeting']").first
driver.execute_script(%<arguments[0].innerHTML = arguments[1]>, greeting, "new content")
driver.find_xpath("//p[@id='greeting'][contains(., 'new content')]").should_not be_empty
end
it "passes arguments to evaaluated Javascript" do
driver.evaluate_script(%<arguments[0]>, 3).should eq 3
end
it "passes multiple arguments to evaluated Javascript" do
driver.evaluate_script(%<arguments[0] + arguments[1] + arguments[2].num>, 3, 4, {num: 5}).should eq 12
end
it "passes page elements to evaluated Javascript" do
greeting = driver.find_xpath("//p[@id='greeting']").first
driver.evaluate_script(%<arguments[1].innerHTML = arguments[0]; arguments[2]>, "newer content", greeting, 7).should eq 7
driver.find_xpath("//p[@id='greeting'][contains(., 'newer content')]").should_not be_empty
end
it "doesn't raise an error for Javascript that doesn't return anything" do it "doesn't raise an error for Javascript that doesn't return anything" do
lambda { driver.execute_script(%<(function () { "returns nothing" })()>) }. lambda { driver.execute_script(%<(function () { "returns nothing" })()>) }.
should_not raise_error should_not raise_error

View File

@ -8,7 +8,26 @@ Evaluate::Evaluate(WebPageManager *manager, QStringList &arguments, QObject *par
} }
void Evaluate::start() { void Evaluate::start() {
QVariant result = page()->currentFrame()->evaluateJavaScript(arguments()[0]); QString script = arguments()[0];
QString jsonArgs;
if (arguments().length()>1){
jsonArgs = arguments()[1];
} else {
jsonArgs ="[]";
}
QString eval_script = QString("(function(){"
" for(var i=0; i<arguments.length; i++) {"
" arguments[i] = JSON.parse(arguments[i]);"
" if (arguments[i]['ELEMENT']) {"
" arguments[i] = Capybara.getNode(arguments[i]['ELEMENT']);"
" };"
" };"
" return eval(\"%1\");"
" }).apply(null, %2)").arg(script.replace("\"","\\\"").remove("\n"), jsonArgs);
QObject invocation_stub;
invocation_stub.setProperty("allowUnattached", false);
page()->currentFrame()->addToJavaScriptWindowObject("CapybaraInvocation", &invocation_stub);
QVariant result = page()->currentFrame()->evaluateJavaScript(eval_script);
JsonSerializer serializer; JsonSerializer serializer;
finish(true, serializer.serialize(result)); finish(true, serializer.serialize(result));
} }

View File

@ -7,7 +7,24 @@ Execute::Execute(WebPageManager *manager, QStringList &arguments, QObject *paren
} }
void Execute::start() { void Execute::start() {
QString script = arguments()[0] + QString("; 'success'"); QString jsonArgs;
if (arguments().length()>1){
jsonArgs = arguments()[1];
} else {
jsonArgs ="[]";
}
QString script = QString("(function(){"
" for(var i=0; i<arguments.length; i++) {"
" arguments[i] = JSON.parse(arguments[i]);"
" if (arguments[i]['ELEMENT']) {"
" arguments[i] = Capybara.getNode(arguments[i]['ELEMENT']);"
" };"
" };"
" %1 }).apply(null, %2); 'success'").arg(arguments()[0], jsonArgs);
QObject invocation_stub;
invocation_stub.setProperty("allowUnattached", false);
page()->currentFrame()->addToJavaScriptWindowObject("CapybaraInvocation", &invocation_stub);
QVariant result = page()->currentFrame()->evaluateJavaScript(script); QVariant result = page()->currentFrame()->evaluateJavaScript(script);
if (result.isValid()) { if (result.isValid()) {
finish(true); finish(true);

View File

@ -8,7 +8,6 @@ FrameFocus::FrameFocus(WebPageManager *manager, QStringList &arguments, QObject
} }
void FrameFocus::start() { void FrameFocus::start() {
findFrames();
switch(arguments().length()) { switch(arguments().length()) {
case 1: case 1:
focusId(arguments()[0]); focusId(arguments()[0]);
@ -26,8 +25,10 @@ void FrameFocus::findFrames() {
} }
void FrameFocus::focusIndex(int index) { void FrameFocus::focusIndex(int index) {
findFrames();
if (isFrameAtIndex(index)) { if (isFrameAtIndex(index)) {
frames[index]->setFocus(); frames[index]->setFocus();
page()->setCurrentFrameParent(frames[index]->parentFrame());
success(); success();
} else { } else {
frameNotFound(); frameNotFound();
@ -39,9 +40,11 @@ bool FrameFocus::isFrameAtIndex(int index) {
} }
void FrameFocus::focusId(QString name) { void FrameFocus::focusId(QString name) {
findFrames();
for (int i = 0; i < frames.length(); i++) { for (int i = 0; i < frames.length(); i++) {
if (frames[i]->frameName().compare(name) == 0) { if (frames[i]->frameName().compare(name) == 0) {
frames[i]->setFocus(); frames[i]->setFocus();
page()->setCurrentFrameParent(frames[i]->parentFrame());
success(); success();
return; return;
} }
@ -51,10 +54,13 @@ void FrameFocus::focusId(QString name) {
} }
void FrameFocus::focusParent() { void FrameFocus::focusParent() {
if (page()->currentFrame()->parentFrame() == 0) { // if (page()->currentFrame()->parentFrame() == 0) {
if (page()->currentFrameParent() == 0) {
finish(false, new ErrorMessage("Already at parent frame.")); finish(false, new ErrorMessage("Already at parent frame."));
} else { } else {
page()->currentFrame()->parentFrame()->setFocus(); // page()->currentFrame()->parentFrame()->setFocus();
page()->currentFrameParent()->setFocus();
page()->setCurrentFrameParent(page()->currentFrameParent()->parentFrame());
success(); success();
} }
} }

View File

@ -37,9 +37,15 @@ InvocationResult JavascriptInvocation::invoke(QWebFrame *frame) {
QVariant result = frame->evaluateJavaScript("Capybara.invoke()"); QVariant result = frame->evaluateJavaScript("Capybara.invoke()");
if (getError().isValid()) if (getError().isValid())
return InvocationResult(getError(), true); return InvocationResult(getError(), true);
else else {
if (functionName() == "leftClick") {
// Don't trigger the left click from JS incase the frame closes
QVariantMap qm = result.toMap();
leftClick(qm["absoluteX"].toInt(), qm["absoluteY"].toInt());
}
return InvocationResult(result); return InvocationResult(result);
} }
}
void JavascriptInvocation::leftClick(int x, int y) { void JavascriptInvocation::leftClick(int x, int y) {
QPoint mousePos(x, y); QPoint mousePos(x, y);

View File

@ -11,6 +11,9 @@ void Node::start() {
QString functionName = functionArguments.takeFirst(); QString functionName = functionArguments.takeFirst();
QString allowUnattached = functionArguments.takeFirst(); QString allowUnattached = functionArguments.takeFirst();
InvocationResult result = page()->invokeCapybaraFunction(functionName, allowUnattached == "true", functionArguments); InvocationResult result = page()->invokeCapybaraFunction(functionName, allowUnattached == "true", functionArguments);
if (functionName == "focus") {
page()->setCurrentFrameParent(page()->currentFrame()->parentFrame());
}
finish(&result); finish(&result);
} }

View File

@ -21,6 +21,7 @@ WebPage::WebPage(WebPageManager *manager, QObject *parent) : QWebPage(parent) {
m_uuid = QUuid::createUuid().toString(); m_uuid = QUuid::createUuid().toString();
m_confirmAction = true; m_confirmAction = true;
m_promptAction = false; m_promptAction = false;
m_currentFrameParent = 0;
setForwardUnsupportedContent(true); setForwardUnsupportedContent(true);
loadJavascript(); loadJavascript();
@ -255,6 +256,7 @@ bool WebPage::javaScriptPrompt(QWebFrame *frame, const QString &message, const Q
void WebPage::loadStarted() { void WebPage::loadStarted() {
m_loading = true; m_loading = true;
m_currentFrameParent = currentFrame()->parentFrame();
m_errorPageMessage = QString(); m_errorPageMessage = QString();
} }
@ -485,3 +487,13 @@ void WebPage::addModalMessage(bool expectedType, const QString &message, const Q
m_modalMessages << QString(); m_modalMessages << QString();
emit modalReady(); emit modalReady();
} }
QWebFrame* WebPage::currentFrameParent() {
return m_currentFrameParent;
}
void WebPage::setCurrentFrameParent(QWebFrame* frame) {
m_currentFrameParent = frame;
}

View File

@ -55,6 +55,8 @@ class WebPage : public QWebPage {
void resize(int, int); void resize(int, int);
int modalCount(); int modalCount();
QString modalMessage(); QString modalMessage();
void setCurrentFrameParent(QWebFrame* frame);
QWebFrame* currentFrameParent();
public slots: public slots:
bool shouldInterruptJavaScript(); bool shouldInterruptJavaScript();
@ -105,6 +107,7 @@ class WebPage : public QWebPage {
QList<QVariantMap> m_modalResponses; QList<QVariantMap> m_modalResponses;
QStringList m_modalMessages; QStringList m_modalMessages;
void addModalMessage(bool, const QString &, const QRegExp &); void addModalMessage(bool, const QString &, const QRegExp &);
QWebFrame* m_currentFrameParent;
}; };
#endif //_WEBPAGE_H #endif //_WEBPAGE_H

View File

@ -5,7 +5,11 @@ Capybara = {
invoke: function () { invoke: function () {
try { try {
if (CapybaraInvocation.functionName == "leftClick") {
return this["verifiedClickPosition"].apply(this, CapybaraInvocation.arguments);
} else {
return this[CapybaraInvocation.functionName].apply(this, CapybaraInvocation.arguments); return this[CapybaraInvocation.functionName].apply(this, CapybaraInvocation.arguments);
}
} catch (e) { } catch (e) {
CapybaraInvocation.error = e; CapybaraInvocation.error = e;
} }
@ -204,12 +208,17 @@ Capybara = {
throw new Capybara.UnpositionedElement(this.pathForNode(node), visible); throw new Capybara.UnpositionedElement(this.pathForNode(node), visible);
}, },
click: function (index, action) { verifiedClickPosition: function (index) {
var node = this.getNode(index); var node = this.getNode(index);
node.scrollIntoViewIfNeeded(); node.scrollIntoViewIfNeeded();
var pos = this.clickPosition(node); var pos = this.clickPosition(node);
CapybaraInvocation.hover(pos.relativeX, pos.relativeY); CapybaraInvocation.hover(pos.relativeX, pos.relativeY);
this.expectNodeAtPosition(node, pos); this.expectNodeAtPosition(node, pos);
return pos;
},
click: function (index, action) {
var pos = this.verifiedClickPosition(index);
action(pos.absoluteX, pos.absoluteY); action(pos.absoluteX, pos.absoluteY);
}, },