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
@@ -3,6 +3,12 @@
3
3
  require 'spec_helper'
4
4
  require 'capybara/webkit'
5
5
 
6
+ module TestSessions
7
+ Webkit = Capybara::Session.new(:reusable_webkit, TestApp)
8
+ end
9
+
10
+ Capybara::SpecHelper.run_specs TestSessions::Webkit, "webkit"
11
+
6
12
  describe Capybara::Session do
7
13
  subject { Capybara::Session.new(:reusable_webkit, @app) }
8
14
  after { subject.reset! }
@@ -125,13 +131,101 @@ describe Capybara::Session do
125
131
  subject.response_headers['X-Capybara'].should == nil
126
132
  end
127
133
  end
128
- end
129
134
 
130
- describe Capybara::Session, "with TestApp" do
131
- before do
132
- @session = Capybara::Session.new(:reusable_webkit, TestApp)
135
+ context "slow iframe app" do
136
+ before do
137
+ @app = Class.new(ExampleApp) do
138
+ get '/' do
139
+ <<-HTML
140
+ <html>
141
+ <head>
142
+ <script>
143
+ function hang() {
144
+ xhr = new XMLHttpRequest();
145
+ xhr.onreadystatechange = function() {
146
+ if(xhr.readyState == 4){
147
+ document.getElementById('p').innerText = 'finished'
148
+ }
149
+ }
150
+ xhr.open('GET', '/slow', true);
151
+ xhr.send();
152
+ document.getElementById("f").src = '/iframe';
153
+ return false;
154
+ }
155
+ </script>
156
+ </head>
157
+ <body>
158
+ <a href="#" onclick="hang()">Click Me!</a>
159
+ <iframe src="about:blank" id="f"></iframe>
160
+ <p id="p"></p>
161
+ </body>
162
+ </html>
163
+ HTML
164
+ end
165
+
166
+ get '/slow' do
167
+ sleep 1
168
+ status 204
169
+ end
170
+
171
+ get '/iframe' do
172
+ status 204
173
+ end
174
+ end
175
+ end
176
+
177
+ it "should not hang the server" do
178
+ subject.visit("/")
179
+ subject.click_link('Click Me!')
180
+ Capybara.using_wait_time(5) do
181
+ subject.should have_content("finished")
182
+ end
183
+ end
133
184
  end
134
185
 
135
- it_should_behave_like "session"
136
- it_should_behave_like "session with javascript support"
186
+ context "session app" do
187
+ before do
188
+ @app = Class.new(ExampleApp) do
189
+ enable :sessions
190
+ get '/' do
191
+ <<-HTML
192
+ <html>
193
+ <body>
194
+ <form method="post" action="/sign_in">
195
+ <input type="text" name="username">
196
+ <input type="password" name="password">
197
+ <input type="submit" value="Submit">
198
+ </form>
199
+ </body>
200
+ </html>
201
+ HTML
202
+ end
203
+
204
+ post '/sign_in' do
205
+ session[:username] = params[:username]
206
+ session[:password] = params[:password]
207
+ redirect '/'
208
+ end
209
+
210
+ get '/other' do
211
+ <<-HTML
212
+ <html>
213
+ <body>
214
+ <p>Welcome, #{session[:username]}.</p>
215
+ </body>
216
+ </html>
217
+ HTML
218
+ end
219
+ end
220
+ end
221
+
222
+ it "should not start queued commands more than once" do
223
+ subject.visit('/')
224
+ subject.fill_in('username', with: 'admin')
225
+ subject.fill_in('password', with: 'temp4now')
226
+ subject.click_button('Submit')
227
+ subject.visit('/other')
228
+ subject.should have_content('admin')
229
+ end
230
+ end
137
231
  end
@@ -17,28 +17,25 @@ $:.detect do |dir|
17
17
  end
18
18
  end
19
19
 
20
- RSpec.configure do |c|
21
- c.filter_run_excluding :skip_on_windows => !(RbConfig::CONFIG['host_os'] =~ /mingw32/).nil?
22
- end
23
-
24
20
  require 'capybara/webkit'
