otherinbox-capybara-webkit 0.12.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (123) hide show
  1. data/.gitignore +19 -0
  2. data/.rspec +2 -0
  3. data/Appraisals +7 -0
  4. data/CONTRIBUTING.md +47 -0
  5. data/ChangeLog +70 -0
  6. data/Gemfile +3 -0
  7. data/Gemfile.lock +68 -0
  8. data/LICENSE +19 -0
  9. data/NEWS.md +36 -0
  10. data/README.md +114 -0
  11. data/Rakefile +65 -0
  12. data/bin/Info.plist +22 -0
  13. data/capybara-webkit.gemspec +28 -0
  14. data/extconf.rb +2 -0
  15. data/gemfiles/1.0.gemfile +7 -0
  16. data/gemfiles/1.0.gemfile.lock +70 -0
  17. data/gemfiles/1.1.gemfile +7 -0
  18. data/gemfiles/1.1.gemfile.lock +70 -0
  19. data/lib/capybara-webkit.rb +1 -0
  20. data/lib/capybara/driver/webkit.rb +135 -0
  21. data/lib/capybara/driver/webkit/browser.rb +168 -0
  22. data/lib/capybara/driver/webkit/connection.rb +120 -0
  23. data/lib/capybara/driver/webkit/cookie_jar.rb +55 -0
  24. data/lib/capybara/driver/webkit/node.rb +118 -0
  25. data/lib/capybara/driver/webkit/socket_debugger.rb +43 -0
  26. data/lib/capybara/driver/webkit/version.rb +7 -0
  27. data/lib/capybara/webkit.rb +11 -0
  28. data/lib/capybara/webkit/matchers.rb +37 -0
  29. data/lib/capybara_webkit_builder.rb +68 -0
  30. data/spec/browser_spec.rb +248 -0
  31. data/spec/capybara_webkit_builder_spec.rb +37 -0
  32. data/spec/connection_spec.rb +54 -0
  33. data/spec/cookie_jar_spec.rb +48 -0
  34. data/spec/driver_rendering_spec.rb +80 -0
  35. data/spec/driver_resize_window_spec.rb +59 -0
  36. data/spec/driver_spec.rb +1552 -0
  37. data/spec/integration/driver_spec.rb +20 -0
  38. data/spec/integration/session_spec.rb +137 -0
  39. data/spec/self_signed_ssl_cert.rb +42 -0
  40. data/spec/spec_helper.rb +46 -0
  41. data/src/Body.h +12 -0
  42. data/src/ClearCookies.cpp +15 -0
  43. data/src/ClearCookies.h +11 -0
  44. data/src/Command.cpp +19 -0
  45. data/src/Command.h +31 -0
  46. data/src/CommandFactory.cpp +38 -0
  47. data/src/CommandFactory.h +16 -0
  48. data/src/CommandParser.cpp +76 -0
  49. data/src/CommandParser.h +33 -0
  50. data/src/Connection.cpp +71 -0
  51. data/src/Connection.h +37 -0
  52. data/src/ConsoleMessages.cpp +10 -0
  53. data/src/ConsoleMessages.h +12 -0
  54. data/src/CurrentUrl.cpp +68 -0
  55. data/src/CurrentUrl.h +16 -0
  56. data/src/Evaluate.cpp +84 -0
  57. data/src/Evaluate.h +22 -0
  58. data/src/Execute.cpp +16 -0
  59. data/src/Execute.h +12 -0
  60. data/src/Find.cpp +19 -0
  61. data/src/Find.h +13 -0
  62. data/src/FrameFocus.cpp +66 -0
  63. data/src/FrameFocus.h +28 -0
  64. data/src/GetCookies.cpp +20 -0
  65. data/src/GetCookies.h +14 -0
  66. data/src/Header.cpp +18 -0
  67. data/src/Header.h +11 -0
  68. data/src/Headers.cpp +10 -0
  69. data/src/Headers.h +12 -0
  70. data/src/IgnoreSslErrors.cpp +12 -0
  71. data/src/IgnoreSslErrors.h +12 -0
  72. data/src/JavascriptInvocation.cpp +14 -0
  73. data/src/JavascriptInvocation.h +19 -0
  74. data/src/NetworkAccessManager.cpp +29 -0
  75. data/src/NetworkAccessManager.h +19 -0
  76. data/src/NetworkCookieJar.cpp +101 -0
  77. data/src/NetworkCookieJar.h +15 -0
  78. data/src/Node.cpp +14 -0
  79. data/src/Node.h +13 -0
  80. data/src/NullCommand.cpp +10 -0
  81. data/src/NullCommand.h +11 -0
  82. data/src/PageLoadingCommand.cpp +46 -0
  83. data/src/PageLoadingCommand.h +40 -0
  84. data/src/Render.cpp +18 -0
  85. data/src/Render.h +12 -0
  86. data/src/RequestedUrl.cpp +12 -0
  87. data/src/RequestedUrl.h +12 -0
  88. data/src/Reset.cpp +29 -0
  89. data/src/Reset.h +15 -0
  90. data/src/ResizeWindow.cpp +16 -0
  91. data/src/ResizeWindow.h +12 -0
  92. data/src/Response.cpp +24 -0
  93. data/src/Response.h +15 -0
  94. data/src/Server.cpp +24 -0
  95. data/src/Server.h +21 -0
  96. data/src/SetCookie.cpp +16 -0
  97. data/src/SetCookie.h +11 -0
  98. data/src/SetProxy.cpp +22 -0
  99. data/src/SetProxy.h +11 -0
  100. data/src/SetSkipImageLoading.cpp +11 -0
  101. data/src/SetSkipImageLoading.h +11 -0
  102. data/src/Source.cpp +18 -0
  103. data/src/Source.h +19 -0
  104. data/src/Status.cpp +12 -0
  105. data/src/Status.h +12 -0
  106. data/src/UnsupportedContentHandler.cpp +32 -0
  107. data/src/UnsupportedContentHandler.h +18 -0
  108. data/src/Url.cpp +12 -0
  109. data/src/Url.h +12 -0
  110. data/src/Visit.cpp +12 -0
  111. data/src/Visit.h +12 -0
  112. data/src/WebPage.cpp +246 -0
  113. data/src/WebPage.h +58 -0
  114. data/src/body.cpp +10 -0
  115. data/src/capybara.js +315 -0
  116. data/src/find_command.h +30 -0
  117. data/src/main.cpp +31 -0
  118. data/src/webkit_server.pro +87 -0
  119. data/src/webkit_server.qrc +5 -0
  120. data/templates/Command.cpp +10 -0
  121. data/templates/Command.h +12 -0
  122. data/webkit_server.pro +4 -0
  123. metadata +300 -0
