From fe6eff79e6a029a391f002902907bcccd8a7ca7e Mon Sep 17 00:00:00 2001 From: Matthew Horan Date: Sun, 20 Jan 2013 18:57:04 -0500 Subject: [PATCH] JavaScript error handling --- src/CurrentUrl.cpp | 2 +- src/Find.cpp | 16 ++++++++-------- src/InvocationResult.cpp | 14 ++++++++++++++ src/InvocationResult.h | 13 +++++++++++++ src/JavascriptInvocation.cpp | 18 ++++++++++++++++++ src/JavascriptInvocation.h | 7 ++++++- src/Node.cpp | 9 +++++++-- src/WebPage.cpp | 10 ++++------ src/WebPage.h | 5 +++-- src/capybara.js | 10 +++++----- src/webkit_server.pro | 6 ++++-- 11 files changed, 83 insertions(+), 27 deletions(-) create mode 100644 src/InvocationResult.cpp create mode 100644 src/InvocationResult.h diff --git a/src/CurrentUrl.cpp b/src/CurrentUrl.cpp index d66e812..548e9c9 100644 --- a/src/CurrentUrl.cpp +++ b/src/CurrentUrl.cpp @@ -7,7 +7,7 @@ CurrentUrl::CurrentUrl(WebPageManager *manager, QStringList &arguments, QObject void CurrentUrl::start() { QStringList arguments; - QVariant result = page()->invokeCapybaraFunction("currentUrl", arguments); + QVariant result = page()->currentFrame()->evaluateJavaScript("window.location.toString()"); QString url = result.toString(); emitFinished(true, url); } diff --git a/src/Find.cpp b/src/Find.cpp index 82f7286..e311268 100644 --- a/src/Find.cpp +++ b/src/Find.cpp @@ -2,19 +2,19 @@ #include "SocketCommand.h" #include "WebPage.h" #include "WebPageManager.h" +#include "InvocationResult.h" Find::Find(WebPageManager *manager, QStringList &arguments, QObject *parent) : SocketCommand(manager, arguments, parent) { } void Find::start() { - QString message; - QVariant result = page()->invokeCapybaraFunction("find", arguments()); + InvocationResult result = page()->invokeCapybaraFunction("find", arguments()); - if (result.isValid()) { - message = result.toString(); - emitFinished(true, message); - } else { - emitFinished(false, QString("Invalid XPath expression")); - } + if (result.hasError()) + return emitFinished(false, QString("Invalid XPath expression")); + + QString message; + message = result.result().toString(); + emitFinished(true, message); } diff --git a/src/InvocationResult.cpp b/src/InvocationResult.cpp new file mode 100644 index 0000000..8fb6d0b --- /dev/null +++ b/src/InvocationResult.cpp @@ -0,0 +1,14 @@ +#include "InvocationResult.h" + +InvocationResult::InvocationResult(QVariant result, bool error) { + m_result = result; + m_error = error; +} + +const QVariant &InvocationResult::result() const { + return m_result; +} + +bool InvocationResult::hasError() { + return m_error; +} diff --git a/src/InvocationResult.h b/src/InvocationResult.h new file mode 100644 index 0000000..f88c5d2 --- /dev/null +++ b/src/InvocationResult.h @@ -0,0 +1,13 @@ +#include + +class InvocationResult { + public: + InvocationResult(QVariant result, bool error = false); + const QVariant &result() const; + bool hasError(); + + private: + QVariant m_result; + bool m_error; +}; + diff --git a/src/JavascriptInvocation.cpp b/src/JavascriptInvocation.cpp index 7764036..7554e4d 100644 --- a/src/JavascriptInvocation.cpp +++ b/src/JavascriptInvocation.cpp @@ -1,5 +1,6 @@ #include "JavascriptInvocation.h" #include "WebPage.h" +#include "InvocationResult.h" #include JavascriptInvocation::JavascriptInvocation(const QString &functionName, const QStringList &arguments, WebPage *page, QObject *parent) : QObject(parent) { @@ -16,6 +17,23 @@ QStringList &JavascriptInvocation::arguments() { return m_arguments; } +QVariantMap JavascriptInvocation::getError() { + return m_error; +} + +void JavascriptInvocation::setError(QVariantMap error) { + m_error = error; +} + +InvocationResult JavascriptInvocation::invoke(QWebFrame *frame) { + frame->addToJavaScriptWindowObject("CapybaraInvocation", this); + QVariant result = frame->evaluateJavaScript("Capybara.invoke()"); + if (getError().isEmpty()) + return InvocationResult(result); + else + return InvocationResult(getError(), true); +} + bool JavascriptInvocation::click(QWebElement element, int left, int top, int width, int height) { QRect elementBox(left, top, width, height); QRect viewport(QPoint(0, 0), m_page->viewportSize()); diff --git a/src/JavascriptInvocation.h b/src/JavascriptInvocation.h index 8cb3ca0..ae31784 100644 --- a/src/JavascriptInvocation.h +++ b/src/JavascriptInvocation.h @@ -4,23 +4,28 @@ #include class WebPage; +class InvocationResult; class JavascriptInvocation : public QObject { Q_OBJECT Q_PROPERTY(QString functionName READ functionName) Q_PROPERTY(QStringList arguments READ arguments) + Q_PROPERTY(QVariantMap error READ getError WRITE setError) public: 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); + QVariantMap getError(); + void setError(QVariantMap error); + InvocationResult invoke(QWebFrame *); private: QString m_functionName; QStringList m_arguments; WebPage *m_page; void execClick(QPoint mousePos); - + QVariantMap m_error; }; diff --git a/src/Node.cpp b/src/Node.cpp index 5b4cbd0..c5b981e 100644 --- a/src/Node.cpp +++ b/src/Node.cpp @@ -1,6 +1,7 @@ #include "Node.h" #include "WebPage.h" #include "WebPageManager.h" +#include "InvocationResult.h" Node::Node(WebPageManager *manager, QStringList &arguments, QObject *parent) : SocketCommand(manager, arguments, parent) { } @@ -8,8 +9,12 @@ Node::Node(WebPageManager *manager, QStringList &arguments, QObject *parent) : S void Node::start() { QStringList functionArguments(arguments()); QString functionName = functionArguments.takeFirst(); - QVariant result = page()->invokeCapybaraFunction(functionName, functionArguments); - QString attributeValue = result.toString(); + InvocationResult result = page()->invokeCapybaraFunction(functionName, functionArguments); + + if (result.hasError()) + return emitFinished(false); + + QString attributeValue = result.result().toString(); emitFinished(true, attributeValue); } diff --git a/src/WebPage.cpp b/src/WebPage.cpp index f9af911..eee3a56 100644 --- a/src/WebPage.cpp +++ b/src/WebPage.cpp @@ -4,6 +4,7 @@ #include "NetworkAccessManager.h" #include "NetworkCookieJar.h" #include "UnsupportedContentHandler.h" +#include "InvocationResult.h" #include #include #include @@ -117,16 +118,13 @@ bool WebPage::shouldInterruptJavaScript() { return false; } -QVariant WebPage::invokeCapybaraFunction(const char *name, const QStringList &arguments) { +InvocationResult WebPage::invokeCapybaraFunction(const char *name, const QStringList &arguments) { QString qname(name); - QString objectName("CapybaraInvocation"); JavascriptInvocation invocation(qname, arguments, this); - currentFrame()->addToJavaScriptWindowObject(objectName, &invocation); - QString javascript = QString("Capybara.invoke()"); - return currentFrame()->evaluateJavaScript(javascript); + return invocation.invoke(currentFrame()); } -QVariant WebPage::invokeCapybaraFunction(QString &name, const QStringList &arguments) { +InvocationResult WebPage::invokeCapybaraFunction(QString &name, const QStringList &arguments) { return invokeCapybaraFunction(name.toAscii().data(), arguments); } diff --git a/src/WebPage.h b/src/WebPage.h index 1460aac..6b402fc 100644 --- a/src/WebPage.h +++ b/src/WebPage.h @@ -4,14 +4,15 @@ class WebPageManager; class NetworkAccessManager; +class InvocationResult; class WebPage : public QWebPage { Q_OBJECT public: WebPage(WebPageManager *, QObject *parent = 0); - QVariant invokeCapybaraFunction(const char *name, const QStringList &arguments); - QVariant invokeCapybaraFunction(QString &name, const QStringList &arguments); + InvocationResult invokeCapybaraFunction(const char *name, const QStringList &arguments); + InvocationResult invokeCapybaraFunction(QString &name, const QStringList &arguments); QString failureString(); QString userAgentForUrl(const QUrl &url ) const; void setUserAgent(QString userAgent); diff --git a/src/capybara.js b/src/capybara.js index d634c1b..ed479a4 100644 --- a/src/capybara.js +++ b/src/capybara.js @@ -4,17 +4,17 @@ Capybara = { attachedFiles: [], invoke: function () { - return this[CapybaraInvocation.functionName].apply(this, CapybaraInvocation.arguments); + try { + return this[CapybaraInvocation.functionName].apply(this, CapybaraInvocation.arguments); + } catch (e) { + CapybaraInvocation.error = e; + } }, find: function (xpath) { return this.findRelativeTo(document, xpath); }, - currentUrl: function () { - return window.location.toString(); - }, - findWithin: function (index, xpath) { return this.findRelativeTo(this.nodes[index], xpath); }, diff --git a/src/webkit_server.pro b/src/webkit_server.pro index 8a8a235..f9a2edc 100644 --- a/src/webkit_server.pro +++ b/src/webkit_server.pro @@ -56,7 +56,8 @@ HEADERS = \ TimeoutCommand.h \ SetUrlBlacklist.h \ NoOpReply.h \ - JsonSerializer.h + JsonSerializer.h \ + InvocationResult.h SOURCES = \ Version.cpp \ @@ -114,7 +115,8 @@ SOURCES = \ TimeoutCommand.cpp \ SetUrlBlacklist.cpp \ NoOpReply.cpp \ - JsonSerializer.cpp + JsonSerializer.cpp \ + InvocationResult.cpp RESOURCES = webkit_server.qrc QT += network webkit