25
- connection = Capybara::Webkit::Connection.new(:socket_class => TCPSocket, :stdout => nil)
21
+ connection = Capybara::Webkit::Connection.new(:socket_class => TCPSocket)
26
22
  $webkit_browser = Capybara::Webkit::Browser.new(connection)
27
23
 
28
24
  if ENV['DEBUG']
29
25
  $webkit_browser.enable_logging
30
26
  end
31
27
 
32
- RSpec.configure do |config|
33
- config.before { $webkit_browser.reset! }
34
- end
35
-
36
28
  require File.join(spec_dir, "spec_helper")
37
29
 
38
30
  Capybara.register_driver :reusable_webkit do |app|
39
31
  Capybara::Webkit::Driver.new(app, :browser => $webkit_browser)
40
32
  end
41
33
 
34
+ RSpec.configure do |c|
35
+ c.filter_run_excluding :skip_on_windows => !(RbConfig::CONFIG['host_os'] =~ /mingw32/).nil?
36
+ Capybara::SpecHelper.configure(c)
37
+ end
38
+
42
39
  def with_env_vars(vars)
43
40
  old_env_variables = {}
44
41
  vars.each do |key, value|
@@ -1,5 +1,5 @@
1
1
  # Boots a single Capybara::Server for a Rack application that delegates to another, singleton Rack
2
- # application that can be configured for each spec. Also configures Capybara to use that server.
2
+ # application that can be configured for each spec.
3
3
 
4
4
  require 'sinatra/base'
5
5
 
@@ -51,17 +51,7 @@ module AppRunner
51
51
  def self.included(example_group)
52
52
  example_group.class_eval do
53
53
  before { AppRunner.reset }
54
-
55
- around do |example|
56
- Capybara.run_server = false
57
- Capybara.app_host = AppRunner.app_host
58
- begin
59
- example.run
60
- ensure
61
- Capybara.run_server = true
62
- Capybara.app_host = nil
63
- end
64
- end
54
+ after { $webkit_browser.reset! }
65
55
  end
66
56
  end
67
57
  end
@@ -9,10 +9,10 @@ void Authenticate::start() {
9
9
  QString username = arguments()[0];
10
10
  QString password = arguments()[1];
11
11
 
12
- NetworkAccessManager* networkAccessManager = qobject_cast<NetworkAccessManager*>(page()->networkAccessManager());
12
+ NetworkAccessManager* networkAccessManager = page()->networkAccessManager();
13
13
  networkAccessManager->setUserName(username);
14
14
  networkAccessManager->setPassword(password);
15
15
 
16
- emit finished(new Response(true));
16
+ emitFinished(true);
17
17
  }
18
18
 
