marekj-watirloo 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/History.txt ADDED
@@ -0,0 +1,19 @@
1
+ == 0.0.2 2009-02-03
2
+
3
+ * implement radio_group and checkbox_group for IE and Firefox
4
+ * Create RadioGroup and CheckboxGroup class for Watir::IE and FireWatir::Firefox
5
+ * update tests to run for both browsers unchanged.
6
+
7
+ == 0.0.1 2008-12-22
8
+
9
+ * initial merge with newgem generated structure to make it a gem
10
+ * Patches to Watir and Firewatir
11
+ * radio_group method added to Watir (not to FireWatir yet)
12
+ * patch fof Firefox.attach to just attach to the latest window without starting new ff win.
13
+ * tests
14
+ * built with intent to run unchanged on IE and Firefox
15
+ * tests run on test/spec gem
16
+
17
+ == 0.0.0
18
+
19
+ * start collecting ideas about building an abstratction layer based on semantic domain model vocabulary customers speak.
data/Manifest.txt ADDED
@@ -0,0 +1,36 @@
1
+ History.txt
2
+ Manifest.txt
3
+ README.rdoc
4
+ Rakefile.rb
5
+ lib/watirloo
6
+ lib/watirloo.rb
7
+ lib/watirloo/firewatir_ducktape.rb
8
+ lib/watirloo/reflector.rb
9
+ lib/watirloo/watir_ducktape.rb
10
+ script/console
11
+ script/console.cmd
12
+ script/destroy
13
+ script/destroy.cmd
14
+ script/generate
15
+ script/generate.cmd
16
+ script/reflect.rb
17
+ test/checkbox_group_test.rb
18
+ test/checkboxes_value_test.rb
19
+ test/firewatir
20
+ test/firewatir/attach_instance_test.rb
21
+ test/html
22
+ test/html/census.html
23
+ test/html/checkbox_group1.html
24
+ test/html/labels.html
25
+ test/html/person.html
26
+ test/html/radio_group.html
27
+ test/html/select_lists.html
28
+ test/label_test.rb
29
+ test/person_def_wrappers_test.rb
30
+ test/radio_group_test.rb
31
+ test/select_list_as_face_test.rb
32
+ test/select_list_options_test.rb
33
+ test/select_lists_test.rb
34
+ test/test_helper.rb
35
+ test/text_fields_test.rb
36
+ watirloo.gemspec
data/README.rdoc ADDED
@@ -0,0 +1,104 @@
1
+ = Watirloo
2
+
3
+ * http://watirloo.testr.us
4
+
5
+ == DESCRIPTION:
6
+
7
+ Watir Framework and Helper based on Semantic Page Objects Modeling.
8
+ Helps you design tests expressing DOM elements and groups of elements
9
+ on the page as Semantic Page Objects rather than their DOM implementations.
10
+ It is not a DSL but it helps you write human readable tests and hooks them up
11
+ to Watir browsers for implementation
12
+
13
+ Give it a try. You will like it.
14
+
15
+ == FEATURES/PROBLEMS:
16
+
17
+ * Watirloo::Page acts as an adapter with customer facing semantic names for page objects and developer facing implamention talking to the browser.
18
+ * Page creates an abstraction adapter: Human Readable and Machine Executable.
19
+ * Pages contain faces; page objects that are named with semantic intent
20
+ * Best to work with one browser instance on the desktop.
21
+ * Patches Watir and Firewatir to ease testing
22
+ * groups radios in radio_group and checkboxes in checkbox_group and acts each group as page object
23
+
24
+ == SYNOPSIS:
25
+
26
+ By convention Watirloo::Page.new attaches itself to the existing IE browser instance on the desktop.
27
+
28
+ Example: Given a page with text fields for last name and first name we want to enter name 'Kurt Vonnegut'
29
+ You can define hash with key as semantic name and value as watir implementation
30
+
31
+ page = Watirloo::Page.new
32
+ page.add_face :last => [:text_field, :name, 'l_nm'],
33
+ :first => [:text_field, :name, 'f_nm']
34
+ page.last.set "Vonnegut"
35
+ page.first.set "Kurt"
36
+
37
+ Or you can create a wrapper method that delegates to the browser
38
+
39
+ class Person < Watirloo::Page
40
+ def last
41
+ @b.text_field(:name, 'lnm')
42
+ end
43
+ def first
44
+ @b.text_field(:name, 'fnm')
45
+ end
46
+ end
47
+
48
+ Or define a hash where key will match the defined faces to be set
49
+ params = {:first => 'Kurt', :last => 'Vonnegut'}
50
+ page = Watirloo::Page.new.spray params
51
+
52
+ Or pass page cofiguration in the block at page creation
53
+
54
+ page = Person.new do
55
+ last.set 'Vonnegut'
56
+ first.set 'Kurt'
57
+ end
58
+
59
+
60
+ == REQUIREMENTS:
61
+
62
+ * watir >= 1.6.2 runs on IE by default
63
+ * firewatir >= 1.6.2 if you want to use Firefox
64
+ * test/spec gem if you want to run tests
65
+ * newgem and hoe for dev
66
+
67
+ == INSTALL:
68
+
69
+ * gem install watirloo
70
+
71
+ === ROADMAP
72
+
73
+ Towards version 0.0.2
74
+
75
+ * make Watirloo agnostic to browser IE or Firefox or Safari
76
+ * make tests run on IE, Firefox, Safari with the same interface
77
+ * create radio_group to behave like select list and checkbox_group like multi select list
78
+ * build UseCase class as template for scenario based execution of tests for exploratory testing
79
+
80
+ == LICENSE:
81
+
82
+ (The MIT License)
83
+
84
+ Copyright (c) 2008 marekj
85
+
86
+ Permission is hereby granted, free of charge, to any person obtaining
87
+ a copy of this software and associated documentation files (the
88
+ 'Software'), to deal in the Software without restriction, including
89
+ without limitation the rights to use, copy, modify, merge, publish,
90
+ distribute, sublicense, and/or sell copies of the Software, and to
91
+ permit persons to whom the Software is furnished to do so, subject to
92
+ the following conditions:
93
+
94
+ The above copyright notice and this permission notice shall be
95
+ included in all copies or substantial portions of the Software.
96
+
97
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
98
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
99
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
100
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
101
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
102
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
103
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
104
+
data/Rakefile.rb ADDED
@@ -0,0 +1,59 @@
1
+ %w[rubygems rake rake/clean fileutils newgem rubigen].each { |f| require f }
2
+ require File.dirname(__FILE__) + '/lib/watirloo'
3
+
4
+ # Generate all the Rake tasks
5
+ # Run 'rake -T' to see list of generated tasks (from gem root directory)
6
+ $hoe = Hoe.new('watirloo', Watirloo::VERSION) do |p|
7
+ p.developer('marekj', 'marekj.com@gmail.com')
8
+ p.changes = p.paragraphs_of("History.txt", 0..1).join("\n\n")
9
+ p.rubyforge_name = p.name # TODO this is default value
10
+ p.extra_deps = [
11
+ ['watir','>= 1.6.2'],
12
+ ]
13
+ p.extra_dev_deps = [
14
+ ['newgem', ">= #{::Newgem::VERSION}"],
15
+ ['test/spec', '>=0.9.0']
16
+ ]
17
+ p.test_globs =['test/*_test.rb']
18
+ p.testlib = ['test/spec']
19
+ p.clean_globs |= %w[**/.DS_Store tmp *.log]
20
+ path = (p.rubyforge_name == p.name) ? p.rubyforge_name : "\#{p.rubyforge_name}/\#{p.name}"
21
+ p.remote_rdoc_dir = File.join(path.gsub(/^#{p.rubyforge_name}\/?/,''), 'rdoc')
22
+ p.rsync_args = '-av --delete --ignore-errors'
23
+ end
24
+
25
+ require 'newgem/tasks' # load /tasks/*.rake
26
+ Dir['tasks/**/*.rake'].each { |t| load t }
27
+
28
+ desc "run all tests on IE."
29
+ task :test_ie do
30
+ # all tests use attach method to a browser that exit on the desktop
31
+ # open new ie browser
32
+ Watir::Browser.default = 'ie'
33
+ Watir::Browser.new
34
+ Watirloo::BrowserHerd.target = :ie
35
+ tests = Dir["test/*_test.rb"]
36
+ tests.each do |t|
37
+ require t
38
+ end
39
+ # at the end of test you will have one extra browser
40
+ end
41
+
42
+
43
+ desc "run all tests on Firefox (config per FireWatir gem)"
44
+ task :test_ff do
45
+ # all tests attach to an existing firefox browser
46
+ # start browser with jssh option
47
+ Watir::Browser.default='firefox'
48
+ Watir::Browser.new
49
+ tests = Dir["test/*_test.rb"]
50
+ tests.each do |t|
51
+ Watirloo::BrowserHerd.target = :firefox
52
+ require t
53
+ end
54
+ # at the end of test you will have one extra browser
55
+ end
56
+
57
+
58
+
59
+
data/lib/watirloo.rb ADDED
@@ -0,0 +1,113 @@
1
+ $:.unshift(File.dirname(__FILE__)) unless
2
+ $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
3
+
4
+ require 'watirloo/watir_ducktape'
5
+ require 'watirloo/reflector'
6
+
7
+ module Watirloo
8
+
9
+ VERSION = '0.0.2' # Jan2009
10
+
11
+ # Generic Semantic Test Object
12
+ module TestObject
13
+ attr_accessor :id, :desc
14
+
15
+ end
16
+
17
+ # browser. we return IE or Firefox. Safari? Other Browser?
18
+ class BrowserHerd
19
+ include TestObject
20
+
21
+ @@target = :ie #default target
22
+
23
+ def self.target=(indicator)
24
+ @@target = indicator
25
+ end
26
+
27
+ def self.target
28
+ @@target
29
+ end
30
+
31
+ #provide browser
32
+ def self.browser
33
+ case @@target
34
+ when :ie
35
+ Watir::IE.attach :url, // #this attach is a crutch
36
+ when :firefox
37
+ require 'watirloo/firewatir_ducktape'
38
+ # this is a cruch for quick work with pages.
39
+ # in reality you want to create a browser and pass it as argument to initialize Page class
40
+ FireWatir::Firefox.attach #this attach is a crutch
41
+ end
42
+ end
43
+ end
44
+
45
+ # Semantic Page Objects Container.
46
+ # page objects are defined as faces of a Page.
47
+ # Each face (aka Interface of a page) is accessed by page.facename or page.face(:facename) methods
48
+ # Pages make Watir fun
49
+ class Page
50
+
51
+ include TestObject
52
+ attr_accessor :b
53
+ attr_reader :faces
54
+
55
+ # by convention the Page just attaches to the first available browser.
56
+ # the smart thing to do is to manage browsers existence on the desktop separately
57
+ # and supply Page class with the instance of browser you want for your tests.
58
+ # &block is the convenience at creation time to do some work.
59
+ # example:
60
+ # browser = Watir::start("http://mysitetotest")
61
+ # page = Page.new(browser) # specify browser instance to work with or
62
+ # page = Page.new # just let the page do lazy thing and attach itself to browser.
63
+ # part of this page initialization is to provide a convenience while developing tests where
64
+ # we may have only one browser open and that's the one browser were we want to talk to.
65
+ def initialize(browser = Watirloo::BrowserHerd.browser , &blk)
66
+ @b = browser
67
+ @faces = {}
68
+ instance_eval(&blk) if block_given? # allows the shortcut to do some work at page creation
69
+ end
70
+
71
+ # enter values on controls idenfied by keys on the page.
72
+ # data map is a hash, key represents the page object,
73
+ # value represents its value to be set, either text, array or boolean
74
+ def spray(dataMap)
75
+ dataMap.each_pair do |face_symbol, value|
76
+ get_face(face_symbol).set value #make every element in the dom respond to set to set its value
77
+ end
78
+ end
79
+
80
+ # return Watir object given by its semantic face symbol name
81
+ def get_face(face_symbol)
82
+ if self.respond_to? face_symbol # if there is a defined wrapper method for page element provided
83
+ return self.send(face_symbol)
84
+ elsif @faces.member?(face_symbol) # pull element from @faces and send to browser
85
+ method, *args = @faces[face_symbol] # return definition for face consumable by browser
86
+ return @b.send(method, *args)
87
+ else
88
+ #??? I ran out of ideas
89
+ raise ::Watir::Exception::WatirException, 'I ran out of ideas in Watirloo'
90
+ end
91
+ end
92
+ alias face get_face
93
+
94
+ # add face definition to page
95
+ def add_face(definitions)
96
+ if definitions.kind_of?(Hash)
97
+ @faces.update definitions
98
+ end
99
+ end
100
+
101
+ # Delegate execution to browser if no method or face defined on page class
102
+ def method_missing method, *args
103
+ if @b.respond_to? method
104
+ @b.send method, *args
105
+ elsif @faces.member?(method.to_sym)
106
+ get_face(method.to_sym)
107
+ else
108
+ raise ::Watir::Exception::WatirException, 'I ran out of ideas in Watirloo'
109
+ end
110
+ end
111
+ end
112
+
113
+ end
@@ -0,0 +1,194 @@
1
+ gem 'firewatir', '>=1.6.2' # dependency
2
+ require 'firewatir'
3
+
4
+ module FireWatir
5
+
6
+ # duck punch and ducktape Firefox for Watirloo needs
7
+ # some of it is cosmetic surgery and some new methods with intention of
8
+ # sending a patch to Watir maintainers
9
+ class Firefox
10
+
11
+ # attach to the existing Firefox that was already started with JSSH option.
12
+ # this is a hack for Watirloo. it only attaches to the latest firefox.
13
+ # it assumes there is only one instance of FF window open on the desktop
14
+ def self.attach
15
+ Firefox.new :attach => true
16
+ end
17
+
18
+ # add option key :attach as a hack
19
+ # :attach => true to attach to topmost window in getWindows().lenght-1
20
+ # split up initialize to conditionally start FireFox
21
+ def initialize(options = {})
22
+ _start_firefox(options) unless options[:attach]
23
+ set_defaults()
24
+ get_window_number()
25
+ set_browser_document()
26
+ end
27
+
28
+ # refactor initialize method to move all starting of FF into its own method
29
+ def _start_firefox(options)
30
+ if(options.kind_of?(Integer))
31
+ options = {:waitTime => options}
32
+ end
33
+
34
+ if(options[:profile])
35
+ profile_opt = "-no-remote -P #{options[:profile]}"
36
+ else
37
+ profile_opt = ""
38
+ end
39
+
40
+ waitTime = options[:waitTime] || 2
41
+
42
+ case RUBY_PLATFORM
43
+ when /mswin/
44
+ # Get the path to Firefox.exe using Registry.
45
+ require 'win32/registry.rb'
46
+ path_to_bin = ""
47
+ Win32::Registry::HKEY_LOCAL_MACHINE.open('SOFTWARE\Mozilla\Mozilla Firefox') do |reg|
48
+ keys = reg.keys
49
+ reg1 = Win32::Registry::HKEY_LOCAL_MACHINE.open("SOFTWARE\\Mozilla\\Mozilla Firefox\\#{keys[0]}\\Main")
50
+ reg1.each do |subkey, type, data|
51
+ if(subkey =~ /pathtoexe/i)
52
+ path_to_bin = data
53
+ end
54
+ end
55
+ end
56
+
57
+ when /linux/i
58
+ path_to_bin = `which firefox`.strip
59
+ when /darwin/i
60
+ path_to_bin = '/Applications/Firefox.app/Contents/MacOS/firefox'
61
+ when /java/
62
+ raise "Not implemented: Create a browser finder in JRuby"
63
+ end
64
+
65
+ @t = Thread.new { system("#{path_to_bin} -jssh #{profile_opt}")}
66
+ sleep waitTime
67
+
68
+ end
69
+ private :_start_firefox
70
+
71
+ end
72
+
73
+ class SelectList
74
+
75
+ include Watir::SelectListCommonWatir
76
+
77
+ # accepts one text item or array of text items. if array then sets one after another.
78
+ # For single select lists the last item in array wins
79
+ #
80
+ # examples
81
+ # select_list.set 'bla' # => single option text
82
+ # select_list.set ['bla','foo','gugu'] # => set 3 options by text. If
83
+ # this is a single select list box it will set each value in turn
84
+ # select_list set 1 # => set the first option in a list
85
+ # select_list.set [1,3,5] => set the first, third and fith options
86
+ def set(item)
87
+ _set(:text, item)
88
+ end
89
+
90
+ # set item by the option value attribute. if array then set one after anohter.
91
+ # see examples in set method
92
+ def set_value(value)
93
+ _set(:value, value)
94
+ end
95
+
96
+ # returns array of value attributes
97
+ # each option usually has a value attribute
98
+ # which is hidden to the person viewing the page
99
+ def values
100
+ a = []
101
+ items.each do |item|
102
+ a << option(:text, item).value
103
+ end
104
+ return a
105
+ end
106
+
107
+ alias clear clearSelection
108
+
109
+ # alias, items or contents return the same visible text items
110
+ alias items getAllContents
111
+
112
+ end
113
+
114
+ # RadioGroup and CheckboxGroup common behaviour
115
+ module RadioCheckGroup
116
+
117
+ include Watir::RadioCheckGroupCommonWatir
118
+
119
+ def values
120
+ values = []
121
+ @o.each {|thing| values << thing.value}
122
+ return values
123
+ end
124
+
125
+ def get_by_value value
126
+ if values.member? value
127
+ @o.find {|thing| thing.value == value}
128
+ else
129
+ raise ::Watir::Exception::WatirException, "value #{value} not found in hidden values"
130
+ end
131
+ end
132
+ end
133
+
134
+ class CheckboxGroup
135
+
136
+ include RadioCheckGroup
137
+ include Watir::CheckboxGroupCommonWatir
138
+
139
+ def initialize(container, name)
140
+ @container = container
141
+ @name = name
142
+ @o = []
143
+ @container.checkboxes.each do |cb| #TODO find why find_all does not work
144
+ if cb.name == @name
145
+ @o << cb
146
+ end
147
+ end
148
+ end
149
+
150
+ # which values are selected?
151
+ def selected_values
152
+ values = []
153
+ selected_checkboxes.each do |cb|
154
+ values << cb.value
155
+ end
156
+ return values
157
+ end
158
+ end
159
+
160
+ class RadioGroup
161
+
162
+ include RadioCheckGroup
163
+ include Watir::RadioGroupCommonWatir
164
+
165
+ def initialize(container, name)
166
+ @container = container
167
+ @name = name
168
+ @o = []
169
+ @container.radios.each do |r| #TODO find why find_all does not work
170
+ if r.name == @name
171
+ @o << r
172
+ end
173
+ end
174
+ return @o
175
+ end
176
+
177
+ # see Watir::RadioGroup.selected_value
178
+ def selected_value
179
+ selected_radio.value
180
+ end
181
+ alias selected selected_value
182
+ end
183
+
184
+
185
+ module Container
186
+ def radio_group(name)
187
+ RadioGroup.new(self, name)
188
+ end
189
+
190
+ def checkbox_group(name)
191
+ CheckboxGroup.new(self, name)
192
+ end
193
+ end
194
+ end