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.
- checksums.yaml +4 -4
- data/.travis.yml +1 -0
- data/CONTRIBUTING.md +4 -1
- data/Gemfile.lock +1 -1
- data/NEWS.md +12 -0
- data/README.md +54 -12
- data/lib/capybara/webkit.rb +9 -4
- data/lib/capybara/webkit/browser.rb +18 -2
- data/lib/capybara/webkit/configuration.rb +98 -0
- data/lib/capybara/webkit/connection.rb +13 -1
- data/lib/capybara/webkit/driver.rb +133 -52
- data/lib/capybara/webkit/errors.rb +3 -0
- data/lib/capybara/webkit/node.rb +9 -8
- data/lib/capybara/webkit/version.rb +1 -1
- data/spec/browser_spec.rb +0 -229
- data/spec/configuration_spec.rb +16 -0
- data/spec/connection_spec.rb +15 -2
- data/spec/driver_spec.rb +343 -53
- data/spec/selenium_compatibility_spec.rb +88 -9
- data/spec/spec_helper.rb +7 -2
- data/spec/support/app_runner.rb +13 -3
- data/src/Authenticate.cpp +4 -0
- data/src/Headers.cpp +4 -1
- data/src/Server.cpp +7 -0
- data/src/WebPage.cpp +11 -9
- data/src/WebPage.h +1 -1
- data/src/WebPageManager.cpp +0 -3
- data/src/capybara.js +20 -3
- metadata +5 -3
- data/lib/capybara/webkit/socket_debugger.rb +0 -46
@@ -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
|
-
<
|
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.
|
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
|
-
|
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
|
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
|
52
|
-
|
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
|
data/spec/spec_helper.rb
CHANGED
@@ -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
|
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
|
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 =>
|
data/spec/support/app_runner.rb
CHANGED
@@ -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(
|
54
|
-
|
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)
|
data/src/Authenticate.cpp
CHANGED
@@ -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
|
|
data/src/Headers.cpp
CHANGED
@@ -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
|
-
|
10
|
+
JsonSerializer serializer;
|
11
|
+
QByteArray json = serializer.serialize(page()->pageHeaders());
|
12
|
+
finish(true, json);
|
10
13
|
}
|
11
14
|
|
data/src/Server.cpp
CHANGED
@@ -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
|
}
|
data/src/WebPage.cpp
CHANGED
@@ -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
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
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
|
-
|
363
|
-
return currentFrame()->property("headers").
|
364
|
+
QVariantMap WebPage::pageHeaders() {
|
365
|
+
return currentFrame()->property("headers").toMap();
|
364
366
|
}
|
365
367
|
|
366
368
|
QByteArray WebPage::body() {
|
data/src/WebPage.h
CHANGED
@@ -47,7 +47,7 @@ class WebPage : public QWebPage {
|
|
47
47
|
bool matchesWindowSelector(QString);
|
48
48
|
void setFocus();
|
49
49
|
void unsupportedContentFinishedReply(QNetworkReply *reply);
|
50
|
-
|
50
|
+
QVariantMap pageHeaders();
|
51
51
|
QByteArray body();
|
52
52
|
QString contentType();
|
53
53
|
void mouseEvent(QEvent::Type type, const QPoint &position, Qt::MouseButton button);
|
data/src/WebPageManager.cpp
CHANGED
@@ -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
|
|
data/src/capybara.js
CHANGED
@@ -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
|
-
|
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)
|
327
|
-
|
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.
|
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-
|
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
|