Skip to content

Commit

Permalink
Merge branch 'master' of git@github.com:a-e/rsel
Browse files Browse the repository at this point in the history
  • Loading branch information
Ken-g6 committed Apr 2, 2012
2 parents e43cd29 + 1c7c95a commit 5dbd728
Show file tree
Hide file tree
Showing 5 changed files with 274 additions and 48 deletions.
97 changes: 53 additions & 44 deletions lib/rsel/selenium_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,9 @@ class SeleniumTest
# Unrecognized strings result in the default.
# @option options [String, Integer] :timeout
# Default timeout in seconds. This determines how long the `open` method
# will wait for the page to load.
# will wait for the page to load, as well as the default timeout for
# methods like `see_within_seconds`, `do_not_see_within_seconds`, and
# `see_alert_within_seconds`.
#
# @example
# | script | selenium test | http://site.to.test/ |
Expand Down Expand Up @@ -323,18 +325,17 @@ def maximize_browser
#
def see(text, scope=nil)
return skip_status if skip_step?
if scope == nil
if scope.nil?
# Can't do a Study workaround - it doesn't know what's visible.
return pass_if @browser.text?(text)
else
selector = loc("css=", '', scope).strip
@study.undo_last_dirty # This method does not modify the browser page contents.
# Default selenium_compare does not allow text around a glob. Allow such text.
searchtext = text
searchtext = text.sub(/^(glob:)?\*?/, '*').sub(/\*?$/, '*') unless /^(exact|regexpi?):/ === text
# Can't do a Study workaround - it doesn't know what's visible.
fail_on_exception do
return pass_if selenium_compare(@browser.get_text(selector), searchtext), "'#{text}' not found in '#{@browser.get_text(selector)}'"
match = selenium_compare(@browser.get_text(selector), globify(text))
return pass_if match,
"'#{text}' not found in '#{@browser.get_text(selector)}'"
end
end
end
Expand All @@ -353,18 +354,17 @@ def see(text, scope=nil)
#
def do_not_see(text, scope=nil)
return skip_status if skip_step?
if scope == nil
if scope.nil?
# Can't do a Study workaround - it doesn't know what's visible.
return pass_if !@browser.text?(text)
else
selector = loc("css=", '', scope).strip
@study.undo_last_dirty # This method does not modify the browser page contents.
begin
# Default selenium_compare does not allow text around a glob. Allow such text.
searchtext = text
searchtext = text.sub(/^(glob:)?\*?/, '*').sub(/\*?$/, '*') unless /^(exact|regexpi?):/ === text
# Can't do a Study workaround - it doesn't know what's visible.
return pass_if !selenium_compare(@browser.get_text(selector), searchtext), "'#{text}' found in '#{@browser.get_text(selector)}'"
match = selenium_compare(@browser.get_text(selector), globify(text))
return pass_if !match,
"'#{text}' not expected, but found in '#{@browser.get_text(selector)}'"
rescue
# Do not see the selector, so do not see the text within it.
return true
Expand All @@ -379,8 +379,8 @@ def do_not_see(text, scope=nil)
#
# @param [String] text
# Plain text that should be appear on or visible on the current page
# @param [String] seconds
# Integer number of seconds to wait.
# @param [Integer, String] seconds
# Integer number of seconds to wait, or `-1` to use the default timeout.
# @param [Hash] scope
# Scoping keywords as understood by {#xpath}
#
Expand All @@ -396,29 +396,31 @@ def do_not_see(text, scope=nil)
def see_within_seconds(text, seconds=-1, scope=nil)
return skip_status if skip_step?
end_study
if scope == nil && (seconds.is_a? Hash)
if scope.nil? && (seconds.is_a? Hash)
scope = seconds
seconds = -1
end
seconds = @browser.default_timeout_in_seconds if seconds == -1
if scope == nil
return pass_if !(Integer(seconds)+1).times{ break if (@browser.text?(text) rescue false); sleep 1 }
if scope.nil?
return pass_if result_within(seconds) {
@browser.text?(text)
}
# This would be better if it worked:
# pass_if @browser.wait_for(:text => text, :timeout_in_seconds => seconds);
else
selector = loc("css=", '', scope).strip
# Default selenium_compare does not allow text around a glob. Allow such text.
text = text.sub(/^(glob:)?\*?/, '*').sub(/\*?$/, '*') unless /^(exact|regexpi?):/ === text
return pass_if !(Integer(seconds)+1).times{ break if (selenium_compare(@browser.get_text(selector), text) rescue false); sleep 1 }
return pass_if result_within(seconds) {
selenium_compare(@browser.get_text(selector), globify(text))
}
end
end

