capybara-webkit 0.13.2 → 0.14.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.
Files changed (91) hide show
  1. data/.travis.yml +10 -0
  2. data/Gemfile.lock +20 -18
  3. data/NEWS.md +20 -1
  4. data/README.md +12 -10
  5. data/capybara-webkit.gemspec +3 -2
  6. data/lib/capybara/webkit/browser.rb +10 -19
  7. data/lib/capybara/webkit/connection.rb +13 -34
  8. data/lib/capybara/webkit/driver.rb +5 -22
  9. data/lib/capybara/webkit/node.rb +10 -2
  10. data/lib/capybara/webkit/version.rb +1 -1
  11. data/lib/capybara_webkit_builder.rb +10 -1
  12. data/spec/browser_spec.rb +1 -1
  13. data/spec/connection_spec.rb +4 -2
  14. data/spec/driver_rendering_spec.rb +2 -2
  15. data/spec/driver_resize_window_spec.rb +29 -40
  16. data/spec/driver_spec.rb +368 -125
  17. data/spec/integration/session_spec.rb +100 -6
  18. data/spec/spec_helper.rb +6 -9
  19. data/spec/support/app_runner.rb +2 -12
  20. data/src/Authenticate.cpp +2 -2
  21. data/src/ClearCookies.cpp +1 -1
  22. data/src/ClearPromptText.cpp +1 -1
  23. data/src/Command.cpp +13 -0
  24. data/src/Command.h +6 -0
  25. data/src/CommandFactory.cpp +1 -3
  26. data/src/Connection.cpp +4 -3
  27. data/src/ConsoleMessages.cpp +4 -1
  28. data/src/CurrentUrl.cpp +1 -16
  29. data/src/CurrentUrl.h +0 -6
  30. data/src/EnableLogging.cpp +1 -1
  31. data/src/Evaluate.cpp +3 -74
  32. data/src/Evaluate.h +0 -8
  33. data/src/Execute.cpp +2 -2
  34. data/src/Find.cpp +2 -2
  35. data/src/FrameFocus.cpp +3 -3
  36. data/src/GetCookies.cpp +1 -1
  37. data/src/GetTimeout.cpp +1 -1
  38. data/src/GetWindowHandle.cpp +1 -1
  39. data/src/GetWindowHandles.cpp +6 -5
  40. data/src/Header.cpp +2 -2
  41. data/src/Headers.cpp +1 -1
  42. data/src/IgnoreSslErrors.cpp +1 -1
  43. data/src/JavascriptAlertMessages.cpp +4 -1
  44. data/src/JavascriptConfirmMessages.cpp +4 -1
  45. data/src/JavascriptPromptMessages.cpp +4 -1
  46. data/src/JsonSerializer.cpp +116 -0
  47. data/src/JsonSerializer.h +20 -0
  48. data/src/NetworkAccessManager.cpp +58 -17
  49. data/src/NetworkAccessManager.h +6 -0
  50. data/src/NoOpReply.cpp +32 -0
  51. data/src/NoOpReply.h +18 -0
  52. data/src/Node.cpp +1 -1
  53. data/src/NullCommand.cpp +1 -1
  54. data/src/PageLoadingCommand.cpp +5 -4
  55. data/src/Render.cpp +1 -1
  56. data/src/Reset.cpp +1 -1
  57. data/src/ResizeWindow.cpp +1 -1
  58. data/src/Response.cpp +3 -3
  59. data/src/Response.h +13 -4
  60. data/src/SetConfirmAction.cpp +1 -1
  61. data/src/SetCookie.cpp +1 -1
  62. data/src/SetPromptAction.cpp +1 -1
  63. data/src/SetPromptText.cpp +1 -1
  64. data/src/SetProxy.cpp +2 -2
  65. data/src/SetSkipImageLoading.cpp +1 -1
  66. data/src/SetTimeout.cpp +2 -2
  67. data/src/SetUrlBlacklist.cpp +15 -0
  68. data/src/SetUrlBlacklist.h +11 -0
  69. data/src/Status.cpp +1 -1
  70. data/src/TimeoutCommand.cpp +6 -6
  71. data/src/TimeoutCommand.h +0 -3
  72. data/src/UnsupportedContentHandler.cpp +1 -4
  73. data/src/Visit.cpp +1 -1
  74. data/src/WebPage.cpp +41 -31
  75. data/src/WebPage.h +14 -12
  76. data/src/WebPageManager.cpp +13 -8
  77. data/src/WebPageManager.h +3 -2
  78. data/src/WindowFocus.cpp +2 -2
  79. data/src/body.cpp +7 -2
  80. data/src/capybara.js +10 -2
  81. data/src/find_command.h +1 -3
  82. data/src/webkit_server.pro +7 -7
  83. metadata +47 -82
  84. checksums.yaml +0 -7
  85. data/spec/integration/driver_spec.rb +0 -21
  86. data/src/RequestedUrl.cpp +0 -13
  87. data/src/RequestedUrl.h +0 -10
  88. data/src/Source.cpp +0 -19
  89. data/src/Source.h +0 -18
  90. data/src/Url.cpp +0 -13
  91. data/src/Url.h +0 -10
