# -*- encoding: UTF-8 -*- require 'spec_helper' require 'capybara/webkit/driver' require 'base64' require 'self_signed_ssl_cert' describe Capybara::Webkit::Driver do include AppRunner def visit(path, driver=self.driver) driver.visit(url(path)) end def url(path) "#{AppRunner.app_host}#{path}" end context "configuration" do let(:options) { AppRunner.configuration.to_hash } it "configures server automatically" do expect { Capybara::Webkit::Driver.new(AppRunner.app, options) }. to_not raise_error end end context "iframe app" do let(:driver) do driver_for_app do get "/" do if params[:iframe] == "true" redirect '/iframe' else <<-HTML
HTML end end get '/iframe' do headers 'X-Redirected' => 'true' <<-HTML#{env['CONTENT_TYPE']}
" end get '/form' do <<-HTML HTML end post '/redirect' do redirect '/target' end get '/redirect-me' do if session[:redirected] redirect '/target' else session[:redirected] = true redirect '/redirect-me' end end end end it "should redirect without content type" do visit("/form") driver.find_xpath("//input").first.click driver.find_xpath("//p").first.visible_text.should eq "" end it "returns the current URL when changed by pushState after a redirect" do visit("/redirect-me") driver.current_url.should eq driver_url(driver, "/target") driver.execute_script("window.history.pushState({}, '', '/pushed-after-redirect')") driver.current_url.should eq driver_url(driver, "/pushed-after-redirect") end it "returns the current URL when changed by replaceState after a redirect" do visit("/redirect-me") driver.current_url.should eq driver_url(driver, "/target") driver.execute_script("window.history.replaceState({}, '', '/replaced-after-redirect')") driver.current_url.should eq driver_url(driver, "/replaced-after-redirect") end it "should make headers available through response_headers" do visit('/redirect-me') driver.response_headers['X-Redirected'].should eq "true" visit('/target') driver.response_headers['X-Redirected'].should eq "false" end it "should make the status code available through status_code" do visit('/redirect-me') driver.status_code.should eq 200 visit('/target') driver.status_code.should eq 200 end end context "css app" do let(:driver) do driver_for_app do get "/" do headers "Content-Type" => "text/css" "css" end end end before { visit("/") } it "renders unsupported content types gracefully" do driver.html.should =~ /css/ end it "sets the response headers with respect to the unsupported request" do driver.response_headers["Content-Type"].should eq "text/css" end it "does not wrap the content in HTML tags" do driver.html.should_not =~ // end end context "html app" do let(:driver) do driver_for_html(<<-HTML)hello
HTML end end end before { visit("/") } it "raises a webkit error and then continues" do driver.find_xpath("//input").first.click expect { driver.find_xpath("//p") }.to raise_error(Capybara::Webkit::InvalidResponseError) visit("/") driver.find_xpath("//p").first.visible_text.should eq "hello" end end context "popup app" do let(:driver) do driver_for_app do get "/" do sleep(0.5) return <<-HTMLsuccess
HTML end end end before { visit("/") } it "doesn't crash from alerts" do driver.find_xpath("//p").first.visible_text.should eq "success" end end context "custom header" do let(:driver) do driver_for_app do get "/" do <<-HTML#{env['HTTP_USER_AGENT']}
#{env['HTTP_X_CAPYBARA_WEBKIT_HEADER']}
#{env['HTTP_ACCEPT']}
/ HTML end end end before { visit("/") } before do driver.header('user-agent', 'capybara-webkit/custom-user-agent') driver.header('x-capybara-webkit-header', 'x-capybara-webkit-header') driver.header('accept', 'text/html') visit('/') end it "can set user_agent" do driver.find_xpath('id("user-agent")').first.visible_text.should eq 'capybara-webkit/custom-user-agent' driver.evaluate_script('navigator.userAgent').should eq 'capybara-webkit/custom-user-agent' end it "keep user_agent in next page" do driver.find_xpath("//a").first.click driver.find_xpath('id("user-agent")').first.visible_text.should eq 'capybara-webkit/custom-user-agent' driver.evaluate_script('navigator.userAgent').should eq 'capybara-webkit/custom-user-agent' end it "can set custom header" do driver.find_xpath('id("x-capybara-webkit-header")').first.visible_text.should eq 'x-capybara-webkit-header' end it "can set Accept header" do driver.find_xpath('id("accept")').first.visible_text.should eq 'text/html' end it "can reset all custom header" do driver.reset! visit('/') driver.find_xpath('id("user-agent")').first.visible_text.should_not eq 'capybara-webkit/custom-user-agent' driver.evaluate_script('navigator.userAgent').should_not eq 'capybara-webkit/custom-user-agent' driver.find_xpath('id("x-capybara-webkit-header")').first.visible_text.should be_empty driver.find_xpath('id("accept")').first.visible_text.should_not eq 'text/html' end end context "no response app" do let(:driver) do driver_for_html(<<-HTML) HTML end let!(:connection) { fork_connection } before { visit("/") } it "raises a webkit error for the requested url" do make_the_server_go_away expect { driver.find_xpath("//body") }. to raise_error(Capybara::Webkit::NoResponseError, %r{response}) make_the_server_come_back end def make_the_server_come_back connection.unstub(:gets) connection.unstub(:puts) connection.unstub(:print) end def make_the_server_go_away connection.stub(:gets).and_return(nil) connection.stub(:puts) connection.stub(:print) end end context "custom font app" do let(:driver) do driver_for_html(<<-HTML)Hello
HTML end before { visit("/") } let(:font_family) do driver.evaluate_script(<<-SCRIPT) var element = document.getElementById("text"); element.ownerDocument.defaultView.getComputedStyle(element, null).getPropertyValue("font-family"); SCRIPT end it "ignores custom fonts" do font_family.should eq "Arial" end it "ignores custom fonts before an element" do font_family.should eq "Arial" end it "ignores custom fonts after an element" do font_family.should eq "Arial" end end context "cookie-based app" do let(:driver) do driver_for_app do get "/" do headers 'Set-Cookie' => 'cookie=abc; domain=127.0.0.1; path=/' <<-HTML HTML end end end before { visit("/") } def echoed_cookie driver.find_xpath('id("cookie")').first.visible_text end it "remembers the cookie on second visit" do echoed_cookie.should eq "" visit "/" echoed_cookie.should eq "abc" end it "uses a custom cookie" do driver.set_cookie 'cookie=abc; domain=127.0.0.1; path=/' visit "/" echoed_cookie.should eq "abc" end it "clears cookies" do driver.clear_cookies visit "/" echoed_cookie.should eq "" end it "allows reading cookies" do driver.cookies["cookie"].should eq "abc" driver.cookies.find("cookie").path.should eq "/" driver.cookies.find("cookie").domain.should include "127.0.0.1" end end context "remove node app" do let(:driver) do driver_for_html(<<-HTML)Hello
Chapter | Page |
Intro | 1 |
Chapter 1 | 1 |
Chapter 2 | 1 |
Written by me
Let's try out XPath
in capybara-webkit
This paragraph is fascinating.
But not as much as this one.
Let's try if we can select this
HTML end before { visit("/") } it "builds up node paths correctly" do cases = { "//*[contains(@class, 'author')]" => "/html/head/meta[2]", "//*[contains(@class, 'td1')]" => "/html/body/div[@id='toc']/table/thead[@id='head']/tr/td[1]", "//*[contains(@class, 'td2')]" => "/html/body/div[@id='toc']/table/tbody/tr[2]/td[2]", "//h1" => "/html/body/h1", "//*[contains(@class, 'chapter2')]" => "/html/body/h2[2]", "//*[contains(@class, 'p1')]" => "/html/body/p[1]", "//*[contains(@class, 'p2')]" => "/html/body/div[@id='intro']/p[2]", "//*[contains(@class, 'p3')]" => "/html/body/p[3]", } cases.each do |xpath, path| nodes = driver.find_xpath(xpath) nodes.size.should eq 1 nodes[0].path.should eq path end end end context "css overflow app" do let(:driver) do driver_for_html(<<-HTML)finished
" end end end it "loads a page without error" do 10.times do visit("/redirect") driver.find_xpath("//p").first.visible_text.should eq "finished" end end end context "localStorage works" do let(:driver) do driver_for_html(<<-HTML) HTML end before { visit("/") } it "displays the message on subsequent page loads" do driver.find_xpath("//span[contains(.,'localStorage is enabled')]").should be_empty visit "/" driver.find_xpath("//span[contains(.,'localStorage is enabled')]").should_not be_empty end it "clears the message after a driver reset!" do visit "/" driver.find_xpath("//span[contains(.,'localStorage is enabled')]").should_not be_empty driver.reset! visit "/" driver.find_xpath("//span[contains(.,'localStorage is enabled')]").should be_empty end end context "caching app" do let(:driver) do etag_value = SecureRandom.hex driver_for_app do get '/' do etag etag_value <<-HTML Expected body HTML end end end it "returns a body for cached responses" do visit '/' first = driver.html visit '/' second = driver.html expect(second).to eq(first) end end context "offline application cache" do let(:driver) do @visited = [] visited = @visited driver_for_app do get '/8d853f09-4275-409d-954d-ebbf6e2ce732' do content_type 'text/cache-manifest' visited << 'manifest' <<-TEXT CACHE MANIFEST /4aaffa31-f42d-403e-a19e-6b248d608087 TEXT end # UUID urls so that this gets isolated from other tests get '/f8742c39-8bef-4196-b1c3-80f8a3d65f3e' do visited << 'complex' <<-HTML HTML end get '/4aaffa31-f42d-403e-a19e-6b248d608087' do visited << 'simple' <<-HTML HTML end end end before { visit("/f8742c39-8bef-4196-b1c3-80f8a3d65f3e") } it "has proper state available" do driver.find_xpath("//*[@id='state']").first.visible_text.should == '0' sleep 1 @visited.should eq(['complex', 'manifest', 'simple']), 'files were not downloaded in expected order' driver.find_xpath("//*[@id='finished']").first.visible_text.should == 'cached' end it "is cleared on driver reset!" do sleep 1 @visited.should eq(['complex', 'manifest', 'simple']), 'files were not downloaded in expected order' driver.reset! @visited.clear visit '/4aaffa31-f42d-403e-a19e-6b248d608087' sleep 1 @visited.should eq(['simple', 'manifest', 'simple']), 'simple action was used from cache instead of server' end end context "form app with server-side handler" do let(:driver) do driver_for_app do post "/" do "Congrats!
" end get "/" do <<-HTMLbananas
HTML end get "/" do sleep params['sleep'].to_i if params['sleep'] "finished
" end end end before { visit("/") } it "has the expected text in the new window" do visit("/new_window") driver.within_window(driver.window_handles.last) do driver.find_xpath("//p").first.visible_text.should eq "finished" end end it "can switch to another window" do visit("/new_window") driver.switch_to_window(driver.window_handles.last) driver.find_xpath("//p").first.visible_text.should eq "finished" end it "knows the current window handle" do visit("/new_window") driver.within_window(driver.window_handles.last) do driver.current_window_handle.should eq driver.window_handles.last end end it "can close the current window" do visit("/new_window") original_handle = driver.current_window_handle driver.switch_to_window(driver.window_handles.last) driver.close_window(driver.current_window_handle) driver.current_window_handle.should eq(original_handle) end it "can close an unfocused window" do visit("/new_window") driver.close_window(driver.window_handles.last) driver.window_handles.size.should eq(1) end it "can close the last window" do visit("/new_window") handles = driver.window_handles handles.each { |handle| driver.close_window(handle) } driver.html.should be_empty handles.should_not include(driver.current_window_handle) end it "waits for the new window to load" do visit("/new_window?sleep=1") driver.within_window(driver.window_handles.last) do driver.find_xpath("//p").first.visible_text.should eq "finished" end end it "waits for the new window to load when the window location has changed" do visit("/new_window?sleep=2") driver.execute_script("setTimeout(function() { window.location = 'about:blank' }, 1000)") driver.within_window(driver.window_handles.last) do driver.find_xpath("//p").first.visible_text.should eq "finished" end end it "switches back to the original window" do visit("/new_window") driver.within_window(driver.window_handles.last) { } driver.find_xpath("//p").first.visible_text.should eq "bananas" end it "supports finding a window by name" do visit("/new_window") driver.within_window('myWindow') do driver.find_xpath("//p").first.visible_text.should eq "finished" end end it "supports finding a window by title" do visit("/new_window?sleep=5") driver.within_window('My New Window') do driver.find_xpath("//p").first.visible_text.should eq "finished" end end it "supports finding a window by url" do visit("/new_window?test") driver.within_window(driver_url(driver, "/?test")) do driver.find_xpath("//p").first.visible_text.should eq "finished" end end it "raises an error if the window is not found" do expect { driver.within_window('myWindowDoesNotExist') }. to raise_error(Capybara::Webkit::NoSuchWindowError) end it "has a number of window handles equal to the number of open windows" do driver.window_handles.size.should eq 1 visit("/new_window") driver.window_handles.size.should eq 2 end it "removes windows when closed via JavaScript" do visit("/new_window") driver.execute_script('console.log(window.document.title); window.close()') sleep 2 driver.window_handles.size.should eq 1 end it "closes new windows on reset" do visit("/new_window") last_handle = driver.window_handles.last driver.reset! driver.window_handles.should_not include(last_handle) end it "leaves the old window focused when opening a new window" do visit("/new_window") current_window = driver.current_window_handle driver.open_new_window driver.current_window_handle.should eq current_window driver.window_handles.size.should eq 3 end it "opens blank windows" do visit("/new_window") driver.open_new_window driver.switch_to_window(driver.window_handles.last) driver.html.should be_empty end end it "preserves cookies across windows" do session_id = '12345' driver = driver_for_app do get '/new_window' do <<-HTML HTML end get '/set_cookie' do response.set_cookie 'session_id', session_id end end visit("/new_window", driver) driver.cookies['session_id'].should eq session_id end context "timers app" do let(:driver) do driver_for_app do get "/success" do '' end get "/not-found" do 404 end get "/outer" do <<-HTML HTML end get '/' do "" end end end before { visit("/") } it "raises error for any loadFinished failure" do expect do visit("/outer") sleep 1 driver.find_xpath("//body") end.to raise_error(Capybara::Webkit::InvalidResponseError) end end describe "basic auth" do let(:driver) do driver_for_app do get "/" do if env["HTTP_AUTHORIZATION"] == "Basic #{Base64.encode64("user:password").strip}" env["HTTP_AUTHORIZATION"] else headers "WWW-Authenticate" => 'Basic realm="Secure Area"' status 401 "401 Unauthorized." end end get "/reset" do headers "WWW-Authenticate" => 'Basic realm="Secure Area"' status 401 "401 Unauthorized." end end end before do visit('/reset') end it "can authenticate a request" do driver.authenticate('user', 'password') visit("/") driver.html.should include("Basic "+Base64.encode64("user:password").strip) end it "returns 401 for incorrectly authenticated request" do driver.authenticate('user1', 'password1') lambda { visit("/") }.should_not raise_error driver.status_code.should eq 401 end it "returns 401 for unauthenticated request" do lambda { visit("/") }.should_not raise_error driver.status_code.should eq 401 end it "can be reset with subsequent authenticate call", skip_on_qt4: true do driver.authenticate('user', 'password') visit("/") driver.html.should include("Basic "+Base64.encode64("user:password").strip) driver.authenticate('user1', 'password1') lambda { visit("/") }.should_not raise_error driver.status_code.should eq 401 end end describe "url blacklisting", skip_if_offline: true do let(:driver) do driver_for_app do get "/" do <<-HTML HTML end get "/frame" do <<-HTMLInner
HTML end get "/script" do <<-JS document.write('Script Run
') JS end end end before do configure do |config| config.block_url "http://example.org/path/to/file" config.block_url "http://example.*/foo/*" config.block_url "http://example.com" config.block_url "#{AppRunner.app_host}/script" end end it "should not fetch urls blocked by host" do visit("/") driver.within_frame('frame1') do driver.find_xpath("//body").first.visible_text.should be_empty end end it "should not fetch urls blocked by path" do visit('/') driver.within_frame('frame2') do driver.find_xpath("//body").first.visible_text.should be_empty end end it "should not fetch blocked scripts" do visit("/") driver.html.should_not include("Script Run") end it "should fetch unblocked urls" do visit('/') driver.within_frame('frame3') do driver.find_xpath("//p").first.visible_text.should eq "Inner" end end it "should not fetch urls blocked by wildcard match" do visit('/') driver.within_frame('frame4') do driver.find("//body").first.text.should be_empty end end it "returns a status code for blocked urls" do visit("/") driver.within_frame('frame1') do driver.status_code.should eq 200 end end end describe "url whitelisting", skip_if_offline: true do it_behaves_like "output writer" do let(:driver) do driver_for_html(<<-HTML) <<-HTML HTML end it "prints a warning for remote requests by default" do visit("/") expect(stderr).to include("http://example.com/path") expect(stderr).not_to include(driver.current_url) end it "can allow specific hosts" do configure do |config| config.allow_url("example.com") config.allow_url("www.example.com") end visit("/") expect(stderr).not_to include("http://example.com/path") expect(stderr).not_to include(driver.current_url) driver.within_frame("frame") do expect(driver.find("//body").first.text).not_to be_empty end end it "can allow all hosts" do configure(&:allow_unknown_urls) visit("/") expect(stderr).not_to include("http://example.com/path") expect(stderr).not_to include(driver.current_url) driver.within_frame("frame") do expect(driver.find("//body").first.text).not_to be_empty end end it "resets allowed hosts on reset" do driver.allow_unknown_urls driver.reset! visit("/") expect(stderr).to include("http://example.com/path") expect(stderr).not_to include(driver.current_url) end it "can block unknown hosts" do configure(&:block_unknown_urls) visit("/") expect(stderr).not_to include("http://example.com/path") expect(stderr).not_to include(driver.current_url) driver.within_frame("frame") do expect(driver.find("//body").first.text).to be_empty end end it "can allow urls with wildcards" do configure { |config| config.allow_url("*/path") } visit("/") expect(stderr).to include("www.example.com") expect(stderr).not_to include("example.com/path") expect(stderr).not_to include(driver.current_url) end it "whitelists localhost on reset" do driver.reset! visit("/") expect(stderr).not_to include(driver.current_url) end it "does not print a warning for data URIs" do visit("/") expect(stderr).not_to include('Request to unknown URL: data:text/plain') end end end describe "timeout for long requests" do let(:driver) do driver_for_app do html = <<-HTML HTML get "/" do sleep(2) html end post "/form" do sleep(4) html end end end it "should not raise a timeout error when zero" do configure { |config| config.timeout = 0 } lambda { visit("/") }.should_not raise_error end it "should raise a timeout error" do configure { |config| config.timeout = 1 } lambda { visit("/") }.should raise_error(Timeout::Error, "Request timed out after 1 second(s)") end it "should not raise an error when the timeout is high enough" do configure { |config| config.timeout = 10 } lambda { visit("/") }.should_not raise_error end it "should set the timeout for each request" do configure { |config| config.timeout = 10 } lambda { visit("/") }.should_not raise_error driver.timeout = 1 lambda { visit("/") }.should raise_error(Timeout::Error) end it "should set the timeout for each request" do configure { |config| config.timeout = 1 } lambda { visit("/") }.should raise_error(Timeout::Error) driver.reset! driver.timeout = 10 lambda { visit("/") }.should_not raise_error end it "should raise a timeout on a slow form" do configure { |config| config.timeout = 3 } visit("/") driver.status_code.should eq 200 driver.timeout = 1 driver.find_xpath("//input").first.click lambda { driver.status_code }.should raise_error(Timeout::Error) end it "get timeout" do configure { |config| config.timeout = 10 } driver.browser.timeout.should eq 10 end end describe "logger app" do it_behaves_like "output writer" do let(:driver) do driver_for_html("Hello") end it "logs nothing in normal mode" do configure { |config| config.debug = false } visit("/") stderr.should_not include logging_message end it "logs its commands in debug mode" do configure { |config| config.debug = true } visit("/") stderr.should include logging_message end let(:logging_message) { 'Wrote response true' } end end context "synchronous ajax app" do let(:driver) do driver_for_app do get '/' do <<-HTML HTML end post '/' do request.body.read end end end it 'should not hang the server' do visit('/') driver.find_xpath('//input').first.click driver.console_messages.first[:message].should eq "hello" end end context 'path' do let(:driver) do driver_for_html(<<-HTML)Remove me
remove HTML end it 'raises NodeNotAttachedError' do visit '/' remove_me = driver.find_css('#remove-me').first expect(remove_me).not_to be_nil driver.find_css('#remove-button').first.click expect { remove_me.text }.to raise_error(Capybara::Webkit::NodeNotAttachedError) end it 'raises NodeNotAttachedError if the argument node is unattached' do visit '/' remove_me = driver.find_css('#remove-me').first expect(remove_me).not_to be_nil remove_button = driver.find_css('#remove-button').first expect(remove_button).not_to be_nil remove_button.click expect { remove_button == remove_me }.to raise_error(Capybara::Webkit::NodeNotAttachedError) expect { remove_me == remove_button }.to raise_error(Capybara::Webkit::NodeNotAttachedError) end end context "version" do let(:driver) do driver_for_html(<<-HTML) HTML end before { visit("/") } it "includes Capybara, capybara-webkit, Qt, and WebKit versions" do result = driver.version result.should include("Capybara: #{Capybara::VERSION}") result.should include("capybara-webkit: #{Capybara::Driver::Webkit::VERSION}") result.should =~ /Qt: \d+\.\d+\.\d+/ result.should =~ /WebKit: \d+\.\d+/ result.should =~ /QtWebKit: \d+\.\d+/ end end context "history" do let(:driver) do driver_for_app do get "/:param" do |param| <<-HTML#{param}
Navigate HTML end end end it "can navigate in history" do visit("/first") driver.find_xpath("//p").first.text.should eq('first') driver.find_xpath("//a").first.click driver.find_xpath("//p").first.text.should eq('navigated') driver.go_back driver.find_xpath("//p").first.text.should eq('first') driver.go_forward driver.find_xpath("//p").first.text.should eq('navigated') end end context "response header contains colon" do let(:driver) do driver_for_app do get "/" do headers "Content-Disposition" => 'filename="File: name.txt"' end end end it "sets the response header" do visit("/") expect( driver.response_headers["Content-Disposition"] ).to eq 'filename="File: name.txt"' end end context "with unfinished responses" do it_behaves_like "output writer" do let(:driver) do count = 0 driver_for_app do get "/" do count += 1 <<-HTML HTML end get "/async" do sleep 2 "" end end end it "aborts unfinished responses" do driver.enable_logging visit "/" sleep 0.5 visit "/" sleep 0.5 driver.reset! stderr.should abort_request_to("/async?2") stderr.should_not abort_request_to("/async?1") end def abort_request_to(path) include(%{Aborting request to "#{url(path)}"}) end end end context "when the driver process crashes" do let(:driver) do driver_for_app do get "/" do "Relaunched" end end end it "reports and relaunches on reset" do connection = fork_connection Process.kill "KILL", connection.pid expect { driver.reset! }.to raise_error(Capybara::Webkit::CrashError) visit "/" expect(driver.html).to include("Relaunched") end end context "handling of SSL validation errors" do before do # set up minimal HTTPS server @host = "127.0.0.1" @server = TCPServer.new(@host, 0) @port = @server.addr[1] # set up SSL layer ssl_serv = OpenSSL::SSL::SSLServer.new(@server, $openssl_self_signed_ctx) @server_thread = Thread.new(ssl_serv) do |serv| while conn = serv.accept do # read request request = [] until (line = conn.readline.strip).empty? request << line end # write response html = "D'oh!" conn.write "HTTP/1.1 200 OK\r\n" conn.write "Content-Type:text/html\r\n" conn.write "Content-Length: %i\r\n" % html.size conn.write "\r\n" conn.write html conn.close end end fork_connection end after do @server_thread.kill @server.close end context "with default settings" do it "doesn't accept a self-signed certificate" do lambda { driver.visit "https://#{@host}:#{@port}/" }.should raise_error end it "doesn't accept a self-signed certificate in a new window" do driver.execute_script("window.open('about:blank')") driver.switch_to_window(driver.window_handles.last) lambda { driver.visit "https://#{@host}:#{@port}/" }.should raise_error end end context "ignoring SSL errors" do it "accepts a self-signed certificate if configured to do so" do configure(&:ignore_ssl_errors) driver.visit "https://#{@host}:#{@port}/" end it "accepts a self-signed certificate in a new window when configured" do configure(&:ignore_ssl_errors) driver.execute_script("window.open('about:blank')") driver.switch_to_window(driver.window_handles.last) driver.visit "https://#{@host}:#{@port}/" end end let(:driver) { driver_for_html("") } end context "skip image loading" do let(:driver) do driver_for_app do requests = [] get "/" do <<-HTML#{path}
" }.join} HTML end get %r{/path/to/(.*)} do |path| requests << path end end end it "should load images by default" do visit("/") requests.should match_array %w(image bgimage) end it "should not load images when disabled" do configure(&:skip_image_loading) visit("/") requests.should eq [] end let(:requests) do visit "/requests" driver.find("//p").map(&:text) end end describe "#set_proxy" do before do @host = "127.0.0.1" @user = "user" @pass = "secret" @url = "http://example.org/" @server = TCPServer.new(@host, 0) @port = @server.addr[1] @proxy_requests = [] @proxy = Thread.new(@server, @proxy_requests) do |serv, proxy_requests| while conn = serv.accept do # read request request = [] until (line = conn.readline.strip).empty? request << line end # send response auth_header = request.find { |h| h =~ /Authorization:/i } if auth_header || request[0].split(/\s+/)[1] =~ /^\// html = "D'oh!" conn.write "HTTP/1.1 200 OK\r\n" conn.write "Content-Type:text/html\r\n" conn.write "Content-Length: %i\r\n" % html.size conn.write "\r\n" conn.write html conn.close proxy_requests << request if auth_header else conn.write "HTTP/1.1 407 Proxy Auth Required\r\n" conn.write "Proxy-Authenticate: Basic realm=\"Proxy\"\r\n" conn.write "\r\n" conn.close proxy_requests << request end end end configure do |config| config.allow_url("example.org") config.use_proxy host: @host, port: @port, user: @user, pass: @pass end fork_connection driver.visit @url @proxy_requests.size.should eq 2 @request = @proxy_requests[-1] end after do @proxy.kill @server.close end let(:driver) do driver_for_html("") end it "uses the HTTP proxy correctly" do @request[0].should match(/^GET\s+http:\/\/example.org\/\s+HTTP/i) @request.find { |header| header =~ /^Host:\s+example.org$/i }.should_not be nil end it "sends correct proxy authentication" do auth_header = @request.find { |header| header =~ /^Proxy-Authorization:\s+/i } auth_header.should_not be nil user, pass = Base64.decode64(auth_header.split(/\s+/)[-1]).split(":") user.should eq @user pass.should eq @pass end it "uses the proxy's response" do driver.html.should include "D'oh!" end it "uses original URL" do driver.current_url.should eq @url end it "uses URLs changed by javascript" do driver.execute_script %{window.history.pushState("", "", "/blah")} driver.current_url.should eq "http://example.org/blah" end it "is possible to disable proxy again" do @proxy_requests.clear driver.browser.clear_proxy driver.visit "http://#{@host}:#{@port}/" @proxy_requests.size.should eq 0 end end def driver_url(driver, path) URI.parse(driver.current_url).merge(path).to_s end end