# Ensure that the given text does not appear on the current page, eventually.
#
# @param [String] text
# Plain text that should disappear from or not be present on the current page
# @param [String] seconds
# Integer number of seconds to wait.
# @param [Integer, String] seconds
# Integer number of seconds to wait, or `-1` to use the default timeout.
# @param [Hash] scope
# Scoping keywords as understood by {#xpath}
#
Expand All @@ -431,21 +433,22 @@ def see_within_seconds(text, seconds=-1, scope=nil)
def do_not_see_within_seconds(text, seconds=-1, scope=nil)
return skip_status if skip_step?
end_study
if scope == nil && (seconds.is_a? Hash)
if scope.nil? && (seconds.is_a? Hash)
scope = seconds
seconds = -1
end
seconds = @browser.default_timeout_in_seconds if seconds == -1
if scope == nil
pass_if !(Integer(seconds)+1).times{ break if (!@browser.text?(text) rescue false); sleep 1 }
if scope.nil?
return pass_if result_within(seconds) {
!@browser.text?(text)
}
# This would be better if it worked:
# pass_if @browser.wait_for(:no_text => text, :timeout_in_seconds => seconds);
else
selector = loc("css=", '', scope).strip
# Default selenium_compare does not allow text around a glob. Allow such text.
text = text.sub(/^(glob:)?\*?/, '*').sub(/\*?$/, '*') unless /^(exact|regexpi?):/ === text
# Re: rescue: If the scope is not found, the text is not seen.
return pass_if !(Integer(seconds)+1).times{ break if (!selenium_compare(@browser.get_text(selector), text) rescue true); sleep 1 }
return pass_if failed_within(seconds) {
selenium_compare(@browser.get_text(selector), globify(text))
}
end
end

Expand All @@ -464,7 +467,8 @@ def see_title(title)
# Study workaround when possible. (Probably won't happen a lot, but possible.)
bodynode = @study.get_node('xpath=/html/head/title')
return true if bodynode && bodynode.inner_text.strip == title
pass_if @browser.get_title == title, "Page title is '#{@browser.get_title}', not '#{title}'"
pass_if @browser.get_title == title,
"Page title is '#{@browser.get_title}', not '#{title}'"
end


Expand All @@ -487,8 +491,8 @@ def do_not_see_title(title)
# @param [String] text
# Text of the alert that you expect to see
#
# @param [String] seconds
# Integer number of seconds to wait.
# @param [Integer, String] seconds
# Integer number of seconds to wait, or `-1` to use the default timeout.
#
# @example
# | see alert within seconds |
Expand All @@ -511,10 +515,13 @@ def see_alert_within_seconds(text=nil, seconds=-1)
end
end
seconds = @browser.default_timeout_in_seconds if seconds == -1
alert_text = nil
if !(Integer(seconds)+1).times{ break if ((alert_text=@browser.get_alert) rescue false); sleep 1 }
return true if text == nil
return pass_if selenium_compare(alert_text, text), "Expected alert '#{text}', but got '#{alert_text}'!"
alert_text = result_within(seconds) {
@browser.get_alert
}
if alert_text
return true if text.nil?
return pass_if selenium_compare(alert_text, text),
"Expected alert '#{text}', but got '#{alert_text}'!"
else
return failure
end
Expand Down Expand Up @@ -585,7 +592,8 @@ def button_exists(locator, scope={})
#
def row_exists(cells)
return skip_status if skip_step?
locator = ("xpath=#{xpath_row_containing(cells.split(/, */).map{|s| escape_for_hash(s)})}")
cells = cells.split(/, */).map { |s| escape_for_hash(s) }
locator = "xpath=#{xpath_row_containing(cells)}"

# Study workaround when possible.
bodynode = @study.get_node(locator)
Expand Down Expand Up @@ -1323,11 +1331,11 @@ def fields_equal(fields={}, scope={})
fields.keys.each do |field|
unless generic_field_equals(escape_for_hash(field.to_s), escape_for_hash(fields[field]), scope)
end_study if method_study
return failure
return failure
end
end
if method_study
end_study
end_study
@study.undo_last_dirty
end
return true
Expand Down Expand Up @@ -1386,11 +1394,11 @@ def fields_equal_among(fields={}, ids={}, scope={})
fields.keys.each do |field|
unless field_equals_among(escape_for_hash(field.to_s), escape_for_hash(fields[field]), ids, scope)
end_study if method_study
return failure
return failure
end
end
if method_study
end_study
end_study
@study.undo_last_dirty
end
return true
Expand Down Expand Up @@ -1432,7 +1440,8 @@ def method_missing(method, *args, &block)
# The method call succeeded
# Should we check this against another string?
if do_check
return pass_if selenium_compare(result.to_s, check_against), "Expected '#{check_against}', but got '#{result.to_s}'"
return pass_if selenium_compare(result.to_s, check_against),
"Expected '#{check_against}', but got '#{result.to_s}'"
end
# Did it return true or false?
return failure if result == false
Expand Down Expand Up @@ -1548,7 +1557,7 @@ def end_if

