capybara-webkit 1.5.2 → 1.6.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -7,19 +7,23 @@ describe Capybara::Webkit, 'compatibility with selenium' do
7
7
  run_application_for_html(<<-HTML)
8
8
  <html><body>
9
9
  <form onsubmit="return false">
10
- <label for="one">One</label><input type="text" name="one" id="one" />
11
- <label for="two">Two</label><input type="text" name="two" id="two" />
12
- <label for="three">Three</label><input type="text" name="three" id="three" readonly="readonly" />
10
+ <label for="one">One</label><input type="text" name="one" id="one" class="watch" />
11
+ <label for="two">Two</label><input type="text" name="two" id="two" class="watch" />
12
+ <label for="three">Three</label><input type="text" name="three" id="three" readonly="readonly" class="watch" />
13
13
  <label for="textarea">Textarea</label>
14
14
  <textarea name="textarea" id="textarea"></textarea>
15
- <input type="submit" value="Submit" id="submit" />
15
+ <select name="select" id="five" class="watch">
16
+ <option>Nothing here</option>
17
+ <option>some option</option>
18
+ </select>
19
+ <input type="submit" value="Submit" id="submit" class="watch" />
16
20
  </form>
17
21
  <script type="text/javascript">
18
22
  window.log = [];
19
23
  var recordEvent = function (event) {
20
24
  log.push(event.target.id + '.' + event.type);
21
25
  };
22
- var elements = document.getElementsByTagName("input");
26
+ var elements = document.getElementsByClassName("watch");
23
27
  var events = ["mousedown", "mouseup", "click", "keyup", "keydown",
24
28
  "keypress", "focus", "blur", "input", "change"];
