mirror of
https://github.com/thoughtbot/capybara-webkit
synced 2023-03-27 23:22:28 -04:00
Raise Capybara.ClickFailed on click test failure
Prevents Node#set from succeeding when click test fails.
This commit is contained in:
parent
6c72a99174
commit
5dcbe9a0a4
5 changed files with 78 additions and 30 deletions
|
@ -54,9 +54,7 @@ module Capybara::Webkit
|
|||
end
|
||||
|
||||
def click
|
||||
unless invoke("click") == "true"
|
||||
raise Capybara::Webkit::ClickFailed
|
||||
end
|
||||
invoke("click")
|
||||
end
|
||||
|
||||
def drag_to(element)
|
||||
|
|
|
@ -345,6 +345,9 @@ describe Capybara::Session do
|
|||
<div id="one" class="target"></div>
|
||||
<div id="two" class="target"></div>
|
||||
<div id="offscreen"><a href="/" id="foo">Click Me</a></div>
|
||||
<form>
|
||||
<input type="checkbox" id="bar">
|
||||
</form>
|
||||
<script type="text/javascript">
|
||||
var targets = document.getElementsByClassName('target');
|
||||
for (var i = 0; i < targets.length; i++) {
|
||||
|
@ -400,6 +403,30 @@ describe Capybara::Session do
|
|||
}.should raise_error(Capybara::Webkit::ClickFailed)
|
||||
end
|
||||
|
||||
it 'raises an error if a checkbox is obscured when checked' do
|
||||
subject.visit('/')
|
||||
|
||||
subject.execute_script(<<-JS)
|
||||
var div = document.createElement('div');
|
||||
div.style.position = 'absolute';
|
||||
div.style.left = '0px';
|
||||
div.style.top = '0px';
|
||||
div.style.width = '100%';
|
||||
div.style.height = '100%';
|
||||
document.body.appendChild(div);
|
||||
JS
|
||||
|
||||
lambda {
|
||||
subject.check('bar')
|
||||
}.should raise_error(Capybara::Webkit::ClickFailed)
|
||||
end
|
||||
|
||||
it 'raises an error if an element is not visible when clicked' do
|
||||
subject.visit('/')
|
||||
subject.execute_script "document.getElementById('foo').style.display = 'none'"
|
||||
lambda { subject.click_link "Click Me" }.should raise_error(Capybara::Webkit::ClickFailed)
|
||||
end
|
||||
|
||||
it 'raises an error if an element is not in the viewport when clicked' do
|
||||
subject.visit('/')
|
||||
lambda { subject.click_link "Click Me" }.should raise_error(Capybara::Webkit::ClickFailed)
|
||||
|
|
|
@ -34,14 +34,34 @@ InvocationResult JavascriptInvocation::invoke(QWebFrame *frame) {
|
|||
return InvocationResult(result);
|
||||
}
|
||||
|
||||
bool JavascriptInvocation::click(QWebElement element, int left, int top, int width, int height) {
|
||||
void JavascriptInvocation::click(int x, int y) {
|
||||
QPoint mousePos(x, y);
|
||||
|
||||
QMouseEvent event(QEvent::MouseMove, mousePos, Qt::NoButton, Qt::NoButton, Qt::NoModifier);
|
||||
QApplication::sendEvent(m_page, &event);
|
||||
|
||||
event = QMouseEvent(QEvent::MouseButtonPress, mousePos, Qt::LeftButton, Qt::LeftButton, Qt::NoModifier);
|
||||
QApplication::sendEvent(m_page, &event);
|
||||
|
||||
event = QMouseEvent(QEvent::MouseButtonRelease, mousePos, Qt::LeftButton, Qt::LeftButton, Qt::NoModifier);
|
||||
QApplication::sendEvent(m_page, &event);
|
||||
}
|
||||
|
||||
bool JavascriptInvocation::clickTest(QWebElement element, int absoluteX, int absoluteY) {
|
||||
QPoint mousePos(absoluteX, absoluteY);
|
||||
QWebHitTestResult res = m_page->mainFrame()->hitTestContent(mousePos);
|
||||
return res.frame() == element.webFrame();
|
||||
}
|
||||
|
||||
QVariantMap JavascriptInvocation::clickPosition(QWebElement element, int left, int top, int width, int height) {
|
||||
QRect elementBox(left, top, width, height);
|
||||
QRect viewport(QPoint(0, 0), m_page->viewportSize());
|
||||
QRect boundedBox = elementBox.intersected(viewport);
|
||||
QPoint mousePos = boundedBox.center();
|
||||
|
||||
QString script = QString("Capybara.clickTest(this, %1, %2);").arg(mousePos.x()).arg(mousePos.y());
|
||||
bool ok = element.evaluateJavaScript(script).toBool();
|
||||
QVariantMap m;
|
||||
m["relativeX"] = mousePos.x();
|
||||
m["relativeY"] = mousePos.y();
|
||||
|
||||
QWebFrame *parent = element.webFrame();
|
||||
while (parent) {
|
||||
|
@ -52,22 +72,8 @@ bool JavascriptInvocation::click(QWebElement element, int left, int top, int wid
|
|||
boundedBox = elementBox.intersected(viewport);
|
||||
mousePos = boundedBox.center();
|
||||
|
||||
QWebHitTestResult res = m_page->mainFrame()->hitTestContent(mousePos);
|
||||
ok = ok && res.frame() == element.webFrame();
|
||||
m["absoluteX"] = mousePos.x();
|
||||
m["absoluteY"] = mousePos.y();
|
||||
|
||||
if (ok) {
|
||||
execClick(mousePos);
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
void JavascriptInvocation::execClick(QPoint mousePos) {
|
||||
QMouseEvent event(QEvent::MouseMove, mousePos, Qt::NoButton, Qt::NoButton, Qt::NoModifier);
|
||||
QApplication::sendEvent(m_page, &event);
|
||||
|
||||
event = QMouseEvent(QEvent::MouseButtonPress, mousePos, Qt::LeftButton, Qt::LeftButton, Qt::NoModifier);
|
||||
QApplication::sendEvent(m_page, &event);
|
||||
|
||||
event = QMouseEvent(QEvent::MouseButtonRelease, mousePos, Qt::LeftButton, Qt::LeftButton, Qt::NoModifier);
|
||||
QApplication::sendEvent(m_page, &event);
|
||||
return m;
|
||||
}
|
||||
|
|
|
@ -16,7 +16,9 @@ class JavascriptInvocation : public QObject {
|
|||
JavascriptInvocation(const QString &functionName, const QStringList &arguments, WebPage *page, QObject *parent = 0);
|
||||
QString &functionName();
|
||||
QStringList &arguments();
|
||||
Q_INVOKABLE bool click(QWebElement element, int left, int top, int width, int height);
|
||||
Q_INVOKABLE void click(int x, int y);
|
||||
Q_INVOKABLE bool clickTest(QWebElement element, int absoluteX, int absoluteY);
|
||||
Q_INVOKABLE QVariantMap clickPosition(QWebElement element, int left, int top, int width, int height);
|
||||
QVariant getError();
|
||||
void setError(QVariant error);
|
||||
InvocationResult invoke(QWebFrame *);
|
||||
|
@ -25,7 +27,6 @@ class JavascriptInvocation : public QObject {
|
|||
QString m_functionName;
|
||||
QStringList m_arguments;
|
||||
WebPage *m_page;
|
||||
void execClick(QPoint mousePos);
|
||||
QVariant m_error;
|
||||
};
|
||||
|
||||
|
|
|
@ -108,12 +108,12 @@ Capybara = {
|
|||
return this.nodes[index].submit();
|
||||
},
|
||||
|
||||
clickTest: function(node, x, y) {
|
||||
var el = document.elementFromPoint(x, y);
|
||||
clickTest: function(node, pos) {
|
||||
var el = document.elementFromPoint(pos.relativeX, pos.relativeY);
|
||||
|
||||
while (el) {
|
||||
if (el === node)
|
||||
return true;
|
||||
return CapybaraInvocation.clickTest(node, pos.absoluteX, pos.absoluteY);
|
||||
else
|
||||
el = el.parentNode;
|
||||
}
|
||||
|
@ -121,11 +121,22 @@ Capybara = {
|
|||
return false;
|
||||
},
|
||||
|
||||
clickPosition: function(node) {
|
||||
var rect = node.getClientRects()[0];
|
||||
if (rect)
|
||||
return CapybaraInvocation.clickPosition(node, rect.left, rect.top, rect.width, rect.height);
|
||||
},
|
||||
|
||||
click: function (index) {
|
||||
var node = this.nodes[index];
|
||||
node.scrollIntoViewIfNeeded();
|
||||
var rect = node.getClientRects()[0];
|
||||
return CapybaraInvocation.click(node, rect.left, rect.top, rect.width, rect.height);
|
||||
|
||||
var pos = this.clickPosition(node);
|
||||
|
||||
if (pos && this.clickTest(node, pos))
|
||||
CapybaraInvocation.click(pos.absoluteX, pos.absoluteY);
|
||||
else
|
||||
throw new Capybara.ClickFailed();
|
||||
},
|
||||
|
||||
trigger: function (index, eventName) {
|
||||
|
@ -348,3 +359,8 @@ Capybara = {
|
|||
}
|
||||
};
|
||||
|
||||
Capybara.ClickFailed = function() {
|
||||
this.name = 'Capybara.ClickFailed';
|
||||
};
|
||||
Capybara.ClickFailed.prototype = new Error();
|
||||
Capybara.ClickFailed.prototype.constructor = Capybara.ClickFailed;
|
||||
|
|
Loading…
Reference in a new issue