capybara-webkit 0.14.2 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (111) hide show
  1. data/.gitignore +2 -0
  2. data/.travis.yml +21 -0
  3. data/Appraisals +4 -4
  4. data/CONTRIBUTING.md +14 -3
  5. data/Gemfile +1 -1
  6. data/Gemfile.lock +27 -19
  7. data/NEWS.md +15 -0
  8. data/README.md +126 -76
  9. data/Vagrantfile +7 -0
  10. data/capybara-webkit.gemspec +3 -0
  11. data/gemfiles/2.0.gemfile +7 -0
  12. data/gemfiles/2.0.gemfile.lock +72 -0
  13. data/gemfiles/2.1.gemfile +7 -0
  14. data/gemfiles/2.1.gemfile.lock +71 -0
  15. data/lib/capybara/webkit/browser.rb +22 -22
  16. data/lib/capybara/webkit/connection.rb +9 -6
  17. data/lib/capybara/webkit/driver.rb +22 -6
  18. data/lib/capybara/webkit/errors.rb +25 -0
  19. data/lib/capybara/webkit/node.rb +36 -10
  20. data/lib/capybara/webkit/version.rb +1 -1
  21. data/spec/browser_spec.rb +16 -1
  22. data/spec/capybara_webkit_builder_spec.rb +9 -3
  23. data/spec/connection_spec.rb +19 -3
  24. data/spec/driver_spec.rb +324 -144
  25. data/spec/errors_spec.rb +11 -0
  26. data/spec/integration/session_spec.rb +244 -0
  27. data/spec/selenium_compatibility_spec.rb +3 -1
  28. data/spec/spec_helper.rb +1 -9
  29. data/src/Authenticate.cpp +3 -2
  30. data/src/ClearCookies.cpp +1 -1
  31. data/src/ClearPromptText.cpp +1 -1
  32. data/src/Command.cpp +8 -4
  33. data/src/Command.h +7 -4
  34. data/src/CommandFactory.cpp +4 -2
  35. data/src/CommandParser.cpp +1 -1
  36. data/src/Connection.cpp +4 -4
  37. data/src/ConsoleMessages.cpp +1 -1
  38. data/src/CurrentUrl.cpp +2 -2
  39. data/src/EnableLogging.cpp +1 -1
  40. data/src/ErrorMessage.cpp +26 -0
  41. data/src/ErrorMessage.h +21 -0
  42. data/src/Evaluate.cpp +1 -1
  43. data/src/Execute.cpp +3 -2
  44. data/src/FindCss.cpp +13 -0
  45. data/src/FindCss.h +11 -0
  46. data/src/FindXpath.cpp +13 -0
  47. data/src/FindXpath.h +11 -0
  48. data/src/FrameFocus.cpp +4 -3
  49. data/src/GetCookies.cpp +1 -1
  50. data/src/GetTimeout.cpp +1 -1
  51. data/src/GetWindowHandle.cpp +1 -1
  52. data/src/GetWindowHandles.cpp +1 -1
  53. data/src/Header.cpp +2 -2
  54. data/src/Headers.cpp +1 -6
  55. data/src/IgnoreSslErrors.cpp +1 -1
  56. data/src/InvocationResult.cpp +29 -0
  57. data/src/InvocationResult.h +16 -0
  58. data/src/JavascriptAlertMessages.cpp +1 -1
  59. data/src/JavascriptCommand.cpp +15 -0
  60. data/src/JavascriptCommand.h +20 -0
  61. data/src/JavascriptConfirmMessages.cpp +1 -1
  62. data/src/JavascriptInvocation.cpp +128 -1
  63. data/src/JavascriptInvocation.h +22 -1
  64. data/src/JavascriptPromptMessages.cpp +1 -1
  65. data/src/NetworkAccessManager.cpp +8 -16
  66. data/src/NetworkAccessManager.h +5 -11
  67. data/src/NetworkReplyProxy.cpp +91 -0
  68. data/src/NetworkReplyProxy.h +65 -0
  69. data/src/Node.cpp +4 -4
  70. data/src/Node.h +2 -2
  71. data/src/NullCommand.cpp +2 -1
  72. data/src/PageLoadingCommand.cpp +2 -1
  73. data/src/Render.cpp +1 -1
  74. data/src/Reset.cpp +1 -1
  75. data/src/ResizeWindow.cpp +1 -1
  76. data/src/Response.cpp +7 -0
  77. data/src/Response.h +8 -3
  78. data/src/SetConfirmAction.cpp +1 -1
  79. data/src/SetCookie.cpp +2 -2
  80. data/src/SetPromptAction.cpp +1 -1
  81. data/src/SetPromptText.cpp +1 -1
  82. data/src/SetProxy.cpp +2 -2
  83. data/src/SetSkipImageLoading.cpp +1 -1
  84. data/src/SetTimeout.cpp +3 -2
  85. data/src/SetUrlBlacklist.cpp +2 -2
  86. data/src/Status.cpp +1 -1
  87. data/src/TimeoutCommand.cpp +4 -2
  88. data/src/Title.cpp +11 -0
  89. data/src/Title.h +9 -0
  90. data/src/Version.cpp +13 -0
  91. data/src/Version.h +10 -0
  92. data/src/Visit.cpp +1 -1
  93. data/src/WebPage.cpp +49 -27
  94. data/src/WebPage.h +14 -7
  95. data/src/WebPageManager.cpp +10 -1
  96. data/src/WebPageManager.h +4 -1
  97. data/src/WindowFocus.cpp +3 -2
  98. data/src/body.cpp +3 -6
  99. data/src/capybara.js +103 -101
  100. data/src/find_command.h +4 -2
  101. data/src/main.cpp +1 -1
  102. data/src/stable.h +39 -0
  103. data/src/webkit_server.pro +26 -6
  104. data/vagrant_setup.sh +58 -0
  105. metadata +51 -78
  106. data/gemfiles/1.0.gemfile +0 -7
  107. data/gemfiles/1.0.gemfile.lock +0 -70
  108. data/gemfiles/1.1.gemfile +0 -7
  109. data/gemfiles/1.1.gemfile.lock +0 -70
  110. data/src/Find.cpp +0 -20
  111. data/src/Find.h +0 -11