@@ -0,0 +1,33 @@
1
+ #include <QObject>
2
+ #include <QStringList>
3
+
4
+ class QIODevice;
5
+ class CommandFactory;
6
+ class Command;
7
+
8
+ class CommandParser : public QObject {
9
+ Q_OBJECT
10
+
11
+ public:
12
+ CommandParser(QIODevice *device, CommandFactory *commandFactory, QObject *parent = 0);
13
+
14
+ public slots:
15
+ void checkNext();
16
+
17
+ signals:
18
+ void commandReady(Command *command);
19
+
20
+ private:
21
+ void readLine();
22
+ void readDataBlock();
23
+ void processNext(const char *line);
24
+ void processArgument(const char *data);
25
+ void reset();
26
+ QIODevice *m_device;
27
+ QString m_commandName;
28
+ QStringList m_arguments;
29
+ int m_argumentsExpected;
30
+ int m_expectingDataSize;
31
+ CommandFactory *m_commandFactory;
32
+ };
33
+
@@ -0,0 +1,71 @@
1
+ #include "Connection.h"
2
+ #include "WebPage.h"
3
+ #include "CommandParser.h"
4
+ #include "CommandFactory.h"
5
+ #include "PageLoadingCommand.h"
6
+ #include "Command.h"
7
+
8
+ #include <QTcpSocket>
9
+
10
+ Connection::Connection(QTcpSocket *socket, WebPage *page, QObject *parent) :
11
+ QObject(parent) {
12
+ m_socket = socket;
13
+ m_page = page;
14
+ m_commandFactory = new CommandFactory(page, this);
15
+ m_commandParser = new CommandParser(socket, m_commandFactory, this);
16
+ m_pageSuccess = true;
17
+ m_commandWaiting = false;
18
+ connect(m_socket, SIGNAL(readyRead()), m_commandParser, SLOT(checkNext()));
19
+ connect(m_commandParser, SIGNAL(commandReady(Command *)), this, SLOT(commandReady(Command *)));
20
+ connect(m_page, SIGNAL(pageFinished(bool)), this, SLOT(pendingLoadFinished(bool)));
21
+ }
22
+
23
+ void Connection::commandReady(Command *command) {
24
+ m_queuedCommand = command;
25
+ if (m_page->isLoading())
26
+ m_commandWaiting = true;
27
+ else
28
+ startCommand();
29
+ }
30
+
31
+ void Connection::startCommand() {
32
+ m_commandWaiting = false;
33
+ if (m_pageSuccess) {
34
+ m_runningCommand = new PageLoadingCommand(m_queuedCommand, m_page, this);
35
+ connect(m_runningCommand, SIGNAL(finished(Response *)), this, SLOT(finishCommand(Response *)));
36
+ m_runningCommand->start();
37
+ } else {
38
+ writePageLoadFailure();
39
+ }
40
+ }
41
+
42
+ void Connection::pendingLoadFinished(bool success) {
43
+ m_pageSuccess = success;
44
+ if (m_commandWaiting)
45
+ startCommand();
46
+ }
47
+
48
+ void Connection::writePageLoadFailure() {
49
+ m_pageSuccess = true;
50
+ QString message = m_page->failureString();
51
+ writeResponse(new Response(false, message));
52
+ }
53
+
54
+ void Connection::finishCommand(Response *response) {
55
+ m_runningCommand->deleteLater();
56
+ writeResponse(response);
57
+ }
58
+
59
+ void Connection::writeResponse(Response *response) {
60
+ if (response->isSuccess())
61
+ m_socket->write("ok\n");
62
+ else
63
+ m_socket->write("failure\n");
64
+
65
+ QByteArray messageUtf8 = response->message();
66
+ QString messageLength = QString::number(messageUtf8.size()) + "\n";
67
+ m_socket->write(messageLength.toAscii());
68
+ m_socket->write(messageUtf8);
69
+ delete response;
70
+ }
71
+
data/src/Connection.h ADDED
@@ -0,0 +1,37 @@
1
+ #include <QObject>
2
+ #include <QStringList>
3
+
4
+ class QTcpSocket;
5
+ class WebPage;
6
+ class Command;
7
+ class Response;
8
+ class CommandParser;
9
+ class CommandFactory;
10
+ class PageLoadingCommand;
11
+
12
+ class Connection : public QObject {
13
+ Q_OBJECT
14
+
15
+ public:
16
+ Connection(QTcpSocket *socket, WebPage *page, QObject *parent = 0);
17
+
18
+ public slots:
19
+ void commandReady(Command *command);
20
+ void finishCommand(Response *response);
21
+ void pendingLoadFinished(bool success);
22
+
23
+ private:
24
+ void startCommand();
25
+ void writeResponse(Response *response);
26
+ void writePageLoadFailure();
27
+
28
+ QTcpSocket *m_socket;
29
+ Command *m_queuedCommand;
30
+ WebPage *m_page;
31
+ CommandParser *m_commandParser;
32
+ CommandFactory *m_commandFactory;
33
+ PageLoadingCommand *m_runningCommand;
34
+ bool m_pageSuccess;
35
+ bool m_commandWaiting;
36
+ };
37
+
@@ -0,0 +1,10 @@
1
+ #include "ConsoleMessages.h"
2
+ #include "WebPage.h"
3
+
4
+ ConsoleMessages::ConsoleMessages(WebPage *page, QStringList &arguments, QObject *parent) : Command(page, arguments, parent) {
5
+ }
6
+
7
+ void ConsoleMessages::start() {
8
+ emit finished(new Response(true, page()->consoleMessages()));
9
+ }
10
+
@@ -0,0 +1,12 @@
1
+ #include "Command.h"
2
+
3
+ class WebPage;
4
+
5
+ class ConsoleMessages : public Command {
6
+ Q_OBJECT
7
+
8
+ public:
9
+ ConsoleMessages(WebPage *page, QStringList &arguments, QObject *parent = 0);
10
+ virtual void start();
11
+ };
12
+
@@ -0,0 +1,68 @@
1
+ #include "CurrentUrl.h"
2
+ #include "WebPage.h"
3
+
4
+ CurrentUrl::CurrentUrl(WebPage *page, QStringList &arguments, QObject *parent) : Command(page, arguments, parent) {
5
+ }
6
+
7
+ /*
8
+ * This CurrentUrl command attempts to produce a current_url value consistent
9
+ * with that returned by the Selenium WebDriver Capybara driver.
10
+ *
11
+ * It does not currently return the correct value in the case of an iframe whose
12
+ * source URL results in a redirect because the loading of the iframe does not
13
+ * generate a history item. This is most likely a rare case and is consistent
14
+ * with the current behavior of the capybara-webkit driver.
15
+ *
16
+ * The following two values are *not* affected by Javascript pushState.
17
+ *
18
+ * QWebFrame->url()
19
+ * QWebHistoryItem.originalUrl()
20
+ *
21
+ * The following two values *are* affected by Javascript pushState.
22
+ *
23
+ * QWebFrame->requestedUrl()
24
+ * QWebHistoryItem.url()
25
+ *
26
+ * In the cases that we have access to both the QWebFrame values and the
27
+ * correct history item for that frame, we can compare the values and determine
28
+ * if a redirect occurred and if pushState was used. The table below describes
29
+ * the various combinations of URL values that are possible.
30
+ *
31
+ * O -> originally requested URL
32
+ * R -> URL after redirection
33
+ * P -> URL set by pushState
34
+ * * -> denotes the desired URL value from the frame
35
+ *
36
+ * frame history
37
+ * case url requestedUrl url originalUrl
38
+ * -----------------------------------------------------------------
39
+ * regular load O O* O O
40
+ *
41
+ * redirect w/o R* O R O
42
+ * pushState
43
+ *
44
+ * pushState O P* P O
45
+ * only
46
+ *
47
+ * redirect w/ R P* P O
48
+ * pushState
49
+ *
50
+ * Based on the above information, we only need to check for the case of a
51
+ * redirect w/o pushState, in which case QWebFrame->url() will have the correct
52
+ * current_url value. In all other cases QWebFrame->requestedUrl() is correct.
53
+ */
54
+ void CurrentUrl::start() {
55
+ QUrl humanUrl = wasRedirectedAndNotModifiedByJavascript() ?
56
+ page()->currentFrame()->url() : page()->currentFrame()->requestedUrl();
57
+ QByteArray encodedBytes = humanUrl.toEncoded();
58
+ emit finished(new Response(true, encodedBytes));
59
+ }
60
+
61
+ bool CurrentUrl::wasRegularLoad() {
62
+ return page()->currentFrame()->url() == page()->currentFrame()->requestedUrl();
63
+ }
64
+
65
+ bool CurrentUrl::wasRedirectedAndNotModifiedByJavascript() {
66
+ return !wasRegularLoad() && page()->currentFrame()->url() == page()->history()->currentItem().url();
67
+ }
68
+
data/src/CurrentUrl.h ADDED
@@ -0,0 +1,16 @@
1
+ #include "Command.h"
2
+
3
+ class WebPage;
4
+
5
+ class CurrentUrl : public Command {
6
+ Q_OBJECT
7
+
8
+ public:
9
+ CurrentUrl(WebPage *page, QStringList &arguments, QObject *parent = 0);
10
+ virtual void start();
11
+
12
+ private:
13
+ bool wasRegularLoad();
14
+ bool wasRedirectedAndNotModifiedByJavascript();
15
+ };
16
+
data/src/Evaluate.cpp ADDED
@@ -0,0 +1,84 @@
1
+ #include "Evaluate.h"
2
+ #include "WebPage.h"
3
+ #include <iostream>
4
+
5
+ Evaluate::Evaluate(WebPage *page, QStringList &arguments, QObject *parent) : Command(page, arguments, parent) {
6
+ m_buffer = "";
7
+ }
8
+
9
+ void Evaluate::start() {
10
+ QVariant result = page()->currentFrame()->evaluateJavaScript(arguments()[0]);
11
+ addVariant(result);
12
+ emit finished(new Response(true, m_buffer));
13
+ }
14
+
15
+ void Evaluate::addVariant(QVariant &object) {
16
+ if (object.isValid()) {
17
+ switch(object.type()) {
18
+ case QMetaType::QString:
19
+ {
20
+ QString string = object.toString();
21
+ addString(string);
22
+ }
23
+ break;
24
+ case QMetaType::QVariantList:
25
+ {
26
+ QVariantList list = object.toList();
27
+ addArray(list);
28
+ }
29
+ break;
30
+ case QMetaType::Double:
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
+ default:
45
+ m_buffer.append("null");
46
+ }
47
+ } else {
48
+ m_buffer.append("null");
49
+ }
50
+ }
51
+
52
+ void Evaluate::addString(QString &string) {
53
+ QString escapedString(string);
54
+ escapedString.replace("\"", "\\\"");
55
+ m_buffer.append("\"");
56
+ m_buffer.append(escapedString);
57
+ m_buffer.append("\"");
58
+ }
59
+
60
+ void Evaluate::addArray(QVariantList &list) {
61
+ m_buffer.append("[");
62
+ for (int i = 0; i < list.length(); i++) {
63
+ if (i > 0)
64
+ m_buffer.append(",");
65
+ addVariant(list[i]);
66
+ }
67
+ m_buffer.append("]");
68
+ }
69
+
70
+ void Evaluate::addMap(QVariantMap &map) {
71
+ m_buffer.append("{");
72
+ QMapIterator<QString, QVariant> iterator(map);
73
+ while (iterator.hasNext()) {
74
+ iterator.next();
75
+ QString key = iterator.key();
76
+ QVariant value = iterator.value();
77
+ addString(key);
78
+ m_buffer.append(":");
79
+ addVariant(value);
80
+ if (iterator.hasNext())
81
+ m_buffer.append(",");
82
+ }
83
+ m_buffer.append("}");
84
+ }
data/src/Evaluate.h ADDED
@@ -0,0 +1,22 @@
1
+ #include "Command.h"
2
+
3
+ #include <QVariantList>
4
+
5
+ class WebPage;
6
+
7
+ class Evaluate : public Command {
8
+ Q_OBJECT
9
+
10
+ public:
11
+ Evaluate(WebPage *page, QStringList &arguments, QObject *parent = 0);
12
+ virtual void start();
13
+
14
+ private:
15
+ void addVariant(QVariant &object);
16
+ void addString(QString &string);
17
+ void addArray(QVariantList &list);
18
+ void addMap(QVariantMap &map);
19
+
20
+ QString m_buffer;
21
+ };
22
+
data/src/Execute.cpp ADDED
@@ -0,0 +1,16 @@
1
+ #include "Execute.h"
2
+ #include "WebPage.h"
3
+
4
+ Execute::Execute(WebPage *page, QStringList &arguments, QObject *parent) : Command(page, arguments, parent) {
5
+ }
6
+
7
+ void Execute::start() {
8
+ QString script = arguments()[0] + QString("; 'success'");
9
+ QVariant result = page()->currentFrame()->evaluateJavaScript(script);
10
+ if (result.isValid()) {
11
+ emit finished(new Response(true));
12
+ } else {
13
+ emit finished(new Response(false, QString("Javascript failed to execute")));
14
+ }
15
+ }
16
+
data/src/Execute.h ADDED
@@ -0,0 +1,12 @@
1
+ #include "Command.h"
2
+
3
+ class WebPage;
4
+
5
+ class Execute : public Command {
6
+ Q_OBJECT
7
+
8
+ public:
9
+ Execute(WebPage *page, QStringList &arguments, QObject *parent = 0);
10
+ virtual void start();
11
+ };
12
+
data/src/Find.cpp ADDED
@@ -0,0 +1,19 @@
1
+ #include "Find.h"
2
+ #include "Command.h"
3
+ #include "WebPage.h"
4
+
5
+ Find::Find(WebPage *page, QStringList &arguments, QObject *parent) : Command(page, arguments, parent) {
6
+ }
7
+
8
+ void Find::start() {
9
+ QString message;
10
+ QVariant result = page()->invokeCapybaraFunction("find", arguments());
11
+
12
+ if (result.isValid()) {
13
+ message = result.toString();
14
+ emit finished(new Response(true, message));
15
+ } else {
16
+ emit finished(new Response(false, QString("Invalid XPath expression")));
17
+ }
18
+ }
19
+
data/src/Find.h ADDED
@@ -0,0 +1,13 @@
1
+ #include "Command.h"
2
+
3
+ class WebPage;
4
+
5
+ class Find : public Command {
6
+ Q_OBJECT
7
+
8
+ public:
9
+ Find(WebPage *page, QStringList &arguments, QObject *parent = 0);
10
+ virtual void start();
11
+ };
12
+
13
+
@@ -0,0 +1,66 @@
1
+ #include "FrameFocus.h"
2
+ #include "Command.h"
3
+ #include "WebPage.h"
4
+
5
+ FrameFocus::FrameFocus(WebPage *page, QStringList &arguments, QObject *parent) : Command(page, arguments, parent) {
6
+ }
7
+
8
+ void FrameFocus::start() {
9
+ findFrames();
10
+ switch(arguments().length()) {
11
+ case 1:
12
+ focusId(arguments()[0]);
13
+ break;
14
+ case 2:
15
+ focusIndex(arguments()[1].toInt());
16
+ break;
17
+ default:
18
+ focusParent();
19
+ }
20
+ }
21
+
22
+ void FrameFocus::findFrames() {
23
+ frames = page()->currentFrame()->childFrames();
24
+ }
25
+
26
+ void FrameFocus::focusIndex(int index) {
27
+ if (isFrameAtIndex(index)) {
28
+ frames[index]->setFocus();
29
+ success();
30
+ } else {
31
+ frameNotFound();
32
+ }
33
+ }
34
+
35
+ bool FrameFocus::isFrameAtIndex(int index) {
36
+ return 0 <= index && index < frames.length();
37
+ }
38
+
39
+ void FrameFocus::focusId(QString name) {
40
+ for (int i = 0; i < frames.length(); i++) {
41
+ if (frames[i]->frameName().compare(name) == 0) {
42
+ frames[i]->setFocus();
43
+ success();
44
+ return;
45
+ }
46
+ }
47
+
48
+ frameNotFound();
49
+ }
50
+
51
+ void FrameFocus::focusParent() {
52
+ if (page()->currentFrame()->parentFrame() == 0) {
53
+ emit finished(new Response(false, QString("Already at parent frame.")));
54
+ } else {
55
+ page()->currentFrame()->parentFrame()->setFocus();
56
+ success();
57
+ }
58
+ }
59
+
60
+ void FrameFocus::frameNotFound() {
61
+ emit finished(new Response(false, QString("Unable to locate frame. ")));
62
+ }
63
+
64
+ void FrameFocus::success() {
65
+ emit finished(new Response(true));
66
+ }