Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Click elements with native events

  • Loading branch information...
commit 30c79fcfcb0486c5ee2641abc343ccd76f97ecfa 1 parent c47f0a1
@mhoran mhoran authored
View
130 spec/integration/session_spec.rb
@@ -228,4 +228,134 @@ module TestSessions
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
View
25 src/JavascriptInvocation.cpp
@@ -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);
+}
View
7 src/JavascriptInvocation.h
@@ -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;
};
View
2  src/WebPage.cpp
@@ -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);
View
22 src/capybara.js
@@ -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) {
Please sign in to comment.
Something went wrong with that request. Please try again.