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.
@@ -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