kuali-test-factory 0.5.3.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,158 @@
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
+ # Some date and time helper functions....
16
+ module DateFactory
17
+
18
+ MONTHS = %w{JAN FEB MAR APR MAY JUN JUL AUG SEP OCT NOV DEC}
19
+
20
+ # Takes a time object and returns a hash containing
21
+ # various parts of the relevant date.
22
+ # @param time_object [Time] the moment you want to convert
23
+ # @returns [Hash] a hash object containing various parts of the date/time you passed to the method
24
+ #
25
+ def date_factory(time_object)
26
+ {
27
+ sakai: make_date(time_object),
28
+ sakai_rounded: make_date(time_object).gsub!(/:\d+/, ":#{Time.at(time_object.to_i/(5*60)*(5*60)).strftime("%M")}"), # Date with time rounded to nearest 5-minute mark.
29
+ short_date: time_object.strftime("%b %-d, %Y"), # => "Oct 18, 2013"
30
+ samigo: time_object.strftime("%m/%d/%Y %I:%M:%S %p"), # => "10/30/2012 07:02:05 AM"
31
+ MON: time_object.strftime("%^b"), # => "DEC"
32
+ Mon: time_object.strftime("%b"), # => "Jan"
33
+ Month: time_object.strftime("%B"), # => "February"
34
+ month_int: time_object.month, # => 3
35
+ day_of_month: time_object.day, # => 17 Note this is not zero-padded
36
+ weekday: time_object.strftime("%A"), # => "Monday"
37
+ wkdy: time_object.strftime("%a"), # => "Tue"
38
+ year: time_object.year, # => 2013
39
+ hour: time_object.strftime("%I").to_i, # => "07" Zero-padded, 12-hour clock
40
+ minute: time_object.strftime("%M"), # => "02" Zero-padded
41
+ minute_rounded: (Time.at(time_object.to_i/(5*60)*(5*60))).strftime("%M"), # => "05" Zero-padded, rounded to 5-minute increments
42
+ meridian: time_object.strftime("%P"), # => "pm"
43
+ MERIDIAN: time_object.strftime("%p"), # => "AM"
44
+ date_w_slashes: time_object.strftime("%m/%d/%Y"), # => 02/08/2013
45
+ custom: time_object # => Allows creation of a custom date string using the passed time value.
46
+ }
47
+ end
48
+
49
+ def an_hour_ago
50
+ date_factory(Time.now - 3600)
51
+ end
52
+ alias last_hour an_hour_ago
53
+
54
+ def right_now
55
+ date_factory(Time.now)
56
+ end
57
+
58
+ def in_an_hour
59
+ date_factory(Time.now + 3600)
60
+ end
61
+ alias next_hour in_an_hour
62
+
63
+ def last_year
64
+ date_factory(Time.now - (3600*24*365))
65
+ end
66
+ alias a_year_ago last_year
67
+
68
+ # Returns a randomly selected date/time from
69
+ # within the last year.
70
+ def in_the_last_year
71
+ date_factory(Time.random(:year_range=>1))
72
+ end
73
+
74
+ def last_month
75
+ index = MONTHS.index(current_month)
76
+ return MONTHS[index-1]
77
+ end
78
+
79
+ def hours_ago(hours)
80
+ date_factory(Time.now - hours*3600)
81
+ end
82
+
83
+ def hours_from_now(hours)
84
+ date_factory(Time.now + hours*3600)
85
+ end
86
+
87
+ # Takes an integer representing
88
+ # the count of minutes as the parameter, and
89
+ # returns the date_factory hash for the
90
+ # resulting Time value.
91
+ #
92
+ def minutes_ago(mins)
93
+ date_factory(Time.now - mins*60)
94
+ end
95
+
96
+ def minutes_from_now(mins)
97
+ date_factory(Time.now + mins*60)
98
+ end
99
+
100
+ # Returns the current month as an
101
+ # upper-case 3-letter string.
102
+ # example: "JUL"
103
+ #
104
+ def current_month
105
+ Time.now.strftime("%^b")
106
+ end
107
+
108
+ def next_month
109
+ index = MONTHS.index(current_month)
110
+ if index < 11
111
+ return MONTHS[index+1]
112
+ else
113
+ return MONTHS[0]
114
+ end
115
+ end
116
+
117
+ def in_a_year
118
+ date_factory(Time.now + (3600*24*365))
119
+ end
120
+ alias next_year in_a_year
121
+
122
+ def yesterday
123
+ date_factory(Time.now - (3600*24))
124
+ end
125
+
126
+ def tomorrow
127
+ date_factory(Time.now + (3600*24))
128
+ end
129
+
130
+ def in_a_week
131
+ date_factory(Time.now + (3600*24*7))
132
+ end
133
+ alias next_week in_a_week
134
+
135
+ def a_week_ago
136
+ date_factory(Time.now - (3600*24*7))
137
+ end
138
+
139
+ def next_monday
140
+ date_factory(Time.at(Time.now+(8-Time.now.wday)*24*3600))
141
+ end
142
+
143
+ # Formats a date string Sakai-style.
144
+ # Useful for verifying creation dates and such.
145
+ #
146
+ # @param time_object [Time] the moment that you want converted to the string
147
+ # @returns [String] a date formatted to look like this: Jun 8, 2012 12:02 pm
148
+ #
149
+ def make_date(time_object)
150
+ month = time_object.strftime("%b ")
151
+ day = time_object.strftime("%-d")
152
+ year = time_object.strftime(", %Y ")
153
+ mins = time_object.strftime(":%M %P")
154
+ hour = time_object.strftime("%l").to_i
155
+ return month + day + year + hour.to_s + mins
156
+ end
157
+
158
+ end
@@ -0,0 +1,76 @@
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
+ # This module provides methods that instantiate the page and data classes.
16
+ module Foundry
17
+
18
+ # Using the page_url defined in the provided page_class,
19
+ # this method will enter that url into the browser's address bar, then run the block of
20
+ # code that you specify.
21
+ # @param page_class [Class] the name of the page class that you want to instantiate
22
+ # @param &block [C] this is the block of code that you want to run while on the given page
23
+ #
24
+ def visit page_class, &block
25
+ on page_class, true, &block
26
+ end
27
+
28
+ # Instantiates the supplied page class, then runs the supplied block of code. Use this
29
+ # method when you are already on the site page you want to interact with.
30
+ # @param page_class [Class] the name of the page class that you want to instantiate
31
+ # @param visit [TrueClass, FalseClass] Essentially you will never have to specify this explicitly
32
+ # @param &block [C] this is the block of code that you want to run while on the given page
33
+ #
34
+ def on page_class, visit=false, &block
35
+ $current_page = page_class.new @browser, visit
36
+ block.call $current_page if block
37
+ $current_page
38
+ end
39
+ alias_method :on_page, :on
40
+
41
+ # Use this for making a data object in your test steps
42
+ #
43
+ # @param data_object_class [Class] The name of the class you want to use to build a data object for testing
44
+ # @param opts [Hash] The list of attributes you want to give to your data object
45
+ #
46
+ def make data_object_class, opts={}
47
+ data_object_class.new @browser, opts
48
+ end
49
+
50
+ # An extension of the #make method that simplifies and improves
51
+ # the readability of your "create" step definitions by
52
+ # combining the make with the create. Of course, this
53
+ # requires that your data object classes properly follow the design
54
+ # pattern and have a #create method available.
55
+ #
56
+ def create data_object_class, opts={}
57
+ data_object = make data_object_class, opts
58
+ data_object.create
59
+ data_object
60
+ end
61
+
62
+ # A helper method that takes a block of code and waits until it resolves to true.
63
+ # Useful when you need to wait for something to be on a page that's a little more
64
+ # involved than a simple element (for those, you should use the #expected_element
65
+ # method found in the PageFactory class)
66
+ # @param timeout [Fixnum] Defaults to 30 seconds
67
+ # @param message [String] The text thrown if the timeout is reached
68
+ #
69
+ # @example
70
+ # page.wait_until { |b| b.processing_message=="Done" }
71
+ #
72
+ def wait_until(timeout=30, message=nil, &block)
73
+ Object::Watir::Wait.until(timeout, message, &block)
74
+ end
75
+
76
+ end
@@ -0,0 +1,224 @@
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
+ # We are extending Watir's element methods here with the #fit method,
16
+ # which can be used with text fields, select lists, radio buttons,
17
+ # and checkboxes.
18
+ #
19
+ # The purpose of +#fit+ is to allow the creation, in your Data Object classes,
20
+ # of a minimal number of +#edit+ methods (ideally only one) written as
21
+ # concisely as possible.
22
+ #
23
+ # Without the +#fit+ method, you would either have to write separate edit
24
+ # methods for every possible field you want to edit, or else your
25
+ # edit method would have to contain lots of repetitive conditional code
26
+ # to prevent making inadvertent updates to those fields that don't need it.
27
+ #
28
+ # Proper use of the +#fit+ method requires following a particular coding
29
+ # pattern, however:
30
+ #
31
+ # * In your Page Classes, define your text field, select list, radio button, and
32
+ # checkbox elements directly. Do not define +#select+, +#set+ and/or +#clear+
33
+ # actions there.
34
+ # * Your data object's instance variables for radio buttons and checkboxes, when
35
+ # not +nil+, should have the values of +:set+ or +:clear+. If they *need* to be
36
+ # something else, then define a Hash transform method to easily convert the
37
+ # custom values back to +:set+ or +:clear+, then pass that transform to the +#fit+ method.
38
+ # * Always remember to end your +#edit+ methods with the +#set_options()+
39
+ # method (a.k.a. +#update_options+), from the DataFactory module. It
40
+ # automatically takes care of updating your data object's instance variables
41
+ # with any new values.
42
+ #
43
+ # ==Example
44
+ #
45
+ # Let's take a look at how the proper use of +#fit+ in your code can significantly
46
+ # clean things up, using a checkbox field for our example. Remember that +#fit+
47
+ # works with radio buttons, text fields, and select lists, too.
48
+ #
49
+ # First, here's some code written without using +#fit+, and using
50
+ # actions for the checkbox page objects, and a Data Object
51
+ # instance variable, +@option+, that is either "YES" or "NO"...
52
+ #
53
+ # class MyPage < BasePage
54
+ # # ...
55
+ # action(:check_checkbox) { |b| b.checkbox(id: "checkbox").set }
56
+ # action(:clear_checkbox) { |b| b.checkbox(id: "checkbox").clear }
57
+ # # ...
58
+ # end
59
+ #
60
+ # class DataObject
61
+ # # ...
62
+ # def edit opts={}
63
+ # # ...
64
+ # if opts[:option] != @option
65
+ # on MyPage do |page|
66
+ # if opts[:option] == "NO"
67
+ # page.clear_checkbox
68
+ # else
69
+ # page.check_checkbox
70
+ # end
71
+ # end
72
+ # @option = opts[:option]
73
+ # end
74
+ # # ...
75
+ # end
76
+ # # ...
77
+ # end
78
+ #
79
+ # That's just nasty! Your Page Class has two element definitions that are nearly identical.
80
+ # And the nested conditional in the Data Object's #edit method hurts the eyes!
81
+ #
82
+ # Now, let's take that same code, but this time use the +#fit+ method. We'll assume that
83
+ # the data object's +@option+ instance variable will be +:set+, +:clear+, or +nil+, and
84
+ # end the +#edit+ with the DataFactory's +#set_options+ helper method...
85
+ #
86
+ # class MyPage < BasePage
87
+ # # ...
88
+ # element(:checkbox) { |b| b.checkbox(id: "checkbox") }
89
+ # # ...
90
+ # end
91
+ #
92
+ # class DataObject
93
+ # # ...
94
+ # def edit opts={}
95
+ # # ...
96
+ # on MyPage do |page|
97
+ # # ...
98
+ # page.checkbox.fit opts[:option]
99
+ # # ...
100
+ # end
101
+ # # ...
102
+ # update_options opts
103
+ # end
104
+ # # ...
105
+ # end
106
+ #
107
+ # Much cleaner!
108
+ #
109
+ # The +#fit+ method is designed to allow for other values than just +:set+ or +:clear+. It will support
110
+ # 'Yes', 'No', 'on', 'off' (and it's case insensitive), +true+, and +false+, as well. This way you don't have to worry so much
111
+ # about making methods that transform from one type to another.
112
+ #
113
+ module Watir
114
+
115
+ module Container
116
+ def frm
117
+ case
118
+ when div(id: 'embedded').exists?
119
+ iframe(id: /easyXDM_default\d+_provider/).iframe(id: 'iframeportlet')
120
+ when div(id: 'Uif-ViewContentWrapper').exists?
121
+ iframe(class: 'uif-iFrame uif-boxLayoutVerticalItem pull-left clearfix')
122
+ else
123
+ self
124
+ end
125
+ end
126
+ end
127
+
128
+ class CheckBox
129
+ def fit(arg)
130
+ setting = TestFactory.binary_transform(arg)
131
+ self.send(setting) unless setting==nil
132
+ end
133
+ end
134
+
135
+ class Radio
136
+ def fit(arg)
137
+ setting = TestFactory.binary_transform(arg)
138
+ self.set if setting==:set
139
+ end
140
+ end
141
+
142
+ module UserEditable
143
+
144
+ # Extends Watir's methods.
145
+ # Use when the argument you are passing to a text field
146
+ # may be nil, in which case you don't
147
+ # want to do anything with the page element.
148
+ #
149
+ def fit(args)
150
+ unless args==nil
151
+ assert_exists
152
+ assert_writable
153
+
154
+ @element.clear
155
+ @element.send_keys(args)
156
+ end
157
+ end
158
+ end
159
+
160
+ class Select
161
+
162
+ # Extends Watir's methods.
163
+ # Use when the argument you are passing to a text field
164
+ # may be nil, in which case you don't
165
+ # want to do anything with the page element.
166
+ # @example
167
+ # page.select_list.fit @my_selection
168
+ #
169
+ def fit(str_or_rx)
170
+ select_by :text, str_or_rx unless str_or_rx==nil
171
+ end
172
+
173
+ # Allows you to select a specific item in a
174
+ # select list, or, if desired, it will pick an item from
175
+ # the list at random.
176
+ #
177
+ # If you pass this method the string '::random::' then
178
+ # it will select an item at random from the select
179
+ # list and, assuming what you passed it was a class instance
180
+ # variable, it will be updated to contain the
181
+ # selected value (hence the ! in the method name).
182
+ # Note that this method will be slow with large selection lists.
183
+ #
184
+ # @example
185
+ # @my_selection='::random::'
186
+ # page.select_list.pick! @my_selection
187
+ # puts @my_selection # => <Value of randomly selected item from list>
188
+ #
189
+ def pick!(item)
190
+ if item=='::random::'
191
+ item.replace(select_at_random)
192
+ else
193
+ fit item
194
+ end
195
+ end
196
+
197
+ # Same as #pick!, except it does not change the
198
+ # value of 'item'
199
+ #
200
+ def pick(item)
201
+ if item=='::random::'
202
+ select_at_random
203
+ else
204
+ fit item
205
+ end
206
+ end
207
+
208
+ private
209
+
210
+ def select_at_random
211
+ ar = options.map(&:text)
212
+ # Must break out of this method if the select list has nothing to select...
213
+ return '::random::' if ar.size==1 && (ar[0]=~/^select(.?)$/i || ar[0]=='')
214
+ sel = ar.sample
215
+ while sel=~/^select(.?)$/i || sel==''
216
+ sel = ar.sample
217
+ end
218
+ select sel
219
+ sel
220
+ end
221
+
222
+ end
223
+
224
+ end