require 'spreewald_support/tolerance_for_selenium_sync_issues'

describe ToleranceForSeleniumSyncIssues do
  subject { World.new }
  let(:wait_time) { 0.2 }

  before do
    Capybara.default_max_wait_time = wait_time
    allow(subject.page.driver).to receive(:wait?).and_return(true)
  end

  describe '#patiently' do
    it 'calls the block' do
      reached = false
      subject.patiently do
        reached = true
      end
      expect(reached).to eq true
    end

    it 'fails if the block raises an unknown error' do
      reached = false
      expect {
        subject.patiently do
          raise 'some unknown error'
          reached = true
        end
      }.to raise_error(/some unknown error/)
      expect(reached).to eq false
    end

    it 'retries the block if it raises a whitelisted error, but eventually raises it' do
      count = 0
      expect {
        subject.patiently do
          count += 1
          raise Capybara::ElementNotFound
        end
      }.to raise_error(Capybara::ElementNotFound)
      expect(count).to be > 2
    end

    it 'retries the block if it fails an expectation' do
      count = 0
      expect {
        subject.patiently do
          count += 1
          expect(true).to eq false
        end
      }.to raise_error(RSpec::Expectations::ExpectationNotMetError)
      expect(count).to be > 2
    end

    it 'does not retry the block if page.driver.wait? is false' do
      allow(subject.page.driver).to receive(:wait?).and_return(false)
      count = 0
      expect {
        subject.patiently do
          count += 1
          raise Capybara::ElementNotFound
        end
      }.to raise_error(Capybara::ElementNotFound)
      expect(count).to eq 1
    end

    it 'will not raise an error if the block eventually succeeds' do
      count = 0
      expect {
        subject.patiently do
          count += 1
          if count < 3
            raise Capybara::ElementNotFound
          end
        end
      }.not_to raise_error
    end

    it 'will retry the block until a specified amount of time has passed' do
      started = Time.now
      expect {
        subject.patiently do
          raise Capybara::ElementNotFound
        end
      }.to raise_error(Capybara::ElementNotFound)
      expect(Time.now - started).to be > wait_time
    end

    it 'retries the block at least twice even if the given time has passed' do
      count = 0
      expect {
        subject.patiently do
          count += 1
          sleep wait_time
          raise Capybara::ElementNotFound
        end
      }.to raise_error(Capybara::ElementNotFound)
      expect(count).to be > 1
    end

    it 'retries the block if the given time has been used within the last retry (see issue #202)' do
      count = 0
      expect {
        subject.patiently do
          count += 1
          sleep wait_time if count == 2
          raise Capybara::ElementNotFound
        end
      }.to raise_error(Capybara::ElementNotFound)
      expect(count).to be > 2
    end

    it 'will retry an outer patiently block if an inner patiently block took up all the time' do
      try = 0
      expect {
        subject.patiently do
          try += 1
          correct_element_found = try > 1
          subject.patiently do
            raise Capybara::ElementNotFound unless correct_element_found
          end
        end
      }.not_to raise_error
    end

  end
end
