module Watir
class InputElement < Element #:nodoc:all
def locate
@o = @container.locate_input_element(@how, @what, self.class::INPUT_TYPES)
end
def initialize(container, how, what)
set_container container
@how = how
@what = what
super(nil)
end
end
#
# Input: Select
#
# This class is the way in which select boxes are manipulated.
# Normally a user would not need to create this object as it is returned by the Watir::Container#select_list method
class SelectList < InputElement
#:stopdoc:
INPUT_TYPES = ["select-one", "select-multiple"]
#exposed to Option class
attr_accessor :o
#:startdoc:
# This method clears the selected items in the select box
def clear
assert_exists
highlight(:set)
wait = false
@o.each do |selectBoxItem|
if selectBoxItem.selected
selectBoxItem.selected = false
wait = true
end
end
@container.wait if wait
highlight(:clear)
end
# This method selects an item, or items in a select box, by text.
# Raises NoValueFoundException if the specified value is not found.
# * item - the thing to select, string or reg exp
def select(item)
select_item_in_select_list(:text, item)
end
alias :set :select
# Selects an item, or items in a select box, by value.
# Raises NoValueFoundException if the specified value is not found.
# * item - the value of the thing to select, string, reg exp
def select_value(item)
select_item_in_select_list(:value, item)
end
# BUG: Should be private
# Selects something from the select box
# * name - symbol :value or :text - how we find an item in the select box
# * item - string or reg exp - what we are looking for
def select_item_in_select_list(attribute, value) #:nodoc:
assert_exists
highlight(:set)
found = false
value = value.to_s unless [Regexp, String].any? { |e| value.kind_of? e }
@container.log "Setting box #{@o.name} to #{attribute.inspect} => #{value.inspect}"
@o.each do |option| # items in the list
if value.matches(option.invoke(attribute.to_s))
if option.selected
found = true
break
else
option.selected = true
@o.fireEvent("onChange")
@container.wait
found = true
break
end
end
end
unless found
raise NoValueFoundException, "No option with #{attribute.inspect} of #{value.inspect} in this select element"
end
highlight(:clear)
end
# Returns array of all text items displayed in a select box
# An empty array is returned if the select box has no contents.
# Raises UnknownObjectException if the select box is not found
def options
assert_exists
@container.log "There are #{@o.length} items"
returnArray = []
@o.each { |thisItem| returnArray << thisItem.text }
return returnArray
end
# Returns array of the selected text items in a select box
# Raises UnknownObjectException if the select box is not found.
def selected_options
assert_exists
returnArray = []
@container.log "There are #{@o.length} items"
@o.each do |thisItem|
if thisItem.selected
@container.log "Item (#{thisItem.text}) is selected"
returnArray << thisItem.text
end
end
return returnArray
end
# Does the SelectList include the specified option (text)?
def include? text_or_regexp
getAllContents.grep(text_or_regexp).size > 0
end
# Is the specified option (text) selected? Raises exception of option does not exist.
def selected? text_or_regexp
unless includes? text_or_regexp
raise UnknownObjectException, "Option #{text_or_regexp.inspect} not found."
end
getSelectedItems.grep(text_or_regexp).size > 0
end
# this method provides the access to the item in select_list
#
# Usage example:
#
# Given the following html:
#
#
#
# get the +value+ attribute of option with visible +text+ 'Female'
# browser.select_list(:id, 'gender').option(:text, 'Female').value #=> 'F'
# or find out if the +value+ 'M' is selected
# browser.select_list(:id, 'gender').option(:value, 'M').selected #=> true
#
# * attribute - Symbol :value, :text or other attribute - how we find an item in the select box
# * value - string or reg exp - what we are looking for
def option(attribute, value)
assert_exists
Option.new(self, attribute, value)
end
end
module OptionAccess
# text of SelectList#option
def text
@option.text
end
# value of SelectList#option
def value
@option.value
end
# return true if SelectList#option is selected, else false
def selected
@option.selected
end
end
class OptionWrapper #:nodoc:all
include OptionAccess
def initialize(option)
@option = option
end
end
# An item in a select list.
# Normally a user would not need to create this object as it is returned by the Watir::SelectList#option method
class Option
include OptionAccess
include Watir::Exception
def initialize(select_list, attribute, value)
@select_list = select_list
@how = attribute
@what = value
@option = nil
unless [:text, :value, :label].include? attribute
raise MissingWayOfFindingObjectException,
"Option does not support attribute #{@how}"
end
@select_list.o.each do |option| # items in the list
if value.matches(option.invoke(attribute.to_s))
@option = option
break
end
end
end
def assert_exists
unless @option
raise UnknownObjectException,
"Unable to locate an option using #{@how} and #{@what}"
end
end
private :assert_exists
# select the accessed option in select_list
def select
assert_exists
@select_list.select_item_in_select_list(@how, @what)
end
end
#
# Input: Button
#
# Returned by the Watir::Container#button method
class Button < InputElement
#:stopdoc:
INPUT_TYPES = ["button", "submit", "image", "reset"]
#:startdoc:
end
#
# Input: Text
#
# This class is the main class for Text Fields
# Normally a user would not need to create this object as it is returned by the Watir::Container#text_field method
class TextField < InputElement
#:stopdoc:
INPUT_TYPES = ["text", "password", "textarea"]
def_wrap_guard :size
# Returns true or false if the text field is read only.
# Raises UnknownObjectException if the object can't be found.
def_wrap :readonly?, :readOnly
#:startdoc:
# return number of maxlength attribute
def maxlength
assert_exists
begin
ole_object.invoke('maxlength').to_i
rescue WIN32OLERuntimeError
0
end
end
def text_string_creator
n = []
n << "length:".ljust(TO_S_SIZE) + self.size.to_s
n << "max length:".ljust(TO_S_SIZE) + self.maxlength.to_s
n << "read only:".ljust(TO_S_SIZE) + self.readonly?.to_s
n
end
private :text_string_creator
def to_s
assert_exists
r = string_creator
r += text_string_creator
r.join("\n")
end
def assert_not_readonly #:nodoc:
if self.readonly?
raise ObjectReadOnlyException,
"Textfield #{@how} and #{@what} is read only."
end
end
# Returns true if the text field contents is matches the specified target,
# which can be either a string or a regular expression.
# Raises UnknownObjectException if the object can't be found
#--
# I vote for deprecating this
# we should use text_field().text.include?(some) or text.match(/some/) instead of this method
def verify_contains(target) #:nodoc:
assert_exists
if target.kind_of? String
return true if self.value == target
elsif target.kind_of? Regexp
return true if self.value.match(target) != nil
end
return false
end
# Drag the entire contents of the text field to another text field
# 19 Jan 2005 - It is added as prototype functionality, and may change
# * destination_how - symbol, :id, :name how we identify the drop target
# * destination_what - string or regular expression, the name, id, etc of the text field that will be the drop target
def drag_contents_to(destination_how, destination_what)
assert_exists
destination = @container.text_field(destination_how, destination_what)
unless destination.exists?
raise UnknownObjectException, "Unable to locate destination using #{destination_how } and #{destination_what } "
end
@o.focus
@o.select
value = self.value
@o.fireEvent("onSelect")
@o.fireEvent("ondragstart")
@o.fireEvent("ondrag")
destination.fireEvent("onDragEnter")
destination.fireEvent("onDragOver")
destination.fireEvent("ondrop")
@o.fireEvent("ondragend")
destination.value = destination.value + value.to_s
self.value = ""
end
# Clears the contents of the text box.
# Raises UnknownObjectException if the object can't be found
# Raises ObjectDisabledException if the object is disabled
# Raises ObjectReadOnlyException if the object is read only
def clear
assert_enabled
assert_not_readonly
highlight(:set)
@o.scrollIntoView
@o.focus
@o.select
@o.fireEvent("onSelect")
@o.value = ""
@o.fireEvent("onKeyPress")
@o.fireEvent("onChange")
@container.wait
highlight(:clear)
end
# Appends the specified string value to the contents of the text box.
# Raises UnknownObjectException if the object cant be found
# Raises ObjectDisabledException if the object is disabled
# Raises ObjectReadOnlyException if the object is read only
def append(value)
assert_enabled
assert_not_readonly
highlight(:set)
@o.scrollIntoView
@o.focus
type_by_character(value)
highlight(:clear)
end
# Sets the contents of the text box to the specified text value
# Raises UnknownObjectException if the object cant be found
# Raises ObjectDisabledException if the object is disabled
# Raises ObjectReadOnlyException if the object is read only
def set(value)
assert_enabled
assert_not_readonly
highlight(:set)
@o.scrollIntoView
if type_keys
@o.focus
@o.select
@o.fireEvent("onSelect")
@o.fireEvent("onKeyPress")
@o.value = ""
type_by_character(value)
@o.fireEvent("onChange")
@o.fireEvent("onBlur")
else
@o.value = limit_to_maxlength(value)
end
highlight(:clear)
end
# Sets the value of the text field directly.
# It causes no events to be fired or exceptions to be raised,
# so generally shouldn't be used.
# It is preffered to use the set method.
def value=(v)
assert_exists
@o.value = v.to_s
end
def requires_typing #:nodoc:
@type_keys = true
self
end
def abhors_typing #:nodoc:
@type_keys = false
self
end
private
# Type the characters in the specified string (value) one by one.
# It should not be used externally.
# * value - string - The string to enter into the text field
def type_by_character(value)
value = limit_to_maxlength(value)
characters_in(value) do |c|
sleep @container.typingspeed
@o.value = @o.value.to_s + c
@o.fireEvent("onKeyDown")
@o.fireEvent("onKeyPress")
@o.fireEvent("onKeyUp")
end
end
# Supports double-byte characters
def characters_in(value, &blk)
if RUBY_VERSION =~ /^1\.8/
index = 0
while index < value.length
len = value[index] > 128 ? 2 : 1
yield value[index, len]
index += len
end
else
value.each_char(&blk)
end
end
# Return the value (a string), limited to the maxlength of the element.
def limit_to_maxlength(value)
return value if @o.invoke('type') =~ /textarea/i # text areas don't have maxlength
if value.length > maxlength
value = value[0 .. maxlength - 1]
@container.log " Supplied string is #{value.length} chars, which exceeds the max length (#{maxlength}) of the field. Using value: #{value}"
end
value
end
end
# this class can be used to access hidden field objects
# Normally a user would not need to create this object as it is returned by the Watir::Container#hidden method
class Hidden < TextField
#:stopdoc:
INPUT_TYPES = ["hidden"]
#:startdoc:
# set is overriden in this class, as there is no way to set focus to a hidden field
def set(n)
self.value = n
end
# override the append method, so that focus isnt set to the hidden object
def append(n)
self.value = self.value.to_s + n.to_s
end
# override the clear method, so that focus isnt set to the hidden object
def clear
self.value = ""
end
# this method will do nothing, as you cant set focus to a hidden field
def focus
end
# Hidden element is never visible - returns false.
def visible?
assert_exists
false
end
end
# For fields that accept file uploads
# Windows dialog is opened and handled in this case by autoit
# launching into a new process.
# Normally a user would not need to create this object as it is returned by the Watir::Container#file_field method
class FileField < InputElement
#:stopdoc:
INPUT_TYPES = ["file"]
POPUP_TITLES = ['Choose file', 'Choose File to Upload']
#:startdoc:
# set the file location in the Choose file dialog in a new process
# will raise a WatirException if AutoIt is not correctly installed
def set(path_to_file)
assert_exists
require 'watir/windowhelper'
WindowHelper.check_autoit_installed
begin
Thread.new do
sleep 1 # it takes some time for popup to appear
system %{ruby -e '
require "win32ole"
@autoit = WIN32OLE.new("AutoItX3.Control")
time = Time.now
while (Time.now - time) < 15 # the loop will wait up to 15 seconds for popup to appear
#{POPUP_TITLES.inspect}.each do |popup_title|
next unless @autoit.WinWait(popup_title, "", 1) == 1
@autoit.ControlSetText(popup_title, "", "Edit1", #{path_to_file.inspect})
@autoit.ControlSend(popup_title, "", "Button2", "{ENTER}")
exit
end # each
end # while
'}
end.join(1)
rescue
raise Watir::Exception::WatirException, "Problem accessing Choose file dialog"
end
click
end
end
# This class contains common methods to both radio buttons and check boxes.
# Normally a user would not need to create this object as it is returned by the Watir::Container#checkbox or by Watir::Container#radio methods
#--
# most of the methods available to this element are inherited from the Element class
class RadioCheckCommon < InputElement
def locate #:nodoc:
@o = @container.locate_input_element(@how, @what, self.class::INPUT_TYPES, @value)
end
def initialize(container, how, what, value=nil)
super container, how, what
@value = value
end
def inspect
'#<%s:0x%x located=%s how=%s what=%s value=%s>' % [self.class, hash*2, !!ole_object, @how.inspect, @what.inspect, @value.inspect]
end
# This method determines if a radio button or check box is set.
# Returns true if set/checked; false if not set/checked.
# Raises UnknownObjectException if its unable to locate an object.
def set?
assert_exists
return @o.checked
end
alias checked? set?
# This method is the common code for setting or clearing checkboxes and radio.
def set_clear_item(set)
@o.checked = set
@o.fireEvent("onClick")
@container.wait
end
private :set_clear_item
end
#--
# this class makes the docs better
#++
# This class is the watir representation of a radio button.
# Normally a user would not need to create this object as it is returned by the Watir::Container#radio method
class Radio < RadioCheckCommon
INPUT_TYPES = ["radio"]
# This method clears a radio button. One of them will almost always be set.
# Returns true if set or false if not set.
# Raises UnknownObjectException if its unable to locate an object
# ObjectDisabledException IF THE OBJECT IS DISABLED
def clear
assert_enabled
highlight(:set)
set_clear_item(false)
highlight(:clear)
end
# This method sets the radio list item.
# Raises UnknownObjectException if it's unable to locate an object
# ObjectDisabledException if the object is disabled
def set
assert_enabled
highlight(:set)
@o.scrollIntoView
set_clear_item(true)
highlight(:clear)
end
end
# This class is the watir representation of a check box.
# Normally a user would not need to create this object as it is returned by the Watir::Container#checkbox method
class CheckBox < RadioCheckCommon
INPUT_TYPES = ["checkbox"]
# This method checks or unchecks the checkbox.
# With no arguments supplied it sets the checkbox.
# Setting false argument unchecks/clears the checkbox.
# Raises UnknownObjectException if it's unable to locate an object
# ObjectDisabledException if the object is disabled
def set(value=true)
assert_enabled
highlight :set
unless @o.checked == value
set_clear_item value
end
highlight :clear
end
# Clears a check box.
# Raises UnknownObjectException if its unable to locate an object
# ObjectDisabledException if the object is disabled
def clear
set false
end
end
end