require "watirspec_helper" describe Watir::Wait do describe "#until" do it "waits until the block returns true" do Watir::Wait.until(timeout: 0.5) { @result = true } expect(@result).to be true end it "executes block if timeout is zero" do Watir::Wait.until(timeout: 0) { @result = true } expect(@result).to be true end it "times out" do expect { Watir::Wait.until(timeout: 0.5) { false } }.to raise_error(Watir::Wait::TimeoutError) end it "times out with a custom message" do expect { Watir::Wait.until(timeout: 0.5, message: "oops") { false } }.to raise_error(Watir::Wait::TimeoutError, "timed out after 0.5 seconds, oops") end it "uses provided interval" do begin Watir::Wait.until(timeout: 0.4, interval: 0.2) do @result = @result.nil? ? 1 : @result + 1 false end rescue Watir::Wait::TimeoutError end expect(@result).to eq 2 end it "uses timer for waiting" do timer = Watir::Wait.timer expect(timer).to receive(:wait).with(0.5).and_call_original Watir::Wait.until(timeout: 0.5) { true } end end describe "#while" do it "waits while the block returns true" do expect(Watir::Wait.while(timeout: 0.5) { false }).to be_nil end it "executes block if timeout is zero" do expect(Watir::Wait.while(timeout: 0) { false }).to be_nil end it "times out" do expect { Watir::Wait.while(timeout: 0.5) { true } }.to raise_error(Watir::Wait::TimeoutError) end it "times out with a custom message" do expect { Watir::Wait.while(timeout: 0.5, message: "oops") { true } }.to raise_error(Watir::Wait::TimeoutError, "timed out after 0.5 seconds, oops") end it "uses provided interval" do begin Watir::Wait.while(timeout: 0.4, interval: 0.2) do @result = @result.nil? ? 1 : @result + 1 true end rescue Watir::Wait::TimeoutError end expect(@result).to eq 2 end it "uses timer for waiting" do timer = Watir::Wait.timer expect(timer).to receive(:wait).with(0.5).and_call_original Watir::Wait.while(timeout: 0.5) { false } end end describe "#timer" do it "returns default timer" do expect(Watir::Wait.timer).to be_a(Watir::Wait::Timer) end end describe "#timer=" do after { Watir::Wait.timer = nil } it "changes default timer" do timer = Class.new Watir::Wait.timer = timer expect(Watir::Wait.timer).to eq(timer) end end end describe Watir::Element do before do browser.goto WatirSpec.url_for("wait.html") end # TODO: This is deprecated; remove in future version not_compliant_on :relaxed_locate do describe "#when_present" do it "invokes subsequent method calls when the element becomes present" do browser.a(id: 'show_bar').click bar = browser.div(id: 'bar') bar.when_present(2).click expect(bar.text).to eq "changed" end it "times out when given a block" do expect { browser.div(id: 'bar').when_present(1) {} }.to raise_error(Watir::Wait::TimeoutError) end it "times out when not given a block" do message = /^timed out after 1 seconds, waiting for (\{:id=>"bar", :tag_name=>"div"\}|\{:tag_name=>"div", :id=>"bar"\}) to become present$/ expect { browser.div(id: 'bar').when_present(1).click }.to raise_error(Watir::Wait::TimeoutError, message) end it "responds to Element methods" do decorator = browser.div.when_present expect(decorator).to respond_to(:exist?) expect(decorator).to respond_to(:present?) expect(decorator).to respond_to(:click) end it "delegates present? to element" do Object.class_eval do def present? false end end element = browser.a(id: "show_bar").when_present(1) expect(element).to be_present end it "processes before calling present?" do browser.a(id: 'show_bar').click expect(browser.div(id: 'bar').when_present.present?).to be true end end end compliant_on :relaxed_locate do it "clicking automatically waits until the element appears" do browser.a(id: 'show_bar').click expect { browser.div(id: 'bar').click }.to_not raise_exception expect(browser.div(id: 'bar').text).to eq 'changed' end it "raises exception if the element doesn't appear" do expect { browser.div(id: 'bar').click }.to raise_unknown_object_exception end it "raises exception if the element doesn't become enabled" do expect { browser.button(id: 'btn').click }.to raise_object_disabled_exception end end not_compliant_on :relaxed_locate do describe "#wait_until &:enabled?" do it "invokes subsequent method calls when the element becomes enabled" do browser.a(id: 'enable_btn').click btn = browser.button(id: 'btn') btn.wait_until(timeout: 2, &:enabled?).click Watir::Wait.while { btn.enabled? } expect(btn.disabled?).to be true end it "times out" do error = Watir::Wait::TimeoutError inspected = '#"btn", :tag_name=>"button"}>' message = "timed out after 1 seconds, waiting for true condition on #{inspected}" element = browser.button(id: 'btn') expect { element.wait_until(timeout: 1, &:enabled?).click }.to raise_error(error, message) end it "responds to Element methods" do element = browser.button.wait_until { true } expect(element).to respond_to(:exist?) expect(element).to respond_to(:present?) expect(element).to respond_to(:click) end it "can be chained with #wait_until &:present?" do browser.a(id: 'show_and_enable_btn').click browser.button(id: 'btn2').wait_until(&:present?).wait_until(&:enabled?).click expect(browser.button(id: 'btn2')).to exist expect(browser.button(id: 'btn2')).to be_enabled end end end describe "#wait_until_present" do it "waits until the element appears" do browser.a(id: 'show_bar').click expect { browser.div(id: 'bar').wait_until_present(timeout: 5) }.to_not raise_exception end it "waits until the element re-appears" do browser.link(id: 'readd_bar').click expect { browser.div(id: 'bar').wait_until_present }.to_not raise_exception end it "times out if the element doesn't appear" do inspected = '#"bar", :tag_name=>"div"}>' error = Watir::Wait::TimeoutError message = "timed out after 1 seconds, waiting for true condition on #{inspected}" expect { browser.div(id: 'bar').wait_until_present(timeout: 1) }.to raise_error(error, message) end it "uses provided interval" do element = browser.div(id: 'bar') expect(element).to receive(:present?).twice begin element.wait_until_present(timeout: 0.4, interval: 0.2) rescue Watir::Wait::TimeoutError end end end describe "#wait_while_present" do it "waits until the element disappears" do browser.a(id: 'hide_foo').click expect { browser.div(id: 'foo').wait_while_present(timeout: 2) }.to_not raise_exception end it "times out if the element doesn't disappear" do error = Watir::Wait::TimeoutError inspected = '#"foo", :tag_name=>"div"}>' message = "timed out after 1 seconds, waiting for false condition on #{inspected}" expect { browser.div(id: 'foo').wait_while_present(timeout: 1) }.to raise_error(error, message) end it "uses provided interval" do element = browser.div(id: 'foo') expect(element).to receive(:present?).twice begin element.wait_until_present(timeout: 0.4, interval: 0.2) rescue Watir::Wait::TimeoutError end end it "does not error when element goes stale" do element = browser.div(id: 'foo').tap(&:exists?) allow(element).to receive(:stale?).and_return(false, true) browser.a(id: 'hide_foo').click expect { element.wait_while_present(timeout: 1) }.to_not raise_exception end it "waits until the selector no longer matches" do Watir.default_timeout = 1 element = browser.link(name: 'add_select').wait_until(&:exists?) begin browser.link(id: 'change_select').click expect { element.wait_while_present }.not_to raise_error ensure Watir.default_timeout = 30 end end end describe "#wait_until" do it "returns element for additional actions" do element = browser.div(id: 'foo') expect(element.wait_until(&:exist?)).to eq element end it "accepts self in block" do element = browser.div(id: 'bar') browser.a(id: 'show_bar').click expect { element.wait_until { |el| el.text == 'bar' } }.to_not raise_exception end it "accepts any values in block" do element = browser.div(id: 'bar') expect { element.wait_until { true } }.to_not raise_exception end it "accepts just a timeout parameter" do element = browser.div(id: 'bar') expect { element.wait_until(timeout: 0) { true } }.to_not raise_exception end it "accepts just a message parameter" do element = browser.div(id: 'bar') expect { element.wait_until(message: 'no') { true } }.to_not raise_exception end it "accepts just an interval parameter" do element = browser.div(id: 'bar') expect { element.wait_until(interval: 0.1) { true } }.to_not raise_exception end end describe "#wait_while" do it "returns element for additional actions" do element = browser.div(id: 'foo') browser.a(id: 'hide_foo').click expect(element.wait_while(&:present?)).to eq element end not_compliant_on :safari do it "accepts self in block" do element = browser.div(id: 'foo') browser.a(id: 'hide_foo').click expect { element.wait_while { |el| el.text == 'foo' } }.to_not raise_exception end end it "accepts any values in block" do element = browser.div(id: 'foo') expect { element.wait_while { false } }.to_not raise_exception end it "accepts just a timeout parameter" do element = browser.div(id: 'foo') expect { element.wait_while(timeout: 0) { false } }.to_not raise_exception end it "accepts just a message parameter" do element = browser.div(id: 'foo') expect { element.wait_while(message: 'no') { false } }.to_not raise_exception end it "accepts just an interval parameter" do element = browser.div(id: 'foo') expect { element.wait_while(interval: 0.1) { false } }.to_not raise_exception end end end describe Watir do describe "#default_timeout" do before do Watir.default_timeout = 1 browser.goto WatirSpec.url_for("wait.html") end after do # Reset the default timeout Watir.default_timeout = 30 end context "when no timeout is specified" do it "is used by Wait#until" do expect { Watir::Wait.until { false } }.to raise_error(Watir::Wait::TimeoutError) end it "is used by Wait#while" do expect { Watir::Wait.while { true } }.to raise_error(Watir::Wait::TimeoutError) end it "is used by Element#wait_until_present" do expect { browser.div(id: 'bar').wait_until_present }.to raise_error(Watir::Wait::TimeoutError) end it "is used by Element#wait_while_present" do expect { browser.div(id: 'foo').wait_while_present }.to raise_error(Watir::Wait::TimeoutError) end end end end