require 'spec_helper' require 'capybara/driver/webkit' describe Capybara::Driver::Webkit do subject { Capybara::Driver::Webkit.new(@app, :browser => $webkit_browser) } before { subject.visit("/hello/world?success=true") } after { subject.reset! } context "iframe app" do before(:all) do @app = lambda do |env| params = ::Rack::Utils.parse_query(env['QUERY_STRING']) if params["iframe"] == "true" # We are in an iframe request. p_id = "farewell" msg = "goodbye" iframe = nil else # We are not in an iframe request and need to make an iframe! p_id = "greeting" msg = "hello" iframe = "" end body = <<-HTML
#{iframe} HTML [200, { 'Content-Type' => 'text/html', 'Content-Length' => body.length.to_s }, [body]] end end it "finds frames by index" do subject.within_frame(0) do subject.find("//*[contains(., 'goodbye')]").should_not be_empty end end it "finds frames by id" do subject.within_frame("f") do subject.find("//*[contains(., 'goodbye')]").should_not be_empty end end it "raises error for missing frame by index" do expect { subject.within_frame(1) { } }. to raise_error(Capybara::Driver::Webkit::WebkitInvalidResponseError) end it "raise_error for missing frame by id" do expect { subject.within_frame("foo") { } }. to raise_error(Capybara::Driver::Webkit::WebkitInvalidResponseError) end it "returns an attribute's value" do subject.within_frame("f") do subject.find("//p").first["id"].should == "farewell" end end it "returns a node's text" do subject.within_frame("f") do subject.find("//p").first.text.should == "goodbye" end end it "returns the current URL" do subject.within_frame("f") do port = subject.instance_variable_get("@rack_server").port subject.current_url.should == "http://127.0.0.1:#{port}/?iframe=true" end end it "returns the source code for the page" do subject.within_frame("f") do subject.source.should =~ %r{.*farewell.*}m end end it "evaluates Javascript" do subject.within_frame("f") do result = subject.evaluate_script(%#{env['CONTENT_TYPE']}
" [200, {"Content-Type" => "text/html", "Content-Length" => content_type.length.to_s}, [content_type]] elsif env['PATH_INFO'] == '/form' body = <<-HTML HTML [200, {"Content-Type" => "text/html", "Content-Length" => body.length.to_s}, [body]] else [301, {"Location" => "/target"}, [""]] end end end it "should redirect without content type" do subject.visit("/form") subject.find("//input").first.click subject.find("//p").first.text.should == "" end it "returns the current URL when changed by pushState after a redirect" do subject.visit("/redirect-me") port = subject.instance_variable_get("@rack_server").port subject.execute_script("window.history.pushState({}, '', '/pushed-after-redirect')") subject.current_url.should == "http://127.0.0.1:#{port}/pushed-after-redirect" end it "returns the current URL when changed by replaceState after a redirect" do subject.visit("/redirect-me") port = subject.instance_variable_get("@rack_server").port subject.execute_script("window.history.replaceState({}, '', '/replaced-after-redirect')") subject.current_url.should == "http://127.0.0.1:#{port}/replaced-after-redirect" end end context "css app" do before(:all) do body = "css" @app = lambda do |env| [200, {"Content-Type" => "text/css", "Content-Length" => body.length.to_s}, [body]] end subject.visit("/") end it "renders unsupported content types gracefully" do subject.body.should =~ /css/ end it "sets the response headers with respect to the unsupported request" do subject.response_headers["Content-Type"].should == "text/css" end end context "hello app" do before(:all) do @app = lambda do |env| body = <<-HTMLhello
HTML [200, { 'Content-Type' => 'text/html', 'Content-Length' => body.length.to_s }, [body]] end end end it "raises a webkit error and then continues" do subject.find("//input").first.click expect { subject.find("//p") }.to raise_error(Capybara::Driver::Webkit::WebkitInvalidResponseError) subject.visit("/") subject.find("//p").first.text.should == "hello" end end context "popup app" do before(:all) do @app = lambda do |env| body = <<-HTMLsuccess
HTML sleep(0.5) [200, { 'Content-Type' => 'text/html', 'Content-Length' => body.length.to_s }, [body]] end end it "doesn't crash from alerts" do subject.find("//p").first.text.should == "success" end end context "custom header" do before(:all) do @app = lambda do |env| body = <<-HTML#{env['HTTP_USER_AGENT']}
#{env['HTTP_X_CAPYBARA_WEBKIT_HEADER']}
#{env['HTTP_ACCEPT']}
/ HTML [200, { 'Content-Type' => 'text/html', 'Content-Length' => body.length.to_s }, [body]] end end before do subject.header('user-agent', 'capybara-webkit/custom-user-agent') subject.header('x-capybara-webkit-header', 'x-capybara-webkit-header') subject.header('accept', 'text/html') subject.visit('/') end it "can set user_agent" do subject.find('id("user-agent")').first.text.should == 'capybara-webkit/custom-user-agent' subject.evaluate_script('navigator.userAgent').should == 'capybara-webkit/custom-user-agent' end it "keep user_agent in next page" do subject.find("//a").first.click subject.find('id("user-agent")').first.text.should == 'capybara-webkit/custom-user-agent' subject.evaluate_script('navigator.userAgent').should == 'capybara-webkit/custom-user-agent' end it "can set custom header" do subject.find('id("x-capybara-webkit-header")').first.text.should == 'x-capybara-webkit-header' end it "can set Accept header" do subject.find('id("accept")').first.text.should == 'text/html' end it "can reset all custom header" do subject.reset! subject.visit('/') subject.find('id("user-agent")').first.text.should_not == 'capybara-webkit/custom-user-agent' subject.evaluate_script('navigator.userAgent').should_not == 'capybara-webkit/custom-user-agent' subject.find('id("x-capybara-webkit-header")').first.text.should be_empty subject.find('id("accept")').first.text.should_not == 'text/html' end end context "no response app" do before(:all) do @app = lambda do |env| body = <<-HTML HTML [200, { 'Content-Type' => 'text/html', 'Content-Length' => body.length.to_s }, [body]] end end it "raises a webkit error for the requested url" do make_the_server_go_away expect { subject.find("//body") }. to raise_error(Capybara::Driver::Webkit::WebkitNoResponseError, %r{response}) make_the_server_come_back end def make_the_server_come_back subject.browser.instance_variable_get(:@connection).unstub!(:gets) subject.browser.instance_variable_get(:@connection).unstub!(:puts) subject.browser.instance_variable_get(:@connection).unstub!(:print) end def make_the_server_go_away subject.browser.instance_variable_get(:@connection).stub!(:gets).and_return(nil) subject.browser.instance_variable_get(:@connection).stub!(:puts) subject.browser.instance_variable_get(:@connection).stub!(:print) end end context "custom font app" do before(:all) do @app = lambda do |env| body = <<-HTMLHello
HTML [200, { 'Content-Type' => 'text/html', 'Content-Length' => body.length.to_s }, [body]] end end it "ignores custom fonts" do font_family = subject.evaluate_script(<<-SCRIPT) var element = document.getElementById("text"); element.ownerDocument.defaultView.getComputedStyle(element, null).getPropertyValue("font-family"); SCRIPT font_family.should == "Arial" end end context "cookie-based app" do before(:all) do @cookie = 'cookie=abc; domain=127.0.0.1; path=/' @app = lambda do |env| request = ::Rack::Request.new(env) body = <<-HTML HTML [200, { 'Content-Type' => 'text/html; charset=UTF-8', 'Content-Length' => body.length.to_s, 'Set-Cookie' => @cookie, }, [body]] end end def echoed_cookie subject.find('id("cookie")').first.text end it "remembers the cookie on second visit" do echoed_cookie.should == "" subject.visit "/" echoed_cookie.should == "abc" end it "uses a custom cookie" do subject.browser.set_cookie @cookie subject.visit "/" echoed_cookie.should == "abc" end it "clears cookies" do subject.browser.clear_cookies subject.visit "/" echoed_cookie.should == "" end it "allows enumeration of cookies" do cookies = subject.browser.get_cookies cookies.size.should == 1 cookie = Hash[cookies[0].split(/\s*;\s*/).map { |x| x.split("=", 2) }] cookie["cookie"].should == "abc" cookie["domain"].should include "127.0.0.1" cookie["path"].should == "/" end it "allows reading access to cookies using a nice syntax" do subject.cookies["cookie"].should == "abc" end end context "with socket debugger" do let(:socket_debugger_class){ Capybara::Driver::Webkit::SocketDebugger } let(:browser_with_debugger){ connection = Capybara::Driver::Webkit::Connection.new(:socket_class => socket_debugger_class) Capybara::Driver::Webkit::Browser.new(connection) } let(:driver_with_debugger){ Capybara::Driver::Webkit.new(@app, :browser => browser_with_debugger) } before(:all) do @app = lambda do |env| body = <<-HTMLHello
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 [200, { 'Content-Type' => 'text/html', 'Content-Length' => body.length.to_s }, [body]] end end 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 = subject.find(xpath) nodes.size.should == 1 nodes[0].path.should == path end end end context "css overflow app" do before(:all) do @app = lambda do |env| body = <<-HTMLfinished
" end [200, { 'Content-Type' => 'text/html', 'Content-Length' => body.length.to_s }, [body]] end end it "loads a page without error" do 10.times do subject.visit("/redirect") subject.find("//p").first.text.should == "finished" end end end context "localStorage works" do before(:all) do @app = lambda do |env| body = <<-HTML HTML [200, { 'Content-Type' => 'text/html', 'Content-Length' => body.length.to_s }, [body]] end end it "displays the message on subsequent page loads" do subject.find("//span[contains(.,'localStorage is enabled')]").should be_empty subject.visit "/" subject.find("//span[contains(.,'localStorage is enabled')]").should_not be_empty end end context "app with a lot of HTML tags" do before(:all) do @app = lambda do |env| body = <<-HTMLChapter | 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 [200, { 'Content-Type' => 'text/html', 'Content-Length' => body.length.to_s }, [body]] end end 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 = subject.find(xpath) nodes.size.should == 1 nodes[0].path.should == path end end end context "form app with server-side handler" do before(:all) do @app = lambda do |env| if env["REQUEST_METHOD"] == "POST" body = "Congrats!
" else body = <<-HTMLbananas
HTML else params = request.params sleep params['sleep'].to_i if params['sleep'] body = "finished
" end [200, { 'Content-Type' => 'text/html', 'Content-Length' => body.length.to_s }, [body]] end end it "has the expected text in the new window" do subject.visit("/new_window") subject.within_window(subject.window_handles.last) do subject.find("//p").first.text.should == "finished" end end it "waits for the new window to load" do subject.visit("/new_window?sleep=1") subject.within_window(subject.window_handles.last) do lambda { Timeout::timeout(1) { subject.find("//p") } }.should_not raise_error(Timeout::Error) end end it "switches back to the original window" do subject.visit("/new_window") subject.within_window(subject.window_handles.last) { } subject.find("//p").first.text.should == "bananas" end end end