=begin
license
---------------------------------------------------------------------------
Copyright (c) 2004-2005, Atomic Object LLC
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name "Atomic Object LLC" nor the names of contributors to
this software may be used to endorse or promote products derived from this
software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--------------------------------------------------------------------------
(based on BSD Open Source License)
=end
require 'test/unit/assertions'
require 'watir'
module Watir
# = Description
# Watir::Simple is a simple wrapper around the Watir module. It provides a
# similar set of operations while simplifying them and removing as much syntax
# and test-framework context code as possible.
# The goal is to allow toolsmiths to write domain-language frameworks on top of
# Watir, using Watir::Simple as an easier, lightweight interface to the power
# of Watir.
#
# = Note
# Most action methods in Watir::Simple will automatically wait for the browser
# not to be busy before and after they perform the specified action.
#--
# revision: $Revision$
module Simple
# Open up a browser and point it at a certain URL.
def new_browser_at(url)
@@browser = IE.new
@@browser.typingspeed = 0
@@browser.goto url
end
# Tell the browser to load a particular URL.
def navigate_to(url)
@@browser.goto url
end
# Much like click_link_with_url but navigates to link instead of clicking it,
# thereby not invoking OnClick for links.
def navigate_to_link_with_url(url)
# FIXME: this should be moved into Watir!
wait_before_and_after do
doc = @@browser.getDocument
links = doc.links
link = nil
links.each do |n|
match = false
case url
when Regexp
match = (n.invoke("href") =~ url)
when String
match = (n.invoke("href") == url)
end
if match
link = n
break
end
end
raise "Couldn't find link with url #{url}" unless link
@@browser.goto link
end
end
# Much like click_link_with_id but navigates to link instead of clicking it,
# thereby not invoking OnClick for links.
def navigate_to_link_with_id(id)
# FIXME: this should be moved into Watir!
wait_before_and_after do
doc = @@browser.getDocument
links = doc.links
link = nil
links.each do |n|
match = false
case id
when Regexp
match = (n.invoke("id") =~ id)
when String
match = (n.invoke("id") == id)
end
if match
link = n
break
end
end
raise "Couldn't find link with id #{id}" unless link
@@browser.goto link
end
end
# Tell the browser to click on the first link with the specified URL.
# This takes the address of the link instead of the text displayed.
# * url - can be a string to match exactly, or a regular expression.
#
# Example:
# click_link_with_url "http://google.com"
# or:
# click_link_with_url /goo*/
def click_link_with_url(url)
wait_before_and_after { @@browser.link(:url, url).click }
end
# Tell the browser to click on the first link with the specified id attribute
# (the preferred method.)
def click_link_with_id(id)
wait_before_and_after { @@browser.link(:id, id).click }
end
# Tell the browser to click on the first link with the specified name attribute
def click_link_with_name(name)
wait_before_and_after { @@browser.link(:name, name).click }
end
# Tell the browser to click on the specified link as determined by the
# sequential ordering of links on the document.
def click_link_with_index(index)
wait_before_and_after { @@browser.link(:index, index).click }
end
# Tell the browser to click on the first link with the specified text in the
# link body.
def click_link_with_text(text)
wait_before_and_after { @@browser.link(:text, text).click }
end
# Set the text of the field with a given name (the preferred method.)
# This only types characters into the field and does not submit the form.
def enter_text_into_field_with_name(name, text)
wait_before_and_after { @@browser.textField(:name, name).set(text) }
end
# Set the text of the field with a given id attribute (the preferred method.)
# This only types characters into the field and does not submit the form.
def enter_text_into_field_with_id(id, text)
wait_before_and_after { @@browser.textField(:id, id).set(text) }
end
# Set the text of the indexed field. This only types characters
# into the field and does not submit the form.
def enter_text_into_field_with_index(index, text)
wait_before_and_after { @@browser.textField(:index, index).set(text) }
end
# Select an item from a selectbox (a.k.a "combo box", or "pulldown")
# The selectbox is chose by matching its name attribute.
# The item is selected based on the text content of tags.
def select_from_combobox_with_name(name, text)
wait_before_and_after { @@browser.selectBox(:name, name).select(text) }
end
# Select an item from a selectbox (a.k.a "combo box", or "pulldown")
# The selectbox is chose by matching its id attribute.
# The item is selected based on the text content of tags.
def select_from_combobox_with_id(id, text)
wait_before_and_after { @@browser.selectBox(:id, id).select(text) }
end
# Select an item from a selectbox (a.k.a "combo box", or "pulldown")
# The selectbox is chose by matching its order of appearance in the
# document.
# The item is selected based on the text content of tags.
def select_from_combobox_with_index(index, text)
wait_before_and_after { @@browser.selectBox(:index, index).select(text) }
end
# Select an item (+value+) from the radio button collection with +name+.
def select_radio_button_with_name(name, value)
wait_before_and_after { @@browser.radio(:name, name, value).click }
end
# Select an item (+value+) from the +index+'th radio button collection.
def select_radio_button_with_name(index, value)
wait_before_and_after { @@browser.radio(:index, index, value).click }
end
# Select an item (+value+) from the radio button collection with a matching
# +id+ attribute.
def select_radio_button_with_id(id, value)
wait_before_and_after { @@browser.radio(:id, id, value).click }
end
# Tell the browser to click on a form button with +name+.
def click_button_with_name(name)
wait_before_and_after { @@browser.button(:name, name).click }
end
# Tell the browser to click on a form button with the specified id attribute.
def click_button_with_id(id)
wait_before_and_after { @@browser.button(:id, id).click }
end
# Tell the browser to click on a form button with the specified value attribute.
def click_button_with_value(value)
wait_before_and_after { @@browser.button(:value, value).click }
end
# Tell the browser to click on a form button with the specified caption text.
def click_button_with_caption(caption)
wait_before_and_after { @@browser.button(:caption, caption).click }
end
# Tell the browser to click on the +index+'th form button on the page.
def click_button_with_index(index)
wait_before_and_after { @@browser.button(:index, index).click }
end
# Make a Test::Unit assertion that the given +text+ does not appear in the text
# body.
#
# * mesg - An assertion-failed message.
def assert_text_not_in_body(text,mesg=nil)
if mesg.nil? then
assert_false( @@browser.pageContainsText(text), "found in body: [#{text}]")
else
assert_false( @@browser.pageContainsText(text), mesg)
end
end
# Make a Test::Unit assertion that the given +text+ appears in the text
# body.
#
# * text - +String+ or +RegExp+ - The text or regular expression to search for.
# * mesg - +String+ - An optional assertion-failed message.
def assert_text_in_body(text,mesg=nil)
if mesg.nil? then
assert(@@browser.pageContainsText(text), "couldn't find in body: [#{text}]")
else
assert(@@browser.pageContainsText(text), mesg)
end
end
# This method returns true|false if the text/reg exp supplied is in a the text field "name".
#
# * name - +String+ - Name of field to examine.
# * text - +String+ or +RegExp+ - The text or regular expression to search for.
# * mesg - +String+ - An optional assertion-failed message.
def assert_text_in_field(name, text, mesg=nil)
if mesg.nil? then
assert(@@browser.textField(:name, name).verify_contains(text), "couldn't find in field #{name}: [#{text}]")
else
assert(@@browser.textField(:name, name).verify_contains(text), mesg)
end
end
#
# * how - symbol - the way we look for the object. Supported values are
# - :name
# - :id
# - :index
# * what - string - What field, id or name to examine.
# * text - string/Array of Strings - The string or array of strings to search for.
# * mesg - Optional! string - Set this if you want to supply your own error message
def assert_text_in_combobox_wrapper(how, what, text, mesg=nil)
assert(@@browser.selectBox(how, what), "could not find a combobox with what: #{what} and how: #{how}")
selectedItems = @@browser.selectBox(how, what).getSelectedItems
if text.kind_of? String
if mesg.nil? then
assert(selectedItems[0] == text, "couldn't find text in combobox with #{how}: #{what} - [#{text}], had [#{selectedItems[0]}]")
else
assert(selectedItems[0] == text, mesg)
end
elsif text.kind_of? Array
if mesg.nil? then
text.each do |item|
assert(selectedItems.include?(item), "couldn't find text in combobox with #{how}: #{what} - [#{text}], had [#{selectedItems}]")
end
else
text.each do |item|
assert(selectedItems.include?(item), mesg)
end
end
end
end
# This method returns true|false if the text is selected in the combobox
# with the supplied name.
#
# * name - string - Name of field to examine.
# * text - string/Array of Strings - The string or array of strings to search for.
# * mesg - Optional! string - Set this if you want to supply your own error message
def assert_text_in_combobox_by_name(name, text, mesg=nil)
assert_text_in_combobox_wrapper(:name, name, text, mesg)
end
# FIXME: how to use?
# This method returns true|false if the text is selected in the combobox
# with the supplied index.
#
# * index - string - Index of field to examine.
# * text - string/Array of Strings - The string or array of strings to search for.
# * mesg - Optional! string - Set this if you want to supply your own error message
#def assert_text_in_combobox_by_index(index, text, mesg=nil)
# assert_text_in_combobox_wrapper(:index, name, text, mesg)
#end
# This method returns true|false if the text is selected in the combobox
# with the supplied id.
#
# * id - string - Id of field to examine.
# * text - string/Array of Strings - The string or array of strings to search for.
# * mesg - Optional! string - Set this if you want to supply your own error message
def assert_text_in_combobox_by_id(id, text, mesg=nil)
assert_text_in_combobox_wrapper(:id, name, text, mesg)
end
# Close the browser window. Useful for automated test suites to reduce
# test interaction.
def close_browser
@@browser.getIE.quit
sleep 2
end
# Tell the browser to cick the Back button.
def go_back
@@browser.back
end
# Tell the browser to cick the Forward button.
def go_forward
@@browser.forward
end
# Fill a series of text fields. This takes a hash of textfield names to
# values for those fields.
#
# Example:
#
# fill_text_fields {
# 'username' => 'joe',
# 'password' => 'blahblah',
# 'email' => 'joe@blahblah.com',
# 'favorite_num' => 42
# }
def fill_text_fields(data)
data.each do |field, value|
@@browser.textField(:name, field).set(value)
end
end
# Fill a single textfield with a value
def fill_text_field(field_name, text)
@@browser.textField(:name, field_name).set(text)
end
# Some browsers (i.e. IE) need to be waited on before more actions can be
# performed. Most action methods in Watir::Simple already call this before
# and after.
def wait_for_browser
@@browser.waitForIE
end
def combobox_default_selection(name)
# FIXME _where_ is this used?
@@browser.selectBox(:name, name).value
end
# Returns the number of times +text+ appears in the body text of the page.
def count_instances_of(text)
@@browser.getDocument.body.innerText.scan(text).size
end
# Make a Test::Unit assertion that an image exists on the page with the given
# +src+ attribute.
#
# * mesg - +String+ - An optional assertion-failed message.
def assert_image_with_src(src, mesg=nil)
if mesg.nil? then
assert( get_image_with_src(src) != nil, "image with src: [#{src}] is not present")
else
assert( get_image_with_src(src) != nil, mesg)
end
end
# Make a Test::Unit assertion that an image exists on the page with the given
# +id+ attribute. (Preferred method)
#
# * mesg - +String+ - An optional assertion-failed message.
def assert_image_with_id(id, mesg=nil)
if mesg.nil? then
assert( get_image_with_id(id) != nil, "image with id: [#{id}] is not present")
else
assert( get_image_with_id(id) != nil, mesg)
end
end
# A convenience method to wait at both ends of an operation for the browser
# to catch up.
def wait_before_and_after
wait_for_browser
yield
wait_for_browser
end
#### PRIVATE METHODS BEYOND THIS POINT
private
####
def get_image_with_src(src)
@@browser.image(:src, src)
end
def get_image_with_id(id)
@@browser.image(:id, id)
end
end
end