kuali-test-factory 0.5.3.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|