watir 1.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/readme.rb +211 -0
- data/unittests/WindowLogonExample.rb +30 -0
- data/unittests/WindowLogonExtra.rb +7 -0
- data/unittests/all_tests.rb +10 -0
- data/unittests/all_tests_concurrent.rb +57 -0
- data/unittests/attachToExistingWindow_test.rb +40 -0
- data/unittests/buttons_test.rb +131 -0
- data/unittests/checkbox_test.rb +149 -0
- data/unittests/core_tests.rb +9 -0
- data/unittests/css_test.rb +60 -0
- data/unittests/div_test.rb +179 -0
- data/unittests/errorchecker_test.rb +29 -0
- data/unittests/filefield_test.rb +35 -0
- data/unittests/form_test.rb +279 -0
- data/unittests/frame_test.rb +141 -0
- data/unittests/html/blankpage.html +12 -0
- data/unittests/html/buttons1.html +40 -0
- data/unittests/html/checkboxes1.html +69 -0
- data/unittests/html/complex_table.html +36 -0
- data/unittests/html/cssTest.html +42 -0
- data/unittests/html/div.html +105 -0
- data/unittests/html/fileupload.html +45 -0
- data/unittests/html/formTest1.html +39 -0
- data/unittests/html/forms2.html +45 -0
- data/unittests/html/forms3.html +132 -0
- data/unittests/html/forms4.html +27 -0
- data/unittests/html/frame_buttons.html +4 -0
- data/unittests/html/frame_links.html +4 -0
- data/unittests/html/frame_multi.html +5 -0
- data/unittests/html/iframeTest.html +13 -0
- data/unittests/html/iframeTest1.html +7 -0
- data/unittests/html/iframeTest2.html +6 -0
- data/unittests/html/images/1.gif +0 -0
- data/unittests/html/images/2.GIF +0 -0
- data/unittests/html/images/3.GIF +0 -0
- data/unittests/html/images/button.jpg +0 -0
- data/unittests/html/images/circle.jpg +0 -0
- data/unittests/html/images/minus.GIF +0 -0
- data/unittests/html/images/originaltriangle.jpg +0 -0
- data/unittests/html/images/plus.gif +0 -0
- data/unittests/html/images/square.jpg +0 -0
- data/unittests/html/images/triangle.jpg +0 -0
- data/unittests/html/images1.html +52 -0
- data/unittests/html/javascriptevents.html +39 -0
- data/unittests/html/link_pass.html +11 -0
- data/unittests/html/links1.html +37 -0
- data/unittests/html/links2.html +11 -0
- data/unittests/html/nestedFrames.html +6 -0
- data/unittests/html/pass.html +10 -0
- data/unittests/html/popups1.html +60 -0
- data/unittests/html/radioButtons1.html +71 -0
- data/unittests/html/select_tealeaf.html +54 -0
- data/unittests/html/selectboxes1.html +55 -0
- data/unittests/html/simple_table.html +26 -0
- data/unittests/html/simple_table_buttons.html +104 -0
- data/unittests/html/simple_table_columns.html +76 -0
- data/unittests/html/table1.html +142 -0
- data/unittests/html/textarea.html +30 -0
- data/unittests/html/textfields1.html +87 -0
- data/unittests/html/textsearch.html +44 -0
- data/unittests/ie_mock.rb +93 -0
- data/unittests/ie_test.rb +50 -0
- data/unittests/images_test.rb +179 -0
- data/unittests/iostring.rb +30 -0
- data/unittests/iostring_test.rb +48 -0
- data/unittests/js_events_test.rb +77 -0
- data/unittests/jscriptExtraAlert.rb +6 -0
- data/unittests/jscriptExtraConfirmCancel.rb +7 -0
- data/unittests/jscriptExtraConfirmOk.rb +7 -0
- data/unittests/jscriptPushButton.rb +5 -0
- data/unittests/jscript_test.rb +57 -0
- data/unittests/links_test.rb +169 -0
- data/unittests/minmax_test.rb +31 -0
- data/unittests/navigate_test.rb +56 -0
- data/unittests/non_core_tests.rb +9 -0
- data/unittests/pagecontainstext_test.rb +49 -0
- data/unittests/popups_test.rb +44 -0
- data/unittests/radios_test.rb +164 -0
- data/unittests/screen_capture_test.rb +53 -0
- data/unittests/selectbox_test.rb +197 -0
- data/unittests/send_keys_test.rb +29 -0
- data/unittests/setup.rb +47 -0
- data/unittests/table_test.rb +306 -0
- data/unittests/textAreafields_test.rb +81 -0
- data/unittests/textfields_test.rb +239 -0
- data/watir.rb +3744 -0
- data/watir/AutoItX3.dll +0 -0
- data/watir/WindowHelper.rb +47 -0
- data/watir/camel_case.rb +37 -0
- data/watir/clickJSDialog.rb +19 -0
- data/watir/cookiemanager.rb +53 -0
- data/watir/exceptions.rb +60 -0
- data/watir/screen_capture.rb +115 -0
- data/watir/setFileDialog.rb +16 -0
- data/watir/testUnitAddons.rb +47 -0
- data/watir/watir_simple.rb +475 -0
- data/watir/winClicker.rb +505 -0
- metadata +152 -0
data/watir/AutoItX3.dll
ADDED
Binary file
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'win32ole'
|
2
|
+
|
3
|
+
class WindowHelper
|
4
|
+
def initialize( )
|
5
|
+
@autoit = WIN32OLE.new('AutoItX3.Control')
|
6
|
+
end
|
7
|
+
|
8
|
+
def push_alert_button()
|
9
|
+
@autoit.WinWait "Microsoft Internet Explorer", ""
|
10
|
+
@autoit.Send "{ENTER}"
|
11
|
+
end
|
12
|
+
|
13
|
+
def push_confirm_button_ok()
|
14
|
+
@autoit.WinWait "Microsoft Internet Explorer", ""
|
15
|
+
@autoit.Send "{ENTER}"
|
16
|
+
end
|
17
|
+
|
18
|
+
def push_confirm_button_cancel()
|
19
|
+
@autoit.WinWait "Microsoft Internet Explorer", ""
|
20
|
+
@autoit.Send "{ESCAPE}"
|
21
|
+
end
|
22
|
+
|
23
|
+
def push_security_alert_yes()
|
24
|
+
@autoit.WinWait "Security Alert", ""
|
25
|
+
@autoit.Send "{TAB}"
|
26
|
+
@autoit.Send "{TAB}"
|
27
|
+
@autoit.Send "{SPACE}"
|
28
|
+
end
|
29
|
+
|
30
|
+
def logon(title,name = 'john doe',password = 'john doe')
|
31
|
+
@autoit.WinWait title, ""
|
32
|
+
@autoit.Send name
|
33
|
+
@autoit.Send "{TAB}"
|
34
|
+
@autoit.Send password
|
35
|
+
@autoit.Send "{ENTER}"
|
36
|
+
end
|
37
|
+
|
38
|
+
def WindowHelper.check_autoit_installed
|
39
|
+
begin
|
40
|
+
WIN32OLE.new('AutoItX3.Control')
|
41
|
+
rescue
|
42
|
+
raise Watir::Exception::WatirException, "The AutoIt dll must be correctly registered for this feature to work properly"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
|
data/watir/camel_case.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
# These are provided for backwards compatability with Watir 1.1
|
2
|
+
|
3
|
+
module Watir
|
4
|
+
module SupportsSubElements
|
5
|
+
alias waitForIE wait
|
6
|
+
alias fileField file_field
|
7
|
+
alias textField text_field
|
8
|
+
alias selectBox select_list
|
9
|
+
alias checkBox checkbox
|
10
|
+
end
|
11
|
+
class IE
|
12
|
+
alias getStatus status
|
13
|
+
alias getDocument document
|
14
|
+
alias pageContainsText contains_text
|
15
|
+
alias waitForIE wait
|
16
|
+
alias getHTML html
|
17
|
+
alias getText text
|
18
|
+
alias showFrames show_frames
|
19
|
+
alias showForms show_forms
|
20
|
+
alias showImages show_images
|
21
|
+
alias showLinks show_links
|
22
|
+
alias showActive show_active
|
23
|
+
alias showAllObjects show_all_objects
|
24
|
+
end
|
25
|
+
class Frame
|
26
|
+
alias getDocument document
|
27
|
+
alias waitForIE wait
|
28
|
+
end
|
29
|
+
class Form
|
30
|
+
alias waitForIE wait
|
31
|
+
end
|
32
|
+
|
33
|
+
class SpanDivCommon
|
34
|
+
alias innerText text
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
#
|
2
|
+
# clickJSDialog.rb
|
3
|
+
#
|
4
|
+
#
|
5
|
+
# This file contains the JS clicker when it runs as a separate process
|
6
|
+
|
7
|
+
$LOAD_PATH << File.expand_path(File.join(File.dirname(__FILE__), '..'))
|
8
|
+
puts $LOAD_PATH
|
9
|
+
require 'watir/winClicker'
|
10
|
+
|
11
|
+
button = "OK"
|
12
|
+
button = ARGV[0] unless ARGV[0] == nil
|
13
|
+
sleepTime = 0
|
14
|
+
sleepTime = ARGV[1] unless ARGV[1] == nil
|
15
|
+
|
16
|
+
|
17
|
+
clicker= WinClicker.new
|
18
|
+
result = clicker.clickJavaScriptDialog( button )
|
19
|
+
clicker = nil
|
@@ -0,0 +1,53 @@
|
|
1
|
+
|
2
|
+
class Dir
|
3
|
+
def Dir.visit(dir = '.', files_first = false, &block)
|
4
|
+
if files_first
|
5
|
+
paths = []
|
6
|
+
Find.find(dir) { |path| paths << path }
|
7
|
+
paths.reverse_each {|path| yield path}
|
8
|
+
else
|
9
|
+
Find.find(dir, &block)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
# simulates unix rm -rf command
|
13
|
+
def Dir.rm_rf(dir)
|
14
|
+
Dir.visit(dir, true) do |path|
|
15
|
+
if FileTest.directory?(path)
|
16
|
+
begin
|
17
|
+
Dir.unlink(path)
|
18
|
+
rescue # Security Exception for Content.IE
|
19
|
+
end
|
20
|
+
else
|
21
|
+
begin
|
22
|
+
File.unlink(path)
|
23
|
+
rescue #Security exception index.dat etc.
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
module Watir
|
31
|
+
module CookieManager
|
32
|
+
|
33
|
+
class WatirHelper
|
34
|
+
#taken from shlObj.h used in win32 SHGetSpecialFolderLocation
|
35
|
+
#define CSIDL_INTERNET_CACHE 0x0020
|
36
|
+
#define CSIDL_COOKIES 0x0021
|
37
|
+
#define CSIDL_HISTORY 0x0022
|
38
|
+
COOKIES = 0x0021
|
39
|
+
INTERNET_CACHE = 0x0020
|
40
|
+
|
41
|
+
def WatirHelper.getSpecialFolderLocation(specFolderName)
|
42
|
+
shell = WIN32OLE.new("Shell.Application")
|
43
|
+
folder = shell.Namespace(specFolderName)
|
44
|
+
folderItem = folder.Self
|
45
|
+
folderPath = folderItem.Path
|
46
|
+
end
|
47
|
+
def WatirHelper.deleteSpecialFolderContents(specFolderName)
|
48
|
+
Dir.rm_rf(self.getSpecialFolderLocation(specFolderName))
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
data/watir/exceptions.rb
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
module Watir
|
2
|
+
module Exception
|
3
|
+
|
4
|
+
# Root class for all Watir Exceptions
|
5
|
+
class WatirException < RuntimeError
|
6
|
+
def initialize(message="")
|
7
|
+
super(message)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
# This exception is thrown if an attempt is made to access an object that doesn't exist
|
12
|
+
class UnknownObjectException < WatirException
|
13
|
+
end
|
14
|
+
|
15
|
+
# This exception is thrown if an attempt is made to access an object that is in a disabled state
|
16
|
+
class ObjectDisabledException < WatirException
|
17
|
+
end
|
18
|
+
|
19
|
+
# This exception is thrown if an attempt is made to access a frame that cannot be found
|
20
|
+
class UnknownFrameException< WatirException
|
21
|
+
end
|
22
|
+
|
23
|
+
# This exception is thrown if an attempt is made to access a form that cannot be found
|
24
|
+
class UnknownFormException< WatirException
|
25
|
+
end
|
26
|
+
|
27
|
+
# This exception is thrown if an attempt is made to access an object that is in a read only state
|
28
|
+
class ObjectReadOnlyException < WatirException
|
29
|
+
end
|
30
|
+
|
31
|
+
# This exception is thrown if an attempt is made to access an object when the specified value cannot be found
|
32
|
+
class NoValueFoundException < WatirException
|
33
|
+
end
|
34
|
+
|
35
|
+
# This exception gets raised if part of finding an object is missing
|
36
|
+
class MissingWayOfFindingObjectException < WatirException
|
37
|
+
end
|
38
|
+
|
39
|
+
# This exception is raised if an attempt is made to access a table that doesn't exist
|
40
|
+
class UnknownTableException < WatirException
|
41
|
+
end
|
42
|
+
|
43
|
+
# this exception is raised if an attempt is made to access a table cell that doesnt exist
|
44
|
+
class UnknownCellException < WatirException
|
45
|
+
end
|
46
|
+
|
47
|
+
# This exception is thrown if the window cannot be found
|
48
|
+
class NoMatchingWindowFoundException < WatirException
|
49
|
+
end
|
50
|
+
|
51
|
+
# This exception is thrown if an attemp is made to acces the status bar of the browser when it doesnt exist
|
52
|
+
class NoStatusBarException < WatirException
|
53
|
+
end
|
54
|
+
|
55
|
+
# This exception is thrown if an http error, such as a 404, 500 etc is encountered while navigating
|
56
|
+
class NavigationException < WatirException
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,115 @@
|
|
1
|
+
|
2
|
+
require 'Win32API'
|
3
|
+
|
4
|
+
module Watir
|
5
|
+
module ScreenCapture
|
6
|
+
|
7
|
+
KEYEVENTF_KEYUP = 0x2
|
8
|
+
SW_HIDE = 0
|
9
|
+
SW_SHOW = 5
|
10
|
+
SW_SHOWNORMAL = 1
|
11
|
+
VK_CONTROL = 0x11
|
12
|
+
VK_F4 = 0x73
|
13
|
+
VK_MENU = 0x12
|
14
|
+
VK_RETURN = 0x0D
|
15
|
+
VK_SHIFT = 0x10
|
16
|
+
VK_SNAPSHOT = 0x2C
|
17
|
+
VK_TAB = 0x09
|
18
|
+
GMEM_MOVEABLE = 0x0002
|
19
|
+
CF_TEXT = 1
|
20
|
+
|
21
|
+
# this method saves the current window or whole screen as either a bitmap or a jpeg
|
22
|
+
# It uses paint to save the file, so will barf if a duplicate filename is selected, or the path doesnt exist etc
|
23
|
+
# * filename - string - the name of the file to save. If its not fully qualified the current directory is used
|
24
|
+
# * active_window - boolean - if true, the whole screen is captured, if false, just the active window is captured
|
25
|
+
# * save_as_bmp - boolean - if true saves the file as a bitmap, saves it as a jpeg otherwise
|
26
|
+
def screen_capture(filename , active_window_only=false, save_as_bmp=false)
|
27
|
+
|
28
|
+
|
29
|
+
keybd_event = Win32API.new("user32", "keybd_event", ['I','I','L','L'], 'V')
|
30
|
+
vkKeyScan = Win32API.new("user32", "VkKeyScan", ['I'], 'I')
|
31
|
+
winExec = Win32API.new("kernel32", "WinExec", ['P','L'], 'L')
|
32
|
+
openClipboard = Win32API.new('user32', 'OpenClipboard', ['L'], 'I')
|
33
|
+
setClipboardData = Win32API.new('user32', 'SetClipboardData', ['I', 'I'], 'I')
|
34
|
+
closeClipboard = Win32API.new('user32', 'CloseClipboard', [], 'I')
|
35
|
+
globalAlloc = Win32API.new('kernel32', 'GlobalAlloc', ['I', 'I'], 'I')
|
36
|
+
globalLock = Win32API.new('kernel32', 'GlobalLock', ['I'], 'I')
|
37
|
+
globalUnlock = Win32API.new('kernel32', 'GlobalUnlock', ['I'], 'I')
|
38
|
+
memcpy = Win32API.new('msvcrt', 'memcpy', ['I', 'P', 'I'], 'I')
|
39
|
+
|
40
|
+
|
41
|
+
filename = Dir.getwd.tr('/','\\') + '\\' + filename unless filename.index('\\')
|
42
|
+
|
43
|
+
if active_window_only ==false
|
44
|
+
keybd_event.Call(VK_SNAPSHOT,0,0,0) # Print Screen
|
45
|
+
else
|
46
|
+
keybd_event.Call(VK_SNAPSHOT,1,0,0) # Alt+Print Screen
|
47
|
+
end
|
48
|
+
|
49
|
+
winExec.Call('mspaint.exe', SW_SHOW)
|
50
|
+
sleep(1)
|
51
|
+
|
52
|
+
# Ctrl + V : Paste
|
53
|
+
keybd_event.Call(VK_CONTROL, 1, 0, 0)
|
54
|
+
keybd_event.Call(vkKeyScan.Call(?V), 1, 0, 0)
|
55
|
+
keybd_event.Call(vkKeyScan.Call(?V), 1, KEYEVENTF_KEYUP, 0)
|
56
|
+
keybd_event.Call(VK_CONTROL, 1, KEYEVENTF_KEYUP, 0)
|
57
|
+
|
58
|
+
|
59
|
+
# Alt F + A : Save As
|
60
|
+
keybd_event.Call(VK_MENU, 1, 0, 0)
|
61
|
+
keybd_event.Call(vkKeyScan.Call(?F), 1, 0, 0)
|
62
|
+
keybd_event.Call(vkKeyScan.Call(?F), 1, KEYEVENTF_KEYUP, 0)
|
63
|
+
keybd_event.Call(VK_MENU, 1, KEYEVENTF_KEYUP, 0)
|
64
|
+
keybd_event.Call(vkKeyScan.Call(?A), 1, 0, 0)
|
65
|
+
keybd_event.Call(vkKeyScan.Call(?A), 1, KEYEVENTF_KEYUP, 0)
|
66
|
+
sleep(1)
|
67
|
+
|
68
|
+
# copy filename to clipboard
|
69
|
+
hmem = globalAlloc.Call(GMEM_MOVEABLE, filename.length+1)
|
70
|
+
mem = globalLock.Call(hmem)
|
71
|
+
memcpy.Call(mem, filename, filename.length+1)
|
72
|
+
globalUnlock.Call(hmem)
|
73
|
+
openClipboard.Call(0)
|
74
|
+
setClipboardData.Call(CF_TEXT, hmem)
|
75
|
+
closeClipboard.Call
|
76
|
+
sleep(1)
|
77
|
+
|
78
|
+
# Ctrl + V : Paste
|
79
|
+
keybd_event.Call(VK_CONTROL, 1, 0, 0)
|
80
|
+
keybd_event.Call(vkKeyScan.Call(?V), 1, 0, 0)
|
81
|
+
keybd_event.Call(vkKeyScan.Call(?V), 1, KEYEVENTF_KEYUP, 0)
|
82
|
+
keybd_event.Call(VK_CONTROL, 1, KEYEVENTF_KEYUP, 0)
|
83
|
+
|
84
|
+
if save_as_bmp == false
|
85
|
+
# goto the combo box
|
86
|
+
keybd_event.Call(VK_TAB, 1, 0, 0)
|
87
|
+
keybd_event.Call(VK_TAB, 1, KEYEVENTF_KEYUP, 0)
|
88
|
+
sleep(0.5)
|
89
|
+
|
90
|
+
# select the first entry with J
|
91
|
+
keybd_event.Call(vkKeyScan.Call(?J), 1, 0, 0)
|
92
|
+
keybd_event.Call(vkKeyScan.Call(?J), 1, KEYEVENTF_KEYUP, 0)
|
93
|
+
sleep(0.5)
|
94
|
+
end
|
95
|
+
|
96
|
+
# Enter key
|
97
|
+
keybd_event.Call(VK_RETURN, 1, 0, 0)
|
98
|
+
keybd_event.Call(VK_RETURN, 1, KEYEVENTF_KEYUP, 0)
|
99
|
+
sleep(1)
|
100
|
+
|
101
|
+
# Alt + F4 : Exit
|
102
|
+
keybd_event.Call(VK_MENU, 1, 0, 0)
|
103
|
+
keybd_event.Call(VK_F4, 1, 0, 0)
|
104
|
+
keybd_event.Call(VK_F4, 1, KEYEVENTF_KEYUP, 0)
|
105
|
+
keybd_event.Call(VK_MENU, 1, KEYEVENTF_KEYUP, 0)
|
106
|
+
sleep(1)
|
107
|
+
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
end
|
112
|
+
|
113
|
+
|
114
|
+
#screenCapture( "f.bmp", false , true)
|
115
|
+
|
@@ -0,0 +1,16 @@
|
|
1
|
+
#
|
2
|
+
# setFileDialog.rb
|
3
|
+
#
|
4
|
+
#
|
5
|
+
# This file contains the file dialog when it runs as a separate process
|
6
|
+
|
7
|
+
$LOAD_PATH << File.expand_path(File.join(File.dirname(__FILE__), '..'))
|
8
|
+
puts $LOAD_PATH
|
9
|
+
require 'watir/winClicker'
|
10
|
+
|
11
|
+
filepath = "invalid path passed to setFileDialog.rb"
|
12
|
+
filepath = ARGV[0] unless ARGV[0] == nil
|
13
|
+
|
14
|
+
clicker= WinClicker.new
|
15
|
+
clicker.setFileRequesterFileName(filepath)
|
16
|
+
clicker = nil
|
@@ -0,0 +1,47 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
module Test::Unit::Assertions
|
4
|
+
|
5
|
+
|
6
|
+
def assert_false(boolean, message=nil)
|
7
|
+
_wrap_assertion do
|
8
|
+
assert_block("assert should not be called with a block.") { !block_given? }
|
9
|
+
assert_block(build_message(message, "<?> is not false.", boolean)) { !boolean }
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
|
14
|
+
def compareArrays( expectArray, actualArray)
|
15
|
+
result = true
|
16
|
+
expectArray.each_with_index do |element,i|
|
17
|
+
#puts "Comparing #{element} #{element.class} with #{actualArray[i]} #{actualArray[i].class} "
|
18
|
+
if element != actualArray[i]
|
19
|
+
result = false
|
20
|
+
break
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
return result
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
def assert_arrayEquals(expectArray, actualArray, message = nil )
|
29
|
+
_wrap_assertion do
|
30
|
+
assert_block("assert should not be called with a block.") { !block_given? }
|
31
|
+
assert_equal(expectArray.length, actualArray.length, "Lengths did not match")
|
32
|
+
|
33
|
+
assert_block("contents are different." ){ compareArrays( expectArray, actualArray) }
|
34
|
+
end #_wrap
|
35
|
+
end #def
|
36
|
+
|
37
|
+
|
38
|
+
def assert_arrayContains(array, string , message =nil)
|
39
|
+
|
40
|
+
_wrap_assertion do
|
41
|
+
assert_block("assert should not be called with a block.") { !block_given? }
|
42
|
+
assert(array.kind_of?(Array) , "Must have an array")
|
43
|
+
assert(array.include?(string) , message)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
end # module test
|
@@ -0,0 +1,475 @@
|
|
1
|
+
=begin
|
2
|
+
license
|
3
|
+
---------------------------------------------------------------------------
|
4
|
+
Copyright (c) 2004-2005, Atomic Object LLC
|
5
|
+
All rights reserved.
|
6
|
+
|
7
|
+
Redistribution and use in source and binary forms, with or without
|
8
|
+
modification, are permitted provided that the following conditions are met:
|
9
|
+
|
10
|
+
1. Redistributions of source code must retain the above copyright notice,
|
11
|
+
this list of conditions and the following disclaimer.
|
12
|
+
|
13
|
+
2. Redistributions in binary form must reproduce the above copyright
|
14
|
+
notice, this list of conditions and the following disclaimer in the
|
15
|
+
documentation and/or other materials provided with the distribution.
|
16
|
+
|
17
|
+
3. Neither the name "Atomic Object LLC" nor the names of contributors to
|
18
|
+
this software may be used to endorse or promote products derived from this
|
19
|
+
software without specific prior written permission.
|
20
|
+
|
21
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
|
22
|
+
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
23
|
+
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
24
|
+
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
|
25
|
+
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
26
|
+
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
27
|
+
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
28
|
+
OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
29
|
+
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
30
|
+
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
31
|
+
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
32
|
+
--------------------------------------------------------------------------
|
33
|
+
(based on BSD Open Source License)
|
34
|
+
=end
|
35
|
+
|
36
|
+
require 'test/unit/assertions'
|
37
|
+
require 'watir'
|
38
|
+
|
39
|
+
module Watir
|
40
|
+
# = Description
|
41
|
+
# Watir::Simple is a simple wrapper around the Watir module. It provides a
|
42
|
+
# similar set of operations while simplifying them and removing as much syntax
|
43
|
+
# and test-framework context code as possible.
|
44
|
+
# The goal is to allow toolsmiths to write domain-language frameworks on top of
|
45
|
+
# Watir, using Watir::Simple as an easier, lightweight interface to the power
|
46
|
+
# of Watir.
|
47
|
+
#
|
48
|
+
# = Note
|
49
|
+
# Most action methods in Watir::Simple will automatically wait for the browser
|
50
|
+
# not to be busy before and after they perform the specified action.
|
51
|
+
#
|
52
|
+
# revision: $Revision: 1.1 $
|
53
|
+
module Simple
|
54
|
+
|
55
|
+
# Open up a browser and point it at a certain URL.
|
56
|
+
def new_browser_at(url)
|
57
|
+
@@browser = IE.new
|
58
|
+
@@browser.typingspeed = 0
|
59
|
+
@@browser.goto url
|
60
|
+
end
|
61
|
+
|
62
|
+
|
63
|
+
# Tell the browser to load a particular URL.
|
64
|
+
def navigate_to(url)
|
65
|
+
@@browser.goto url
|
66
|
+
end
|
67
|
+
|
68
|
+
|
69
|
+
# Much like click_link_with_url but navigates to link instead of clicking it,
|
70
|
+
# thereby not invoking OnClick for links.
|
71
|
+
def navigate_to_link_with_url(url)
|
72
|
+
# FIXME: this should be moved into Watir!
|
73
|
+
wait_before_and_after do
|
74
|
+
doc = @@browser.getDocument()
|
75
|
+
links = doc.links
|
76
|
+
link = nil
|
77
|
+
links.each do |n|
|
78
|
+
match = false
|
79
|
+
case url
|
80
|
+
when Regexp
|
81
|
+
match = (n.invoke("href") =~ url)
|
82
|
+
when String
|
83
|
+
match = (n.invoke("href") == url)
|
84
|
+
end
|
85
|
+
if match
|
86
|
+
link = n
|
87
|
+
break
|
88
|
+
end
|
89
|
+
end
|
90
|
+
raise "Couldn't find link with url #{url}" unless link
|
91
|
+
@@browser.goto link
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
# Much like click_link_with_id but navigates to link instead of clicking it,
|
96
|
+
# thereby not invoking OnClick for links.
|
97
|
+
def navigate_to_link_with_id(id)
|
98
|
+
# FIXME: this should be moved into Watir!
|
99
|
+
wait_before_and_after do
|
100
|
+
doc = @@browser.getDocument()
|
101
|
+
links = doc.links
|
102
|
+
link = nil
|
103
|
+
links.each do |n|
|
104
|
+
match = false
|
105
|
+
case id
|
106
|
+
when Regexp
|
107
|
+
match = (n.invoke("id") =~ id)
|
108
|
+
when String
|
109
|
+
match = (n.invoke("id") == id)
|
110
|
+
end
|
111
|
+
if match
|
112
|
+
link = n
|
113
|
+
break
|
114
|
+
end
|
115
|
+
end
|
116
|
+
raise "Couldn't find link with id #{id}" unless link
|
117
|
+
@@browser.goto link
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
# Tell the browser to click on the first link with the specified URL.
|
122
|
+
# This takes the address of the link instead of the text displayed.
|
123
|
+
# * url - can be a string to match exactly, or a regular expression.
|
124
|
+
#
|
125
|
+
# Example:
|
126
|
+
# click_link_with_url "http://google.com"
|
127
|
+
# or:
|
128
|
+
# click_link_with_url /goo*/
|
129
|
+
def click_link_with_url(url)
|
130
|
+
wait_before_and_after { @@browser.link(:url, url).click }
|
131
|
+
end
|
132
|
+
|
133
|
+
|
134
|
+
# Tell the browser to click on the first link with the specified id attribute
|
135
|
+
# (the preferred method.)
|
136
|
+
def click_link_with_id(id)
|
137
|
+
wait_before_and_after { @@browser.link(:id, id).click }
|
138
|
+
end
|
139
|
+
|
140
|
+
|
141
|
+
# Tell the browser to click on the first link with the specified name attribute
|
142
|
+
def click_link_with_name(name)
|
143
|
+
wait_before_and_after { @@browser.link(:name, name).click }
|
144
|
+
end
|
145
|
+
|
146
|
+
|
147
|
+
# Tell the browser to click on the specified link as determined by the
|
148
|
+
# sequential ordering of links on the document.
|
149
|
+
def click_link_with_index(index)
|
150
|
+
wait_before_and_after { @@browser.link(:index, index).click }
|
151
|
+
end
|
152
|
+
|
153
|
+
|
154
|
+
# Tell the browser to click on the first link with the specified text in the
|
155
|
+
# link body.
|
156
|
+
def click_link_with_text(text)
|
157
|
+
wait_before_and_after { @@browser.link(:text, text).click }
|
158
|
+
end
|
159
|
+
|
160
|
+
|
161
|
+
# Set the text of the field with a given name (the preferred method.)
|
162
|
+
# This only types characters into the field and does not submit the form.
|
163
|
+
def enter_text_into_field_with_name(name, text)
|
164
|
+
wait_before_and_after { @@browser.textField(:name, name).set(text) }
|
165
|
+
end
|
166
|
+
|
167
|
+
|
168
|
+
# Set the text of the field with a given id attribute (the preferred method.)
|
169
|
+
# This only types characters into the field and does not submit the form.
|
170
|
+
def enter_text_into_field_with_id(id, text)
|
171
|
+
wait_before_and_after { @@browser.textField(:id, id).set(text) }
|
172
|
+
end
|
173
|
+
|
174
|
+
|
175
|
+
# Set the text of the indexed field. This only types characters
|
176
|
+
# into the field and does not submit the form.
|
177
|
+
def enter_text_into_field_with_index(index, text)
|
178
|
+
wait_before_and_after { @@browser.textField(:index, index).set(text) }
|
179
|
+
end
|
180
|
+
|
181
|
+
|
182
|
+
# Select an item from a selectbox (a.k.a "combo box", or "pulldown")
|
183
|
+
# The selectbox is chose by matching its name attribute.
|
184
|
+
# The item is selected based on the text content of <OPTION> tags.
|
185
|
+
def select_from_combobox_with_name(name, text)
|
186
|
+
wait_before_and_after { @@browser.selectBox(:name, name).select(text) }
|
187
|
+
end
|
188
|
+
|
189
|
+
|
190
|
+
# Select an item from a selectbox (a.k.a "combo box", or "pulldown")
|
191
|
+
# The selectbox is chose by matching its id attribute.
|
192
|
+
# The item is selected based on the text content of <OPTION> tags.
|
193
|
+
def select_from_combobox_with_id(id, text)
|
194
|
+
wait_before_and_after { @@browser.selectBox(:id, id).select(text) }
|
195
|
+
end
|
196
|
+
|
197
|
+
|
198
|
+
# Select an item from a selectbox (a.k.a "combo box", or "pulldown")
|
199
|
+
# The selectbox is chose by matching its order of appearance in the
|
200
|
+
# document.
|
201
|
+
# The item is selected based on the text content of <OPTION> tags.
|
202
|
+
def select_from_combobox_with_index(index, text)
|
203
|
+
wait_before_and_after { @@browser.selectBox(:index, index).select(text) }
|
204
|
+
end
|
205
|
+
|
206
|
+
|
207
|
+
# Select an item (+value+) from the radio button collection with +name+.
|
208
|
+
def select_radio_button_with_name(name, value)
|
209
|
+
wait_before_and_after { @@browser.radio(:name, name, value).click }
|
210
|
+
end
|
211
|
+
|
212
|
+
|
213
|
+
# Select an item (+value+) from the +index+'th radio button collection.
|
214
|
+
def select_radio_button_with_name(index, value)
|
215
|
+
wait_before_and_after { @@browser.radio(:index, index, value).click }
|
216
|
+
end
|
217
|
+
|
218
|
+
|
219
|
+
# Select an item (+value+) from the radio button collection with a matching
|
220
|
+
# +id+ attribute.
|
221
|
+
def select_radio_button_with_id(id, value)
|
222
|
+
wait_before_and_after { @@browser.radio(:id, id, value).click }
|
223
|
+
end
|
224
|
+
|
225
|
+
|
226
|
+
# Tell the browser to click on a form button with +name+.
|
227
|
+
def click_button_with_name(name)
|
228
|
+
wait_before_and_after { @@browser.button(:name, name).click }
|
229
|
+
end
|
230
|
+
|
231
|
+
|
232
|
+
# Tell the browser to click on a form button with the specified id attribute.
|
233
|
+
def click_button_with_id(id)
|
234
|
+
wait_before_and_after { @@browser.button(:id, id).click }
|
235
|
+
end
|
236
|
+
|
237
|
+
|
238
|
+
# Tell the browser to click on a form button with the specified value attribute.
|
239
|
+
def click_button_with_value(value)
|
240
|
+
wait_before_and_after { @@browser.button(:value, value).click }
|
241
|
+
end
|
242
|
+
|
243
|
+
|
244
|
+
# Tell the browser to click on a form button with the specified caption text.
|
245
|
+
def click_button_with_caption(caption)
|
246
|
+
wait_before_and_after { @@browser.button(:caption, caption).click }
|
247
|
+
end
|
248
|
+
|
249
|
+
|
250
|
+
# Tell the browser to click on the +index+'th form button on the page.
|
251
|
+
def click_button_with_index(index)
|
252
|
+
wait_before_and_after { @@browser.button(:index, index).click }
|
253
|
+
end
|
254
|
+
|
255
|
+
|
256
|
+
# Make a Test::Unit assertion that the given +text+ does not appear in the text
|
257
|
+
# body.
|
258
|
+
#
|
259
|
+
# * mesg - An assertion-failed message.
|
260
|
+
def assert_text_not_in_body(text,mesg=nil)
|
261
|
+
if mesg.nil? then
|
262
|
+
assert(! @@browser.pageContainsText(text), "couldn't find in body: [#{text}]")
|
263
|
+
else
|
264
|
+
assert(! @@browser.pageContainsText(text), mesg)
|
265
|
+
end
|
266
|
+
end
|
267
|
+
|
268
|
+
|
269
|
+
# Make a Test::Unit assertion that the given +text+ appears in the text
|
270
|
+
# body.
|
271
|
+
#
|
272
|
+
# * text - +String+ or +RegExp+ - The text or regular expression to search for.
|
273
|
+
# * mesg - +String+ - An optional assertion-failed message.
|
274
|
+
def assert_text_in_body(text,mesg=nil)
|
275
|
+
if mesg.nil? then
|
276
|
+
assert(@@browser.pageContainsText(text), "couldn't find in body: [#{text}]")
|
277
|
+
else
|
278
|
+
assert(@@browser.pageContainsText(text), mesg)
|
279
|
+
end
|
280
|
+
end
|
281
|
+
|
282
|
+
|
283
|
+
# This method returns true|false if the text/reg exp supplied is in a the text field "name".
|
284
|
+
#
|
285
|
+
# * name - +String+ - Name of field to examine.
|
286
|
+
# * text - +String+ or +RegExp+ - The text or regular expression to search for.
|
287
|
+
# * mesg - +String+ - An optional assertion-failed message.
|
288
|
+
def assert_text_in_field(name, text, mesg=nil)
|
289
|
+
if mesg.nil? then
|
290
|
+
assert(@@browser.textField(:name, name).verify_contains(text), "couldn't find in field #{name}: [#{text}]")
|
291
|
+
else
|
292
|
+
assert(@@browser.textField(:name, name).verify_contains(text), mesg)
|
293
|
+
end
|
294
|
+
end
|
295
|
+
|
296
|
+
#
|
297
|
+
# * how - symbol - the way we look for the object. Supported values are
|
298
|
+
# - :name
|
299
|
+
# - :id
|
300
|
+
# - :index
|
301
|
+
# * what - string - What field, id or name to examine.
|
302
|
+
# * text - string/Array of Strings - The string or array of strings to search for.
|
303
|
+
# * mesg - Optional! string - Set this if you want to supply your own error message
|
304
|
+
def assert_text_in_combobox_wrapper(how, what, text, mesg=nil)
|
305
|
+
assert(@@browser.selectBox(how, what), "could not find a combobox with what: #{what} and how: #{how}")
|
306
|
+
selectedItems = @@browser.selectBox(how, what).getSelectedItems
|
307
|
+
|
308
|
+
if text.kind_of? String
|
309
|
+
if mesg.nil? then
|
310
|
+
assert(selectedItems[0] == text, "couldn't find text in combobox with #{how}: #{what} - [#{text}], had [#{selectedItems[0]}]")
|
311
|
+
else
|
312
|
+
assert(selectedItems[0] == text, mesg)
|
313
|
+
end
|
314
|
+
|
315
|
+
elsif text.kind_of? Array
|
316
|
+
if mesg.nil? then
|
317
|
+
text.each do |item|
|
318
|
+
assert(selectedItems.include?(item), "couldn't find text in combobox with #{how}: #{what} - [#{text}], had [#{selectedItems}]")
|
319
|
+
end
|
320
|
+
else
|
321
|
+
text.each do |item|
|
322
|
+
assert(selectedItems.include?(item), mesg)
|
323
|
+
end
|
324
|
+
end
|
325
|
+
end
|
326
|
+
end
|
327
|
+
|
328
|
+
|
329
|
+
# This method returns true|false if the text is selected in the combobox
|
330
|
+
# with the supplied name.
|
331
|
+
#
|
332
|
+
# * name - string - Name of field to examine.
|
333
|
+
# * text - string/Array of Strings - The string or array of strings to search for.
|
334
|
+
# * mesg - Optional! string - Set this if you want to supply your own error message
|
335
|
+
def assert_text_in_combobox_by_name(name, text, mesg=nil)
|
336
|
+
assert_text_in_combobox_wrapper(:name, name, text, mesg)
|
337
|
+
end
|
338
|
+
|
339
|
+
# FIXME: how to use?
|
340
|
+
# This method returns true|false if the text is selected in the combobox
|
341
|
+
# with the supplied index.
|
342
|
+
#
|
343
|
+
# * index - string - Index of field to examine.
|
344
|
+
# * text - string/Array of Strings - The string or array of strings to search for.
|
345
|
+
# * mesg - Optional! string - Set this if you want to supply your own error message
|
346
|
+
#def assert_text_in_combobox_by_index(index, text, mesg=nil)
|
347
|
+
# assert_text_in_combobox_wrapper(:index, name, text, mesg)
|
348
|
+
#end
|
349
|
+
|
350
|
+
# This method returns true|false if the text is selected in the combobox
|
351
|
+
# with the supplied id.
|
352
|
+
#
|
353
|
+
# * id - string - Id of field to examine.
|
354
|
+
# * text - string/Array of Strings - The string or array of strings to search for.
|
355
|
+
# * mesg - Optional! string - Set this if you want to supply your own error message
|
356
|
+
def assert_text_in_combobox_by_id(id, text, mesg=nil)
|
357
|
+
assert_text_in_combobox_wrapper(:id, name, text, mesg)
|
358
|
+
end
|
359
|
+
|
360
|
+
|
361
|
+
|
362
|
+
# Close the browser window. Useful for automated test suites to reduce
|
363
|
+
# test interaction.
|
364
|
+
def close_browser
|
365
|
+
@@browser.getIE.quit
|
366
|
+
sleep 2
|
367
|
+
end
|
368
|
+
|
369
|
+
|
370
|
+
# Tell the browser to cick the Back button.
|
371
|
+
def go_back
|
372
|
+
@@browser.back
|
373
|
+
end
|
374
|
+
|
375
|
+
|
376
|
+
# Tell the browser to cick the Forward button.
|
377
|
+
def go_forward
|
378
|
+
@@browser.forward
|
379
|
+
end
|
380
|
+
|
381
|
+
|
382
|
+
# Fill a series of text fields. This takes a hash of textfield names to
|
383
|
+
# values for those fields.
|
384
|
+
#
|
385
|
+
# Example:
|
386
|
+
#
|
387
|
+
# fill_text_fields {
|
388
|
+
# 'username' => 'joe',
|
389
|
+
# 'password' => 'blahblah',
|
390
|
+
# 'email' => 'joe@blahblah.com',
|
391
|
+
# 'favorite_num' => 42
|
392
|
+
# }
|
393
|
+
def fill_text_fields(data)
|
394
|
+
data.each do |field, value|
|
395
|
+
@@browser.textField(:name, field).set(value)
|
396
|
+
end
|
397
|
+
end
|
398
|
+
|
399
|
+
|
400
|
+
# Fill a single textfield with a value
|
401
|
+
def fill_text_field(field_name, text)
|
402
|
+
@@browser.textField(:name, field_name).set(text)
|
403
|
+
end
|
404
|
+
|
405
|
+
|
406
|
+
# Some browsers (i.e. IE) need to be waited on before more actions can be
|
407
|
+
# performed. Most action methods in Watir::Simple already call this before
|
408
|
+
# and after.
|
409
|
+
def wait_for_browser
|
410
|
+
@@browser.waitForIE
|
411
|
+
end
|
412
|
+
|
413
|
+
|
414
|
+
def combobox_default_selection(name)
|
415
|
+
# FIXME _where_ is this used?
|
416
|
+
@@browser.selectBox(:name, name).value
|
417
|
+
end
|
418
|
+
|
419
|
+
|
420
|
+
# Returns the number of times +text+ appears in the body text of the page.
|
421
|
+
def count_instances_of(text)
|
422
|
+
@@browser.getDocument.body.innerText.scan(text).size
|
423
|
+
end
|
424
|
+
|
425
|
+
|
426
|
+
# Make a Test::Unit assertion that an image exists on the page with the given
|
427
|
+
# +src+ attribute.
|
428
|
+
#
|
429
|
+
# * mesg - +String+ - An optional assertion-failed message.
|
430
|
+
def assert_image_with_src(src, mesg=nil)
|
431
|
+
if mesg.nil? then
|
432
|
+
assert( get_image_with_src(src) != nil, "image with src: [#{src}] is not present")
|
433
|
+
else
|
434
|
+
assert( get_image_with_src(src) != nil, mesg)
|
435
|
+
end
|
436
|
+
end
|
437
|
+
|
438
|
+
|
439
|
+
# Make a Test::Unit assertion that an image exists on the page with the given
|
440
|
+
# +id+ attribute. (Preferred method)
|
441
|
+
#
|
442
|
+
# * mesg - +String+ - An optional assertion-failed message.
|
443
|
+
def assert_image_with_id(id, mesg=nil)
|
444
|
+
if mesg.nil? then
|
445
|
+
assert( get_image_with_id(id) != nil, "image with id: [#{id}] is not present")
|
446
|
+
else
|
447
|
+
assert( get_image_with_id(id) != nil, mesg)
|
448
|
+
end
|
449
|
+
end
|
450
|
+
|
451
|
+
|
452
|
+
# A convenience method to wait at both ends of an operation for the browser
|
453
|
+
# to catch up.
|
454
|
+
def wait_before_and_after
|
455
|
+
wait_for_browser
|
456
|
+
yield
|
457
|
+
wait_for_browser
|
458
|
+
end
|
459
|
+
|
460
|
+
|
461
|
+
#### PRIVATE METHODS BEYOND THIS POINT
|
462
|
+
private
|
463
|
+
####
|
464
|
+
|
465
|
+
def get_image_with_src(src)
|
466
|
+
@@browser.image(:src, src)
|
467
|
+
end
|
468
|
+
|
469
|
+
|
470
|
+
def get_image_with_id(id)
|
471
|
+
@@browser.image(:id, id)
|
472
|
+
end
|
473
|
+
|
474
|
+
end
|
475
|
+
end
|