@@ -8,13 +8,5 @@ class Evaluate : public SocketCommand {
8
8
  public:
9
9
  Evaluate(WebPageManager *, QStringList &arguments, QObject *parent = 0);
10
10
  virtual void start();
11
-
12
- private:
13
- void addVariant(QVariant &object);
14
- void addString(QString &string);
15
- void addArray(QVariantList &list);
16
- void addMap(QVariantMap &map);
17
-
18
- QString m_buffer;
19
11
  };
20
12
 
@@ -9,9 +9,9 @@ void Execute::start() {
9
9
  QString script = arguments()[0] + QString("; 'success'");
10
10
  QVariant result = page()->currentFrame()->evaluateJavaScript(script);
11
11
  if (result.isValid()) {
12
- emit finished(new Response(true));
12
+ emitFinished(true);
13
13
  } else {
14
- emit finished(new Response(false, QString("Javascript failed to execute")));
14
+ emitFinished(false, QString("Javascript failed to execute"));
15
15
  }
16
16
  }
17
17
 
@@ -12,9 +12,9 @@ void Find::start() {
12
12
 
13
13
  if (result.isValid()) {
14
14
  message = result.toString();
15
- emit finished(new Response(true, message));
15
+ emitFinished(true, message);
16
16
  } else {
17
- emit finished(new Response(false, QString("Invalid XPath expression")));
17
+ emitFinished(false, QString("Invalid XPath expression"));
18
18
  }
19
19
  }
20
20
 