25
29
  for (var i = 0; i < elements.length; i++) {
@@ -38,17 +42,92 @@ describe Capybara::Webkit, 'compatibility with selenium' do
38
42
  fill_in "Two", :with => "other value"
39
43
  fill_in "Three", :with => "readonly value"
40
44
  fill_in "Textarea", :with => "last value"
45
+ select "some option", :from => "five"
41
46
  click_button "Submit"
42
47
  end
43
48
  end
44
49
 
50
+ it 'generates the same requests and responses as selenium', selenium_compatibility: true do
51
+ requests = []
52
+
53
+ app = Class.new(ExampleApp) do
54
+ before do
55
+ unless request.path_info =~ /favicon\.ico/
56
+ requests << request.path_info
57
+ end
58
+ end
59
+
60
+ get '/' do
61
+ <<-HTML
62
+ <html>
63
+ <head>
64
+ <script src="/one.js"></script>
65
+ <script src="/two.js"></script>
66
+ </head>
67
+ <body>Original</body>
68
+ </html>
69
+ HTML
70
+ end
71
+
72
+ get '/:script.js' do
73
+ ''
74
+ end
75
+
76
+ get '/requests' do
77
+ <<-HTML
78
+ <html>
79
+ <body>
80
+ #{requests.sort.join("\n")}
81
+ </body>
82
+ </html>
83
+ HTML
84
+ end
85
+ end
86
+
87
+ run_application app
88
+
89
+ compare_for_drivers(:reusable_webkit, :selenium) do |session|
90
+ responses = []
91
+ session.visit "/"
92
+ responses << record_response(session)
93
+ session.visit "/"
94
+ responses << record_response(session)
95
+ session.visit "/requests"
96
+ responses << record_response(session)
97
+ requests.clear
98
+ responses.join("\n\n")
99
+ end
100
+ end
101
+
45
102
  def compare_events_for_drivers(first, second, &block)
46
- events_for_driver(first, &block).should == events_for_driver(second, &block)
103
+ compare_for_drivers(first, second) do |session|
104
+ session.instance_eval(&block)
105
+ session.evaluate_script("window.log")
106
+ end
47
107
  end
48
108
 
49
- def events_for_driver(name, &block)
109
+ def compare_for_drivers(first, second, &block)
110
+ for_driver(first, &block).should == for_driver(second, &block)
111
+ end
112
+
113
+ def for_driver(name, &block)
50
114
  session = Capybara::Session.new(name, AppRunner.app)
51
- session.instance_eval(&block)
52
- session.evaluate_script("window.log")
115
+ result = yield session
116
+ result
117
+ end
118
+
119
+ def record_response(session)
120
+ [
121
+ session.current_url,
122
+ normalize_body(session.body)
123
+ ].join("\n")
124
+ end
125
+
126
+ def normalize_body(body)
127
+ if body.length > 0
128
+ Nokogiri::HTML.parse(body).at("//body").text.strip
129
+ else
130
+ "(empty)"
131
+ end
53
132
  end
54
133
  end
@@ -10,7 +10,7 @@ $LOAD_PATH << File.join(PROJECT_ROOT, 'lib')
10
10
  Dir[File.join(PROJECT_ROOT, 'spec', 'support', '**', '*.rb')].each { |file| require(file) }
11
11
 
12
12
  require 'capybara/webkit'
13
- $webkit_connection = Capybara::Webkit::Connection.new(:socket_class => TCPSocket)
13
+ $webkit_connection = Capybara::Webkit::Connection.new
14
14
  $webkit_browser = Capybara::Webkit::Browser.new($webkit_connection)
15
15
 
16
16
  if ENV['DEBUG']
@@ -29,7 +29,7 @@ def has_internet?
29
29
  begin
30
30
  dns_resolver.getaddress("example.com")
31
31
  true
32
- rescue Resolv::ResolvError => e
32
+ rescue Resolv::ResolvError
33
33
  false
34
34
  end
35
35
  end
@@ -42,6 +42,11 @@ RSpec.configure do |c|
42
42
  c.filter_run_excluding :selenium_compatibility => (Capybara::VERSION =~ /^2\.4\./).nil?
43
43
  c.filter_run_excluding :skip_if_offline => !has_internet?
44
44
 
45
+ #Check for QT version is 4 to skip QT5 required specs
46
+ #This should be removed once support for QT4 is dropped
47
+ require 'capybara_webkit_builder'
48
+ c.filter_run_excluding :skip_on_qt4 => !(%x(#{CapybaraWebkitBuilder.qmake_bin} -v).match(/Using Qt version 4/)).nil?
49
+
45
50
  # We can't support outerWidth and outerHeight without a visible window.
46
51
  # We focus the next window instead of failing when closing windows.
47
52
  c.filter_run_excluding :full_description =>
@@ -5,7 +5,7 @@ require 'sinatra/base'
5
5
 
6
6
  module AppRunner
7
7
  class << self
8
- attr_accessor :app, :app_host
8
+ attr_accessor :app, :app_host, :configuration
9
9
  end
10
10
 
11
11
  def self.boot
@@ -19,12 +19,18 @@ module AppRunner
19
19
  self.app = lambda do |env|
20
20
  [200, { 'Content-Type' => 'html', 'Content-Length' => 0 }, []]
21
21
  end
22
+
23
+ self.configuration = Capybara::Webkit::Configuration.new
22
24
  end
23
25
 
24
26
  def run_application(app)
25
27
  AppRunner.app = app
26
28
  end
27
29
 
30
+ def configure
31
+ yield AppRunner.configuration
32
+ end
33
+
28
34
  def driver_for_app(*driver_args, &body)
29
35
  app = Class.new(ExampleApp, &body)
30
36
  run_application app
@@ -50,8 +56,12 @@ module AppRunner
50
56
 
51
57
  private
52
58
 
53
- def build_driver(browser = $webkit_browser)
54
- Capybara::Webkit::Driver.new(AppRunner.app, :browser => browser)
59
+ def build_driver(overrides = {})
60
+ options = AppRunner.configuration.
61
+ to_hash.
62
+ merge(browser: $webkit_browser).
63
+ merge(overrides)
64
+ Capybara::Webkit::Driver.new(AppRunner.app, options)
55
65
  end
56
66
 
57
67
  def self.included(example_group)
@@ -11,6 +11,10 @@ void Authenticate::start() {
11
11
  QString password = arguments()[1];
12
12
 
13
13
  NetworkAccessManager* networkAccessManager = manager()->networkAccessManager();
14
+ #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
15
+ //Reset Authentication cache
16
+ networkAccessManager->clearAccessCache();
17
+ #endif
14
18
  networkAccessManager->setUserName(username);
15
19
  networkAccessManager->setPassword(password);
16
20
 
@@ -1,11 +1,14 @@
1
1
  #include "Headers.h"
2
2
  #include "WebPage.h"
3
3
  #include "WebPageManager.h"
4
+ #include "JsonSerializer.h"
4
5
 
5
6
  Headers::Headers(WebPageManager *manager, QStringList &arguments, QObject *parent) : SocketCommand(manager, arguments, parent) {
6
7
  }
7
8
 
8
9
  void Headers::start() {
9
- finish(true, page()->pageHeaders().join("\n"));
10
+ JsonSerializer serializer;
11
+ QByteArray json = serializer.serialize(page()->pageHeaders());
12
+ finish(true, json);
10
13
  }
11
14
 
@@ -9,6 +9,13 @@ Server::Server(QObject *parent) : QObject(parent) {
9
9
  }
10
10
 
11
11
  bool Server::start() {
12
+ #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
13
+ QTextStream(stderr) <<
14
+ "WARNING: The next major version of capybara-webkit " <<
15
+ "will require at least version 5.0 of Qt. " <<
16
+ "You're using version " << QT_VERSION_STR << "." << endl;
17
+ #endif
18
+
12
19
  connect(m_tcp_server, SIGNAL(newConnection()), this, SLOT(handleConnection()));
13
20
  return m_tcp_server->listen(QHostAddress::LocalHost, 0);
14
21
  }
@@ -83,13 +83,15 @@ void WebPage::setFrameProperties(QWebFrame *frame, QUrl &requestedUrl, NetworkRe
83
83
  if (frame->requestedUrl() == requestedUrl) {
84
84
  int statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
85
85
  frame->setProperty("statusCode", statusCode);
86
- QStringList headers;
87
- foreach(QNetworkReply::RawHeaderPair header, reply->rawHeaderPairs())
88
- headers << header.first+": "+header.second;
89
- frame->setProperty("headers", headers);
90
- frame->setProperty("body", reply->data());
91
- QVariant contentMimeType = reply->header(QNetworkRequest::ContentTypeHeader);
92
- frame->setProperty("contentType", contentMimeType);
86
+ if (statusCode != 304) {
87
+ QVariantMap headers;
88
+ foreach(QNetworkReply::RawHeaderPair header, reply->rawHeaderPairs())
89
+ headers[header.first] = QString(header.second);
90
+ frame->setProperty("headers", headers);
91
+ frame->setProperty("body", reply->data());
92
+ QVariant contentMimeType = reply->header(QNetworkRequest::ContentTypeHeader);
93
+ frame->setProperty("contentType", contentMimeType);
94
+ }
93
95
  }
94
96
  }
95
97
 
@@ -359,8 +361,8 @@ int WebPage::getLastStatus() {
359
361
  return currentFrame()->property("statusCode").toInt();
360
362
  }
361
363
 
362
- QStringList WebPage::pageHeaders() {
363
- return currentFrame()->property("headers").toStringList();
364
+ QVariantMap WebPage::pageHeaders() {
365
+ return currentFrame()->property("headers").toMap();
364
366
  }
365
367
 
366
368
  QByteArray WebPage::body() {
@@ -47,7 +47,7 @@ class WebPage : public QWebPage {
47
47
  bool matchesWindowSelector(QString);
48
48
  void setFocus();
49
49
  void unsupportedContentFinishedReply(QNetworkReply *reply);
50
- QStringList pageHeaders();
50
+ QVariantMap pageHeaders();
51
51
  QByteArray body();
52
52
  QString contentType();
53
53
  void mouseEvent(QEvent::Type type, const QPoint &position, Qt::MouseButton button);
@@ -30,9 +30,6 @@ WebPageManager::WebPageManager(QObject *parent) : QObject(parent) {
30
30
  new NetworkAccessManager(m_blacklistedRequestHandler, this);
31
31
  m_networkAccessManager->setCookieJar(m_cookieJar);
32
32
 
33
- QWebSettings::setMaximumPagesInCache(0);
34
- QWebSettings::setObjectCacheCapacities(0, 0, 0);
35
-
36
33
  createPage()->setFocus();
37
34
  }
38
35
 
@@ -228,9 +228,13 @@ Capybara = {
228
228
  },
229
229
 
230
230
  trigger: function (index, eventName) {
231
+ this.triggerOnNode(this.getNode(index), eventName);
232
+ },
233
+
234
+ triggerOnNode: function(node, eventName) {
231
235
  var eventObject = document.createEvent("HTMLEvents");
232
236
  eventObject.initEvent(eventName, true, true);
233
- this.getNode(index).dispatchEvent(eventObject);
237
+ node.dispatchEvent(eventObject);
234
238
  },
235
239
 
236
240
  visible: function (index) {
@@ -323,8 +327,21 @@ Capybara = {
323
327
  },
324
328
 
325
329
  selectOption: function(index) {
326
- this.getNode(index).selected = true;
327
- this.trigger(index, "change");
330
+ var optionNode = this.getNode(index);
331
+ var selectNode = optionNode.parentNode;
332
+
333
+ // click on select list
334
+ this.triggerOnNode(selectNode, 'mousedown');
335
+ selectNode.focus();
336
+ this.triggerOnNode(selectNode, 'mouseup');
337
+ this.triggerOnNode(selectNode, 'click');
338
+
339
+ // select option from list
340
+ this.triggerOnNode(optionNode, 'mousedown');
341
+ optionNode.selected = true;
342
+ this.triggerOnNode(selectNode, 'change');
343
+ this.triggerOnNode(optionNode, 'mouseup');
344
+ this.triggerOnNode(optionNode, 'click');
328
345
  },
329
346
 
330
347
  unselectOption: function(index) {
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: capybara-webkit
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.5.2
4
+ version: 1.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - thoughtbot
@@ -13,7 +13,7 @@ authors:
13
13
  autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
- date: 2015-06-05 00:00:00.000000000 Z
16
+ date: 2015-06-26 00:00:00.000000000 Z
17
17
  dependencies:
18
18
  - !ruby/object:Gem::Dependency
19
19
  name: capybara
@@ -177,17 +177,18 @@ files:
177
177
  - lib/capybara-webkit.rb
178
178
  - lib/capybara/webkit.rb
179
179
  - lib/capybara/webkit/browser.rb
180
+ - lib/capybara/webkit/configuration.rb
180
181
  - lib/capybara/webkit/connection.rb
181
182
  - lib/capybara/webkit/cookie_jar.rb
182
183
  - lib/capybara/webkit/driver.rb
183
184
  - lib/capybara/webkit/errors.rb
184
185
  - lib/capybara/webkit/matchers.rb
185
186
  - lib/capybara/webkit/node.rb
186
- - lib/capybara/webkit/socket_debugger.rb
187
187
  - lib/capybara/webkit/version.rb
188
188
  - lib/capybara_webkit_builder.rb
189
189
  - spec/browser_spec.rb
190
190
  - spec/capybara_webkit_builder_spec.rb
191
+ - spec/configuration_spec.rb
191
192
  - spec/connection_spec.rb
192
193
  - spec/cookie_jar_spec.rb
193
194
  - spec/driver_rendering_spec.rb
@@ -403,6 +404,7 @@ summary: Headless Webkit driver for Capybara
403
404
  test_files:
404
405
  - spec/browser_spec.rb
405
406
  - spec/capybara_webkit_builder_spec.rb
407
+ - spec/configuration_spec.rb
406
408
  - spec/connection_spec.rb
407
409
  - spec/cookie_jar_spec.rb
408
410
  - spec/driver_rendering_spec.rb
@@ -1,46 +0,0 @@
1
- # Wraps the TCP socket and prints data sent and received. Used for debugging
2
- # the wire protocol. You can use this by passing a :socket_class to Browser.
3
- module Capybara::Webkit
4
- class SocketDebugger
5
- def self.open(host, port)
6
- real_socket = TCPSocket.open(host, port)
7
- new(real_socket)
8
- end
9
-
10
- def initialize(socket)
11
- @socket = socket
12
- end
13
-
14
- def read(length)
15
- received @socket.read(length)
16
- end
17
-
18
- def puts(line)
19
- sent line
20
- @socket.puts(line)
21
- end
22
-
23
- def print(content)
24
- sent content
25
- @socket.print(content)
26
- end
27
-
28
- def gets
29
- received @socket.gets
30
- end
31
-
32
- def setsockopt(level, name, value)
33
- end
34
-
35
- private
36
-
37
- def sent(content)
38
- Kernel.puts " >> " + content.to_s
39
- end
40
-
41
- def received(content)
42
- Kernel.puts " << " + content.to_s
43
- content
44
- end
45
- end
46
- end