capybara-webkit 1.5.2 → 1.6.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.
@@ -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