last_status = @conditional_stack.pop
# If this end_if is within an un-executed if block, don't execute it.
return nil if last_status == nil
return nil if last_status.nil?
return true
end

Expand Down Expand Up @@ -1605,7 +1614,7 @@ def in_conditional?
# @since 0.1.2
#
def in_nil_conditional?
return in_conditional? && @conditional_stack.last == nil
return in_conditional? && @conditional_stack.last.nil?
end

# Return true if we're inside a conditional block that was skipped,
Expand Down Expand Up @@ -1645,7 +1654,7 @@ def push_conditional(result)

# Overrides the support.rb loc() method, allowing searching a studied page
# to try simplify a CSS or XPath expression to an id= or name= expression.
#
#
# @param [Boolean] try_study
# Try to use the studied page to simplify the path? Defaults to true.
def loc(locator, kind='', scope={}, try_study=true)
Expand Down
82 changes: 79 additions & 3 deletions lib/rsel/support.rb
Original file line number Diff line number Diff line change
Expand Up @@ -268,15 +268,91 @@ def selenium_compare(text, expected)
end
end

# Default selenium_compare does not allow text around a glob. Allow such text.
# TODO: Document/test this
def allow_text_in_glob(text)
# Return `text` with glob markers `*` on each end, unless the text
# begins with `exact:`, `regexp:`, or `regexpi:`. This effectively
# allows normal text to match as a "contains" search instead of
# matching the entire string.
#
# @param [String] text
# Text to globify
#
# @since 0.1.2
#
def globify(text)
if /^(exact|regexpi?):/ === text
return text
else
return text.sub(/^(glob:)?\*?/, '*').sub(/\*?$/, '*')
end
end


# Ensure that a given block gets a result within a timeout.
#
# This executes the given block statement once per second, until it returns
# a value that evaluates as true (meaning anything other than `false` or
# `nil`), or until the `seconds` timeout is reached. If the block evaluates
# as true within the timeout, return the block result. Otherwise, return
# `nil`.
#
# If the block never returns a value other than `false` or `nil`, then
# return `nil`. If the block raises an exception (*any* exception), that's
# considered a false result, and the block will be retried until a true
# result is returned, or the `seconds` timeout is reached.
#
# @param [Integer, String] seconds
# Integer number of seconds to keep retrying the block
# @param [Block] block
# Any block of code that might evaluate to a non-false value
#
# @return
# Result of the block if it evaluated true-ish within the timeout, nil
# if the block always evaluated as false or raised an exception.
#
# @since 0.1.2
#
# TODO: Return false if the block takes too long to execute (and exceeds
# the timeout)
#
def result_within(seconds, &block)
(seconds.to_i + 1).times do
result = yield rescue nil
return result if result
sleep 1
end
return nil
end


# Ensure that a given block fails within a timeout.
#
# This is a kind of counterpart to {#result_within}
#
# @param [Integer, String] seconds
# Integer number of seconds to keep retrying the block
# @param [Block] block
# Any block of code that might evaluate to a false value,
# or raise an exception, within the timeout.
#
# @return [Boolean]
# true if the block failed (returned false/nil or raised an exception)
# within the timeout, false if the block never failed within the timeout.
#
# @since 0.1.2
#
def failed_within(seconds, &block)
(seconds.to_i + 1).times do
begin
result = yield
rescue
return true
else
return true if !result
end
sleep 1
end
return false
end
end
end

2 changes: 2 additions & 0 deletions spec/st_temporal_visibility_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@
@st.see_within_seconds("The text is here!", 1).should be_false
end
it "text appears too late in an id" do
# FIXME: This test occasionally fails for no apparent reason
# (the text is found within the timeout)
@st.see_within_seconds("The text is here!", 1, :within => 'newtext').should be_false
end
it "text never appears" do
Expand Down
2 changes: 1 addition & 1 deletion spec/st_visibility_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@
it "sees text within an id" do
@st.errors
@st.do_not_see("About this site", :within => 'header').should be_false
@st.errors.should eq("'About this site' found in 'About this site'")
@st.errors.should eq("'About this site' not expected, but found in 'About this site'")
end
end

Expand Down
Loading

0 comments on commit 5dbd728

Please sign in to comment.