Skip to content

Commit

Permalink
implement Selenium::Helpers::Wait (#25)
Browse files Browse the repository at this point in the history
  • Loading branch information
mamantoha committed Feb 28, 2023
1 parent eda762d commit 93768b3
Show file tree
Hide file tree
Showing 2 changed files with 101 additions and 0 deletions.
51 changes: 51 additions & 0 deletions spec/features/wait_spec.cr
@@ -0,0 +1,51 @@
require "../spec_helper"

describe Selenium::Helpers::Wait do
describe ".wait" do
it "success if true" do
TestServer.route "/home", <<-HTML
<div id="div"></div>
HTML

with_session do |session|
session.navigate_to("http://localhost:3002/home")

wait = Selenium::Helpers::Wait.new(timeout: 2.seconds, interval: 1.second)

wait.until { session.find_element(:css, "#div") }
end
end

it "raises an error if false" do
TestServer.route "/home", <<-HTML
<div id="div"></div>
HTML

with_session do |session|
session.navigate_to("http://localhost:3002/home")

wait = Selenium::Helpers::Wait.new(timeout: 2.seconds, interval: 1.second)

expect_raises(IO::TimeoutError, /timed out after 2 seconds \(no such element.*/) do
wait.until { session.find_element(:css, "#div1") }
end
end
end

it "raises an error with custom message" do
TestServer.route "/home", <<-HTML
<div id="div"></div>
HTML

with_session do |session|
session.navigate_to("http://localhost:3002/home")

wait = Selenium::Helpers::Wait.new(timeout: 2.seconds, interval: 1.second, message: "custom message")

expect_raises(IO::TimeoutError, /custom message \(no such element.*/) do
wait.until { session.find_element(:css, "#div1") }
end
end
end
end
end
50 changes: 50 additions & 0 deletions src/selenium/helpers/wait.cr
@@ -0,0 +1,50 @@
class Selenium::Helpers::Wait
@timeout : Time::Span
@interval : Time::Span
@ignored = [] of Exception

# Create a new `Wait` instance.
#
# `timeout` - seconds to wait before timing out
# `interval` - seconds to sleep between polls
# `message` - exception mesage if timed out
# `ignored` - exceptions to ignore while polling
def initialize(@timeout = 5.seconds, @interval = 0.2.seconds, @ignored = [Selenium::Error], @message : String? = nil)
end

# Wait until the given block returns a `true` value.
# Otherwise raise an exception `IO::TimeoutError`.
#
# ```
# wait = Selenium::Helpers::Wait.new(timeout: 10.seconds, interval: 1.second)
# wait.until { session.document_manager.execute_script("return document.readyState;") == "complete" }
# ```
def until(&) : Nil
end_time = current_time + @timeout
last_error : Exception? = nil

until current_time > end_time
begin
result = yield

return result if result
rescue ex
last_error = ex

raise ex unless @ignored.includes?(ex.class)
end

sleep @interval
end

message = @message || "timed out after #{@timeout.seconds} seconds"

message = message + " (#{last_error.message})" if last_error

raise IO::TimeoutError.new(message)
end

private def current_time
Time.utc
end
end

0 comments on commit 93768b3

Please sign in to comment.