capybara-webkit 0.13.2 → 0.14.0

Sign up to get free protection for your applications and to get access to all the features.
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);