Module: Rsel::Support
- Included in:
- SeleniumTest, StudyHtml
- Defined in:
- lib/rsel/support.rb
Overview
Support functions for Rsel
Instance Method Summary collapse
-
#apply_scope(container, inner) ⇒ Object
Restrict the scope of all XPath expressions in
inner
by prependingcontainer
to each of them, and return new union expression whereinner
matches only if it's a child ofcontainer
. -
#csspath(locator, scope = {}) ⇒ Object
Return a Selenium-style CSS extending the given CSS with a locator.
-
#escape_for_hash(text) ⇒ Object
Escape certain characters to generate characters that can't otherwise be used in FitNesse hashtables.
-
#failed_within(seconds, &block) ⇒ Boolean
Ensure that a given block fails within a timeout.
-
#globify(text) ⇒ Object
Return
text
with glob markers*
on each end, unless the text begins withexact:
,regexp:
, orregexpi:
. -
#loc(locator, kind = '', scope = {}) ⇒ Object
Convert the given locator to a format accepted by Selenium.
-
#normalize_ids(ids) ⇒ Object
Normalize the given hash of name => locator mappings.
-
#result_within(seconds, &block) ⇒ Object
Ensure that a given block gets a result within a timeout.
-
#selenium_compare(text, expected) ⇒ Object
Compare values like Selenium does, with regexpi? and globs.
-
#string_is_true?(s) ⇒ Boolean
Convert a string like "yes", "true", "1", etc.
-
#strip_tags(text) ⇒ Object
Strip HTML tags from the given text.
-
#xpath(kind, locator, scope = {}) ⇒ Object
Return a Selenium-style xpath generated by calling
XPath::HTML.<kind>
with the givenlocator
. -
#xpath_expressions(union) ⇒ Object
Return an array of individual Expressions in the given XPath::Union, or just
[union]
if it has no sub-expressions. -
#xpath_row_containing(texts) ⇒ Object
Return an XPath for any table row containing all strings in
texts
, within the current context. -
#xpath_sanitize(text) ⇒ Object
Return the given text string in an XPath-safe form, with any single-quotes escaped by using the XPath
concat
function to combine them with the rest of the text.
Instance Method Details
#apply_scope(container, inner) ⇒ Object
Restrict the scope of all XPath expressions in inner
by prepending
container
to each of them, and return new union expression where
inner
matches only if it's a child of container
.
124 125 126 127 128 129 |
# File 'lib/rsel/support.rb', line 124
def apply_scope(container, inner)
scoped_expressions = xpath_expressions(inner).collect do |expr|
container.child(expr)
end
return XPath::Union.new(*scoped_expressions).to_s
end
|
#csspath(locator, scope = {}) ⇒ Object
Return a Selenium-style CSS extending the given CSS with a locator.
67 68 69 70 71 72 73 74 75 |
# File 'lib/rsel/support.rb', line 67
def csspath(locator, scope={})
return locator unless locator =~ /^css=/ && scope != {}
if scope[:within]
locator[4,0] = "##{scope[:within]} "
elsif scope[:in_row]
locator[4,0] = "tr:contains(\"#{scope[:in_row]}\") "
end
return locator
end
|
#escape_for_hash(text) ⇒ Object
Escape certain characters to generate characters that can't otherwise be used in FitNesse hashtables.
- \; becomes :
- \' becomes ,
- [ becomes {
- ] becomes }
- \ becomes \
164 165 166 167 168 169 170 171 172 |
# File 'lib/rsel/support.rb', line 164
def escape_for_hash(text)
# ((?:\\\\)*) allows any extra pairs of "\"s to be saved.
text = text.gsub(/(^|[^\\])\\((?:\\\\)*);/, '\1\2:')
text = text.gsub(/(^|[^\\])\\((?:\\\\)*)'/, '\1\2,')
text = text.gsub(/(^|[^\\])\\((?:\\\\)*)\[/, '\1\2{')
text = text.gsub(/(^|[^\\])\\((?:\\\\)*)\]/, '\1\2}')
text = text.gsub(/\\\\/, '\\')
return text
end
|
#failed_within(seconds, &block) ⇒ Boolean
Ensure that a given block fails within a timeout.
This is a kind of counterpart to #result_within
354 355 356 357 358 359 360 361 362 363 364 365 366 |
# File 'lib/rsel/support.rb', line 354
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
|
#globify(text) ⇒ Object
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.
292 293 294 295 296 297 298 |
# File 'lib/rsel/support.rb', line 292
def globify(text)
if /^(exact|regexpi?):/ === text
return text
else
return text.sub(/^(glob:)?\*?/, '*').sub(/\*?$/, '*')
end
end
|
#loc(locator, kind = '', scope = {}) ⇒ Object
Convert the given locator to a format accepted by Selenium. If locator
starts with id=
, name=
, dom=
, xpath=
link=
or css=
, then the
locator is returned unchanged. Otherwise, locator
is assumed to be a
plain string, and a Selenium-style xpath=
locator is returned, matching
HTML elements of the given kind, in the given scope. This allows you to
use simple human-readable locator strings, or more specific
Selenium-style locators.
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
# File 'lib/rsel/support.rb', line 31
def loc(locator, kind='', scope={})
if locator.empty?
raise ArgumentError, "locator is required."
elsif locator =~ /^css=/ && scope != {}
return csspath(locator, scope)
elsif locator =~ /^(id=|name=|dom=|xpath=|link=|css=)/
return locator
else
if kind.empty?
raise ArgumentError, "kind is required for Rsel-style locators"
else
return xpath(kind, locator, scope)
end
end
end
|
#normalize_ids(ids) ⇒ Object
Normalize the given hash of name => locator mappings. Converts all keys to lowercase and calls #escape_for_hash on them.
180 181 182 183 184 185 186 187 188 189 190 191 192 |
# File 'lib/rsel/support.rb', line 180
def normalize_ids(ids)
ids = {} unless ids.is_a? Hash
ids.keys.each do |key|
new_key = escape_for_hash(key.to_s.downcase)
new_value = escape_for_hash(ids[key])
ids[new_key] = new_value
# Delete the old key if necessary
if new_key != key
ids.delete(key)
end
end
end
|
#result_within(seconds, &block) ⇒ Object
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.
TODO: Return false if the block takes too long to execute (and exceeds the timeout)
328 329 330 331 332 333 334 335 |
# File 'lib/rsel/support.rb', line 328
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
|
#selenium_compare(text, expected) ⇒ Object
Compare values like Selenium does, with regexpi? and globs.
268 269 270 271 272 273 274 275 276 277 278 279 280 |
# File 'lib/rsel/support.rb', line 268
def selenium_compare(text, expected)
if expected.sub!(/^regexp:/, '')
return /#{expected}/ === text
elsif expected.sub!(/^regexpi:/, '')
return /#{expected}/i === text
elsif expected.sub!(/^exact:/, '')
return text == expected
else
# Default is glob, whether or not glob: is present.
expected.sub!(/^glob:/, '')
return File.fnmatch(expected, text)
end
end
|
#string_is_true?(s) ⇒ Boolean
Convert a string like "yes", "true", "1", etc. Values currently recognized as true, case-insensitive:
- [empty string]
- 1
- Check
- Checked
- On
- Select
- Selected
- True
- Yes
255 256 257 |
# File 'lib/rsel/support.rb', line 255
def string_is_true?(s)
return /^(?:yes|true|on|(?:check|select)(?:ed)?|1|)$/i === s
end
|
#strip_tags(text) ⇒ Object
Strip HTML tags from the given text. This can be used for converting URLs that FitNesse has marked up back into plain URLs.
203 204 205 |
# File 'lib/rsel/support.rb', line 203
def strip_tags(text)
return text.gsub(/<\/?[^>]*>/, '')
end
|
#xpath(kind, locator, scope = {}) ⇒ Object
Return a Selenium-style xpath generated by calling XPath::HTML.<kind>
with the given locator
. If scope
options are provided, the xpath is
modified accordingly, to match only elements in the given scope.
102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 |
# File 'lib/rsel/support.rb', line 102
def xpath(kind, locator, scope={})
if !XPath::HTML.respond_to?(kind)
raise ArgumentError, "Unknown kind of locator: '#{kind}'"
end
loc_xp = XPath::HTML.send(kind, locator)
if scope[:within]
parent = XPath.descendant[XPath.attr(:id).equals(scope[:within])]
result = apply_scope(parent, loc_xp)
elsif scope[:in_row]
row = XPath.descendant(:tr)[XPath.contains(scope[:in_row])]
result = apply_scope(row, loc_xp)
else
result = loc_xp.to_s
end
return "xpath=#{result}"
end
|
#xpath_expressions(union) ⇒ Object
Return an array of individual Expressions in the given XPath::Union, or
just [union]
if it has no sub-expressions. This is an ugly recursive
hack, designed to allow splitting up unions into their constituents for
the purpose of modifying them individually and re-combining them.
142 143 144 145 146 147 148 149 150 |
# File 'lib/rsel/support.rb', line 142
def xpath_expressions(union)
if union.respond_to?(:expressions)
return union.expressions.collect do |expr|
xpath_expressions(expr)
end.flatten
else
return [union]
end
end
|
#xpath_row_containing(texts) ⇒ Object
Return an XPath for any table row containing all strings in texts
,
within the current context.
212 213 214 215 216 217 218 |
# File 'lib/rsel/support.rb', line 212
def xpath_row_containing(texts)
texts = [texts] if texts.class == String
conditions = texts.collect do |text|
"contains(., #{xpath_sanitize(text)})"
end.join(' and ')
return "//tr[#{conditions}]"
end
|
#xpath_sanitize(text) ⇒ Object
Return the given text string in an XPath-safe form, with
any single-quotes escaped by using the XPath concat
function to combine them with the rest of the text.
230 231 232 233 234 235 236 237 238 |
# File 'lib/rsel/support.rb', line 230
def xpath_sanitize(text)
# If there's nothing to escape, just wrap text in single-quotes
if !text.include?("'")
return "'#{text}'"
else
result = text.gsub(/'/, %{', "'", '})
return "concat('#{result}')"
end
end
|