capybara-2.1.0/0000755000175000017500000000000012140721202012307 5ustar lunarlunarcapybara-2.1.0/spec/0000755000175000017500000000000012140721202013241 5ustar lunarlunarcapybara-2.1.0/spec/fixtures/0000755000175000017500000000000012140721202015112 5ustar lunarlunarcapybara-2.1.0/spec/fixtures/selenium_driver_rspec_failure.rb0000644000175000017500000000032112140721202023532 0ustar lunarlunarrequire 'spec_helper' describe Capybara::Selenium::Driver do it "should exit with a non-zero exit status" do browser = Capybara::Selenium::Driver.new(TestApp).browser true.should == false end end capybara-2.1.0/spec/fixtures/selenium_driver_rspec_success.rb0000644000175000017500000000031412140721202023555 0ustar lunarlunarrequire 'spec_helper' describe Capybara::Selenium::Driver do it "should exit with a zero exit status" do browser = Capybara::Selenium::Driver.new(TestApp).browser true.should == true end end capybara-2.1.0/spec/spec_helper.rb0000644000175000017500000000017412140721202016061 0ustar lunarlunarrequire "capybara/spec/spec_helper" require "pry" RSpec.configure do |config| Capybara::SpecHelper.configure(config) end capybara-2.1.0/spec/rack_test_spec.rb0000644000175000017500000001135312140721202016562 0ustar lunarlunarrequire 'spec_helper' module TestSessions RackTest = Capybara::Session.new(:rack_test, TestApp) end Capybara::SpecHelper.run_specs TestSessions::RackTest, "RackTest", :skip => [ :js, :screenshot, :frames, :windows, :server, :hover ] describe Capybara::Session do context 'with rack test driver' do before do @session = TestSessions::RackTest end describe '#driver' do it "should be a rack test driver" do @session.driver.should be_an_instance_of(Capybara::RackTest::Driver) end end describe '#mode' do it "should remember the mode" do @session.mode.should == :rack_test end end describe '#click_link' do it "should use data-method if option is true" do @session.driver.options[:respect_data_method] = true @session.visit "/with_html" @session.click_link "A link with data-method" @session.html.should include('The requested object was deleted') end it "should not use data-method if option is false" do @session.driver.options[:respect_data_method] = false @session.visit "/with_html" @session.click_link "A link with data-method" @session.html.should include('Not deleted') end it "should use data-method if available even if it's capitalized" do @session.driver.options[:respect_data_method] = true @session.visit "/with_html" @session.click_link "A link with capitalized data-method" @session.html.should include('The requested object was deleted') end after do @session.driver.options[:respect_data_method] = false end end describe "#attach_file" do context "with multipart form" do it "should submit an empty form-data section if no file is submitted" do @session.visit("/form") @session.click_button("Upload Empty") @session.html.should include('Successfully ignored empty file field.') end end end end end describe Capybara::RackTest::Driver do before do @driver = TestSessions::RackTest.driver end describe ':headers option' do it 'should always set headers' do @driver = Capybara::RackTest::Driver.new(TestApp, :headers => {'HTTP_FOO' => 'foobar'}) @driver.visit('/get_header') @driver.html.should include('foobar') end it 'should keep headers on link clicks' do @driver = Capybara::RackTest::Driver.new(TestApp, :headers => {'HTTP_FOO' => 'foobar'}) @driver.visit('/header_links') @driver.find_xpath('.//a').first.click @driver.html.should include('foobar') end it 'should keep headers on form submit' do @driver = Capybara::RackTest::Driver.new(TestApp, :headers => {'HTTP_FOO' => 'foobar'}) @driver.visit('/header_links') @driver.find_xpath('.//input').first.click @driver.html.should include('foobar') end it 'should keep headers on redirects' do @driver = Capybara::RackTest::Driver.new(TestApp, :headers => {'HTTP_FOO' => 'foobar'}) @driver.visit('/get_header_via_redirect') @driver.html.should include('foobar') end end describe ':follow_redirects option' do it "defaults to following redirects" do @driver = Capybara::RackTest::Driver.new(TestApp) @driver.visit('/redirect') @driver.response.header['Location'].should be_nil @driver.browser.current_url.should match %r{/landed$} end it "is possible to not follow redirects" do @driver = Capybara::RackTest::Driver.new(TestApp, :follow_redirects => false) @driver.visit('/redirect') @driver.response.header['Location'].should match %r{/redirect_again$} @driver.browser.current_url.should match %r{/redirect$} end end describe ':redirect_limit option' do context "with default redirect limit" do before do @driver = Capybara::RackTest::Driver.new(TestApp) end it "should follow 5 redirects" do @driver.visit("/redirect/5/times") @driver.html.should include('redirection complete') end it "should not follow more than 6 redirects" do expect do @driver.visit("/redirect/6/times") end.to raise_error(Capybara::InfiniteRedirectError) end end context "with 21 redirect limit" do before do @driver = Capybara::RackTest::Driver.new(TestApp, :redirect_limit => 21) end it "should follow 21 redirects" do @driver.visit("/redirect/21/times") @driver.html.should include('redirection complete') end it "should not follow more than 21 redirects" do expect do @driver.visit("/redirect/22/times") end.to raise_error(Capybara::InfiniteRedirectError) end end end end capybara-2.1.0/spec/rspec_spec.rb0000644000175000017500000000253112140721202015715 0ustar lunarlunarrequire 'spec_helper' describe 'capybara/rspec', :type => :feature do it "should include Capybara in rspec" do visit('/foo') page.body.should include('Another World') end context "resetting session" do it "sets a cookie in one example..." do visit('/set_cookie') page.body.should include('Cookie set to test_cookie') end it "...then it is not availbable in the next" do visit('/get_cookie') page.body.should_not include('test_cookie') end end context "setting the current driver" do it "sets the current driver in one example..." do Capybara.current_driver = :selenium end it "...then it has returned to the default in the next example" do Capybara.current_driver.should == :rack_test end end it "switches to the javascript driver when giving it as metadata", :js => true do Capybara.current_driver.should == Capybara.javascript_driver end it "switches to the given driver when giving it as metadata", :driver => :culerity do Capybara.current_driver.should == :culerity end end describe 'capybara/rspec', :type => :other do it "should not include Capybara" do expect { visit('/') }.to raise_error(NoMethodError) end end feature "Feature DSL" do scenario "is pulled in" do visit('/foo') page.body.should include('Another World') end end capybara-2.1.0/spec/basic_node_spec.rb0000644000175000017500000001050512140721202016667 0ustar lunarlunarrequire 'spec_helper' describe Capybara do describe '.string' do let :string do Capybara.string <<-STRING simple_node

Totally awesome

Yes it is

STRING end it "allows using matchers" do string.should have_css('#page') string.should_not have_css('#does-not-exist') end it "allows using custom matchers" do Capybara.add_selector :lifeform do xpath { |name| "//option[contains(.,'#{name}')]" } end string.should have_selector(:id, "page") string.should_not have_selector(:id, 'does-not-exist') string.should have_selector(:lifeform, "Monkey") string.should_not have_selector(:lifeform, "Gorilla") end it 'allows custom matcher using css' do Capybara.add_selector :section do css { |css_class| "section .#{css_class}" } end string.should have_selector(:section, 'subsection') string.should_not have_selector(:section, 'section_8') end it "allows using matchers with text option" do string.should have_css('h1', :text => 'Totally awesome') string.should_not have_css('h1', :text => 'Not so awesome') end it "allows finding only visible nodes" do string.all(:css, '#secret', :visible => true).should be_empty string.all(:css, '#secret', :visible => false).should have(1).element end it "allows finding elements and extracting text from them" do string.find('//h1').text.should == 'Totally awesome' end it "allows finding elements and extracting attributes from them" do string.find('//h1')[:data].should == 'fantastic' end it "allows finding elements and extracting the tag name from them" do string.find('//h1').tag_name.should == 'h1' end it "allows finding elements and extracting the path" do string.find('//h1').path.should == '/html/body/div/div[1]/h1' end it "allows finding elements and extracting the path" do string.find('//div/input').value.should == 'bar' string.find('//select').value.should == 'Capybara' end it "allows finding elements and checking if they are visible" do string.find('//h1').should be_visible string.find(:css, "#secret", :visible => false).should_not be_visible end it "allows finding elements and checking if they are disabled" do string.find('//form/input[@name="bleh"]').should be_disabled string.find('//form/input[@name="meh"]').should_not be_disabled end describe "#title" do it "returns the page title" do string.title.should == "simple_node" end end describe "#has_title?" do it "returns whether the page has the given title" do string.has_title?('simple_node').should be_true string.has_title?('monkey').should be_false end it "allows regexp matches" do string.has_title?(/s[a-z]+_node/).should be_true string.has_title?(/monkey/).should be_false end end describe '#has_no_title?' do it "returns whether the page does not have the given title" do string.has_no_title?('simple_node').should be_false string.has_no_title?('monkey').should be_true end it "allows regexp matches" do string.has_no_title?(/s[a-z]+_node/).should be_false string.has_no_title?(/monkey/).should be_true end end end end capybara-2.1.0/spec/dsl_spec.rb0000644000175000017500000001613712140721202015372 0ustar lunarlunarrequire 'spec_helper' require 'capybara/dsl' class TestClass include Capybara::DSL end Capybara::SpecHelper.run_specs TestClass.new, "DSL", :skip => [ :js, :screenshot, :frames, :windows, :server, :hover ] describe Capybara::DSL do after do Capybara.session_name = nil Capybara.default_driver = nil Capybara.javascript_driver = nil Capybara.use_default_driver Capybara.app = TestApp end describe '#default_driver' do it "should default to rack_test" do Capybara.default_driver.should == :rack_test end it "should be changeable" do Capybara.default_driver = :culerity Capybara.default_driver.should == :culerity end end describe '#current_driver' do it "should default to the default driver" do Capybara.current_driver.should == :rack_test Capybara.default_driver = :culerity Capybara.current_driver.should == :culerity end it "should be changeable" do Capybara.current_driver = :culerity Capybara.current_driver.should == :culerity end end describe '#javascript_driver' do it "should default to selenium" do Capybara.javascript_driver.should == :selenium end it "should be changeable" do Capybara.javascript_driver = :culerity Capybara.javascript_driver.should == :culerity end end describe '#use_default_driver' do it "should restore the default driver" do Capybara.current_driver = :culerity Capybara.use_default_driver Capybara.current_driver.should == :rack_test end end describe '#using_driver' do before do Capybara.current_driver.should_not == :selenium end it 'should set the driver using Capybara.current_driver=' do driver = nil Capybara.using_driver(:selenium) { driver = Capybara.current_driver } driver.should == :selenium end it 'should return the driver to default if it has not been changed' do Capybara.using_driver(:selenium) do Capybara.current_driver.should == :selenium end Capybara.current_driver.should == Capybara.default_driver end it 'should reset the driver even if an exception occurs' do driver_before_block = Capybara.current_driver begin Capybara.using_driver(:selenium) { raise "ohnoes!" } rescue Exception end Capybara.current_driver.should == driver_before_block end it 'should return the driver to what it was previously' do Capybara.current_driver = :selenium Capybara.using_driver(:culerity) do Capybara.using_driver(:rack_test) do Capybara.current_driver.should == :rack_test end Capybara.current_driver.should == :culerity end Capybara.current_driver.should == :selenium end it 'should yield the passed block' do called = false Capybara.using_driver(:selenium) { called = true } called.should == true end end describe '#using_wait_time' do before do @previous_wait_time = Capybara.default_wait_time end after do Capybara.default_wait_time = @previous_wait_time end it "should switch the wait time and switch it back" do in_block = nil Capybara.using_wait_time 6 do in_block = Capybara.default_wait_time end in_block.should == 6 Capybara.default_wait_time.should == @previous_wait_time end it "should ensure wait time is reset" do expect do Capybara.using_wait_time 6 do raise "hell" end end.to raise_error Capybara.default_wait_time.should == @previous_wait_time end end describe '#app' do it "should be changeable" do Capybara.app = "foobar" Capybara.app.should == 'foobar' end end describe '#current_session' do it "should choose a session object of the current driver type" do Capybara.current_session.should be_a(Capybara::Session) end it "should use #app as the application" do Capybara.app = proc {} Capybara.current_session.app.should == Capybara.app end it "should change with the current driver" do Capybara.current_session.mode.should == :rack_test Capybara.current_driver = :selenium Capybara.current_session.mode.should == :selenium end it "should be persistent even across driver changes" do object_id = Capybara.current_session.object_id Capybara.current_session.object_id.should == object_id Capybara.current_driver = :selenium Capybara.current_session.mode.should == :selenium Capybara.current_session.object_id.should_not == object_id Capybara.current_driver = :rack_test Capybara.current_session.object_id.should == object_id end it "should change when changing application" do object_id = Capybara.current_session.object_id Capybara.current_session.object_id.should == object_id Capybara.app = proc {} Capybara.current_session.object_id.should_not == object_id Capybara.current_session.app.should == Capybara.app end it "should change when the session name changes" do object_id = Capybara.current_session.object_id Capybara.session_name = :administrator Capybara.session_name.should == :administrator Capybara.current_session.object_id.should_not == object_id Capybara.session_name = :default Capybara.session_name.should == :default Capybara.current_session.object_id.should == object_id end end describe "#using_session" do it "should change the session name for the duration of the block" do Capybara.session_name.should == :default Capybara.using_session(:administrator) do Capybara.session_name.should == :administrator end Capybara.session_name.should == :default end it "should reset the session to the default, even if an exception occurs" do begin Capybara.using_session(:raise) do raise end rescue Exception end Capybara.session_name.should == :default end it "should yield the passed block" do called = false Capybara.using_session(:administrator) { called = true } called.should == true end end describe "#session_name" do it "should default to :default" do Capybara.session_name.should == :default end end describe 'the DSL' do before do @session = Class.new { include Capybara::DSL }.new end it "should be possible to include it in another class" do @session.visit('/with_html') @session.click_link('ullamco') @session.body.should include('Another World') end it "should provide a 'page' shortcut for more expressive tests" do @session.page.visit('/with_html') @session.page.click_link('ullamco') @session.page.body.should include('Another World') end it "should provide an 'using_session' shortcut" do Capybara.should_receive(:using_session).with(:name) @session.using_session(:name) end it "should provide a 'using_wait_time' shortcut" do Capybara.should_receive(:using_wait_time).with(6) @session.using_wait_time(6) end end end capybara-2.1.0/spec/result_spec.rb0000644000175000017500000000166412140721202016125 0ustar lunarlunarrequire 'spec_helper' describe Capybara::Result do let :string do Capybara.string <<-STRING STRING end let :result do string.all '//li' end it "has a length" do result.length.should == 4 end it "has a first element" do result.first.text == 'Alpha' end it "has a last element" do result.last.text == 'Delta' end it "can return an element by its index" do result.at(1).text.should == 'Beta' result[2].text.should == 'Gamma' end it "can be mapped" do result.map(&:text).should == %w(Alpha Beta Gamma Delta) end it "can be selected" do result.select do |element| element.text.include? 't' end.length.should == 2 end it "can be reduced" do result.reduce('') do |memo, element| memo += element.text[0] end.should == 'ABGD' end end capybara-2.1.0/spec/capybara_spec.rb0000644000175000017500000000261512140721202016366 0ustar lunarlunarrequire 'spec_helper' describe Capybara do describe 'default_wait_time' do after do Capybara.default_wait_time = @previous_default_time end it "should be changeable" do @previous_default_time = Capybara.default_wait_time Capybara.default_wait_time = 5 Capybara.default_wait_time.should == 5 end end describe '.register_driver' do it "should add a new driver" do Capybara.register_driver :schmoo do |app| Capybara::RackTest::Driver.new(app) end session = Capybara::Session.new(:schmoo, TestApp) session.visit('/') session.body.should include("Hello world!") end end describe ".server" do after do Capybara.server {|app, port| Capybara.run_default_server(app, port)} end it "should default to a proc that calls run_default_server" do mock_app = mock('app') Capybara.should_receive(:run_default_server).with(mock_app, 8000) Capybara.server.call(mock_app, 8000) end it "should return a custom server proc" do server = lambda {|app, port|} Capybara.server(&server) Capybara.server.should == server end end end describe Capybara::Session do context 'with non-existant driver' do it "should raise an error" do expect { Capybara::Session.new(:quox, TestApp).driver }.to raise_error(Capybara::DriverNotFoundError) end end end capybara-2.1.0/spec/rspec/0000755000175000017500000000000012140721202014355 5ustar lunarlunarcapybara-2.1.0/spec/rspec/features_spec.rb0000644000175000017500000000302212140721202017527 0ustar lunarlunarrequire 'spec_helper' require 'capybara/rspec' RSpec.configuration.before(:each, :example_group => {:file_path => "./spec/rspec/features_spec.rb"}) do @in_filtered_hook = true end feature "Capybara's feature DSL" do background do @in_background = true end scenario "includes Capybara" do visit('/') page.should have_content('Hello world!') end scenario "preserves description" do example.metadata[:full_description].should == "Capybara's feature DSL preserves description" end scenario "allows driver switching", :driver => :selenium do Capybara.current_driver.should == :selenium end scenario "runs background" do @in_background.should be_true end scenario "runs hooks filtered by file path" do @in_filtered_hook.should be_true end scenario "doesn't pollute the Object namespace" do Object.new.respond_to?(:feature, true).should be_false end end feature "given and given! aliases to let and let!" do given(:value) { :available } given!(:value_in_background) { :available } background do value_in_background.should be(:available) end scenario "given and given! work as intended" do value.should be(:available) value_in_background.should be(:available) end end feature "if xscenario aliases to pending then" do xscenario "this test should be 'temporarily disabled with xscenario'" do end end feature "Capybara's feature DSL with driver", :driver => :culerity do scenario "switches driver" do Capybara.current_driver.should == :culerity end end capybara-2.1.0/spec/rspec/matchers_spec.rb0000644000175000017500000005117512140721202017533 0ustar lunarlunarrequire 'spec_helper' require 'capybara/dsl' require 'capybara/rspec/matchers' describe Capybara::RSpecMatchers do include Capybara::DSL include Capybara::RSpecMatchers describe "have_css matcher" do it "gives proper description" do have_css('h1').description.should == "have css \"h1\"" end context "on a string" do context "with should" do it "passes if has_css? returns true" do "

Text

".should have_css('h1') end it "fails if has_css? returns false" do expect do "

Text

".should have_css('h2') end.to raise_error(/expected to find css "h2" but there were no matches/) end it "passes if matched node count equals expected count" do "

Text

".should have_css('h1', :count => 1) end it "fails if matched node count does not equal expected count" do expect do "

Text

".should have_css('h1', count: 2) end.to raise_error("expected to find css \"h1\" 2 times, found 1 match: \"Text\"") end it "fails if matched node count is less than expected minimum count" do expect do "

Text

".should have_css('p', minimum: 1) end.to raise_error("expected to find css \"p\" at least 1 time but there were no matches") end it "fails if matched node count is more than expected maximum count" do expect do "

Text

Text

Text

".should have_css('h1', maximum: 2) end.to raise_error('expected to find css "h1" at most 2 times, found 3 matches: "Text", "Text", "Text"') end it "fails if matched node count does not belong to expected range" do expect do "

Text

".should have_css('h1', between: 2..3) end.to raise_error("expected to find css \"h1\" between 2 and 3 times, found 1 match: \"Text\"") end end context "with should_not" do it "passes if has_no_css? returns true" do "

Text

".should_not have_css('h2') end it "fails if has_no_css? returns false" do expect do "

Text

".should_not have_css('h1') end.to raise_error(/expected not to find css "h1"/) end it "passes if matched node count does not equal expected count" do "

Text

".should_not have_css('h1', :count => 2) end it "fails if matched node count equals expected count" do expect do "

Text

".should_not have_css('h1', :count => 1) end.to raise_error(/expected not to find css "h1"/) end end end context "on a page or node" do before do visit('/with_html') end context "with should" do it "passes if has_css? returns true" do page.should have_css('h1') end it "fails if has_css? returns false" do expect do page.should have_css('h1#doesnotexist') end.to raise_error(/expected to find css "h1#doesnotexist" but there were no matches/) end end context "with should_not" do it "passes if has_no_css? returns true" do page.should_not have_css('h1#doesnotexist') end it "fails if has_no_css? returns false" do expect do page.should_not have_css('h1') end.to raise_error(/expected not to find css "h1"/) end end end end describe "have_xpath matcher" do it "gives proper description" do have_xpath('//h1').description.should == "have xpath \"\/\/h1\"" end context "on a string" do context "with should" do it "passes if has_xpath? returns true" do "

Text

".should have_xpath('//h1') end it "fails if has_xpath? returns false" do expect do "

Text

".should have_xpath('//h2') end.to raise_error(%r(expected to find xpath "//h2" but there were no matches)) end end context "with should_not" do it "passes if has_no_xpath? returns true" do "

Text

".should_not have_xpath('//h2') end it "fails if has_no_xpath? returns false" do expect do "

Text

".should_not have_xpath('//h1') end.to raise_error(%r(expected not to find xpath "//h1")) end end end context "on a page or node" do before do visit('/with_html') end context "with should" do it "passes if has_xpath? returns true" do page.should have_xpath('//h1') end it "fails if has_xpath? returns false" do expect do page.should have_xpath("//h1[@id='doesnotexist']") end.to raise_error(%r(expected to find xpath "//h1\[@id='doesnotexist'\]" but there were no matches)) end end context "with should_not" do it "passes if has_no_xpath? returns true" do page.should_not have_xpath('//h1[@id="doesnotexist"]') end it "fails if has_no_xpath? returns false" do expect do page.should_not have_xpath('//h1') end.to raise_error(%r(expected not to find xpath "//h1")) end end end end describe "have_selector matcher" do it "gives proper description" do matcher = have_selector('//h1') "

Text

".should matcher matcher.description.should == "have xpath \"//h1\"" end context "on a string" do context "with should" do it "passes if has_selector? returns true" do "

Text

".should have_selector('//h1') end it "fails if has_selector? returns false" do expect do "

Text

".should have_selector('//h2') end.to raise_error(%r(expected to find xpath "//h2" but there were no matches)) end end context "with should_not" do it "passes if has_no_selector? returns true" do "

Text

".should_not have_selector(:css, 'h2') end it "fails if has_no_selector? returns false" do expect do "

Text

".should_not have_selector(:css, 'h1') end.to raise_error(%r(expected not to find css "h1")) end end end context "on a page or node" do before do visit('/with_html') end context "with should" do it "passes if has_selector? returns true" do page.should have_selector('//h1', :text => 'test') end it "fails if has_selector? returns false" do expect do page.should have_selector("//h1[@id='doesnotexist']") end.to raise_error(%r(expected to find xpath "//h1\[@id='doesnotexist'\]" but there were no matches)) end it "includes text in error message" do expect do page.should have_selector("//h1", :text => 'wrong text') end.to raise_error(%r(expected to find xpath "//h1" with text "wrong text" but there were no matches)) end end context "with should_not" do it "passes if has_no_css? returns true" do page.should_not have_selector(:css, 'h1#doesnotexist') end it "fails if has_no_selector? returns false" do expect do page.should_not have_selector(:css, 'h1', :text => 'test') end.to raise_error(%r(expected not to find css "h1" with text "test")) end end end end describe "have_content matcher" do it "gives proper description" do have_content('Text').description.should == "text \"Text\"" end context "on a string" do context "with should" do it "passes if has_content? returns true" do "

Text

".should have_content('Text') end it "passes if has_content? returns true using regexp" do "

Text

".should have_content(/ext/) end it "fails if has_content? returns false" do expect do "

Text

".should have_content('No such Text') end.to raise_error(/expected to find text "No such Text" in "Text"/) end end context "with should_not" do it "passes if has_no_content? returns true" do "

Text

".should_not have_content('No such Text') end it "passes because escapes any characters that would have special meaning in a regexp" do "

Text

".should_not have_content('.') end it "fails if has_no_content? returns false" do expect do "

Text

".should_not have_content('Text') end.to raise_error(/expected not to find text "Text" in "Text"/) end end end context "on a page or node" do before do visit('/with_html') end context "with should" do it "passes if has_content? returns true" do page.should have_content('This is a test') end it "passes if has_content? returns true using regexp" do page.should have_content(/test/) end it "fails if has_content? returns false" do expect do page.should have_content('No such Text') end.to raise_error(/expected to find text "No such Text" in "(.*)This is a test(.*)"/) end context "with default selector CSS" do before { Capybara.default_selector = :css } it "fails if has_content? returns false" do expect do page.should have_content('No such Text') end.to raise_error(/expected to find text "No such Text" in "(.*)This is a test(.*)"/) end after { Capybara.default_selector = :xpath } end end context "with should_not" do it "passes if has_no_content? returns true" do page.should_not have_content('No such Text') end it "fails if has_no_content? returns false" do expect do page.should_not have_content('This is a test') end.to raise_error(/expected not to find text "This is a test"/) end end end end describe "have_text matcher" do it "gives proper description" do have_text('Text').description.should == "text \"Text\"" end context "on a string" do context "with should" do it "passes if has_text? returns true" do "

Text

".should have_text('Text') end it "passes if has_text? returns true using regexp" do "

Text

".should have_text(/ext/) end it "fails if has_text? returns false" do expect do "

Text

".should have_text('No such Text') end.to raise_error(/expected to find text "No such Text" in "Text"/) end it "casts Fixnum to string" do expect do "

Text

".should have_text(3) end.to raise_error(/expected to find text "3" in "Text"/) end it "fails if matched text count does not equal to expected count" do expect do "

Text

".should have_text('Text', count: 2) end.to raise_error(/expected to find text "Text" 2 times in "Text"/) end it "fails if matched text count is less than expected minimum count" do expect do "

Text

".should have_text('Lorem', minimum: 1) end.to raise_error(/expected to find text "Lorem" at least 1 time in "Text"/) end it "fails if matched text count is more than expected maximum count" do expect do "

Text TextText

".should have_text('Text', maximum: 2) end.to raise_error(/expected to find text "Text" at most 2 times in "Text TextText"/) end it "fails if matched text count does not belong to expected range" do expect do "

Text

".should have_text('Text', between: 2..3) end.to raise_error(/expected to find text "Text" between 2 and 3 times in "Text"/) end end context "with should_not" do it "passes if has_no_text? returns true" do "

Text

".should_not have_text('No such Text') end it "passes because escapes any characters that would have special meaning in a regexp" do "

Text

".should_not have_text('.') end it "fails if has_no_text? returns false" do expect do "

Text

".should_not have_text('Text') end.to raise_error(/expected not to find text "Text" in "Text"/) end end end context "on a page or node" do before do visit('/with_html') end context "with should" do it "passes if has_text? returns true" do page.should have_text('This is a test') end it "passes if has_text? returns true using regexp" do page.should have_text(/test/) end it "can check for all text" do page.should have_text(:all, 'Some of this text is hidden!') end it "can check for visible text" do page.should have_text(:visible, 'Some of this text is') page.should_not have_text(:visible, 'Some of this text is hidden!') end it "fails if has_text? returns false" do expect do page.should have_text('No such Text') end.to raise_error(/expected to find text "No such Text" in "(.*)This is a test(.*)"/) end context "with default selector CSS" do before { Capybara.default_selector = :css } it "fails if has_text? returns false" do expect do page.should have_text('No such Text') end.to raise_error(/expected to find text "No such Text" in "(.*)This is a test(.*)"/) end after { Capybara.default_selector = :xpath } end end context "with should_not" do it "passes if has_no_text? returns true" do page.should_not have_text('No such Text') end it "fails if has_no_text? returns false" do expect do page.should_not have_text('This is a test') end.to raise_error(/expected not to find text "This is a test"/) end end end end describe "have_link matcher" do let(:html) { 'Just a link' } it "gives proper description" do have_link('Just a link').description.should == "have link \"Just a link\"" end it "passes if there is such a button" do html.should have_link('Just a link') end it "fails if there is no such button" do expect do html.should have_link('No such Link') end.to raise_error(/expected to find link "No such Link"/) end end describe "have_title matcher" do it "gives proper description" do have_title('Just a title').description.should == "have title \"Just a title\"" end context "on a string" do let(:html) { 'Just a title' } it "passes if there is such a title" do html.should have_title('Just a title') end it "fails if there is no such title" do expect do html.should have_title('No such title') end.to raise_error(/expected there to be title "No such title"/) end end context "on a page or node" do before do visit('/with_js') end it "passes if there is such a title" do page.should have_title('with_js') end it "fails if there is no such title" do expect do page.should have_title('No such title') end.to raise_error(/expected there to be title "No such title"/) end end end describe "have_button matcher" do let(:html) { '' } it "gives proper description" do have_button('A button').description.should == "have button \"A button\"" end it "passes if there is such a button" do html.should have_button('A button') end it "fails if there is no such button" do expect do html.should have_button('No such Button') end.to raise_error(/expected to find button "No such Button"/) end end describe "have_field matcher" do let(:html) { '

' } it "gives proper description" do have_field('Text field').description.should == "have field \"Text field\"" end it "passes if there is such a field" do html.should have_field('Text field') end it "fails if there is no such field" do expect do html.should have_field('No such Field') end.to raise_error(/expected to find field "No such Field"/) end end describe "have_checked_field matcher" do let(:html) do ' ' end it "gives proper description" do have_checked_field('it is checked').description.should == "have field \"it is checked\"" end context "with should" do it "passes if there is such a field and it is checked" do html.should have_checked_field('it is checked') end it "fails if there is such a field but it is not checked" do expect do html.should have_checked_field('unchecked field') end.to raise_error(/expected to find field "unchecked field"/) end it "fails if there is no such field" do expect do html.should have_checked_field('no such field') end.to raise_error(/expected to find field "no such field"/) end end context "with should not" do it "fails if there is such a field and it is checked" do expect do html.should_not have_checked_field('it is checked') end.to raise_error(/expected not to find field "it is checked"/) end it "passes if there is such a field but it is not checked" do html.should_not have_checked_field('unchecked field') end it "passes if there is no such field" do html.should_not have_checked_field('no such field') end end end describe "have_unchecked_field matcher" do let(:html) do ' ' end it "gives proper description" do have_unchecked_field('unchecked field').description.should == "have field \"unchecked field\"" end context "with should" do it "passes if there is such a field and it is not checked" do html.should have_unchecked_field('unchecked field') end it "fails if there is such a field but it is checked" do expect do html.should have_unchecked_field('it is checked') end.to raise_error(/expected to find field "it is checked"/) end it "fails if there is no such field" do expect do html.should have_unchecked_field('no such field') end.to raise_error(/expected to find field "no such field"/) end end context "with should not" do it "fails if there is such a field and it is not checked" do expect do html.should_not have_unchecked_field('unchecked field') end.to raise_error(/expected not to find field "unchecked field"/) end it "passes if there is such a field but it is checked" do html.should_not have_unchecked_field('it is checked') end it "passes if there is no such field" do html.should_not have_unchecked_field('no such field') end end end describe "have_select matcher" do let(:html) { '' } it "gives proper description" do have_select('Select Box').description.should == "have select box \"Select Box\"" end it "passes if there is such a select" do html.should have_select('Select Box') end it "fails if there is no such select" do expect do html.should have_select('No such Select box') end.to raise_error(/expected to find select box "No such Select box"/) end end describe "have_table matcher" do let(:html) { '
Lovely table
' } it "gives proper description" do have_table('Lovely table').description.should == "have table \"Lovely table\"" end it "passes if there is such a select" do html.should have_table('Lovely table') end it "fails if there is no such select" do expect do html.should have_table('No such Table') end.to raise_error(/expected to find table "No such Table"/) end end end capybara-2.1.0/spec/server_spec.rb0000644000175000017500000000650512140721202016114 0ustar lunarlunarrequire 'spec_helper' describe Capybara::Server do it "should spool up a rack server" do @app = proc { |env| [200, {}, ["Hello Server!"]]} @server = Capybara::Server.new(@app).boot @res = Net::HTTP.start(@server.host, @server.port) { |http| http.get('/') } @res.body.should include('Hello Server') end it "should do nothing when no server given" do expect do @server = Capybara::Server.new(nil).boot end.not_to raise_error end it "should bind to the specified host" do Capybara.server_host = '0.0.0.0' app = proc { |env| [200, {}, ["Hello Server!"]]} server = Capybara::Server.new(app).boot server.host.should == '0.0.0.0' Capybara.server_host = nil end it "should use specified port" do Capybara.server_port = 22789 @app = proc { |env| [200, {}, ["Hello Server!"]]} @server = Capybara::Server.new(@app).boot @res = Net::HTTP.start(@server.host, 22789) { |http| http.get('/') } @res.body.should include('Hello Server') Capybara.server_port = nil end it "should use given port" do @app = proc { |env| [200, {}, ["Hello Server!"]]} @server = Capybara::Server.new(@app, 22790).boot @res = Net::HTTP.start(@server.host, 22790) { |http| http.get('/') } @res.body.should include('Hello Server') Capybara.server_port = nil end it "should find an available port" do @app1 = proc { |env| [200, {}, ["Hello Server!"]]} @app2 = proc { |env| [200, {}, ["Hello Second Server!"]]} @server1 = Capybara::Server.new(@app1).boot @server2 = Capybara::Server.new(@app2).boot @res1 = Net::HTTP.start(@server1.host, @server1.port) { |http| http.get('/') } @res1.body.should include('Hello Server') @res2 = Net::HTTP.start(@server2.host, @server2.port) { |http| http.get('/') } @res2.body.should include('Hello Second Server') end it "should use the server if it already running" do @app1 = proc { |env| [200, {}, ["Hello Server!"]]} @app2 = proc { |env| [200, {}, ["Hello Second Server!"]]} @server1a = Capybara::Server.new(@app1).boot @server1b = Capybara::Server.new(@app1).boot @server2a = Capybara::Server.new(@app2).boot @server2b = Capybara::Server.new(@app2).boot @res1 = Net::HTTP.start(@server1b.host, @server1b.port) { |http| http.get('/') } @res1.body.should include('Hello Server') @res2 = Net::HTTP.start(@server2b.host, @server2b.port) { |http| http.get('/') } @res2.body.should include('Hello Second Server') @server1a.port.should == @server1b.port @server2a.port.should == @server2b.port end it "should raise server errors when the server errors before the timeout" do begin Capybara.server do sleep 0.1 raise 'kaboom' end proc do Capybara::Server.new(proc {|e|}).boot end.should raise_error(RuntimeError, 'kaboom') ensure # TODO refactor out the defaults so it's reliant on unset state instead of # a one-time call in capybara.rb Capybara.server {|app, port| Capybara.run_default_server(app, port)} end end it "is not #responsive? when Net::HTTP raises a SystemCallError" do app = lambda { [200, {}, ['Hello, world']] } server = Capybara::Server.new(app) Net::HTTP.should_receive(:start).and_raise(SystemCallError.allocate) expect(server.responsive?).to eq false end end capybara-2.1.0/spec/selenium_spec.rb0000644000175000017500000000235412140721202016425 0ustar lunarlunarrequire 'spec_helper' module TestSessions Selenium = Capybara::Session.new(:selenium, TestApp) end Capybara::SpecHelper.run_specs TestSessions::Selenium, "selenium", :skip => [ :response_headers, :status_code, :trigger ] describe Capybara::Session do context 'with selenium driver' do before do @session = TestSessions::Selenium end describe '#driver' do it "should be a selenium driver" do @session.driver.should be_an_instance_of(Capybara::Selenium::Driver) end end describe '#mode' do it "should remember the mode" do @session.mode.should == :selenium end end describe "exit codes" do before do @current_dir = Dir.getwd Dir.chdir(File.join(File.dirname(__FILE__), '..')) end after do Dir.chdir(@current_dir) end it "should have return code 1 when running selenium_driver_rspec_failure.rb" do `rspec spec/fixtures/selenium_driver_rspec_failure.rb` $?.exitstatus.should be 1 end it "should have return code 0 when running selenium_driver_rspec_success.rb" do `rspec spec/fixtures/selenium_driver_rspec_success.rb` $?.exitstatus.should be 0 end end end end capybara-2.1.0/History.md0000644000175000017500000006005712140721202014302 0ustar lunarlunar# Version 2.1.0 Release date: Unreleased ### Changed * Hard version requirement on Ruby >= 1.9.3. Capybara will no longer install on 1.8.7. [Felix Schäfer] * Capybara no longer depends on the `selenium-webdriver` gem. Add it to your Gemfile if you wish to use the Selenium driver. [Jonas Nicklas] * `Capybara.ignore_hidden_elements` defaults to `true`. [Jonas Nicklas] * In case of multiple matches `smart` matching is used by default. Set `Capybara.match = :one` to revert to old behaviour. [Jonas Nicklas]. * Options in select boxes use smart matching and no longer need to match exactly. Set `Capybara.exact_options = false` to revert to old behaviour. [Jonas Nicklas]. * Visibility of text depends on `Capybara.ignore_hidden_elements` instead of always returning only visible text. Set `Capybara.visible_text_only = true` to revert to old behaviour. [Jonas Nicklas] * Cucumber cleans up session after scenario instead. This is consistent with RSpec and makes more sense, since we raise server errors in `reset!`. [Jonas Nicklas] ### Added * All actions (`click_link`, `fill_in`, etc...) and finders now take an options hash, which is passed through to `find`. [Jonas Nicklas] * CSS selectors are sent straight through to driver instead of being converted to XPath first. Enables the use of some pseudo selectors, such as `invalid` in some drivers. [Thomas Walpole] * `Capybara.asset_host` option, which inserts a `base` tag into the page on `save_and_open_page`, eases debugging with the Rails asset pipeline. [Steve Hull] * `exact` option, can specify whether to match substrings or entire text. [Jonas Nicklas] * `match` option, can specify behaviour in case of multiple matches. [Jonas Nicklas] * `wait` option, can specify how long to wait for a given action/finder. [Jonas Nicklas] * Config option which disables bubbling of errors raised inside server. [Jonas Nicklas] * `text` now takes a parameter which makes it possible to return either all text or only visible text. The default depends on `Capybara.ignore_hidden_elements`. `Capybara.visible_text_only` option is available for compatibility. [Jonas Nicklas] * `has_content?` and `has_text?` now take the same count options as `has_selector?` [Andrey Botalov] * `current_scope` is now public API, returns the current element when `within` is used. [Martijn Walraven] * `find("input").disabled?` returns true if a node is disabled. [Ben Lovell] * Find disabled fields and buttons with `:disabled => false`. [Jonas Nicklas] * `find("input").hover` moves the mouse to the element in supported drivers. [Thomas Walpole] * RackTest driver now support `form` attribute on form elements. [Thomas Walpole] * `page.title` returns the page title. [Terry Progetto] * `has_title?` matcher to assert on page title. [Jonas Nicklas] * The gem is now signed with a certicficate. The public key is available in the repo. [Jonas Nicklas] * `:select` and `:textarea` are valid options for the `:type` filter on `find_field` and `has_field?`. [Yann Plancqueel] ### Fixed * Fixed race conditions when synchronizing across multiple nodes [Jonas Nicklas] * Fixed race conditions in deeply nested selectors [Jonas Nicklas] * Fix issue with `within_frame`, where selecting multiple nested frames didn't work as intended. [Thomas Walpole] * RackTest no longer fills in readonly textareas. [Thomas Walpole] * Don't use autoload to load files, require them directly instead. [Jonas Nicklas] * Rescue weird exceptions when booting server [John Wilger] * Non strings are now properly cast when using the maxlength attribute [Jonas Nicklas] # Version 2.0.3 Release date: 2013-03-26 * Check against Rails version fixed to work with Rails' master branch now returning a Gem::Version [Jonas Nicklas] * Use posix character class for whitespace replace, solves various encoding problems on Ruby 2.0.0 and JRuby. [Ben Cates] # Version 2.0.2 Release date: 2012-12-31 ### Changed * Capybara no longer uses thin as a server if it is available, due to thread safety issues. Now Capybara always defaults to WEBrick. [Jonas Nicklas] ### Fixed * Suppress several warnings [Kouhei Sutou] * Fix default host becoming nil [Brian Cardarella] * Fix regression in 2.0.1 which caused node comparisons with non node objects to throw an exception [Kouhei Sotou] * A few changes to the specs, only relevant to driver authors [Jonas Nicklas] * Encoding error under JRuby [Piotr Krawiec] * Ruby 2 encoding fix [Murahashi Sanemat Kenichi] * Catch correct exception on server timeout [Jonathan del Strother] # Version 2.0.1 Release date: 2012-12-21 ### Changed * Move the RackTest driver override with the `:respect_data_method` option enabled from capybara/rspec to capybara/rails, so that it is enabled in Rails projects that don't use RSpec. [Carlos Antonio da Silva] * `source` is now an alias for `html`. RackTest no longer returns modifications to `html`. This basically codifies the behaviour which we've had for a while anyway, and should have minimal impact for end users. For driver authors, it means that they only have to implement `html`, and not `source`. [Jonas Nicklas] ### Fixed * Visiting relative URLs when `app_host` is set and no server is running works as expected. [Jonas Nicklas] * `fill_in` works properly under Selenium again when the caret is not at the end of the field before the method is called. [Douwe Maan, Jonas Nicklas, Jari Bakken] * `attach_file` can once again be given a Pathname [Jake Goulding] # Version 2.0.0 Release date: 2012-11-05 ### Changed * Dropped official support for Ruby 1.8.x. [Jonas Nicklas] * `respect_data_method` default to `false` for the RackTest driver in non-rails applications. That means that Capybara no longer picks up `data-method="post"` et. al. from links by default when you haven't required capybara/rails [Jonas Nicklas] * `find` now raises an error if more than one element was found. Since `find` is used by most actions, like `click_link` under the surface, this means that all actions need to unambiguous in the future. [Jonas Nicklas] * All methods which find or manipulate fields or buttons now ignore them when they are disabled. [Jonas Nicklas] * Can no longer find elements by id via `find(:foo)`, use `find("#foo")` or `find_by_id("foo")` instead. [Jonas Nicklas] * `Element#text` on RackTest now only returns visible text and normalizes (strips) whitespace, as with Selenium [Mark Dodwell, Jo Liss] * `has_content?` now checks the text value returned by `Element#text`, as opposed to querying the DOM. Which means it does not match hidden text. [Ryan Montgomery, Mark Dodwell, Jo Liss] * #394: `#body` now returns the unmodified source (like `#source`), not the current state of the DOM (like `#html`), by popular request [Jonas Nicklas] * `Node#all` no longer returns an array, but rather an enumerable `Capybara::Result` [Jonas Nicklas] * The arguments to `select` and `unselect` needs to be the exact text of an option in a select box, substrings are no longer allowed [Jonas Nicklas] * The `options` option to `has_select?` must match the exact set of options. Use `with_options` for the old behaviour. [Gonzalo Rodriguez] * The `selected` option to `has_select?` must match all selected options for multiple selects. [Gonzalo Rodriguez] * Various internals for running driver specs, this should only affect driver authors [Jonas Nicklas] * Rename `Driver#body` to `Driver#html` (relevant only for driver authors) [Jo Liss] ### Removed * No longer possible to specify `failure_message` for custom selectors. [Jonas Nicklas] * #589: `Capybara.server_boot_timeout` has been removed in favor of a higher (60-second) hard-coded timeout [Jo Liss] * `Capybara.prefer_visible_elements` has been removed, as it is no longer needed with the changed find semantics [Jonas Nicklas] * `Node#wait_until` and `Session#wait_until` have been removed. See `Node#synchronize` for an alternative [Jonas Nicklas] * `Capybara.timeout` has been removed [Jonas Nicklas] * The `:resynchronize` option has been removed from the Selenium driver [Jonas Nicklas] * The `rows` option to `has_table?` has been removed without replacement. [Jonas Nicklas] ### Added * Much improved error message [Jonas Nicklas] * Errors from inside the session for apps running in a server are raised when session is reset [James Tucker, Jonas Nicklas] * A ton of new selectors built in out of the box, like `field`, `link`, `button`, etc... [Adam McCrea, Jonas Nicklas] * `has_text?` has been added as an alias for `has_content?` [Jonas Nicklas] * Add `Capybara.server_host` option (default: 127.0.0.1) [David Balatero] * Add `:type` option for `page.has_field?` [Gonzalo Rodríguez] * Custom matchers can now be specified in CSS in addition to XPath [Jonas Nicklas] * `Node#synchronize` method to rerun a block of code if certain errors are raised [Jonas Nicklas] * `Capybara.always_include_port` config option always includes the server port in URLs when using `visit`. Facilitates testing different domain names`. [Douwe Maan] * Redirect limit for RackTest driver is configurable [Josh Lane] * Server port can be manually specified during initialization of server. [Jonas Nicklas, John Wilger] * `has_content?` and `has_text?` can be given a regular expression [Vasiliy Ermolovich] * Multiple files can be uploaded with `attach_file` [Jarl Friis] ### Fixed * Nodes found via `all` are no longer reloaded. This fixes weird quirks where nodes would seemingly randomly replace themselves with other nodes [Jonas Nicklas] * Session is only reset if it has been modified, dramatically improves performance if only part of the test suite runs Capybara. [Jonas Nicklas] * Test suite now passes on Ruby 1.8 [Jo Liss] * #565: `require 'capybara/dsl'` is no longer necessary [Jo Liss] * `Rack::Test` now respects ports when changing hosts [Jo Liss] * #603: `Rack::Test` now preserves the original referer URL when following a redirect [Rob van Dijk] * Rack::Test now does not send a referer when calling `visit` multiple times [Jo Liss] * Exceptions during server boot now propagate to main thread [James Tucker] * RSpec integration now cleans up before the test instead of after [Darwin] * If `respect_data_method` is true, the data-method attribute can be capitalized [Marco Antonio] * Rack app boot timing out raises an error as opposed to just logging to STDOUT [Adrian Irving-Beer] * `#source` returns an empty string instead of nil if no pages have been visited [Jonas Nicklas] * Ignore first leading newline in textareas in RackTest [Vitalii Khustochka] * `within_frame` returns the value of the given block [Alistair Hutchison] * Running `Node.set` on text fields will not trigger more than one change event [Andrew Kasper] * Throw an error when an option is given to a finder method, like `all` or `has_selector?` which Capybara doesn't understand [Jonas Nicklas] * Two references to the node now register as equal when comparing them with `==` [Jonas Nicklas] * `has_text` (`has_content`) now accepts non-string arguments, like numbers. [Jo Liss] * `has_text` and `text` now correctly normalize Unicode whitespace, such as ` `. [Jo Liss] * RackTest allows protocol relative URLs [Jonas Nicklas] * Arguments are cast to string where necessary, so that e.g. `click_link(:foo)` works as expected. [Jonas Nicklas] * `:count => 0` now works as expected [Jarl Friis] * Fixed race conditions on negative assertions when removing nodes [Jonas Nicklas] # Version 1.1.4 Release date: 2012-11-28 ### Fixed * Fix more race conditions on negative assertions. [Jonas Nicklas] # Version 1.1.3 Release date: 2012-10-30 ### Fixed: * RackTest driver ignores leading newline in textareas, this is consistent with the spec and how browsers behave. [Vitalii Khustochka] * Nodes found via `all` and `first` are never reloaded. This fixes issues where a node would sometimes magically turn into a completely different node. [Jonas Nicklas] * Fix race conditions on negative assertions. This fixes issues where removing an element and asserting on its non existence could cause StaleElementReferenceError and similar to be thrown. [Jonas Nicklas] * Options are no longer lost when reloading elements. This fixes issues where reloading an element would cause a non-matching element to be found, because options to `find` were ignored. [Jonas Nicklas] # Version 1.1.2 Release date: 2011-11-15 ### Fixed * #541: Make attach_file work with selenium-webdriver >=2.12 [Jonas Nicklas] # Version 1.1.0 Release date: 2011-09-02 ### Fixed * Sensible inspect for Capybara::Session [Jo Liss] * Fix headers and host on redirect [Matt Colyer, Jonas Nicklas, Kim Burgestrand] * using_driver now restores the old driver instead of reverting to the default [Carol Nichols] * Errors when following links relative to the root path under rack-test [Jonas Nicklas, Kim Burgestrand] * Make sure exit codes are propagated properly [Edgar Beigarts] ### Changed * resynchronization is off by default under Selenium ### Added * Elements are automatically reloaded (including parents) during wait [Jonas Nicklas] * Rescue driver specific element errors, such as the dreaded ObsoleteElementError and retry [Jonas Nicklas] * Raise an error if something has frozen time [Jonas Nicklas] * Allow within to take a node instead of a selector [Peter Williams] * Using wait_time_time to change wait time for a block of code [Jonas Nicklas, Kim Burgestrand] * Option for rack-test driver to disable data-method hack [Jonas Nicklas, Kim Burgestrand] # Version 1.0.1 Release date: 2011-08-12 ### Fixed * Dependend on selenium-webdriver ~>2.0 and fix deprecations [Thomas Walpole, Jo Liss] * Depend on Launch 2.0 [Jeremy Hinegardner] * Rack-Test ignores fill in on fields with maxlength="" # Version 1.0.0 Release date: 2011-06-14 ### Added * Added DSL for acceptance tests, inspired by Luismi Cavallé's Steak [Luismi Cavalle and Jonas Nicklas] * Selenium driver automatically waits for AJAX requests to finish [mgiambalvo, Nicklas Ramhöj and Jonas Nicklas] * Support for switching between multiple named sessions [Tristan Dunn] * failure_message can be specified for Selectors [Jonas Nicklas] * RSpec matchers [David Chelimsky and Jonas Nicklas] * Added save_page to save tempfile without opening in browser [Jeff Kreeftmeijer] * Cucumber now switches automatically to a registered driver if the tag matches the name [Jonas Nicklas] * Added Session#text [Jonas Nicklas and Scott Cytacki] * Added Session#html as an alias for Session#body [Jo Liss] * Added Session#current_host method [Jonas Nicklas] * Buttons can now be clicked by title [Javier Martin] * :headers option for RackTest driver to set custom HTTP headers [Jonas Nicklas] ### Removed * Culerity and Celerity drivers have been removed and split into separate gems [Gabriel Sobrinho] ### Deprecated * `include Capybara` has been deprecated in favour of `include Capybara::DSL` [Jonas Nicklas] ### Changed * Rack test driver class has been renamed from Capybara::Driver::RackTest to Capybara::RackTest::Driver [Jonas Nicklas] * Selenium driver class has been renamed from Capybara::Driver::Selenium to Capybara::Selenium::Driver [Jonas Nicklas] * Capybara now prefers visible elements over hidden elements, disable by setting Capybara.prefer_visible_elements = false [Jonas Nicklas and Nicklas Ramhöj] * For RSpec, :type => :request is now supported (and preferred over :acceptance) [Jo Liss] * Selenium driver tried to wait for AJAX requests to finish before proceeding [Jonas Nicklas and Nicklas Ramhöj] * Session no longer uses method missing, uses explicit delegates instead [Jonas Nicklas] ### Fixed * The Rack::Test driver now respects maxlength on text fields [Guilherme Carvalho] * Allow for more than one save_and_open_page call per second [Jo Liss] * Automatically convert options to :count, :minimum, :maximum, etc. to integers [Keith Marcum] * Rack::Test driver honours maxlength on input fields [Guilherme Carvalho] * Rack::Test now works as expected with domains and subdomains [Jonas Nicklas] * Session is reset more thoroughly between tests. [Jonas Nicklas] * Raise error when uploading non-existant file [Jonas Nicklas] * Rack reponse body should respond to #each [Piotr Sarnacki] * Deprecation warnings with selenium webdriver 0.2.0 [Aaron Gibraltar] * Selenium Chrome no longer YELLS tagname [Carl Jackson & David W. Frank] * Capybara no longer strips encoding before sending to Rack [Jonas Nicklas] * Improve handling of relative URLs [John Barton] * Readd and fix build_rack_mock_session [Jonas Nicklas, Jon Leighton] # Version 0.4.1 Release date: 2011-01-21 ### Added * New click_on alias for click_link_or_button, shorter yet unambiguous. [Jonas Nicklas] * Finders now accept :visible => false which will find all elements regardless of Capybara.ignore_hidden_elements [Jonas Nicklas] * Configure how the server is started via Capybara.server { |app, port| ... }. [John Firebough] * Added :between, :maximum and :minimum options to has_selector and friends [James B. Byrne] * New Capybara.string util function which allows matchers on arbitrary strings, mostly for helper and view specs [David Chelimsky and Jonas Nicklas] * Server boot timeout is now configurable, via Capybara.server_boot_timeout [Adam Cigánek] * Built in support for RSpec [Jonas Nicklas] * Capybara.using_driver to switch to a different driver temporarily [Jeff Kreeftmeijer] * Added Session#first which is somewhat speedier than Session#all, use it internally for speed boost [John Firebaugh] ### Changed * Session#within now accepts the same arguments as other finders, like Session#all and Session#find [Jonas Nicklas] ### Removed * All deprecations from 0.4.0 have been removed. [Jonas Nicklas] ### Fixed * Don't mangle URLs in save_and_open_page when using self-closing tags [Adam Spiers] * Catch correct error when server boot times out [Jonas Nicklas] * Celerity driver now properly passes through options, making it configurable [Jonas Nicklas] * Better implementation of attributes in C[ue]lerity, should fix issues with attributes with strange names [Jonas Nicklas] * Session#find no longer swallows errors [Jonas Nicklas] * Fix problems with multiple file inputs [Philip Arndt] * Submit multipart forms as multipart under rack-test even if they contain no files [Ryan Kinderman] * Matchers like has_select? and has_checked_field? now work with dynamically changed values [John Firebaugh] * Preserve order of rack params [Joel Chippindale] * RackTest#reset! is more thorough [Joel Chippindale] # Version 0.4.0 Release date: 2010-10-22 ### Changed * The Selector API was changed slightly, use Capybara.add_selector, see README ### Fixed * Celerity driver is registered properly * has_selector? and has_no_selector? added to DSL * Multiple selects return correct values under C[cu]lerity * Naked query strings are handled correctly by rack-test # Version 0.4.0.rc Release date: 2010-10-12 ### Changed * within and find/locate now follow the XPath spec in that //foo finds all nodes in the document, instead of only for the context node. See this post for details: http://groups.google.com/group/ruby-capybara/browse_thread/thread/b129067979df21b3 * within now executes within the first found instance of the selector, not in all of them * find now waits for AJAX requests and raises an exception when the element is not found (same as locate used to do) * The default selector is now CSS, not XPath ### Deprecated * Session#click has been renamed click_link_or_button and the old click has been deprecated * Node#node has been renamed native * Node#locate is deprecated in favor of Node#find, which now behaves identically * Session#drag is deprecated, please use Node#drag_to(other_node) instead ### Added * Pretty much everything is properly documented now * It's now possible to call all session methods on nodes, like `find('#foo').fill_in(...)` * Custom selectors can be added with Capybara::Selector.add * The :id selector is added by default, use it lile `find(:id, 'foo')` or `find(:foo)` * Added Node#has_selector? so any kind of selector can be queried. * Added Capybara.configure for less wordy configuration * Added within_window to switch between different windows (currently Selenium only) * Capybara.server_port to provide a fixed port if wanted (defaults to automatic selection) ### Fixed * CSS selectors with multiple selectors, such as "h1, h2" now work correctly * Port is automatically assigned instead of guessing * Strip encodings in rack-test, no more warnings! * RackTest no longer submits disabled fields * Servers no longer output annoying debug information when started * TCP port selection is left to Ruby to decide, no more port guessing * Select boxes now return option value instead of text if present * The default has been changed from localhost to 127.0.0.1, should fix some obscure selenium bugs * RackTest now supports complex field names, such as foo[bar][][baz] # Version 0.3.9 Release date: 2010-07-03 ### Added * status_code which returns the HTTP status code of the last response (no Selenium!) * Capybara.save_and_open_page to store tempfiles * RackTest and Culerity drivers now clean up after themselves properly ### Fixed * When no rack app is set and the app is called, a more descriptive error is raised * select now works with optgroups * Don't submit image buttons unless they were clicked under rack-test * Support custom field types under Selenium * Support input fields without a type, treat them as though they were text fields * Redirect now throws an error after 5 redirects, as per RFC * Selenium now properly raises an error when Node#trigger is called * Node#value now returns the correct value for textareas under rack-test # Version 0.3.8 Release date: 2010-05-12 ### Added * Within_frame method to execute a block of code within a particular iframe (Selenium only!) ### Fixed * Single quotes are properly escaped with `select` under rack-test and Selenium. * The :text option for searches now escapes regexp special characters when a string is given. * Selenium now correctly checks already checked checkboxes (same with uncheck) * Timing issue which caused Selenium to hang under certain circumstances. * Selenium now resolves attributes even if they are given as a Symbol # Version 0.3.7 Release date: 2010-04-09 This is a drop in compatible maintainance release. It's mostly important for driver authors. ### Added * RackTest scans for data-method which rails3 uses to change the request method ### Fixed * Don't hang when starting server on Windoze ### Changed * The driver and session specs are now located inside lib! Driver authors can simply require them. # Version 0.3.6 Release date: 2010-03-22 This is a maintainance release with minor bug fixes, should be drop in compatible. ### Added * It's now possible to load in external drivers ### Fixed * has_content? ignores whitespace * Trigger events when choosing radios and checking checkboxes under Selenium * Make Capybara.app totally optional when running without server * Changed fallback host so it matches the one set up by Rails' integration tests # Version 0.3.5 Release date: 2010-02-26 This is a mostly backwards compatible release, it does break the API in some minor places, which should hopefully not affect too many users, please read the release notes carefully! ### Breaking * Relative searching in a node (e.g. find('//p').all('//a')) will now follow XPath standard this means that if you want to find descendant nodes only, you'll need to prefix a dot! * `visit` now accepts fully qualified URLs for drivers that support it. * Capybara will always try to run a rack server, unless you set Capybara.run_sever = false ### Changed * thin is preferred over mongrel and webrick, since it is Ruby 1.9 compatible * click_button and click will find , clicking them does nothing in RackTest ### Added * Much improved error messages in a multitude of places * More semantic page querying with has_link?, has_button?, etc... * Option to ignore hidden elements when querying and interacting with the page * Support for multiple selects ### Fixed * find_by_id is no longer broken * clicking links where the image's alt attribute contains the text is now possible * within_fieldset and within_table work when the default selector is CSS * boolean attributes work the same across drivers (return true/false) capybara-2.1.0/README.md0000644000175000017500000006404112140721202013573 0ustar lunarlunar# Capybara [![Build Status](https://secure.travis-ci.org/jnicklas/capybara.png)](http://travis-ci.org/jnicklas/capybara) [![Dependency Status](https://gemnasium.com/jnicklas/capybara.png)](https://gemnasium.com/jnicklas/capybara) [![Code Quality](https://codeclimate.com/badge.png)](https://codeclimate.com/github/jnicklas/capybara) Capybara helps you test web applications by simulating how a real user would interact with your app. It is agnostic about the driver running your tests and comes with Rack::Test and Selenium support built in. WebKit is supported through an external gem. **Need help?** Ask on the mailing list (please do not open an issue on GitHub): http://groups.google.com/group/ruby-capybara ## Key benefits - **No setup** necessary for Rails and Rack application. Works out of the box. - **Intuitive API** which mimics the language an actual user would use. - **Switch the backend** your tests run against from fast headless mode to an actual browser with no changes to your tests. - **Powerful synchronization** features mean you never have to manually wait for asynchronous processes to complete. ## Setup Capybara requires Ruby 1.9.3 or later. To install, type: ```bash gem install capybara ``` If the application that you are testing is a Rails app, add this line to your test helper file: ```ruby require 'capybara/rails' ``` If the application that you are testing is a Rack app, but not Rails, set Capybara.app to your Rack app: ```ruby Capybara.app = MyRackApp ``` If you need to test JavaScript, or if your app interacts with (or is located at) a remote URL, you'll need to [use a different driver](#drivers). ## Using Capybara with Cucumber The `cucumber-rails` gem comes with Capybara support built-in. If you are not using Rails, manually load the `capybara/cucumber` module: ```ruby require 'capybara/cucumber' Capybara.app = MyRackApp ``` You can use the Capybara DSL in your steps, like so: ```ruby When /I sign in/ do within("#session") do fill_in 'Login', :with => 'user@example.com' fill_in 'Password', :with => 'password' end click_link 'Sign in' end ``` You can switch to the `Capybara.javascript_driver` (`:selenium` by default) by tagging scenarios (or features) with `@javascript`: ```ruby @javascript Scenario: do something Ajaxy When I click the Ajax link ... ``` There are also explicit `@selenium` and `@rack_test` tags set up for you. ## Using Capybara with RSpec Load RSpec 2.x support by adding the following line (typically to your `spec_helper.rb` file): ```ruby require 'capybara/rspec' ``` If you are using Rails, put your Capybara specs in `spec/features`. If you are not using Rails, tag all the example groups in which you want to use Capybara with `:type => :feature`. You can now write your specs like so: ```ruby describe "the signup process", :type => :feature do before :each do User.make(:email => 'user@example.com', :password => 'caplin') end it "signs me in" do visit '/sessions/new' within("#session") do fill_in 'Login', :with => 'user@example.com' fill_in 'Password', :with => 'password' end click_link 'Sign in' page.should have_content 'Success' end end ``` Use `:js => true` to switch to the `Capybara.javascript_driver` (`:selenium` by default), or provide a `:driver` option to switch to one specific driver. For example: ```ruby describe 'some stuff which requires js', :js => true do it 'will use the default js driver' it 'will switch to one specific driver', :driver => :webkit end ``` Finally, Capybara also comes with a built in DSL for creating descriptive acceptance tests: ```ruby feature "Signing up" do background do User.make(:email => 'user@example.com', :password => 'caplin') end scenario "Signing in with correct credentials" do visit '/sessions/new' within("#session") do fill_in 'Login', :with => 'user@example.com' fill_in 'Password', :with => 'caplin' end click_link 'Sign in' page.should have_content 'Success' end given(:other_user) { User.make(:email => 'other@example.com', :password => 'rous') } scenario "Signing in as another user" do visit '/sessions/new' within("#session") do fill_in 'Login', :with => other_user.email fill_in 'Password', :with => other_user.password end click_link 'Sign in' page.should have_content 'Invalid email or password' end end ``` `feature` is in fact just an alias for `describe ..., :type => :feature`, `background` is an alias for `before`, `scenario` for `it`, and `given`/`given!` aliases for `let`/`let!`, respectively. ## Using Capybara with Test::Unit * If you are using Rails, add the following code in your `test_helper.rb` file to make Capybara available in all test cases deriving from `ActionDispatch::IntegrationTest`: ```ruby class ActionDispatch::IntegrationTest # Make the Capybara DSL available in all integration tests include Capybara::DSL end ``` * If you are not using Rails, define a base class for your Capybara tests like so: ```ruby class CapybaraTestCase < Test::Unit::TestCase include Capybara::DSL def teardown Capybara.reset_sessions! Capybara.use_default_driver end end ``` Remember to call `super` in any subclasses that override `teardown`. To switch the driver, set `Capybara.current_driver`. For instance, ```ruby class BlogTest < ActionDispatch::IntegrationTest setup do Capybara.current_driver = Capybara.javascript_driver # :selenium by default end test 'shows blog posts' do # ... this test is run with Selenium ... end end ``` ## Using Capybara with MiniTest::Spec Set up your base class as with Test::Unit. (On Rails, the right base class could be something other than ActionDispatch::IntegrationTest.) The capybara_minitest_spec gem ([Github](https://github.com/ordinaryzelig/capybara_minitest_spec), [rubygems.org](https://rubygems.org/gems/capybara_minitest_spec)) provides MiniTest::Spec expectations for Capybara. For example: ```ruby page.must_have_content('Important!') ``` ## Drivers Capybara uses the same DSL to drive a variety of browser and headless drivers. ### Selecting the Driver By default, Capybara uses the `:rack_test` driver, which is fast but limited: it does not support JavaScript, nor is it able to access HTTP resources outside of your Rack application, such as remote APIs and OAuth services. To get around these limitations, you can set up a different default driver for your features. For example if you'd prefer to run everything in Selenium, you could do: ```ruby Capybara.default_driver = :selenium ``` However, if you are using RSpec or Cucumber, you may instead want to consider leaving the faster `:rack_test` as the __default_driver__, and marking only those tests that require a JavaScript-capable driver using `:js => true` or `@javascript`, respectively. By default, JavaScript tests are run using the `:selenium` driver. You can change this by setting `Capybara.javascript_driver`. You can also change the driver temporarily (typically in the Before/setup and After/teardown blocks): ```ruby Capybara.current_driver = :webkit # temporarily select different driver ... tests ... Capybara.use_default_driver # switch back to default driver ``` **Note**: switching the driver creates a new session, so you may not be able to switch in the middle of a test. ### RackTest RackTest is Capybara's default driver. It is written in pure Ruby and does not have any support for executing JavaScript. Since the RackTest driver interacts directly with Rack interfaces, it does not require a server to be started. However, this means that if your application is not a Rack application (Rails, Sinatra and most other Ruby frameworks are Rack applications) then you cannot use this driver. Furthermore, you cannot use the RackTest driver to test a remote application, or to access remote URLs (e.g., redirects to external sites, external APIs, or OAuth services) that your application might interact with. [capybara-mechanize](https://github.com/jeroenvandijk/capybara-mechanize) provides a similar driver that can access remote servers. RackTest can be configured with a set of headers like this: ```ruby Capybara.register_driver :rack_test do |app| Capybara::RackTest::Driver.new(app, :browser => :chrome) end ``` See the section on adding and configuring drivers. ### Selenium At the moment, Capybara supports [Selenium 2.0 (Webdriver)](http://seleniumhq.org/docs/01_introducing_selenium.html#selenium-2-aka-selenium-webdriver), *not* Selenium RC. Provided Firefox is installed, everything is set up for you, and you should be able to start using Selenium right away. **Note**: drivers which run the server in a different thread may not work share the same transaction as your tests, causing data not to be shared between your test and test server, see "Transactions and database setup" below. ### Capybara-webkit The [capybara-webkit driver](https://github.com/thoughtbot/capybara-webkit) is for true headless testing. It uses QtWebKit to start a rendering engine process. It can execute JavaScript as well. It is significantly faster than drivers like Selenium since it does not load an entire browser. You can install it with: ```bash gem install capybara-webkit ``` And you can use it by: ```ruby Capybara.javascript_driver = :webkit ``` ### Poltergeist [Poltergeist](https://github.com/jonleighton/poltergeist) is another headless driver which integrates Capybara with [PhantomJS](http://phantomjs.org/). It is truly headless, so doesn't require Xvfb to run on your CI server. It will also detect and report any Javascript errors that happen within the page. ## The DSL *A complete reference is available at [rubydoc.info](http://rubydoc.info/github/jnicklas/capybara/master)*. **Note**: All searches in Capybara are *case sensitive*. This is because Capybara heavily uses XPath, which doesn't support case insensitivity. ### Navigating You can use the [#visit](http://rubydoc.info/github/jnicklas/capybara/master/Capybara/Session#visit-instance_method) method to navigate to other pages: ```ruby visit('/projects') visit(post_comments_path(post)) ``` The visit method only takes a single parameter, the request method is **always** GET. You can get the [current path](http://rubydoc.info/github/jnicklas/capybara/master/Capybara/Session#current_path-instance_method) of the browsing session for test assertions: ```ruby current_path.should == post_comments_path(post) ``` ### Clicking links and buttons *Full reference: [Capybara::Node::Actions](http://rubydoc.info/github/jnicklas/capybara/master/Capybara/Node/Actions)* You can interact with the webapp by following links and buttons. Capybara automatically follows any redirects, and submits forms associated with buttons. ```ruby click_link('id-of-link') click_link('Link Text') click_button('Save') click_on('Link Text') # clicks on either links or buttons click_on('Button Value') ``` ### Interacting with forms *Full reference: [Capybara::Node::Actions](http://rubydoc.info/github/jnicklas/capybara/master/Capybara/Node/Actions)* There are a number of tools for interacting with form elements: ```ruby fill_in('First Name', :with => 'John') fill_in('Password', :with => 'Seekrit') fill_in('Description', :with => 'Really Long Text...') choose('A Radio Button') check('A Checkbox') uncheck('A Checkbox') attach_file('Image', '/path/to/image.jpg') select('Option', :from => 'Select Box') ``` ### Querying *Full reference: [Capybara::Node::Matchers](http://rubydoc.info/github/jnicklas/capybara/master/Capybara/Node/Matchers)* Capybara has a rich set of options for querying the page for the existence of certain elements, and working with and manipulating those elements. ```ruby page.has_selector?('table tr') page.has_selector?(:xpath, '//table/tr') page.has_xpath?('//table/tr') page.has_css?('table tr.foo') page.has_content?('foo') ``` **Note:** The negative forms like `has_no_selector?` are different from `not has_selector?`. Read the section on asynchronous JavaScript for an explanation. You can use these with RSpec's magic matchers: ```ruby page.should have_selector('table tr') page.should have_selector(:xpath, '//table/tr') page.should have_xpath('//table/tr') page.should have_css('table tr.foo') page.should have_content('foo') ``` ### Finding _Full reference: [Capybara::Node::Finders](http://rubydoc.info/github/jnicklas/capybara/master/Capybara/Node/Finders)_ You can also find specific elements, in order to manipulate them: ```ruby find_field('First Name').value find_link('Hello').visible? find_button('Send').click find(:xpath, "//table/tr").click find("#overlay").find("h1").click all('a').each { |a| a[:href] } ``` **Note**: `find` will wait for an element to appear on the page, as explained in the Ajax section. If the element does not appear it will raise an error. These elements all have all the Capybara DSL methods available, so you can restrict them to specific parts of the page: ```ruby find('#navigation').click_link('Home') find('#navigation').should have_button('Sign out') ``` ### Scoping Capybara makes it possible to restrict certain actions, such as interacting with forms or clicking links and buttons, to within a specific area of the page. For this purpose you can use the generic [within](http://rubydoc.info/github/jnicklas/capybara/master/Capybara/Session#within-instance_method) method. Optionally you can specify which kind of selector to use. ```ruby within("li#employee") do fill_in 'Name', :with => 'Jimmy' end within(:xpath, "//li[@id='employee']") do fill_in 'Name', :with => 'Jimmy' end ``` **Note**: `within` will scope the actions to the _first_ (not _any_) element that matches the selector. There are special methods for restricting the scope to a specific fieldset, identified by either an id or the text of the fieldset's legend tag, and to a specific table, identified by either id or text of the table's caption tag. ```ruby within_fieldset('Employee') do fill_in 'Name', :with => 'Jimmy' end within_table('Employee') do fill_in 'Name', :with => 'Jimmy' end ``` ### Scripting In drivers which support it, you can easily execute JavaScript: ```ruby page.execute_script("$('body').empty()") ``` For simple expressions, you can return the result of the script. Note that this may break with more complicated expressions: ```ruby result = page.evaluate_script('4 + 4'); ``` ### Debugging It can be useful to take a snapshot of the page as it currently is and take a look at it: ```ruby save_and_open_page ``` You can also retrieve the current state of the DOM as a string using [page.html](http://rubydoc.info/github/jnicklas/capybara/master/Capybara/Session#html-instance_method). ```ruby print page.html ``` This is mostly useful for debugging. You should avoid testing against the contents of `page.html` and use the more expressive finder methods instead. Finally, in drivers that support it, you can save a screenshot: ```ruby page.save_screenshot('screenshot.png') ``` ## Matching It is possible to customize how Capybara finds elements. At your disposal are two options, `Capybara.exact` and `Capybara.match`. ### Exactness `Capybara.exact` and the `exact` option work together with the `is` expression inside the XPath gem. When `exact` is true, all `is` expressions match exactly, when it is false, they allow substring matches. Many of the selectors built into Capybara use the `is` expression. This way you can specify whether you want to allow substring matches or not. `Capybara.exact` is false by default. For example: ```ruby click_link("Password") # also matches "Password confirmation" Capybara.exact = true click_link("Password") # does not match "Password confirmation" click_link("Password", exact: false) # can be overridden ``` ### Strategy Using `Capybara.match` and the equivalent `match` option, you can control how Capybara behaves when multiple elements all match a query. There are currently four different strategies built into Capybara: 1. **first:** Just picks the first element that matches. 2. **one:** Raises an error if more than one element matches. 3. **smart:** If `exact` is `true`, raises an error if more than one element matches, just like `one`. If `exact` is `false`, it will first try to find an exact match. An error is raised if more than one element is found. If no element is found, a new search is performed which allows partial matches. If that search returns multiple matches, an error is raised. 4. **prefer_exact:** If multiple matches are found, some of which are exact, and some of which are not, then the first exactly matching element is returned. The default for `Capybara.match` is `:smart`. To emulate the behaviour in Capybara 2.0.x, set `Capybara.match` to `:one`. To emulate the behaviour in Capybara 1.x, set `Capybara.match` to `:prefer_exact`. ## Transactions and database setup Some Capybara drivers need to run against an actual HTTP server. Capybara takes care of this and starts one for you in the same process as your test, but on another thread. Selenium is one of those drivers, whereas RackTest is not. If you are using a SQL database, it is common to run every test in a transaction, which is rolled back at the end of the test, rspec-rails does this by default out of the box for example. Since transactions are usually not shared across threads, this will cause data you have put into the database in your test code to be invisible to Capybara. Cucumber handles this by using truncation instead of transactions, i.e. they empty out the entire database after each test. You can get the same behaviour by using a gem such as [database_cleaner](https://github.com/bmabey/database_cleaner). It is also possible to force your ORM to use the same transaction for all threads. This may have thread safety implications and could cause strange failures, so use caution with this approach. It can be implemented in ActiveRecord through the following monkey patch: ```ruby class ActiveRecord::Base mattr_accessor :shared_connection @@shared_connection = nil def self.connection @@shared_connection || retrieve_connection end end ActiveRecord::Base.shared_connection = ActiveRecord::Base.connection ``` ## Asynchronous JavaScript (Ajax and friends) When working with asynchronous JavaScript, you might come across situations where you are attempting to interact with an element which is not yet present on the page. Capybara automatically deals with this by waiting for elements to appear on the page. When issuing instructions to the DSL such as: ```ruby click_link('foo') click_link('bar') page.should have_content('baz') ``` If clicking on the *foo* link triggers an asynchronous process, such as an Ajax request, which, when complete will add the *bar* link to the page, clicking on the *bar* link would be expected to fail, since that link doesn't exist yet. However Capybara is smart enough to retry finding the link for a brief period of time before giving up and throwing an error. The same is true of the next line, which looks for the content *baz* on the page; it will retry looking for that content for a brief time. You can adjust how long this period is (the default is 2 seconds): ```ruby Capybara.default_wait_time = 5 ``` Be aware that because of this behaviour, the following two statements are **not** equivalent, and you should **always** use the latter! ```ruby !page.has_xpath?('a') page.has_no_xpath?('a') ``` The former would immediately fail because the content has not yet been removed. Only the latter would wait for the asynchronous process to remove the content from the page. Capybara's Rspec matchers, however, are smart enough to handle either form. The two following statements are functionally equivalent: ```ruby page.should_not have_xpath('a') page.should have_no_xpath('a') ``` Capybara's waiting behaviour is quite advanced, and can deal with situations such as the following line of code: ```ruby find('#sidebar').find('h1').should have_content('Something') ``` Even if JavaScript causes `#sidebar` to disappear off the page, Capybara will automatically reload it and any elements it contains. So if an AJAX request causes the contents of `#sidebar` to change, which would update the text of the `h1` to "Something", and this happened, this test would pass. If you do not want this behaviour, you can set `Capybara.automatic_reload` to `false`. ## Using the DSL elsewhere You can mix the DSL into any context by including Capybara::DSL: ```ruby require 'capybara' require 'capybara/dsl' Capybara.default_driver = :webkit module MyModule include Capybara::DSL def login! within("//form[@id='session']") do fill_in 'Login', :with => 'user@example.com' fill_in 'Password', :with => 'password' end click_link 'Sign in' end end ``` This enables its use in unsupported testing frameworks, and for general-purpose scripting. ## Calling remote servers Normally Capybara expects to be testing an in-process Rack application, but you can also use it to talk to a web server running anywhere on the internet, by setting app_host: ```ruby Capybara.current_driver = :selenium Capybara.app_host = 'http://www.google.com' ... visit('/') ``` **Note**: the default driver (`:rack_test`) does not support running against a remote server. With drivers that support it, you can also visit any URL directly: ```ruby visit('http://www.google.com') ``` By default Capybara will try to boot a rack application automatically. You might want to switch off Capybara's rack server if you are running against a remote application: ```ruby Capybara.run_server = false ``` ## Using the sessions manually For ultimate control, you can instantiate and use a [Session](http://rubydoc.info/github/jnicklas/capybara/master/Capybara/Session) manually. ```ruby require 'capybara' session = Capybara::Session.new(:webkit, my_rack_app) session.within("//form[@id='session']") do session.fill_in 'Login', :with => 'user@example.com' session.fill_in 'Password', :with => 'password' end session.click_link 'Sign in' ``` ## XPath, CSS and selectors Capybara does not try to guess what kind of selector you are going to give it, and will always use CSS by default. If you want to use XPath, you'll need to do: ```ruby within(:xpath, '//ul/li') { ... } find(:xpath, '//ul/li').text find(:xpath, '//li[contains(.//a[@href = "#"]/text(), "foo")]').value ``` Alternatively you can set the default selector to XPath: ```ruby Capybara.default_selector = :xpath find('//ul/li').text ``` Capybara allows you to add custom selectors, which can be very useful if you find yourself using the same kinds of selectors very often: ```ruby Capybara.add_selector(:id) do xpath { |id| XPath.descendant[XPath.attr(:id) == id.to_s] } end Capybara.add_selector(:row) do xpath { |num| ".//tbody/tr[#{num}]" } end Capybara.add_selector(:flash_type) do css { |type| "#flash.#{type}" } end ``` The block given to xpath must always return an XPath expression as a String, or an XPath expression generated through the XPath gem. You can now use these selectors like this: ```ruby find(:id, 'post_123') find(:row, 3) find(:flash_type, :notice) ``` ## Beware the XPath // trap In XPath the expression // means something very specific, and it might not be what you think. Contrary to common belief, // means "anywhere in the document" not "anywhere in the current context". As an example: ```ruby page.find(:xpath, '//body').all(:xpath, '//script') ``` You might expect this to find all script tags in the body, but actually, it finds all script tags in the entire document, not only those in the body! What you're looking for is the .// expression which means "any descendant of the current node": ```ruby page.find(:xpath, '//body').all(:xpath, './/script') ``` The same thing goes for within: ```ruby within(:xpath, '//body') do page.find(:xpath, './/script') within(:xpath, './/table/tbody') do ... end end ``` ## Configuring and adding drivers Capybara makes it convenient to switch between different drivers. It also exposes an API to tweak those drivers with whatever settings you want, or to add your own drivers. This is how to switch the selenium driver to use chrome: ```ruby Capybara.register_driver :selenium do |app| Capybara::Selenium::Driver.new(app, :browser => :chrome) end ``` However, it's also possible to give this a different name, so tests can switch between using different browsers effortlessly: ```ruby Capybara.register_driver :selenium_chrome do |app| Capybara::Selenium::Driver.new(app, :browser => :chrome) end ``` Whatever is returned from the block should conform to the API described by Capybara::Driver::Base, it does not however have to inherit from this class. Gems can use this API to add their own drivers to Capybara. The [Selenium wiki](http://code.google.com/p/selenium/wiki/RubyBindings) has additional info about how the underlying driver can be configured. ## Gotchas: * Access to session and request is not possible from the test, Access to response is limited. Some drivers allow access to response headers and HTTP status code, but this kind of functionality is not provided by some drivers, such as Selenium. * Access to Rails specific stuff (such as `controller`) is unavailable, since we're not using Rails' integration testing. * Freezing time: It's common practice to mock out the Time so that features that depend on the current Date work as expected. This can be problematic, since Capybara's Ajax timing uses the system time, resulting in Capybara never timing out and just hanging when a failure occurs. It's still possible to use gems which allow you to travel in time, rather than freeze time. One such gem is [Timecop](http://github.com/travisjeffery/timecop). * When using Rack::Test, beware if attempting to visit absolute URLs. For example, a session might not be shared between visits to `posts_path` and `posts_url`. If testing an absolute URL in an Action Mailer email, set `default_url_options` to match the Rails default of `www.example.com`. ## Development To set up a development environment, simply do: ```bash bundle install bundle exec rake # run the test suite ``` See [CONTRIBUTING.md](https://github.com/jnicklas/capybara/blob/master/CONTRIBUTING.md) for how to send issues and pull requests. capybara-2.1.0/data.tar.gz.sig0000644000175000017500000000040012140721202015122 0ustar lunarlunar`Z6xׄ9K"B9"2oȩ3fmEchJIBc^kLdoY%Y)#WoMnJ-jm>3U5 T \BUh ̐V 0r~:y_ԥT2c3^{~XfaF2DhI$`#<챎ԽH=' - !ruby/object:Gem::Version version: 1.3.3 type: :runtime prerelease: false version_requirements: !ruby/object:Gem::Requirement none: false requirements: - - ! '>=' - !ruby/object:Gem::Version version: 1.3.3 - !ruby/object:Gem::Dependency name: mime-types requirement: !ruby/object:Gem::Requirement none: false requirements: - - ! '>=' - !ruby/object:Gem::Version version: '1.16' type: :runtime prerelease: false version_requirements: !ruby/object:Gem::Requirement none: false requirements: - - ! '>=' - !ruby/object:Gem::Version version: '1.16' - !ruby/object:Gem::Dependency name: rack requirement: !ruby/object:Gem::Requirement none: false requirements: - - ! '>=' - !ruby/object:Gem::Version version: 1.0.0 type: :runtime prerelease: false version_requirements: !ruby/object:Gem::Requirement none: false requirements: - - ! '>=' - !ruby/object:Gem::Version version: 1.0.0 - !ruby/object:Gem::Dependency name: rack-test requirement: !ruby/object:Gem::Requirement none: false requirements: - - ! '>=' - !ruby/object:Gem::Version version: 0.5.4 type: :runtime prerelease: false version_requirements: !ruby/object:Gem::Requirement none: false requirements: - - ! '>=' - !ruby/object:Gem::Version version: 0.5.4 - !ruby/object:Gem::Dependency name: xpath requirement: !ruby/object:Gem::Requirement none: false requirements: - - ~> - !ruby/object:Gem::Version version: '2.0' type: :runtime prerelease: false version_requirements: !ruby/object:Gem::Requirement none: false requirements: - - ~> - !ruby/object:Gem::Version version: '2.0' - !ruby/object:Gem::Dependency name: selenium-webdriver requirement: !ruby/object:Gem::Requirement none: false requirements: - - ~> - !ruby/object:Gem::Version version: '2.0' type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement none: false requirements: - - ~> - !ruby/object:Gem::Version version: '2.0' - !ruby/object:Gem::Dependency name: sinatra requirement: !ruby/object:Gem::Requirement none: false requirements: - - ! '>=' - !ruby/object:Gem::Version version: 0.9.4 type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement none: false requirements: - - ! '>=' - !ruby/object:Gem::Version version: 0.9.4 - !ruby/object:Gem::Dependency name: rspec requirement: !ruby/object:Gem::Requirement none: false requirements: - - ! '>=' - !ruby/object:Gem::Version version: 2.2.0 type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement none: false requirements: - - ! '>=' - !ruby/object:Gem::Version version: 2.2.0 - !ruby/object:Gem::Dependency name: launchy requirement: !ruby/object:Gem::Requirement none: false requirements: - - ! '>=' - !ruby/object:Gem::Version version: 2.0.4 type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement none: false requirements: - - ! '>=' - !ruby/object:Gem::Version version: 2.0.4 - !ruby/object:Gem::Dependency name: yard requirement: !ruby/object:Gem::Requirement none: false requirements: - - ! '>=' - !ruby/object:Gem::Version version: 0.5.8 type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement none: false requirements: - - ! '>=' - !ruby/object:Gem::Version version: 0.5.8 - !ruby/object:Gem::Dependency name: fuubar requirement: !ruby/object:Gem::Requirement none: false requirements: - - ! '>=' - !ruby/object:Gem::Version version: 0.0.1 type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement none: false requirements: - - ! '>=' - !ruby/object:Gem::Version version: 0.0.1 - !ruby/object:Gem::Dependency name: cucumber requirement: !ruby/object:Gem::Requirement none: false requirements: - - ! '>=' - !ruby/object:Gem::Version version: 0.10.5 type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement none: false requirements: - - ! '>=' - !ruby/object:Gem::Version version: 0.10.5 - !ruby/object:Gem::Dependency name: rake requirement: !ruby/object:Gem::Requirement none: false requirements: - - ! '>=' - !ruby/object:Gem::Version version: '0' type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement none: false requirements: - - ! '>=' - !ruby/object:Gem::Version version: '0' - !ruby/object:Gem::Dependency name: pry requirement: !ruby/object:Gem::Requirement none: false requirements: - - ! '>=' - !ruby/object:Gem::Version version: '0' type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement none: false requirements: - - ! '>=' - !ruby/object:Gem::Version version: '0' description: Capybara is an integration testing tool for rack based web applications. It simulates how a user would interact with a website email: - jonas.nicklas@gmail.com executables: [] extensions: [] extra_rdoc_files: [] files: - lib/capybara/cucumber.rb - lib/capybara/driver/base.rb - lib/capybara/driver/node.rb - lib/capybara/dsl.rb - lib/capybara/helpers.rb - lib/capybara/node/actions.rb - lib/capybara/node/base.rb - lib/capybara/node/document.rb - lib/capybara/node/element.rb - lib/capybara/node/finders.rb - lib/capybara/node/matchers.rb - lib/capybara/node/simple.rb - lib/capybara/query.rb - lib/capybara/rack_test/browser.rb - lib/capybara/rack_test/css_handlers.rb - lib/capybara/rack_test/driver.rb - lib/capybara/rack_test/form.rb - lib/capybara/rack_test/node.rb - lib/capybara/rails.rb - lib/capybara/result.rb - lib/capybara/rspec/features.rb - lib/capybara/rspec/matchers.rb - lib/capybara/rspec.rb - lib/capybara/selector.rb - lib/capybara/selenium/driver.rb - lib/capybara/selenium/node.rb - lib/capybara/server.rb - lib/capybara/session.rb - lib/capybara/spec/fixtures/another_test_file.txt - lib/capybara/spec/fixtures/capybara.jpg - lib/capybara/spec/fixtures/test_file.txt - lib/capybara/spec/public/jquery-ui.js - lib/capybara/spec/public/jquery.js - lib/capybara/spec/public/test.js - lib/capybara/spec/session/all_spec.rb - lib/capybara/spec/session/assert_selector.rb - lib/capybara/spec/session/attach_file_spec.rb - lib/capybara/spec/session/body_spec.rb - lib/capybara/spec/session/check_spec.rb - lib/capybara/spec/session/choose_spec.rb - lib/capybara/spec/session/click_button_spec.rb - lib/capybara/spec/session/click_link_or_button_spec.rb - lib/capybara/spec/session/click_link_spec.rb - lib/capybara/spec/session/current_scope_spec.rb - lib/capybara/spec/session/current_url_spec.rb - lib/capybara/spec/session/evaluate_script_spec.rb - lib/capybara/spec/session/execute_script_spec.rb - lib/capybara/spec/session/fill_in_spec.rb - lib/capybara/spec/session/find_button_spec.rb - lib/capybara/spec/session/find_by_id_spec.rb - lib/capybara/spec/session/find_field_spec.rb - lib/capybara/spec/session/find_link_spec.rb - lib/capybara/spec/session/find_spec.rb - lib/capybara/spec/session/first_spec.rb - lib/capybara/spec/session/has_button_spec.rb - lib/capybara/spec/session/has_css_spec.rb - lib/capybara/spec/session/has_field_spec.rb - lib/capybara/spec/session/has_link_spec.rb - lib/capybara/spec/session/has_select_spec.rb - lib/capybara/spec/session/has_selector_spec.rb - lib/capybara/spec/session/has_table_spec.rb - lib/capybara/spec/session/has_text_spec.rb - lib/capybara/spec/session/has_title_spec.rb - lib/capybara/spec/session/has_xpath_spec.rb - lib/capybara/spec/session/headers.rb - lib/capybara/spec/session/html_spec.rb - lib/capybara/spec/session/node_spec.rb - lib/capybara/spec/session/reset_session_spec.rb - lib/capybara/spec/session/response_code.rb - lib/capybara/spec/session/save_page_spec.rb - lib/capybara/spec/session/screenshot.rb - lib/capybara/spec/session/select_spec.rb - lib/capybara/spec/session/source_spec.rb - lib/capybara/spec/session/text_spec.rb - lib/capybara/spec/session/title_spec.rb - lib/capybara/spec/session/uncheck_spec.rb - lib/capybara/spec/session/unselect_spec.rb - lib/capybara/spec/session/visit_spec.rb - lib/capybara/spec/session/within_frame_spec.rb - lib/capybara/spec/session/within_spec.rb - lib/capybara/spec/session/within_window_spec.rb - lib/capybara/spec/spec_helper.rb - lib/capybara/spec/test_app.rb - lib/capybara/spec/views/buttons.erb - lib/capybara/spec/views/fieldsets.erb - lib/capybara/spec/views/form.erb - lib/capybara/spec/views/frame_child.erb - lib/capybara/spec/views/frame_one.erb - lib/capybara/spec/views/frame_parent.erb - lib/capybara/spec/views/frame_two.erb - lib/capybara/spec/views/header_links.erb - lib/capybara/spec/views/host_links.erb - lib/capybara/spec/views/popup_one.erb - lib/capybara/spec/views/popup_two.erb - lib/capybara/spec/views/postback.erb - lib/capybara/spec/views/tables.erb - lib/capybara/spec/views/with_base_tag.erb - lib/capybara/spec/views/with_count.erb - lib/capybara/spec/views/with_hover.erb - lib/capybara/spec/views/with_html.erb - lib/capybara/spec/views/with_html_entities.erb - lib/capybara/spec/views/with_js.erb - lib/capybara/spec/views/with_scope.erb - lib/capybara/spec/views/with_simple_html.erb - lib/capybara/spec/views/with_title.erb - lib/capybara/spec/views/within_frames.erb - lib/capybara/spec/views/within_popups.erb - lib/capybara/version.rb - lib/capybara.rb - spec/basic_node_spec.rb - spec/capybara_spec.rb - spec/dsl_spec.rb - spec/fixtures/selenium_driver_rspec_failure.rb - spec/fixtures/selenium_driver_rspec_success.rb - spec/rack_test_spec.rb - spec/result_spec.rb - spec/rspec/features_spec.rb - spec/rspec/matchers_spec.rb - spec/rspec_spec.rb - spec/selenium_spec.rb - spec/server_spec.rb - spec/spec_helper.rb - README.md - History.md - License.txt homepage: http://github.com/jnicklas/capybara licenses: [] post_install_message: ! "IMPORTANT! Some of the defaults have changed in Capybara 2.1. If you're experiencing failures,\nplease revert to the old behaviour by setting:\n\n \ Capybara.configure do |config|\n config.match = :one\n config.exact_options = true\n config.ignore_hidden_elements = true\n config.visible_text_only = true\n end\n\nIf you're migrating from Capybara 1.x, try:\n\n Capybara.configure do |config|\n config.match = :prefer_exact\n config.ignore_hidden_elements = false\n end\n\nDetails here: http://www.elabs.se/blog/60-introducing-capybara-2-1\n\n" rdoc_options: [] require_paths: - lib required_ruby_version: !ruby/object:Gem::Requirement none: false requirements: - - ! '>=' - !ruby/object:Gem::Version version: 1.9.3 required_rubygems_version: !ruby/object:Gem::Requirement none: false requirements: - - ! '>=' - !ruby/object:Gem::Version version: '0' requirements: [] rubyforge_project: capybara rubygems_version: 1.8.25 signing_key: specification_version: 3 summary: Capybara aims to simplify the process of integration testing Rack applications, such as Rails, Sinatra or Merb test_files: [] has_rdoc: capybara-2.1.0/lib/0000755000175000017500000000000012140721202013055 5ustar lunarlunarcapybara-2.1.0/lib/capybara.rb0000644000175000017500000002505612140721202015174 0ustar lunarlunarrequire 'timeout' require 'nokogiri' require 'xpath' module Capybara class CapybaraError < StandardError; end class DriverNotFoundError < CapybaraError; end class FrozenInTime < CapybaraError; end class ElementNotFound < CapybaraError; end class Ambiguous < ElementNotFound; end class ExpectationNotMet < ElementNotFound; end class FileNotFound < CapybaraError; end class UnselectNotAllowed < CapybaraError; end class NotSupportedByDriverError < CapybaraError; end class InfiniteRedirectError < CapybaraError; end class << self attr_accessor :asset_host, :app_host, :run_server, :default_host, :always_include_port attr_accessor :server_host, :server_port, :exact, :match, :exact_options, :visible_text_only attr_accessor :default_selector, :default_wait_time, :ignore_hidden_elements attr_accessor :save_and_open_page_path, :automatic_reload, :raise_server_errors attr_writer :default_driver, :current_driver, :javascript_driver, :session_name attr_accessor :app ## # # Configure Capybara to suit your needs. # # Capybara.configure do |config| # config.run_server = false # config.app_host = 'http://www.google.com' # end # # === Configurable options # # [app_host = String] The default host to use when giving a relative URL to visit # [always_include_port = Boolean] Whether the Rack server's port should automatically be inserted into every visited URL (Default: false) # [asset_host = String] Where dynamic assets are hosted - will be prepended to relative asset locations if present (Default: nil) # [run_server = Boolean] Whether to start a Rack server for the given Rack app (Default: true) # [default_selector = :css/:xpath] Methods which take a selector use the given type by default (Default: CSS) # [default_wait_time = Integer] The number of seconds to wait for asynchronous processes to finish (Default: 2) # [ignore_hidden_elements = Boolean] Whether to ignore hidden elements on the page (Default: false) # [automatic_reload = Boolean] Whether to automatically reload elements as Capybara is waiting (Default: true) # [save_and_open_page_path = String] Where to put pages saved through save_and_open_page (Default: Dir.pwd) # # === DSL Options # # when using capybara/dsl, the following options are also available: # # [default_driver = Symbol] The name of the driver to use by default. (Default: :rack_test) # [javascript_driver = Symbol] The name of a driver to use for JavaScript enabled tests. (Default: :selenium) # def configure yield self end ## # # Register a new driver for Capybara. # # Capybara.register_driver :rack_test do |app| # Capybara::Driver::RackTest.new(app) # end # # @param [Symbol] name The name of the new driver # @yield [app] This block takes a rack app and returns a Capybara driver # @yieldparam [] app The rack application that this driver runs agains. May be nil. # @yieldreturn [Capybara::Driver::Base] A Capybara driver instance # def register_driver(name, &block) drivers[name] = block end ## # # Add a new selector to Capybara. Selectors can be used by various methods in Capybara # to find certain elements on the page in a more convenient way. For example adding a # selector to find certain table rows might look like this: # # Capybara.add_selector(:row) do # xpath { |num| ".//tbody/tr[#{num}]" } # end # # This makes it possible to use this selector in a variety of ways: # # find(:row, 3) # page.find('table#myTable').find(:row, 3).text # page.find('table#myTable').has_selector?(:row, 3) # within(:row, 3) { page.should have_content('$100.000') } # # Here is another example: # # Capybara.add_selector(:id) do # xpath { |id| XPath.descendant[XPath.attr(:id) == id.to_s] } # end # # Note that this particular selector already ships with Capybara. # # @param [Symbol] name The name of the selector to add # @yield A block executed in the context of the new {Capybara::Selector} # def add_selector(name, &block) Capybara::Selector.add(name, &block) end def drivers @drivers ||= {} end ## # # Register a proc that Capybara will call to run the Rack application. # # Capybara.server do |app, port| # require 'rack/handler/mongrel' # Rack::Handler::Mongrel.run(app, :Port => port) # end # # By default, Capybara will try to run webrick. # # @yield [app, port] This block recieves a rack app and port and should run a Rack handler # def server(&block) if block_given? @server = block else @server end end ## # # Wraps the given string, which should contain an HTML document or fragment # in a {Capybara::Node::Simple} which exposes all {Capybara::Node::Matchers} and # {Capybara::Node::Finders}. This allows you to query any string containing # HTML in the exact same way you would query the current document in a Capybara # session. For example: # # node = Capybara.string <<-HTML # # HTML # # node.find('#projects').text # => 'Projects' # node.has_selector?('li#home', :text => 'Home') # node.has_selector?(:projects) # node.find('ul').find('li').text # => 'Home' # # @param [String] html An html fragment or document # @return [Capybara::Node::Simple] A node which has Capybara's finders and matchers # def string(html) Capybara::Node::Simple.new(html) end ## # # Runs Capybara's default server for the given application and port # under most circumstances you should not have to call this method # manually. # # @param [Rack Application] app The rack application to run # @param [Fixnum] port The port to run the application on # def run_default_server(app, port) require 'rack/handler/webrick' Rack::Handler::WEBrick.run(app, :Port => port, :AccessLog => [], :Logger => WEBrick::Log::new(nil, 0)) end ## # # @return [Symbol] The name of the driver to use by default # def default_driver @default_driver || :rack_test end ## # # @return [Symbol] The name of the driver currently in use # def current_driver @current_driver || default_driver end alias_method :mode, :current_driver ## # # @return [Symbol] The name of the driver used when JavaScript is needed # def javascript_driver @javascript_driver || :selenium end ## # # Use the default driver as the current driver # def use_default_driver @current_driver = nil end ## # # Yield a block using a specific driver # def using_driver(driver) previous_driver = Capybara.current_driver Capybara.current_driver = driver yield ensure @current_driver = previous_driver end ## # # Yield a block using a specific wait time # def using_wait_time(seconds) previous_wait_time = Capybara.default_wait_time Capybara.default_wait_time = seconds yield ensure Capybara.default_wait_time = previous_wait_time end ## # # The current Capybara::Session based on what is set as Capybara.app and Capybara.current_driver # # @return [Capybara::Session] The currently used session # def current_session session_pool["#{current_driver}:#{session_name}:#{app.object_id}"] ||= Capybara::Session.new(current_driver, app) end ## # # Reset sessions, cleaning out the pool of sessions. This will remove any session information such # as cookies. # def reset_sessions! session_pool.each { |mode, session| session.reset! } end alias_method :reset!, :reset_sessions! ## # # The current session name. # # @return [Symbol] The name of the currently used session. # def session_name @session_name ||= :default end ## # # Yield a block using a specific session name. # def using_session(name) self.session_name = name yield ensure self.session_name = :default end def included(base) base.send(:include, Capybara::DSL) warn "`include Capybara` is deprecated. Please use `include Capybara::DSL` instead." end def deprecate(method, alternate_method) warn "DEPRECATED: ##{method} is deprecated, please use ##{alternate_method} instead" end private def session_pool @session_pool ||= {} end end self.default_driver = nil self.current_driver = nil module Driver; end module RackTest; end module Selenium; end require 'capybara/helpers' require 'capybara/session' require 'capybara/dsl' require 'capybara/server' require 'capybara/selector' require 'capybara/query' require 'capybara/result' require 'capybara/version' require 'capybara/node/finders' require 'capybara/node/matchers' require 'capybara/node/actions' require 'capybara/node/simple' require 'capybara/node/base' require 'capybara/node/element' require 'capybara/node/document' require 'capybara/driver/base' require 'capybara/driver/node' require 'capybara/rack_test/driver' require 'capybara/rack_test/node' require 'capybara/rack_test/form' require 'capybara/rack_test/browser' require 'capybara/rack_test/css_handlers.rb' require 'capybara/selenium/node' require 'capybara/selenium/driver' end Capybara.configure do |config| config.always_include_port = false config.run_server = true config.server {|app, port| Capybara.run_default_server(app, port)} config.default_selector = :css config.default_wait_time = 2 config.ignore_hidden_elements = true config.default_host = "http://www.example.com" config.automatic_reload = true config.match = :smart config.exact = false config.raise_server_errors = true config.visible_text_only = false end Capybara.register_driver :rack_test do |app| Capybara::RackTest::Driver.new(app) end Capybara.register_driver :selenium do |app| Capybara::Selenium::Driver.new(app) end capybara-2.1.0/lib/capybara/0000755000175000017500000000000012140721202014637 5ustar lunarlunarcapybara-2.1.0/lib/capybara/selenium/0000755000175000017500000000000012140721202016460 5ustar lunarlunarcapybara-2.1.0/lib/capybara/selenium/driver.rb0000644000175000017500000001040512140721202020300 0ustar lunarlunarclass Capybara::Selenium::Driver < Capybara::Driver::Base DEFAULT_OPTIONS = { :browser => :firefox } SPECIAL_OPTIONS = [:browser] attr_reader :app, :options def browser unless @browser @browser = Selenium::WebDriver.for(options[:browser], options.reject { |key,val| SPECIAL_OPTIONS.include?(key) }) main = Process.pid at_exit do # Store the exit status of the test run since it goes away after calling the at_exit proc... @exit_status = $!.status if $!.is_a?(SystemExit) quit if Process.pid == main exit @exit_status if @exit_status # Force exit with stored status end end @browser end def initialize(app, options={}) begin require 'selenium-webdriver' rescue LoadError => e if e.message =~ /selenium-webdriver/ raise LoadError, "Capybara's selenium driver is unable to load `selenium-webdriver`, please install the gem and add `gem 'selenium-webdriver'` to your Gemfile if you are using bundler." else raise e end end @app = app @browser = nil @exit_status = nil @frame_handles = {} @options = DEFAULT_OPTIONS.merge(options) end def visit(path) browser.navigate.to(path) end def html browser.page_source end def title browser.title end def current_url browser.current_url end def find_xpath(selector) browser.find_elements(:xpath, selector).map { |node| Capybara::Selenium::Node.new(self, node) } end def find_css(selector) browser.find_elements(:css, selector).map { |node| Capybara::Selenium::Node.new(self, node) } end def wait?; true; end def needs_server?; true; end def execute_script(script) browser.execute_script script end def evaluate_script(script) browser.execute_script "return #{script}" end def save_screenshot(path, options={}) browser.save_screenshot(path) end def reset! # Use instance variable directly so we avoid starting the browser just to reset the session if @browser begin @browser.manage.delete_all_cookies rescue Selenium::WebDriver::Error::UnhandledError # delete_all_cookies fails when we've previously gone # to about:blank, so we rescue this error and do nothing # instead. end @browser.navigate.to('about:blank') end end ## # # Webdriver supports frame name, id, index(zero-based) or {Capybara::Element} to find iframe # # @overload within_frame(index) # @param [Integer] index index of a frame # @overload within_frame(name_or_id) # @param [String] name_or_id name or id of a frame # @overload within_frame(element) # @param [Capybara::Node::Base] a_node frame element # def within_frame(frame_handle) @frame_handles[browser.window_handle] ||= [] frame_handle = frame_handle.native if frame_handle.is_a?(Capybara::Node::Base) @frame_handles[browser.window_handle] << frame_handle a=browser.switch_to.frame(frame_handle) yield ensure # There doesnt appear to be any way in Webdriver to move back to a parent frame # other than going back to the root and then reiterating down @frame_handles[browser.window_handle].pop browser.switch_to.default_content @frame_handles[browser.window_handle].each { |fh| browser.switch_to.frame(fh) } end def find_window( selector ) original_handle = browser.window_handle browser.window_handles.each do |handle| browser.switch_to.window handle if( selector == browser.execute_script("return window.name") || browser.title.include?(selector) || browser.current_url.include?(selector) || (selector == handle) ) browser.switch_to.window original_handle return handle end end raise Capybara::ElementNotFound, "Could not find a window identified by #{selector}" end def within_window(selector, &blk) handle = find_window( selector ) browser.switch_to.window(handle, &blk) end def quit @browser.quit rescue Errno::ECONNREFUSED # Browser must have already gone end def invalid_element_errors [Selenium::WebDriver::Error::StaleElementReferenceError, Selenium::WebDriver::Error::UnhandledError, Selenium::WebDriver::Error::ElementNotVisibleError] end end capybara-2.1.0/lib/capybara/selenium/node.rb0000644000175000017500000000536112140721202017737 0ustar lunarlunarclass Capybara::Selenium::Node < Capybara::Driver::Node def visible_text # Selenium doesn't normalize Unicode whitespace. Capybara::Helpers.normalize_whitespace(native.text) end def all_text text = driver.browser.execute_script("return arguments[0].textContent", native) Capybara::Helpers.normalize_whitespace(text) end def [](name) native.attribute(name.to_s) rescue Selenium::WebDriver::Error::WebDriverError nil end def value if tag_name == "select" and self[:multiple] and not self[:multiple] == "false" native.find_elements(:xpath, ".//option").select { |n| n.selected? }.map { |n| n[:value] || n.text } else native[:value] end end def set(value) tag_name = self.tag_name type = self[:type] if (Array === value) && !self[:multiple] raise ArgumentError.new "Value cannot be an Array when 'multiple' attribute is not present. Not a #{value.class}" end if tag_name == 'input' and type == 'radio' click elsif tag_name == 'input' and type == 'checkbox' click if value ^ native.attribute('checked').to_s.eql?("true") elsif tag_name == 'input' and type == 'file' path_names = value.to_s.empty? ? [] : value native.send_keys(*path_names) elsif tag_name == 'textarea' or tag_name == 'input' #script can change a readonly element which user input cannot, so dont execute if readonly driver.browser.execute_script "arguments[0].value = ''", native unless self[:readonly] native.send_keys(value.to_s) end end def select_option native.click unless selected? end def unselect_option if select_node['multiple'] != 'multiple' and select_node['multiple'] != 'true' raise Capybara::UnselectNotAllowed, "Cannot unselect option from single select box." end native.click if selected? end def click native.click end def hover driver.browser.action.move_to(native).perform end def drag_to(element) driver.browser.action.drag_and_drop(native, element.native).perform end def tag_name native.tag_name.downcase end def visible? displayed = native.displayed? displayed and displayed != "false" end def selected? selected = native.selected? selected and selected != "false" end def disabled? !native.enabled? end alias :checked? :selected? def find_xpath(locator) native.find_elements(:xpath, locator).map { |n| self.class.new(driver, n) } end def find_css(locator) native.find_elements(:css, locator).map { |n| self.class.new(driver, n) } end def ==(other) native == other.native end private # a reference to the select node if this is an option node def select_node find_xpath('./ancestor::select').first end end capybara-2.1.0/lib/capybara/rails.rb0000644000175000017500000000106012140721202016273 0ustar lunarlunarrequire 'capybara' require 'capybara/dsl' Capybara.app = Rack::Builder.new do map "/" do if Gem::Version.new(Rails.version) >= Gem::Version.new("3.0") run Rails.application else # Rails 2 use Rails::Rack::Static run ActionController::Dispatcher.new end end end.to_app Capybara.save_and_open_page_path = Rails.root.join('tmp/capybara') # Override default rack_test driver to respect data-method attributes. Capybara.register_driver :rack_test do |app| Capybara::RackTest::Driver.new(app, :respect_data_method => true) end capybara-2.1.0/lib/capybara/version.rb0000644000175000017500000000005012140721202016644 0ustar lunarlunarmodule Capybara VERSION = '2.1.0' end capybara-2.1.0/lib/capybara/cucumber.rb0000644000175000017500000000100312140721202016763 0ustar lunarlunarrequire 'capybara' require 'capybara/dsl' require 'capybara/rspec/matchers' World(Capybara::DSL) World(Capybara::RSpecMatchers) After do Capybara.reset_sessions! end Before do Capybara.use_default_driver end Before '@javascript' do Capybara.current_driver = Capybara.javascript_driver end Before do |scenario| scenario.source_tag_names.each do |tag| driver_name = tag.sub(/^@/, '').to_sym if Capybara.drivers.has_key?(driver_name) Capybara.current_driver = driver_name end end end capybara-2.1.0/lib/capybara/driver/0000755000175000017500000000000012140721202016132 5ustar lunarlunarcapybara-2.1.0/lib/capybara/driver/base.rb0000644000175000017500000000242212140721202017371 0ustar lunarlunarclass Capybara::Driver::Base def current_url raise NotImplementedError end def visit(path) raise NotImplementedError end def find_xpath(query) raise NotImplementedError end def find_css(query) raise NotImplementedError end def html raise NotImplementedError end def execute_script(script) raise Capybara::NotSupportedByDriverError, 'Capybara::Driver::Base#execute_script' end def evaluate_script(script) raise Capybara::NotSupportedByDriverError, 'Capybara::Driver::Base#evaluate_script' end def save_screenshot(path, options={}) raise Capybara::NotSupportedByDriverError, 'Capybara::Driver::Base#save_screenshot' end def response_headers raise Capybara::NotSupportedByDriverError, 'Capybara::Driver::Base#response_headers' end def status_code raise Capybara::NotSupportedByDriverError, 'Capybara::Driver::Base#status_code' end def within_frame(frame_handle) raise Capybara::NotSupportedByDriverError, 'Capybara::Driver::Base#within_frame' end def within_window(handle) raise Capybara::NotSupportedByDriverError, 'Capybara::Driver::Base#within_window' end def invalid_element_errors [] end def wait? false end def reset! end def needs_server? false end end capybara-2.1.0/lib/capybara/driver/node.rb0000644000175000017500000000340012140721202017401 0ustar lunarlunarmodule Capybara module Driver class Node attr_reader :driver, :native def initialize(driver, native) @driver = driver @native = native end def all_text raise NotImplementedError end def visible_text raise NotImplementedError end def [](name) raise NotImplementedError end def value raise NotImplementedError end # @param value String or Array. Array is only allowed if node has 'multiple' attribute def set(value) raise NotImplementedError end def select_option raise NotImplementedError end def unselect_option raise NotImplementedError end def click raise NotImplementedError end def hover raise NotImplementedError end def drag_to(element) raise NotImplementedError end def tag_name raise NotImplementedError end def visible? raise NotImplementedError end def checked? raise NotImplementedError end def selected? raise NotImplementedError end def disabled? raise NotImplementedError end def path raise NotSupportedByDriverError, 'Capybara::Driver::Node#path' end def trigger(event) raise NotSupportedByDriverError, 'Capybara::Driver::Node#trigger' end def inspect %(#<#{self.class} tag="#{tag_name}" path="#{path}">) rescue NotSupportedByDriverError, 'Capybara::Driver::Node#inspect' %(#<#{self.class} tag="#{tag_name}">) end def ==(other) raise NotSupportedByDriverError, 'Capybara::Driver::Node#==' end end end end capybara-2.1.0/lib/capybara/helpers.rb0000644000175000017500000000756112140721202016637 0ustar lunarlunar# encoding: UTF-8 module Capybara # @api private module Helpers extend self ## # # Normalizes whitespace space by stripping leading and trailing # whitespace and replacing sequences of whitespace characters # with a single space. # # @param [String] text Text to normalize # @return [String] Normalized text # def normalize_whitespace(text) text.to_s.gsub(/[[:space:]]+/, ' ').strip end ## # # Escapes any characters that would have special meaning in a regexp # if text is not a regexp # # @param [String] text Text to escape # @return [String] Escaped text # def to_regexp(text) text.is_a?(Regexp) ? text : Regexp.new(Regexp.escape(normalize_whitespace(text))) end ## # # Injects a `` tag into the given HTML code, pointing to # `Capybara.asset_host`. # # @param [String] html HTML code to inject into # @return [String] The modified HTML code # def inject_asset_host(html) if Capybara.asset_host if Nokogiri::HTML(html).css("base").empty? and match = html.match(//) html.clone.insert match.end(0), "" end else html end end ## # # Checks if the given count matches the given count options. By default, # when no options are given, count should be larger than zero. # # @param [Integer] count The actual number. Should be coercible via Integer() # @option [Range] between Count must be within the given range # @option [Integer] count Count must be exactly this # @option [Integer] maximum Count must be smaller than or equal to this value # @option [Integer] minimum Count must be larger than or equal to this value # def matches_count?(count, options={}) case when options[:between] options[:between] === count when options[:count] Integer(options[:count]) == count when options[:maximum] Integer(options[:maximum]) >= count when options[:minimum] Integer(options[:minimum]) <= count else count > 0 end end ## # # Generates a failure message given a description of the query and count # options. # # @param [String] description Description of a query # @option [Range] between Count should have been within the given range # @option [Integer] count Count should have been exactly this # @option [Integer] maximum Count should have been smaller than or equal to this value # @option [Integer] minimum Count should have been larger than or equal to this value # def failure_message(description, options={}) message = "expected to find #{description}" if options[:count] message << " #{options[:count]} #{declension('time', 'times', options[:count])}" elsif options[:between] message << " between #{options[:between].first} and #{options[:between].last} times" elsif options[:maximum] message << " at most #{options[:maximum]} #{declension('time', 'times', options[:maximum])}" elsif options[:minimum] message << " at least #{options[:minimum]} #{declension('time', 'times', options[:minimum])}" end message end ## # # A poor man's `pluralize`. Given two declensions, one singular and one # plural, as well as a count, this will pick the correct declension. This # way we can generate gramatically correct error message. # # @param [String] singular The singular form of the word # @param [String] plural The plural form of the word # @param [Integer] count The number of items # def declension(singular, plural, count) if count == 1 singular else plural end end end end capybara-2.1.0/lib/capybara/spec/0000755000175000017500000000000012140721202015571 5ustar lunarlunarcapybara-2.1.0/lib/capybara/spec/fixtures/0000755000175000017500000000000012140721202017442 5ustar lunarlunarcapybara-2.1.0/lib/capybara/spec/fixtures/test_file.txt0000644000175000017500000000002112140721202022152 0ustar lunarlunarThisIsTheTestFilecapybara-2.1.0/lib/capybara/spec/fixtures/capybara.jpg0000644000175000017500000000021512140721202021724 0ustar lunarlunarThis is a jpeg file :) Since it is rendered in the view it doesn't actually contain any binary data, as that would cause Nokogiri to go mad. capybara-2.1.0/lib/capybara/spec/fixtures/another_test_file.txt0000644000175000017500000000002712140721202023700 0ustar lunarlunarThisIsTheOtherTestFile capybara-2.1.0/lib/capybara/spec/spec_helper.rb0000644000175000017500000000441312140721202020411 0ustar lunarlunarrequire "rspec" require "capybara" require "capybara/rspec" # Required here instead of in rspec_spec to avoid RSpec deprecation warning require "capybara/spec/test_app" require "nokogiri" module Capybara module SpecHelper class << self def configure(config) config.filter_run_excluding :requires => method(:filter).to_proc config.before { Capybara::SpecHelper.reset! } config.after { Capybara::SpecHelper.reset! } end def reset! Capybara.app = TestApp Capybara.app_host = nil Capybara.default_selector = :xpath Capybara.default_wait_time = 1 Capybara.ignore_hidden_elements = true Capybara.exact = false Capybara.exact_options = false Capybara.raise_server_errors = true Capybara.visible_text_only = false Capybara.match = :smart end def filter(requires, metadata) if requires and metadata[:skip] requires.any? do |require| metadata[:skip].include?(require) end else false end end def spec(name, options={}, &block) @specs ||= [] @specs << [name, options, block] end def run_specs(session, name, options={}) specs = @specs describe Capybara::Session, name, options do include Capybara::SpecHelper before do @session = session end after do @session.reset_session! end specs.each do |spec_name, spec_options, block| describe spec_name, spec_options do class_eval(&block) end end end end end # class << self def silence_stream(stream) old_stream = stream.dup stream.reopen(RbConfig::CONFIG['host_os'] =~ /rmswin|mingw/ ? 'NUL:' : '/dev/null') stream.sync = true yield ensure stream.reopen(old_stream) end def quietly silence_stream(STDOUT) do silence_stream(STDERR) do yield end end end def extract_results(session) YAML.load Nokogiri::HTML(session.body).xpath("//pre[@id='results']").first.inner_html.lstrip end end end Dir[File.dirname(__FILE__)+'/session/*'].each { |group| require group } capybara-2.1.0/lib/capybara/spec/public/0000755000175000017500000000000012140721202017047 5ustar lunarlunarcapybara-2.1.0/lib/capybara/spec/public/test.js0000644000175000017500000000366612140721202020377 0ustar lunarlunarvar activeRequests = 0; $(function() { $('#change').text('I changed it'); $('#drag').draggable(); $('#drop').droppable({ drop: function(event, ui) { ui.draggable.remove(); $(this).html('Dropped!'); } }); $('#clickable').click(function() { var link = $(this); setTimeout(function() { $(link).after('Has been clicked'); $(link).after(''); $(link).after(''); $('#change').remove(); }, 500); return false; }); $('#slow-click').click(function() { var link = $(this); setTimeout(function() { $(link).after('Slow link clicked'); }, 4000); return false; }); $('#waiter').change(function() { activeRequests = 1; setTimeout(function() { activeRequests = 0; }, 500); }); $('#with_focus_event').focus(function() { $('body').append('

Focus Event triggered

'); }); $('#with_change_event').change(function() { if($(this).val() == '') $(this).val("Can't be empty"); }); $('#checkbox_with_event').click(function() { $('body').append('

Checkbox event triggered

'); }); $('#fire_ajax_request').click(function() { $.ajax({url: "/slow_response", context: document.body, success: function() { $('body').append('

Ajax request done

'); }}); }); $('#reload-link').click(function() { setTimeout(function() { $('#reload-me').replaceWith(''); }, 250) }); $('#reload-list').click(function() { setTimeout(function() { $('#the-list').html('
  • Foo
  • Bar
  • '); }, 250) }); $('#change-title').click(function() { setTimeout(function() { $('title').text('changed title') }, 250) }); }); capybara-2.1.0/lib/capybara/spec/session/0000755000175000017500000000000012140721202017254 5ustar lunarlunarcapybara-2.1.0/lib/capybara/spec/session/unselect_spec.rb0000644000175000017500000001022412140721202022434 0ustar lunarlunarCapybara::SpecHelper.spec "#unselect" do before do @session.visit('/form') end context "with multiple select" do it "should unselect an option from a select box by id" do @session.unselect('Commando', :from => 'form_underwear') @session.click_button('awesome') extract_results(@session)['underwear'].should include('Briefs', 'Boxerbriefs') extract_results(@session)['underwear'].should_not include('Commando') end it "should unselect an option without a select box" do @session.unselect('Commando') @session.click_button('awesome') extract_results(@session)['underwear'].should include('Briefs', 'Boxerbriefs') extract_results(@session)['underwear'].should_not include('Commando') end it "should unselect an option from a select box by label" do @session.unselect('Commando', :from => 'Underwear') @session.click_button('awesome') extract_results(@session)['underwear'].should include('Briefs', 'Boxerbriefs') extract_results(@session)['underwear'].should_not include('Commando') end it "should favour exact matches to option labels" do @session.unselect("Briefs", :from => 'Underwear') @session.click_button('awesome') extract_results(@session)['underwear'].should include('Commando', 'Boxerbriefs') extract_results(@session)['underwear'].should_not include('Briefs') end it "should escape quotes" do @session.unselect("Frenchman's Pantalons", :from => 'Underwear') @session.click_button('awesome') extract_results(@session)['underwear'].should_not include("Frenchman's Pantalons") end it "casts to string" do @session.unselect(:"Briefs", :from => :'Underwear') @session.click_button('awesome') extract_results(@session)['underwear'].should include('Commando', 'Boxerbriefs') extract_results(@session)['underwear'].should_not include('Briefs') end end context "with single select" do it "should raise an error" do expect { @session.unselect("English", :from => 'form_locale') }.to raise_error(Capybara::UnselectNotAllowed) end end context "with a locator that doesn't exist" do it "should raise an error" do msg = "Unable to find select box \"does not exist\"" expect do @session.unselect('foo', :from => 'does not exist') end.to raise_error(Capybara::ElementNotFound, msg) end end context "with an option that doesn't exist" do it "should raise an error" do msg = "Unable to find option \"Does not Exist\"" expect do @session.unselect('Does not Exist', :from => 'form_underwear') end.to raise_error(Capybara::ElementNotFound, msg) end end context "with :exact option" do context "when `false`" do it "can match select box approximately" do @session.unselect("Boxerbriefs", :from => "Under", :exact => false) @session.click_button("awesome") extract_results(@session)["underwear"].should_not include("Boxerbriefs") end it "can match option approximately" do @session.unselect("Boxerbr", :from => "Underwear", :exact => false) @session.click_button("awesome") extract_results(@session)["underwear"].should_not include("Boxerbriefs") end it "can match option approximately when :from not given" do @session.unselect("Boxerbr", :exact => false) @session.click_button("awesome") extract_results(@session)["underwear"].should_not include("Boxerbriefs") end end context "when `true`" do it "can match select box approximately" do expect do @session.unselect("Boxerbriefs", :from => "Under", :exact => true) end.to raise_error(Capybara::ElementNotFound) end it "can match option approximately" do expect do @session.unselect("Boxerbr", :from => "Underwear", :exact => true) end.to raise_error(Capybara::ElementNotFound) end it "can match option approximately when :from not given" do expect do @session.unselect("Boxerbr", :exact => true) end.to raise_error(Capybara::ElementNotFound) end end end end capybara-2.1.0/lib/capybara/spec/session/has_css_spec.rb0000644000175000017500000002063312140721202022242 0ustar lunarlunarCapybara::SpecHelper.spec '#has_css?' do before do @session.visit('/with_html') end it "should be true if the given selector is on the page" do @session.should have_css("p") @session.should have_css("p a#foo") end it "should be false if the given selector is not on the page" do @session.should_not have_css("abbr") @session.should_not have_css("p a#doesnotexist") @session.should_not have_css("p.nosuchclass") end it "should respect scopes" do @session.within "//p[@id='first']" do @session.should have_css("a#foo") @session.should_not have_css("a#red") end end it "should wait for content to appear", :requires => [:js] do @session.visit('/with_js') @session.click_link('Click me') @session.should have_css("input[type='submit'][value='New Here']") end context "with between" do it "should be true if the content occurs within the range given" do @session.should have_css("p", :between => 1..4) @session.should have_css("p a#foo", :between => 1..3) @session.should have_css("p a.doesnotexist", :between => 0..8) end it "should be false if the content occurs more or fewer times than range" do @session.should_not have_css("p", :between => 6..11 ) @session.should_not have_css("p a#foo", :between => 4..7) @session.should_not have_css("p a.doesnotexist", :between => 3..8) end end context "with count" do it "should be true if the content occurs the given number of times" do @session.should have_css("p", :count => 3) @session.should have_css("p a#foo", :count => 1) @session.should have_css("p a.doesnotexist", :count => 0) end it "should be false if the content occurs a different number of times than the given" do @session.should_not have_css("p", :count => 6) @session.should_not have_css("p a#foo", :count => 2) @session.should_not have_css("p a.doesnotexist", :count => 1) end it "should coerce count to an integer" do @session.should have_css("p", :count => "3") @session.should have_css("p a#foo", :count => "1") end end context "with maximum" do it "should be true when content occurs same or fewer times than given" do @session.should have_css("h2.head", :maximum => 5) # edge case @session.should have_css("h2", :maximum => 10) @session.should have_css("p a.doesnotexist", :maximum => 1) @session.should have_css("p a.doesnotexist", :maximum => 0) end it "should be false when content occurs more times than given" do @session.should_not have_css("h2.head", :maximum => 4) # edge case @session.should_not have_css("h2", :maximum => 3) @session.should_not have_css("p", :maximum => 1) end it "should coerce maximum to an integer" do @session.should have_css("h2.head", :maximum => "5") # edge case @session.should have_css("h2", :maximum => "10") end end context "with minimum" do it "should be true when content occurs same or more times than given" do @session.should have_css("h2.head", :minimum => 5) # edge case @session.should have_css("h2", :minimum => 3) @session.should have_css("p a.doesnotexist", :minimum => 0) end it "should be false when content occurs fewer times than given" do @session.should_not have_css("h2.head", :minimum => 6) # edge case @session.should_not have_css("h2", :minimum => 8) @session.should_not have_css("p", :minimum => 10) @session.should_not have_css("p a.doesnotexist", :minimum => 1) end it "should coerce minimum to an integer" do @session.should have_css("h2.head", :minimum => "5") # edge case @session.should have_css("h2", :minimum => "3") end end context "with text" do it "should discard all matches where the given string is not contained" do @session.should have_css("p a", :text => "Redirect", :count => 1) @session.should_not have_css("p a", :text => "Doesnotexist") end it "should discard all matches where the given regexp is not matched" do @session.should have_css("p a", :text => /re[dab]i/i, :count => 1) @session.should_not have_css("p a", :text => /Red$/) end end end Capybara::SpecHelper.spec '#has_no_css?' do before do @session.visit('/with_html') end it "should be false if the given selector is on the page" do @session.should_not have_no_css("p") @session.should_not have_no_css("p a#foo") end it "should be true if the given selector is not on the page" do @session.should have_no_css("abbr") @session.should have_no_css("p a#doesnotexist") @session.should have_no_css("p.nosuchclass") end it "should respect scopes" do @session.within "//p[@id='first']" do @session.should_not have_no_css("a#foo") @session.should have_no_css("a#red") end end it "should wait for content to disappear", :requires => [:js] do @session.visit('/with_js') @session.click_link('Click me') @session.should have_no_css("p#change") end context "with between" do it "should be false if the content occurs within the range given" do @session.should_not have_no_css("p", :between => 1..4) @session.should_not have_no_css("p a#foo", :between => 1..3) @session.should_not have_no_css("p a.doesnotexist", :between => 0..2) end it "should be true if the content occurs more or fewer times than range" do @session.should have_no_css("p", :between => 6..11 ) @session.should have_no_css("p a#foo", :between => 4..7) @session.should have_no_css("p a.doesnotexist", :between => 3..8) end end context "with count" do it "should be false if the content is on the page the given number of times" do @session.should_not have_no_css("p", :count => 3) @session.should_not have_no_css("p a#foo", :count => 1) @session.should_not have_no_css("p a.doesnotexist", :count => 0) end it "should be true if the content is on the page the given number of times" do @session.should have_no_css("p", :count => 6) @session.should have_no_css("p a#foo", :count => 2) @session.should have_no_css("p a.doesnotexist", :count => 1) end it "should coerce count to an integer" do @session.should_not have_no_css("p", :count => "3") @session.should_not have_no_css("p a#foo", :count => "1") end end context "with maximum" do it "should be false when content occurs same or fewer times than given" do @session.should_not have_no_css("h2.head", :maximum => 5) # edge case @session.should_not have_no_css("h2", :maximum => 10) @session.should_not have_no_css("p a.doesnotexist", :maximum => 0) end it "should be true when content occurs more times than given" do @session.should have_no_css("h2.head", :maximum => 4) # edge case @session.should have_no_css("h2", :maximum => 3) @session.should have_no_css("p", :maximum => 1) end it "should coerce maximum to an integer" do @session.should_not have_no_css("h2.head", :maximum => "5") # edge case @session.should_not have_no_css("h2", :maximum => "10") end end context "with minimum" do it "should be false when content occurs same or more times than given" do @session.should_not have_no_css("h2.head", :minimum => 5) # edge case @session.should_not have_no_css("h2", :minimum => 3) @session.should_not have_no_css("p a.doesnotexist", :minimum => 0) end it "should be true when content occurs fewer times than given" do @session.should have_no_css("h2.head", :minimum => 6) # edge case @session.should have_no_css("h2", :minimum => 8) @session.should have_no_css("p", :minimum => 15) @session.should have_no_css("p a.doesnotexist", :minimum => 1) end it "should coerce minimum to an integer" do @session.should_not have_no_css("h2.head", :minimum => "4") # edge case @session.should_not have_no_css("h2", :minimum => "3") end end context "with text" do it "should discard all matches where the given string is not contained" do @session.should_not have_no_css("p a", :text => "Redirect", :count => 1) @session.should have_no_css("p a", :text => "Doesnotexist") end it "should discard all matches where the given regexp is not matched" do @session.should_not have_no_css("p a", :text => /re[dab]i/i, :count => 1) @session.should have_no_css("p a", :text => /Red$/) end end end capybara-2.1.0/lib/capybara/spec/session/has_table_spec.rb0000644000175000017500000000141012140721202022531 0ustar lunarlunarCapybara::SpecHelper.spec '#has_table?' do before do @session.visit('/tables') end it "should be true if the table is on the page" do @session.should have_table('Villain') @session.should have_table('villain_table') @session.should have_table(:'villain_table') end it "should be false if the table is not on the page" do @session.should_not have_table('Monkey') end end Capybara::SpecHelper.spec '#has_no_table?' do before do @session.visit('/tables') end it "should be false if the table is on the page" do @session.should_not have_no_table('Villain') @session.should_not have_no_table('villain_table') end it "should be true if the table is not on the page" do @session.should have_no_table('Monkey') end end capybara-2.1.0/lib/capybara/spec/session/response_code.rb0000644000175000017500000000031112140721202022424 0ustar lunarlunarCapybara::SpecHelper.spec '#status_code' do it "should return response codes", :requires => [:status_code] do @session.visit('/with_simple_html') @session.status_code.should == 200 end end capybara-2.1.0/lib/capybara/spec/session/has_text_spec.rb0000644000175000017500000002275512140721202022445 0ustar lunarlunarCapybara::SpecHelper.spec '#has_text?' do it "should be true if the given text is on the page at least once" do @session.visit('/with_html') @session.should have_text('est') @session.should have_text('Lorem') @session.should have_text('Redirect') @session.should have_text(:'Redirect') end it "should be true if scoped to an element which has the text" do @session.visit('/with_html') @session.within("//a[@title='awesome title']") do @session.should have_text('labore') end end it "should be false if scoped to an element which does not have the text" do @session.visit('/with_html') @session.within("//a[@title='awesome title']") do @session.should_not have_text('monkey') end end it "should ignore tags" do @session.visit('/with_html') @session.should_not have_text('exercitation ullamco laboris') @session.should have_text('exercitation ullamco laboris') end it "should ignore extra whitespace and newlines" do @session.visit('/with_html') @session.should have_text('text with whitespace') end it "should ignore whitespace and newlines in the search string" do @session.visit('/with_html') @session.should have_text("text with \n\n whitespace") end it "should be false if the given text is not on the page" do @session.visit('/with_html') @session.should_not have_text('xxxxyzzz') @session.should_not have_text('monkey') end it 'should handle single quotes in the text' do @session.visit('/with-quotes') @session.should have_text("can't") end it 'should handle double quotes in the text' do @session.visit('/with-quotes') @session.should have_text(%q{"No," he said}) end it 'should handle mixed single and double quotes in the text' do @session.visit('/with-quotes') @session.should have_text(%q{"you can't do that."}) end it 'should be false if text is in the title tag in the head' do @session.visit('/with_js') @session.should_not have_text('with_js') end it 'should be false if text is inside a script tag in the body' do @session.visit('/with_js') @session.should_not have_text('a javascript comment') @session.should_not have_text('aVar') end it "should be false if the given text is on the page but not visible" do @session.visit('/with_html') @session.should_not have_text('Inside element with hidden ancestor') end it "should be true if :all given and text is invisible." do @session.visit('/with_html') @session.should have_text(:all, 'Some of this text is hidden!') end it "should be true if `Capybara.ignore_hidden_elements = true` and text is invisible." do Capybara.ignore_hidden_elements = false @session.visit('/with_html') @session.should have_text('Some of this text is hidden!') end it "should be true if the text in the page matches given regexp" do @session.visit('/with_html') @session.should have_text(/Lorem/) end it "should be false if the text in the page doesn't match given regexp" do @session.visit('/with_html') @session.should_not have_text(/xxxxyzzz/) end it "should escape any characters that would have special meaning in a regexp" do @session.visit('/with_html') @session.should_not have_text('.orem') end it "should accept non-string parameters" do @session.visit('/with_html') @session.should have_text(42) end it "should be true when passed nil" do # Historical behavior; no particular reason other than compatibility. @session.visit('/with_html') @session.should have_text(nil) end it "should wait for text to appear", :requires => [:js] do @session.visit('/with_js') @session.click_link('Click me') @session.should have_text("Has been clicked") end context "with between" do it "should be true if the text occurs within the range given" do @session.visit('/with_count') @session.should have_text('count', between: 1..3) @session.should have_text(/count/, between: 2..2) end it "should be false if the text occurs more or fewer times than range" do @session.visit('/with_count') @session.should_not have_text('count', between: 0..1) @session.should_not have_text('count', between: 3..10) @session.should_not have_text(/count/, between: 2...2) end end context "with count" do it "should be true if the text occurs the given number of times" do @session.visit('/with_count') @session.should have_text('count', count: 2) end it "should be false if the text occurs a different number of times than the given" do @session.visit('/with_count') @session.should_not have_text('count', count: 0) @session.should_not have_text('count', count: 1) @session.should_not have_text(/count/, count: 3) end it "should coerce count to an integer" do @session.visit('/with_count') @session.should have_text('count', count: '2') @session.should_not have_text('count', count: '3') end end context "with maximum" do it "should be true when text occurs same or fewer times than given" do @session.visit('/with_count') @session.should have_text('count', maximum: 2) @session.should have_text(/count/, maximum: 3) end it "should be false when text occurs more times than given" do @session.visit('/with_count') @session.should_not have_text('count', maximum: 1) @session.should_not have_text('count', maximum: 0) end it "should coerce maximum to an integer" do @session.visit('/with_count') @session.should have_text('count', maximum: '2') @session.should_not have_text('count', maximum: '1') end end context "with minimum" do it "should be true when text occurs same or more times than given" do @session.visit('/with_count') @session.should have_text('count', minimum: 2) @session.should have_text(/count/, minimum: 0) end it "should be false when text occurs fewer times than given" do @session.visit('/with_count') @session.should_not have_text('count', minimum: 3) end it "should coerce minimum to an integer" do @session.visit('/with_count') @session.should have_text('count', minimum: '2') @session.should_not have_text('count', minimum: '3') end end end Capybara::SpecHelper.spec '#has_no_text?' do it "should be false if the given text is on the page at least once" do @session.visit('/with_html') @session.should_not have_no_text('est') @session.should_not have_no_text('Lorem') @session.should_not have_no_text('Redirect') end it "should be false if scoped to an element which has the text" do @session.visit('/with_html') @session.within("//a[@title='awesome title']") do @session.should_not have_no_text('labore') end end it "should be true if scoped to an element which does not have the text" do @session.visit('/with_html') @session.within("//a[@title='awesome title']") do @session.should have_no_text('monkey') end end it "should ignore tags" do @session.visit('/with_html') @session.should have_no_text('exercitation ullamco laboris') @session.should_not have_no_text('exercitation ullamco laboris') end it "should be true if the given text is not on the page" do @session.visit('/with_html') @session.should have_no_text('xxxxyzzz') @session.should have_no_text('monkey') end it 'should handle single quotes in the text' do @session.visit('/with-quotes') @session.should_not have_no_text("can't") end it 'should handle double quotes in the text' do @session.visit('/with-quotes') @session.should_not have_no_text(%q{"No," he said}) end it 'should handle mixed single and double quotes in the text' do @session.visit('/with-quotes') @session.should_not have_no_text(%q{"you can't do that."}) end it 'should be true if text is in the title tag in the head' do @session.visit('/with_js') @session.should have_no_text('with_js') end it 'should be true if text is inside a script tag in the body' do @session.visit('/with_js') @session.should have_no_text('a javascript comment') @session.should have_no_text('aVar') end it "should be true if the given text is on the page but not visible" do @session.visit('/with_html') @session.should have_no_text('Inside element with hidden ancestor') end it "should be false if :all given and text is invisible." do @session.visit('/with_html') @session.should_not have_no_text(:all, 'Some of this text is hidden!') end it "should be false if `Capybara.ignore_hidden_elements = true` and text is invisible." do Capybara.ignore_hidden_elements = false @session.visit('/with_html') @session.should_not have_no_text('Some of this text is hidden!') end it "should be true if the text in the page doesn't match given regexp" do @session.visit('/with_html') @session.should have_no_text(/xxxxyzzz/) end it "should be false if the text in the page matches given regexp" do @session.visit('/with_html') @session.should_not have_no_text(/Lorem/) end it "should escape any characters that would have special meaning in a regexp" do @session.visit('/with_html') @session.should have_no_text('.orem') end it "should wait for text to disappear", :requires => [:js] do @session.visit('/with_js') @session.click_link('Click me') @session.should have_no_text("I changed it") end end capybara-2.1.0/lib/capybara/spec/session/assert_selector.rb0000644000175000017500000001276512140721202023015 0ustar lunarlunarCapybara::SpecHelper.spec '#assert_selector' do before do @session.visit('/with_html') end it "should be true if the given selector is on the page" do @session.assert_selector(:xpath, "//p") @session.assert_selector(:css, "p a#foo") @session.assert_selector("//p[contains(.,'est')]") end it "should be false if the given selector is not on the page" do expect { @session.assert_selector(:xpath, "//abbr") }.to raise_error(Capybara::ElementNotFound) expect { @session.assert_selector(:css, "p a#doesnotexist") }.to raise_error(Capybara::ElementNotFound) expect { @session.assert_selector("//p[contains(.,'thisstringisnotonpage')]") }.to raise_error(Capybara::ElementNotFound) end it "should use default selector" do Capybara.default_selector = :css expect { @session.assert_selector("p a#doesnotexist") }.to raise_error(Capybara::ElementNotFound) @session.assert_selector("p a#foo") end it "should respect scopes" do @session.within "//p[@id='first']" do @session.assert_selector(".//a[@id='foo']") expect { @session.assert_selector(".//a[@id='red']") }.to raise_error(Capybara::ElementNotFound) end end context "with count" do it "should be true if the content is on the page the given number of times" do @session.assert_selector("//p", :count => 3) @session.assert_selector("//p//a[@id='foo']", :count => 1) @session.assert_selector("//p[contains(.,'est')]", :count => 1) end it "should be false if the content is on the page the given number of times" do expect { @session.assert_selector("//p", :count => 6) }.to raise_error(Capybara::ElementNotFound) expect { @session.assert_selector("//p//a[@id='foo']", :count => 2) }.to raise_error(Capybara::ElementNotFound) expect { @session.assert_selector("//p[contains(.,'est')]", :count => 5) }.to raise_error(Capybara::ElementNotFound) end it "should be false if the content isn't on the page at all" do expect { @session.assert_selector("//abbr", :count => 2) }.to raise_error(Capybara::ElementNotFound) expect { @session.assert_selector("//p//a[@id='doesnotexist']", :count => 1) }.to raise_error(Capybara::ElementNotFound) end end context "with text" do it "should discard all matches where the given string is not contained" do @session.assert_selector("//p//a", :text => "Redirect", :count => 1) expect { @session.assert_selector("//p", :text => "Doesnotexist") }.to raise_error(Capybara::ElementNotFound) end it "should discard all matches where the given regexp is not matched" do @session.assert_selector("//p//a", :text => /re[dab]i/i, :count => 1) expect { @session.assert_selector("//p//a", :text => /Red$/) }.to raise_error(Capybara::ElementNotFound) end end end Capybara::SpecHelper.spec '#assert_no_selector' do before do @session.visit('/with_html') end it "should be false if the given selector is on the page" do expect { @session.assert_no_selector(:xpath, "//p") }.to raise_error(Capybara::ElementNotFound) expect { @session.assert_no_selector(:css, "p a#foo") }.to raise_error(Capybara::ElementNotFound) expect { @session.assert_no_selector("//p[contains(.,'est')]") }.to raise_error(Capybara::ElementNotFound) end it "should be true if the given selector is not on the page" do @session.assert_no_selector(:xpath, "//abbr") @session.assert_no_selector(:css, "p a#doesnotexist") @session.assert_no_selector("//p[contains(.,'thisstringisnotonpage')]") end it "should use default selector" do Capybara.default_selector = :css @session.assert_no_selector("p a#doesnotexist") expect { @session.assert_no_selector("p a#foo") }.to raise_error(Capybara::ElementNotFound) end it "should respect scopes" do @session.within "//p[@id='first']" do expect { @session.assert_no_selector(".//a[@id='foo']") }.to raise_error(Capybara::ElementNotFound) @session.assert_no_selector(".//a[@id='red']") end end context "with count" do it "should be false if the content is on the page the given number of times" do expect { @session.assert_no_selector("//p", :count => 3) }.to raise_error(Capybara::ElementNotFound) expect { @session.assert_no_selector("//p//a[@id='foo']", :count => 1) }.to raise_error(Capybara::ElementNotFound) expect { @session.assert_no_selector("//p[contains(.,'est')]", :count => 1) }.to raise_error(Capybara::ElementNotFound) end it "should be true if the content is on the page the wrong number of times" do @session.assert_no_selector("//p", :count => 6) @session.assert_no_selector("//p//a[@id='foo']", :count => 2) @session.assert_no_selector("//p[contains(.,'est')]", :count => 5) end it "should be true if the content isn't on the page at all" do @session.assert_no_selector("//abbr", :count => 2) @session.assert_no_selector("//p//a[@id='doesnotexist']", :count => 1) end end context "with text" do it "should discard all matches where the given string is contained" do expect { @session.assert_no_selector("//p//a", :text => "Redirect", :count => 1) }.to raise_error(Capybara::ElementNotFound) @session.assert_no_selector("//p", :text => "Doesnotexist") end it "should discard all matches where the given regexp is matched" do expect { @session.assert_no_selector("//p//a", :text => /re[dab]i/i, :count => 1) }.to raise_error(Capybara::ElementNotFound) @session.assert_no_selector("//p//a", :text => /Red$/) end end end capybara-2.1.0/lib/capybara/spec/session/has_field_spec.rb0000644000175000017500000002050712140721202022535 0ustar lunarlunarCapybara::SpecHelper.spec '#has_field' do before { @session.visit('/form') } it "should be true if the field is on the page" do @session.should have_field('Dog') @session.should have_field('form_description') @session.should have_field('Region') @session.should have_field(:'Region') end it "should be false if the field is not on the page" do @session.should_not have_field('Monkey') end context 'with value' do it "should be true if a field with the given value is on the page" do @session.should have_field('First Name', :with => 'John') @session.should have_field('Phone', :with => '+1 555 7021') @session.should have_field('Street', :with => 'Sesame street 66') @session.should have_field('Description', :with => 'Descriptive text goes here') end it "should be false if the given field is not on the page" do @session.should_not have_field('First Name', :with => 'Peter') @session.should_not have_field('Wrong Name', :with => 'John') @session.should_not have_field('Description', :with => 'Monkey') end it "should be true after the field has been filled in with the given value" do @session.fill_in('First Name', :with => 'Jonas') @session.should have_field('First Name', :with => 'Jonas') end it "should be false after the field has been filled in with a different value" do @session.fill_in('First Name', :with => 'Jonas') @session.should_not have_field('First Name', :with => 'John') end end context 'with type' do it "should be true if a field with the given type is on the page" do @session.should have_field('First Name', :type => 'text') @session.should have_field('Html5 Email', :type => 'email') @session.should have_field('Html5 Tel', :type => 'tel') @session.should have_field('Description', :type => 'textarea') @session.should have_field('Languages', :type => 'select') end it "should be false if the given field is not on the page" do @session.should_not have_field('First Name', :type => 'textarea') @session.should_not have_field('Html5 Email', :type => 'tel') @session.should_not have_field('Description', :type => '') @session.should_not have_field('Description', :type => 'email') @session.should_not have_field('Languages', :type => 'textarea') end end end Capybara::SpecHelper.spec '#has_no_field' do before { @session.visit('/form') } it "should be false if the field is on the page" do @session.should_not have_no_field('Dog') @session.should_not have_no_field('form_description') @session.should_not have_no_field('Region') end it "should be true if the field is not on the page" do @session.should have_no_field('Monkey') end context 'with value' do it "should be false if a field with the given value is on the page" do @session.should_not have_no_field('First Name', :with => 'John') @session.should_not have_no_field('Phone', :with => '+1 555 7021') @session.should_not have_no_field('Street', :with => 'Sesame street 66') @session.should_not have_no_field('Description', :with => 'Descriptive text goes here') end it "should be true if the given field is not on the page" do @session.should have_no_field('First Name', :with => 'Peter') @session.should have_no_field('Wrong Name', :with => 'John') @session.should have_no_field('Description', :with => 'Monkey') end it "should be false after the field has been filled in with the given value" do @session.fill_in('First Name', :with => 'Jonas') @session.should_not have_no_field('First Name', :with => 'Jonas') end it "should be true after the field has been filled in with a different value" do @session.fill_in('First Name', :with => 'Jonas') @session.should have_no_field('First Name', :with => 'John') end end context 'with type' do it "should be false if a field with the given type is on the page" do @session.should_not have_no_field('First Name', :type => 'text') @session.should_not have_no_field('Html5 Email', :type => 'email') @session.should_not have_no_field('Html5 Tel', :type => 'tel') @session.should_not have_no_field('Description', :type => 'textarea') @session.should_not have_no_field('Languages', :type => 'select') end it "should be true if the given field is not on the page" do @session.should have_no_field('First Name', :type => 'textarea') @session.should have_no_field('Html5 Email', :type => 'tel') @session.should have_no_field('Description', :type => '') @session.should have_no_field('Description', :type => 'email') @session.should have_no_field('Languages', :type => 'textarea') end end end Capybara::SpecHelper.spec '#has_checked_field?' do before { @session.visit('/form') } it "should be true if a checked field is on the page" do @session.should have_checked_field('gender_female') @session.should have_checked_field('Hamster') end it "should be false if an unchecked field is on the page" do @session.should_not have_checked_field('form_pets_cat') @session.should_not have_checked_field('Male') end it "should be false if no field is on the page" do @session.should_not have_checked_field('Does Not Exist') end it "should be true after an unchecked checkbox is checked" do @session.check('form_pets_cat') @session.should have_checked_field('form_pets_cat') end it "should be false after a checked checkbox is unchecked" do @session.uncheck('form_pets_dog') @session.should_not have_checked_field('form_pets_dog') end it "should be true after an unchecked radio button is chosen" do @session.choose('gender_male') @session.should have_checked_field('gender_male') end it "should be false after another radio button in the group is chosen" do @session.choose('gender_male') @session.should_not have_checked_field('gender_female') end end Capybara::SpecHelper.spec '#has_no_checked_field?' do before { @session.visit('/form') } it "should be false if a checked field is on the page" do @session.should_not have_no_checked_field('gender_female') @session.should_not have_no_checked_field('Hamster') end it "should be true if an unchecked field is on the page" do @session.should have_no_checked_field('form_pets_cat') @session.should have_no_checked_field('Male') end it "should be true if no field is on the page" do @session.should have_no_checked_field('Does Not Exist') end end Capybara::SpecHelper.spec '#has_unchecked_field?' do before { @session.visit('/form') } it "should be false if a checked field is on the page" do @session.should_not have_unchecked_field('gender_female') @session.should_not have_unchecked_field('Hamster') end it "should be true if an unchecked field is on the page" do @session.should have_unchecked_field('form_pets_cat') @session.should have_unchecked_field('Male') end it "should be false if no field is on the page" do @session.should_not have_unchecked_field('Does Not Exist') end it "should be false after an unchecked checkbox is checked" do @session.check('form_pets_cat') @session.should_not have_unchecked_field('form_pets_cat') end it "should be true after a checked checkbox is unchecked" do @session.uncheck('form_pets_dog') @session.should have_unchecked_field('form_pets_dog') end it "should be false after an unchecked radio button is chosen" do @session.choose('gender_male') @session.should_not have_unchecked_field('gender_male') end it "should be true after another radio button in the group is chosen" do @session.choose('gender_male') @session.should have_unchecked_field('gender_female') end end Capybara::SpecHelper.spec '#has_no_unchecked_field?' do before { @session.visit('/form') } it "should be true if a checked field is on the page" do @session.should have_no_unchecked_field('gender_female') @session.should have_no_unchecked_field('Hamster') end it "should be false if an unchecked field is on the page" do @session.should_not have_no_unchecked_field('form_pets_cat') @session.should_not have_no_unchecked_field('Male') end it "should be true if no field is on the page" do @session.should have_no_unchecked_field('Does Not Exist') end end capybara-2.1.0/lib/capybara/spec/session/node_spec.rb0000644000175000017500000002221212140721202021537 0ustar lunarlunarCapybara::SpecHelper.spec "node" do before do @session.visit('/with_html') end it "should act like a session object" do @session.visit('/form') @form = @session.find(:css, '#get-form') @form.should have_field('Middle Name') @form.should have_no_field('Languages') @form.fill_in('Middle Name', :with => 'Monkey') @form.click_button('med') extract_results(@session)['middle_name'].should == 'Monkey' end it "should scope CSS selectors" do @session.find(:css, '#second').should have_no_css('h1') end describe "#parent" do it "should have a reference to its parent if there is one" do @node = @session.find(:css, '#first') @node.parent.should == @node.session.document @node.find(:css, '#foo').parent.should == @node end end describe "#text" do it "should extract node texts" do @session.all('//a')[0].text.should == 'labore' @session.all('//a')[1].text.should == 'ullamco' end it "should return document text on /html selector" do @session.visit('/with_simple_html') @session.all('/html')[0].text.should == 'Bar' end end describe "#[]" do it "should extract node attributes" do @session.all('//a')[0][:class].should == 'simple' @session.all('//a')[1][:id].should == 'foo' @session.all('//input')[0][:type].should == 'text' end it "should extract boolean node attributes" do @session.find('//input[@id="checked_field"]')[:checked].should be_true end end describe "#value" do it "should allow retrieval of the value" do @session.find('//textarea[@id="normal"]').value.should == 'banana' end it "should not swallow extra newlines in textarea" do @session.find('//textarea[@id="additional_newline"]').value.should == "\nbanana" end it "return any HTML content in textarea" do @session.find('//textarea[1]').set("some html here") @session.find('//textarea[1]').value.should == "some html here" end end describe "#set" do it "should allow assignment of field value" do @session.first('//input').value.should == 'monkey' @session.first('//input').set('gorilla') @session.first('//input').value.should == 'gorilla' end it "should fill the field even if the caret was not at the end", :requires => [:js] do @session.execute_script("var el = document.getElementById('test_field'); el.focus(); el.setSelectionRange(0, 0);") @session.first('//input').set('') @session.first('//input').value.should == '' end it "should not set if the text field is readonly" do @session.first('//input[@readonly]').value.should == 'should not change' @session.first('//input[@readonly]').set('changed') @session.first('//input[@readonly]').value.should == 'should not change' end it "should not set if the textarea is readonly" do @session.first('//textarea[@readonly]').value.should == 'textarea should not change' @session.first('//textarea[@readonly]').set('changed') @session.first('//textarea[@readonly]').value.should == 'textarea should not change' end end describe "#tag_name" do it "should extract node tag name" do @session.all('//a')[0].tag_name.should == 'a' @session.all('//a')[1].tag_name.should == 'a' @session.all('//p')[1].tag_name.should == 'p' end end describe "#disabled?" do it "should extract disabled node" do @session.visit('/form') @session.find('//input[@id="customer_name"]').should be_disabled @session.find('//input[@id="customer_email"]').should_not be_disabled end it "should see disabled options as disabled" do @session.visit('/form') @session.find('//select[@id="form_title"]/option[1]').should_not be_disabled @session.find('//select[@id="form_title"]/option[@disabled]').should be_disabled end it "should see enabled options in disabled select as disabled" do @session.visit('/form') @session.find('//select[@id="form_disabled_select"]/option').should be_disabled @session.find('//select[@id="form_title"]/option[1]').should_not be_disabled end end describe "#visible?" do it "should extract node visibility" do Capybara.ignore_hidden_elements = false @session.first('//a').should be_visible @session.find('//div[@id="hidden"]').should_not be_visible @session.find('//div[@id="hidden_via_ancestor"]').should_not be_visible end end describe "#checked?" do it "should extract node checked state" do @session.visit('/form') @session.find('//input[@id="gender_female"]').should be_checked @session.find('//input[@id="gender_male"]').should_not be_checked @session.first('//h1').should_not be_checked end end describe "#selected?" do it "should extract node selected state" do @session.visit('/form') @session.find('//option[@value="en"]').should be_selected @session.find('//option[@value="sv"]').should_not be_selected @session.first('//h1').should_not be_selected end end describe "#==" do it "preserve object identity" do (@session.find('//h1') == @session.find('//h1')).should be_true (@session.find('//h1') === @session.find('//h1')).should be_true (@session.find('//h1').eql? @session.find('//h1')).should be_false end it "returns false for unrelated object" do (@session.find('//h1') == "Not Capybara::Node::Base").should be_false end end describe "#trigger", :requires => [:js, :trigger] do it "should allow triggering of custom JS events" do @session.visit('/with_js') @session.find(:css, '#with_focus_event').trigger(:focus) @session.should have_css('#focus_event_triggered') end end describe '#drag_to', :requires => [:js, :drag] do it "should drag and drop an object" do @session.visit('/with_js') element = @session.find('//div[@id="drag"]') target = @session.find('//div[@id="drop"]') element.drag_to(target) @session.find('//div[contains(., "Dropped!")]').should_not be_nil end end describe '#hover', :requires => [:hover] do it "should allow hovering on an element" do pending "Selenium with firefox doesn't currently work with this (selenium with chrome does)" if @session.respond_to?(:mode) && @session.mode == :selenium && @session.driver.browser.browser == :firefox @session.visit('/with_hover') @session.find(:css,'.hidden_until_hover', :visible => false).should_not be_visible @session.find(:css,'.wrapper').hover @session.find(:css, '.hidden_until_hover', :visible => false).should be_visible end end describe '#reload', :requires => [:js] do context "without automatic reload" do before { Capybara.automatic_reload = false } it "should reload the current context of the node" do @session.visit('/with_js') node = @session.find(:css, '#reload-me') @session.click_link('Reload!') sleep(0.3) node.reload.text.should == 'has been reloaded' node.text.should == 'has been reloaded' end it "should reload a parent node" do @session.visit('/with_js') node = @session.find(:css, '#reload-me').find(:css, 'em') @session.click_link('Reload!') sleep(0.3) node.reload.text.should == 'has been reloaded' node.text.should == 'has been reloaded' end it "should not automatically reload" do @session.visit('/with_js') node = @session.find(:css, '#reload-me') @session.click_link('Reload!') sleep(0.3) expect { node.text.to == 'has been reloaded' }.to raise_error end after { Capybara.automatic_reload = true } end context "with automatic reload" do it "should reload the current context of the node automatically" do @session.visit('/with_js') node = @session.find(:css, '#reload-me') @session.click_link('Reload!') sleep(0.3) node.text.should == 'has been reloaded' end it "should reload a parent node automatically" do @session.visit('/with_js') node = @session.find(:css, '#reload-me').find(:css, 'em') @session.click_link('Reload!') sleep(0.3) node.text.should == 'has been reloaded' end it "should reload a node automatically when using find" do @session.visit('/with_js') node = @session.find(:css, '#reload-me') @session.click_link('Reload!') sleep(0.3) node.find(:css, 'a').text.should == 'has been reloaded' end it "should not reload nodes which haven't been found" do @session.visit('/with_js') node = @session.all(:css, '#the-list li')[1] @session.click_link('Fetch new list!') sleep(0.3) expect { node.text.to == 'Foo' }.to raise_error expect { node.text.to == 'Bar' }.to raise_error end it "should reload nodes with options" do @session.visit('/with_js') node = @session.find(:css, 'em', :text => "reloaded") @session.click_link('Reload!') sleep(1) node.text.should == 'has been reloaded' end end end end capybara-2.1.0/lib/capybara/spec/session/save_page_spec.rb0000644000175000017500000000422612140721202022551 0ustar lunarlunarCapybara::SpecHelper.spec '#save_page' do let(:alternative_path) { File.join(Dir.pwd, "save_and_open_page_tmp") } before do @session.visit("/foo") end after do Capybara.save_and_open_page_path = nil Dir.glob("capybara-*.html").each do |file| FileUtils.rm(file) end FileUtils.rm_rf alternative_path end it "saves the page in the root directory" do @session.save_page path = Dir.glob("capybara-*.html").first File.read(path).should include("Another World") end it "generates a sensible filename" do @session.save_page path = Dir.glob("capybara-*.html").first filename = path.split("/").last filename.should =~ /^capybara-\d+\.html$/ end it "can store files in a specified directory" do Capybara.save_and_open_page_path = alternative_path @session.save_page path = Dir.glob(alternative_path + "/capybara-*.html").first File.read(path).should include("Another World") end it "uses the given filename" do @session.save_page("capybara-001122.html") File.read("capybara-001122.html").should include("Another World") end it "returns the filename" do result = @session.save_page path = Dir.glob("capybara-*.html").first filename = path.split("/").last result.should == filename end context "asset_host contains a string" do before { Capybara.asset_host = "http://example.com" } after { Capybara.asset_host = nil } it "prepends base tag with value from asset_host to the head" do @session.visit("/with_js") path = @session.save_page result = File.read(path) result.should include("") end it "doesn't prepend base tag to pages when asset_host is nil" do Capybara.asset_host = nil @session.visit("/with_js") path = @session.save_page result = File.read(path) result.should_not include("http://example.com") end it "doesn't prepend base tag to pages which already have it" do @session.visit("/with_base_tag") path = @session.save_page result = File.read(path) result.should_not include("http://example.com") end end end capybara-2.1.0/lib/capybara/spec/session/within_frame_spec.rb0000644000175000017500000000352312140721202023272 0ustar lunarlunarCapybara::SpecHelper.spec '#within_frame', :requires => [:frames] do before(:each) do @session.visit('/within_frames') end it "should find the div in frameOne" do @session.within_frame("frameOne") do @session.find("//*[@id='divInFrameOne']").text.should eql 'This is the text of divInFrameOne' end end it "should find the div in FrameTwo" do @session.within_frame("frameTwo") do @session.find("//*[@id='divInFrameTwo']").text.should eql 'This is the text of divInFrameTwo' end end it "should find the text div in the main window after finding text in frameOne" do @session.within_frame("frameOne") do @session.find("//*[@id='divInFrameOne']").text.should eql 'This is the text of divInFrameOne' end @session.find("//*[@id='divInMainWindow']").text.should eql 'This is the text for divInMainWindow' end it "should find the text div in the main window after finding text in frameTwo" do @session.within_frame("frameTwo") do @session.find("//*[@id='divInFrameTwo']").text.should eql 'This is the text of divInFrameTwo' end @session.find("//*[@id='divInMainWindow']").text.should eql 'This is the text for divInMainWindow' end it "should return the result of executing the block" do @session.within_frame("frameOne") { "return value" }.should eql "return value" end it "should find the div given Element" do element = @session.find(:id, 'frameOne') @session.within_frame element do @session.find("//*[@id='divInFrameOne']").text.should eql 'This is the text of divInFrameOne' end end it "should find multiple nested frames" do @session.within_frame 'parentFrame' do @session.within_frame 'childFrame' do @session.within_frame 'grandchildFrame1' do end @session.within_frame 'grandchildFrame2' do end end end end end capybara-2.1.0/lib/capybara/spec/session/screenshot.rb0000644000175000017500000000055112140721202021757 0ustar lunarlunar#coding: US-ASCII Capybara::SpecHelper.spec "#save_screenshot" do let(:image_path) { File.join(Dir.tmpdir, 'capybara-screenshot.png') } before do @session.visit '/' @session.save_screenshot image_path end it "should generate PNG file", :requires => [:screenshot] do magic = File.read(image_path, 4) magic.should eq "\x89PNG" end end capybara-2.1.0/lib/capybara/spec/session/click_link_spec.rb0000644000175000017500000001007412140721202022717 0ustar lunarlunarCapybara::SpecHelper.spec '#click_link' do before do @session.visit('/with_html') end it "should wait for asynchronous load", :requires => [:js] do @session.visit('/with_js') @session.click_link('Click me') @session.click_link('Has been clicked') end it "casts to string" do @session.click_link(:'foo') @session.should have_content('Another World') end context "with id given" do it "should take user to the linked page" do @session.click_link('foo') @session.should have_content('Another World') end end context "with text given" do it "should take user to the linked page" do @session.click_link('labore') @session.should have_content('Bar') end it "should accept partial matches" do @session.click_link('abo') @session.should have_content('Bar') end end context "with title given" do it "should take user to the linked page" do @session.click_link('awesome title') @session.should have_content('Bar') end it "should accept partial matches" do @session.click_link('some titl') @session.should have_content('Bar') end end context "with alternative text given to a contained image" do it "should take user to the linked page" do @session.click_link('awesome image') @session.should have_content('Bar') end it "should accept partial matches" do @session.click_link('some imag') @session.should have_content('Bar') end end context "with a locator that doesn't exist" do it "should raise an error" do msg = "Unable to find link \"does not exist\"" expect do @session.click_link('does not exist') end.to raise_error(Capybara::ElementNotFound, msg) end end context "with :href option given" do it "should find links with valid href" do @session.click_link('labore', :href => '/with_simple_html') @session.should have_content('Bar') end it "should raise error if link wasn't found" do expect { @session.click_link('labore', :href => 'invalid_href') }.to raise_error(Capybara::ElementNotFound) end end it "should follow relative links" do @session.visit('/') @session.click_link('Relative') @session.should have_content('This is a test') end it "should follow protocol relative links" do @session.click_link('Protocol') @session.should have_content('Another World') end it "should follow redirects" do @session.click_link('Redirect') @session.should have_content('You landed') end it "should follow redirects" do @session.click_link('BackToMyself') @session.should have_content('This is a test') end it "should add query string to current URL with naked query string" do @session.click_link('Naked Query String') @session.should have_content('Query String sent') end it "should do nothing on anchor links" do @session.fill_in("test_field", :with => 'blah') @session.click_link('Normal Anchor') @session.find_field("test_field").value.should == 'blah' @session.click_link('Blank Anchor') @session.find_field("test_field").value.should == 'blah' end it "should do nothing on URL+anchor links for the same page" do @session.fill_in("test_field", :with => 'blah') @session.click_link('Anchor on same page') @session.find_field("test_field").value.should == 'blah' end it "should follow link on URL+anchor links for a different page" do @session.click_link('Anchor on different page') @session.should have_content('Bar') end it "raise an error with links with no href" do expect do @session.click_link('No Href') end.to raise_error(Capybara::ElementNotFound) end context "with :exact option" do it "should accept partial matches when false" do @session.click_link('abo', :exact => false) @session.should have_content('Bar') end it "should not accept partial matches when true" do expect do @session.click_link('abo', :exact => true) end.to raise_error(Capybara::ElementNotFound) end end end capybara-2.1.0/lib/capybara/spec/session/headers.rb0000644000175000017500000000036412140721202021217 0ustar lunarlunarCapybara::SpecHelper.spec '#response_headers' do it "should return response headers", :requires => [:response_headers] do @session.visit('/with_simple_html') @session.response_headers['Content-Type'].should =~ %r(text/html) end end capybara-2.1.0/lib/capybara/spec/session/current_scope_spec.rb0000644000175000017500000000144412140721202023471 0ustar lunarlunarCapybara::SpecHelper.spec '#current_scope' do before do @session.visit('/with_scope') end context "when not in a #within block" do it "should return the document" do @session.current_scope.should be_kind_of Capybara::Node::Document end end context "when in a #within block" do it "should return the element in scope" do @session.within(:css, "#simple_first_name") do @session.current_scope[:name].should eq 'first_name' end end end context "when in a nested #within block" do it "should return the element in scope" do @session.within("//div[@id='for_bar']") do @session.within(".//input[@value='Peter']") do @session.current_scope[:name].should eq 'form[first_name]' end end end end endcapybara-2.1.0/lib/capybara/spec/session/has_title_spec.rb0000644000175000017500000000231212140721202022565 0ustar lunarlunarCapybara::SpecHelper.spec '#has_title?' do before do @session.visit('/with_js') end it "should be true if the page has the given title" do @session.should have_title('with_js') end it "should allow regexp matches" do @session.should have_title(/w[a-z]{3}_js/) @session.should_not have_title(/monkey/) end it "should wait for title", :requires => [:js] do @session.click_link("Change title") @session.should have_title("changed title") end it "should be false if the page has not the given title" do @session.should_not have_title('monkey') end end Capybara::SpecHelper.spec '#has_no_title?' do before do @session.visit('/with_js') end it "should be false if the page has the given title" do @session.should_not have_no_title('with_js') end it "should allow regexp matches" do @session.should_not have_no_title(/w[a-z]{3}_js/) @session.should have_no_title(/monkey/) end it "should wait for title to disappear", :requires => [:js] do @session.click_link("Change title") @session.should have_no_title('with_js') end it "should be true if the page has not the given title" do @session.should have_no_title('monkey') end end capybara-2.1.0/lib/capybara/spec/session/all_spec.rb0000644000175000017500000000533212140721202021366 0ustar lunarlunarCapybara::SpecHelper.spec "#all" do before do @session.visit('/with_html') end it "should find all elements using the given locator" do @session.all('//p').should have(3).elements @session.all('//h1').first.text.should == 'This is a test' @session.all("//input[@id='test_field']").first[:value].should == 'monkey' end it "should return an empty array when nothing was found" do @session.all('//div[@id="nosuchthing"]').should be_empty end it "should accept an XPath instance" do @session.visit('/form') @xpath = XPath::HTML.fillable_field('Name') @result = @session.all(@xpath).map { |r| r.value } @result.should include('Smith', 'John', 'John Smith') end it "should raise an error when given invalid options" do expect { @session.all('//p', :schmoo => "foo") }.to raise_error(ArgumentError) end context "with css selectors" do it "should find all elements using the given selector" do @session.all(:css, 'h1').first.text.should == 'This is a test' @session.all(:css, "input[id='test_field']").first[:value].should == 'monkey' end it "should find all elements when given a list of selectors" do @session.all(:css, 'h1, p').should have(4).elements end end context "with xpath selectors" do it "should find the first element using the given locator" do @session.all(:xpath, '//h1').first.text.should == 'This is a test' @session.all(:xpath, "//input[@id='test_field']").first[:value].should == 'monkey' end end context "with css as default selector" do before { Capybara.default_selector = :css } it "should find the first element using the given locator" do @session.all('h1').first.text.should == 'This is a test' @session.all("input[id='test_field']").first[:value].should == 'monkey' end end context "with visible filter" do it "should only find visible nodes when true" do @session.all(:css, "a.simple", :visible => true).should have(1).elements end it "should find nodes regardless of whether they are invisible when false" do @session.all(:css, "a.simple", :visible => false).should have(2).elements end it "should default to Capybara.ignore_hidden_elements" do Capybara.ignore_hidden_elements = true @session.all(:css, "a.simple").should have(1).elements Capybara.ignore_hidden_elements = false @session.all(:css, "a.simple").should have(2).elements end end context "within a scope" do before do @session.visit('/with_scope') end it "should find any element using the given locator" do @session.within(:xpath, "//div[@id='for_bar']") do @session.all('.//li').should have(2).elements end end end end capybara-2.1.0/lib/capybara/spec/session/fill_in_spec.rb0000644000175000017500000001344612140721202022237 0ustar lunarlunarCapybara::SpecHelper.spec "#fill_in" do before do @session.visit('/form') end it "should fill in a text field by id" do @session.fill_in('form_first_name', :with => 'Harry') @session.click_button('awesome') extract_results(@session)['first_name'].should == 'Harry' end it "should fill in a text field by name" do @session.fill_in('form[last_name]', :with => 'Green') @session.click_button('awesome') extract_results(@session)['last_name'].should == 'Green' end it "should fill in a text field by label without for" do @session.fill_in('First Name', :with => 'Harry') @session.click_button('awesome') extract_results(@session)['first_name'].should == 'Harry' end it "should fill in a url field by label without for" do @session.fill_in('Html5 Url', :with => 'http://www.avenueq.com') @session.click_button('html5_submit') extract_results(@session)['html5_url'].should == 'http://www.avenueq.com' end it "should fill in a textarea by id" do @session.fill_in('form_description', :with => 'Texty text') @session.click_button('awesome') extract_results(@session)['description'].should == 'Texty text' end it "should fill in a textarea by label" do @session.fill_in('Description', :with => 'Texty text') @session.click_button('awesome') extract_results(@session)['description'].should == 'Texty text' end it "should fill in a textarea by name" do @session.fill_in('form[description]', :with => 'Texty text') @session.click_button('awesome') extract_results(@session)['description'].should == 'Texty text' end it "should fill in a password field by id" do @session.fill_in('form_password', :with => 'supasikrit') @session.click_button('awesome') extract_results(@session)['password'].should == 'supasikrit' end it "should handle HTML in a textarea" do @session.fill_in('form_description', :with => 'is very secret!') @session.click_button('awesome') extract_results(@session)['description'].should == 'is very secret!' end it "should fill in a field with a custom type" do @session.fill_in('Schmooo', :with => 'Schmooo is the game') @session.click_button('awesome') extract_results(@session)['schmooo'].should == 'Schmooo is the game' end it "should fill in a field without a type" do @session.fill_in('Phone', :with => '+1 555 7022') @session.click_button('awesome') extract_results(@session)['phone'].should == '+1 555 7022' end it "should fill in a text field respecting its maxlength attribute" do @session.fill_in('Zipcode', :with => '52071350') @session.click_button('awesome') extract_results(@session)['zipcode'].should == '52071' end it "should fill in a password field by name" do @session.fill_in('form[password]', :with => 'supasikrit') @session.click_button('awesome') extract_results(@session)['password'].should == 'supasikrit' end it "should fill in a password field by label" do @session.fill_in('Password', :with => 'supasikrit') @session.click_button('awesome') extract_results(@session)['password'].should == 'supasikrit' end it "should fill in a password field by name" do @session.fill_in('form[password]', :with => 'supasikrit') @session.click_button('awesome') extract_results(@session)['password'].should == 'supasikrit' end it "should throw an exception if a hash containing 'with' is not provided" do lambda{@session.fill_in 'Name', 'ignu'}.should raise_error end it "should wait for asynchronous load", :requires => [:js] do @session.visit('/with_js') @session.click_link('Click me') @session.fill_in('new_field', :with => 'Testing...') end it "casts to string" do @session.fill_in(:'form_first_name', :with => :'Harry') @session.click_button('awesome') extract_results(@session)['first_name'].should == 'Harry' end it "casts to string if field has maxlength", :focus => true do @session.fill_in(:'form_zipcode', :with => 1234567) @session.click_button('awesome') extract_results(@session)['zipcode'].should == '12345' end context 'on a pre-populated textfield with a reformatting onchange', :requires => [:js] do it 'should only trigger onchange once' do @session.visit('/with_js') @session.fill_in('with_change_event', :with => 'some value') @session.find(:css, '#with_change_event').value.should == 'some value' end end context "with ignore_hidden_fields" do before { Capybara.ignore_hidden_elements = true } after { Capybara.ignore_hidden_elements = false } it "should not find a hidden field" do msg = "Unable to find field \"Super Secret\"" expect do @session.fill_in('Super Secret', :with => '777') end.to raise_error(Capybara::ElementNotFound, msg) end end context "with a locator that doesn't exist" do it "should raise an error" do msg = "Unable to find field \"does not exist\"" expect do @session.fill_in('does not exist', :with => 'Blah blah') end.to raise_error(Capybara::ElementNotFound, msg) end end context "on a disabled field" do it "should raise an error" do expect do @session.fill_in('Disabled Text Field', :with => 'Blah blah') end.to raise_error(Capybara::ElementNotFound) end end context "with :exact option" do it "should accept partial matches when false" do @session.fill_in("Explanation", :with => "Dude", :exact => false) @session.click_button("awesome") extract_results(@session)["name_explanation"].should == "Dude" end it "should not accept partial matches when true" do expect do @session.fill_in("Explanation", :with => "Dude", :exact => true) end.to raise_error(Capybara::ElementNotFound) end end end capybara-2.1.0/lib/capybara/spec/session/html_spec.rb0000644000175000017500000000221312140721202021555 0ustar lunarlunarCapybara::SpecHelper.spec '#html' do it "should return the unmodified page body" do @session.visit('/') @session.html.should include('Hello world!') end it "should return the current state of the page", :requires => [:js] do @session.visit('/with_js') @session.html.should include('I changed it') @session.html.should_not include('This is text') end end Capybara::SpecHelper.spec '#source' do it "should return the unmodified page source" do @session.visit('/') @session.source.should include('Hello world!') end it "should return the current state of the page", :requires => [:js] do @session.visit('/with_js') @session.source.should include('I changed it') @session.source.should_not include('This is text') end end Capybara::SpecHelper.spec '#body' do it "should return the unmodified page source" do @session.visit('/') @session.body.should include('Hello world!') end it "should return the current state of the page", :requires => [:js] do @session.visit('/with_js') @session.body.should include('I changed it') @session.body.should_not include('This is text') end end capybara-2.1.0/lib/capybara/spec/session/attach_file_spec.rb0000644000175000017500000000772612140721202023072 0ustar lunarlunarCapybara::SpecHelper.spec "#attach_file" do before do @test_file_path = File.expand_path('../fixtures/test_file.txt', File.dirname(__FILE__)) @another_test_file_path = File.expand_path('../fixtures/another_test_file.txt', File.dirname(__FILE__)) @test_jpg_file_path = File.expand_path('../fixtures/capybara.jpg', File.dirname(__FILE__)) @session.visit('/form') end context "with normal form" do it "should set a file path by id" do @session.attach_file "form_image", __FILE__ @session.click_button('awesome') extract_results(@session)['image'].should == File.basename(__FILE__) end it "should set a file path by label" do @session.attach_file "Image", __FILE__ @session.click_button('awesome') extract_results(@session)['image'].should == File.basename(__FILE__) end it "casts to string" do @session.attach_file :"form_image", __FILE__ @session.click_button('awesome') extract_results(@session)['image'].should == File.basename(__FILE__) end end context "with multipart form" do it "should set a file path by id" do @session.attach_file "form_document", @test_file_path @session.click_button('Upload Single') @session.should have_content(File.read(@test_file_path)) end it "should set a file path by label" do @session.attach_file "Single Document", @test_file_path @session.click_button('Upload Single') @session.should have_content(File.read(@test_file_path)) end it "should not break if no file is submitted" do @session.click_button('Upload Single') @session.should have_content('No file uploaded') end it "should send content type text/plain when uploading a text file" do @session.attach_file "Single Document", @test_file_path @session.click_button 'Upload Single' @session.should have_content('text/plain') end it "should send content type image/jpeg when uploading an image" do @session.attach_file "Single Document", @test_jpg_file_path @session.click_button 'Upload Single' @session.should have_content('image/jpeg') end it "should not break when using HTML5 multiple file input" do @session.attach_file "Multiple Documents", @test_file_path @session.click_button('Upload Multiple') @session.body.should include("1 | ")#number of files @session.should have_content(File.read(@test_file_path)) end it "should not break when using HTML5 multiple file input uploading multiple files" do pending "Selenium is buggy on this, see http://code.google.com/p/selenium/issues/detail?id=2239" if @session.respond_to?(:mode) && @session.mode == :selenium @session.attach_file "Multiple Documents", [@test_file_path, @another_test_file_path] @session.click_button('Upload Multiple') @session.body.should include("2 | ")#number of files @session.body.should include(File.read(@test_file_path)) @session.body.should include(File.read(@another_test_file_path)) end end context "with a locator that doesn't exist" do it "should raise an error" do msg = "Unable to find file field \"does not exist\"" expect do @session.attach_file('does not exist', @test_file_path) end.to raise_error(Capybara::ElementNotFound, msg) end end context "with a path that doesn't exist" do it "should raise an error" do expect { @session.attach_file('Image', '/no_such_file.png') }.to raise_error(Capybara::FileNotFound) end end context "with :exact option" do it "should set a file path by partial label when false" do @session.attach_file "Imag", __FILE__, :exact => false @session.click_button('awesome') extract_results(@session)['image'].should == File.basename(__FILE__) end it "not allow partial matches when true" do expect do @session.attach_file "Imag", __FILE__, :exact => true end.to raise_error(Capybara::ElementNotFound) end end end capybara-2.1.0/lib/capybara/spec/session/execute_script_spec.rb0000644000175000017500000000047112140721202023643 0ustar lunarlunarCapybara::SpecHelper.spec "#execute_script", :requires => [:js] do it "should execute the given script and return nothing" do @session.visit('/with_js') @session.execute_script("$('#change').text('Funky Doodle')").should be_nil @session.should have_css('#change', :text => 'Funky Doodle') end end capybara-2.1.0/lib/capybara/spec/session/visit_spec.rb0000644000175000017500000000572412140721202021761 0ustar lunarlunarCapybara::SpecHelper.spec '#visit' do it "should fetch a response from the driver with a relative url" do @session.visit('/') @session.should have_content('Hello world!') @session.visit('/foo') @session.should have_content('Another World') end it "should fetch a response from the driver with an absolute url with a port" do # Preparation @session.visit('/') root_uri = URI.parse(@session.current_url) @session.visit("http://#{root_uri.host}:#{root_uri.port}/") @session.should have_content('Hello world!') @session.visit("http://#{root_uri.host}:#{root_uri.port}/foo") @session.should have_content('Another World') end context "when Capybara.always_include_port is true" do let(:root_uri) do @session.visit('/') URI.parse(@session.current_url) end before(:each) do Capybara.always_include_port = true end after(:each) do Capybara.always_include_port = false end it "should fetch a response from the driver with an absolute url without a port" do @session.visit("http://#{root_uri.host}/") URI.parse(@session.current_url).port.should == root_uri.port @session.should have_content('Hello world!') @session.visit("http://#{root_uri.host}/foo") URI.parse(@session.current_url).port.should == root_uri.port @session.should have_content('Another World') end end context "without a server", :requires => [:server] do it "should respect `app_host`" do serverless_session = Capybara::Session.new(@session.mode, nil) Capybara.app_host = "http://#{@session.server.host}:#{@session.server.port}" serverless_session.visit("/foo") serverless_session.should have_content("Another World") end it "should visit a fully qualified URL" do serverless_session = Capybara::Session.new(@session.mode, nil) serverless_session.visit("http://#{@session.server.host}:#{@session.server.port}/foo") serverless_session.should have_content("Another World") end end it "should send no referer when visiting a page" do @session.visit '/get_referer' @session.should have_content 'No referer' end it "should send no referer when visiting a second page" do @session.visit '/get_referer' @session.visit '/get_referer' @session.should have_content 'No referer' end it "should send a referer when following a link" do @session.visit '/referer_base' @session.find('//a[@href="/get_referer"]').click @session.should have_content %r{http://.*/referer_base} end it "should preserve the original referer URL when following a redirect" do @session.visit('/referer_base') @session.find('//a[@href="/redirect_to_get_referer"]').click @session.should have_content %r{http://.*/referer_base} end it "should send a referer when submitting a form" do @session.visit '/referer_base' @session.find('//input').click @session.should have_content %r{http://.*/referer_base} end end capybara-2.1.0/lib/capybara/spec/session/find_field_spec.rb0000644000175000017500000000344612140721202022705 0ustar lunarlunarCapybara::SpecHelper.spec '#find_field' do before do @session.visit('/form') end it "should find any field" do @session.find_field('Dog').value.should == 'dog' @session.find_field('form_description').text.should == 'Descriptive text goes here' @session.find_field('Region')[:name].should == 'form[region]' end it "casts to string" do @session.find_field(:'Dog').value.should == 'dog' end it "should raise error if the field doesn't exist" do expect do @session.find_field('Does not exist') end.to raise_error(Capybara::ElementNotFound) end it "should be aliased as 'field_labeled' for webrat compatibility" do @session.field_labeled('Dog').value.should == 'dog' expect do @session.field_labeled('Does not exist') end.to raise_error(Capybara::ElementNotFound) end context "with :exact option" do it "should accept partial matches when false" do @session.find_field("Explanation", :exact => false)[:name].should == "form[name_explanation]" end it "should not accept partial matches when true" do expect do @session.find_field("Explanation", :exact => true) end.to raise_error(Capybara::ElementNotFound) end end context "with :disabled option" do it "should find disabled fields when true" do @session.find_field("Disabled Checkbox", :disabled => true)[:name].should == "form[disabled_checkbox]" end it "should not find disabled fields when false" do expect do @session.find_field("Disabled Checkbox", :disabled => false) end.to raise_error(Capybara::ElementNotFound) end it "should not find disabled fields by default" do expect do @session.find_field("Disabled Checkbox") end.to raise_error(Capybara::ElementNotFound) end end end capybara-2.1.0/lib/capybara/spec/session/has_select_spec.rb0000644000175000017500000001747412140721202022742 0ustar lunarlunarCapybara::SpecHelper.spec '#has_select?' do before { @session.visit('/form') } it "should be true if the field is on the page" do @session.should have_select('Locale') @session.should have_select('form_region') @session.should have_select('Languages') @session.should have_select(:'Languages') end it "should be false if the field is not on the page" do @session.should_not have_select('Monkey') end context 'with selected value' do it "should be true if a field with the given value is on the page" do @session.should have_select('form_locale', :selected => 'English') @session.should have_select('Region', :selected => 'Norway') @session.should have_select('Underwear', :selected => [ 'Boxerbriefs', 'Briefs', 'Commando', "Frenchman's Pantalons", 'Long Johns' ]) end it "should be false if the given field is not on the page" do @session.should_not have_select('Locale', :selected => 'Swedish') @session.should_not have_select('Does not exist', :selected => 'John') @session.should_not have_select('City', :selected => 'Not there') @session.should_not have_select('Underwear', :selected => [ 'Boxerbriefs', 'Briefs', 'Commando', "Frenchman's Pantalons", 'Long Johns', 'Nonexistant' ]) @session.should_not have_select('Underwear', :selected => [ 'Boxerbriefs', 'Briefs', 'Boxers', 'Commando', "Frenchman's Pantalons", 'Long Johns' ]) @session.should_not have_select('Underwear', :selected => [ 'Boxerbriefs', 'Briefs','Commando', "Frenchman's Pantalons" ]) end it "should be true after the given value is selected" do @session.select('Swedish', :from => 'Locale') @session.should have_select('Locale', :selected => 'Swedish') end it "should be false after a different value is selected" do @session.select('Swedish', :from => 'Locale') @session.should_not have_select('Locale', :selected => 'English') end it "should be true after the given values are selected" do @session.select('Boxers', :from => 'Underwear') @session.should have_select('Underwear', :selected => [ 'Boxerbriefs', 'Briefs', 'Boxers', 'Commando', "Frenchman's Pantalons", 'Long Johns' ]) end it "should be false after one of the values is unselected" do @session.unselect('Briefs', :from => 'Underwear') @session.should_not have_select('Underwear', :selected => [ 'Boxerbriefs', 'Briefs', 'Commando', "Frenchman's Pantalons", 'Long Johns' ]) end end context 'with exact options' do it "should be true if a field with the given options is on the page" do @session.should have_select('Region', :options => ['Norway', 'Sweden', 'Finland']) @session.should have_select('Tendency', :options => []) end it "should be false if the given field is not on the page" do @session.should_not have_select('Locale', :options => ['Swedish']) @session.should_not have_select('Does not exist', :options => ['John']) @session.should_not have_select('City', :options => ['London', 'Made up city']) @session.should_not have_select('Region', :options => ['Norway', 'Sweden']) @session.should_not have_select('Region', :options => ['Norway', 'Norway', 'Norway']) end end context 'with partial options' do it "should be true if a field with the given partial options is on the page" do @session.should have_select('Region', :with_options => ['Norway', 'Sweden']) @session.should have_select('City', :with_options => ['London']) end it "should be false if a field with the given partial options is not on the page" do @session.should_not have_select('Locale', :with_options => ['Uruguayan']) @session.should_not have_select('Does not exist', :with_options => ['John']) @session.should_not have_select('Region', :with_options => ['Norway', 'Sweden', 'Finland', 'Latvia']) end end end Capybara::SpecHelper.spec '#has_no_select?' do before { @session.visit('/form') } it "should be false if the field is on the page" do @session.should_not have_no_select('Locale') @session.should_not have_no_select('form_region') @session.should_not have_no_select('Languages') end it "should be true if the field is not on the page" do @session.should have_no_select('Monkey') end context 'with selected value' do it "should be false if a field with the given value is on the page" do @session.should_not have_no_select('form_locale', :selected => 'English') @session.should_not have_no_select('Region', :selected => 'Norway') @session.should_not have_no_select('Underwear', :selected => [ 'Boxerbriefs', 'Briefs', 'Commando', "Frenchman's Pantalons", 'Long Johns' ]) end it "should be true if the given field is not on the page" do @session.should have_no_select('Locale', :selected => 'Swedish') @session.should have_no_select('Does not exist', :selected => 'John') @session.should have_no_select('City', :selected => 'Not there') @session.should have_no_select('Underwear', :selected => [ 'Boxerbriefs', 'Briefs', 'Commando', "Frenchman's Pantalons", 'Long Johns', 'Nonexistant' ]) @session.should have_no_select('Underwear', :selected => [ 'Boxerbriefs', 'Briefs', 'Boxers', 'Commando', "Frenchman's Pantalons", 'Long Johns' ]) @session.should have_no_select('Underwear', :selected => [ 'Boxerbriefs', 'Briefs','Commando', "Frenchman's Pantalons" ]) end it "should be false after the given value is selected" do @session.select('Swedish', :from => 'Locale') @session.should_not have_no_select('Locale', :selected => 'Swedish') end it "should be true after a different value is selected" do @session.select('Swedish', :from => 'Locale') @session.should have_no_select('Locale', :selected => 'English') end it "should be false after the given values are selected" do @session.select('Boxers', :from => 'Underwear') @session.should_not have_no_select('Underwear', :selected => [ 'Boxerbriefs', 'Briefs', 'Boxers', 'Commando', "Frenchman's Pantalons", 'Long Johns' ]) end it "should be true after one of the values is unselected" do @session.unselect('Briefs', :from => 'Underwear') @session.should have_no_select('Underwear', :selected => [ 'Boxerbriefs', 'Briefs', 'Commando', "Frenchman's Pantalons", 'Long Johns' ]) end end context 'with exact options' do it "should be false if a field with the given options is on the page" do @session.should_not have_no_select('Region', :options => ['Norway', 'Sweden', 'Finland']) end it "should be true if the given field is not on the page" do @session.should have_no_select('Locale', :options => ['Swedish']) @session.should have_no_select('Does not exist', :options => ['John']) @session.should have_no_select('City', :options => ['London', 'Made up city']) @session.should have_no_select('Region', :options => ['Norway', 'Sweden']) @session.should have_no_select('Region', :options => ['Norway', 'Norway', 'Norway']) end end context 'with partial options' do it "should be false if a field with the given partial options is on the page" do @session.should_not have_no_select('Region', :with_options => ['Norway', 'Sweden']) @session.should_not have_no_select('City', :with_options => ['London']) end it "should be true if a field with the given partial options is not on the page" do @session.should have_no_select('Locale', :with_options => ['Uruguayan']) @session.should have_no_select('Does not exist', :with_options => ['John']) @session.should have_no_select('Region', :with_options => ['Norway', 'Sweden', 'Finland', 'Latvia']) end end end capybara-2.1.0/lib/capybara/spec/session/click_button_spec.rb0000644000175000017500000003102212140721202023271 0ustar lunarlunarCapybara::SpecHelper.spec '#click_button' do before do @session.visit('/form') end it "should wait for asynchronous load", :requires => [:js] do @session.visit('/with_js') @session.click_link('Click me') @session.click_button('New Here') end it "casts to string" do @session.click_button(:'Relative Action') @session.current_path.should == '/relative' extract_results(@session)['relative'].should == 'Relative Action' end context "with multiple values with the same name" do it "should use the latest given value" do @session.check('Terms of Use') @session.click_button('awesome') extract_results(@session)['terms_of_use'].should == '1' end end context "with a form that has a relative url as an action" do it "should post to the correct url" do @session.click_button('Relative Action') @session.current_path.should == '/relative' extract_results(@session)['relative'].should == 'Relative Action' end end context "with a form that has no action specified" do it "should post to the correct url" do @session.click_button('No Action') @session.current_path.should == '/form' extract_results(@session)['no_action'].should == 'No Action' end end context "with value given on a submit button" do context "on a form with HTML5 fields" do before do @session.click_button('html5_submit') @results = extract_results(@session) end it "should serialise and submit search fields" do @results['html5_search'].should == 'what are you looking for' end it "should serialise and submit email fields" do @results['html5_email'].should == 'person@email.com' end it "should serialise and submit url fields" do @results['html5_url'].should == 'http://www.example.com' end it "should serialise and submit tel fields" do @results['html5_tel'].should == '911' end it "should serialise and submit color fields" do @results['html5_color'].upcase.should == '#FFFFFF' end end context "on an HTML4 form" do before do @session.click_button('awesome') @results = extract_results(@session) end it "should serialize and submit text fields" do @results['first_name'].should == 'John' end it "should escape fields when submitting" do @results['phone'].should == '+1 555 7021' end it "should serialize and submit password fields" do @results['password'].should == 'seeekrit' end it "should serialize and submit hidden fields" do @results['token'].should == '12345' end it "should not serialize fields from other forms" do @results['middle_name'].should be_nil end it "should submit the button that was clicked, but not other buttons" do @results['awesome'].should == 'awesome' @results['crappy'].should be_nil end it "should serialize radio buttons" do @results['gender'].should == 'female' end it "should serialize check boxes" do @results['pets'].should include('dog', 'hamster') @results['pets'].should_not include('cat') end it "should serialize text areas" do @results['description'].should == 'Descriptive text goes here' end it "should serialize select tag with values" do @results['locale'].should == 'en' end it "should serialize select tag without values" do @results['region'].should == 'Norway' end it "should serialize first option for select tag with no selection" do @results['city'].should == 'London' end it "should not serialize a select tag without options" do @results['tendency'].should be_nil end it "should not submit disabled fields" do @results['disabled_text_field'].should be_nil @results['disabled_textarea'].should be_nil @results['disabled_checkbox'].should be_nil @results['disabled_radio'].should be_nil @results['disabled_select'].should be_nil @results['disabled_file'].should be_nil end end end context "with id given on a submit button" do it "should submit the associated form" do @session.click_button('awe123') extract_results(@session)['first_name'].should == 'John' end it "should work with partial matches" do @session.click_button('Go') @session.should have_content('You landed') end end context "with title given on a submit button" do it "should submit the associated form" do @session.click_button('What an Awesome Button') extract_results(@session)['first_name'].should == 'John' end it "should work with partial matches" do @session.click_button('What an Awesome') extract_results(@session)['first_name'].should == 'John' end end context "with fields associated with the form using the form attribute" do before do @session.click_button('submit_form1') @results = extract_results(@session) end it "should serialize and submit text fields" do @results['outside_input'].should == 'outside_input' end it "should serialize text areas" do @results['outside_textarea'].should == 'Some text here' end it "should serialize select tags" do @results['outside_select'].should == 'Ruby' end it "should not serliaze fields associated with a different form" do @results['for_form2'].should be_nil end end context "with submit button outside the form defined by capybara-2.1.0/lib/capybara/spec/views/tables.erb0000644000175000017500000000235012140721202020672 0ustar lunarlunar
    Agent
    Girl
    Villain
    capybara-2.1.0/lib/capybara/spec/views/fieldsets.erb0000644000175000017500000000125212140721202021402 0ustar lunarlunar
    Agent

    Villain

    capybara-2.1.0/lib/capybara/spec/views/within_frames.erb0000644000175000017500000000052112140721202022255 0ustar lunarlunar With Frames
    This is the text for divInMainWindow
    capybara-2.1.0/lib/capybara/spec/views/within_popups.erb0000644000175000017500000000117212140721202022331 0ustar lunarlunar With Popups
    This is the text for divInMainWindow
    capybara-2.1.0/lib/capybara/spec/views/header_links.erb0000644000175000017500000000021112140721202022042 0ustar lunarlunar

    Link

    capybara-2.1.0/lib/capybara/spec/views/popup_two.erb0000644000175000017500000000027312140721202021456 0ustar lunarlunar This is the title of popup two
    This is the text of divInPopupTwo
    capybara-2.1.0/lib/capybara/spec/views/frame_one.erb0000644000175000017500000000027212140721202021354 0ustar lunarlunar This is the title of frame one
    This is the text of divInFrameOne
    capybara-2.1.0/lib/capybara/spec/views/with_base_tag.erb0000644000175000017500000000043512140721202022222 0ustar lunarlunar with_external_source

    FooBar

    with_js

    FooBar

    This is text

    This is a draggable element.

    It should be dropped here.

    Click me

    Slowly

    Reload! this won't change

    waiting to be reloaded

    Fetch new list!

    • Item 1
    • Item 2

    Change title

    capybara-2.1.0/lib/capybara/spec/views/with_html_entities.erb0000644000175000017500000000005412140721202023322 0ustar lunarlunarEncoding with — html entities » capybara-2.1.0/lib/capybara/spec/views/frame_two.erb0000644000175000017500000000027212140721202021404 0ustar lunarlunar This is the title of frame two
    This is the text of divInFrameTwo
    capybara-2.1.0/lib/capybara/spec/views/form.erb0000644000175000017500000003132112140721202020363 0ustar lunarlunar

    Form


    First address

    Second address

    capybara-2.1.0/lib/capybara/spec/views/with_count.erb0000644000175000017500000000017612140721202021607 0ustar lunarlunar

    This page is used for testing number options of has_text?

    count1

    2 count

    Count

    capybara-2.1.0/lib/capybara/spec/views/with_hover.erb0000644000175000017500000000076312140721202021604 0ustar lunarlunar with_hover
    Some text here so the wrapper has size
    Here I am
    capybara-2.1.0/lib/capybara/spec/views/with_simple_html.erb0000644000175000017500000000000312140721202022761 0ustar lunarlunarBarcapybara-2.1.0/lib/capybara/spec/views/popup_one.erb0000644000175000017500000000030112140721202021416 0ustar lunarlunar This is the title of the first popup
    This is the text of divInPopupOne
    capybara-2.1.0/lib/capybara/spec/views/with_html.erb0000644000175000017500000000725512140721202021430 0ustar lunarlunar

    This is a test

    Header Class Test One

    Header Class Test Two

    Header Class Test Three

    Header Class Test Four

    Header Class Test Five

    42

    Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. awesome image

    Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat Redirect pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia text with   whitespace id est laborum.

    BackToMyself A link came first A link A link with data-method A link with capitalized data-method No Href Blank Href Blank Anchor Normal Anchor Anchor on different page Anchor on same page Relative Protocol very fine image fine image Disabled link Naked Query String <% if params[:query_string] %> Query String sent <% end %>

    Some of this text is hidden!
    visible link
    Number 42
    • John
    • Paul
    • George
    • Ringo
    singular
    multiple one
    multiple two
    almost singular but not quite
    almost singular
    capybara-2.1.0/lib/capybara/spec/views/with_title.erb0000644000175000017500000000003112140721202021566 0ustar lunarlunarTest Titlecapybara-2.1.0/lib/capybara/spec/views/frame_parent.erb0000644000175000017500000000025512140721202022065 0ustar lunarlunar This is the parent frame title capybara-2.1.0/lib/capybara/spec/views/frame_child.erb0000644000175000017500000000035712140721202021662 0ustar lunarlunar This is the child frame title capybara-2.1.0/lib/capybara/spec/test_app.rb0000644000175000017500000000636612140721202017750 0ustar lunarlunarrequire 'sinatra/base' require 'rack' require 'yaml' class TestApp < Sinatra::Base class TestAppError < StandardError; end set :root, File.dirname(__FILE__) set :static, true set :raise_errors, true set :show_exceptions, false # Also check lib/capybara/spec/views/*.erb for pages not listed here get '/' do 'Hello world! Relative' end get '/foo' do 'Another World' end get '/redirect' do redirect '/redirect_again' end get '/redirect_again' do redirect '/landed' end get '/referer_base' do 'direct link' + 'link via redirect' + '
    ' end get '/redirect_to_get_referer' do redirect '/get_referer' end get '/get_referer' do request.referer.nil? ? "No referer" : "Got referer: #{request.referer}" end get '/host' do "Current host is #{request.scheme}://#{request.host}:#{request.port}" end get '/redirect/:times/times' do times = params[:times].to_i if times.zero? "redirection complete" else redirect "/redirect/#{times - 1}/times" end end get '/landed' do "You landed" end get '/with-quotes' do %q{"No," he said, "you can't do that."} end get '/form/get' do '
    ' + params[:form].to_yaml + '
    ' end post '/relative' do '
    ' + params[:form].to_yaml + '
    ' end get '/favicon.ico' do nil end post '/redirect' do redirect '/redirect_again' end delete "/delete" do "The requested object was deleted" end get "/delete" do "Not deleted" end get '/redirect_back' do redirect back end get '/redirect_secure' do redirect "https://#{request.host}:#{request.port}/host" end get '/slow_response' do sleep 2 'Finally!' end get '/set_cookie' do cookie_value = 'test_cookie' response.set_cookie('capybara', cookie_value) "Cookie set to #{cookie_value}" end get '/get_cookie' do request.cookies['capybara'] end get '/get_header' do env['HTTP_FOO'] end get '/get_header_via_redirect' do redirect '/get_header' end get '/error' do raise TestAppError, "some error" end get '/:view' do |view| erb view.to_sym end post '/form' do '
    ' + params[:form].to_yaml + '
    ' end post '/upload_empty' do if params[:form][:file].nil? 'Successfully ignored empty file field.' else 'Something went wrong.' end end post '/upload' do begin buffer = [] buffer << "Content-type: #{params[:form][:document][:type]}" buffer << "File content: #{params[:form][:document][:tempfile].read}" buffer.join(' | ') rescue 'No file uploaded' end end post '/upload_multiple' do begin buffer = ["#{params[:form][:multiple_documents].size}"] params[:form][:multiple_documents].each do |doc| buffer << "Content-type: #{doc[:type]}" buffer << "File content: #{doc[:tempfile].read}" end buffer.join(' | ') rescue 'No files uploaded' end end end if __FILE__ == $0 Rack::Handler::WEBrick.run TestApp, :Port => 8070 end capybara-2.1.0/lib/capybara/query.rb0000644000175000017500000000646312140721202016342 0ustar lunarlunarmodule Capybara class Query attr_accessor :selector, :locator, :options, :expression, :find, :negative VALID_KEYS = [:text, :visible, :between, :count, :maximum, :minimum, :exact, :match, :wait] VALID_MATCH = [:first, :smart, :prefer_exact, :one] def initialize(*args) @options = if args.last.is_a?(Hash) then args.pop.dup else {} end if args[0].is_a?(Symbol) @selector = Selector.all[args[0]] @locator = args[1] else @selector = Selector.all.values.find { |s| s.match?(args[0]) } @locator = args[0] end @selector ||= Selector.all[Capybara.default_selector] # for compatibility with Capybara 2.0 if Capybara.exact_options and @selector == Selector.all[:option] @options[:exact] = true end @expression = @selector.call(@locator) assert_valid_keys! end def name; selector.name; end def label; selector.label or selector.name; end def description @description = "#{label} #{locator.inspect}" @description << " with text #{options[:text].inspect}" if options[:text] @description end def matches_filters?(node) if options[:text] regexp = options[:text].is_a?(Regexp) ? options[:text] : Regexp.escape(options[:text].to_s) return false if not node.text(visible).match(regexp) end case visible when :visible then return false unless node.visible? when :hidden then return false if node.visible? end selector.custom_filters.each do |name, filter| if options.has_key?(name) return false unless filter.matches?(node, options[name]) elsif filter.default? return false unless filter.matches?(node, filter.default) end end end def visible if options.has_key?(:visible) case @options[:visible] when true then :visible when false then :all else @options[:visible] end else if Capybara.ignore_hidden_elements :visible else :all end end end def wait if options.has_key?(:wait) @options[:wait] or 0 else Capybara.default_wait_time end end def exact? if options.has_key?(:exact) @options[:exact] else Capybara.exact end end def match if options.has_key?(:match) @options[:match] else Capybara.match end end def xpath(exact=nil) exact = self.exact? if exact == nil if @expression.respond_to?(:to_xpath) and exact @expression.to_xpath(:exact) else @expression.to_s end end def css @expression end private def assert_valid_keys! valid_keys = VALID_KEYS + @selector.custom_filters.keys invalid_keys = @options.keys - valid_keys unless invalid_keys.empty? invalid_names = invalid_keys.map(&:inspect).join(", ") valid_names = valid_keys.map(&:inspect).join(", ") raise ArgumentError, "invalid keys #{invalid_names}, should be one of #{valid_names}" end unless VALID_MATCH.include?(match) raise ArgumentError, "invalid option #{match.inspect} for :match, should be one of #{VALID_MATCH.map(&:inspect).join(", ")}" end end end end capybara-2.1.0/lib/capybara/rspec.rb0000644000175000017500000000144212140721202016301 0ustar lunarlunarrequire 'capybara' require 'capybara/dsl' require 'rspec/core' require 'capybara/rspec/matchers' require 'capybara/rspec/features' RSpec.configure do |config| config.include Capybara::DSL, :type => :feature config.include Capybara::RSpecMatchers, :type => :feature # The before and after blocks must run instantaneously, because Capybara # might not actually be used in all examples where it's included. config.after do if self.class.include?(Capybara::DSL) Capybara.reset_sessions! Capybara.use_default_driver end end config.before do if self.class.include?(Capybara::DSL) Capybara.current_driver = Capybara.javascript_driver if example.metadata[:js] Capybara.current_driver = example.metadata[:driver] if example.metadata[:driver] end end end capybara-2.1.0/lib/capybara/server.rb0000644000175000017500000000362312140721202016476 0ustar lunarlunarrequire 'uri' require 'net/http' require 'rack' module Capybara class Server class Middleware attr_accessor :error def initialize(app) @app = app end def call(env) if env["PATH_INFO"] == "/__identify__" [200, {}, [@app.object_id.to_s]] else begin @app.call(env) rescue StandardError => e @error = e unless @error raise e end end end end class << self def ports @ports ||= {} end end attr_reader :app, :port def initialize(app, port=Capybara.server_port) @app = app @middleware = Middleware.new(@app) @server_thread = nil # supress warnings @port = port @port ||= Capybara::Server.ports[@app.object_id] @port ||= find_available_port end def reset_error! @middleware.error = nil end def error @middleware.error end def host Capybara.server_host || "127.0.0.1" end def responsive? return false if @server_thread && @server_thread.join(0) res = Net::HTTP.start(host, @port) { |http| http.get('/__identify__') } if res.is_a?(Net::HTTPSuccess) or res.is_a?(Net::HTTPRedirection) return res.body == @app.object_id.to_s end rescue SystemCallError return false end def boot unless responsive? Capybara::Server.ports[@app.object_id] = @port @server_thread = Thread.new do Capybara.server.call(@middleware, @port) end Timeout.timeout(60) { @server_thread.join(0.1) until responsive? } end rescue Timeout::Error raise "Rack application timed out during boot" else self end private def find_available_port server = TCPServer.new('127.0.0.1', 0) server.addr[1] ensure server.close if server end end end capybara-2.1.0/lib/capybara/rspec/0000755000175000017500000000000012140721202015753 5ustar lunarlunarcapybara-2.1.0/lib/capybara/rspec/features.rb0000644000175000017500000000110512140721202020113 0ustar lunarlunarmodule Capybara module Features def self.included(base) base.instance_eval do alias :background :before alias :scenario :it alias :xscenario :xit alias :given :let alias :given! :let! end end end end def self.feature(*args, &block) options = if args.last.is_a?(Hash) then args.pop else {} end options[:capybara_feature] = true options[:type] = :feature options[:caller] ||= caller args.push(options) describe(*args, &block) end RSpec.configuration.include Capybara::Features, :capybara_feature => true capybara-2.1.0/lib/capybara/rspec/matchers.rb0000644000175000017500000000662312140721202020115 0ustar lunarlunarmodule Capybara module RSpecMatchers class Matcher def wrap(actual) if actual.respond_to?("has_selector?") actual else Capybara.string(actual.to_s) end end end class HaveSelector < Matcher def initialize(*args) @args = args end def matches?(actual) wrap(actual).assert_selector(*@args) end def does_not_match?(actual) wrap(actual).assert_no_selector(*@args) end def description "have #{query.description}" end def query @query ||= Capybara::Query.new(*@args) end end class HaveText < Matcher attr_reader :type, :content, :options def initialize(*args) @type = args.shift if args.first.is_a?(Symbol) @content = args.shift @options = (args.first.is_a?(Hash))? args.first : {} end def matches?(actual) @actual = wrap(actual) @actual.has_text?(type, content, options) end def does_not_match?(actual) @actual = wrap(actual) @actual.has_no_text?(type, content, options) end def failure_message_for_should message = Capybara::Helpers.failure_message(description, options) message << " in #{format(@actual.text(type))}" message end def failure_message_for_should_not failure_message_for_should.sub(/(to find)/, 'not \1') end def description "text #{format(content)}" end def format(content) content = Capybara::Helpers.normalize_whitespace(content) unless content.is_a? Regexp content.inspect end end class HaveTitle < Matcher attr_reader :title def initialize(title) @title = title end def matches?(actual) @actual = wrap(actual) @actual.has_title?(title) end def does_not_match?(actual) @actual = wrap(actual) @actual.has_no_title?(title) end def failure_message_for_should "expected there to be title #{title.inspect} in #{@actual.title.inspect}" end def failure_message_for_should_not "expected there not to be title #{title.inspect} in #{@actual.title.inspect}" end def description "have title #{title.inspect}" end end def have_selector(*args) HaveSelector.new(*args) end def have_xpath(xpath, options={}) HaveSelector.new(:xpath, xpath, options) end def have_css(css, options={}) HaveSelector.new(:css, css, options) end def have_text(*args) HaveText.new(*args) end alias_method :have_content, :have_text def have_title(title) HaveTitle.new(title) end def have_link(locator, options={}) HaveSelector.new(:link, locator, options) end def have_button(locator) HaveSelector.new(:button, locator) end def have_field(locator, options={}) HaveSelector.new(:field, locator, options) end def have_checked_field(locator) HaveSelector.new(:field, locator, :checked => true) end def have_unchecked_field(locator) HaveSelector.new(:field, locator, :unchecked => true) end def have_select(locator, options={}) HaveSelector.new(:select, locator, options) end def have_table(locator, options={}) HaveSelector.new(:table, locator, options) end end end capybara-2.1.0/lib/capybara/result.rb0000644000175000017500000000306412140721202016505 0ustar lunarlunarrequire 'forwardable' module Capybara ## # A {Capybara::Result} represents a collection of {Capybara::Element} on the page. It is possible to interact with this # collection similar to an Array because it implements Enumerable and offers the following Array methods through delegation: # # * [] # * each() # * at() # * size() # * count() # * length() # * first() # * last() # * empty?() # # @see Capybara::Element # class Result include Enumerable extend Forwardable def initialize(elements, query) @elements = elements @result = elements.select { |node| query.matches_filters?(node) } @rest = @elements - @result @query = query end def_delegators :@result, :each, :[], :at, :size, :count, :length, :first, :last, :empty? def matches_count? Capybara::Helpers.matches_count?(@result.size, @query.options) end def failure_message message = Capybara::Helpers.failure_message(@query.description, @query.options) if count > 0 message << ", found #{count} #{Capybara::Helpers.declension("match", "matches", count)}: " << @result.map(&:text).map(&:inspect).join(", ") else message << " but there were no matches" end unless @rest.empty? elements = @rest.map(&:text).map(&:inspect).join(", ") message << ". Also found " << elements << ", which matched the selector but not all filters." end message end def negative_failure_message failure_message.sub(/(to be found|to find)/, 'not \1') end end end capybara-2.1.0/lib/capybara/session.rb0000644000175000017500000002705012140721202016653 0ustar lunarlunarmodule Capybara ## # # The Session class represents a single user's interaction with the system. The Session can use # any of the underlying drivers. A session can be initialized manually like this: # # session = Capybara::Session.new(:culerity, MyRackApp) # # The application given as the second argument is optional. When running Capybara against an external # page, you might want to leave it out: # # session = Capybara::Session.new(:culerity) # session.visit('http://www.google.com') # # Session provides a number of methods for controlling the navigation of the page, such as +visit+, # +current_path, and so on. It also delegate a number of methods to a Capybara::Document, representing # the current HTML document. This allows interaction: # # session.fill_in('q', :with => 'Capybara') # session.click_button('Search') # session.should have_content('Capybara') # # When using capybara/dsl, the Session is initialized automatically for you. # class Session NODE_METHODS = [ :all, :first, :attach_file, :text, :check, :choose, :click_link_or_button, :click_button, :click_link, :field_labeled, :fill_in, :find, :find_button, :find_by_id, :find_field, :find_link, :has_content?, :has_text?, :has_css?, :has_no_content?, :has_no_text?, :has_no_css?, :has_no_xpath?, :resolve, :has_xpath?, :select, :uncheck, :has_link?, :has_no_link?, :has_button?, :has_no_button?, :has_field?, :has_no_field?, :has_checked_field?, :has_unchecked_field?, :has_no_table?, :has_table?, :unselect, :has_select?, :has_no_select?, :has_selector?, :has_no_selector?, :click_on, :has_no_checked_field?, :has_no_unchecked_field?, :query, :assert_selector, :assert_no_selector ] SESSION_METHODS = [ :body, :html, :current_url, :current_host, :evaluate_script, :source, :visit, :within, :within_fieldset, :within_table, :within_frame, :within_window, :current_path, :save_page, :save_and_open_page, :save_screenshot, :reset_session!, :response_headers, :status_code, :title, :has_title?, :has_no_title?, :current_scope ] DSL_METHODS = NODE_METHODS + SESSION_METHODS attr_reader :mode, :app, :server attr_accessor :synchronized def initialize(mode, app=nil) @mode = mode @app = app if Capybara.run_server and @app and driver.needs_server? @server = Capybara::Server.new(@app).boot else @server = nil end @touched = false end def driver @driver ||= begin unless Capybara.drivers.has_key?(mode) other_drivers = Capybara.drivers.keys.map { |key| key.inspect } raise Capybara::DriverNotFoundError, "no driver called #{mode.inspect} was found, available drivers: #{other_drivers.join(', ')}" end Capybara.drivers[mode].call(app) end end ## # # Reset the session, removing all cookies. # def reset! driver.reset! if @touched @touched = false raise @server.error if Capybara.raise_server_errors and @server and @server.error ensure @server.reset_error! if @server end alias_method :cleanup!, :reset! alias_method :reset_session!, :reset! ## # # Returns a hash of response headers. Not supported by all drivers (e.g. Selenium) # # @return [Hash{String => String}] A hash of response headers. # def response_headers driver.response_headers end ## # # Returns the current HTTP status code as an Integer. Not supported by all drivers (e.g. Selenium) # # @return [Integer] Current HTTP status code # def status_code driver.status_code end ## # # @return [String] A snapshot of the DOM of the current document, as it looks right now (potentially modified by JavaScript). # def html driver.html end alias_method :body, :html alias_method :source, :html ## # # @return [String] Path of the current page, without any domain information # def current_path path = URI.parse(current_url).path path if path and not path.empty? end ## # # @return [String] Host of the current page # def current_host uri = URI.parse(current_url) "#{uri.scheme}://#{uri.host}" if uri.host end ## # # @return [String] Fully qualified URL of the current page # def current_url driver.current_url end ## # # @return [String] Title of the current page # def title driver.title end ## # # Navigate to the given URL. The URL can either be a relative URL or an absolute URL # The behaviour of either depends on the driver. # # session.visit('/foo') # session.visit('http://google.com') # # For drivers which can run against an external application, such as the selenium driver # giving an absolute URL will navigate to that page. This allows testing applications # running on remote servers. For these drivers, setting {Capybara.app_host} will make the # remote server the default. For example: # # Capybara.app_host = 'http://google.com' # session.visit('/') # visits the google homepage # # If {Capybara.always_include_port} is set to true and this session is running against # a rack application, then the port that the rack application is running on will automatically # be inserted into the URL. Supposing the app is running on port `4567`, doing something like: # # visit("http://google.com/test") # # Will actually navigate to `http://google.com:4567/test`. # # @param [String] url The URL to navigate to # def visit(url) @touched = true if url !~ /^http/ and Capybara.app_host url = Capybara.app_host + url.to_s end if @server url = "http://#{@server.host}:#{@server.port}" + url.to_s unless url =~ /^http/ if Capybara.always_include_port uri = URI.parse(url) uri.port = @server.port if uri.port == uri.default_port url = uri.to_s end end driver.visit(url) end ## # # Execute the given block for a particular scope on the page. Within will find the first # element matching the given selector and execute the block scoped to that element: # # within(:xpath, '//div[@id="delivery-address"]') do # fill_in('Street', :with => '12 Main Street') # end # # It is possible to omit the first parameter, in that case, the selector is assumed to be # of the type set in Capybara.default_selector. # # within('div#delivery-address') do # fill_in('Street', :with => '12 Main Street') # end # # @overload within(*find_args) # @param (see Capybara::Node::Finders#all) # # @overload within(a_node) # @param [Capybara::Node::Base] a_node The node in whose scope the block should be evaluated # # @raise [Capybara::ElementNotFound] If the scope can't be found before time expires # def within(*args) new_scope = if args.first.is_a?(Capybara::Node::Base) then args.first else find(*args) end begin scopes.push(new_scope) yield ensure scopes.pop end end ## # # Execute the given block within the a specific fieldset given the id or legend of that fieldset. # # @param [String] locator Id or legend of the fieldset # def within_fieldset(locator) within :fieldset, locator do yield end end ## # # Execute the given block within the a specific table given the id or caption of that table. # # @param [String] locator Id or caption of the table # def within_table(locator) within :table, locator do yield end end ## # # Execute the given block within the given iframe using given frame name or index. # May be supported by not all drivers. Drivers that support it, may provide additional options. # # @overload within_frame(index) # @param [Integer] index index of a frame # @overload within_frame(name) # @param [String] name name of a frame # def within_frame(frame_handle) driver.within_frame(frame_handle) do yield end end ## # # Execute the given block within the given window. Only works on # some drivers (e.g. Selenium) # # @param [String] handle of the window # def within_window(handle, &blk) driver.within_window(handle, &blk) end ## # # Execute the given script, not returning a result. This is useful for scripts that return # complex objects, such as jQuery statements. +execute_script+ should be used over # +evaluate_script+ whenever possible. # # @param [String] script A string of JavaScript to execute # def execute_script(script) @touched = true driver.execute_script(script) end ## # # Evaluate the given JavaScript and return the result. Be careful when using this with # scripts that return complex objects, such as jQuery statements. +execute_script+ might # be a better alternative. # # @param [String] script A string of JavaScript to evaluate # @return [Object] The result of the evaluated JavaScript (may be driver specific) # def evaluate_script(script) @touched = true driver.evaluate_script(script) end ## # # Save a snapshot of the page. # # @param [String] path The path to where it should be saved [optional] # def save_page(path=nil) path ||= "capybara-#{Time.new.strftime("%Y%m%d%H%M%S")}#{rand(10**10)}.html" path = File.expand_path(path, Capybara.save_and_open_page_path) if Capybara.save_and_open_page_path FileUtils.mkdir_p(File.dirname(path)) File.open(path,'w') { |f| f.write(Capybara::Helpers.inject_asset_host(body)) } path end ## # # Save a snapshot of the page and open it in a browser for inspection # # @param [String] file_name The path to where it should be saved [optional] # def save_and_open_page(file_name=nil) require "launchy" Launchy.open(save_page(file_name)) rescue LoadError warn "Please install the launchy gem to open page with save_and_open_page" end ## # # Save a screenshot of page # # @param [String] path A string of image path # @option [Hash] options Options for saving screenshot def save_screenshot(path, options={}) driver.save_screenshot(path, options) end def document @document ||= Capybara::Node::Document.new(self, driver) end NODE_METHODS.each do |method| define_method method do |*args, &block| @touched = true current_scope.send(method, *args, &block) end end def inspect %(#) end def has_title?(content) document.synchronize do unless title.match(Capybara::Helpers.to_regexp(content)) raise ExpectationNotMet end end return true rescue Capybara::ExpectationNotMet return false end def has_no_title?(content) document.synchronize do if title.match(Capybara::Helpers.to_regexp(content)) raise ExpectationNotMet end end return true rescue Capybara::ExpectationNotMet return false end def current_scope scopes.last end private def scopes @scopes ||= [document] end end end capybara-2.1.0/lib/capybara/rack_test/0000755000175000017500000000000012140721202016616 5ustar lunarlunarcapybara-2.1.0/lib/capybara/rack_test/driver.rb0000644000175000017500000000337112140721202020442 0ustar lunarlunarrequire 'rack/test' require 'rack/utils' require 'mime/types' require 'nokogiri' require 'cgi' class Capybara::RackTest::Driver < Capybara::Driver::Base DEFAULT_OPTIONS = { :respect_data_method => false, :follow_redirects => true, :redirect_limit => 5 } attr_reader :app, :options def initialize(app, options={}) raise ArgumentError, "rack-test requires a rack application, but none was given" unless app @app = app @options = DEFAULT_OPTIONS.merge(options) end def browser @browser ||= Capybara::RackTest::Browser.new(self) end def follow_redirects? @options[:follow_redirects] end def redirect_limit @options[:redirect_limit] end def response browser.last_response end def request browser.last_request end def visit(path, attributes = {}) browser.visit(path, attributes) end def submit(method, path, attributes) browser.submit(method, path, attributes) end def follow(method, path, attributes = {}) browser.follow(method, path, attributes) end def current_url browser.current_url end def response_headers response.headers end def status_code response.status end def find_xpath(selector) browser.find(:xpath, selector) end def find_css(selector) browser.find(:css,selector) end def html browser.html end def dom browser.dom end def title browser.title end def reset! @browser = nil end def get(*args, &block); browser.get(*args, &block); end def post(*args, &block); browser.post(*args, &block); end def put(*args, &block); browser.put(*args, &block); end def delete(*args, &block); browser.delete(*args, &block); end def header(key, value); browser.header(key, value); end end capybara-2.1.0/lib/capybara/rack_test/css_handlers.rb0000644000175000017500000000033612140721202021615 0ustar lunarlunarclass Capybara::RackTest::CSSHandlers def disabled list list.find_all { |node| node.has_attribute? 'disabled' } end def enabled list list.find_all { |node| !node.has_attribute? 'disabled' } end end capybara-2.1.0/lib/capybara/rack_test/browser.rb0000644000175000017500000000533512140721202020634 0ustar lunarlunarclass Capybara::RackTest::Browser include ::Rack::Test::Methods attr_reader :driver attr_accessor :current_host def initialize(driver) @driver = driver end def app driver.app end def options driver.options end def visit(path, attributes = {}) reset_host! process_and_follow_redirects(:get, path, attributes) end def submit(method, path, attributes) path = request_path if not path or path.empty? process_and_follow_redirects(method, path, attributes, {'HTTP_REFERER' => current_url}) end def follow(method, path, attributes = {}) return if path.gsub(/^#{request_path}/, '').start_with?('#') process_and_follow_redirects(method, path, attributes, {'HTTP_REFERER' => current_url}) end def process_and_follow_redirects(method, path, attributes = {}, env = {}) process(method, path, attributes, env) if driver.follow_redirects? driver.redirect_limit.times do process(:get, last_response["Location"], {}, env) if last_response.redirect? end raise Capybara::InfiniteRedirectError, "redirected more than #{driver.redirect_limit} times, check for infinite redirects." if last_response.redirect? end end def process(method, path, attributes = {}, env = {}) new_uri = URI.parse(path) method.downcase! unless method.is_a? Symbol new_uri.path = request_path if path.start_with?("?") new_uri.path = request_path.sub(%r(/[^/]*$), '/') + new_uri.path unless new_uri.path.start_with?('/') new_uri.scheme ||= @current_scheme new_uri.host ||= @current_host new_uri.port ||= @current_port unless new_uri.default_port == @current_port @current_scheme = new_uri.scheme @current_host = new_uri.host @current_port = new_uri.port reset_cache! send(method, new_uri.to_s, attributes, env.merge(options[:headers] || {})) end def current_url last_request.url rescue Rack::Test::Error "" end def reset_host! uri = URI.parse(Capybara.app_host || Capybara.default_host) @current_scheme = uri.scheme @current_host = uri.host @current_port = uri.port end def reset_cache! @dom = nil end def dom @dom ||= Nokogiri::HTML(html) end def find(format, selector) if format==:css dom.css(selector, Capybara::RackTest::CSSHandlers.new) else dom.xpath(selector) end.map { |node| Capybara::RackTest::Node.new(self, node) } end def html last_response.body rescue Rack::Test::Error "" end def title dom.xpath("//title").text end protected def build_rack_mock_session reset_host! unless current_host Rack::MockSession.new(app, current_host) end def request_path last_request.path rescue Rack::Test::Error "" end end capybara-2.1.0/lib/capybara/rack_test/node.rb0000644000175000017500000001045112140721202020071 0ustar lunarlunarclass Capybara::RackTest::Node < Capybara::Driver::Node def all_text Capybara::Helpers.normalize_whitespace(native.text) end def visible_text Capybara::Helpers.normalize_whitespace(unnormalized_text) end def [](name) string_node[name] end def value string_node.value end def set(value) if (Array === value) && !self[:multiple] raise ArgumentError.new "Value cannot be an Array when 'multiple' attribute is not present. Not a #{value.class}" end if radio? set_radio(value) elsif checkbox? set_checkbox(value) elsif input_field? set_input(value) elsif textarea? native.content = value.to_s unless self[:readonly] end end def select_option if select_node['multiple'] != 'multiple' select_node.find_xpath(".//option[@selected]").each { |node| node.native.remove_attribute("selected") } end native["selected"] = 'selected' end def unselect_option if select_node['multiple'] != 'multiple' raise Capybara::UnselectNotAllowed, "Cannot unselect option from single select box." end native.remove_attribute('selected') end def click if tag_name == 'a' method = self["data-method"] if driver.options[:respect_data_method] method ||= :get driver.follow(method, self[:href].to_s) elsif (tag_name == 'input' and %w(submit image).include?(type)) or ((tag_name == 'button') and type.nil? or type == "submit") Capybara::RackTest::Form.new(driver, form).submit(self) end end def tag_name native.node_name end def visible? string_node.visible? end def checked? string_node.checked? end def selected? string_node.selected? end def disabled? if %w(option optgroup).include? tag_name string_node.disabled? || find_xpath("parent::*")[0].disabled? else string_node.disabled? end end def path native.path end def find_xpath(locator) native.xpath(locator).map { |n| self.class.new(driver, n) } end def find_css(locator) native.css(locator, Capybara::RackTest::CSSHandlers.new).map { |n| self.class.new(driver, n) } end def ==(other) native == other.native end protected def unnormalized_text if !visible? '' elsif native.text? native.text elsif native.element? native.children.map do |child| Capybara::RackTest::Node.new(driver, child).unnormalized_text end.join else '' end end private def string_node @string_node ||= Capybara::Node::Simple.new(native) end # a reference to the select node if this is an option node def select_node find_xpath('./ancestor::select').first end def type native[:type] end def form if native[:form] native.xpath("//form[@id='#{native[:form]}']").first else native.ancestors('form').first end end def set_radio(value) other_radios_xpath = XPath.generate { |x| x.anywhere(:input)[x.attr(:name).equals(self[:name])] }.to_s driver.dom.xpath(other_radios_xpath).each { |node| node.remove_attribute("checked") } native['checked'] = 'checked' end def set_checkbox(value) if value && !native['checked'] native['checked'] = 'checked' elsif !value && native['checked'] native.remove_attribute('checked') end end def set_input(value) if text_or_password? && attribute_is_not_blank?(:maxlength) # Browser behavior for maxlength="0" is inconsistent, so we stick with # Firefox, allowing no input value = value.to_s[0...self[:maxlength].to_i] end if Array === value #Assert multiple attribute is present value.each do |v| new_native = native.clone new_native.remove_attribute('value') native.add_next_sibling(new_native) new_native['value'] = v.to_s end native.remove else native['value'] = value.to_s unless self[:readonly] end end def attribute_is_not_blank?(attribute) self[attribute] && !self[attribute].empty? end def checkbox? input_field? && type == 'checkbox' end def input_field? tag_name == 'input' end def radio? input_field? && type == 'radio' end def textarea? tag_name == "textarea" end def text_or_password? input_field? && (type == 'text' || type == 'password') end end capybara-2.1.0/lib/capybara/rack_test/form.rb0000644000175000017500000000611212140721202020106 0ustar lunarlunarclass Capybara::RackTest::Form < Capybara::RackTest::Node # This only needs to inherit from Rack::Test::UploadedFile because Rack::Test checks for # the class specifically when determing whether to consturct the request as multipart. # That check should be based solely on the form element's 'enctype' attribute value, # which should probably be provided to Rack::Test in its non-GET request methods. class NilUploadedFile < Rack::Test::UploadedFile def initialize @empty_file = Tempfile.new("nil_uploaded_file") @empty_file.close end def original_filename; ""; end def content_type; "application/octet-stream"; end def path; @empty_file.path; end end def params(button) params = {} form_element_types=[:input, :select, :textarea] form_elements_xpath=XPath.generate do |x| xpath=x.descendant(*form_element_types).where(~x.attr(:form)) xpath=xpath.union(x.anywhere(*form_element_types).where(x.attr(:form) == native[:id])) if native[:id] xpath.where(~x.attr(:disabled)) end.to_s native.xpath(form_elements_xpath).map do |field| case field.name when 'input' if %w(radio checkbox).include? field['type'] merge_param!(params, field['name'].to_s, field['value'].to_s) if field['checked'] elsif %w(submit image).include? field['type'] # TO DO identify the click button here (in document order, rather # than leaving until the end of the params) elsif field['type'] =='file' if multipart? file = \ if (value = field['value']).to_s.empty? NilUploadedFile.new else content_type = MIME::Types.type_for(value).first.to_s Rack::Test::UploadedFile.new(value, content_type) end merge_param!(params, field['name'].to_s, file) else merge_param!(params, field['name'].to_s, File.basename(field['value'].to_s)) end else merge_param!(params, field['name'].to_s, field['value'].to_s) end when 'select' if field['multiple'] == 'multiple' options = field.xpath(".//option[@selected]") options.each do |option| merge_param!(params, field['name'].to_s, (option['value'] || option.text).to_s) end else option = field.xpath(".//option[@selected]").first option ||= field.xpath('.//option').first merge_param!(params, field['name'].to_s, (option['value'] || option.text).to_s) if option end when 'textarea' merge_param!(params, field['name'].to_s, field.text.to_s) end end merge_param!(params, button[:name], button[:value] || "") if button[:name] params end def submit(button) driver.submit(method, native['action'].to_s, params(button)) end def multipart? self[:enctype] == "multipart/form-data" end private def method self[:method] =~ /post/i ? :post : :get end def merge_param!(params, key, value) Rack::Utils.normalize_params(params, key, value) end end capybara-2.1.0/lib/capybara/node/0000755000175000017500000000000012140721202015564 5ustar lunarlunarcapybara-2.1.0/lib/capybara/node/simple.rb0000644000175000017500000001004112140721202017376 0ustar lunarlunarmodule Capybara module Node ## # # A {Capybara::Node::Simple} is a simpler version of {Capybara::Node::Base} which # includes only {Capybara::Node::Finders} and {Capybara::Node::Matchers} and does # not include {Capybara::Node::Actions}. This type of node is returned when # using {Capybara.string}. # # It is useful in that it does not require a session, an application or a driver, # but can still use Capybara's finders and matchers on any string that contains HTML. # class Simple include Capybara::Node::Finders include Capybara::Node::Matchers attr_reader :native def initialize(native) native = Nokogiri::HTML(native) if native.is_a?(String) @native = native end ## # # @return [String] The text of the element # def text(type=nil) native.text end ## # # Retrieve the given attribute # # element[:title] # => HTML title attribute # # @param [Symbol] name The attribute name to retrieve # @return [String] The value of the attribute # def [](name) attr_name = name.to_s if attr_name == 'value' value elsif 'input' == tag_name and 'checkbox' == native[:type] and 'checked' == attr_name native['checked'] == 'checked' else native[attr_name] end end ## # # @return [String] The tag name of the element # def tag_name native.node_name end ## # # An XPath expression describing where on the page the element can be found # # @return [String] An XPath expression # def path native.path end ## # # @return [String] The value of the form element # def value if tag_name == 'textarea' native.content.sub(/\A\n/, '') elsif tag_name == 'select' if native['multiple'] == 'multiple' native.xpath(".//option[@selected='selected']").map { |option| option[:value] || option.content } else option = native.xpath(".//option[@selected='selected']").first || native.xpath(".//option").first option[:value] || option.content if option end else native[:value] end end ## # # Whether or not the element is visible. Does not support CSS, so # the result may be inaccurate. # # @return [Boolean] Whether the element is visible # def visible? native.xpath("./ancestor-or-self::*[contains(@style, 'display:none') or contains(@style, 'display: none') or name()='script' or name()='head']").size == 0 end ## # # Whether or not the element is checked. # # @return [Boolean] Whether the element is checked # def checked? native[:checked] end ## # # Whether or not the element is disabled. # # @return [Boolean] Whether the element is disabled def disabled? native[:disabled] end ## # # Whether or not the element is selected. # # @return [Boolean] Whether the element is selected # def selected? native[:selected] end def synchronize(seconds=nil) yield # simple nodes don't need to wait end def allow_reload! # no op end def title native.xpath("//title").first.text end def has_title?(content) title.match(Capybara::Helpers.to_regexp(content)) end def has_no_title?(content) not has_title?(content) end private def resolve_query(query, exact=nil) elements = if query.selector.format == :css native.css(query.css) else native.xpath(query.xpath(exact)) end.map do |node| self.class.new(node) end Capybara::Result.new(elements, query) end end end end capybara-2.1.0/lib/capybara/node/base.rb0000644000175000017500000001024712140721202017027 0ustar lunarlunarmodule Capybara module Node ## # # A {Capybara::Node::Base} represents either an element on a page through the subclass # {Capybara::Node::Element} or a document through {Capybara::Node::Document}. # # Both types of Node share the same methods, used for interacting with the # elements on the page. These methods are divided into three categories, # finders, actions and matchers. These are found in the modules # {Capybara::Node::Finders}, {Capybara::Node::Actions} and {Capybara::Node::Matchers} # respectively. # # A {Capybara::Session} exposes all methods from {Capybara::Node::Document} directly: # # session = Capybara::Session.new(:rack_test, my_app) # session.visit('/') # session.fill_in('Foo', :with => 'Bar') # from Capybara::Node::Actions # bar = session.find('#bar') # from Capybara::Node::Finders # bar.select('Baz', :from => 'Quox') # from Capybara::Node::Actions # session.has_css?('#foobar') # from Capybara::Node::Matchers # class Base attr_reader :session, :base, :parent include Capybara::Node::Finders include Capybara::Node::Actions include Capybara::Node::Matchers def initialize(session, base) @session = session @base = base end # overridden in subclasses, e.g. Capybara::Node::Element def reload self end ## # # This method is Capybara's primary defence agains asynchronicity # problems. It works by attempting to run a given block of code until it # succeeds. The exact behaviour of this method depends on a number of # factors. Basically there are certain exceptions which, when raised # from the block, instead of bubbling up, are caught, and the block is # re-run. # # Certain drivers, such as RackTest, have no support for aynchronous # processes, these drivers run the block, and any error raised bubbles up # immediately. This allows faster turn around in the case where an # expectation fails. # # Only exceptions that are {Capybara::ElementNotFound} or any subclass # thereof cause the block to be rerun. Drivers may specify additional # exceptions which also cause reruns. This usually occurs when a node is # manipulated which no longer exists on the page. For example, the # Selenium driver specifies # `Selenium::WebDriver::Error::ObsoleteElementError`. # # As long as any of these exceptions are thrown, the block is re-run, # until a certain amount of time passes. The amount of time defaults to # {Capybara.default_wait_time} and can be overriden through the `seconds` # argument. This time is compared with the system time to see how much # time has passed. If the return value of `Time.now` is stubbed out, # Capybara will raise `Capybara::FrozenInTime`. # # @param [Integer] seconds Number of seconds to retry this block # @return [Object] The result of the given block # @raise [Capybara::FrozenInTime] If the return value of `Time.now` appears stuck # def synchronize(seconds=Capybara.default_wait_time) start_time = Time.now if session.synchronized yield else session.synchronized = true begin yield rescue => e raise e unless driver.wait? raise e unless catch_error?(e) raise e if (Time.now - start_time) >= seconds sleep(0.05) raise Capybara::FrozenInTime, "time appears to be frozen, Capybara does not work with libraries which freeze time, consider using time travelling instead" if Time.now == start_time reload if Capybara.automatic_reload retry ensure session.synchronized = false end end end protected def catch_error?(error) (driver.invalid_element_errors + [Capybara::ElementNotFound]).any? do |type| error.is_a?(type) end end def driver session.driver end end end end capybara-2.1.0/lib/capybara/node/element.rb0000644000175000017500000001312612140721202017545 0ustar lunarlunarmodule Capybara module Node ## # # A {Capybara::Element} represents a single element on the page. It is possible # to interact with the contents of this element the same as with a document: # # session = Capybara::Session.new(:rack_test, my_app) # # bar = session.find('#bar') # from Capybara::Node::Finders # bar.select('Baz', :from => 'Quox') # from Capybara::Node::Actions # # {Capybara::Element} also has access to HTML attributes and other properties of the # element: # # bar.value # bar.text # bar[:title] # # @see Capybara::Node # class Element < Base def initialize(session, base, parent, query) super(session, base) @parent = parent @query = query end def allow_reload! @allow_reload = true end ## # # @return [Object] The native element from the driver, this allows access to driver specific methods # def native synchronize { base.native } end ## # # Retrieve the text of the element. If `Capybara.ignore_hidden_elements` # is `true`, which it is by default, then this will return only text # which is visible. The exact semantics of this may differ between # drivers, but generally any text within elements with `display:none` is # ignored. This behaviour can be overridden by passing `:all` to this # method. # # @param [:all, :visible] type Whether to return only visible or all text # @return [String] The text of the element # def text(type=nil) type ||= :all unless Capybara.ignore_hidden_elements or Capybara.visible_text_only synchronize do if type == :all base.all_text else base.visible_text end end end ## # # Retrieve the given attribute # # element[:title] # => HTML title attribute # # @param [Symbol] attribute The attribute to retrieve # @return [String] The value of the attribute # def [](attribute) synchronize { base[attribute] } end ## # # @return [String] The value of the form element # def value synchronize { base.value } end ## # # Set the value of the form element to the given value. # # @param [String] value The new value # def set(value) synchronize { base.set(value) } end ## # # Select this node if is an option element inside a select tag # def select_option synchronize { base.select_option } end ## # # Unselect this node if is an option element inside a multiple select tag # def unselect_option synchronize { base.unselect_option } end ## # # Click the Element # def click synchronize { base.click } end ## # # Hover on the Element # def hover synchronize { base.hover } end ## # # @return [String] The tag name of the element # def tag_name synchronize { base.tag_name } end ## # # Whether or not the element is visible. Not all drivers support CSS, so # the result may be inaccurate. # # @return [Boolean] Whether the element is visible # def visible? synchronize { base.visible? } end ## # # Whether or not the element is checked. # # @return [Boolean] Whether the element is checked # def checked? synchronize { base.checked? } end ## # # Whether or not the element is selected. # # @return [Boolean] Whether the element is selected # def selected? synchronize { base.selected? } end ## # # Whether or not the element is disabled. # # @return [Boolean] Whether the element is disabled # def disabled? synchronize { base.disabled? } end ## # # An XPath expression describing where on the page the element can be found # # @return [String] An XPath expression # def path synchronize { base.path } end ## # # Trigger any event on the current element, for example mouseover or focus # events. Does not work in Selenium. # # @param [String] event The name of the event to trigger # def trigger(event) synchronize { base.trigger(event) } end ## # # Drag the element to the given other element. # # source = page.find('#foo') # target = page.find('#bar') # source.drag_to(target) # # @param [Capybara::Element] node The element to drag to # def drag_to(node) synchronize { base.drag_to(node.base) } end def reload if @allow_reload begin reloaded = parent.reload.first(@query.name, @query.locator, @query.options) @base = reloaded.base if reloaded rescue => e raise e unless catch_error?(e) end end self end def inspect %(#) rescue NotSupportedByDriverError, 'Capybara::Node::Element#inspect' %(#) end end end end capybara-2.1.0/lib/capybara/node/document.rb0000644000175000017500000000102612140721202017726 0ustar lunarlunarmodule Capybara module Node ## # # A {Capybara::Document} represents an HTML document. Any operation # performed on it will be performed on the entire document. # # @see Capybara::Node # class Document < Base def inspect %(#) end ## # # @return [String] The text of the document # def text(type=nil) find(:xpath, '/html').text(type) end def title session.driver.title end end end end capybara-2.1.0/lib/capybara/node/finders.rb0000644000175000017500000001362112140721202017546 0ustar lunarlunarmodule Capybara module Node module Finders ## # # Find an {Capybara::Element} based on the given arguments. +find+ will raise an error if the element # is not found. # # If the driver is capable of executing JavaScript, +find+ will wait for a set amount of time # and continuously retry finding the element until either the element is found or the time # expires. The length of time +find+ will wait is controlled through {Capybara.default_wait_time} # and defaults to 2 seconds. # # +find+ takes the same options as +all+. # # page.find('#foo').find('.bar') # page.find(:xpath, '//div[contains(., "bar")]') # page.find('li', :text => 'Quox').click_link('Delete') # # @param (see Capybara::Node::Finders#all) # @option options [Boolean] match The matching strategy to use. # @option options [false, Numeric] wait How long to wait for the element to appear. # # @return [Capybara::Element] The found element # @raise [Capybara::ElementNotFound] If the element can't be found before time expires # def find(*args) query = Capybara::Query.new(*args) synchronize(query.wait) do if query.match == :smart or query.match == :prefer_exact result = resolve_query(query, true) result = resolve_query(query, false) if result.size == 0 and not query.exact? else result = resolve_query(query) end if query.match == :one or query.match == :smart and result.size > 1 raise Capybara::Ambiguous.new("Ambiguous match, found #{result.size} elements matching #{query.description}") end if result.size == 0 raise Capybara::ElementNotFound.new("Unable to find #{query.description}") end result.first end.tap(&:allow_reload!) end ## # # Find a form field on the page. The field can be found by its name, id or label text. # # @param [String] locator Which field to find # @return [Capybara::Element] The found element # def find_field(locator, options={}) find(:field, locator, options) end alias_method :field_labeled, :find_field ## # # Find a link on the page. The link can be found by its id or text. # # @param [String] locator Which link to find # @return [Capybara::Element] The found element # def find_link(locator, options={}) find(:link, locator, options) end ## # # Find a button on the page. The button can be found by its id, name or value. # # @param [String] locator Which button to find # @return [Capybara::Element] The found element # def find_button(locator, options={}) find(:button, locator, options) end ## # # Find a element on the page, given its id. # # @param [String] id Which element to find # @return [Capybara::Element] The found element # def find_by_id(id, options={}) find(:id, id, options) end ## # # Find all elements on the page matching the given selector # and options. # # Both XPath and CSS expressions are supported, but Capybara # does not try to automatically distinguish between them. The # following statements are equivalent: # # page.all(:css, 'a#person_123') # page.all(:xpath, '//a[@id="person_123"]') # # # If the type of selector is left out, Capybara uses # {Capybara.default_selector}. It's set to :css by default. # # page.all("a#person_123") # # Capybara.default_selector = :xpath # page.all('//a[@id="person_123"]') # # The set of found elements can further be restricted by specifying # options. It's possible to select elements by their text or visibility: # # page.all('a', :text => 'Home') # page.all('#menu li', :visible => true) # # @overload all([kind], locator, options) # @param [:css, :xpath] kind The type of selector # @param [String] locator The selector # @option options [String, Regexp] text Only find elements which contain this text or match this regexp # @option options [Boolean] visible Only find elements that are visible on the page. Setting this to false # finds invisible _and_ visible elements. # @option options [Boolean] exact Control whether `is` expressions in the given XPath match exactly or partially # @return [Capybara::Result] A collection of found elements # def all(*args) resolve_query(Capybara::Query.new(*args)) end ## # # Find the first element on the page matching the given selector # and options, or nil if no element matches. # # @overload first([kind], locator, options) # @param [:css, :xpath] kind The type of selector # @param [String] locator The selector # @param [Hash] options Additional options; see {#all} # @return [Capybara::Element] The found element or nil # def first(*args) all(*args).first end private def resolve_query(query, exact=nil) elements = synchronize do if query.selector.format==:css base.find_css(query.css) else base.find_xpath(query.xpath(exact)) end.map do |node| Capybara::Node::Element.new(session, node, self, query) end end Capybara::Result.new(elements, query) end end end end capybara-2.1.0/lib/capybara/node/actions.rb0000644000175000017500000001176612140721202017564 0ustar lunarlunarmodule Capybara module Node module Actions ## # # Finds a button or link by id, text or value and clicks it. Also looks at image # alt text inside the link. # # @param [String] locator Text, id or value of link or button # def click_link_or_button(locator, options={}) find(:link_or_button, locator, options).click end alias_method :click_on, :click_link_or_button ## # # Finds a link by id or text and clicks it. Also looks at image # alt text inside the link. # # @param [String] locator Text, id or text of link # @param options # @option options [String] :href The value the href attribute must be # def click_link(locator, options={}) find(:link, locator, options).click end ## # # Finds a button by id, text or value and clicks it. # # @param [String] locator Text, id or value of button # def click_button(locator, options={}) find(:button, locator, options).click end ## # # Locate a text field or text area and fill it in with the given text # The field can be found via its name, id or label text. # # page.fill_in 'Name', :with => 'Bob' # # @param [String] locator Which field to fill in # @param [Hash{:with => String}] options The value to fill in # def fill_in(locator, options={}) raise "Must pass a hash containing 'with'" if not options.is_a?(Hash) or not options.has_key?(:with) with = options.delete(:with) find(:fillable_field, locator, options).set(with) end ## # # Find a radio button and mark it as checked. The radio button can be found # via name, id or label text. # # page.choose('Male') # # @param [String] locator Which radio button to choose # def choose(locator, options={}) find(:radio_button, locator, options).set(true) end ## # # Find a check box and mark it as checked. The check box can be found # via name, id or label text. # # page.check('German') # # @param [String] locator Which check box to check # def check(locator, options={}) find(:checkbox, locator, options).set(true) end ## # # Find a check box and mark uncheck it. The check box can be found # via name, id or label text. # # page.uncheck('German') # # @param [String] locator Which check box to uncheck # def uncheck(locator, options={}) find(:checkbox, locator, options).set(false) end ## # # Find a select box on the page and select a particular option from it. If the select # box is a multiple select, +select+ can be called multiple times to select more than # one option. The select box can be found via its name, id or label text. # # page.select 'March', :from => 'Month' # # @param [String] value Which option to select # @param [Hash{:from => String}] options The id, name or label of the select box # def select(value, options={}) if options.has_key?(:from) from = options.delete(:from) find(:select, from, options).find(:option, value, options).select_option else find(:option, value, options).select_option end end ## # # Find a select box on the page and unselect a particular option from it. If the select # box is a multiple select, +unselect+ can be called multiple times to unselect more than # one option. The select box can be found via its name, id or label text. # # page.unselect 'March', :from => 'Month' # # @param [String] value Which option to unselect # @param [Hash{:from => String}] options The id, name or label of the select box # def unselect(value, options={}) if options.has_key?(:from) from = options.delete(:from) find(:select, from, options).find(:option, value, options).unselect_option else find(:option, value, options).unselect_option end end ## # # Find a file field on the page and attach a file given its path. The file field can # be found via its name, id or label text. # # page.attach_file(locator, '/path/to/file.png') # # @param [String] locator Which field to attach the file to # @param [String] path The path of the file that will be attached, or an array of paths # def attach_file(locator, path, options={}) Array(path).each do |p| raise Capybara::FileNotFound, "cannot attach file, #{p} does not exist" unless File.exist?(p.to_s) end find(:file_field, locator, options).set(path) end end end end capybara-2.1.0/lib/capybara/node/matchers.rb0000644000175000017500000004075312140721202017730 0ustar lunarlunarmodule Capybara module Node module Matchers ## # # Checks if a given selector is on the page or current node. # # page.has_selector?('p#foo') # page.has_selector?(:xpath, './/p[@id="foo"]') # page.has_selector?(:foo) # # By default it will check if the expression occurs at least once, # but a different number can be specified. # # page.has_selector?('p.foo', :count => 4) # # This will check if the expression occurs exactly 4 times. # # It also accepts all options that {Capybara::Node::Finders#all} accepts, # such as :text and :visible. # # page.has_selector?('li', :text => 'Horse', :visible => true) # # has_selector? can also accept XPath expressions generated by the # XPath gem: # # page.has_selector?(:xpath, XPath.descendant(:p)) # # @param (see Capybara::Node::Finders#all) # @param args # @option args [Integer] :count (nil) Number of times the text should occur # @option args [Integer] :minimum (nil) Minimum number of times the text should occur # @option args [Integer] :maximum (nil) Maximum number of times the text should occur # @option args [Range] :between (nil) Range of times that should contain number of times text occurs # @return [Boolean] If the expression exists # def has_selector?(*args) assert_selector(*args) rescue Capybara::ExpectationNotMet return false end ## # # Checks if a given selector is not on the page or current node. # Usage is identical to Capybara::Node::Matchers#has_selector? # # @param (see Capybara::Node::Finders#has_selector?) # @return [Boolean] # def has_no_selector?(*args) assert_no_selector(*args) rescue Capybara::ExpectationNotMet return false end ## # # Asserts that a given selector is on the page or current node. # # page.assert_selector('p#foo') # page.assert_selector(:xpath, './/p[@id="foo"]') # page.assert_selector(:foo) # # By default it will check if the expression occurs at least once, # but a different number can be specified. # # page.assert_selector('p#foo', :count => 4) # # This will check if the expression occurs exactly 4 times. # # It also accepts all options that {Capybara::Node::Finders#all} accepts, # such as :text and :visible. # # page.assert_selector('li', :text => 'Horse', :visible => true) # # `assert_selector` can also accept XPath expressions generated by the # XPath gem: # # page.assert_selector(:xpath, XPath.descendant(:p)) # # @param (see Capybara::Node::Finders#all) # @option options [Integer] :count (nil) Number of times the expression should occur # @raise [Capybara::ExpectationNotMet] If the selector does not exist # def assert_selector(*args) synchronize do result = all(*args) result.matches_count? or raise Capybara::ExpectationNotMet, result.failure_message end return true end ## # # Asserts that a given selector is not on the page or current node. # Usage is identical to Capybara::Node::Matchers#assert_selector # # @param (see Capybara::Node::Finders#assert_selector) # @raise [Capybara::ExpectationNotMet] If the selector exists # def assert_no_selector(*args) synchronize do result = all(*args) result.matches_count? and raise Capybara::ExpectationNotMet, result.negative_failure_message end return true end ## # # Checks if a given XPath expression is on the page or current node. # # page.has_xpath?('.//p[@id="foo"]') # # By default it will check if the expression occurs at least once, # but a different number can be specified. # # page.has_xpath?('.//p[@id="foo"]', :count => 4) # # This will check if the expression occurs exactly 4 times. # # It also accepts all options that {Capybara::Node::Finders#all} accepts, # such as :text and :visible. # # page.has_xpath?('.//li', :text => 'Horse', :visible => true) # # has_xpath? can also accept XPath expressions generate by the # XPath gem: # # xpath = XPath.generate { |x| x.descendant(:p) } # page.has_xpath?(xpath) # # @param [String] path An XPath expression # @param options (see Capybara::Node::Finders#all) # @option options [Integer] :count (nil) Number of times the expression should occur # @return [Boolean] If the expression exists # def has_xpath?(path, options={}) has_selector?(:xpath, path, options) end ## # # Checks if a given XPath expression is not on the page or current node. # Usage is identical to Capybara::Node::Matchers#has_xpath? # # @param (see Capybara::Node::Finders#has_xpath?) # @return [Boolean] # def has_no_xpath?(path, options={}) has_no_selector?(:xpath, path, options) end ## # # Checks if a given CSS selector is on the page or current node. # # page.has_css?('p#foo') # # By default it will check if the selector occurs at least once, # but a different number can be specified. # # page.has_css?('p#foo', :count => 4) # # This will check if the selector occurs exactly 4 times. # # It also accepts all options that {Capybara::Node::Finders#all} accepts, # such as :text and :visible. # # page.has_css?('li', :text => 'Horse', :visible => true) # # @param [String] path A CSS selector # @param options (see Capybara::Node::Finders#all) # @option options [Integer] :count (nil) Number of times the selector should occur # @return [Boolean] If the selector exists # def has_css?(path, options={}) has_selector?(:css, path, options) end ## # # Checks if a given CSS selector is not on the page or current node. # Usage is identical to Capybara::Node::Matchers#has_css? # # @param (see Capybara::Node::Finders#has_css?) # @return [Boolean] # def has_no_css?(path, options={}) has_no_selector?(:css, path, options) end ## # # Checks if the page or current node has the given text content, # ignoring any HTML tags and normalizing whitespace. # # By default it will check if the text occurs at least once, # but a different number can be specified. # # page.has_text?('lorem ipsum', between: 2..4) # # This will check if the text occurs from 2 to 4 times. # # @overload has_text?([type], text, [options]) # @param [:all, :visible] type Whether to check for only visible or all text # @param [String, Regexp] text The text/regexp to check for # @param [Hash] options additional options # @option options [Integer] :count (nil) Number of times the text should occur # @option options [Integer] :minimum (nil) Minimum number of times the text should occur # @option options [Integer] :maximum (nil) Maximum number of times the text should occur # @option options [Range] :between (nil) Range of times that should contain number of times text occurs # @return [Boolean] Whether it exists # def has_text?(*args) synchronize do raise ExpectationNotMet unless text_found?(*args) end return true rescue Capybara::ExpectationNotMet return false end alias_method :has_content?, :has_text? ## # # Checks if the page or current node does not have the given text # content, ignoring any HTML tags and normalizing whitespace. # # @param (see #has_text?) # @return [Boolean] Whether it doesn't exist # def has_no_text?(*args) synchronize do raise ExpectationNotMet if text_found?(*args) end return true rescue Capybara::ExpectationNotMet return false end alias_method :has_no_content?, :has_no_text? ## # # Checks if the page or current node has a link with the given # text or id. # # @param [String] locator The text or id of a link to check for # @param options # @option options [String] :href The value the href attribute must be # @return [Boolean] Whether it exists # def has_link?(locator, options={}) has_selector?(:link, locator, options) end ## # # Checks if the page or current node has no link with the given # text or id. # # @param (see Capybara::Node::Finders#has_link?) # @return [Boolean] Whether it doesn't exist # def has_no_link?(locator, options={}) has_no_selector?(:link, locator, options) end ## # # Checks if the page or current node has a button with the given # text, value or id. # # @param [String] locator The text, value or id of a button to check for # @return [Boolean] Whether it exists # def has_button?(locator) has_selector?(:button, locator) end ## # # Checks if the page or current node has no button with the given # text, value or id. # # @param [String] locator The text, value or id of a button to check for # @return [Boolean] Whether it doesn't exist # def has_no_button?(locator) has_no_selector?(:button, locator) end ## # # Checks if the page or current node has a form field with the given # label, name or id. # # For text fields and other textual fields, such as textareas and # HTML5 email/url/etc. fields, it's possible to specify a :with # option to specify the text the field should contain: # # page.has_field?('Name', :with => 'Jonas') # # It is also possible to filter by the field type attribute: # # page.has_field?('Email', :type => 'email') # # Note: 'textarea' and 'select' are valid type values, matching the associated tag names. # # @param [String] locator The label, name or id of a field to check for # @option options [String] :with The text content of the field # @option options [String] :type The type attribute of the field # @return [Boolean] Whether it exists # def has_field?(locator, options={}) has_selector?(:field, locator, options) end ## # # Checks if the page or current node has no form field with the given # label, name or id. See {Capybara::Node::Matchers#has_field?}. # # @param [String] locator The label, name or id of a field to check for # @option options [String] :with The text content of the field # @option options [String] :type The type attribute of the field # @return [Boolean] Whether it doesn't exist # def has_no_field?(locator, options={}) has_no_selector?(:field, locator, options) end ## # # Checks if the page or current node has a radio button or # checkbox with the given label, value or id, that is currently # checked. # # @param [String] locator The label, name or id of a checked field # @return [Boolean] Whether it exists # def has_checked_field?(locator) has_selector?(:field, locator, :checked => true) end ## # # Checks if the page or current node has no radio button or # checkbox with the given label, value or id, that is currently # checked. # # @param [String] locator The label, name or id of a checked field # @return [Boolean] Whether it doesn't exists # def has_no_checked_field?(locator) has_no_selector?(:field, locator, :checked => true) end ## # # Checks if the page or current node has a radio button or # checkbox with the given label, value or id, that is currently # unchecked. # # @param [String] locator The label, name or id of an unchecked field # @return [Boolean] Whether it exists # def has_unchecked_field?(locator) has_selector?(:field, locator, :unchecked => true) end ## # # Checks if the page or current node has no radio button or # checkbox with the given label, value or id, that is currently # unchecked. # # @param [String] locator The label, name or id of an unchecked field # @return [Boolean] Whether it doesn't exists # def has_no_unchecked_field?(locator) has_no_selector?(:field, locator, :unchecked => true) end ## # # Checks if the page or current node has a select field with the # given label, name or id. # # It can be specified which option should currently be selected: # # page.has_select?('Language', :selected => 'German') # # For multiple select boxes, several options may be specified: # # page.has_select?('Language', :selected => ['English', 'German']) # # It's also possible to check if the exact set of options exists for # this select box: # # page.has_select?('Language', :options => ['English', 'German', 'Spanish']) # # You can also check for a partial set of options: # # page.has_select?('Language', :with_options => ['English', 'German']) # # @param [String] locator The label, name or id of a select box # @option options [Array] :options Options which should be contained in this select box # @option options [Array] :with_options Partial set of options which should be contained in this select box # @option options [String, Array] :selected Options which should be selected # @return [Boolean] Whether it exists # def has_select?(locator, options={}) has_selector?(:select, locator, options) end ## # # Checks if the page or current node has no select field with the # given label, name or id. See {Capybara::Node::Matchers#has_select?}. # # @param (see Capybara::Node::Matchers#has_select?) # @return [Boolean] Whether it doesn't exist # def has_no_select?(locator, options={}) has_no_selector?(:select, locator, options) end ## # # Checks if the page or current node has a table with the given id # or caption: # # page.has_table?('People') # # @param [String] locator The id or caption of a table # @return [Boolean] Whether it exist # def has_table?(locator, options={}) has_selector?(:table, locator, options) end ## # # Checks if the page or current node has no table with the given id # or caption. See {Capybara::Node::Matchers#has_table?}. # # @param (see Capybara::Node::Matchers#has_table?) # @return [Boolean] Whether it doesn't exist # def has_no_table?(locator, options={}) has_no_selector?(:table, locator, options) end def ==(other) self.eql?(other) or (other.respond_to?(:base) and base == other.base) end private def text_found?(*args) type = args.shift if args.first.is_a?(Symbol) or args.first.nil? content, options = args count = Capybara::Helpers.normalize_whitespace(text(type)).scan(Capybara::Helpers.to_regexp(content)).count Capybara::Helpers.matches_count?(count, options || {}) end end end end capybara-2.1.0/lib/capybara/selector.rb0000644000175000017500000001140712140721202017007 0ustar lunarlunarmodule Capybara class Selector class Filter def initialize(name, block, options={}) @name = name @block = block @options = options end def default? @options.has_key?(:default) end def default @options[:default] end def matches?(node, value) @block.call(node, value) end end attr_reader :name, :custom_filters, :format class << self def all @selectors ||= {} end def add(name, &block) all[name.to_sym] = Capybara::Selector.new(name.to_sym, &block) end def remove(name) all.delete(name.to_sym) end end def initialize(name, &block) @name = name @custom_filters = {} @match = nil @label = nil @failure_message = nil instance_eval(&block) end def xpath(&block) @format = :xpath @xpath = block if block @xpath end # Same as xpath, but wrap in XPath.css(). def css(&block) @format = :css @css = block if block @css end def match(&block) @match = block if block @match end def label(label=nil) @label = label if label @label end def call(locator) if @format==:css @css.call(locator) else @xpath.call(locator) end end def match?(locator) @match and @match.call(locator) end def filter(name, options={}, &block) @custom_filters[name] = Filter.new(name, block, options) end end end Capybara.add_selector(:xpath) do xpath { |xpath| xpath } end Capybara.add_selector(:css) do css { |css| css } end Capybara.add_selector(:id) do xpath { |id| XPath.descendant[XPath.attr(:id) == id.to_s] } end Capybara.add_selector(:field) do xpath { |locator| XPath::HTML.field(locator) } filter(:checked) { |node, value| not(value ^ node.checked?) } filter(:unchecked) { |node, value| (value ^ node.checked?) } filter(:disabled, :default => false) { |node, value| not(value ^ node.disabled?) } filter(:with) { |node, with| node.value == with } filter(:type) do |node, type| if ['textarea', 'select'].include?(type) node.tag_name == type else node[:type] == type end end end Capybara.add_selector(:fieldset) do xpath { |locator| XPath::HTML.fieldset(locator) } end Capybara.add_selector(:link_or_button) do label "link or button" xpath { |locator| XPath::HTML.link_or_button(locator) } filter(:disabled, :default => false) { |node, value| node.tag_name == "a" or not(value ^ node.disabled?) } end Capybara.add_selector(:link) do xpath { |locator| XPath::HTML.link(locator) } filter(:href) do |node, href| node.first(:xpath, XPath.axis(:self)[XPath.attr(:href).equals(href.to_s)]) end end Capybara.add_selector(:button) do xpath { |locator| XPath::HTML.button(locator) } filter(:disabled, :default => false) { |node, value| not(value ^ node.disabled?) } end Capybara.add_selector(:fillable_field) do label "field" xpath { |locator| XPath::HTML.fillable_field(locator) } filter(:disabled, :default => false) { |node, value| not(value ^ node.disabled?) } end Capybara.add_selector(:radio_button) do label "radio button" xpath { |locator| XPath::HTML.radio_button(locator) } filter(:checked) { |node, value| not(value ^ node.checked?) } filter(:unchecked) { |node, value| (value ^ node.checked?) } filter(:disabled, :default => false) { |node, value| not(value ^ node.disabled?) } end Capybara.add_selector(:checkbox) do xpath { |locator| XPath::HTML.checkbox(locator) } filter(:checked) { |node, value| not(value ^ node.checked?) } filter(:unchecked) { |node, value| (value ^ node.checked?) } filter(:disabled, :default => false) { |node, value| not(value ^ node.disabled?) } end Capybara.add_selector(:select) do label "select box" xpath { |locator| XPath::HTML.select(locator) } filter(:options) do |node, options| actual = node.all(:xpath, './/option').map { |option| option.text } options.sort == actual.sort end filter(:with_options) { |node, options| options.all? { |option| node.first(:option, option) } } filter(:selected) do |node, selected| actual = node.all(:xpath, './/option').select { |option| option.selected? }.map { |option| option.text } [selected].flatten.sort == actual.sort end filter(:disabled, :default => false) { |node, value| not(value ^ node.disabled?) } end Capybara.add_selector(:option) do xpath { |locator| XPath::HTML.option(locator) } end Capybara.add_selector(:file_field) do label "file field" xpath { |locator| XPath::HTML.file_field(locator) } filter(:disabled, :default => false) { |node, value| not(value ^ node.disabled?) } end Capybara.add_selector(:table) do xpath { |locator| XPath::HTML.table(locator) } end capybara-2.1.0/lib/capybara/dsl.rb0000644000175000017500000000227512140721202015754 0ustar lunarlunarrequire 'capybara' module Capybara module DSL def self.included(base) warn "including Capybara::DSL in the global scope is not recommended!" if base == Object super end def self.extended(base) warn "extending the main object with Capybara::DSL is not recommended!" if base == TOPLEVEL_BINDING.eval("self") super end ## # # Shortcut to working in a different session. # def using_session(name, &block) Capybara.using_session(name, &block) end ## # # Shortcut to using a different wait time. # def using_wait_time(seconds, &block) Capybara.using_wait_time(seconds, &block) end ## # # Shortcut to accessing the current session. # # class MyClass # include Capybara::DSL # # def has_header? # page.has_css?('h1') # end # end # # @return [Capybara::Session] The current session object # def page Capybara.current_session end Session::DSL_METHODS.each do |method| define_method method do |*args, &block| page.send method, *args, &block end end end extend(Capybara::DSL) end capybara-2.1.0/metadata.gz.sig0000644000175000017500000000040012140721202015204 0ustar lunarlunargUVC#T91@6KH}wVTDH]vŤIk%ˑ$lT} ~i1캎"1kRʳjQbvP露D}YZj!hk$_#Rk6:8Er<~?:(Ϗr:7-5AIbWG9ЁeP,Ax|capybara-2.1.0/License.txt0000644000175000017500000000207112140721202014432 0ustar lunarlunar(The MIT License) Copyright (c) 2009-2012 Jonas Nicklas Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.