kuali-test-factory 0.5.3.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.
- checksums.yaml +7 -0
- data/COPYING +68 -0
- data/Gemfile +5 -0
- data/Gemfile.lock +33 -0
- data/LICENSE +68 -0
- data/README.md +241 -0
- data/lib/test-factory.rb +18 -0
- data/lib/test-factory/collections_factory.rb +67 -0
- data/lib/test-factory/core_ext.rb +133 -0
- data/lib/test-factory/data_factory.rb +334 -0
- data/lib/test-factory/date_factory.rb +158 -0
- data/lib/test-factory/foundry.rb +76 -0
- data/lib/test-factory/gem_ext.rb +224 -0
- data/lib/test-factory/page_factory.rb +238 -0
- data/lib/test-factory/string_factory.rb +167 -0
- data/lib/test-factory/test_factory.rb +16 -0
- data/test-factory.gemspec +13 -0
- metadata +78 -0
@@ -0,0 +1,67 @@
|
|
1
|
+
# Copyright 2012-2014 The rSmart Group, Inc.
|
2
|
+
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
#
|
15
|
+
# =================
|
16
|
+
# CollectionsFactory
|
17
|
+
# =================
|
18
|
+
#
|
19
|
+
# Use this as the superclass for your data object collection classes.
|
20
|
+
class CollectionsFactory < Array
|
21
|
+
|
22
|
+
def initialize(browser)
|
23
|
+
@browser=browser
|
24
|
+
end
|
25
|
+
|
26
|
+
# Defines the class of objects contained in the collection
|
27
|
+
#
|
28
|
+
def self.contains klass
|
29
|
+
|
30
|
+
# Creates a method called "add" that will create the specified data
|
31
|
+
# object and then add it as an item in the collection.
|
32
|
+
#
|
33
|
+
# Note that it's assumed that the target data object will have a
|
34
|
+
# create method defined. If not, this will not work properly.
|
35
|
+
define_method 'add' do |opts={}|
|
36
|
+
element = klass.new @browser, opts
|
37
|
+
element.create
|
38
|
+
self << element
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
# Makes a "deep copy" of the Collection. See the #data_object_copy
|
44
|
+
# method description in the DataObject class for more information.
|
45
|
+
#
|
46
|
+
def copy
|
47
|
+
new_collection = self.class.new(@browser)
|
48
|
+
self.each do |item|
|
49
|
+
new_collection << item.data_object_copy
|
50
|
+
end
|
51
|
+
new_collection
|
52
|
+
end
|
53
|
+
|
54
|
+
# Used in conjunction with the Parent object containing
|
55
|
+
# the collection.
|
56
|
+
#
|
57
|
+
# The parent sends updated information to the collection(s)
|
58
|
+
# using #notify_collections
|
59
|
+
#
|
60
|
+
def notify_members *updates
|
61
|
+
self.each { |member| member.update_from_parent *updates }
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
|
66
|
+
# Just an alias class name.
|
67
|
+
class CollectionFactory < CollectionsFactory; end
|
@@ -0,0 +1,133 @@
|
|
1
|
+
# Copyright 2012-2014 The rSmart Group, Inc.
|
2
|
+
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
class Time
|
16
|
+
|
17
|
+
# Using the :year_range option (or no option), this method creates a
|
18
|
+
# Time object of a random value, within
|
19
|
+
# the year range specified (default is 5 years in the past).
|
20
|
+
#
|
21
|
+
# Using the :series option, this method returns an array
|
22
|
+
# containing a randomized Time object as its first element (limited by
|
23
|
+
# the specified :year_range value). Subsequent elements will be Time objects
|
24
|
+
# with values putting them later than the prior element, within the specified
|
25
|
+
# range value (see examples).
|
26
|
+
#
|
27
|
+
# Usage Examples:
|
28
|
+
# @example
|
29
|
+
# a random date...
|
30
|
+
# ?> Time.random
|
31
|
+
# => Tue Aug 05 00:00:00 EDT 2007
|
32
|
+
#
|
33
|
+
# birthdays, anyone?...
|
34
|
+
# 5.times { p Time.random(:year_range=>80) }
|
35
|
+
# Wed Feb 06 00:00:00 EDT 1974
|
36
|
+
# Tue Dec 22 00:00:00 EST 1992
|
37
|
+
# Fri Apr 14 00:00:00 EWT 1944
|
38
|
+
# Thu Jul 01 00:00:00 EDT 1993
|
39
|
+
# Wed Oct 02 00:00:00 EDT 2002
|
40
|
+
#
|
41
|
+
# A series of dates are useful for account-related info...
|
42
|
+
# ?> Time.random(:series=>[20.days, 3.years])
|
43
|
+
# => [Sat Jan 22 00:00:00 EST 2005,
|
44
|
+
# Sat Jan 29 12:58:45 EST 2005,
|
45
|
+
# Fri Sep 08 09:34:58 EDT 2006]
|
46
|
+
#
|
47
|
+
# or maybe to simulate events during an hour?...
|
48
|
+
# ?> Time.random(:series=>[1.hour,1.hour,1.hour])
|
49
|
+
# => [Wed Apr 21 00:00:00 EDT 2004,
|
50
|
+
# Wed Apr 21 00:45:59 EDT 2004,
|
51
|
+
# Wed Apr 21 01:02:47 EDT 2004,
|
52
|
+
# Wed Apr 21 01:31:00 EDT 2004]
|
53
|
+
#
|
54
|
+
def self.random(params={})
|
55
|
+
years_back = params[:year_range] || 5
|
56
|
+
year = (rand * (years_back)).ceil + (Time.now.year - years_back)
|
57
|
+
month = (rand * 12).ceil
|
58
|
+
day = (rand * 31).ceil
|
59
|
+
series = [date = Time.local(year, month, day)]
|
60
|
+
if params[:series]
|
61
|
+
params[:series].each do |some_time_after|
|
62
|
+
series << series.last + (rand * some_time_after).ceil
|
63
|
+
end
|
64
|
+
return series
|
65
|
+
end
|
66
|
+
date
|
67
|
+
end
|
68
|
+
|
69
|
+
end # Time
|
70
|
+
|
71
|
+
module Enumerable
|
72
|
+
|
73
|
+
# Use for getting a natural sort order instead of the ASCII
|
74
|
+
# sort order.
|
75
|
+
#
|
76
|
+
def alphabetize
|
77
|
+
sort { |a, b| grouped_compare(a, b) }
|
78
|
+
end
|
79
|
+
|
80
|
+
# Use for sorting an Enumerable object in place.
|
81
|
+
#
|
82
|
+
def alphabetize!
|
83
|
+
sort! { |a, b| grouped_compare(a, b) }
|
84
|
+
end
|
85
|
+
|
86
|
+
private
|
87
|
+
|
88
|
+
def grouped_compare(a, b)
|
89
|
+
loop {
|
90
|
+
a_chunk, a = extract_alpha_or_number_group(a)
|
91
|
+
b_chunk, b = extract_alpha_or_number_group(b)
|
92
|
+
ret = a_chunk <=> b_chunk
|
93
|
+
return -1 if a_chunk == ''
|
94
|
+
return ret if ret != 0
|
95
|
+
}
|
96
|
+
end
|
97
|
+
|
98
|
+
def extract_alpha_or_number_group(item)
|
99
|
+
test_item = item.downcase
|
100
|
+
matchdata = /([a-z]+|[\d]+)/.match(test_item)
|
101
|
+
if matchdata.nil?
|
102
|
+
["", ""]
|
103
|
+
else
|
104
|
+
[matchdata[0], test_item = test_item[matchdata.offset(0)[1] .. -1]]
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
end # Enumerable
|
109
|
+
|
110
|
+
class Numeric
|
111
|
+
|
112
|
+
# Converts a number object to a string containing commas every 3rd digit. Adds
|
113
|
+
# trailing zeroes if necessary to match round currency amounts.
|
114
|
+
def commas
|
115
|
+
self.to_s =~ /([^\.]*)(\..*)?/
|
116
|
+
int, dec = $1.reverse, $2 ? ('%.2f' % $2).to_s[/.\d+$/] : ".00"
|
117
|
+
while int.gsub!(/(,|\.|^)(\d{3})(\d)/, '\1\2,\3')
|
118
|
+
end
|
119
|
+
int.reverse + dec
|
120
|
+
end
|
121
|
+
|
122
|
+
end # Numeric
|
123
|
+
|
124
|
+
class String
|
125
|
+
|
126
|
+
# Used to remove commas and dollar signs from long number strings,
|
127
|
+
# then converting the result to a Float so that it
|
128
|
+
# can be used in calculations.
|
129
|
+
def groom
|
130
|
+
self.gsub(/[$,]/,'').to_f
|
131
|
+
end
|
132
|
+
|
133
|
+
end # String
|
@@ -0,0 +1,334 @@
|
|
1
|
+
# Copyright 2012-2014 The rSmart Group, Inc.
|
2
|
+
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
# The Superclass for all of your data objects.
|
16
|
+
class DataFactory
|
17
|
+
|
18
|
+
include Foundry
|
19
|
+
extend Forwardable
|
20
|
+
|
21
|
+
# Since Data Objects are not "Marshallable", and they generally
|
22
|
+
# contain lots of types of data in their instance variables,
|
23
|
+
# we have this method. This will create and return a 'deep copy' of
|
24
|
+
# the data object as well as any and all nested data objects
|
25
|
+
# and collections it contains.
|
26
|
+
#
|
27
|
+
# Please note that this method will fail if you are putting
|
28
|
+
# Data Objects into Arrays or Hashes instead
|
29
|
+
# of into Collection classes
|
30
|
+
#
|
31
|
+
def data_object_copy
|
32
|
+
opts = {}
|
33
|
+
self.instance_variables.each do |var|
|
34
|
+
key = var.to_s.gsub('@','').to_sym
|
35
|
+
orig_val = instance_variable_get var
|
36
|
+
opts[key] = case
|
37
|
+
when orig_val.kind_of?(CollectionsFactory)
|
38
|
+
orig_val.copy
|
39
|
+
when orig_val.instance_of?(Array) || orig_val.instance_of?(Hash)
|
40
|
+
begin
|
41
|
+
Marshal::load(Marshal.dump(orig_val))
|
42
|
+
rescue TypeError
|
43
|
+
raise %{\nKey: #{key.inspect}\nValue: #{orig_val.inspect}\nClass: #{orig_val.class}\n\nThe copying of the Data Object has thrown a TypeError,\nwhich means the object detailed above is not "Marshallable".\nThe most likely cause is that you have put\na Data Object inside an\nArray or Hash.\nIf possible, put the Data Object into a Collection.\n\n}
|
44
|
+
end
|
45
|
+
when orig_val.kind_of?(DataFactory)
|
46
|
+
orig_val.data_object_copy
|
47
|
+
else
|
48
|
+
orig_val
|
49
|
+
end
|
50
|
+
end
|
51
|
+
self.class.new(@browser, opts)
|
52
|
+
end
|
53
|
+
|
54
|
+
# Add this to the bottom of your Data Object's initialize method.
|
55
|
+
# This method does 2 things:
|
56
|
+
# 1) Converts the contents of the hash into the class's instance variables.
|
57
|
+
# 2) Grabs the names of your collection class instance variables and stores
|
58
|
+
# them in an Array. This is to allow for the data object class to send
|
59
|
+
# any needed updates to its children. See #notify_coolections for more
|
60
|
+
# details.
|
61
|
+
# @param hash [Hash] Contains all options required for creating the needed Data Object
|
62
|
+
#
|
63
|
+
def set_options(hash)
|
64
|
+
@collections ||= []
|
65
|
+
hash.each do |key, value|
|
66
|
+
instance_variable_set("@#{key}", value)
|
67
|
+
@collections << key if value.kind_of?(CollectionsFactory)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
alias update_options set_options
|
71
|
+
|
72
|
+
# Use for setting a data object's class instance variable as a nested collection class.
|
73
|
+
#
|
74
|
+
# This method assumes your collection class name ends with "Collection". Therefore,
|
75
|
+
# the string you pass in its parameter is the first part of the class name.
|
76
|
+
#
|
77
|
+
# E.g., your collection class is called "DataObjectCollection", so, inside your
|
78
|
+
# parent object's defaults, you'd set the instance variable like this:
|
79
|
+
#
|
80
|
+
# @example
|
81
|
+
# data_objects: collection('DataObject')
|
82
|
+
#
|
83
|
+
def collection(name)
|
84
|
+
Kernel.const_get("#{name}Collection").new(@browser)
|
85
|
+
end
|
86
|
+
|
87
|
+
# Items passed to this method are checked to ensure that the associated class instance variable
|
88
|
+
# is not nil. If it is, the script is aborted and an error is thrown. Use symbols separated
|
89
|
+
# by commas with this method. The symbol(s) should exactly match the name of the instance
|
90
|
+
# variable that must not be empty.
|
91
|
+
#
|
92
|
+
# NOTE: Currently this is backwards compatible with prior versions, which took the instance
|
93
|
+
# variables directly in the parameter. This backwards compatibility will be removed in
|
94
|
+
# some future update of the gem.
|
95
|
+
#
|
96
|
+
# @param elements [Array] the list of items that are required.
|
97
|
+
#
|
98
|
+
# @example
|
99
|
+
# requires :site, :assignment, :document_id
|
100
|
+
#
|
101
|
+
def requires(*elements)
|
102
|
+
elements.each do |inst_var|
|
103
|
+
if inst_var.kind_of? Symbol
|
104
|
+
string="@#{inst_var.to_s}"
|
105
|
+
if instance_variable_get(string)==nil
|
106
|
+
raise "You've neglected to define a required variable for your #{self.class}.\n\nPlease ensure you always specify a value for #{string} when you create the data object."
|
107
|
+
end
|
108
|
+
elsif inst_var.kind_of? String
|
109
|
+
warn "<<<<WARNING!>>>>\n\nPlease update the requires method in your\n#{self.class} class to refer to symbols\ninstead of directly referencing the class'\ninstance variables.\n\n Example:\n\n This...\n requires @document_id\n Should be updated to...\n requires :document_id\n\nIn future versions of TestFactory the 'requires'\nmethod will only support symbolized references\nto the instance variables. The backwards\ncompatibility will be removed.\n\n<<<<WARNING!>>>>"
|
110
|
+
elsif inst_var==nil
|
111
|
+
raise "You've neglected to define a required variable for your #{self.class}.\n\n<<<<WARNING!>>>>\n\nPlease update the requires method in your #{self} class to refer to symbols\ninstead of directly referencing the class'\ninstance variables.\n\nIn future versions of TestFactory the 'requires' method\nwill only support symbolized references\nto the instance variables. The backwards\ncompatibility will be removed.\n\n<<<<WARNING!>>>>"
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
# A shortcut method for filling out fields on a page. The
|
117
|
+
# method's first parameter is the page class that contains the fields
|
118
|
+
# you want to fill out. That is followed by the list of field name(s)
|
119
|
+
# (as Symbols).
|
120
|
+
#
|
121
|
+
# This method has a number of requirements:
|
122
|
+
#
|
123
|
+
# 1) The field name and the instance variable name in your data object
|
124
|
+
# must be identical. For this reason, this method can only
|
125
|
+
# be used in your data objects' create methods.
|
126
|
+
#
|
127
|
+
# 2) Your checkbox and radio button data object instance variables are
|
128
|
+
# either +nil+, +:set+, or +:clear+. Any other values will not be handled
|
129
|
+
# correctly.
|
130
|
+
#
|
131
|
+
# 3) Since the listed fields get filled out in random order, be sure that
|
132
|
+
# this is okay in the context of your page--in other words, if field A
|
133
|
+
# needs to be specified before field B then having them both in your
|
134
|
+
# fill_out step would be inappropriate. If you need a specific order,
|
135
|
+
# use #ordered_fill instead.
|
136
|
+
#
|
137
|
+
# 4) This method supports text fields, select lists, check boxes, and
|
138
|
+
# radio buttons, but only if their element definitions don't take a
|
139
|
+
# parameter. Please use the +#fill_out_item+ with elements that do need
|
140
|
+
# a parameter defined.
|
141
|
+
#
|
142
|
+
# @example
|
143
|
+
# on PageClass do |page|
|
144
|
+
# fill_out page, :text_field_name, :radio_name, :select_list_name, :checkbox_name
|
145
|
+
# end
|
146
|
+
#
|
147
|
+
def fill_out(page, *fields)
|
148
|
+
f_o_i true, nil, page, *fields
|
149
|
+
end
|
150
|
+
|
151
|
+
# Use when you need to specify the order that the fields should be
|
152
|
+
# updated.
|
153
|
+
#
|
154
|
+
# @example
|
155
|
+
# on PageClass do |page|
|
156
|
+
# ordered_fill page, :text_field_name, :radio_name, :select_list_name, :checkbox_name
|
157
|
+
# end
|
158
|
+
#
|
159
|
+
def ordered_fill(page, *fields)
|
160
|
+
f_o_i false, nil, page, *fields
|
161
|
+
end
|
162
|
+
|
163
|
+
# Same as #fill_out, but used with methods that take a
|
164
|
+
# parameter to identify the target element...
|
165
|
+
#
|
166
|
+
# @example
|
167
|
+
# on PageClass do |page|
|
168
|
+
# fill_out_item 'Joe Schmoe', page, :text_field_name, :radio_name, :select_list_name, :checkbox_name
|
169
|
+
# end
|
170
|
+
#
|
171
|
+
def fill_out_item(name, page, *fields)
|
172
|
+
f_o_i true, name, page, *fields
|
173
|
+
end
|
174
|
+
|
175
|
+
# Use instead of #fill_out_item when you need to
|
176
|
+
# specify the order that the fields should be
|
177
|
+
# updated.
|
178
|
+
#
|
179
|
+
# @example
|
180
|
+
# on PageClass do |page|
|
181
|
+
# ordered_item_fill 'Joe Schmoe', page, :text_field_name, :radio_name, :select_list_name, :checkbox_name
|
182
|
+
# end
|
183
|
+
#
|
184
|
+
def ordered_item_fill(name, page, *fields)
|
185
|
+
f_o_i false, name, page, *fields
|
186
|
+
end
|
187
|
+
|
188
|
+
# Equivalent to #ordered_fill, except that it's used
|
189
|
+
# in the context of a Data Object's #edit method(s). As such, it
|
190
|
+
# requires the #edit method's hash to be passed as its own
|
191
|
+
# first parameter.
|
192
|
+
#
|
193
|
+
# @example
|
194
|
+
# on PageClass do |page|
|
195
|
+
# edit_fields opts, page, :text_field_name, :radio_name, :select_list_name, :checkbox_name
|
196
|
+
# end
|
197
|
+
#
|
198
|
+
def edit_fields(opts, page, *fields)
|
199
|
+
edit_item_fields opts, nil, page, *fields
|
200
|
+
end
|
201
|
+
|
202
|
+
# Equivalent to #ordered_item_fill, except that it's used
|
203
|
+
# in the context of a Data Object's #edit method(s). As such, it
|
204
|
+
# requires the #edit method's hash to be passed as its own
|
205
|
+
# first parameter.
|
206
|
+
#
|
207
|
+
# @example
|
208
|
+
# on PageClass do |page|
|
209
|
+
# edit_item_fields opts, 'Joe Schmoe', page, :text_field_name, :radio_name, :select_list_name, :checkbox_name
|
210
|
+
# end
|
211
|
+
#
|
212
|
+
def edit_item_fields(opts, name, page, *fields)
|
213
|
+
parse_fields(opts, name, page, *fields)
|
214
|
+
end
|
215
|
+
|
216
|
+
# This is a specialized method for use with any select list boxes
|
217
|
+
# that exist in the site you're testing and will contain
|
218
|
+
# unpredictable default values.
|
219
|
+
#
|
220
|
+
# Admittedly, this is a bit unusual, but one example would be
|
221
|
+
# be a "due date" list that changes its default selection based
|
222
|
+
# on today's date. You're going to want to do one of two things
|
223
|
+
# with that select list:
|
224
|
+
#
|
225
|
+
# 1) Retrieve and store the select list's value
|
226
|
+
# 2) Specify a custom value to select
|
227
|
+
#
|
228
|
+
# Enter: +#get_or_select!+
|
229
|
+
#
|
230
|
+
# Assuming you just want to store the default value, then your
|
231
|
+
# Data Object's instance variable for the field will--initially--be
|
232
|
+
# nil. In that case, +#get_or_select!+ will grab the select list's
|
233
|
+
# current value and store it in your instance variable.
|
234
|
+
#
|
235
|
+
# On the other hand, if you want to update that field with your
|
236
|
+
# custom value, then your instance variable will not be nil, so
|
237
|
+
# +#get_or_select!+ will take that value and use it to update the
|
238
|
+
# select list.
|
239
|
+
#
|
240
|
+
# Note that this method *only* works with select lists that take
|
241
|
+
# a single selection. Multi-selects are not supported.
|
242
|
+
#
|
243
|
+
# Also note that the first parameter is *not* the instance variable
|
244
|
+
# you need to use/update. It is a *symbol* that otherwise matches
|
245
|
+
# the instance variable.
|
246
|
+
#
|
247
|
+
# @param inst_var_sym [Symbol] A Symbol that _must_ match the instance variable that
|
248
|
+
# will either be set or be used to update the page
|
249
|
+
# @param select_list [Watir::Select] The relevant select list element on the page
|
250
|
+
#
|
251
|
+
# @example
|
252
|
+
# get_or_select! :@num_resubmissions, page.num_resubmissions
|
253
|
+
#
|
254
|
+
def get_or_select!(inst_var_sym, select_list)
|
255
|
+
value = instance_variable_get inst_var_sym
|
256
|
+
if value==nil
|
257
|
+
instance_variable_set inst_var_sym, select_list.selected_options[0].text
|
258
|
+
else
|
259
|
+
select_list.select value
|
260
|
+
end
|
261
|
+
end
|
262
|
+
|
263
|
+
# This method accomplishes the same thing as #get_or_select! but
|
264
|
+
# is used specifically when the instance variable being used/updated
|
265
|
+
# is a Hash and you only need to update one of its key/value pairs.
|
266
|
+
#
|
267
|
+
# Pay close attention to the syntax differences between
|
268
|
+
# this method and #get_or_select!
|
269
|
+
#
|
270
|
+
# First, note that the returned value of this method must be explicitly
|
271
|
+
# passed to the relevant key in the Hash instance variable. Note also that, unlike
|
272
|
+
# #get_or_select!, this method does *not* take a symbolized representation
|
273
|
+
# of the instance variable.
|
274
|
+
#
|
275
|
+
# @example
|
276
|
+
# @open[:day] = get_or_select(@open[:day], page.open_day)
|
277
|
+
#
|
278
|
+
def get_or_select(hash_inst_var, select_list)
|
279
|
+
if hash_inst_var==nil
|
280
|
+
select_list.selected_options[0].text
|
281
|
+
else
|
282
|
+
select_list.select hash_inst_var
|
283
|
+
hash_inst_var
|
284
|
+
end
|
285
|
+
end
|
286
|
+
|
287
|
+
# Define this method in your data object when
|
288
|
+
# it has a parent, and that parent
|
289
|
+
# may periodically need to send
|
290
|
+
# it updated information about itself.
|
291
|
+
#
|
292
|
+
def update_from_parent(update)
|
293
|
+
raise %{
|
294
|
+
This method must be implemented in your data object
|
295
|
+
class if you plan to pass updates from a
|
296
|
+
parent object to the members of its
|
297
|
+
collections.
|
298
|
+
}
|
299
|
+
end
|
300
|
+
|
301
|
+
# =======
|
302
|
+
private
|
303
|
+
# =======
|
304
|
+
|
305
|
+
# Do not use this method directly.
|
306
|
+
#
|
307
|
+
def f_o_i(shuffle, name, page, *fields)
|
308
|
+
shuffle ? fields.shuffle! : fields
|
309
|
+
parse_fields(nil, name, page, *fields)
|
310
|
+
end
|
311
|
+
|
312
|
+
# Do not use this method directly.
|
313
|
+
#
|
314
|
+
def parse_fields(opts, name, page, *fields)
|
315
|
+
fields.each do |field|
|
316
|
+
lmnt = page.send(*[field, name].compact)
|
317
|
+
var = opts.nil? ? instance_variable_get("@#{field}") : opts[field]
|
318
|
+
lmnt.class.to_s == 'Watir::Select' ? lmnt.pick!(var) : lmnt.fit(var)
|
319
|
+
end
|
320
|
+
end
|
321
|
+
|
322
|
+
# Use this method in conjunction with your nested
|
323
|
+
# collection classes. The collections will notify
|
324
|
+
# their members about the passed parameters.
|
325
|
+
#
|
326
|
+
# Note: You must write a custom #update_from_parent
|
327
|
+
# method in your data object that will know what to
|
328
|
+
# do with the parameter(s) passed to it.
|
329
|
+
#
|
330
|
+
def notify_collections *updates
|
331
|
+
@collections.each {|coll| instance_variable_get("@#{coll}").notify_members *updates }
|
332
|
+
end
|
333
|
+
|
334
|
+
end
|