capybara-webkit 0.6.1 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,7 @@
1
1
  # -*- encoding: UTF-8 -*-
2
2
 
3
3
  require 'spec_helper'
4
- require 'capybara-webkit'
4
+ require 'capybara/webkit'
5
5
 
6
6
  describe Capybara::Session do
7
7
  subject { Capybara::Session.new(:reusable_webkit, @app) }
@@ -79,6 +79,52 @@ describe Capybara::Session do
79
79
  subject.click_button('ボタン')
80
80
  end
81
81
  end
82
+
83
+ context "response headers with status code" do
84
+ before(:all) do
85
+ @app = lambda do |env|
86
+ params = ::Rack::Utils.parse_query(env['QUERY_STRING'])
87
+ if params["img"] == "true"
88
+ body = 'not found'
89
+ return [404, { 'Content-Type' => 'image/gif', 'Content-Length' => body.length.to_s }, [body]]
90
+ end
91
+ body = <<-HTML
92
+ <html>
93
+ <body>
94
+ <img src="?img=true">
95
+ </body>
96
+ </html>
97
+ HTML
98
+ [200,
99
+ { 'Content-Type' => 'text/html', 'Content-Length' => body.length.to_s, 'X-Capybara' => 'WebKit'},
100
+ [body]]
101
+ end
102
+ end
103
+
104
+ it "should get status code" do
105
+ subject.visit '/'
106
+ subject.status_code.should == 200
107
+ end
108
+
109
+ it "should reset status code" do
110
+ subject.visit '/'
111
+ subject.status_code.should == 200
112
+ subject.reset!
113
+ subject.status_code.should == 0
114
+ end
115
+
116
+ it "should get response headers" do
117
+ subject.visit '/'
118
+ subject.response_headers['X-Capybara'].should == 'WebKit'
119
+ end
120
+
121
+ it "should reset response headers" do
122
+ subject.visit '/'
123
+ subject.response_headers['X-Capybara'].should == 'WebKit'
124
+ subject.reset!
125
+ subject.response_headers['X-Capybara'].should == nil
126
+ end
127
+ end
82
128
  end
83
129
 
84
130
  describe Capybara::Session, "with TestApp" do
@@ -0,0 +1,18 @@
1
+ #include "ClearCookies.h"
2
+ #include "WebPage.h"
3
+ #include "NetworkCookieJar.h"
4
+ #include <QNetworkCookie>
5
+
6
+ ClearCookies::ClearCookies(WebPage *page, QObject *parent)
7
+ : Command(page, parent)
8
+ { }
9
+
10
+ void ClearCookies::start(QStringList &arguments)
11
+ {
12
+ Q_UNUSED(arguments);
13
+ NetworkCookieJar *jar = qobject_cast<NetworkCookieJar*>(page()
14
+ ->networkAccessManager()
15
+ ->cookieJar());
16
+ jar->clearCookies();
17
+ emit finished(new Response(true));
18
+ }
@@ -0,0 +1,11 @@
1
+ #include "Command.h"
2
+
3
+ class WebPage;
4
+
5
+ class ClearCookies : public Command {
6
+ Q_OBJECT;
7
+
8
+ public:
9
+ ClearCookies(WebPage *page, QObject *parent = 0);
10
+ virtual void start(QStringList &arguments);
11
+ };
@@ -1,5 +1,6 @@
1
1
  #include "Connection.h"
2
2
  #include "WebPage.h"
3
+ #include "UnsupportedContentHandler.h"
3
4
  #include "Visit.h"
4
5
  #include "Find.h"
5
6
  #include "Command.h"
@@ -15,6 +16,9 @@
15
16
  #include "Body.h"
16
17
  #include "Status.h"
17
18
  #include "Headers.h"
19
+ #include "SetCookie.h"
20
+ #include "ClearCookies.h"
21
+ #include "GetCookies.h"
18
22
 
19
23
  #include <QTcpSocket>
20
24
  #include <iostream>
@@ -28,7 +32,7 @@ Connection::Connection(QTcpSocket *socket, WebPage *page, QObject *parent) :
28
32
  m_pageSuccess = true;
29
33
  m_commandWaiting = false;
30
34
  connect(m_socket, SIGNAL(readyRead()), this, SLOT(checkNext()));
31
- connect(m_page, SIGNAL(loadFinished(bool)), this, SLOT(pendingLoadFinished(bool)));
35
+ connect(m_page, SIGNAL(pageFinished(bool)), this, SLOT(pendingLoadFinished(bool)));
32
36
  }
