mirror of
https://github.com/thoughtbot/capybara-webkit
synced 2023-03-27 23:22:28 -04:00
Click elements with native events
This commit is contained in:
parent
c47f0a12b3
commit
30c79fcfcb
5 changed files with 165 additions and 21 deletions
|
@ -228,4 +228,134 @@ describe Capybara::Session do
|
|||
subject.should have_content('admin')
|
||||
end
|
||||
end
|
||||
|
||||
context "iframe app" do
|
||||
before(:all) do
|
||||
@app = Class.new(ExampleApp) do
|
||||
get '/' do
|
||||
<<-HTML
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<body>
|
||||
<h1>Main Frame</h1>
|
||||
<iframe src="/a" name="a_frame" width="500" height="500"></iframe>
|
||||
</body>
|
||||
</html>
|
||||
HTML
|
||||
end
|
||||
|
||||
get '/a' do
|
||||
<<-HTML
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<body>
|
||||
<h1>Page A</h1>
|
||||
<iframe src="/b" name="b_frame" width="500" height="500"></iframe>
|
||||
</body>
|
||||
</html>
|
||||
HTML
|
||||
end
|
||||
|
||||
get '/b' do
|
||||
<<-HTML
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<body>
|
||||
<h1>Page B</h1>
|
||||
<form action="/c" method="post">
|
||||
<input id="button" name="commit" type="submit" value="B Button">
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
||||
HTML
|
||||
end
|
||||
|
||||
post '/c' do
|
||||
<<-HTML
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<body>
|
||||
<h1>Page C</h1>
|
||||
</body>
|
||||
</html>
|
||||
HTML
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
it 'supports clicking an element offset from the viewport origin' do
|
||||
subject.visit '/'
|
||||
|
||||
subject.within_frame 'a_frame' do
|
||||
subject.within_frame 'b_frame' do
|
||||
subject.click_button 'B Button'
|
||||
subject.should have_content('Page C')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'click tests' do
|
||||
before(:all) do
|
||||
@app = Class.new(ExampleApp) do
|
||||
get '/' do
|
||||
<<-HTML
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<style>
|
||||
body {
|
||||
width: 800px;
|
||||
margin: 0;
|
||||
}
|
||||
.target {
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
float: left;
|
||||
margin: 100px;
|
||||
}
|
||||
</style>
|
||||
<body>
|
||||
<div id="one" class="target"></div>
|
||||
<div id="two" class="target"></div>
|
||||
<script type="text/javascript">
|
||||
var targets = document.getElementsByClassName('target');
|
||||
for (var i = 0; i < targets.length; i++) {
|
||||
var target = targets[i];
|
||||
target.onclick = function(event) {
|
||||
this.setAttribute('data-click-x', event.clientX);
|
||||
this.setAttribute('data-click-y', event.clientY);
|
||||
};
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
HTML
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
it 'clicks in the center of an element' do
|
||||
subject.visit('/')
|
||||
subject.find(:css, '#one').click
|
||||
subject.find(:css, '#one')['data-click-x'].should == '199'
|
||||
subject.find(:css, '#one')['data-click-y'].should == '199'
|
||||
end
|
||||
|
||||
it 'clicks in the center of the viewable area of an element' do
|
||||
subject.visit('/')
|
||||
subject.driver.resize_window(200, 200)
|
||||
subject.find(:css, '#one').click
|
||||
subject.find(:css, '#one')['data-click-x'].should == '149'
|
||||
subject.find(:css, '#one')['data-click-y'].should == '99'
|
||||
end
|
||||
|
||||
it 'scrolls an element into view when clicked' do
|
||||
subject.visit('/')
|
||||
subject.driver.resize_window(200, 200)
|
||||
subject.find(:css, '#two').click
|
||||
subject.find(:css, '#two')['data-click-x'].should_not be_nil
|
||||
subject.find(:css, '#two')['data-click-y'].should_not be_nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
#include "JavascriptInvocation.h"
|
||||
#include "WebPage.h"
|
||||
#include <QApplication>
|
||||
|
||||
JavascriptInvocation::JavascriptInvocation(const QString &functionName, const QStringList &arguments, QObject *parent) : QObject(parent) {
|
||||
JavascriptInvocation::JavascriptInvocation(const QString &functionName, const QStringList &arguments, WebPage *page, QObject *parent) : QObject(parent) {
|
||||
m_functionName = functionName;
|
||||
m_arguments = arguments;
|
||||
m_page = page;
|
||||
}
|
||||
|
||||
QString &JavascriptInvocation::functionName() {
|
||||
|
@ -12,3 +15,23 @@ QString &JavascriptInvocation::functionName() {
|
|||
QStringList &JavascriptInvocation::arguments() {
|
||||
return m_arguments;
|
||||
}
|
||||
|
||||
void JavascriptInvocation::click(const QWebElement &element, int left, int top, int width, int height) {
|
||||
QRect elementBox(left, top, width, height);
|
||||
QWebFrame *parent = element.webFrame();
|
||||
while (parent) {
|
||||
elementBox = elementBox.translated(parent->geometry().topLeft());
|
||||
parent = parent->parentFrame();
|
||||
}
|
||||
QRect viewport(QPoint(0, 0), m_page->viewportSize());
|
||||
QPoint mousePos = elementBox.intersected(viewport).center();
|
||||
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QWebElement>
|
||||
|
||||
class WebPage;
|
||||
|
||||
class JavascriptInvocation : public QObject {
|
||||
Q_OBJECT
|
||||
|
@ -8,12 +11,14 @@ class JavascriptInvocation : public QObject {
|
|||
Q_PROPERTY(QStringList arguments READ arguments)
|
||||
|
||||
public:
|
||||
JavascriptInvocation(const QString &functionName, const QStringList &arguments, QObject *parent = 0);
|
||||
JavascriptInvocation(const QString &functionName, const QStringList &arguments, WebPage *page, QObject *parent = 0);
|
||||
QString &functionName();
|
||||
QStringList &arguments();
|
||||
Q_INVOKABLE void click(const QWebElement &element, int left, int top, int width, int height);
|
||||
|
||||
private:
|
||||
QString m_functionName;
|
||||
QStringList m_arguments;
|
||||
WebPage *m_page;
|
||||
};
|
||||
|
||||
|
|
|
@ -120,7 +120,7 @@ bool WebPage::shouldInterruptJavaScript() {
|
|||
QVariant WebPage::invokeCapybaraFunction(const char *name, const QStringList &arguments) {
|
||||
QString qname(name);
|
||||
QString objectName("CapybaraInvocation");
|
||||
JavascriptInvocation invocation(qname, arguments);
|
||||
JavascriptInvocation invocation(qname, arguments, this);
|
||||
currentFrame()->addToJavaScriptWindowObject(objectName, &invocation);
|
||||
QString javascript = QString("Capybara.invoke()");
|
||||
return currentFrame()->evaluateJavaScript(javascript);
|
||||
|
|
|
@ -108,25 +108,11 @@ Capybara = {
|
|||
return this.nodes[index].submit();
|
||||
},
|
||||
|
||||
mousedown: function(index) {
|
||||
var mousedownEvent = document.createEvent('MouseEvents');
|
||||
mousedownEvent.initMouseEvent('mousedown', true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
|
||||
this.nodes[index].dispatchEvent(mousedownEvent);
|
||||
},
|
||||
|
||||
mouseup: function(index) {
|
||||
var mouseupEvent = document.createEvent('MouseEvents');
|
||||
mouseupEvent.initMouseEvent('mouseup', true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
|
||||
this.nodes[index].dispatchEvent(mouseupEvent);
|
||||
},
|
||||
|
||||
click: function (index) {
|
||||
this.mousedown(index);
|
||||
this.focus(index);
|
||||
this.mouseup(index);
|
||||
var clickEvent = document.createEvent('MouseEvents');
|
||||
clickEvent.initMouseEvent('click', true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
|
||||
this.nodes[index].dispatchEvent(clickEvent);
|
||||
var node = this.nodes[index];
|
||||
node.scrollIntoViewIfNeeded();
|
||||
var rect = node.getClientRects()[0];
|
||||
CapybaraInvocation.click(node, rect.left, rect.top, rect.width, rect.height);
|
||||
},
|
||||
|
||||
trigger: function (index, eventName) {
|
||||
|
|
Loading…
Reference in a new issue