From a8e64a5f10edd5b8873579a33aed61f3c8f8eccb Mon Sep 17 00:00:00 2001 From: Joe Ferris Date: Wed, 9 Mar 2011 00:08:30 -0500 Subject: [PATCH] Don't create a command until all arguments are received; don't start the next command if a page is still loading --- spec/driver_spec.rb | 22 ++++++++++++++++ src/Connection.cpp | 63 ++++++++++++++++++++++++++++----------------- src/Connection.h | 4 ++- src/Visit.cpp | 3 +++ src/WebPage.cpp | 19 ++++++++++++++ src/WebPage.h | 5 ++++ 6 files changed, 92 insertions(+), 24 deletions(-) diff --git a/spec/driver_spec.rb b/spec/driver_spec.rb index 9a77c95..2f9aa52 100644 --- a/spec/driver_spec.rb +++ b/spec/driver_spec.rb @@ -309,4 +309,26 @@ describe Capybara::Driver::Webkit do parent.find("./*[@class='find']").map(&:text).should == %w(Expected) end end + + context "slow app" do + let(:app) do + lambda do |env| + body = <<-HTML + +
+

#{env['PATH_INFO']}

+ + HTML + sleep(0.5) + [200, + { 'Content-Type' => 'text/html', 'Content-Length' => body.length.to_s }, + [body]] + end + end + + it "waits for a request to load" do + subject.find("//input").first.click + subject.find("//p").first.text.should == "/next" + end + end end diff --git a/src/Connection.cpp b/src/Connection.cpp index 74f192e..91482ba 100644 --- a/src/Connection.cpp +++ b/src/Connection.cpp @@ -1,4 +1,5 @@ #include "Connection.h" +#include "WebPage.h" #include "Visit.h" #include "Find.h" #include "Command.h" @@ -54,33 +55,15 @@ void Connection::readDataBlock() { } void Connection::processNext(const char *data) { - if (m_command) { - continueCommand(data); + if (m_commandName.isNull()) { + m_commandName = data; + m_argumentsExpected = -1; } else { - m_command = createCommand(data); - if (m_command) { - startCommand(); - } else { - QString failure = QString("Unknown command: ") + data + "\n"; - writeResponse(false, failure); - } + processArgument(data); } } -Command *Connection::createCommand(const char *name) { - #include "find_command.h" - return NULL; -} - -void Connection::startCommand() { - m_argumentsExpected = -1; - connect(m_command, - SIGNAL(finished(bool, QString &)), - this, - SLOT(finishCommand(bool, QString &))); -} - -void Connection::continueCommand(const char *data) { +void Connection::processArgument(const char *data) { if (m_argumentsExpected == -1) { m_argumentsExpected = QString(data).toInt(); } else if (m_expectingDataSize == -1) { @@ -90,7 +73,40 @@ void Connection::continueCommand(const char *data) { } if (m_arguments.length() == m_argumentsExpected) { + if (m_page->isLoading()) + connect(m_page, SIGNAL(loadFinished(bool)), this, SLOT(pendingLoadFinished(bool))); + else + startCommand(); + } +} + +void Connection::startCommand() { + m_command = createCommand(m_commandName.toAscii().constData()); + if (m_command) { + connect(m_command, + SIGNAL(finished(bool, QString &)), + this, + SLOT(finishCommand(bool, QString &))); m_command->start(m_arguments); + } else { + QString failure = QString("Unknown command: ") + m_commandName + "\n"; + writeResponse(false, failure); + } + m_commandName = QString(); +} + +Command *Connection::createCommand(const char *name) { + #include "find_command.h" + return NULL; +} + +void Connection::pendingLoadFinished(bool success) { + m_page->disconnect(this, SLOT(pendingLoadFinished(bool))); + if (success) { + startCommand(); + } else { + QString response = m_page->failureString(); + finishCommand(false, response); } } @@ -111,3 +127,4 @@ void Connection::writeResponse(bool success, QString &response) { m_socket->write(responseLength.toAscii()); m_socket->write(response.toAscii()); } + diff --git a/src/Connection.h b/src/Connection.h index d68bd6f..e0a1da5 100644 --- a/src/Connection.h +++ b/src/Connection.h @@ -14,17 +14,19 @@ class Connection : public QObject { public slots: void checkNext(); void finishCommand(bool success, QString &response); + void pendingLoadFinished(bool success); private: void readLine(); void readDataBlock(); void processNext(const char *line); Command *createCommand(const char *name); + void processArgument(const char *line); void startCommand(); - void continueCommand(const char *line); void writeResponse(bool success, QString &response); QTcpSocket *m_socket; + QString m_commandName; Command *m_command; QStringList m_arguments; int m_argumentsExpected; diff --git a/src/Visit.cpp b/src/Visit.cpp index 830fec0..cd15e66 100644 --- a/src/Visit.cpp +++ b/src/Visit.cpp @@ -12,6 +12,9 @@ void Visit::start(QStringList &arguments) { void Visit::loadFinished(bool success) { QString response; + if (!success) + response = page()->failureString(); + emit finished(success, response); } diff --git a/src/WebPage.cpp b/src/WebPage.cpp index 6abaa7a..7322821 100644 --- a/src/WebPage.cpp +++ b/src/WebPage.cpp @@ -11,6 +11,9 @@ WebPage::WebPage(QObject *parent) : QWebPage(parent) { strcpy(javascriptString, (const char *)javascript.data()); javascriptString[javascript.size()] = 0; m_capybaraJavascript = javascriptString; + m_loading = false; + connect(this, SIGNAL(loadStarted()), this, SLOT(loadStarted())); + connect(this, SIGNAL(loadFinished(bool)), this, SLOT(loadFinished(bool))); } void WebPage::injectJavascriptHelpers() { @@ -40,3 +43,19 @@ void WebPage::javaScriptConsoleMessage(const QString &message, int lineNumber, c std::cout << qPrintable(message) << std::endl; } +void WebPage::loadStarted() { + m_loading = true; +} + +void WebPage::loadFinished(bool success) { + m_loading = false; +} + +bool WebPage::isLoading() const { + return m_loading; +} + +QString WebPage::failureString() { + return QString("Unable to load URL: ") + mainFrame()->url().toString(); +} + diff --git a/src/WebPage.h b/src/WebPage.h index e45c7b8..ec65e47 100644 --- a/src/WebPage.h +++ b/src/WebPage.h @@ -7,15 +7,20 @@ class WebPage : public QWebPage { WebPage(QObject *parent = 0); QVariant invokeCapybaraFunction(const char *name, QStringList &arguments); QVariant invokeCapybaraFunction(QString &name, QStringList &arguments); + QString failureString(); public slots: bool shouldInterruptJavaScript(); void injectJavascriptHelpers(); + void loadStarted(); + void loadFinished(bool); + bool isLoading() const; protected: virtual void javaScriptConsoleMessage(const QString &message, int lineNumber, const QString &sourceID); private: QString m_capybaraJavascript; + bool m_loading; };