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
@@ -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
  }