diff --git a/Rakefile b/Rakefile index 82ae841..f956b43 100644 --- a/Rakefile +++ b/Rakefile @@ -22,8 +22,8 @@ task :generate_command do Dir.glob("src/*.pro").each do |project_file_name| project = IO.read(project_file_name) - project.gsub!(/(HEADERS = .*)/, "\\1 #{name}.h") - project.gsub!(/(SOURCES = .*)/, "\\1 #{name}.cpp") + project.gsub!(/^(HEADERS = .*)/, "\\1 #{name}.h") + project.gsub!(/^(SOURCES = .*)/, "\\1 #{name}.cpp") File.open(project_file_name, "w") { |file| file.write(project) } end diff --git a/lib/capybara/driver/webkit.rb b/lib/capybara/driver/webkit.rb index 40e4e78..9cc51cb 100644 --- a/lib/capybara/driver/webkit.rb +++ b/lib/capybara/driver/webkit.rb @@ -41,7 +41,7 @@ class Capybara::Driver::Webkit end def evaluate_script(script) - raise Capybara::NotSupportedByDriverError + browser.evaluate_script script end def response_headers diff --git a/lib/capybara/driver/webkit/browser.rb b/lib/capybara/driver/webkit/browser.rb index b0530e7..a8bccc2 100644 --- a/lib/capybara/driver/webkit/browser.rb +++ b/lib/capybara/driver/webkit/browser.rb @@ -1,5 +1,6 @@ require 'socket' require 'capybara/util/timeout' +require 'json' class Capybara::Driver::Webkit class Browser @@ -36,6 +37,12 @@ class Capybara::Driver::Webkit read_response end + def evaluate_script(script) + json = command('Evaluate', script) + puts "Got JSON: #{json}" + JSON.parse("[#{json}]").first + end + private def start_server diff --git a/spec/driver_spec.rb b/spec/driver_spec.rb index 6494fff..bea53c0 100644 --- a/spec/driver_spec.rb +++ b/spec/driver_spec.rb @@ -65,5 +65,50 @@ describe Capybara::Driver::Webkit do it "aliases body as source" do subject.body.should == subject.source end + + it "evaluates Javascript and returns a string" do + result = subject.evaluate_script(%) + result.should == "hello" + end + + it "evaluates Javascript and returns an array" do + result = subject.evaluate_script(%<["hello", "world"]>) + result.should == %w(hello world) + end + + it "evaluates Javascript and returns an int" do + result = subject.evaluate_script(%<123>) + result.should == 123 + end + + it "evaluates Javascript and returns a float" do + result = subject.evaluate_script(%<1.5>) + result.should == 1.5 + end + + it "evaluates Javascript and returns null" do + result = subject.evaluate_script(%<(function () {})()>) + result.should == nil + end + + it "evaluates Javascript and returns an object" do + result = subject.evaluate_script(%<({ 'one' : 1 })>) + result.should == { 'one' => 1 } + end + + it "evaluates Javascript and returns true" do + result = subject.evaluate_script(%) + result.should === true + end + + it "evaluates Javascript and returns false" do + result = subject.evaluate_script(%) + result.should === false + end + + it "evaluates Javascript and returns an escaped string" do + result = subject.evaluate_script(%<'"'>) + result.should === "\"" + end end diff --git a/src/Connection.cpp b/src/Connection.cpp index 8031bcb..52dbf20 100644 --- a/src/Connection.cpp +++ b/src/Connection.cpp @@ -6,8 +6,10 @@ #include "Node.h" #include "Url.h" #include "Source.h" +#include "Evaluate.h" #include +#include Connection::Connection(QTcpSocket *socket, WebPage *page, QObject *parent) : QObject(parent) { @@ -38,6 +40,7 @@ void Connection::processLine(const char *line) { } else { m_command = createCommand(line); if (m_command) { + std::cout << "Starting command: " << line << std::endl; startCommand(); } else { m_socket->write("bad command\n"); @@ -74,6 +77,7 @@ void Connection::finishCommand(bool success, QString &response) { m_command->deleteLater(); m_command = NULL; m_arguments.clear(); + std::cout << "Finished command" << std::endl; if (success) { m_socket->write("ok\n"); } else { diff --git a/src/Evaluate.cpp b/src/Evaluate.cpp new file mode 100644 index 0000000..0802fa9 --- /dev/null +++ b/src/Evaluate.cpp @@ -0,0 +1,88 @@ +#include "Evaluate.h" +#include "WebPage.h" +#include + +Evaluate::Evaluate(WebPage *page, QObject *parent) : Command(page, parent) { + m_buffer = ""; +} + +void Evaluate::start(QStringList &arguments) { + Q_UNUSED(arguments); + + QVariant result = page()->mainFrame()->evaluateJavaScript(arguments[0]); + addVariant(result); + emit finished(true, m_buffer); +} + +void Evaluate::addVariant(QVariant &object) { + if (object.isValid()) { + std::cout << "Got type:" << object.typeName() << std::endl; + switch(object.type()) { + case QMetaType::QString: + { + QString string = object.toString(); + addString(string); + } + break; + case QMetaType::QVariantList: + { + QVariantList list = object.toList(); + addArray(list); + } + break; + case QMetaType::Double: + m_buffer.append(object.toString()); + break; + case QMetaType::QVariantMap: + { + QVariantMap map = object.toMap(); + addMap(map); + break; + } + case QMetaType::Bool: + { + m_buffer.append(object.toString()); + break; + } + default: + m_buffer.append("null"); + } + } else { + std::cout << "Got invalid result" << std::endl; + m_buffer.append("null"); + } +} + +void Evaluate::addString(QString &string) { + QString escapedString(string); + escapedString.replace("\"", "\\\""); + m_buffer.append("\""); + m_buffer.append(escapedString); + m_buffer.append("\""); +} + +void Evaluate::addArray(QVariantList &list) { + m_buffer.append("["); + for (int i = 0; i < list.length(); i++) { + if (i > 0) + m_buffer.append(","); + addVariant(list[i]); + } + m_buffer.append("]"); +} + +void Evaluate::addMap(QVariantMap &map) { + m_buffer.append("{"); + QMapIterator iterator(map); + while (iterator.hasNext()) { + iterator.next(); + QString key = iterator.key(); + QVariant value = iterator.value(); + addString(key); + m_buffer.append(":"); + addVariant(value); + if (iterator.hasNext()) + m_buffer.append(","); + } + m_buffer.append("}"); +} diff --git a/src/Evaluate.h b/src/Evaluate.h new file mode 100644 index 0000000..f513205 --- /dev/null +++ b/src/Evaluate.h @@ -0,0 +1,22 @@ +#include "Command.h" + +#include + +class WebPage; + +class Evaluate : public Command { + Q_OBJECT + + public: + Evaluate(WebPage *page, QObject *parent = 0); + virtual void start(QStringList &arguments); + + private: + void addVariant(QVariant &object); + void addString(QString &string); + void addArray(QVariantList &list); + void addMap(QVariantMap &map); + + QString m_buffer; +}; + diff --git a/src/WebPage.cpp b/src/WebPage.cpp index 6b74f1e..16e1bcf 100644 --- a/src/WebPage.cpp +++ b/src/WebPage.cpp @@ -1,6 +1,7 @@ #include "WebPage.h" #include "JavascriptInvocation.h" #include +#include WebPage::WebPage(QObject *parent) : QWebPage(parent) { connect(mainFrame(), SIGNAL(javaScriptWindowObjectCleared()), @@ -30,3 +31,9 @@ QVariant WebPage::invokeCapybaraFunction(QString &name, QStringList &arguments) return invokeCapybaraFunction(name.toAscii().data(), arguments); } +void WebPage::javaScriptConsoleMessage(const QString &message, int lineNumber, const QString &sourceID) { + if (!sourceID.isEmpty()) + std::cout << qPrintable(sourceID) << ":" << lineNumber << " "; + std::cout << qPrintable(message) << std::endl; +} + diff --git a/src/WebPage.h b/src/WebPage.h index 3c4d6e4..e45c7b8 100644 --- a/src/WebPage.h +++ b/src/WebPage.h @@ -12,6 +12,9 @@ class WebPage : public QWebPage { bool shouldInterruptJavaScript(); void injectJavascriptHelpers(); + protected: + virtual void javaScriptConsoleMessage(const QString &message, int lineNumber, const QString &sourceID); + private: QString m_capybaraJavascript; }; diff --git a/src/find_command.h b/src/find_command.h index 46082c4..be639f8 100644 --- a/src/find_command.h +++ b/src/find_command.h @@ -9,3 +9,4 @@ CHECK_COMMAND(Reset) CHECK_COMMAND(Node) CHECK_COMMAND(Url) CHECK_COMMAND(Source) +CHECK_COMMAND(Evaluate) \ No newline at end of file diff --git a/src/webkit_server.pro b/src/webkit_server.pro index a6bce58..1ea9283 100644 --- a/src/webkit_server.pro +++ b/src/webkit_server.pro @@ -1,8 +1,8 @@ TEMPLATE = app TARGET = webkit_server DESTDIR = . -HEADERS = WebPage.h Server.h Connection.h Command.h Visit.h Find.h Reset.h Node.h JavascriptInvocation.h Url.h Source.h -SOURCES = main.cpp WebPage.cpp Server.cpp Connection.cpp Command.cpp Visit.cpp Find.cpp Reset.cpp Node.cpp JavascriptInvocation.cpp Url.cpp Source.cpp +HEADERS = WebPage.h Server.h Connection.h Command.h Visit.h Find.h Reset.h Node.h JavascriptInvocation.h Url.h Source.h Evaluate.h +SOURCES = main.cpp WebPage.cpp Server.cpp Connection.cpp Command.cpp Visit.cpp Find.cpp Reset.cpp Node.cpp JavascriptInvocation.cpp Url.cpp Source.cpp Evaluate.cpp RESOURCES = webkit_server.qrc QT += network webkit CONFIG += console