Add support for keys and offset with mouse clicks coming in Capybara 3
This commit is contained in:
parent
5cd1ad0645
commit
1d4dfdaac9
|
@ -6,4 +6,5 @@ end
|
|||
|
||||
appraise "master" do
|
||||
gem "capybara", github: "jnicklas/capybara"
|
||||
gem "puma"
|
||||
end
|
||||
|
|
15
Gemfile.lock
15
Gemfile.lock
|
@ -2,7 +2,7 @@ PATH
|
|||
remote: .
|
||||
specs:
|
||||
capybara-webkit (1.14.0)
|
||||
capybara (~> 2.3)
|
||||
capybara (>= 2.3, < 4.0)
|
||||
json
|
||||
|
||||
GEM
|
||||
|
@ -14,13 +14,13 @@ GEM
|
|||
bundler
|
||||
rake
|
||||
thor (>= 0.14.0)
|
||||
capybara (2.15.4)
|
||||
capybara (2.17.0)
|
||||
addressable
|
||||
mini_mime (>= 0.1.3)
|
||||
nokogiri (>= 1.3.3)
|
||||
rack (>= 1.0.0)
|
||||
rack-test (>= 0.5.4)
|
||||
xpath (~> 2.0)
|
||||
xpath (>= 2.0, < 4.0)
|
||||
diff-lcs (1.3)
|
||||
ffi (1.9.18-java)
|
||||
json (1.8.6)
|
||||
|
@ -36,14 +36,11 @@ GEM
|
|||
mustermann (1.0.1)
|
||||
nokogiri (1.8.1)
|
||||
mini_portile2 (~> 2.3.0)
|
||||
nokogiri (1.8.1-java)
|
||||
nokogiri (1.8.1-x86-mingw32)
|
||||
mini_portile2 (~> 2.3.0)
|
||||
public_suffix (3.0.0)
|
||||
rack (2.0.3)
|
||||
rack-protection (2.0.0)
|
||||
rack
|
||||
rack-test (0.7.0)
|
||||
rack-test (0.8.2)
|
||||
rack (>= 1.0, < 3)
|
||||
rake (11.3.0)
|
||||
rspec (3.7.0)
|
||||
|
@ -68,8 +65,8 @@ GEM
|
|||
ffi
|
||||
thor (0.20.0)
|
||||
tilt (2.0.8)
|
||||
xpath (2.1.0)
|
||||
nokogiri (~> 1.3)
|
||||
xpath (3.0.0)
|
||||
nokogiri (~> 1.8)
|
||||
|
||||
PLATFORMS
|
||||
java
|
||||
|
|
|
@ -21,7 +21,7 @@ Gem::Specification.new do |s|
|
|||
|
||||
s.requirements << "Qt >= 4.8"
|
||||
|
||||
s.add_runtime_dependency("capybara", "~>2.3")
|
||||
s.add_runtime_dependency("capybara", ">= 2.3", "< 4.0")
|
||||
s.add_runtime_dependency("json")
|
||||
|
||||
s.add_development_dependency("rspec", "~> 3.5")
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
source "https://rubygems.org"
|
||||
|
||||
gem "json", "< 2.0", platforms: [:ruby_19, :jruby_19]
|
||||
gem "capybara", github: "jnicklas/capybara"
|
||||
gem "puma"
|
||||
|
||||
gemspec path: "../"
|
||||
|
|
|
@ -68,16 +68,16 @@ module Capybara::Webkit
|
|||
end
|
||||
end
|
||||
|
||||
def click
|
||||
invoke("leftClick")
|
||||
def click(keys = [], offset = {})
|
||||
invoke("leftClick", keys.to_json, offset.to_json)
|
||||
end
|
||||
|
||||
def double_click
|
||||
invoke("doubleClick")
|
||||
def double_click(keys = [], offset = {})
|
||||
invoke("doubleClick", keys.to_json, offset.to_json)
|
||||
end
|
||||
|
||||
def right_click
|
||||
invoke("rightClick")
|
||||
def right_click(keys = [], offset = {})
|
||||
invoke("rightClick", keys.to_json, offset.to_json)
|
||||
end
|
||||
|
||||
def hover
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
#include <QEvent>
|
||||
#include <QContextMenuEvent>
|
||||
|
||||
QMap<QString, Qt::KeyboardModifiers> JavascriptInvocation::m_modifiersMap(JavascriptInvocation::makeModifiersMap());
|
||||
|
||||
JavascriptInvocation::JavascriptInvocation(const QString &functionName, bool allowUnattached, const QStringList &arguments, WebPage *page, QObject *parent) : QObject(parent) {
|
||||
m_functionName = functionName;
|
||||
m_allowUnattached = allowUnattached;
|
||||
|
@ -33,6 +35,7 @@ void JavascriptInvocation::setError(QVariant error) {
|
|||
}
|
||||
|
||||
InvocationResult JavascriptInvocation::invoke(QWebFrame *frame) {
|
||||
|
||||
frame->addToJavaScriptWindowObject("CapybaraInvocation", this);
|
||||
QVariant result = frame->evaluateJavaScript("Capybara.invoke()");
|
||||
if (getError().isValid())
|
||||
|
@ -41,36 +44,43 @@ InvocationResult JavascriptInvocation::invoke(QWebFrame *frame) {
|
|||
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());
|
||||
leftClick(qm["absoluteX"].toInt(), qm["absoluteY"].toInt(), qm["keys"].value<QVariantList>());
|
||||
}
|
||||
return InvocationResult(result);
|
||||
}
|
||||
}
|
||||
|
||||
void JavascriptInvocation::leftClick(int x, int y) {
|
||||
QPoint mousePos(x, y);
|
||||
|
||||
m_page->mouseEvent(QEvent::MouseButtonPress, mousePos, Qt::LeftButton);
|
||||
m_page->mouseEvent(QEvent::MouseButtonRelease, mousePos, Qt::LeftButton);
|
||||
Qt::KeyboardModifiers JavascriptInvocation::modifiers(const QVariantList& keys){
|
||||
Qt::KeyboardModifiers modifiers = Qt::NoModifier;
|
||||
for (int i = 0; i < keys.length(); i++) {
|
||||
modifiers |= m_modifiersMap.value(keys[i].toString(), Qt::NoModifier);
|
||||
}
|
||||
return modifiers;
|
||||
}
|
||||
|
||||
void JavascriptInvocation::rightClick(int x, int y) {
|
||||
void JavascriptInvocation::leftClick(int x, int y, QVariantList keys) {
|
||||
QPoint mousePos(x, y);
|
||||
|
||||
m_page->mouseEvent(QEvent::MouseButtonPress, mousePos, Qt::RightButton);
|
||||
m_page->mouseEvent(QEvent::MouseButtonPress, mousePos, Qt::LeftButton, modifiers(keys));
|
||||
m_page->mouseEvent(QEvent::MouseButtonRelease, mousePos, Qt::LeftButton, modifiers(keys));
|
||||
}
|
||||
|
||||
void JavascriptInvocation::rightClick(int x, int y, QVariantList keys) {
|
||||
QPoint mousePos(x, y);
|
||||
m_page->mouseEvent(QEvent::MouseButtonPress, mousePos, Qt::RightButton, modifiers(keys));
|
||||
|
||||
// swallowContextMenuEvent tries to fire contextmenu event in html page
|
||||
QContextMenuEvent *event = new QContextMenuEvent(QContextMenuEvent::Mouse, mousePos);
|
||||
QContextMenuEvent *event = new QContextMenuEvent(QContextMenuEvent::Mouse, mousePos, QCursor::pos(), modifiers(keys));
|
||||
m_page->swallowContextMenuEvent(event);
|
||||
|
||||
m_page->mouseEvent(QEvent::MouseButtonRelease, mousePos, Qt::RightButton);
|
||||
m_page->mouseEvent(QEvent::MouseButtonRelease, mousePos, Qt::RightButton, modifiers(keys));
|
||||
}
|
||||
|
||||
void JavascriptInvocation::doubleClick(int x, int y) {
|
||||
void JavascriptInvocation::doubleClick(int x, int y, QVariantList keys) {
|
||||
QPoint mousePos(x, y);
|
||||
|
||||
m_page->mouseEvent(QEvent::MouseButtonDblClick, mousePos, Qt::LeftButton);
|
||||
m_page->mouseEvent(QEvent::MouseButtonRelease, mousePos, Qt::LeftButton);
|
||||
m_page->mouseEvent(QEvent::MouseButtonDblClick, mousePos, Qt::LeftButton, modifiers(keys));
|
||||
m_page->mouseEvent(QEvent::MouseButtonRelease, mousePos, Qt::LeftButton, modifiers(keys));
|
||||
}
|
||||
|
||||
bool JavascriptInvocation::clickTest(QWebElement element, int absoluteX, int absoluteY) {
|
||||
|
@ -86,6 +96,8 @@ QVariantMap JavascriptInvocation::clickPosition(QWebElement element, int left, i
|
|||
QVariantMap m;
|
||||
m["relativeX"] = mousePos.x();
|
||||
m["relativeY"] = mousePos.y();
|
||||
m["relativeTop"] = boundedBox.top();
|
||||
m["relativeLeft"] = boundedBox.left();
|
||||
|
||||
QWebFrame *parent = element.webFrame();
|
||||
while (parent) {
|
||||
|
@ -95,7 +107,8 @@ QVariantMap JavascriptInvocation::clickPosition(QWebElement element, int left, i
|
|||
|
||||
boundedBox = elementBox.intersected(viewport);
|
||||
mousePos = boundedBox.center();
|
||||
|
||||
m["absoluteTop"] = boundedBox.top();
|
||||
m["absoluteLeft"] = boundedBox.left();
|
||||
m["absoluteX"] = mousePos.x();
|
||||
m["absoluteY"] = mousePos.y();
|
||||
|
||||
|
@ -217,3 +230,14 @@ const QString JavascriptInvocation::render(void) {
|
|||
m_page->render(path, QSize(1024, 768));
|
||||
return path;
|
||||
}
|
||||
|
||||
QMap<QString, Qt::KeyboardModifiers> JavascriptInvocation::makeModifiersMap(){
|
||||
QMap<QString, Qt::KeyboardModifiers> map;
|
||||
map["alt"] = Qt::AltModifier;
|
||||
map["control"] = Qt::ControlModifier;
|
||||
map["meta"] = Qt::MetaModifier;
|
||||
map["shift"] = Qt::ShiftModifier;
|
||||
return map;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -20,9 +20,9 @@ class JavascriptInvocation : public QObject {
|
|||
QString &functionName();
|
||||
bool allowUnattached();
|
||||
QStringList &arguments();
|
||||
Q_INVOKABLE void leftClick(int x, int y);
|
||||
Q_INVOKABLE void rightClick(int x, int y);
|
||||
Q_INVOKABLE void doubleClick(int x, int y);
|
||||
Q_INVOKABLE void leftClick(int x, int y, QVariantList keys);
|
||||
Q_INVOKABLE void rightClick(int x, int y, QVariantList keys);
|
||||
Q_INVOKABLE void doubleClick(int x, int y, QVariantList keys);
|
||||
Q_INVOKABLE bool clickTest(QWebElement element, int absoluteX, int absoluteY);
|
||||
Q_INVOKABLE QVariantMap clickPosition(QWebElement element, int left, int top, int width, int height);
|
||||
Q_INVOKABLE void hover(int absoluteX, int absoluteY);
|
||||
|
@ -46,5 +46,8 @@ class JavascriptInvocation : public QObject {
|
|||
int keyCodeForName(const QString &);
|
||||
Qt::Key key_enum;
|
||||
Qt::KeyboardModifiers m_currentModifiers;
|
||||
Qt::KeyboardModifiers modifiers(const QVariantList& keys);
|
||||
static QMap<QString, Qt::KeyboardModifiers> makeModifiersMap();
|
||||
static QMap<QString, Qt::KeyboardModifiers> m_modifiersMap;
|
||||
};
|
||||
|
||||
|
|
|
@ -275,9 +275,9 @@ QString WebPage::failureString() {
|
|||
return message + m_errorPageMessage;
|
||||
}
|
||||
|
||||
void WebPage::mouseEvent(QEvent::Type type, const QPoint &position, Qt::MouseButton button) {
|
||||
void WebPage::mouseEvent(QEvent::Type type, const QPoint &position, Qt::MouseButton button, Qt::KeyboardModifiers modifiers) {
|
||||
m_mousePosition = position;
|
||||
QMouseEvent event(type, position, button, button, Qt::NoModifier);
|
||||
QMouseEvent event(type, position, button, button, modifiers);
|
||||
QApplication::sendEvent(this, &event);
|
||||
}
|
||||
|
||||
|
@ -491,5 +491,3 @@ QWebFrame* WebPage::currentFrameParent() {
|
|||
void WebPage::setCurrentFrameParent(QWebFrame* frame) {
|
||||
m_currentFrameParent = frame;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -50,7 +50,7 @@ class WebPage : public QWebPage {
|
|||
QVariantMap pageHeaders();
|
||||
QByteArray body();
|
||||
QString contentType();
|
||||
void mouseEvent(QEvent::Type type, const QPoint &position, Qt::MouseButton button);
|
||||
void mouseEvent(QEvent::Type type, const QPoint &position, Qt::MouseButton button, Qt::KeyboardModifiers modifiers = Qt::NoModifier);
|
||||
bool clickTest(QWebElement element, int absoluteX, int absoluteY);
|
||||
void resize(int, int);
|
||||
int modalCount();
|
||||
|
|
|
@ -7,7 +7,15 @@ Capybara = {
|
|||
invoke: function () {
|
||||
try {
|
||||
if (CapybaraInvocation.functionName == "leftClick") {
|
||||
return this["verifiedClickPosition"].apply(this, CapybaraInvocation.arguments);
|
||||
var args = CapybaraInvocation.arguments;
|
||||
var leftClickOptions = this["verifiedClickPosition"].apply(this, args);
|
||||
leftClickOptions["keys"] = JSON.parse(args[1]);
|
||||
offset = JSON.parse(args[2]);
|
||||
if (offset && offset.x && offset.y){
|
||||
leftClickOptions["absoluteX"] = leftClickOptions["absoluteLeft"] + offset.x;
|
||||
leftClickOptions["absoluteY"] = leftClickOptions["absoluteTop"] + offset.y;
|
||||
}
|
||||
return leftClickOptions;
|
||||
} else {
|
||||
return this[CapybaraInvocation.functionName].apply(this, CapybaraInvocation.arguments);
|
||||
}
|
||||
|
@ -208,22 +216,28 @@ Capybara = {
|
|||
return pos;
|
||||
},
|
||||
|
||||
click: function (index, action) {
|
||||
click: function (index, action, keys, offset) {
|
||||
var pos = this.verifiedClickPosition(index);
|
||||
action(pos.absoluteX, pos.absoluteY);
|
||||
keys = keys ? JSON.parse(keys) : [];
|
||||
offset = offset ? JSON.parse(offset) : {};
|
||||
if (offset && (offset.x != null) && (offset.y != null)){
|
||||
action(pos.absoluteLeft + offset.x, pos.absoluteTop + offset.y, keys);
|
||||
} else {
|
||||
action(pos.absoluteX, pos.absoluteY, keys);
|
||||
}
|
||||
},
|
||||
|
||||
leftClick: function (index) {
|
||||
this.click(index, CapybaraInvocation.leftClick);
|
||||
leftClick: function (index, keys, offset) {
|
||||
this.click(index, CapybaraInvocation.leftClick, keys, offset);
|
||||
},
|
||||
|
||||
doubleClick: function(index) {
|
||||
this.click(index, CapybaraInvocation.leftClick);
|
||||
this.click(index, CapybaraInvocation.doubleClick);
|
||||
doubleClick: function(index, keys, offset) {
|
||||
this.click(index, CapybaraInvocation.leftClick, keys, offset);
|
||||
this.click(index, CapybaraInvocation.doubleClick, keys, offset);
|
||||
},
|
||||
|
||||
rightClick: function(index) {
|
||||
this.click(index, CapybaraInvocation.rightClick);
|
||||
rightClick: function(index, keys, offset) {
|
||||
this.click(index, CapybaraInvocation.rightClick, keys, offset);
|
||||
},
|
||||
|
||||
hover: function (index) {
|
||||
|
|
Loading…
Reference in New Issue