marekj-watirloo 0.0.2

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/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