@@ -9,5 +9,5 @@ ClearCookies::ClearCookies(WebPageManager *manager, QStringList &arguments, QObj
9
9
  void ClearCookies::start()
10
10
  {
11
11
  manager()->cookieJar()->clearCookies();
12
- emit finished(new Response(true));
12
+ emitFinished(true);
13
13
  }
@@ -7,5 +7,5 @@ ClearPromptText::ClearPromptText(WebPageManager *manager, QStringList &arguments
7
7
  void ClearPromptText::start()
8
8
  {
9
9
  page()->setPromptText(QString());
10
- emit finished(new Response(true));
10
+ emitFinished(true);
11
11
  }
@@ -6,3 +6,16 @@ Command::Command(QObject *parent) : QObject(parent) {
6
6
  QString Command::toString() const {
7
7
  return metaObject()->className();
8
8
  }
9
+
10
+ void Command::emitFinished(bool success) {
11
+ emit finished(new Response(success, this));
12
+ }
13
+
14
+ void Command::emitFinished(bool success, QString message) {
15
+ emit finished(new Response(success, message, this));
16
+ }
17
+
18
+ void Command::emitFinished(bool success, QByteArray message) {
19
+ emit finished(new Response(success, message, this));
20
+ }
21
+
@@ -3,6 +3,7 @@
3
3
 
4
4
  #include <QObject>
5
5
  #include "Response.h"
6
+ #include <QString>
6
7
 
7
8
  class Command : public QObject {
8
9
  Q_OBJECT
@@ -12,6 +13,11 @@ class Command : public QObject {
12
13
  virtual void start() = 0;
13
14
  virtual QString toString() const;
14
15
 
16
+ protected:
17
+ void emitFinished(bool success);
18
+ void emitFinished(bool success, QString message);
19
+ void emitFinished(bool success, QByteArray message);
20
+
15
21
  signals:
16
22
  void finished(Response *response);
17
23
  };
@@ -5,8 +5,6 @@
5
5
  #include "Find.h"
6
6
  #include "Reset.h"
7
7
  #include "Node.h"
8
- #include "Url.h"
9
- #include "Source.h"
10
8
  #include "Evaluate.h"
11
9
  #include "Execute.h"
12
10
  #include "FrameFocus.h"
@@ -20,7 +18,6 @@
20
18
  #include "GetCookies.h"
21
19
  #include "SetProxy.h"
22
20
  #include "ConsoleMessages.h"
23
- #include "RequestedUrl.h"
24
21
  #include "CurrentUrl.h"
25
22
  #include "SetTimeout.h"
26
23
  #include "GetTimeout.h"
@@ -40,6 +37,7 @@
40
37
  #include "JavascriptAlertMessages.h"
41
38
  #include "JavascriptConfirmMessages.h"
42
39
  #include "JavascriptPromptMessages.h"
40
+ #include "SetUrlBlacklist.h"
43
41
 
44
42
  CommandFactory::CommandFactory(WebPageManager *manager, QObject *parent) : QObject(parent) {
45
43
  m_manager = manager;
@@ -43,13 +43,15 @@ void Connection::pendingLoadFinished(bool success) {
43
43
  void Connection::writePageLoadFailure() {
44
44
  m_pageSuccess = true;
45
45
  QString message = currentPage()->failureString();
46
- writeResponse(new Response(false, message));
46
+ Response *response = new Response(false, message, this);
47
+ writeResponse(response);
48
+ delete response;
47
49
  }
48
50
 
49
51
  void Connection::finishCommand(Response *response) {
50
52
  m_pageSuccess = true;
51
- sender()->deleteLater();
52
53
  writeResponse(response);
54
+ sender()->deleteLater();
53
55
  }
54
56
 
55
57
  void Connection::writeResponse(Response *response) {
@@ -64,7 +66,6 @@ void Connection::writeResponse(Response *response) {
64
66
  QString messageLength = QString::number(messageUtf8.size()) + "\n";
65
67
  m_socket->write(messageLength.toAscii());
66
68
  m_socket->write(messageUtf8);
67
- delete response;
68
69
  }
69
70
 
70
71
  WebPage *Connection::currentPage() {
@@ -1,11 +1,14 @@
1
1
  #include "ConsoleMessages.h"
2
2
  #include "WebPage.h"
3
3
  #include "WebPageManager.h"
4
+ #include "JsonSerializer.h"
4
5
 
5
6
  ConsoleMessages::ConsoleMessages(WebPageManager *manager, QStringList &arguments, QObject *parent) : SocketCommand(manager, arguments, parent) {
6
7
  }
7
8
 
8
9
  void ConsoleMessages::start() {
9
- emit finished(new Response(true, page()->consoleMessages()));
10
+ JsonSerializer serializer;
11
+ QByteArray json = serializer.serialize(page()->consoleMessages());
12
+ emitFinished(true, json);
10
13
  }
11
14
 
@@ -6,24 +6,9 @@ CurrentUrl::CurrentUrl(WebPageManager *manager, QStringList &arguments, QObject
6
6
  }
7
7
 
8
8
  void CurrentUrl::start() {
9
- #if QT_VERSION >= QT_VERSION_CHECK(4, 8, 0)
10
9
  QStringList arguments;
11
10
  QVariant result = page()->invokeCapybaraFunction("currentUrl", arguments);
12
11
  QString url = result.toString();
13
- emit finished(new Response(true, url));
14
- #else
15
- QUrl humanUrl = wasRedirectedAndNotModifiedByJavascript() ?
16
- page()->currentFrame()->url() : page()->currentFrame()->requestedUrl();
17
- QByteArray encodedBytes = humanUrl.toEncoded();
18
- emit finished(new Response(true, encodedBytes));
19
- }
20
-
21
- bool CurrentUrl::wasRegularLoad() {
22
- return page()->currentFrame()->url() == page()->currentFrame()->requestedUrl();
23
- }
24
-
25
- bool CurrentUrl::wasRedirectedAndNotModifiedByJavascript() {
26
- return !wasRegularLoad() && page()->currentFrame()->url() == page()->history()->currentItem().url();
27
- #endif
12
+ emitFinished(true, url);
28
13
  }
29
14
 
@@ -6,11 +6,5 @@ class CurrentUrl : public SocketCommand {
6
6
  public:
7
7
  CurrentUrl(WebPageManager *, QStringList &arguments, QObject *parent = 0);
8
8
  virtual void start();
9
- #if QT_VERSION < QT_VERSION_CHECK(4, 8, 0)
10
-
11
- private:
12
- bool wasRegularLoad();
13
- bool wasRedirectedAndNotModifiedByJavascript();
14
- #endif
15
9
  };
16
10
 
@@ -6,5 +6,5 @@ EnableLogging::EnableLogging(WebPageManager *manager, QStringList &arguments, QO
6
6
 
7
7
  void EnableLogging::start() {
8
8
  manager()->enableLogging();
9
- emit finished(new Response(true));
9
+ emitFinished(true);
10
10
  }
@@ -1,85 +1,14 @@
1
1
  #include "Evaluate.h"
2
2
  #include "WebPage.h"
3
3
  #include "WebPageManager.h"
4
+ #include "JsonSerializer.h"
4
5
  #include <iostream>
5
6
 
6
7
  Evaluate::Evaluate(WebPageManager *manager, QStringList &arguments, QObject *parent) : SocketCommand(manager, arguments, parent) {
7
- m_buffer = "";
8
8
  }
9
9
 
10
10
  void Evaluate::start() {
11
11
  QVariant result = page()->currentFrame()->evaluateJavaScript(arguments()[0]);
12
- addVariant(result);
13
- emit finished(new Response(true, m_buffer));
14
- }
15
-
16
- void Evaluate::addVariant(QVariant &object) {
17
- if (object.isValid()) {
18
- switch(object.type()) {
19
- case QMetaType::QString:
20
- {
21
- QString string = object.toString();
22
- addString(string);
23
- }
24
- break;
25
- case QMetaType::QVariantList:
26
- {
27
- QVariantList list = object.toList();
28
- addArray(list);
29
- }
30
- break;
31
- case QMetaType::Double:
32
- m_buffer.append(object.toString());
33
- break;
34
- case QMetaType::QVariantMap:
35
- {
36
- QVariantMap map = object.toMap();
37
- addMap(map);
38
- break;
39
- }
40
- case QMetaType::Bool:
41
- {
42
- m_buffer.append(object.toString());
43
- break;
44
- }
45
- default:
46
- m_buffer.append("null");
47
- }
48
- } else {
49
- m_buffer.append("null");
50
- }
51
- }
52
-
53
- void Evaluate::addString(QString &string) {
54
- QString escapedString(string);
55
- escapedString.replace("\"", "\\\"");
56
- m_buffer.append("\"");
57
- m_buffer.append(escapedString);
58
- m_buffer.append("\"");
59
- }
60
-
61
- void Evaluate::addArray(QVariantList &list) {
62
- m_buffer.append("[");
63
- for (int i = 0; i < list.length(); i++) {
64
- if (i > 0)
65
- m_buffer.append(",");
66
- addVariant(list[i]);
67
- }
68
- m_buffer.append("]");
69
- }
70
-
71
- void Evaluate::addMap(QVariantMap &map) {
72
- m_buffer.append("{");
73
- QMapIterator<QString, QVariant> iterator(map);
74
- while (iterator.hasNext()) {
75
- iterator.next();
76
- QString key = iterator.key();
77
- QVariant value = iterator.value();
78
- addString(key);
79
- m_buffer.append(":");
80
- addVariant(value);
81
- if (iterator.hasNext())
82
- m_buffer.append(",");
83
- }
84
- m_buffer.append("}");
12
+ JsonSerializer serializer;
13
+ emitFinished(true, serializer.serialize(result));
85
14
  }