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.
@@ -23,6 +23,9 @@ module Capybara::Webkit
23
23
  class ModalNotFound < StandardError
24
24
  end
25
25
 
26
+ class CrashError < StandardError
27
+ end
28
+
26
29
  class JsonError
27
30
  def initialize(response)
28
31
  error = JSON.parse response
@@ -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?
@@ -1,7 +1,7 @@
1
1
  module Capybara
2
2
  module Driver
3
3
  class Webkit
4
- VERSION = '1.5.2'.freeze
4
+ VERSION = "1.6.0".freeze
5
5
  end
6
6
  end
7
7
  end
@@ -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
@@ -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
- sleep 1
23
- expect { Process.getpgid(webkit_pid) }.to raise_error Errno::ESRCH
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
@@ -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
- driver.browser.instance_variable_get(:@connection).unstub(:gets)
1831
- driver.browser.instance_variable_get(:@connection).unstub(:puts)
1832
- driver.browser.instance_variable_get(:@connection).unstub(:print)
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
- driver.browser.instance_variable_get(:@connection).stub(:gets).and_return(nil)
1837
- driver.browser.instance_variable_get(:@connection).stub(:puts)
1838
- driver.browser.instance_variable_get(:@connection).stub(:print)
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.browser.set_cookie 'cookie=abc; domain=127.0.0.1; path=/'
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.browser.clear_cookies
1919
+ driver.clear_cookies
1916
1920
  visit "/"
1917
1921
  echoed_cookie.should eq ""
1918
1922
  end
1919
1923
 
1920
- it "allows enumeration of cookies" do
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 "does not cache responses" do
2129
+ it "returns a body for cached responses" do
2128
2130
  visit '/'
2131
+ first = driver.html
2129
2132
  visit '/'
2130
- expect(driver.status_code).to eq(200)
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.browser.authenticate('user', 'password')
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.browser.authenticate('user1', 'password1')
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
- driver.browser.timeout = 2
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
- driver.block_url "http://example.org/path/to/file"
2651
- driver.block_url "http://example.*/foo/*"
2652
- driver.block_url "http://example.com"
2653
- driver.block_url "#{AppRunner.app_host}/script"
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
- driver.allow_url("example.com")
2721
- driver.allow_url("www.example.com")
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
- driver.block_unknown_urls
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
- driver.allow_url("*/path")
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
- driver.browser.timeout = 0
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
- driver.browser.timeout = 1
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
- driver.browser.timeout = 10
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
- driver.browser.timeout = 10
2844
+ configure { |config| config.timeout = 10 }
2809
2845
  lambda { visit("/") }.should_not raise_error
2810
- driver.browser.timeout = 1
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
- driver.browser.timeout = 1
2851
+ configure { |config| config.timeout = 1 }
2816
2852
  lambda { visit("/") }.should raise_error(Timeout::Error)
2817
2853
  driver.reset!
2818
- driver.browser.timeout = 10
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
- driver.browser.timeout = 3
2859
+ configure { |config| config.timeout = 3 }
2824
2860
  visit("/")
2825
2861
  driver.status_code.should eq 200
2826
- driver.browser.timeout = 1
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
- driver.browser.timeout = 10
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 before turning on the logger" do
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 after turning on the logger" do
2851
- driver.enable_logging
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