data/src/Connection.cpp CHANGED
@@ -6,6 +6,7 @@
6
6
  #include "PageLoadingCommand.h"
7
7
  #include "TimeoutCommand.h"
8
8
  #include "SocketCommand.h"
9
+ #include "ErrorMessage.h"
9
10
 
10
11
  #include <QTcpSocket>
11
12
 
@@ -43,9 +44,8 @@ void Connection::pendingLoadFinished(bool success) {
43
44
  void Connection::writePageLoadFailure() {
44
45
  m_pageSuccess = true;
45
46
  QString message = currentPage()->failureString();
46
- Response *response = new Response(false, message, this);
47
- writeResponse(response);
48
- delete response;
47
+ Response response(false, new ErrorMessage(message));
48
+ writeResponse(&response);
49
49
  }
50
50
 
51
51
  void Connection::finishCommand(Response *response) {
@@ -64,7 +64,7 @@ void Connection::writeResponse(Response *response) {
64
64
 
65
65
  QByteArray messageUtf8 = response->message();
66
66
  QString messageLength = QString::number(messageUtf8.size()) + "\n";
67
- m_socket->write(messageLength.toAscii());
67
+ m_socket->write(messageLength.toLatin1());
68
68
  m_socket->write(messageUtf8);
69
69
  }
70
70
 
@@ -9,6 +9,6 @@ ConsoleMessages::ConsoleMessages(WebPageManager *manager, QStringList &arguments
9
9
  void ConsoleMessages::start() {
10
10
  JsonSerializer serializer;
11
11
  QByteArray json = serializer.serialize(page()->consoleMessages());
12
- emitFinished(true, json);
12
+ finish(true, json);
13
13
  }
14
14
 
data/src/CurrentUrl.cpp CHANGED
@@ -7,8 +7,8 @@ CurrentUrl::CurrentUrl(WebPageManager *manager, QStringList &arguments, QObject
7
7
 
8
8
  void CurrentUrl::start() {
9
9
  QStringList arguments;
10
- QVariant result = page()->invokeCapybaraFunction("currentUrl", arguments);
10
+ QVariant result = page()->currentFrame()->evaluateJavaScript("window.location.toString()");
11
11
  QString url = result.toString();
12
- emitFinished(true, url);
12
+ finish(true, url);
13
13
  }
14
14
 
@@ -6,5 +6,5 @@ EnableLogging::EnableLogging(WebPageManager *manager, QStringList &arguments, QO
6
6
 
7
7
  void EnableLogging::start() {
8
8
  manager()->enableLogging();
9
- emitFinished(true);
9
+ finish(true);
10
10
  }
@@ -0,0 +1,26 @@
1
+ #include "ErrorMessage.h"
2
+ #include "JsonSerializer.h"
3
+
4
+ ErrorMessage::ErrorMessage(QString message, QObject *parent) : QObject(parent) {
5
+ m_message = message;
6
+ }
7
+
8
+ ErrorMessage::ErrorMessage(QString type, QString message, QObject *parent) : QObject(parent) {
9
+ m_type = type;
10
+ m_message = message;
11
+ }
12
+
13
+ QByteArray ErrorMessage::toString() {
14
+ JsonSerializer serializer;
15
+
16
+ QVariantMap map;
17
+
18
+ if (m_type.isNull())
19
+ map["class"] = "InvalidResponseError";
20
+ else
21
+ map["class"] = m_type;
22
+
23
+ map["message"] = m_message;
24
+
25
+ return serializer.serialize(map);
26
+ }
@@ -0,0 +1,21 @@
1
+ #ifndef __ERROR_MESSAGE_H
2
+ #define __ERROR_MESSAGE_H
3
+
4
+ #include <QObject>
5
+ #include <QString>
6
+ #include <QByteArray>
7
+
8
+ class ErrorMessage : public QObject {
9
+ Q_OBJECT
10
+
11
+ public:
12
+ ErrorMessage(QString message, QObject *parent = 0);
13
+ ErrorMessage(QString type, QString message, QObject *parent = 0);
14
+ QByteArray toString();
15
+
16
+ private:
17
+ QString m_type;
18
+ QString m_message;
19
+ };
20
+
21
+ #endif
data/src/Evaluate.cpp CHANGED
@@ -10,5 +10,5 @@ Evaluate::Evaluate(WebPageManager *manager, QStringList &arguments, QObject *par
10
10
  void Evaluate::start() {
11
11
  QVariant result = page()->currentFrame()->evaluateJavaScript(arguments()[0]);
12
12
  JsonSerializer serializer;
13
- emitFinished(true, serializer.serialize(result));
13
+ finish(true, serializer.serialize(result));
14
14
  }
data/src/Execute.cpp CHANGED
@@ -1,6 +1,7 @@
1
1
  #include "Execute.h"
2
2
  #include "WebPage.h"
3
3
  #include "WebPageManager.h"
4
+ #include "ErrorMessage.h"
4
5
 
5
6
  Execute::Execute(WebPageManager *manager, QStringList &arguments, QObject *parent) : SocketCommand(manager, arguments, parent) {
6
7
  }
@@ -9,9 +10,9 @@ void Execute::start() {
9
10
  QString script = arguments()[0] + QString("; 'success'");
10
11
  QVariant result = page()->currentFrame()->evaluateJavaScript(script);
11
12
  if (result.isValid()) {
12
- emitFinished(true);
13
+ finish(true);
13
14
  } else {
14
- emitFinished(false, QString("Javascript failed to execute"));
15
+ finish(false, new ErrorMessage("Javascript failed to execute"));
15
16
  }
16
17
  }
17
18
 
data/src/FindCss.cpp ADDED
@@ -0,0 +1,13 @@
1
+ #include "FindCss.h"
2
+ #include "WebPage.h"
3
+ #include "WebPageManager.h"
4
+ #include "InvocationResult.h"
5
+
6
+ FindCss::FindCss(WebPageManager *manager, QStringList &arguments, QObject *parent) : JavascriptCommand(manager, arguments, parent) {
7
+ }
8
+
9
+ void FindCss::start() {
10
+ InvocationResult result = page()->invokeCapybaraFunction("findCss", arguments());
11
+ finish(&result);
12
+ }
13
+
data/src/FindCss.h ADDED
@@ -0,0 +1,11 @@
1
+ #include "JavascriptCommand.h"
2
+
3
+ class FindCss : public JavascriptCommand {
4
+ Q_OBJECT
5
+
6
+ public:
7
+ FindCss(WebPageManager *, QStringList &arguments, QObject *parent = 0);
8
+ virtual void start();
9
+ };
10
+
11
+
data/src/FindXpath.cpp ADDED
@@ -0,0 +1,13 @@
1
+ #include "FindXpath.h"
2
+ #include "WebPage.h"
3
+ #include "WebPageManager.h"
4
+ #include "InvocationResult.h"
5
+
6
+ FindXpath::FindXpath(WebPageManager *manager, QStringList &arguments, QObject *parent) : JavascriptCommand(manager, arguments, parent) {
7
+ }
8
+
9
+ void FindXpath::start() {
10
+ InvocationResult result = page()->invokeCapybaraFunction("findXpath", arguments());
11
+ finish(&result);
12
+ }
13
+
data/src/FindXpath.h ADDED
@@ -0,0 +1,11 @@
1
+ #include "JavascriptCommand.h"
2
+
3
+ class FindXpath : public JavascriptCommand {
4
+ Q_OBJECT
5
+
6
+ public:
7
+ FindXpath(WebPageManager *, QStringList &arguments, QObject *parent = 0);
8
+ virtual void start();
9
+ };
10
+
11
+
data/src/FrameFocus.cpp CHANGED
@@ -2,6 +2,7 @@
2
2
  #include "SocketCommand.h"
3
3
  #include "WebPage.h"
4
4
  #include "WebPageManager.h"
5
+ #include "ErrorMessage.h"
5
6
 
6
7
  FrameFocus::FrameFocus(WebPageManager *manager, QStringList &arguments, QObject *parent) : SocketCommand(manager, arguments, parent) {
7
8
  }
@@ -51,7 +52,7 @@ void FrameFocus::focusId(QString name) {
51
52
 
52
53
  void FrameFocus::focusParent() {
53
54
  if (page()->currentFrame()->parentFrame() == 0) {
54
- emitFinished(false, QString("Already at parent frame."));
55
+ finish(false, new ErrorMessage("Already at parent frame."));
55
56
  } else {
56
57
  page()->currentFrame()->parentFrame()->setFocus();
57
58
  success();
@@ -59,9 +60,9 @@ void FrameFocus::focusParent() {
59
60
  }
60
61
 
61
62
  void FrameFocus::frameNotFound() {
62
- emitFinished(false, QString("Unable to locate frame. "));
63
+ finish(false, new ErrorMessage("Unable to locate frame."));
63
64
  }
64
65
 
65
66
  void FrameFocus::success() {
66
- emitFinished(true);
67
+ finish(true);
67
68
  }
data/src/GetCookies.cpp CHANGED
@@ -15,5 +15,5 @@ void GetCookies::start()
15
15
  m_buffer.append(cookie.toRawForm());
16
16
  m_buffer.append("\n");
17
17
  }
18
- emitFinished(true, m_buffer);
18
+ finish(true, m_buffer);
19
19
  }
data/src/GetTimeout.cpp CHANGED
@@ -5,5 +5,5 @@ GetTimeout::GetTimeout(WebPageManager *manager, QStringList &arguments, QObject
5
5
  }
6
6
 
7
7
  void GetTimeout::start() {
8
- emitFinished(true, QString::number(manager()->getTimeout()));
8
+ finish(true, QString::number(manager()->getTimeout()));
9
9
  }
@@ -7,5 +7,5 @@ GetWindowHandle::GetWindowHandle(WebPageManager *manager, QStringList &arguments
7
7
  }
8
8
 
9
9
  void GetWindowHandle::start() {
10
- emitFinished(true, page()->uuid());
10
+ finish(true, page()->uuid());
11
11
  }
@@ -17,5 +17,5 @@ void GetWindowHandles::start() {
17
17
  JsonSerializer serializer;
18
18
  QByteArray json = serializer.serialize(handles);
19
19
 
20
- emitFinished(true, json);
20
+ finish(true, json);
21
21
  }
data/src/Header.cpp CHANGED
@@ -9,11 +9,11 @@ Header::Header(WebPageManager *manager, QStringList &arguments, QObject *parent)
9
9
  void Header::start() {
10
10
  QString key = arguments()[0];
11
11
  QString value = arguments()[1];
12
- NetworkAccessManager* networkAccessManager = page()->networkAccessManager();
12
+ NetworkAccessManager* networkAccessManager = manager()->networkAccessManager();
13
13
  if (key.toLower().replace("-", "_") == "user_agent") {
14
14
  page()->setUserAgent(value);
15
15
  } else {
16
16
  networkAccessManager->addHeader(key, value);
17
17
  }
18
- emitFinished(true);
18
+ finish(true);
19
19
  }
data/src/Headers.cpp CHANGED
@@ -6,11 +6,6 @@ Headers::Headers(WebPageManager *manager, QStringList &arguments, QObject *paren
6
6
  }
7
7
 
8
8
  void Headers::start() {
9
- QStringList headers;
10
-
11
- foreach(QNetworkReply::RawHeaderPair header, page()->pageHeaders())
12
- headers << header.first+": "+header.second;
13
-
14
- emitFinished(true, headers.join("\n"));
9
+ finish(true, page()->pageHeaders().join("\n"));
15
10
  }
16
11
 
@@ -8,6 +8,6 @@ IgnoreSslErrors::IgnoreSslErrors(WebPageManager *manager, QStringList &arguments
8
8
 
9
9
  void IgnoreSslErrors::start() {
10
10
  manager()->setIgnoreSslErrors(true);
11
- emitFinished(true);
11
+ finish(true);
12
12
  }
13
13
 
@@ -0,0 +1,29 @@
1
+ #include "InvocationResult.h"
2
+ #include "ErrorMessage.h"
3
+
4
+ InvocationResult::InvocationResult(QVariant result, bool error) {
5
+ m_result = result;
6
+ m_error = error;
7
+ }
8
+
9
+ const QVariant &InvocationResult::result() const {
10
+ return m_result;
11
+ }
12
+
13
+ bool InvocationResult::hasError() {
14
+ return m_error;
15
+ }
16
+
17
+ ErrorMessage *InvocationResult::errorMessage() {
18
+ if (!m_result.canConvert<QVariantMap>())
19
+ return new ErrorMessage(m_result.toString());
20
+
21
+ QVariantMap error = m_result.toMap();
22
+
23
+ QString message = error["message"].toString();
24
+
25
+ if (error["name"] == "Capybara.ClickFailed")
26
+ return new ErrorMessage("ClickFailed", message);
27
+ else
28
+ return new ErrorMessage(message);
29
+ }
@@ -0,0 +1,16 @@
1
+ #include <QVariant>
2
+
3
+ class ErrorMessage;
4
+
5
+ class InvocationResult {
6
+ public:
7
+ InvocationResult(QVariant result, bool error = false);
8
+ const QVariant &result() const;
9
+ bool hasError();
10
+ ErrorMessage *errorMessage();
11
+
12
+ private:
13
+ QVariant m_result;
14
+ bool m_error;
15
+ };
16
+
@@ -9,5 +9,5 @@ void JavascriptAlertMessages::start()
9
9
  {
10
10
  JsonSerializer serializer;
11
11
  QByteArray json = serializer.serialize(page()->alertMessages());
12
- emitFinished(true, json);
12
+ finish(true, json);
13
13
  }
@@ -0,0 +1,15 @@
1
+ #include "JavascriptCommand.h"
2
+ #include "WebPageManager.h"
3
+ #include "InvocationResult.h"
4
+
5
+ JavascriptCommand::JavascriptCommand(WebPageManager *manager, QStringList &arguments, QObject *parent) : SocketCommand(manager, arguments, parent) {
6
+ }
7
+
8
+ void JavascriptCommand::finish(InvocationResult *result) {
9
+ if (result->hasError())
10
+ SocketCommand::finish(false, result->errorMessage());
11
+ else {
12
+ QString message = result->result().toString();
13
+ SocketCommand::finish(true, message);
14
+ }
15
+ }
@@ -0,0 +1,20 @@
1
+ #ifndef JAVASCRIPT_COMMAND_H
2
+ #define JAVASCRIPT_COMMAND_H
3
+
4
+ #include <QObject>
5
+ #include <QStringList>
6
+ #include "SocketCommand.h"
7
+
8
+ class WebPage;
9
+ class WebPageManager;
10
+ class InvocationResult;
11
+
12
+ class JavascriptCommand : public SocketCommand {
13
+ Q_OBJECT
14
+
15
+ public:
16
+ JavascriptCommand(WebPageManager *, QStringList &arguments, QObject *parent = 0);
17
+ void finish(InvocationResult *result);
18
+ };
19
+
20
+ #endif
@@ -9,5 +9,5 @@ void JavascriptConfirmMessages::start()
9
9
  {
10
10
  JsonSerializer serializer;
11
11
  QByteArray json = serializer.serialize(page()->confirmMessages());
12
- emitFinished(true, json);
12
+ finish(true, json);
13
13
  }
@@ -1,8 +1,14 @@
1
1
  #include "JavascriptInvocation.h"
2
+ #include "WebPage.h"
3
+ #include "InvocationResult.h"
4
+ #include <QApplication>
5
+ #include <QEvent>
6
+ #include <QContextMenuEvent>
2
7
 
3
- JavascriptInvocation::JavascriptInvocation(const QString &functionName, const QStringList &arguments, QObject *parent) : QObject(parent) {
8
+ JavascriptInvocation::JavascriptInvocation(const QString &functionName, const QStringList &arguments, WebPage *page, QObject *parent) : QObject(parent) {
4
9
  m_functionName = functionName;
5
10
  m_arguments = arguments;
11
+ m_page = page;
6
12
  }
7
13
 
8
14
  QString &JavascriptInvocation::functionName() {
@@ -12,3 +18,124 @@ QString &JavascriptInvocation::functionName() {
12
18
  QStringList &JavascriptInvocation::arguments() {
13
19
  return m_arguments;
14
20
  }
21
+
22
+ QVariant JavascriptInvocation::getError() {
23
+ return m_error;
24
+ }
25
+
26
+ void JavascriptInvocation::setError(QVariant error) {
27
+ m_error = error;
28
+ }
29
+
30
+ InvocationResult JavascriptInvocation::invoke(QWebFrame *frame) {
31
+ frame->addToJavaScriptWindowObject("CapybaraInvocation", this);
32
+ QVariant result = frame->evaluateJavaScript("Capybara.invoke()");
33
+ if (getError().isValid())
34
+ return InvocationResult(getError(), true);
35
+ else
36
+ return InvocationResult(result);
37
+ }
38
+
39
+ void JavascriptInvocation::leftClick(int x, int y) {
40
+ QPoint mousePos(x, y);
41
+
42
+ hover(mousePos);
43
+ JavascriptInvocation::mouseEvent(QEvent::MouseButtonPress, mousePos, Qt::LeftButton);
44
+ JavascriptInvocation::mouseEvent(QEvent::MouseButtonRelease, mousePos, Qt::LeftButton);
45
+ }
46
+
47
+ void JavascriptInvocation::rightClick(int x, int y) {
48
+ QPoint mousePos(x, y);
49
+
50
+ hover(mousePos);
51
+ JavascriptInvocation::mouseEvent(QEvent::MouseButtonPress, mousePos, Qt::RightButton);
52
+
53
+ // swallowContextMenuEvent tries to fire contextmenu event in html page
54
+ QContextMenuEvent *event = new QContextMenuEvent(QContextMenuEvent::Mouse, mousePos);
55
+ m_page->swallowContextMenuEvent(event);
56
+
57
+ JavascriptInvocation::mouseEvent(QEvent::MouseButtonRelease, mousePos, Qt::RightButton);
58
+ }
59
+
60
+ void JavascriptInvocation::doubleClick(int x, int y) {
61
+ QPoint mousePos(x, y);
62
+
63
+ JavascriptInvocation::mouseEvent(QEvent::MouseButtonDblClick, mousePos, Qt::LeftButton);
64
+ JavascriptInvocation::mouseEvent(QEvent::MouseButtonRelease, mousePos, Qt::LeftButton);
65
+ }
66
+
67
+ void JavascriptInvocation::mouseEvent(QEvent::Type type, const QPoint &position, Qt::MouseButton button) {
68
+ QMouseEvent event(type, position, button, button, Qt::NoModifier);
69
+ QApplication::sendEvent(m_page, &event);
70
+ }
71
+
72
+ bool JavascriptInvocation::clickTest(QWebElement element, int absoluteX, int absoluteY) {
73
+ QPoint mousePos(absoluteX, absoluteY);
74
+ QWebHitTestResult res = m_page->mainFrame()->hitTestContent(mousePos);
75
+ return res.frame() == element.webFrame();
76
+ }
77
+
78
+ QVariantMap JavascriptInvocation::clickPosition(QWebElement element, int left, int top, int width, int height) {
79
+ QRect elementBox(left, top, width, height);
80
+ QRect viewport(QPoint(0, 0), m_page->viewportSize());
81
+ QRect boundedBox = elementBox.intersected(viewport);
82
+ QPoint mousePos = boundedBox.center();
83
+
84
+ QVariantMap m;
85
+ m["relativeX"] = mousePos.x();
86
+ m["relativeY"] = mousePos.y();
87
+
88
+ QWebFrame *parent = element.webFrame();
89
+ while (parent) {
90
+ elementBox.translate(parent->geometry().topLeft());
91
+ parent = parent->parentFrame();
92
+ }
93
+
94
+ boundedBox = elementBox.intersected(viewport);
95
+ mousePos = boundedBox.center();
96
+
97
+ m["absoluteX"] = mousePos.x();
98
+ m["absoluteY"] = mousePos.y();
99
+
100
+ return m;
101
+ }
102
+
103
+ void JavascriptInvocation::hover(int absoluteX, int absoluteY) {
104
+ QPoint mousePos(absoluteX, absoluteY);
105
+ hover(mousePos);
106
+ }
107
+
108
+ void JavascriptInvocation::hover(const QPoint &mousePos) {
109
+ mouseEvent(QEvent::MouseMove, mousePos, Qt::NoButton);
110
+ }
111
+
112
+ int JavascriptInvocation::keyCodeFor(const QChar &key) {
113
+ switch(key.unicode()) {
114
+ case 0x18:
115
+ return Qt::Key_Cancel;
116
+ case 0x08:
117
+ return Qt::Key_Backspace;
118
+ case 0x09:
119
+ return Qt::Key_Tab;
120
+ case 0x0A:
121
+ return Qt::Key_Return;
122
+ case 0x1B:
123
+ return Qt::Key_Escape;
124
+ case 0x7F:
125
+ return Qt::Key_Delete;
126
+ default:
127
+ int keyCode = key.toUpper().toLatin1();
128
+ if (keyCode >= Qt::Key_Space || keyCode <= Qt::Key_AsciiTilde)
129
+ return keyCode;
130
+ else
131
+ return Qt::Key_unknown;
132
+ }
133
+ }
134
+
135
+ void JavascriptInvocation::keypress(QChar key) {
136
+ int keyCode = keyCodeFor(key);
137
+ QKeyEvent event(QKeyEvent::KeyPress, keyCode, Qt::NoModifier, key);
138
+ QApplication::sendEvent(m_page, &event);
139
+ event = QKeyEvent(QKeyEvent::KeyRelease, keyCode, Qt::NoModifier, key);
140
+ QApplication::sendEvent(m_page, &event);
141
+ }