require_relative 'unit_helper' describe Watir::Locators::Element::Locator do include LocatorSpecHelper describe 'finds a single element' do describe 'by delegating to Selenium' do SELENIUM_SELECTORS.each do |loc| it "delegates to Selenium's #{loc} locator" do expect_one(loc, 'bar').and_return(element(tag_name: 'div')) match = %i[link link_text partial_link_text].include?(loc) ? :to : :to_not msg = /:#{loc} locator is deprecated\. Use :visible_text instead/ expect { locate_one loc => 'bar' }.send(match, output(msg).to_stdout_from_any_process) end end it 'raises exception if locating a non-link element by link locator' do selector = {tag_name: 'div', link_text: 'foo'} msg = 'Can not use link_text locator to find a foo element' expect { expect { locate_one(selector) }.to raise_exception(StandardError, msg) }.to have_deprecated_link_text end end describe 'with selectors not supported by Selenium' do it 'handles selector with tag name and a single attribute' do expect_one :xpath, ".//*[local-name()='div'][@title='foo']" locate_one tag_name: 'div', title: '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 single quotes in the attribute string' do expect_one :xpath, %{.//*[@title=concat('foo and ',"'",'bar',"'",'')]} locate_one title: "foo and 'bar'" end it 'handles selector with tag name and multiple attributes' do expect_one :xpath, ".//*[local-name()='div'][@title='foo' and @dir='bar']" locate_one [:tag_name, 'div', :title, 'foo', :dir, 'bar'] end it 'handles selector with no tag name and multiple attributes' do expect_one :xpath, ".//*[@dir='foo' and @title='bar']" locate_one [:dir, 'foo', :title, 'bar'] end it 'handles selector with attribute presence' do expect_one :xpath, './/*[@data-view]' locate_one [:data_view, true] end it 'handles selector with attribute absence' do expect_one :xpath, './/*[not(@data-view)]' locate_one [:data_view, false] end it 'handles selector with class attribute presence' do expect_one :xpath, './/*[@class]' locate_one class: true end it 'handles selector with multiple classes in array' do xpath = ".//*[contains(concat(' ', @class, ' '), ' a ') and contains(concat(' ', @class, ' '), ' b ')]" expect_one :xpath, xpath locate_one class: %w[a b] end it 'handles selector with multiple classes in string' do expect_one :xpath, ".//*[contains(concat(' ', @class, ' '), ' a b ')]" expect { locate_one class: 'a b' }.to have_deprecated_class_array end it 'handles selector with xpath and tag_name String' do elements = [ element(tag_name: 'div', attributes: {class: 'foo'}), element(tag_name: 'span', attributes: {class: 'foo'}), element(tag_name: 'div', attributes: {class: 'foo'}) ] expect_all(:xpath, './/*[@class="foo"]').and_return(elements) selector = { xpath: './/*[@class="foo"]', tag_name: 'span' } expect(locate_one(selector).tag_name).to eq 'span' end it 'handles selector with xpath and tag_name Symbol' do elements = [ element(tag_name: 'div', attributes: {class: 'foo'}), element(tag_name: 'span', attributes: {class: 'foo'}), element(tag_name: 'div', attributes: {class: 'foo'}) ] expect_all(:xpath, './/*[@class="foo"]').and_return(elements) selector = { xpath: './/*[@class="foo"]', tag_name: 'span' } expect(locate_one(selector).tag_name).to eq 'span' end it 'handles custom attributes' do elements = [ element(tag_name: 'div', attributes: {custom_attribute: 'foo'}), element(tag_name: 'span', attributes: {custom_attribute: 'foo'}), element(tag_name: 'div', attributes: {custom_attribute: 'foo'}) ] expect_one(:xpath, ".//*[local-name()='span'][@custom-attribute='foo']").and_return(elements[1]) selector = { custom_attribute: 'foo', tag_name: 'span' } expect(locate_one(selector).tag_name).to eq 'span' end end describe 'with special cased selectors' do it 'normalizes space for :text' do expect_one :xpath, ".//*[local-name()='div'][normalize-space()='foo']" locate_one tag_name: 'div', text: 'foo' end # TODO: This is deprecated by 'text_string' it "handles 'text' key when it's a string" do expect_one :xpath, ".//*[local-name()='div'][normalize-space()='foo']" locate_one tag_name: 'div', 'text' => 'foo' end it 'translates :caption to :text' do expect_one :xpath, ".//*[local-name()='div'][normalize-space()='foo']" locate_one tag_name: 'div', caption: 'foo' end it 'handles data-* attributes' do expect_one :xpath, ".//*[local-name()='div'][@data-name='foo']" locate_one tag_name: 'div', data_name: 'foo' end it 'handles aria-* attributes' do expect_one :xpath, ".//*[local-name()='div'][@aria-label='foo']" locate_one tag_name: 'div', aria_label: 'foo' end it "doesn't modify attribute name when the attribute key is a string" do expect_one :xpath, ".//*[local-name()='div'][@_ngcontent-c24]" locate_one tag_name: 'div', '_ngcontent-c24' => true end it 'normalizes space for the :href attribute' do expect_one :xpath, ".//*[local-name()='a'][normalize-space(@href)='foo']" selector = { tag_name: 'a', href: 'foo' } locate_one selector, Watir::Anchor.attributes end it 'wraps :type attribute with translate() for upper case values' do translated_type = "translate(@type,'ABCDEFGHIJKLMNOPQRSTUVWXYZÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞŸŽŠŒ'," \ "'abcdefghijklmnopqrstuvwxyzàáâãäåæçèéêëìíîïðñòóôõöøùúûüýþÿžšœ')" expect_one :xpath, ".//*[local-name()='input'][#{translated_type}='file']" selector = [ :tag_name, 'input', :type, 'file' ] locate_one selector, Watir::Input.attributes end it "uses the corresponding