Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

We’re showing branches in this repository, but you can also compare across forks.

base fork: thoughtbot/capybara-webkit
...
head fork: reInteractive/capybara-webkit
  • 1 commit
  • 15 files changed
  • 0 commit comments
  • 1 contributor
Commits on Jul 14, 2012
Sean Geoghegan seangeo Add configurable timeouts to commands.
Timeouts can be set using browser.timeout = <seconds>.
When a command or page load takes longer the specified
timeout a Capybara::TimeoutError will be raised. Calls
to reset! will reset the timeout. You can also clear
the timeout by setting it to -1.

The timeout is implemented as a Command decorator.
09026b6
24 lib/capybara/webkit/browser.rb
View
@@ -165,6 +165,14 @@ def render(path, width, height)
command "Render", path, width, height
end
+ def timeout=(timeout_in_seconds)
+ command "SetTimeout", timeout_in_seconds
+ end
+
+ def timeout
+ command("GetTimeout").to_i
+ end
+
def set_cookie(cookie)
command "SetCookie", cookie
end
@@ -199,12 +207,26 @@ def check
if result.nil?
raise NoResponseError, "No response received from the server."
elsif result != 'ok'
- raise InvalidResponseError, read_response
+ case response = read_response
+ when "timeout"
+ raise Capybara::TimeoutError, "Request timed out after #{timeout_seconds}"
+ else
+ raise InvalidResponseError, response
+ end
end
result
end
+ def timeout_seconds
+ seconds = timeout
+ if seconds > 1
+ "#{seconds} seconds"
+ else
+ "1 second"
+ end
+ end
+
def read_response
response_length = @connection.gets.to_i
if response_length > 0
72 spec/driver_spec.rb
View
@@ -1771,6 +1771,78 @@ def which_for(character)
end
end
+ describe "timeout for long requests" do
+ let(:driver) do
+ driver_for_app do
+ html = <<-HTML
+ <html>
+ <body>
+ <form action="/form" method="post">
+ <input type="submit" value="Submit"/>
+ </form>
+ </body>
+ </html>
+ HTML
+
+ get "/" do
+ sleep(2)
+ html
+ end
+
+ post "/form" do
+ sleep(4)
+ html
+ end
+ end
+ end
+
+ it "should not raise a timeout error when zero" do
+ driver.browser.timeout = 0
+ lambda { driver.visit("/") }.should_not raise_error(Capybara::TimeoutError)
+ end
+
+ it "should raise a timeout error" do
+ driver.browser.timeout = 1
+ lambda { driver.visit("/") }.should raise_error(Capybara::TimeoutError, "Request timed out after 1 second")
+ end
+
+ it "should not raise an error when the timeout is high enough" do
+ driver.browser.timeout = 10
+ lambda { driver.visit("/") }.should_not raise_error(Capybara::TimeoutError)
+ end
+
+ it "should set the timeout for each request" do
+ driver.browser.timeout = 10
+ lambda { driver.visit("/") }.should_not raise_error(Capybara::TimeoutError)
+ driver.browser.timeout = 1
+ lambda { driver.visit("/") }.should raise_error(Capybara::TimeoutError)
+ end
+
+ it "should set the timeout for each request" do
+ driver.browser.timeout = 1
+ lambda { driver.visit("/") }.should raise_error(Capybara::TimeoutError)
+ driver.reset!
+ driver.browser.timeout = 10
+ lambda { driver.visit("/") }.should_not raise_error(Capybara::TimeoutError)
+ end
+
+ it "should raise a timeout on a slow form" do
+ driver.browser.timeout = 3
+ driver.visit("/")
+ driver.status_code.should == 200
+ driver.browser.timeout = 1
+ driver.find("//input").first.click
+ lambda { driver.status_code }.should raise_error(Capybara::TimeoutError)
+ end
+
+ it "get timeout" do
+ driver.browser.timeout = 10
+ driver.browser.timeout.should == 10
+ driver.browser.timeout = 3
+ driver.browser.timeout.should == 3
+ end
+ end
+
describe "logger app" do
it "logs nothing before turning on the logger" do
driver.visit("/")
2  src/CommandFactory.cpp
View
@@ -22,6 +22,8 @@
#include "ConsoleMessages.h"
#include "RequestedUrl.h"
#include "CurrentUrl.h"
+#include "SetTimeout.h"
+#include "GetTimeout.h"
#include "ResizeWindow.h"
#include "IgnoreSslErrors.h"
#include "SetSkipImageLoading.h"
12 src/Connection.cpp
View
@@ -4,6 +4,7 @@
#include "CommandParser.h"
#include "CommandFactory.h"
#include "PageLoadingCommand.h"
+#include "TimeoutCommand.h"
#include "SocketCommand.h"
#include <QTcpSocket>
@@ -24,18 +25,14 @@ Connection::Connection(QTcpSocket *socket, WebPageManager *manager, QObject *par
void Connection::commandReady(Command *command) {
m_queuedCommand = command;
m_manager->logger() << "Received" << command->toString();
- if (m_manager->isLoading()) {
- m_manager->logger() << command->toString() << "waiting for load to finish";
- m_commandWaiting = true;
- } else {
- startCommand();
- }
+ startCommand();
}
void Connection::startCommand() {
m_commandWaiting = false;
if (m_pageSuccess) {
m_runningCommand = new PageLoadingCommand(m_queuedCommand, m_manager, this);
+ m_runningCommand = new TimeoutCommand(m_runningCommand, m_manager, this);
connect(m_runningCommand, SIGNAL(finished(Response *)), this, SLOT(finishCommand(Response *)));
m_runningCommand->start();
} else {
@@ -45,9 +42,6 @@ void Connection::startCommand() {
void Connection::pendingLoadFinished(bool success) {
m_pageSuccess = m_pageSuccess && success;
- if (m_commandWaiting) {
- startCommand();
- }
}
void Connection::writePageLoadFailure() {
2  src/Connection.h
View
@@ -31,7 +31,7 @@ class Connection : public QObject {
WebPageManager *m_manager;
CommandParser *m_commandParser;
CommandFactory *m_commandFactory;
- PageLoadingCommand *m_runningCommand;
+ Command *m_runningCommand;
bool m_pageSuccess;
bool m_commandWaiting;
WebPage *currentPage();
9 src/GetTimeout.cpp
View
@@ -0,0 +1,9 @@
+#include "GetTimeout.h"
+#include "WebPageManager.h"
+
+GetTimeout::GetTimeout(WebPageManager *manager, QStringList &arguments, QObject *parent) : SocketCommand(manager, arguments, parent) {
+}
+
+void GetTimeout::start() {
+ emit finished(new Response(true, QString::number(manager()->getTimeout())));
+}
11 src/GetTimeout.h
View
@@ -0,0 +1,11 @@
+#include "SocketCommand.h"
+
+class WebPageManager;
+
+class GetTimeout : public SocketCommand {
+ Q_OBJECT;
+
+ public:
+ GetTimeout(WebPageManager *page, QStringList &arguments, QObject *parent = 0);
+ virtual void start();
+};
19 src/SetTimeout.cpp
View
@@ -0,0 +1,19 @@
+#include "SetTimeout.h"
+#include "WebPageManager.h"
+
+SetTimeout::SetTimeout(WebPageManager *manager, QStringList &arguments, QObject *parent) : SocketCommand(manager, arguments, parent) {
+}
+
+void SetTimeout::start() {
+ QString timeoutString = arguments()[0];
+ bool ok;
+ int timeout = timeoutString.toInt(&ok);
+
+ if (ok) {
+ manager()->setTimeout(timeout);
+ emit finished(new Response(true));
+ } else {
+ emit finished(new Response(false, QString("Invalid value for timeout")));
+ }
+}
+
9 src/SetTimeout.h
View
@@ -0,0 +1,9 @@
+#include "SocketCommand.h"
+
+class SetTimeout : public SocketCommand {
+ Q_OBJECT
+
+ public:
+ SetTimeout(WebPageManager *manager, QStringList &arguments, QObject *parent = 0);
+ virtual void start();
+};
59 src/TimeoutCommand.cpp
View
@@ -0,0 +1,59 @@
+#include "TimeoutCommand.h"
+#include "Command.h"
+#include "WebPageManager.h"
+#include "WebPage.h"
+#include <QTimer.h>
+
+TimeoutCommand::TimeoutCommand(Command *command, WebPageManager *manager, QObject *parent) : Command(parent) {
+ m_command = command;
+ m_manager = manager;
+ m_timer = new QTimer(this);
+ m_timer->setSingleShot(true);
+ connect(m_timer, SIGNAL(timeout()), this, SLOT(commandTimeout()));
+ connect(m_manager, SIGNAL(loadStarted()), this, SLOT(pageLoadingFromCommand()));
+}
+
+void TimeoutCommand::start() {
+ if (m_manager->isLoading()) {
+ connect(m_manager, SIGNAL(pageFinished(bool)), this, SLOT(pendingLoadFinished(bool)));
+ startTimeout();
+ } else {
+ startCommand();
+ }
+}
+
+void TimeoutCommand::startCommand() {
+ connect(m_command, SIGNAL(finished(Response *)), this, SLOT(commandFinished(Response *)));
+ m_command->start();
+}
+
+void TimeoutCommand::startTimeout() {
+ int timeout = m_manager->getTimeout();
+ if (timeout > 0) {
+ m_timer->start(timeout * 1000);
+ }
+}
+
+void TimeoutCommand::pendingLoadFinished(bool success) {
+ if (success) {
+ startCommand();
+ } else {
+ emit finished(new Response(false, m_manager->currentPage()->failureString()));
+ }
+}
+
+void TimeoutCommand::pageLoadingFromCommand() {
+ startTimeout();
+}
+
+void TimeoutCommand::commandTimeout() {
+ m_manager->currentPage()->triggerAction(QWebPage::Stop);
+ m_command->deleteLater();
+ emit finished(new Response(false, QString("timeout")));
+}
+
+void TimeoutCommand::commandFinished(Response *response) {
+ m_command->deleteLater();
+ emit finished(response);
+}
+
41 src/TimeoutCommand.h
View
@@ -0,0 +1,41 @@
+#include "Command.h"
+#include <QObject>
+#include <QStringList>
+
+class Response;
+class WebPageManager;
+class QTimer;
+
+/* Decorates a command with a timeout.
+ *
+ * If the timeout, using a QTimer is reached before
+ * the command is finished, the load page load will
+ * be stopped and failure response will be issued.
+ *
+ */
+class TimeoutCommand : public Command {
+ Q_OBJECT
+
+ public:
+ TimeoutCommand(Command *command, WebPageManager *page, QObject *parent = 0);
+ virtual void start();
+
+ public slots:
+ void commandTimeout();
+ void commandFinished(Response *response);
+ void pageLoadingFromCommand();
+ void pendingLoadFinished(bool);
+
+ signals:
+ void finished(Response *response);
+
+ protected:
+ void startCommand();
+ void startTimeout();
+
+ private:
+ WebPageManager *m_manager;
+ QTimer *m_timer;
+ Command *m_command;
+};
+
10 src/WebPageManager.cpp
View
@@ -8,6 +8,7 @@ WebPageManager::WebPageManager(QObject *parent) : QObject(parent) {
m_success = true;
m_loggingEnabled = false;
m_ignoredOutput = new QString();
+ m_timeout = -1;
createPage(this)->setFocus();
}
@@ -85,7 +86,16 @@ bool WebPageManager::ignoreSslErrors() {
return m_ignoreSslErrors;
}
+int WebPageManager::getTimeout() {
+ return m_timeout;
+}
+
+void WebPageManager::setTimeout(int timeout) {
+ m_timeout = timeout;
+}
+
void WebPageManager::reset() {
+ m_timeout = -1;
m_cookieJar->clearCookies();
m_pages.first()->deleteLater();
m_pages.clear();
3  src/WebPageManager.h
View
@@ -22,6 +22,8 @@ class WebPageManager : public QObject {
WebPage *createPage(QObject *parent);
void setIgnoreSslErrors(bool);
bool ignoreSslErrors();
+ void setTimeout(int);
+ int getTimeout();
void reset();
NetworkCookieJar *cookieJar();
bool isLoading() const;
@@ -50,6 +52,7 @@ class WebPageManager : public QObject {
bool m_success;
bool m_loggingEnabled;
QString *m_ignoredOutput;
+ int m_timeout;
};
#endif // _WEBPAGEMANAGER_H
3  src/find_command.h
View
@@ -39,3 +39,6 @@ CHECK_COMMAND(ClearPromptText)
CHECK_COMMAND(JavascriptAlertMessages)
CHECK_COMMAND(JavascriptConfirmMessages)
CHECK_COMMAND(JavascriptPromptMessages)
+CHECK_COMMAND(GetTimeout)
+CHECK_COMMAND(SetTimeout)
+
6 src/webkit_server.pro
View
@@ -53,6 +53,9 @@ HEADERS = \
WindowFocus.h \
GetWindowHandles.h \
GetWindowHandle.h \
+ GetTimeout.h \
+ SetTimeout.h \
+ TimeoutCommand.h \
SOURCES = \
EnableLogging.cpp \
@@ -102,11 +105,14 @@ SOURCES = \
SetProxy.cpp \
NullCommand.cpp \
PageLoadingCommand.cpp \
+ SetTimeout.cpp \
+ GetTimeout.cpp \
SetSkipImageLoading.cpp \
WebPageManager.cpp \
WindowFocus.cpp \
GetWindowHandles.cpp \
GetWindowHandle.cpp \
+ TimeoutCommand.cpp \
RESOURCES = webkit_server.qrc
QT += network webkit

No commit comments for this range

Something went wrong with that request. Please try again.