diff --git a/lib/capybara/webkit/browser.rb b/lib/capybara/webkit/browser.rb index b871e774..d8f1256d 100644 --- a/lib/capybara/webkit/browser.rb +++ b/lib/capybara/webkit/browser.rb @@ -39,12 +39,8 @@ def status_code end def console_messages - command("ConsoleMessages").split("\n").map do |messages| - parts = messages.split("|", 3) - message = parts.pop.gsub("\\n", "\n") - { :source => parts.first, :message => message }.tap do |message| - message[:line_number] = Integer(parts[1]) if parts[1] - end + JSON.parse(command("ConsoleMessages")).map do |message| + message.inject({}) { |m,(k,v)| m.merge(k.to_sym => v) } end end diff --git a/spec/driver_spec.rb b/spec/driver_spec.rb index 05a7ba14..6c3a6fa4 100644 --- a/spec/driver_spec.rb +++ b/spec/driver_spec.rb @@ -1,3 +1,5 @@ +# -*- encoding: UTF-8 -*- + require 'spec_helper' require 'capybara/webkit/driver' require 'base64' @@ -470,12 +472,14 @@ def visit(url, driver=driver) driver_for_html(<<-HTML) + @@ -489,9 +493,8 @@ def visit(url, driver=driver) url = driver_url(driver, "/") message = driver.console_messages.first message.should include :source => url, :message => "hello" - # QtWebKit returns different line numbers depending on the version - [5, 6].should include(message[:line_number]) - driver.console_messages.length.should eq 4 + message[:line_number].should == 6 + driver.console_messages.length.should eq 5 end it "logs errors to the console" do @@ -514,6 +517,10 @@ def visit(url, driver=driver) driver.console_messages.last[:source].should be_nil driver.console_messages.last[:line_number].should be_nil end + + it "escapes unicode console messages" do + driver.console_messages[3][:message].should == '𝄞' + end end context "javascript dialog interaction" do diff --git a/src/ConsoleMessages.cpp b/src/ConsoleMessages.cpp index 4cb86fa1..822821cf 100644 --- a/src/ConsoleMessages.cpp +++ b/src/ConsoleMessages.cpp @@ -1,11 +1,14 @@ #include "ConsoleMessages.h" #include "WebPage.h" #include "WebPageManager.h" +#include "JsonSerializer.h" ConsoleMessages::ConsoleMessages(WebPageManager *manager, QStringList &arguments, QObject *parent) : SocketCommand(manager, arguments, parent) { } void ConsoleMessages::start() { - emitFinished(true, page()->consoleMessages()); + JsonSerializer serializer; + QString json = serializer.serialize(page()->consoleMessages()); + emitFinished(true, json); } diff --git a/src/JsonSerializer.cpp b/src/JsonSerializer.cpp index 936a09df..946d6c4a 100644 --- a/src/JsonSerializer.cpp +++ b/src/JsonSerializer.cpp @@ -3,12 +3,12 @@ JsonSerializer::JsonSerializer(QObject *parent) : QObject(parent) { } -QString JsonSerializer::serialize(QVariant &object) { +QString JsonSerializer::serialize(const QVariant &object) { addVariant(object); return m_buffer; } -void JsonSerializer::addVariant(QVariant &object) { +void JsonSerializer::addVariant(const QVariant &object) { if (object.isValid()) { switch(object.type()) { case QMetaType::QString: @@ -37,6 +37,11 @@ void JsonSerializer::addVariant(QVariant &object) { m_buffer.append(object.toString()); break; } + case QMetaType::Int: + { + m_buffer.append(object.toString()); + break; + } default: m_buffer.append("null"); } @@ -45,15 +50,13 @@ void JsonSerializer::addVariant(QVariant &object) { } } -void JsonSerializer::addString(QString &string) { - QString escapedString(string); - escapedString.replace("\"", "\\\""); +void JsonSerializer::addString(const QString &string) { m_buffer.append("\""); - m_buffer.append(escapedString); + m_buffer.append(sanitizeString(string)); m_buffer.append("\""); } -void JsonSerializer::addArray(QVariantList &list) { +void JsonSerializer::addArray(const QVariantList &list) { m_buffer.append("["); for (int i = 0; i < list.length(); i++) { if (i > 0) @@ -63,7 +66,7 @@ void JsonSerializer::addArray(QVariantList &list) { m_buffer.append("]"); } -void JsonSerializer::addMap(QVariantMap &map) { +void JsonSerializer::addMap(const QVariantMap &map) { m_buffer.append("{"); QMapIterator iterator(map); while (iterator.hasNext()) { @@ -79,3 +82,34 @@ void JsonSerializer::addMap(QVariantMap &map) { m_buffer.append("}"); } +QString JsonSerializer::sanitizeString(QString str) { + str.replace("\\", "\\\\"); + + // escape unicode chars + QString result; + const ushort* unicode = str.utf16(); + unsigned int i = 0; + + while (unicode[i]) { + if (unicode[i] < 128) { + result.append(unicode[i]); + } + else { + QString hexCode = QString::number(unicode[i], 16).rightJustified(4, '0'); + + result.append("\\u").append(hexCode); + } + ++i; + } + str = result; + + str.replace("\"", "\\\""); + str.replace("\b", "\\b"); + str.replace("\f", "\\f"); + str.replace("\n", "\\n"); + str.replace("\r", "\\r"); + str.replace("\t", "\\t"); + + return str; +} + diff --git a/src/JsonSerializer.h b/src/JsonSerializer.h index 529c1201..742017cb 100644 --- a/src/JsonSerializer.h +++ b/src/JsonSerializer.h @@ -6,13 +6,14 @@ class JsonSerializer : public QObject { public: JsonSerializer(QObject *parent = 0); - QString serialize(QVariant &object); + QString serialize(const QVariant &object); private: - void addVariant(QVariant &object); - void addString(QString &string); - void addArray(QVariantList &list); - void addMap(QVariantMap &map); + void addVariant(const QVariant &object); + void addString(const QString &string); + void addArray(const QVariantList &list); + void addMap(const QVariantMap &map); + QString sanitizeString(QString string); QString m_buffer; }; diff --git a/src/WebPage.cpp b/src/WebPage.cpp index 57e72120..83ec456f 100644 --- a/src/WebPage.cpp +++ b/src/WebPage.cpp @@ -83,8 +83,8 @@ QString WebPage::userAgentForUrl(const QUrl &url ) const { } } -QString WebPage::consoleMessages() { - return m_consoleMessages.join("\n"); +QVariantList WebPage::consoleMessages() { + return m_consoleMessages; } QString WebPage::alertMessages() { @@ -131,10 +131,15 @@ QVariant WebPage::invokeCapybaraFunction(QString &name, const QStringList &argum } void WebPage::javaScriptConsoleMessage(const QString &message, int lineNumber, const QString &sourceID) { + QVariantMap m; + m["message"] = message; QString fullMessage = QString(message); - if (!sourceID.isEmpty()) + if (!sourceID.isEmpty()) { fullMessage = sourceID + "|" + QString::number(lineNumber) + "|" + fullMessage; - m_consoleMessages.append(fullMessage.replace("\n", "\\n")); + m["source"] = sourceID; + m["line_number"] = lineNumber; + } + m_consoleMessages.append(m); m_manager->logger() << qPrintable(fullMessage); } diff --git a/src/WebPage.h b/src/WebPage.h index 167a865c..ae8664cd 100644 --- a/src/WebPage.h +++ b/src/WebPage.h @@ -23,7 +23,7 @@ class WebPage : public QWebPage { bool render(const QString &fileName); virtual bool extension (Extension extension, const ExtensionOption *option=0, ExtensionReturn *output=0); void setSkipImageLoading(bool skip); - QString consoleMessages(); + QVariantList consoleMessages(); QString alertMessages(); QString confirmMessages(); QString promptMessages(); @@ -71,7 +71,7 @@ class WebPage : public QWebPage { void setUserStylesheet(); bool m_confirm; bool m_prompt; - QStringList m_consoleMessages; + QVariantList m_consoleMessages; QStringList m_alertMessages; QStringList m_confirmMessages; QString m_prompt_text;