33
37
 
34
38
  void Connection::checkNext() {
@@ -0,0 +1,22 @@
1
+ #include "GetCookies.h"
2
+ #include "WebPage.h"
3
+ #include "NetworkCookieJar.h"
4
+
5
+ GetCookies::GetCookies(WebPage *page, QObject *parent)
6
+ : Command(page, parent)
7
+ {
8
+ m_buffer = "";
9
+ }
10
+
11
+ void GetCookies::start(QStringList &arguments)
12
+ {
13
+ Q_UNUSED(arguments);
14
+ NetworkCookieJar *jar = qobject_cast<NetworkCookieJar*>(page()
15
+ ->networkAccessManager()
16
+ ->cookieJar());
17
+ foreach (QNetworkCookie cookie, jar->getAllCookies()) {
18
+ m_buffer.append(cookie.toRawForm());
19
+ m_buffer.append("\n");
20
+ }
21
+ emit finished(new Response(true, m_buffer));
22
+ }
@@ -0,0 +1,14 @@
1
+ #include "Command.h"
2
+
3
+ class WebPage;
4
+
5
+ class GetCookies : public Command {
6
+ Q_OBJECT;
7
+
8
+ public:
9
+ GetCookies(WebPage *page, QObject *parent = 0);
10
+ virtual void start(QStringList &arguments);
11
+
12
+ private:
13
+ QString m_buffer;
14
+ };
@@ -6,14 +6,17 @@
6
6
  NetworkAccessManager::NetworkAccessManager(QObject *parent):QNetworkAccessManager(parent) {
7
7
  }
8
8
 
9
- QNetworkReply* NetworkAccessManager::createRequest(QNetworkAccessManager::Operation oparation, const QNetworkRequest &request, QIODevice * outgoingData = 0) {
9
+ QNetworkReply* NetworkAccessManager::createRequest(QNetworkAccessManager::Operation operation, const QNetworkRequest &request, QIODevice * outgoingData = 0) {
10
10
  QNetworkRequest new_request(request);
11
+ if (operation != QNetworkAccessManager::PostOperation && operation != QNetworkAccessManager::PutOperation) {
12
+ new_request.setHeader(QNetworkRequest::ContentTypeHeader, QVariant());
13
+ }
11
14
  QHashIterator<QString, QString> item(m_headers);
12
15
  while (item.hasNext()) {
13
16
  item.next();
14
17
  new_request.setRawHeader(item.key().toAscii(), item.value().toAscii());
15
18
  }
16
- return QNetworkAccessManager::createRequest(oparation, new_request, outgoingData);
19
+ return QNetworkAccessManager::createRequest(operation, new_request, outgoingData);
17
20
  };
18
21
 
19
22
  void NetworkAccessManager::addHeader(QString key, QString value) {
@@ -0,0 +1,101 @@
1
+ #include "NetworkCookieJar.h"
2
+ #include "QtCore/qdatetime.h"
3
+
4
+ NetworkCookieJar::NetworkCookieJar(QObject *parent)
5
+ : QNetworkCookieJar(parent)
6
+ { }
7
+
8
+ QList<QNetworkCookie> NetworkCookieJar::getAllCookies() const
9
+ {
10
+ return allCookies();
11
+ }
12
+
13
+ void NetworkCookieJar::clearCookies()
14
+ {
15
+ setAllCookies(QList<QNetworkCookie>());
16
+ }
17
+
18
+ static inline bool isParentDomain(QString domain, QString reference)
19
+ {
20
+ if (!reference.startsWith(QLatin1Char('.')))
21
+ return domain == reference;
22
+
23
+ return domain.endsWith(reference) || domain == reference.mid(1);
24
+ }
25
+
26
+ void NetworkCookieJar::overwriteCookies(const QList<QNetworkCookie>& cookieList)
27
+ {
28
+ /* this function is basically a copy-and-paste of the original
29
+ QNetworkCookieJar::setCookiesFromUrl with the domain and
30
+ path validations removed */
31
+
32
+ QString defaultPath(QLatin1Char('/'));
33
+ QDateTime now = QDateTime::currentDateTime();
34
+ QList<QNetworkCookie> newCookies = allCookies();
35
+
36
+ foreach (QNetworkCookie cookie, cookieList) {
37
+ bool isDeletion = (!cookie.isSessionCookie() &&
38
+ cookie.expirationDate() < now);
39
+
40
+ // validate the cookie & set the defaults if unset
41
+ if (cookie.path().isEmpty())
42
+ cookie.setPath(defaultPath);
43
+
44
+ // don't do path checking. See http://bugreports.qt.nokia.com/browse/QTBUG-5815
45
+ // else if (!isParentPath(pathAndFileName, cookie.path())) {
46
+ // continue; // not accepted
47
+ // }
48
+
49
+ if (cookie.domain().isEmpty()) {
50
+ continue;
51
+ } else {
52
+ // Ensure the domain starts with a dot if its field was not empty
53
+ // in the HTTP header. There are some servers that forget the
54
+ // leading dot and this is actually forbidden according to RFC 2109,
55
+ // but all browsers accept it anyway so we do that as well.
56
+ if (!cookie.domain().startsWith(QLatin1Char('.')))
57
+ cookie.setDomain(QLatin1Char('.') + cookie.domain());
58
+
59
+ QString domain = cookie.domain();
60
+
61
+ // the check for effective TLDs makes the "embedded dot" rule from RFC 2109 section 4.3.2
62
+ // redundant; the "leading dot" rule has been relaxed anyway, see above
63
+ // we remove the leading dot for this check
64
+ /*
65
+ if (QNetworkCookieJarPrivate::isEffectiveTLD(domain.remove(0, 1)))
66
+ continue; // not accepted
67
+ */
68
+ }
69
+
70
+ for (int i = 0; i < newCookies.size(); ++i) {
71
+ // does this cookie already exist?
72
+ const QNetworkCookie &current = newCookies.at(i);
73
+ if (cookie.name() == current.name() &&
74
+ cookie.domain() == current.domain() &&
75
+ cookie.path() == current.path()) {
76
+ // found a match
77
+ newCookies.removeAt(i);
78
+ break;
79
+ }
80
+ }
81
+
82
+ // did not find a match
83
+ if (!isDeletion) {
84
+ int countForDomain = 0;
85
+ for (int i = newCookies.size() - 1; i >= 0; --i) {
86
+ // Start from the end and delete the oldest cookies to keep a maximum count of 50.
87
+ const QNetworkCookie &current = newCookies.at(i);
88
+ if (isParentDomain(cookie.domain(), current.domain())
89
+ || isParentDomain(current.domain(), cookie.domain())) {
90
+ if (countForDomain >= 49)
91
+ newCookies.removeAt(i);
92
+ else
93
+ ++countForDomain;
94
+ }
95
+ }
96
+
97
+ newCookies += cookie;
98
+ }
99
+ }
100
+ setAllCookies(newCookies);
101
+ }
@@ -0,0 +1,15 @@
1
+ #include <QtNetwork/QNetworkCookieJar>
2
+ #include <QtNetwork/QNetworkCookie>
3
+
4
+ class NetworkCookieJar : public QNetworkCookieJar {
5
+
6
+ Q_OBJECT;
7
+
8
+ public:
9
+
10
+ NetworkCookieJar(QObject *parent = 0);
11
+
12
+ QList<QNetworkCookie> getAllCookies() const;
13
+ void clearCookies();
14
+ void overwriteCookies(const QList<QNetworkCookie>& cookieList);
15
+ };
@@ -1,6 +1,7 @@
1
1
  #include "Reset.h"
2
2
  #include "WebPage.h"
3
3
  #include "NetworkAccessManager.h"
4
+ #include "NetworkCookieJar.h"
4
5
 
5
6
  Reset::Reset(WebPage *page, QObject *parent) : Command(page, parent) {
6
7
  }
@@ -10,9 +11,10 @@ void Reset::start(QStringList &arguments) {
10
11
 
11
12
  page()->triggerAction(QWebPage::Stop);
12
13
  page()->currentFrame()->setHtml("<html><body></body></html>");
13
- page()->networkAccessManager()->setCookieJar(new QNetworkCookieJar());
14
- page()->setNetworkAccessManager(new NetworkAccessManager());
14
+ page()->networkAccessManager()->setCookieJar(new NetworkCookieJar());
15
+ page()->setCustomNetworkAccessManager();
15
16
  page()->setUserAgent(NULL);
17
+ page()->resetResponseHeaders();
16
18
  emit finished(new Response(true));
17
19
  }
18
20
 
@@ -0,0 +1,18 @@
1
+ #include "SetCookie.h"
2
+ #include "WebPage.h"
3
+ #include "NetworkCookieJar.h"
4
+ #include <QNetworkCookie>
5
+
6
+ SetCookie::SetCookie(WebPage *page, QObject *parent)
7
+ : Command(page, parent)
8
+ { }
9
+
10
+ void SetCookie::start(QStringList &arguments)
11
+ {
12
+ QList<QNetworkCookie> cookies = QNetworkCookie::parseCookies(arguments[0].toAscii());
13
+ NetworkCookieJar *jar = qobject_cast<NetworkCookieJar*>(page()
14
+ ->networkAccessManager()
15
+ ->cookieJar());
16
+ jar->overwriteCookies(cookies);
17
+ emit finished(new Response(true));
18
+ }
@@ -0,0 +1,11 @@
1
+ #include "Command.h"
2
+
3
+ class WebPage;
4
+
5
+ class SetCookie : public Command {
6
+ Q_OBJECT;
7
+
8
+ public:
9
+ SetCookie(WebPage *page, QObject *parent = 0);
10
+ virtual void start(QStringList &arguments);
11
+ };
@@ -0,0 +1,31 @@
1
+ #include "UnsupportedContentHandler.h"
2
+ #include "WebPage.h"
3
+ #include <QNetworkReply>
4
+
5
+ UnsupportedContentHandler::UnsupportedContentHandler(WebPage *page, QNetworkReply *reply, QObject *parent) : QObject(parent) {
6
+ m_page = page;
7
+ m_reply = reply;
8
+ connect(m_reply, SIGNAL(finished()), this, SLOT(handleUnsupportedContent()));
9
+ disconnect(m_page, SIGNAL(loadFinished(bool)), m_page, SLOT(loadFinished(bool)));
10
+ }
11
+
12
+ void UnsupportedContentHandler::handleUnsupportedContent() {
13
+ QVariant contentMimeType = m_reply->header(QNetworkRequest::ContentTypeHeader);
14
+ if(contentMimeType.isNull()) {
15
+ this->finish(false);
16
+ } else {
17
+ this->loadUnsupportedContent();
18
+ this->finish(true);
19
+ }
20
+ this->deleteLater();
21
+ }
22
+
23
+ void UnsupportedContentHandler::loadUnsupportedContent() {
24
+ QByteArray text = m_reply->readAll();
25
+ m_page->mainFrame()->setContent(text, QString("text/plain"), m_reply->url());
26
+ }
27
+
28
+ void UnsupportedContentHandler::finish(bool success) {
29
+ connect(m_page, SIGNAL(loadFinished(bool)), m_page, SLOT(loadFinished(bool)));
30
+ m_page->loadFinished(success);
31
+ }
@@ -0,0 +1,18 @@
1
+ #include <QObject>
2
+ class WebPage;
3
+ class QNetworkReply;
4
+ class UnsupportedContentHandler : public QObject {
5
+ Q_OBJECT
6
+
7
+ public:
8
+ UnsupportedContentHandler(WebPage *page, QNetworkReply *reply, QObject *parent = 0);
9
+
10
+ public slots:
11
+ void handleUnsupportedContent();
12
+
13
+ private:
14
+ WebPage *m_page;
15
+ QNetworkReply *m_reply;
16
+ void loadUnsupportedContent();
17
+ void finish(bool success);
18
+ };
@@ -3,16 +3,12 @@
3
3
  #include "WebPage.h"
4
4
 
5
5
  Visit::Visit(WebPage *page, QObject *parent) : Command(page, parent) {
6
- connect(page, SIGNAL(loadFinished(bool)), this, SLOT(loadFinished(bool)));
6
+ connect(page, SIGNAL(pageFinished(bool)), this, SLOT(loadFinished(bool)));
7
7
  }
8
8
 
9
9
  void Visit::start(QStringList &arguments) {
10
10
  QUrl requestedUrl = QUrl(arguments[0]);
11
- page()->currentFrame()->setUrl(QUrl(requestedUrl));
12
- if(requestedUrl.hasFragment()) {
13
- // workaround for https://bugs.webkit.org/show_bug.cgi?id=32723
14
- page()->currentFrame()->setUrl(QUrl(requestedUrl));
15
- }
11
+ page()->currentFrame()->load(QUrl(requestedUrl));
16
12
  }
17
13
 
18
14
  void Visit::loadFinished(bool success) {
@@ -1,23 +1,32 @@
1
1
  #include "WebPage.h"
2
2
  #include "JavascriptInvocation.h"
3
3
  #include "NetworkAccessManager.h"
4
+ #include "NetworkCookieJar.h"
5
+ #include "UnsupportedContentHandler.h"
4
6
  #include <QResource>
5
7
  #include <iostream>
6
8
 
7
9
  WebPage::WebPage(QObject *parent) : QWebPage(parent) {
10
+ setForwardUnsupportedContent(true);
8
11
  loadJavascript();
9
12
  setUserStylesheet();
10
13
 
11
14
  m_loading = false;
12
-
13
- NetworkAccessManager *manager = new NetworkAccessManager();
14
- this->setNetworkAccessManager(manager);
15
- connect(manager, SIGNAL(finished(QNetworkReply *)), this, SLOT(replyFinished(QNetworkReply *)));
15
+ this->setCustomNetworkAccessManager();
16
16
 
17
17
  connect(this, SIGNAL(loadStarted()), this, SLOT(loadStarted()));
18
18
  connect(this, SIGNAL(loadFinished(bool)), this, SLOT(loadFinished(bool)));
19
19
  connect(this, SIGNAL(frameCreated(QWebFrame *)),
20
20
  this, SLOT(frameCreated(QWebFrame *)));
21
+ connect(this, SIGNAL(unsupportedContent(QNetworkReply*)),
22
+ this, SLOT(handleUnsupportedContent(QNetworkReply*)));
23
+ }
24
+
25
+ void WebPage::setCustomNetworkAccessManager() {
26
+ NetworkAccessManager *manager = new NetworkAccessManager();
27
+ manager->setCookieJar(new NetworkCookieJar());
28
+ this->setNetworkAccessManager(manager);
29
+ connect(manager, SIGNAL(finished(QNetworkReply *)), this, SLOT(replyFinished(QNetworkReply *)));
21
30
  }
22
31
 
23
32
  void WebPage::loadJavascript() {
@@ -108,8 +117,8 @@ void WebPage::loadStarted() {
108
117
  }
109
118
 
110
119
  void WebPage::loadFinished(bool success) {
111
- Q_UNUSED(success);
112
120
  m_loading = false;
121
+ emit pageFinished(success);
113
122
  }
114
123
 
115
124
  bool WebPage::isLoading() const {
@@ -155,6 +164,7 @@ QString WebPage::chooseFile(QWebFrame *parentFrame, const QString &suggestedFile
155
164
  }
156
165
 
157
166
  bool WebPage::extension(Extension extension, const ExtensionOption *option, ExtensionReturn *output) {
167
+ Q_UNUSED(option);
158
168
  if (extension == ChooseMultipleFilesExtension) {
159
169
  QStringList names = QStringList() << getLastAttachedFileName();
160
170
  static_cast<ChooseMultipleFilesExtensionReturn*>(output)->fileNames = names;
@@ -168,22 +178,34 @@ QString WebPage::getLastAttachedFileName() {
168
178
  }
169
179
 
170
180
  void WebPage::replyFinished(QNetworkReply *reply) {
171
- QStringList headers;
172
- lastStatus = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
173
- QList<QByteArray> list = reply->rawHeaderList();
181
+ if (reply->url() == this->currentFrame()->url()) {
182
+ QStringList headers;
183
+ m_lastStatus = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
184
+ QList<QByteArray> list = reply->rawHeaderList();
174
185
 
175
- int length = list.size();
176
- for(int i = 0; i < length; i++) {
177
- headers << list.at(i)+": "+reply->rawHeader(list.at(i));
178
- }
186
+ int length = list.size();
187
+ for(int i = 0; i < length; i++) {
188
+ headers << list.at(i)+": "+reply->rawHeader(list.at(i));
189
+ }
179
190
 
180
- m_pageHeaders = headers.join("\n");
191
+ m_pageHeaders = headers.join("\n");
192
+ }
181
193
  }
182
194
 
183
195
  int WebPage::getLastStatus() {
184
- return lastStatus;
196
+ return m_lastStatus;
197
+ }
198
+
199
+ void WebPage::resetResponseHeaders() {
200
+ m_lastStatus = 0;
201
+ m_pageHeaders = QString();
185
202
  }
186
203
 
187
204
  QString WebPage::pageHeaders() {
188
205
  return m_pageHeaders;
189
206
  }
207
+
208
+ void WebPage::handleUnsupportedContent(QNetworkReply *reply) {
209
+ UnsupportedContentHandler *handler = new UnsupportedContentHandler(this, reply);
210
+ Q_UNUSED(handler);
211
+ }