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
data/lib/capybara/webkit/node.rb
CHANGED
@@ -1,5 +1,10 @@
|
|
1
1
|
module Capybara::Webkit
|
2
2
|
class Node < Capybara::Driver::Node
|
3
|
+
def initialize(session, base, browser)
|
4
|
+
super(session, base)
|
5
|
+
@browser = browser
|
6
|
+
end
|
7
|
+
|
3
8
|
def visible_text
|
4
9
|
Capybara::Helpers.normalize_whitespace(invoke("text"))
|
5
10
|
end
|
@@ -113,7 +118,7 @@ module Capybara::Webkit
|
|
113
118
|
|
114
119
|
def find_xpath(xpath)
|
115
120
|
invoke("findXpathWithin", xpath).split(',').map do |native|
|
116
|
-
self.class.new(driver, native)
|
121
|
+
self.class.new(driver, native, @browser)
|
117
122
|
end
|
118
123
|
end
|
119
124
|
|
@@ -121,12 +126,12 @@ module Capybara::Webkit
|
|
121
126
|
|
122
127
|
def find_css(selector)
|
123
128
|
invoke("findCssWithin", selector).split(',').map do |native|
|
124
|
-
self.class.new(driver, native)
|
129
|
+
self.class.new(driver, native, @browser)
|
125
130
|
end
|
126
131
|
end
|
127
132
|
|
128
133
|
def invoke(name, *args)
|
129
|
-
browser.command "Node", name, allow_unattached_nodes?, native, *args
|
134
|
+
@browser.command "Node", name, allow_unattached_nodes?, native, *args
|
130
135
|
end
|
131
136
|
|
132
137
|
def allow_unattached_nodes?
|
@@ -138,11 +143,7 @@ module Capybara::Webkit
|
|
138
143
|
end
|
139
144
|
|
140
145
|
def attached?
|
141
|
-
browser.command("Node", "isAttached", native) == "true"
|
142
|
-
end
|
143
|
-
|
144
|
-
def browser
|
145
|
-
driver.browser
|
146
|
+
@browser.command("Node", "isAttached", native) == "true"
|
146
147
|
end
|
147
148
|
|
148
149
|
def multiple_select?
|
data/spec/browser_spec.rb
CHANGED
@@ -9,144 +9,6 @@ describe Capybara::Webkit::Browser do
|
|
9
9
|
|
10
10
|
let(:connection) { Capybara::Webkit::Connection.new }
|
11
11
|
let(:browser) { Capybara::Webkit::Browser.new(connection) }
|
12
|
-
let(:browser_ignore_ssl_err) do
|
13
|
-
Capybara::Webkit::Browser.new(Capybara::Webkit::Connection.new).tap do |browser|
|
14
|
-
browser.ignore_ssl_errors
|
15
|
-
end
|
16
|
-
end
|
17
|
-
let(:browser_skip_images) do
|
18
|
-
Capybara::Webkit::Browser.new(Capybara::Webkit::Connection.new).tap do |browser|
|
19
|
-
browser.set_skip_image_loading(true)
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
context 'handling of SSL validation errors' do
|
24
|
-
before do
|
25
|
-
# set up minimal HTTPS server
|
26
|
-
@host = "127.0.0.1"
|
27
|
-
@server = TCPServer.new(@host, 0)
|
28
|
-
@port = @server.addr[1]
|
29
|
-
|
30
|
-
# set up SSL layer
|
31
|
-
ssl_serv = OpenSSL::SSL::SSLServer.new(@server, $openssl_self_signed_ctx)
|
32
|
-
|
33
|
-
@server_thread = Thread.new(ssl_serv) do |serv|
|
34
|
-
while conn = serv.accept do
|
35
|
-
# read request
|
36
|
-
request = []
|
37
|
-
until (line = conn.readline.strip).empty?
|
38
|
-
request << line
|
39
|
-
end
|
40
|
-
|
41
|
-
# write response
|
42
|
-
html = "<html><body>D'oh!</body></html>"
|
43
|
-
conn.write "HTTP/1.1 200 OK\r\n"
|
44
|
-
conn.write "Content-Type:text/html\r\n"
|
45
|
-
conn.write "Content-Length: %i\r\n" % html.size
|
46
|
-
conn.write "\r\n"
|
47
|
-
conn.write html
|
48
|
-
conn.close
|
49
|
-
end
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
after do
|
54
|
-
@server_thread.kill
|
55
|
-
@server.close
|
56
|
-
end
|
57
|
-
|
58
|
-
it "doesn't accept a self-signed certificate by default" do
|
59
|
-
lambda { browser.visit "https://#{@host}:#{@port}/" }.should raise_error
|
60
|
-
end
|
61
|
-
|
62
|
-
it 'accepts a self-signed certificate if configured to do so' do
|
63
|
-
browser_ignore_ssl_err.visit "https://#{@host}:#{@port}/"
|
64
|
-
end
|
65
|
-
|
66
|
-
it "doesn't accept a self-signed certificate in a new window by default" do
|
67
|
-
browser.execute_script("window.open('about:blank')")
|
68
|
-
browser.window_focus(browser.get_window_handles.last)
|
69
|
-
lambda { browser.visit "https://#{@host}:#{@port}/" }.should raise_error
|
70
|
-
end
|
71
|
-
|
72
|
-
it 'accepts a self-signed certificate in a new window if configured to do so' do
|
73
|
-
browser_ignore_ssl_err.execute_script("window.open('about:blank')")
|
74
|
-
browser_ignore_ssl_err.window_focus(browser_ignore_ssl_err.get_window_handles.last)
|
75
|
-
browser_ignore_ssl_err.visit "https://#{@host}:#{@port}/"
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
context "skip image loading" do
|
80
|
-
before(:each) do
|
81
|
-
# set up minimal HTTP server
|
82
|
-
@host = "127.0.0.1"
|
83
|
-
@server = TCPServer.new(@host, 0)
|
84
|
-
@port = @server.addr[1]
|
85
|
-
@received_requests = []
|
86
|
-
|
87
|
-
@server_thread = Thread.new do
|
88
|
-
while conn = @server.accept
|
89
|
-
Thread.new(conn) do |thread_conn|
|
90
|
-
# read request
|
91
|
-
request = []
|
92
|
-
until (line = thread_conn.readline.strip).empty?
|
93
|
-
request << line
|
94
|
-
end
|
95
|
-
|
96
|
-
@received_requests << request.join("\n")
|
97
|
-
|
98
|
-
# write response
|
99
|
-
html = <<-HTML
|
100
|
-
<html>
|
101
|
-
<head>
|
102
|
-
<style>
|
103
|
-
body {
|
104
|
-
background-image: url(/path/to/bgimage);
|
105
|
-
}
|
106
|
-
</style>
|
107
|
-
</head>
|
108
|
-
<body>
|
109
|
-
<img src="/path/to/image"/>
|
110
|
-
</body>
|
111
|
-
</html>
|
112
|
-
HTML
|
113
|
-
thread_conn.write "HTTP/1.1 200 OK\r\n"
|
114
|
-
thread_conn.write "Content-Type:text/html\r\n"
|
115
|
-
thread_conn.write "Content-Length: %i\r\n" % html.size
|
116
|
-
thread_conn.write "\r\n"
|
117
|
-
thread_conn.write html
|
118
|
-
thread_conn.write("\r\n\r\n")
|
119
|
-
thread_conn.close
|
120
|
-
end
|
121
|
-
end
|
122
|
-
end
|
123
|
-
end
|
124
|
-
|
125
|
-
after(:each) do
|
126
|
-
@server_thread.kill
|
127
|
-
@server.close
|
128
|
-
end
|
129
|
-
|
130
|
-
it "should load images in image tags by default" do
|
131
|
-
browser.visit("http://#{@host}:#{@port}/")
|
132
|
-
@received_requests.find {|r| r =~ %r{/path/to/image} }.should_not be_nil
|
133
|
-
end
|
134
|
-
|
135
|
-
it "should load images in css by default" do
|
136
|
-
browser.visit("http://#{@host}:#{@port}/")
|
137
|
-
@received_requests.find {|r| r =~ %r{/path/to/image} }.should_not be_nil
|
138
|
-
end
|
139
|
-
|
140
|
-
it "should not load images in image tags when skip_image_loading is true" do
|
141
|
-
browser_skip_images.visit("http://#{@host}:#{@port}/")
|
142
|
-
@received_requests.find {|r| r =~ %r{/path/to/image} }.should be_nil
|
143
|
-
end
|
144
|
-
|
145
|
-
it "should not load images in css when skip_image_loading is true" do
|
146
|
-
browser_skip_images.visit("http://#{@host}:#{@port}/")
|
147
|
-
@received_requests.find {|r| r =~ %r{/path/to/bgimage} }.should be_nil
|
148
|
-
end
|
149
|
-
end
|
150
12
|
|
151
13
|
describe "forking", skip_on_windows: true, skip_on_jruby: true do
|
152
14
|
it "only shuts down the server from the main process" do
|
@@ -157,97 +19,6 @@ describe Capybara::Webkit::Browser do
|
|
157
19
|
end
|
158
20
|
end
|
159
21
|
|
160
|
-
describe '#set_proxy' do
|
161
|
-
before do
|
162
|
-
@host = '127.0.0.1'
|
163
|
-
@user = 'user'
|
164
|
-
@pass = 'secret'
|
165
|
-
@url = "http://example.org/"
|
166
|
-
|
167
|
-
@server = TCPServer.new(@host, 0)
|
168
|
-
@port = @server.addr[1]
|
169
|
-
|
170
|
-
@proxy_requests = []
|
171
|
-
@proxy = Thread.new(@server, @proxy_requests) do |serv, proxy_requests|
|
172
|
-
while conn = serv.accept do
|
173
|
-
# read request
|
174
|
-
request = []
|
175
|
-
until (line = conn.readline.strip).empty?
|
176
|
-
request << line
|
177
|
-
end
|
178
|
-
|
179
|
-
# send response
|
180
|
-
auth_header = request.find { |h| h =~ /Authorization:/i }
|
181
|
-
if auth_header || request[0].split(/\s+/)[1] =~ /^\//
|
182
|
-
html = "<html><body>D'oh!</body></html>"
|
183
|
-
conn.write "HTTP/1.1 200 OK\r\n"
|
184
|
-
conn.write "Content-Type:text/html\r\n"
|
185
|
-
conn.write "Content-Length: %i\r\n" % html.size
|
186
|
-
conn.write "\r\n"
|
187
|
-
conn.write html
|
188
|
-
conn.close
|
189
|
-
proxy_requests << request if auth_header
|
190
|
-
else
|
191
|
-
conn.write "HTTP/1.1 407 Proxy Auth Required\r\n"
|
192
|
-
conn.write "Proxy-Authenticate: Basic realm=\"Proxy\"\r\n"
|
193
|
-
conn.write "\r\n"
|
194
|
-
conn.close
|
195
|
-
proxy_requests << request
|
196
|
-
end
|
197
|
-
end
|
198
|
-
end
|
199
|
-
|
200
|
-
browser.set_proxy(:host => @host,
|
201
|
-
:port => @port,
|
202
|
-
:user => @user,
|
203
|
-
:pass => @pass)
|
204
|
-
browser.visit @url
|
205
|
-
@proxy_requests.size.should eq 2
|
206
|
-
@request = @proxy_requests[-1]
|
207
|
-
end
|
208
|
-
|
209
|
-
after do
|
210
|
-
@proxy.kill
|
211
|
-
@server.close
|
212
|
-
end
|
213
|
-
|
214
|
-
it 'uses the HTTP proxy correctly' do
|
215
|
-
@request[0].should match(/^GET\s+http:\/\/example.org\/\s+HTTP/i)
|
216
|
-
@request.find { |header|
|
217
|
-
header =~ /^Host:\s+example.org$/i }.should_not be nil
|
218
|
-
end
|
219
|
-
|
220
|
-
it 'sends correct proxy authentication' do
|
221
|
-
auth_header = @request.find { |header|
|
222
|
-
header =~ /^Proxy-Authorization:\s+/i }
|
223
|
-
auth_header.should_not be nil
|
224
|
-
|
225
|
-
user, pass = Base64.decode64(auth_header.split(/\s+/)[-1]).split(":")
|
226
|
-
user.should eq @user
|
227
|
-
pass.should eq @pass
|
228
|
-
end
|
229
|
-
|
230
|
-
it "uses the proxies' response" do
|
231
|
-
browser.body.should include "D'oh!"
|
232
|
-
end
|
233
|
-
|
234
|
-
it 'uses original URL' do
|
235
|
-
browser.current_url.should eq @url
|
236
|
-
end
|
237
|
-
|
238
|
-
it 'uses URLs changed by javascript' do
|
239
|
-
browser.execute_script "window.history.pushState('', '', '/blah')"
|
240
|
-
browser.current_url.should eq 'http://example.org/blah'
|
241
|
-
end
|
242
|
-
|
243
|
-
it 'is possible to disable proxy again' do
|
244
|
-
@proxy_requests.clear
|
245
|
-
browser.clear_proxy
|
246
|
-
browser.visit "http://#{@host}:#{@port}/"
|
247
|
-
@proxy_requests.size.should eq 0
|
248
|
-
end
|
249
|
-
end
|
250
|
-
|
251
22
|
it "doesn't try to read an empty response" do
|
252
23
|
connection = double("connection")
|
253
24
|
connection.stub(:puts)
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Capybara::Webkit::Configuration do
|
4
|
+
it "returns a hash and then prevents future modification" do
|
5
|
+
Capybara::Webkit.configure do |config|
|
6
|
+
config.debug = true
|
7
|
+
end
|
8
|
+
|
9
|
+
result = Capybara::Webkit::Configuration.to_hash
|
10
|
+
|
11
|
+
expect(result).to include(debug: true)
|
12
|
+
expect { Capybara::Webkit.configure {} }.to raise_error(
|
13
|
+
"All configuration must take place before the driver starts"
|
14
|
+
)
|
15
|
+
end
|
16
|
+
end
|
data/spec/connection_spec.rb
CHANGED
@@ -19,8 +19,21 @@ describe Capybara::Webkit::Connection do
|
|
19
19
|
webkit_pid.should be > 1
|
20
20
|
read_io.close
|
21
21
|
Process.kill(9, fork_pid)
|
22
|
-
|
23
|
-
|
22
|
+
eventually { expect { Process.getpgid(webkit_pid) }.to raise_error Errno::ESRCH }
|
23
|
+
end
|
24
|
+
|
25
|
+
def eventually
|
26
|
+
polling_interval = 0.1
|
27
|
+
time_limit = Time.now + 3
|
28
|
+
loop do
|
29
|
+
begin
|
30
|
+
yield
|
31
|
+
return
|
32
|
+
rescue RSpec::Expectations::ExpectationNotMetError => error
|
33
|
+
raise error if Time.now >= time_limit
|
34
|
+
sleep polling_interval
|
35
|
+
end
|
36
|
+
end
|
24
37
|
end
|
25
38
|
|
26
39
|
it "raises an error if the server has stopped", skip_on_windows: true do
|
data/spec/driver_spec.rb
CHANGED
@@ -3,6 +3,7 @@
|
|
3
3
|
require 'spec_helper'
|
4
4
|
require 'capybara/webkit/driver'
|
5
5
|
require 'base64'
|
6
|
+
require 'self_signed_ssl_cert'
|
6
7
|
|
7
8
|
describe Capybara::Webkit::Driver do
|
8
9
|
include AppRunner
|
@@ -1808,7 +1809,7 @@ describe Capybara::Webkit::Driver do
|
|
1808
1809
|
|
1809
1810
|
context "no response app" do
|
1810
1811
|
let(:driver) do
|
1811
|
-
driver_for_html(<<-HTML)
|
1812
|
+
driver_for_html(<<-HTML, browser: browser)
|
1812
1813
|
<html><body>
|
1813
1814
|
<form action="/error"><input type="submit"/></form>
|
1814
1815
|
</body></html>
|
@@ -1827,16 +1828,19 @@ describe Capybara::Webkit::Driver do
|
|
1827
1828
|
end
|
1828
1829
|
|
1829
1830
|
def make_the_server_come_back
|
1830
|
-
|
1831
|
-
|
1832
|
-
|
1831
|
+
connection.unstub(:gets)
|
1832
|
+
connection.unstub(:puts)
|
1833
|
+
connection.unstub(:print)
|
1833
1834
|
end
|
1834
1835
|
|
1835
1836
|
def make_the_server_go_away
|
1836
|
-
|
1837
|
-
|
1838
|
-
|
1837
|
+
connection.stub(:gets).and_return(nil)
|
1838
|
+
connection.stub(:puts)
|
1839
|
+
connection.stub(:print)
|
1839
1840
|
end
|
1841
|
+
|
1842
|
+
let(:browser) { Capybara::Webkit::Browser.new(connection) }
|
1843
|
+
let(:connection) { Capybara::Webkit::Connection.new }
|
1840
1844
|
end
|
1841
1845
|
|
1842
1846
|
context "custom font app" do
|
@@ -1906,30 +1910,21 @@ describe Capybara::Webkit::Driver do
|
|
1906
1910
|
end
|
1907
1911
|
|
1908
1912
|
it "uses a custom cookie" do
|
1909
|
-
driver.
|
1913
|
+
driver.set_cookie 'cookie=abc; domain=127.0.0.1; path=/'
|
1910
1914
|
visit "/"
|
1911
1915
|
echoed_cookie.should eq "abc"
|
1912
1916
|
end
|
1913
1917
|
|
1914
1918
|
it "clears cookies" do
|
1915
|
-
driver.
|
1919
|
+
driver.clear_cookies
|
1916
1920
|
visit "/"
|
1917
1921
|
echoed_cookie.should eq ""
|
1918
1922
|
end
|
1919
1923
|
|
1920
|
-
it "allows
|
1921
|
-
cookies = driver.browser.get_cookies
|
1922
|
-
|
1923
|
-
cookies.size.should eq 1
|
1924
|
-
|
1925
|
-
cookie = Hash[cookies[0].split(/\s*;\s*/).map { |x| x.split("=", 2) }]
|
1926
|
-
cookie["cookie"].should eq "abc"
|
1927
|
-
cookie["domain"].should include "127.0.0.1"
|
1928
|
-
cookie["path"].should eq "/"
|
1929
|
-
end
|
1930
|
-
|
1931
|
-
it "allows reading access to cookies using a nice syntax" do
|
1924
|
+
it "allows reading cookies" do
|
1932
1925
|
driver.cookies["cookie"].should eq "abc"
|
1926
|
+
driver.cookies.find("cookie").path.should eq "/"
|
1927
|
+
driver.cookies.find("cookie").domain.should include "127.0.0.1"
|
1933
1928
|
end
|
1934
1929
|
end
|
1935
1930
|
|
@@ -2120,14 +2115,23 @@ describe Capybara::Webkit::Driver do
|
|
2120
2115
|
driver_for_app do
|
2121
2116
|
get '/' do
|
2122
2117
|
etag etag_value
|
2118
|
+
<<-HTML
|
2119
|
+
<html>
|
2120
|
+
<body>
|
2121
|
+
Expected body
|
2122
|
+
</body>
|
2123
|
+
</html>
|
2124
|
+
HTML
|
2123
2125
|
end
|
2124
2126
|
end
|
2125
2127
|
end
|
2126
2128
|
|
2127
|
-
it "
|
2129
|
+
it "returns a body for cached responses" do
|
2128
2130
|
visit '/'
|
2131
|
+
first = driver.html
|
2129
2132
|
visit '/'
|
2130
|
-
|
2133
|
+
second = driver.html
|
2134
|
+
expect(second).to eq(first)
|
2131
2135
|
end
|
2132
2136
|
end
|
2133
2137
|
|
@@ -2592,20 +2596,27 @@ CACHE MANIFEST
|
|
2592
2596
|
end
|
2593
2597
|
|
2594
2598
|
it "can authenticate a request" do
|
2595
|
-
driver.
|
2599
|
+
driver.authenticate('user', 'password')
|
2596
2600
|
visit("/")
|
2597
2601
|
driver.html.should include("Basic "+Base64.encode64("user:password").strip)
|
2598
2602
|
end
|
2599
2603
|
|
2600
2604
|
it "returns 401 for incorrectly authenticated request" do
|
2601
|
-
driver.
|
2602
|
-
driver.browser.timeout = 2
|
2605
|
+
driver.authenticate('user1', 'password1')
|
2603
2606
|
lambda { visit("/") }.should_not raise_error
|
2604
2607
|
driver.status_code.should eq 401
|
2605
2608
|
end
|
2606
2609
|
|
2607
2610
|
it "returns 401 for unauthenticated request" do
|
2608
|
-
|
2611
|
+
lambda { visit("/") }.should_not raise_error
|
2612
|
+
driver.status_code.should eq 401
|
2613
|
+
end
|
2614
|
+
|
2615
|
+
it "can be reset with subsequent authenticate call", skip_on_qt4: true do
|
2616
|
+
driver.authenticate('user', 'password')
|
2617
|
+
visit("/")
|
2618
|
+
driver.html.should include("Basic "+Base64.encode64("user:password").strip)
|
2619
|
+
driver.authenticate('user1', 'password1')
|
2609
2620
|
lambda { visit("/") }.should_not raise_error
|
2610
2621
|
driver.status_code.should eq 401
|
2611
2622
|
end
|
@@ -2647,10 +2658,12 @@ CACHE MANIFEST
|
|
2647
2658
|
end
|
2648
2659
|
|
2649
2660
|
before do
|
2650
|
-
|
2651
|
-
|
2652
|
-
|
2653
|
-
|
2661
|
+
configure do |config|
|
2662
|
+
config.block_url "http://example.org/path/to/file"
|
2663
|
+
config.block_url "http://example.*/foo/*"
|
2664
|
+
config.block_url "http://example.com"
|
2665
|
+
config.block_url "#{AppRunner.app_host}/script"
|
2666
|
+
end
|
2654
2667
|
end
|
2655
2668
|
|
2656
2669
|
it "should not fetch urls blocked by host" do
|
@@ -2697,7 +2710,7 @@ CACHE MANIFEST
|
|
2697
2710
|
describe "url whitelisting", skip_if_offline: true do
|
2698
2711
|
it_behaves_like "output writer" do
|
2699
2712
|
let(:driver) do
|
2700
|
-
driver_for_html(<<-HTML, browser)
|
2713
|
+
driver_for_html(<<-HTML, browser: browser)
|
2701
2714
|
<<-HTML
|
2702
2715
|
<html>
|
2703
2716
|
<body>
|
@@ -2717,8 +2730,22 @@ CACHE MANIFEST
|
|
2717
2730
|
end
|
2718
2731
|
|
2719
2732
|
it "can allow specific hosts" do
|
2720
|
-
|
2721
|
-
|
2733
|
+
configure do |config|
|
2734
|
+
config.allow_url("example.com")
|
2735
|
+
config.allow_url("www.example.com")
|
2736
|
+
end
|
2737
|
+
|
2738
|
+
visit("/")
|
2739
|
+
|
2740
|
+
expect(stderr).not_to include("http://example.com/path")
|
2741
|
+
expect(stderr).not_to include(driver.current_url)
|
2742
|
+
driver.within_frame("frame") do
|
2743
|
+
expect(driver.find("//body").first.text).not_to be_empty
|
2744
|
+
end
|
2745
|
+
end
|
2746
|
+
|
2747
|
+
it "can allow all hosts" do
|
2748
|
+
configure(&:allow_unknown_urls)
|
2722
2749
|
visit("/")
|
2723
2750
|
|
2724
2751
|
expect(stderr).not_to include("http://example.com/path")
|
@@ -2728,8 +2755,17 @@ CACHE MANIFEST
|
|
2728
2755
|
end
|
2729
2756
|
end
|
2730
2757
|
|
2758
|
+
it "resets allowed hosts on reset" do
|
2759
|
+
driver.allow_unknown_urls
|
2760
|
+
driver.reset!
|
2761
|
+
visit("/")
|
2762
|
+
|
2763
|
+
expect(stderr).to include("http://example.com/path")
|
2764
|
+
expect(stderr).not_to include(driver.current_url)
|
2765
|
+
end
|
2766
|
+
|
2731
2767
|
it "can block unknown hosts" do
|
2732
|
-
|
2768
|
+
configure(&:block_unknown_urls)
|
2733
2769
|
visit("/")
|
2734
2770
|
|
2735
2771
|
expect(stderr).not_to include("http://example.com/path")
|
@@ -2740,7 +2776,7 @@ CACHE MANIFEST
|
|
2740
2776
|
end
|
2741
2777
|
|
2742
2778
|
it "can allow urls with wildcards" do
|
2743
|
-
|
2779
|
+
configure { |config| config.allow_url("*/path") }
|
2744
2780
|
visit("/")
|
2745
2781
|
|
2746
2782
|
expect(stderr).to include("www.example.com")
|
@@ -2790,65 +2826,64 @@ CACHE MANIFEST
|
|
2790
2826
|
end
|
2791
2827
|
|
2792
2828
|
it "should not raise a timeout error when zero" do
|
2793
|
-
|
2829
|
+
configure { |config| config.timeout = 0 }
|
2794
2830
|
lambda { visit("/") }.should_not raise_error
|
2795
2831
|
end
|
2796
2832
|
|
2797
2833
|
it "should raise a timeout error" do
|
2798
|
-
|
2834
|
+
configure { |config| config.timeout = 1 }
|
2799
2835
|
lambda { visit("/") }.should raise_error(Timeout::Error, "Request timed out after 1 second(s)")
|
2800
2836
|
end
|
2801
2837
|
|
2802
2838
|
it "should not raise an error when the timeout is high enough" do
|
2803
|
-
|
2839
|
+
configure { |config| config.timeout = 10 }
|
2804
2840
|
lambda { visit("/") }.should_not raise_error
|
2805
2841
|
end
|
2806
2842
|
|
2807
2843
|
it "should set the timeout for each request" do
|
2808
|
-
|
2844
|
+
configure { |config| config.timeout = 10 }
|
2809
2845
|
lambda { visit("/") }.should_not raise_error
|
2810
|
-
driver.
|
2846
|
+
driver.timeout = 1
|
2811
2847
|
lambda { visit("/") }.should raise_error(Timeout::Error)
|
2812
2848
|
end
|
2813
2849
|
|
2814
2850
|
it "should set the timeout for each request" do
|
2815
|
-
|
2851
|
+
configure { |config| config.timeout = 1 }
|
2816
2852
|
lambda { visit("/") }.should raise_error(Timeout::Error)
|
2817
2853
|
driver.reset!
|
2818
|
-
driver.
|
2854
|
+
driver.timeout = 10
|
2819
2855
|
lambda { visit("/") }.should_not raise_error
|
2820
2856
|
end
|
2821
2857
|
|
2822
2858
|
it "should raise a timeout on a slow form" do
|
2823
|
-
|
2859
|
+
configure { |config| config.timeout = 3 }
|
2824
2860
|
visit("/")
|
2825
2861
|
driver.status_code.should eq 200
|
2826
|
-
driver.
|
2862
|
+
driver.timeout = 1
|
2827
2863
|
driver.find_xpath("//input").first.click
|
2828
2864
|
lambda { driver.status_code }.should raise_error(Timeout::Error)
|
2829
2865
|
end
|
2830
2866
|
|
2831
2867
|
it "get timeout" do
|
2832
|
-
|
2868
|
+
configure { |config| config.timeout = 10 }
|
2833
2869
|
driver.browser.timeout.should eq 10
|
2834
|
-
driver.browser.timeout = 3
|
2835
|
-
driver.browser.timeout.should eq 3
|
2836
2870
|
end
|
2837
2871
|
end
|
2838
2872
|
|
2839
2873
|
describe "logger app" do
|
2840
2874
|
it_behaves_like "output writer" do
|
2841
2875
|
let(:driver) do
|
2842
|
-
driver_for_html("<html><body>Hello</body></html>", browser)
|
2876
|
+
driver_for_html("<html><body>Hello</body></html>", browser: browser)
|
2843
2877
|
end
|
2844
2878
|
|
2845
|
-
it "logs nothing
|
2879
|
+
it "logs nothing in normal mode" do
|
2880
|
+
configure { |config| config.debug = false }
|
2846
2881
|
visit("/")
|
2847
2882
|
stderr.should_not include logging_message
|
2848
2883
|
end
|
2849
2884
|
|
2850
|
-
it "logs its commands
|
2851
|
-
|
2885
|
+
it "logs its commands in debug mode" do
|
2886
|
+
configure { |config| config.debug = true }
|
2852
2887
|
visit("/")
|
2853
2888
|
stderr.should include logging_message
|
2854
2889
|
end
|
@@ -2997,11 +3032,29 @@ CACHE MANIFEST
|
|
2997
3032
|
end
|
2998
3033
|
end
|
2999
3034
|
|
3035
|
+
context "response header contains colon" do
|
3036
|
+
let(:driver) do
|
3037
|
+
driver_for_app do
|
3038
|
+
get "/" do
|
3039
|
+
headers "Content-Disposition" => 'filename="File: name.txt"'
|
3040
|
+
end
|
3041
|
+
end
|
3042
|
+
end
|
3043
|
+
|
3044
|
+
it "sets the response header" do
|
3045
|
+
visit("/")
|
3046
|
+
|
3047
|
+
expect(
|
3048
|
+
driver.response_headers["Content-Disposition"]
|
3049
|
+
).to eq 'filename="File: name.txt"'
|
3050
|
+
end
|
3051
|
+
end
|
3052
|
+
|
3000
3053
|
context "with unfinished responses" do
|
3001
3054
|
it_behaves_like "output writer" do
|
3002
3055
|
let(:driver) do
|
3003
3056
|
count = 0
|
3004
|
-
driver_for_app browser do
|
3057
|
+
driver_for_app browser: browser do
|
3005
3058
|
get "/" do
|
3006
3059
|
count += 1
|
3007
3060
|
<<-HTML
|
@@ -3044,6 +3097,243 @@ CACHE MANIFEST
|
|
3044
3097
|
end
|
3045
3098
|
end
|
3046
3099
|
|
3100
|
+
context "when the driver process crashes" do
|
3101
|
+
let(:driver) do
|
3102
|
+
driver_for_app browser: browser do
|
3103
|
+
get "/" do
|
3104
|
+
"<html><body>Relaunched</body></html>"
|
3105
|
+
end
|
3106
|
+
end
|
3107
|
+
end
|
3108
|
+
|
3109
|
+
let(:browser) { Capybara::Webkit::Browser.new(connection) }
|
3110
|
+
let(:connection) { Capybara::Webkit::Connection.new }
|
3111
|
+
|
3112
|
+
it "reports and relaunches on reset" do
|
3113
|
+
Process.kill "KILL", connection.pid
|
3114
|
+
expect { driver.reset! }.to raise_error(Capybara::Webkit::CrashError)
|
3115
|
+
visit "/"
|
3116
|
+
expect(driver.html).to include("Relaunched")
|
3117
|
+
end
|
3118
|
+
end
|
3119
|
+
|
3120
|
+
context "handling of SSL validation errors" do
|
3121
|
+
before do
|
3122
|
+
# set up minimal HTTPS server
|
3123
|
+
@host = "127.0.0.1"
|
3124
|
+
@server = TCPServer.new(@host, 0)
|
3125
|
+
@port = @server.addr[1]
|
3126
|
+
|
3127
|
+
# set up SSL layer
|
3128
|
+
ssl_serv = OpenSSL::SSL::SSLServer.new(@server, $openssl_self_signed_ctx)
|
3129
|
+
|
3130
|
+
@server_thread = Thread.new(ssl_serv) do |serv|
|
3131
|
+
while conn = serv.accept do
|
3132
|
+
# read request
|
3133
|
+
request = []
|
3134
|
+
until (line = conn.readline.strip).empty?
|
3135
|
+
request << line
|
3136
|
+
end
|
3137
|
+
|
3138
|
+
# write response
|
3139
|
+
html = "<html><body>D'oh!</body></html>"
|
3140
|
+
conn.write "HTTP/1.1 200 OK\r\n"
|
3141
|
+
conn.write "Content-Type:text/html\r\n"
|
3142
|
+
conn.write "Content-Length: %i\r\n" % html.size
|
3143
|
+
conn.write "\r\n"
|
3144
|
+
conn.write html
|
3145
|
+
conn.close
|
3146
|
+
end
|
3147
|
+
end
|
3148
|
+
end
|
3149
|
+
|
3150
|
+
after do
|
3151
|
+
@server_thread.kill
|
3152
|
+
@server.close
|
3153
|
+
end
|
3154
|
+
|
3155
|
+
context "with default settings" do
|
3156
|
+
it "doesn't accept a self-signed certificate" do
|
3157
|
+
lambda { driver.visit "https://#{@host}:#{@port}/" }.should raise_error
|
3158
|
+
end
|
3159
|
+
|
3160
|
+
it "doesn't accept a self-signed certificate in a new window" do
|
3161
|
+
driver.execute_script("window.open('about:blank')")
|
3162
|
+
driver.switch_to_window(driver.window_handles.last)
|
3163
|
+
lambda { driver.visit "https://#{@host}:#{@port}/" }.should raise_error
|
3164
|
+
end
|
3165
|
+
end
|
3166
|
+
|
3167
|
+
context "ignoring SSL errors" do
|
3168
|
+
it "accepts a self-signed certificate if configured to do so" do
|
3169
|
+
configure(&:ignore_ssl_errors)
|
3170
|
+
driver.visit "https://#{@host}:#{@port}/"
|
3171
|
+
end
|
3172
|
+
|
3173
|
+
it "accepts a self-signed certificate in a new window when configured" do
|
3174
|
+
configure(&:ignore_ssl_errors)
|
3175
|
+
driver.execute_script("window.open('about:blank')")
|
3176
|
+
driver.switch_to_window(driver.window_handles.last)
|
3177
|
+
driver.visit "https://#{@host}:#{@port}/"
|
3178
|
+
end
|
3179
|
+
end
|
3180
|
+
|
3181
|
+
let(:driver) { driver_for_html("", browser: browser) }
|
3182
|
+
let(:browser) { Capybara::Webkit::Browser.new(connection) }
|
3183
|
+
let(:connection) { Capybara::Webkit::Connection.new }
|
3184
|
+
end
|
3185
|
+
|
3186
|
+
context "skip image loading" do
|
3187
|
+
let(:driver) do
|
3188
|
+
driver_for_app do
|
3189
|
+
requests = []
|
3190
|
+
|
3191
|
+
get "/" do
|
3192
|
+
<<-HTML
|
3193
|
+
<html>
|
3194
|
+
<head>
|
3195
|
+
<style>
|
3196
|
+
body {
|
3197
|
+
background-image: url(/path/to/bgimage);
|
3198
|
+
}
|
3199
|
+
</style>
|
3200
|
+
</head>
|
3201
|
+
<body>
|
3202
|
+
<img src="/path/to/image"/>
|
3203
|
+
</body>
|
3204
|
+
</html>
|
3205
|
+
HTML
|
3206
|
+
end
|
3207
|
+
|
3208
|
+
get "/requests" do
|
3209
|
+
<<-HTML
|
3210
|
+
<html>
|
3211
|
+
<body>
|
3212
|
+
#{requests.map { |path| "<p>#{path}</p>" }.join}
|
3213
|
+
</body>
|
3214
|
+
</html>
|
3215
|
+
HTML
|
3216
|
+
end
|
3217
|
+
|
3218
|
+
get %r{/path/to/(.*)} do |path|
|
3219
|
+
requests << path
|
3220
|
+
end
|
3221
|
+
end
|
3222
|
+
end
|
3223
|
+
|
3224
|
+
it "should load images by default" do
|
3225
|
+
visit("/")
|
3226
|
+
requests.should match_array %w(image bgimage)
|
3227
|
+
end
|
3228
|
+
|
3229
|
+
it "should not load images when disabled" do
|
3230
|
+
configure(&:skip_image_loading)
|
3231
|
+
visit("/")
|
3232
|
+
requests.should eq []
|
3233
|
+
end
|
3234
|
+
|
3235
|
+
let(:requests) do
|
3236
|
+
visit "/requests"
|
3237
|
+
driver.find("//p").map(&:text)
|
3238
|
+
end
|
3239
|
+
end
|
3240
|
+
|
3241
|
+
describe "#set_proxy" do
|
3242
|
+
before do
|
3243
|
+
@host = "127.0.0.1"
|
3244
|
+
@user = "user"
|
3245
|
+
@pass = "secret"
|
3246
|
+
@url = "http://example.org/"
|
3247
|
+
|
3248
|
+
@server = TCPServer.new(@host, 0)
|
3249
|
+
@port = @server.addr[1]
|
3250
|
+
|
3251
|
+
@proxy_requests = []
|
3252
|
+
@proxy = Thread.new(@server, @proxy_requests) do |serv, proxy_requests|
|
3253
|
+
while conn = serv.accept do
|
3254
|
+
# read request
|
3255
|
+
request = []
|
3256
|
+
until (line = conn.readline.strip).empty?
|
3257
|
+
request << line
|
3258
|
+
end
|
3259
|
+
|
3260
|
+
# send response
|
3261
|
+
auth_header = request.find { |h| h =~ /Authorization:/i }
|
3262
|
+
if auth_header || request[0].split(/\s+/)[1] =~ /^\//
|
3263
|
+
html = "<html><body>D'oh!</body></html>"
|
3264
|
+
conn.write "HTTP/1.1 200 OK\r\n"
|
3265
|
+
conn.write "Content-Type:text/html\r\n"
|
3266
|
+
conn.write "Content-Length: %i\r\n" % html.size
|
3267
|
+
conn.write "\r\n"
|
3268
|
+
conn.write html
|
3269
|
+
conn.close
|
3270
|
+
proxy_requests << request if auth_header
|
3271
|
+
else
|
3272
|
+
conn.write "HTTP/1.1 407 Proxy Auth Required\r\n"
|
3273
|
+
conn.write "Proxy-Authenticate: Basic realm=\"Proxy\"\r\n"
|
3274
|
+
conn.write "\r\n"
|
3275
|
+
conn.close
|
3276
|
+
proxy_requests << request
|
3277
|
+
end
|
3278
|
+
end
|
3279
|
+
end
|
3280
|
+
|
3281
|
+
configure do |config|
|
3282
|
+
config.allow_url("example.org")
|
3283
|
+
config.use_proxy host: @host, port: @port, user: @user, pass: @pass
|
3284
|
+
end
|
3285
|
+
|
3286
|
+
driver.visit @url
|
3287
|
+
@proxy_requests.size.should eq 2
|
3288
|
+
@request = @proxy_requests[-1]
|
3289
|
+
end
|
3290
|
+
|
3291
|
+
after do
|
3292
|
+
@proxy.kill
|
3293
|
+
@server.close
|
3294
|
+
end
|
3295
|
+
|
3296
|
+
let(:driver) do
|
3297
|
+
driver_for_html("", browser: nil)
|
3298
|
+
end
|
3299
|
+
|
3300
|
+
it "uses the HTTP proxy correctly" do
|
3301
|
+
@request[0].should match(/^GET\s+http:\/\/example.org\/\s+HTTP/i)
|
3302
|
+
@request.find { |header|
|
3303
|
+
header =~ /^Host:\s+example.org$/i }.should_not be nil
|
3304
|
+
end
|
3305
|
+
|
3306
|
+
it "sends correct proxy authentication" do
|
3307
|
+
auth_header = @request.find { |header|
|
3308
|
+
header =~ /^Proxy-Authorization:\s+/i }
|
3309
|
+
auth_header.should_not be nil
|
3310
|
+
|
3311
|
+
user, pass = Base64.decode64(auth_header.split(/\s+/)[-1]).split(":")
|
3312
|
+
user.should eq @user
|
3313
|
+
pass.should eq @pass
|
3314
|
+
end
|
3315
|
+
|
3316
|
+
it "uses the proxy's response" do
|
3317
|
+
driver.html.should include "D'oh!"
|
3318
|
+
end
|
3319
|
+
|
3320
|
+
it "uses original URL" do
|
3321
|
+
driver.current_url.should eq @url
|
3322
|
+
end
|
3323
|
+
|
3324
|
+
it "uses URLs changed by javascript" do
|
3325
|
+
driver.execute_script %{window.history.pushState("", "", "/blah")}
|
3326
|
+
driver.current_url.should eq "http://example.org/blah"
|
3327
|
+
end
|
3328
|
+
|
3329
|
+
it "is possible to disable proxy again" do
|
3330
|
+
@proxy_requests.clear
|
3331
|
+
driver.browser.clear_proxy
|
3332
|
+
driver.visit "http://#{@host}:#{@port}/"
|
3333
|
+
@proxy_requests.size.should eq 0
|
3334
|
+
end
|
3335
|
+
end
|
3336
|
+
|
3047
3337
|
def driver_url(driver, path)
|
3048
3338
|
URI.parse(driver.current_url).merge(path).to_s
|
3049
3339
|
end
|