@@ -51,7 +51,7 @@ void FrameFocus::focusId(QString name) {
51
51
 
52
52
  void FrameFocus::focusParent() {
53
53
  if (page()->currentFrame()->parentFrame() == 0) {
54
- emit finished(new Response(false, QString("Already at parent frame.")));
54
+ emitFinished(false, QString("Already at parent frame."));
55
55
  } else {
56
56
  page()->currentFrame()->parentFrame()->setFocus();
57
57
  success();
@@ -59,9 +59,9 @@ void FrameFocus::focusParent() {
59
59
  }
60
60
 
61
61
  void FrameFocus::frameNotFound() {
62
- emit finished(new Response(false, QString("Unable to locate frame. ")));
62
+ emitFinished(false, QString("Unable to locate frame. "));
63
63
  }
64
64
 
65
65
  void FrameFocus::success() {
66
- emit finished(new Response(true));
66
+ emitFinished(true);
67
67
  }
@@ -15,5 +15,5 @@ void GetCookies::start()
15
15
  m_buffer.append(cookie.toRawForm());
16
16
  m_buffer.append("\n");
17
17
  }
18
- emit finished(new Response(true, m_buffer));
18
+ emitFinished(true, m_buffer);
19
19
  }
@@ -5,5 +5,5 @@ GetTimeout::GetTimeout(WebPageManager *manager, QStringList &arguments, QObject
5
5
  }
6
6
 
7
7
  void GetTimeout::start() {
8
- emit finished(new Response(true, QString::number(manager()->getTimeout())));
8
+ emitFinished(true, QString::number(manager()->getTimeout()));
9
9
  }
@@ -7,5 +7,5 @@ GetWindowHandle::GetWindowHandle(WebPageManager *manager, QStringList &arguments
7
7
  }
8
8
 
9
9
  void GetWindowHandle::start() {
10
- emit finished(new Response(true, page()->uuid()));
10
+ emitFinished(true, page()->uuid());
11
11
  }
@@ -2,19 +2,20 @@
2
2
  #include "WebPageManager.h"
3
3
  #include "CommandFactory.h"
4
4
  #include "WebPage.h"
5
+ #include "JsonSerializer.h"
5
6
  #include <QStringList>
6
7
 
7
8
  GetWindowHandles::GetWindowHandles(WebPageManager *manager, QStringList &arguments, QObject *parent) : SocketCommand(manager, arguments, parent) {
8
9
  }
9
10
 
10
11
  void GetWindowHandles::start() {
11
- QString handles = "[";
12
- QStringList stringList;
12
+ QVariantList handles;
13
13
 
14
14
  foreach(WebPage *page, manager()->pages())
15
- stringList.append("\"" + page->uuid() + "\"");
15
+ handles << page->uuid();
16
16
 
17
- handles += stringList.join(",") + "]";
17
+ JsonSerializer serializer;
18
+ QByteArray json = serializer.serialize(handles);
18
19
 
19
- emit finished(new Response(true, handles));
20
+ emitFinished(true, json);
20
21
  }
@@ -9,11 +9,11 @@ Header::Header(WebPageManager *manager, QStringList &arguments, QObject *parent)
9
9
  void Header::start() {
10
10
  QString key = arguments()[0];
11
11
  QString value = arguments()[1];
12
- NetworkAccessManager* networkAccessManager = qobject_cast<NetworkAccessManager*>(page()->networkAccessManager());
12
+ NetworkAccessManager* networkAccessManager = page()->networkAccessManager();
13
13
  if (key.toLower().replace("-", "_") == "user_agent") {
14
14
  page()->setUserAgent(value);
15
15
  } else {
16
16
  networkAccessManager->addHeader(key, value);
17
17
  }
18
- emit finished(new Response(true));
18
+ emitFinished(true);
19
19
  }
@@ -11,6 +11,6 @@ void Headers::start() {
11
11
  foreach(QNetworkReply::RawHeaderPair header, page()->pageHeaders())
12
12
  headers << header.first+": "+header.second;
13
13
 
14
- emit finished(new Response(true, headers.join("\n")));
14
+ emitFinished(true, headers.join("\n"));
15
15
  }
16
16
 
@@ -8,6 +8,6 @@ IgnoreSslErrors::IgnoreSslErrors(WebPageManager *manager, QStringList &arguments
8
8
 
9
9
  void IgnoreSslErrors::start() {
10
10
  manager()->setIgnoreSslErrors(true);
11
- emit finished(new Response(true));
11
+ emitFinished(true);
12
12
  }
13
13
 
@@ -1,10 +1,13 @@
1
1
  #include "JavascriptAlertMessages.h"
2
2
  #include "WebPage.h"
3
3
  #include "WebPageManager.h"
4
+ #include "JsonSerializer.h"
4
5
 
5
6
  JavascriptAlertMessages::JavascriptAlertMessages(WebPageManager *manager, QStringList &arguments, QObject *parent) : SocketCommand(manager, arguments, parent) {}
6
7
 
7
8
  void JavascriptAlertMessages::start()
8
9
  {
9
- emit finished(new Response(true, page()->alertMessages()));
10
+ JsonSerializer serializer;
11
+ QByteArray json = serializer.serialize(page()->alertMessages());
12
+ emitFinished(true, json);
10
13
  }
@@ -1,10 +1,13 @@
1
1
  #include "JavascriptConfirmMessages.h"
2
2
  #include "WebPage.h"
3
3
  #include "WebPageManager.h"
4
+ #include "JsonSerializer.h"
4
5
 
5
6
  JavascriptConfirmMessages::JavascriptConfirmMessages(WebPageManager *manager, QStringList &arguments, QObject *parent) : SocketCommand(manager, arguments, parent) {}
6
7
 
7
8
  void JavascriptConfirmMessages::start()
8
9
  {
9
- emit finished(new Response(true, page()->confirmMessages()));
10
+ JsonSerializer serializer;
11
+ QByteArray json = serializer.serialize(page()->confirmMessages());
12
+ emitFinished(true, json);
10
13
  }
@@ -1,10 +1,13 @@
1
1
  #include "JavascriptPromptMessages.h"
2
2
  #include "WebPage.h"
3
3
  #include "WebPageManager.h"
4
+ #include "JsonSerializer.h"
4
5
 
5
6
  JavascriptPromptMessages::JavascriptPromptMessages(WebPageManager *manager, QStringList &arguments, QObject *parent) : SocketCommand(manager, arguments, parent) {}
6
7
 
7
8
  void JavascriptPromptMessages::start()
8
9
  {
9
- emit finished(new Response(true, page()->promptMessages()));
10
+ JsonSerializer serializer;
11
+ QByteArray json = serializer.serialize(page()->promptMessages());
12
+ emitFinished(true, json);
10
13
  }
@@ -0,0 +1,116 @@
1
+ #include "JsonSerializer.h"
2
+ #include <cmath>
3
+
4
+ JsonSerializer::JsonSerializer(QObject *parent) : QObject(parent) {
5
+ }
6
+
7
+ QByteArray JsonSerializer::serialize(const QVariant &object) {
8
+ addVariant(object);
9
+ return m_buffer;
10
+ }
11
+
12
+ void JsonSerializer::addVariant(const QVariant &object) {
13
+ if (object.isValid()) {
14
+ switch(object.type()) {
15
+ case QMetaType::QString:
16
+ {
17
+ QString string = object.toString();
18
+ addString(string);
19
+ }
20
+ break;
21
+ case QMetaType::QVariantList:
22
+ {
23
+ QVariantList list = object.toList();
24
+ addArray(list);
25
+ }
26
+ break;
27
+ case QMetaType::Double:
28
+ if (std::isinf(object.toDouble()))
29
+ m_buffer.append("null");
30
+ else
31
+ m_buffer.append(object.toString());
32
+ break;
33
+ case QMetaType::QVariantMap:
34
+ {
35
+ QVariantMap map = object.toMap();
36
+ addMap(map);
37
+ break;
38
+ }
39
+ case QMetaType::Bool:
40
+ {
41
+ m_buffer.append(object.toString());
42
+ break;
43
+ }
44
+ case QMetaType::Int:
45
+ {
46
+ m_buffer.append(object.toString());
47
+ break;
48
+ }
49
+ default:
50
+ m_buffer.append("null");
51
+ }
52
+ } else {
53
+ m_buffer.append("null");
54
+ }
55
+ }
56
+
57
+ void JsonSerializer::addString(const QString &string) {
58
+ m_buffer.append("\"");
59
+ m_buffer.append(sanitizeString(string));
60
+ m_buffer.append("\"");
61
+ }
62
+
63
+ void JsonSerializer::addArray(const QVariantList &list) {
64
+ m_buffer.append("[");
65
+ for (int i = 0; i < list.length(); i++) {
66
+ if (i > 0)
67
+ m_buffer.append(",");
68
+ addVariant(list[i]);
69
+ }
70
+ m_buffer.append("]");
71
+ }
72
+
73
+ void JsonSerializer::addMap(const QVariantMap &map) {
74
+ m_buffer.append("{");
75
+ QMapIterator<QString, QVariant> iterator(map);
76
+ while (iterator.hasNext()) {
77
+ iterator.next();
78
+ QString key = iterator.key();
79
+ QVariant value = iterator.value();
80
+ addString(key);
81
+ m_buffer.append(":");
82
+ addVariant(value);
83
+ if (iterator.hasNext())
84
+ m_buffer.append(",");
85
+ }
86
+ m_buffer.append("}");
87
+ }
88
+
89
+ QByteArray JsonSerializer::sanitizeString(QString str) {
90
+ str.replace("\\", "\\\\");
91
+ str.replace("\"", "\\\"");
92
+ str.replace("\b", "\\b");
93
+ str.replace("\f", "\\f");
94
+ str.replace("\n", "\\n");
95
+ str.replace("\r", "\\r");
96
+ str.replace("\t", "\\t");
97
+
98
+ QByteArray result;
99
+ const ushort* unicode = str.utf16();
100
+ unsigned int i = 0;
101
+
102
+ while (unicode[i]) {
103
+ if (unicode[i] > 31 && unicode[i] < 128) {
104
+ result.append(unicode[i]);
105
+ }
106
+ else {
107
+ QString hexCode = QString::number(unicode[i], 16).rightJustified(4, '0');
108
+
109
+ result.append("\\u").append(hexCode);
110
+ }
111
+ ++i;
112
+ }
113
+
114
+ return result;
115
+ }
116
+
@@ -0,0 +1,20 @@
1
+ #include <QObject>
2
+ #include <QVariantList>
3
+
4
+ class JsonSerializer : public QObject {
5
+ Q_OBJECT
6
+
7
+ public:
8
+ JsonSerializer(QObject *parent = 0);
9
+ QByteArray serialize(const QVariant &object);
10
+
11
+ private:
12
+ void addVariant(const QVariant &object);
13
+ void addString(const QString &string);
14
+ void addArray(const QVariantList &list);
15
+ void addMap(const QVariantMap &map);
16
+ QByteArray sanitizeString(QString string);
17
+
18
+ QByteArray m_buffer;
19
+ };
20
+
@@ -2,6 +2,7 @@
2
2
  #include "WebPage.h"
3
3
  #include <iostream>
4
4
  #include <fstream>
5
+ #include "NoOpReply.h"
5
6
 
6
7
  NetworkAccessManager::NetworkAccessManager(QObject *parent):QNetworkAccessManager(parent) {
7
8
  connect(this, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)), SLOT(provideAuthentication(QNetworkReply*,QAuthenticator*)));
@@ -11,24 +12,36 @@ NetworkAccessManager::NetworkAccessManager(QObject *parent):QNetworkAccessManage
11
12
  QNetworkReply* NetworkAccessManager::createRequest(QNetworkAccessManager::Operation operation, const QNetworkRequest &request, QIODevice * outgoingData = 0) {
12
13
  QNetworkRequest new_request(request);
13
14
  QByteArray url = new_request.url().toEncoded();
14
- if (operation != QNetworkAccessManager::PostOperation && operation != QNetworkAccessManager::PutOperation) {
15
- new_request.setHeader(QNetworkRequest::ContentTypeHeader, QVariant());
15
+ if (this->isBlacklisted(new_request.url())) {
16
+ return new NoOpReply(new_request, this);
17
+ } else {
18
+ if (operation != QNetworkAccessManager::PostOperation && operation != QNetworkAccessManager::PutOperation) {
19
+ new_request.setHeader(QNetworkRequest::ContentTypeHeader, QVariant());
20
+ }
21
+ QHashIterator<QString, QString> item(m_headers);
22
+ while (item.hasNext()) {
23
+ item.next();
24
+ new_request.setRawHeader(item.key().toAscii(), item.value().toAscii());
25
+ }
26
+ QNetworkReply *reply = QNetworkAccessManager::createRequest(operation, new_request, outgoingData);
27
+ emit requestCreated(url, reply);
28
+ return reply;
16
29
  }
17
- QHashIterator<QString, QString> item(m_headers);
18
- while (item.hasNext()) {
19
- item.next();
20
- new_request.setRawHeader(item.key().toAscii(), item.value().toAscii());
21
- }
22
- QNetworkReply *reply = QNetworkAccessManager::createRequest(operation, new_request, outgoingData);
23
- emit requestCreated(url, reply);
24
- return reply;
25
- }
30
+ };
26
31
 
27
32
  void NetworkAccessManager::finished(QNetworkReply *reply) {
28
- NetworkResponse response;
29
- response.statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
30
- response.headers = reply->rawHeaderPairs();
31
- m_responses[reply->url()] = response;
33
+ QUrl redirectUrl = reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl();
34
+ if (redirectUrl.isValid())
35
+ m_redirectMappings[reply->url().resolved(redirectUrl)] = reply->url();
36
+ else {
37
+ QUrl requestedUrl = reply->url();
38
+ while (m_redirectMappings.contains(requestedUrl))
39
+ requestedUrl = m_redirectMappings.take(requestedUrl);
40
+ NetworkResponse response;
41
+ response.statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
42
+ response.headers = reply->rawHeaderPairs();
43
+ m_responses[requestedUrl] = response;
44
+ }
32
45
  }
33
46
 
34
47
  void NetworkAccessManager::addHeader(QString key, QString value) {
@@ -49,8 +62,10 @@ void NetworkAccessManager::setPassword(const QString &password) {
49
62
 
50
63
  void NetworkAccessManager::provideAuthentication(QNetworkReply *reply, QAuthenticator *authenticator) {
51
64
  Q_UNUSED(reply);
52
- authenticator->setUser(m_userName);
53
- authenticator->setPassword(m_password);
65
+ if (m_userName != authenticator->user())
66
+ authenticator->setUser(m_userName);
67
+ if (m_password != authenticator->password())
68
+ authenticator->setPassword(m_password);
54
69
  }
55
70
 
56
71
  int NetworkAccessManager::statusFor(QUrl url) {
@@ -60,3 +75,29 @@ int NetworkAccessManager::statusFor(QUrl url) {
60
75
  const QList<QNetworkReply::RawHeaderPair> &NetworkAccessManager::headersFor(QUrl url) {
61
76
  return m_responses[url].headers;
62
77
  }
78
+
79
+ void NetworkAccessManager::setUrlBlacklist(QStringList urlBlacklist) {
80
+ m_urlBlacklist.clear();
81
+
82
+ QStringListIterator iter(urlBlacklist);
83
+ while (iter.hasNext()) {
84
+ m_urlBlacklist << QUrl(iter.next());
85
+ }
86
+ };
87
+
88
+ bool NetworkAccessManager::isBlacklisted(QUrl url) {
89
+ QListIterator<QUrl> iter(m_urlBlacklist);
90
+
91
+ while (iter.hasNext()) {
92
+ QUrl blacklisted = iter.next();
93
+
94
+ if (blacklisted == url) {
95
+ return true;
96
+ } else if (blacklisted.path().isEmpty() && blacklisted.isParentOf(url)) {
97
+ return true;
98
+ }
99
+ }
100
+
101
+ return false;
102
+ };
103
+
@@ -1,6 +1,7 @@
1
1
  #include <QtNetwork/QNetworkAccessManager>
2
2
  #include <QtNetwork/QNetworkRequest>
3
3
  #include <QtNetwork/QNetworkReply>
4
+ #include <QStringList>
4
5
 
5
6
  class NetworkAccessManager : public QNetworkAccessManager {
6
7
 
@@ -20,15 +21,20 @@ class NetworkAccessManager : public QNetworkAccessManager {
20
21
  void setPassword(const QString &password);
21
22
  int statusFor(QUrl url);
22
23
  const QList<QNetworkReply::RawHeaderPair> &headersFor(QUrl url);
24
+ void setUrlBlacklist(QStringList urlBlacklist);
23
25
 
24
26
  protected:
25
27
  QNetworkReply* createRequest(QNetworkAccessManager::Operation op, const QNetworkRequest &req, QIODevice * outgoingData);
26
28
  QString m_userName;
27
29
  QString m_password;
30
+ QList<QUrl> m_urlBlacklist;
31
+
28
32
 
29
33
  private:
30
34
  QHash<QString, QString> m_headers;
31
35
  QHash<QUrl, NetworkResponse> m_responses;
36
+ bool isBlacklisted(QUrl url);
37
+ QHash<QUrl, QUrl> m_redirectMappings;
32
38
 
33
39
  private slots:
34
40
  void provideAuthentication(QNetworkReply *reply, QAuthenticator *authenticator);