mirror of
https://github.com/thoughtbot/capybara-webkit
synced 2023-03-27 23:22:28 -04:00
Revert "Revert "Add configurable timeouts to commands.""
This reverts commit b1b3a4c390
.
This commit is contained in:
parent
b1b3a4c390
commit
cbb58d05f1
15 changed files with 271 additions and 11 deletions
|
@ -165,6 +165,14 @@ module Capybara::Webkit
|
|||
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 @@ module Capybara::Webkit
|
|||
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
|
||||
|
|
|
@ -1825,6 +1825,78 @@ describe Capybara::Webkit::Driver do
|
|||
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("/")
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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
Normal file
9
src/GetTimeout.cpp
Normal file
|
@ -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
Normal file
11
src/GetTimeout.h
Normal file
|
@ -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
Normal file
19
src/SetTimeout.cpp
Normal file
|
@ -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
Normal file
9
src/SetTimeout.h
Normal file
|
@ -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
Normal file
59
src/TimeoutCommand.cpp
Normal file
|
@ -0,0 +1,59 @@
|
|||
#include "TimeoutCommand.h"
|
||||
#include "Command.h"
|
||||
#include "WebPageManager.h"
|
||||
#include "WebPage.h"
|
||||
#include <QTimer>
|
||||
|
||||
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
Normal file
41
src/TimeoutCommand.h
Normal file
|
@ -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;
|
||||
};
|
||||
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -39,3 +39,6 @@ CHECK_COMMAND(ClearPromptText)
|
|||
CHECK_COMMAND(JavascriptAlertMessages)
|
||||
CHECK_COMMAND(JavascriptConfirmMessages)
|
||||
CHECK_COMMAND(JavascriptPromptMessages)
|
||||
CHECK_COMMAND(GetTimeout)
|
||||
CHECK_COMMAND(SetTimeout)
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue