require File.expand_path("spec_helper", File.dirname(__FILE__)) describe Watir::ElementLocator do include LocatorSpecHelper describe "finds a single element" do describe "by delegating to webdriver" do WEBDRIVER_SELECTORS.each do |loc| it "delegates to webdriver's #{loc} locator" do expect_one(loc, "bar").and_return(element(:tag_name => "div")) locate_one loc => "bar" end end end describe "with selectors not supported by webdriver" do it "handles selector with tag name and a single attribute" do expect_one :xpath, ".//div[@class='foo']" locate_one :tag_name => "div", :class => "foo" end it "handles selector with no tag name and and a single attribute" do expect_one :xpath, ".//*[@title='foo']" locate_one :title => "foo" end it "handles selector with tag name and multiple attributes" do expect_one :xpath, ".//div[@class='foo' and @title='bar']" locate_one [:tag_name, "div", :class , "foo", :title , 'bar'] end it "handles selector with no tag name and multiple attributes" do expect_one :xpath, ".//*[@class='foo' and @title='bar']" locate_one [:class, "foo", :title, "bar"] end end describe "with special cased selectors" do it "normalizes space for :text" do expect_one :xpath, ".//div[normalize-space()='foo']" locate_one :tag_name => "div", :text => "foo" end it "translates :caption to :text" do expect_one :xpath, ".//div[normalize-space()='foo']" locate_one :tag_name => "div", :caption => "foo" end it "translates :class_name to :class" do expect_one :xpath, ".//div[@class='foo']" locate_one :tag_name => "div", :class_name => "foo" end it "handles data-* attributes" do expect_one :xpath, ".//div[@data-name='foo']" locate_one :tag_name => "div", :data_name => "foo" end it "normalizes space for the :href attribute" do expect_one :xpath, ".//a[normalize-space(@href)='foo']" selector = { :tag_name => "a", :href => "foo" } locate_one selector, Watir::Anchor.attributes end it "uses the corresponding <label>'s @for attribute when locating by label" do expect_one :xpath, ".//input[@type='text' and @id=//label[normalize-space()='foo']/@for]" selector = [ :tag_name, "input", :type , "text", :label , "foo" ] locate_one selector, Watir::Input.attributes end it "does not use the label element for <option> elements" do expect_one :xpath, ".//option[@label='foo']" locate_one :tag_name => "option", :label => "foo" end it "translates ruby attribute names to content attribute names" do expect_one :xpath, ".//meta[@http-equiv='foo']" selector = { :tag_name => "meta", :http_equiv => "foo" } locate_one selector, Watir::Meta.attributes # TODO: check edge cases end end describe "with regexp selectors" do it "handles selector with tag name and a single regexp attribute" do elements = [ element(:tag_name => "div", :attributes => { :class => "foo" }), element(:tag_name => "div", :attributes => { :class => "foob"}) ] expect_all(:xpath, ".//div").and_return(elements) locate_one(:tag_name => "div", :class => /oob/).should == elements[1] end it "handles :tag_name, :index and a single regexp attribute" do elements = [ element(:tag_name => "div", :attributes => { :class => "foo" }), element(:tag_name => "div", :attributes => { :class => "foo" }) ] expect_all(:xpath, ".//div").and_return(elements) selector = { :tag_name => "div", :class => /foo/, :index => 1 } locate_one(selector).should == elements[1] end it "handles mix of string and regexp attributes" do elements = [ element(:tag_name => "div", :attributes => { :class => "foo", :title => "bar" }), element(:tag_name => "div", :attributes => { :class => "foo", :title => "baz" }) ] expect_all(:xpath, ".//div[@class='foo']").and_return(elements) selector = { :tag_name => "div", :class => "foo", :title => /baz/ } locate_one(selector).should == elements[1] end it "handles :label => /regexp/ selector" do label_elements = [ element(:tag_name => "label", :text => "foo", :attributes => { :for => "bar"}), element(:tag_name => "label", :text => "foob", :attributes => { :for => "baz"}) ] div_elements = [element(:tag_name => "div")] expect_all(:tag_name, "label").ordered.and_return(label_elements) expect_all(:xpath, ".//div[@id='baz']").ordered.and_return(div_elements) locate_one(:tag_name => "div", :label => /oob/).should == div_elements.first end it "returns nil when no label matching the regexp is found" do expect_all(:tag_name, "label").and_return([]) locate_one(:tag_name => "div", :label => /foo/).should be_nil end end it "finds all if :index is given" do # or could we use XPath indeces reliably instead? elements = [ element(:tag_name => "div"), element(:tag_name => "div") ] expect_all(:xpath, ".//div[@class='foo']").and_return(elements) selector = { :tag_name => "div", :class => "foo", :index => 1 } locate_one(selector).should == elements[1] end it "returns nil if found element didn't match the selector tag_name" do expect_one(:xpath, "//div").and_return(element(:tag_name => "div")) selector = { :tag_name => "input", :xpath => "//div" } locate_one(selector, Watir::Input.attributes).should be_nil end describe "errors" do it "raises a TypeError if :index is not a Fixnum" do lambda { locate_one(:tag_name => "div", :index => "bar") }.should raise_error(TypeError, %[expected Fixnum, got "bar":String]) end it "raises a TypeError if selector value is not a String or Regexp" do lambda { locate_one(:tag_name => 123) }.should raise_error(TypeError, %[expected one of [String, Regexp], got 123:Fixnum]) end it "raises a MissingWayOfFindingObjectException if the attribute is not valid" do bad_selector = {:tag_name => "input", :href => "foo"} valid_attributes = Watir::Input.attributes lambda { locate_one(bad_selector, valid_attributes) }.should raise_error(MissingWayOfFindingObjectException, "invalid attribute: :href") end end end describe "finds several elements" do describe "by delegating to webdriver" do WEBDRIVER_SELECTORS.each do |loc| it "delegates to webdriver's #{loc} locator" do expect_all(loc, "bar").and_return([element(:tag_name => "div")]) locate_all(loc => "bar") end end end describe "with selectors not supported by webdriver" do it "handles selector with tag name and a single attribute" do expect_all :xpath, ".//div[@class='foo']" locate_all :tag_name => "div", :class => "foo" end it "handles selector with tag name and multiple attributes" do expect_all :xpath, ".//div[@class='foo' and @title='bar']" locate_all [:tag_name, "div", :class , "foo", :title , 'bar'] end end describe "with regexp selectors" do it "handles selector with tag name and a single regexp attribute" do elements = [ element(:tag_name => "div", :attributes => { :class => "foo" }), element(:tag_name => "div", :attributes => { :class => "foob"}), element(:tag_name => "div", :attributes => { :class => "doob"}), element(:tag_name => "div", :attributes => { :class => "noob"}) ] expect_all(:xpath, ".//div").and_return(elements) locate_all(:tag_name => "div", :class => /oob/).should == elements.last(3) end it "handles mix of string and regexp attributes" do elements = [ element(:tag_name => "div", :attributes => { :class => "foo", :title => "bar" }), element(:tag_name => "div", :attributes => { :class => "foo", :title => "baz" }), element(:tag_name => "div", :attributes => { :class => "foo", :title => "bazt"}) ] expect_all(:xpath, ".//div[@class='foo']").and_return(elements) selector = { :tag_name => "div", :class => "foo", :title => /baz/ } locate_all(selector).should == elements.last(2) end end describe "errors" do it "raises ArgumentError if :index is given" do lambda { locate_all(:tag_name => "div", :index => 1) }.should raise_error(ArgumentError, "can't locate all elements by :index") end end end end