require_relative 'unit_helper'

describe Watir::Locators::Element::Locator do
  include LocatorSpecHelper

  describe '#locate' do
    context 'when XPath can be built to represent entire selector' do
      it 'locates without using match' do
        @locator = {xpath: './/div'}

        expect_one(*@locator.to_a.flatten).and_return(el)
        expect(element_matcher).not_to receive(:match)

        expect(locate_one).to eq el
      end

      it 'returns nil if not found' do
        @locator = {xpath: './/div'}

        expect_one(*@locator.to_a.flatten).and_raise(Selenium::WebDriver::Error::NoSuchElementError)
        expect(locate_one).to eq nil
      end
    end

    context 'when SelectorBuilder result has additional locators to match' do
      it 'locates using match' do
        @locator = {xpath: './/div', id: 'foo'}

        expect_all(*@locator.to_a.first.flatten).and_return([el])
        expect(element_matcher).to receive(:match).and_return(el)

        expect(locate_one).to eq el
      end

      it 'relocates if element goes stale' do
        @locator = {xpath: './/div', id: 'foo'}

        expect_all(*@locator.to_a.first.flatten).exactly(2).times.and_return([el])
        stale_exception = Selenium::WebDriver::Error::StaleElementReferenceError
        expect(element_matcher).to receive(:match).and_raise(stale_exception)
        expect(element_matcher).to receive(:match).and_return(el)

        expect(locate_one).to eq el
      end

      it 'Raises Exception if element continues to go stale' do
        @locator = {xpath: './/div', id: 'foo'}

        expect_all(*@locator.to_a.first.flatten).exactly(3).times.and_return([el])
        stale_exception = Selenium::WebDriver::Error::StaleElementReferenceError
        expect(element_matcher).to receive(:match).and_raise(stale_exception).exactly(3).times

        msg = 'Unable to locate element from {:xpath=>".//div", :id=>"foo"} due to changing page'
        expect { locate_one }.to raise_exception Watir::Exception::LocatorException, msg
      end
    end
  end

  describe '#locate_all' do
    it 'locates using match' do
      @locator = {xpath: './/div', id: 'foo'}

      expect_all(*@locator.to_a.first.flatten).and_return([el])
      expect(element_matcher).to receive(:match).and_return([el])

      expect(locate_all).to eq [el]
    end

    it 'raises LocatorException if element continues to go stale' do
      @locator = {xpath: './/div', id: 'foo'}

      expect_all(*@locator.to_a.first.flatten).exactly(3).times.and_return([el])
      stale_exception = Selenium::WebDriver::Error::StaleElementReferenceError
      expect(element_matcher).to receive(:match).and_raise(stale_exception).exactly(3).times

      msg = 'Unable to locate element collection from {:xpath=>".//div", :id=>"foo"} due to changing page'
      expect { locate_all }.to raise_exception Watir::Exception::LocatorException, msg
    end

    it 'raises Argument error if using index key' do
      expect { locate_all(index: 2) }.to raise_exception(ArgumentError, "can't locate all elements by :index")
    end
  end
end