kuality-coeus 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (161) hide show
  1. data/Gemfile +1 -1
  2. data/Gemfile.lock +16 -18
  3. data/chromedriver.log +46 -0
  4. data/features/grants_gov/grants_gov_forms/code_and_form_mapping.feature +26 -0
  5. data/features/grants_gov/grants_gov_forms/forms_validation.feature +1 -0
  6. data/features/grants_gov/grants_gov_forms/s2s_questionnaire.feature +19 -0
  7. data/features/grants_gov/s2s_submission.feature +30 -0
  8. data/features/grants_gov/s2s_validation.feature +36 -0
  9. data/features/proposal_development/create_budget_versions.feature +31 -0
  10. data/features/proposal_development/create_proposal.feature +25 -0
  11. data/features/proposal_development/key_personnel_validations.feature +41 -0
  12. data/features/proposal_development/proposal_actions_validations.feature +46 -0
  13. data/features/proposal_development/proposal_permissions.feature +73 -0
  14. data/features/proposal_development/proposal_workflow.feature +105 -0
  15. data/features/proposal_development/special_review_validations.feature +12 -0
  16. data/features/step_definitions/action_list.rb +12 -0
  17. data/features/step_definitions/awards/create_award.rb +3 -0
  18. data/features/step_definitions/grants_gov/forms.rb +34 -0
  19. data/features/step_definitions/grants_gov/s2s_submission.rb +51 -0
  20. data/features/step_definitions/institutional_proposals/create_institutional_proposal.rb +3 -0
  21. data/features/step_definitions/proposal_development/budget_versions.rb +102 -0
  22. data/features/step_definitions/proposal_development/create_proposal.rb +157 -0
  23. data/features/step_definitions/proposal_development/edit_proposal.rb +79 -0
  24. data/features/step_definitions/proposal_development/institute_rates.rb +21 -0
  25. data/features/step_definitions/proposal_development/key_personnel_validations.rb +74 -0
  26. data/features/step_definitions/proposal_development/proposal_actions_validations.rb +73 -0
  27. data/features/step_definitions/proposal_development/proposal_permissions.rb +141 -0
  28. data/features/step_definitions/proposal_development/proposal_workflow.rb +81 -0
  29. data/features/step_definitions/proposal_development/s2s_validation.rb +30 -0
  30. data/features/step_definitions/proposal_development/special_review_validations.rb +7 -0
  31. data/features/step_definitions/test.rb +3 -0
  32. data/features/step_definitions/users.rb +65 -0
  33. data/features/support/env.rb +35 -0
  34. data/features/test.feature +13 -0
  35. data/kuality-coeus.gemspec +1 -1
  36. data/lib/chromedriver.log +4483 -0
  37. data/lib/kuality-coeus.rb +5 -2
  38. data/lib/kuality-coeus/core_extensions.rb +10 -0
  39. data/lib/kuality-coeus/data_objects/award/award.rb +126 -0
  40. data/lib/kuality-coeus/data_objects/award/award_transaction.rb +57 -0
  41. data/lib/kuality-coeus/data_objects/budget/budget_periods.rb +114 -0
  42. data/lib/kuality-coeus/data_objects/budget/budget_versions.rb +221 -0
  43. data/lib/kuality-coeus/data_objects/budget/subaward_budget.rb +65 -0
  44. data/lib/kuality-coeus/data_objects/committee_document/committee_document.rb +65 -0
  45. data/lib/kuality-coeus/data_objects/committee_document/committee_members.rb +30 -0
  46. data/lib/kuality-coeus/data_objects/committee_document/committee_schedule.rb +27 -0
  47. data/lib/kuality-coeus/data_objects/committee_document/member_roles.rb +28 -0
  48. data/lib/kuality-coeus/data_objects/conflict_of_interest/financial_entity.rb +48 -0
  49. data/lib/kuality-coeus/data_objects/grants_gov/phs_fellowship_questionnaire.rb +90 -0
  50. data/lib/kuality-coeus/data_objects/grants_gov/phs_training_budget_questionnaire.rb +5 -0
  51. data/lib/kuality-coeus/data_objects/institutional_proposal/institutional_proposal.rb +20 -0
  52. data/lib/kuality-coeus/data_objects/institutional_proposal/intellectual_property_review.rb +62 -0
  53. data/lib/kuality-coeus/data_objects/navigation.rb +64 -0
  54. data/lib/kuality-coeus/data_objects/proposal_development/compliance_questions.rb +47 -0
  55. data/lib/kuality-coeus/data_objects/proposal_development/custom_data.rb +41 -0
  56. data/lib/kuality-coeus/data_objects/proposal_development/degrees.rb +40 -0
  57. data/lib/kuality-coeus/data_objects/proposal_development/key_personnel.rb +299 -0
  58. data/lib/kuality-coeus/data_objects/proposal_development/kuali_university_questions.rb +58 -0
  59. data/lib/kuality-coeus/data_objects/proposal_development/permissions.rb +107 -0
  60. data/lib/kuality-coeus/data_objects/proposal_development/personnel_attachments.rb +46 -0
  61. data/lib/kuality-coeus/data_objects/proposal_development/proposal_attachments.rb +41 -0
  62. data/lib/kuality-coeus/data_objects/proposal_development/proposal_development.rb +301 -0
  63. data/lib/kuality-coeus/data_objects/proposal_development/proposal_questions.rb +52 -0
  64. data/lib/kuality-coeus/data_objects/proposal_development/s2s_questionnaire.rb +129 -0
  65. data/lib/kuality-coeus/data_objects/proposal_development/special_review.rb +79 -0
  66. data/lib/kuality-coeus/data_objects/rates/institute_rate.rb +209 -0
  67. data/lib/kuality-coeus/data_objects/user.rb +303 -33
  68. data/lib/kuality-coeus/gem_extensions.rb +26 -0
  69. data/lib/kuality-coeus/page_objects/000_base_page.rb +196 -14
  70. data/lib/kuality-coeus/page_objects/action_list.rb +32 -0
  71. data/lib/kuality-coeus/page_objects/award/award.rb +25 -0
  72. data/lib/kuality-coeus/page_objects/award/award_actions.rb +7 -0
  73. data/lib/kuality-coeus/page_objects/award/award_budget_versions.rb +9 -0
  74. data/lib/kuality-coeus/page_objects/award/commitments.rb +27 -0
  75. data/lib/kuality-coeus/page_objects/award/contacts.rb +19 -0
  76. data/lib/kuality-coeus/page_objects/award/custom_data.rb +6 -0
  77. data/lib/kuality-coeus/page_objects/award/payment_reports_terms.rb +26 -0
  78. data/lib/kuality-coeus/page_objects/award/special_review.rb +7 -0
  79. data/lib/kuality-coeus/page_objects/award/time_and_money.rb +36 -0
  80. data/lib/kuality-coeus/page_objects/budget/budget_actions.rb +31 -0
  81. data/lib/kuality-coeus/page_objects/budget/budget_versions.rb +13 -0
  82. data/lib/kuality-coeus/page_objects/budget/modular_budget.rb +16 -0
  83. data/lib/kuality-coeus/page_objects/budget/non-personnel.rb +11 -0
  84. data/lib/kuality-coeus/page_objects/budget/parameters.rb +65 -0
  85. data/lib/kuality-coeus/page_objects/budget/personnel.rb +56 -0
  86. data/lib/kuality-coeus/page_objects/budget/rates.rb +7 -0
  87. data/lib/kuality-coeus/page_objects/budget/summary.rb +5 -0
  88. data/lib/kuality-coeus/page_objects/budget_document.rb +19 -0
  89. data/lib/kuality-coeus/page_objects/central_admin.rb +4 -2
  90. data/lib/kuality-coeus/page_objects/committee/committee.rb +10 -10
  91. data/lib/kuality-coeus/page_objects/committee/members.rb +4 -4
  92. data/lib/kuality-coeus/page_objects/committee_document.rb +1 -6
  93. data/lib/kuality-coeus/page_objects/confirmation.rb +16 -0
  94. data/lib/kuality-coeus/page_objects/disclosure/disclosure.rb +56 -0
  95. data/lib/kuality-coeus/page_objects/disclosure/disclosure_actions.rb +9 -0
  96. data/lib/kuality-coeus/page_objects/document_header.rb +5 -0
  97. data/lib/kuality-coeus/page_objects/financial_entities.rb +1 -4
  98. data/lib/kuality-coeus/page_objects/financial_entities/my_financial_entities.rb +6 -0
  99. data/lib/kuality-coeus/page_objects/financial_entities/new_financial_entity.rb +11 -0
  100. data/lib/kuality-coeus/page_objects/financial_entities/reporter.rb +5 -3
  101. data/lib/kuality-coeus/page_objects/identity/person.rb +57 -0
  102. data/lib/kuality-coeus/page_objects/institute_rates_maintenance.rb +18 -0
  103. data/lib/kuality-coeus/page_objects/institutional_proposal.rb +18 -0
  104. data/lib/kuality-coeus/page_objects/institutional_proposal/contacts.rb +32 -0
  105. data/lib/kuality-coeus/page_objects/institutional_proposal/custom_data.rb +6 -0
  106. data/lib/kuality-coeus/page_objects/institutional_proposal/distribution.rb +20 -0
  107. data/lib/kuality-coeus/page_objects/institutional_proposal/institutional_proposal.rb +27 -0
  108. data/lib/kuality-coeus/page_objects/institutional_proposal/institutional_proposal_actions.rb +7 -0
  109. data/lib/kuality-coeus/page_objects/institutional_proposal/intellectual_property_review.rb +20 -0
  110. data/lib/kuality-coeus/page_objects/institutional_proposal/special_review.rb +6 -0
  111. data/lib/kuality-coeus/page_objects/kc_awards.rb +48 -0
  112. data/lib/kuality-coeus/page_objects/kc_protocol.rb +15 -0
  113. data/lib/kuality-coeus/page_objects/login.rb +4 -5
  114. data/lib/kuality-coeus/page_objects/lookup_pages/000_lookups.rb +10 -0
  115. data/lib/kuality-coeus/page_objects/lookup_pages/action_list_filter.rb +6 -0
  116. data/lib/kuality-coeus/page_objects/lookup_pages/address_book_lookup.rb +4 -0
  117. data/lib/kuality-coeus/page_objects/lookup_pages/development_proposal_lookup.rb +3 -0
  118. data/lib/kuality-coeus/page_objects/lookup_pages/document_search.rb +10 -0
  119. data/lib/kuality-coeus/page_objects/lookup_pages/group_lookup.rb +3 -0
  120. data/lib/kuality-coeus/page_objects/lookup_pages/institute_rates_lookup.rb +12 -0
  121. data/lib/kuality-coeus/page_objects/lookup_pages/opportunity_lookup.rb +6 -0
  122. data/lib/kuality-coeus/page_objects/lookup_pages/organization_lookup.rb +5 -0
  123. data/lib/kuality-coeus/page_objects/lookup_pages/person_extended_attributes.rb +5 -0
  124. data/lib/kuality-coeus/page_objects/lookup_pages/person_lookup.rb +10 -0
  125. data/lib/kuality-coeus/page_objects/lookup_pages/role_lookup.rb +6 -0
  126. data/lib/kuality-coeus/page_objects/lookup_pages/sponsor_lookup.rb +9 -0
  127. data/lib/kuality-coeus/page_objects/lookup_pages/unit_admin_lookup.rb +3 -0
  128. data/lib/kuality-coeus/page_objects/lookup_pages/unit_lookup.rb +3 -0
  129. data/lib/kuality-coeus/page_objects/maintenance.rb +7 -0
  130. data/lib/kuality-coeus/page_objects/notification_editor.rb +6 -0
  131. data/lib/kuality-coeus/page_objects/proposal_development.rb +7 -2
  132. data/lib/kuality-coeus/page_objects/proposal_development/abstracts_and_attachments.rb +54 -0
  133. data/lib/kuality-coeus/page_objects/proposal_development/key_personnel.rb +126 -0
  134. data/lib/kuality-coeus/page_objects/proposal_development/pd_custom_data.rb +6 -0
  135. data/lib/kuality-coeus/page_objects/proposal_development/permissions.rb +44 -0
  136. data/lib/kuality-coeus/page_objects/proposal_development/phs_fellowship_questionnaire.rb +44 -0
  137. data/lib/kuality-coeus/page_objects/proposal_development/phs_training_budget_questionnaire.rb +50 -0
  138. data/lib/kuality-coeus/page_objects/proposal_development/proposal.rb +47 -8
  139. data/lib/kuality-coeus/page_objects/proposal_development/proposal_actions.rb +62 -0
  140. data/lib/kuality-coeus/page_objects/proposal_development/proposal_summary.rb +9 -0
  141. data/lib/kuality-coeus/page_objects/proposal_development/questions.rb +111 -0
  142. data/lib/kuality-coeus/page_objects/proposal_development/s2s.rb +35 -0
  143. data/lib/kuality-coeus/page_objects/proposal_development/special_review.rb +6 -0
  144. data/lib/kuality-coeus/page_objects/protocol/custom_data.rb +6 -0
  145. data/lib/kuality-coeus/page_objects/protocol/permissions.rb +5 -0
  146. data/lib/kuality-coeus/page_objects/protocol/personnel.rb +5 -0
  147. data/lib/kuality-coeus/page_objects/protocol/protocol.rb +11 -0
  148. data/lib/kuality-coeus/page_objects/protocol/questionnaire.rb +5 -0
  149. data/lib/kuality-coeus/page_objects/protocol/special_review.rb +6 -0
  150. data/lib/kuality-coeus/page_objects/rejection_confirmation.rb +5 -0
  151. data/lib/kuality-coeus/page_objects/researcher.rb +4 -2
  152. data/lib/kuality-coeus/page_objects/shared/unit_administrator.rb +13 -0
  153. data/lib/kuality-coeus/page_objects/system/person_extended_attributes.rb +18 -0
  154. data/lib/kuality-coeus/page_objects/system_admin.rb +7 -0
  155. data/lib/kuality-coeus/page_objects/unit.rb +2 -4
  156. data/lib/kuality-coeus/utilities.rb +39 -0
  157. data/libpeerconnection.log +0 -0
  158. metadata +140 -5
  159. data/lib/kuality-coeus/data_objects/committee_document.rb +0 -65
  160. data/lib/kuality-coeus/data_objects/proposal_development.rb +0 -53
  161. data/lib/kuality-coeus/navigation.rb +0 -3
@@ -1,40 +1,317 @@
1
+ class UserCollection < Hash
2
+
3
+ # Returns an array of all users with the specified role. Takes the role name as a string.
4
+ # The array is shuffled so that #have_role('role name')[0] will be a random selection
5
+ # from the list of matching users.
6
+ def have_role(role)
7
+ self.find_all{|user| user[1][:roles] != nil && user[1][:roles].include?(role)}.shuffle
8
+ end
9
+
10
+ # Returns an array of all users with the specified campus code. Takes the code as a string.
11
+ # The array is shuffled so that #with_campus_code('code')[0] will be a random selection
12
+ # from the list of matching users.
13
+ def with_campus_code(code)
14
+ self.find_all{|user| user[1][:campus_code]==code }.shuffle
15
+ end
16
+
17
+ # Returns an array of all users with the specified affiliation type. Takes the type name as a string.
18
+ # The array is shuffled so that #with_affiliation_type('type name')[0] will be a random selection
19
+ # from the list of matching users.
20
+ def with_affiliation_type(type)
21
+ self.find_all{|user| user[1][:affiliation_type]==type }.shuffle
22
+ end
23
+
24
+ def with_employee_type(type)
25
+ self.find_all{|user| user[1][:employee_type]==type }.shuffle
26
+ end
27
+
28
+ def with_primary_dept_code(code)
29
+ self.find_all{|user| user[1][:primary_dept_code]==code }.shuffle
30
+ end
31
+
32
+ # This is a short cut to "knowing" which user can be used as a PI for
33
+ # a Grants.gov proposal. At some point this should be eliminated--as in,
34
+ # when we know better what exactly a grants.gov PI requires.
35
+ def era_commons_user(username)
36
+ self.find{ |user| user[1][:era_commons_user_name]==username }[0]
37
+ end
38
+
39
+ end
40
+
1
41
  class UserObject
2
42
 
3
43
  include Foundry
4
44
  include DataFactory
45
+ include Navigation
46
+
47
+ attr_accessor :user_name, :principal_id,
48
+ :first_name, :last_name,
49
+ :description, :affiliation_type, :campus_code,
50
+ :employee_id, :employee_status, :employee_type, :base_salary, :primary_dept_code,
51
+ :groups, :roles, :role_qualifiers, :addresses, :phones, :emails,
52
+ :primary_title, :directory_title, :citizenship_type,
53
+ :era_commons_user_name, :graduate_student_count, :billing_element,
54
+ :directory_department
5
55
 
6
- attr_accessor :name, :username, :email, :password, :role
56
+ USERS = UserCollection[YAML.load_file("#{File.dirname(__FILE__)}/users.yml")]
57
+
58
+ ROLES = {
59
+ # Add roles here as needed for testing...
60
+ 'Aggregator' => '110',
61
+ 'approver' => '103',
62
+ 'Award Budget Aggregator' => '113',
63
+ 'Award Budget Approver' => '112',
64
+ 'Award Budget Modifier' => '102',
65
+ 'Award Budget Viewer' => '101',
66
+ 'Award Viewer' => '123',
67
+ 'Budget Creator' => '108',
68
+ 'Create Proposal Log' => '140',
69
+ 'Departments Awards Viewer' => '121',
70
+ 'IACUC Protocol Aggregator' => '1421',
71
+ 'IACUC Protocol Approver' => '1638',
72
+ 'Institutional Proposal Viewer' => '118',
73
+ 'IRB Administrator' => '128',
74
+ 'IRB Approver' => '99',
75
+ 'IRB Reviewer' => '127',
76
+ 'KC Super User' => '177',
77
+ 'Maintain IRB Questionnaire' => '161',
78
+ 'Maintain Proposal Questionnaire' => '162',
79
+ 'Manager' => '98',
80
+ 'Narrative Writer' => '109',
81
+ 'Negotiation Creator' => '1382',
82
+ 'OSP Administrator' => '131',
83
+ 'OSPApprover' => '100',
84
+ 'Protocol Aggregator' => '105',
85
+ 'Proposal Creator' => '111',
86
+ 'System User' => '90',
87
+ 'Unassigned' => '106',
88
+ 'Viewer' => '107',
89
+ 'View Subaward' => '1409',
90
+ 'View Proposal Log' => '142'
91
+ }
7
92
 
8
93
  def initialize(browser, opts={})
9
94
  @browser = browser
10
- defaults = {
11
- #name: "Tester Ten",
12
- username: "admin",
13
- #email: "test10@customer1.herokuapp.com",
14
- #password: "test10"
15
- }
16
- set_options defaults.merge(opts)
95
+ @user_name=case
96
+ when opts.empty?
97
+ 'admin'
98
+ when opts.key?(:user)
99
+ opts[:user]
100
+ when opts.key?(:role)
101
+ USERS.have_role(ROLES[opts[:role]])[0][0]
102
+ end
103
+ defaults = USERS[@user_name]
104
+ defaults.nil? ? options=opts : options=defaults.merge(opts)
105
+ set_options options
17
106
  end
18
107
 
19
- def edit opts={}
20
-
108
+ def create
109
+ # First we have to make sure we're logged in with
110
+ # a user that has permissions to create other users...
111
+ if login_info_div.text =~ /admin$/
112
+ visit(SystemAdmin).person unless PersonLookup.new(@browser).principal_id.present?
113
+ else
114
+ @logged_in_user_name = login_info_div.text[/\w+$/]
115
+ visit Login do |log_in|
116
+ log_in.close_parents
117
+ log_in.username.set 'admin'
118
+ log_in.login
119
+ end
120
+ visit(SystemAdmin).person
121
+ end
122
+ # Now we're certain the create button will be there, so...
123
+ on(PersonLookup).create
124
+ on Person do |add|
125
+ add.expand_all
126
+ add.principal_name.set @user_name
127
+ fill_out add, :description, :affiliation_type, :campus_code, :first_name, :last_name
128
+ # TODO: These "default" checkboxes will need to be reworked if and when
129
+ # a test is going to require multiple affiliations, names, addresses, etc.
130
+ # Until then, there's no need to do anything other than set the necessary single values
131
+ # as "default"...
132
+ add.affiliation_default.set
133
+ add.name_default.set
134
+ add.add_name
135
+ add.add_affiliation
136
+ # TODO: Another thing that will need to be changed if ever there's a need to test multiple
137
+ # lines of employment:
138
+ unless @employee_id.nil?
139
+ fill_out add, :employee_id, :employee_status, :employee_type, :base_salary, :primary_dept_code
140
+ add.primary_employment.set
141
+ add.add_employment_information
142
+ end
143
+ unless @roles.nil?
144
+ @roles.each do |role|
145
+ add.role_id.set role
146
+ add.add_role
147
+ end
148
+ end
149
+ unless @role_qualifiers.nil?
150
+ @role_qualifiers.each do |role, unit|
151
+ add.unit_number(role).set unit
152
+ add.add_role_qualifier role
153
+ end
154
+ end
155
+ unless @groups.nil?
156
+ @groups.each do |group|
157
+ add.group_id.set group
158
+ add.add_group
159
+ end
160
+ end
161
+ unless @addresses.nil?
162
+ @addresses.each do |address|
163
+ add.address_type.fit address[:type]
164
+ add.line_1.fit address[:line_1]
165
+ add.city.fit address[:city]
166
+ add.state.pick! address[:state]
167
+ add.country.pick! address[:country]
168
+ add.zip.fit address[:zip]
169
+ add.address_default.fit address[:default]
170
+ add.add_address
171
+ end
172
+ end
173
+ unless @phones.nil?
174
+ @phones.each do |phone|
175
+ add.phone_type.fit phone[:type]
176
+ add.phone_number.fit phone[:number]
177
+ add.phone_default.fit phone[:default]
178
+ add.add_phone
179
+ end
180
+ end
181
+ unless @emails.nil?
182
+ @emails.each do |email|
183
+ add.email.fit email[:email]
184
+ add.email_type.pick! email[:type]
185
+ add.email_default.fit email[:default]
186
+ add.add_email
187
+ end
188
+ end
189
+ # A breaking of the design pattern, but there's no other
190
+ # way to obtain this number:
191
+ @principal_id = add.principal_id
192
+ add.blanket_approve
193
+ end
194
+ visit(SystemAdmin).person_extended_attributes
195
+ on(PersonExtendedAttributesLookup).create
196
+ on PersonExtendedAttributes do |page|
197
+ page.expand_all
198
+ fill_out page, :description, :primary_title, :directory_title, :citizenship_type,
199
+ :era_commons_user_name, :graduate_student_count, :billing_element,
200
+ :principal_id, :directory_department
201
+ page.blanket_approve
202
+ end
203
+ # Now that we're done with the user creation, we can log back in
204
+ # with the other user, if necessary...
205
+ unless @logged_in_user_name.nil?
206
+ s_o.click
207
+ on Login do |log_in|
208
+ log_in.username.set @logged_in_user_name
209
+ log_in.login
210
+ end
211
+ end
21
212
  end
22
213
 
214
+ # Keep in mind...
215
+ # - This method does nothing if the user
216
+ # is already logged in
217
+ # - If some other user is logged in, they
218
+ # will be automatically logged out
219
+ # - This method will close all child
220
+ # tabs/windows and return to the window
221
+ # with the header frame, so it can see
222
+ # who is currently logged in
23
223
  def sign_in
24
- if logged_out?
25
- user_login
26
- else # Log the current user out, then log in
27
- log_out
28
- user_login
224
+ unless logged_in?
225
+ if username_field.present?
226
+ # Do nothing because we're already there
227
+ else
228
+ visit Researcher do |page|
229
+ page.return_to_portal
230
+ page.close_children
231
+ page.logout
232
+ end
233
+ end
234
+ on Login do |log_in|
235
+ log_in.username.set @user_name
236
+ log_in.login
237
+ end
238
+ on(Researcher).logout_button.wait_until_present
29
239
  end
30
240
  end
31
241
  alias_method :log_in, :sign_in
32
242
 
33
- def logged_in?
34
- if login_info.present?
35
- login_info.text=~/#{@name}/ ? true : false
243
+ def sign_out
244
+ # This _might_ cause an infinite loop, but I'm
245
+ # hoping not...
246
+ on(Researcher) do |page|
247
+ page.return_to_portal
248
+ page.close_children
249
+ end
250
+ if s_o.present?
251
+ s_o.click
36
252
  else
253
+ visit Login do |page|
254
+ if page.username.present?
255
+ # do nothing because we're already logged out...
256
+ else
257
+ sign_out
258
+ end
259
+ end
260
+ end
261
+ end
262
+ alias_method :log_out, :sign_out
263
+
264
+ def exist?
265
+ visit SystemAdmin do |page|
266
+ if username_field.present?
267
+ UserObject.new(@browser).log_in
268
+ end
269
+ page.person
270
+ end
271
+ on PersonLookup do |search|
272
+ search.principal_name.set @user_name
273
+ search.search
274
+ begin
275
+ if search.item_row(@user_name).present?
276
+ # FIXME!
277
+ # This is a coding abomination to include
278
+ # this here, but it's here until I can come
279
+ # up with a better solution...
280
+ @principal_id = search.item_row(@user_name).link(title: /^Person Principal ID=\d+/).text
281
+ return true
282
+ else
283
+ return false
284
+ end
285
+ rescue
286
+ return false
287
+ end
288
+ end
289
+ end
290
+ alias_method :exists?, :exist?
291
+
292
+ def logged_in?
293
+ # Are we on the login page already?
294
+ if username_field.present?
295
+ # Yes! So, we're not logged in...
37
296
  false
297
+ # No, the Kuali header is showing...
298
+ elsif login_info_div.present?
299
+ # So, is the user currently listed as logged in?
300
+ return login_info_div.text.include? @user_name
301
+ else # We're on some page that has no Kuali header, so...
302
+ begin
303
+ # We'll assume that the portal window exists, and go to it.
304
+ on(Researcher).return_to_portal
305
+ # Oops. Apparently there's no portal window, so...
306
+ rescue
307
+ # We'll close any extra tabs/windows
308
+ visit(Login).close_children if @browser.windows.size > 1
309
+ # And make sure that we're using the "parent" window
310
+ @browser.windows[0].use
311
+ end
312
+ # Now that things are hopefully in a clean state, we'll start
313
+ # the process again...
314
+ logged_in?
38
315
  end
39
316
  end
40
317
 
@@ -42,28 +319,21 @@ class UserObject
42
319
  !logged_in?
43
320
  end
44
321
 
45
- def log_out
46
- s_o.click if s_o.present?
47
- end
48
- alias_method :sign_out, :log_out
49
-
50
322
  #========
51
323
  private
52
324
  #========
53
325
 
54
- def user_login
55
- visit Login do |log_in|
56
- log_in.username.set @name
57
- log_in.login
58
- end
326
+ def s_o
327
+ @browser.button(value: 'Logout')
59
328
  end
60
329
 
61
- def s_o
62
- @browser.button(value: "Logout")
330
+ def login_info_div
331
+ @browser.div(id: 'login-info')
63
332
  end
64
333
 
65
- def login_info
66
- @browser.div(id: "login-info")
334
+ def username_field
335
+ Login.new(@browser).username
67
336
  end
68
337
 
69
- end
338
+ end
339
+
@@ -0,0 +1,26 @@
1
+ module Watir
2
+ module Container
3
+ def frm
4
+ case
5
+ when frame(id: 'iframeportlet').exist?
6
+ frame(id: 'iframeportlet')
7
+ when frame(id: /easyXDM_default\d+_provider/).frame(id: 'iframeportlet').exist?
8
+ frame(id: /easyXDM_default\d+_provider/).frame(id: 'iframeportlet')
9
+ when frame(id: /easyXDM_default\d+_provider/).exist?
10
+ frame(id: /easyXDM_default\d+_provider/)
11
+ else
12
+ self
13
+ end
14
+ end
15
+ end
16
+
17
+ # Because of the unique way we
18
+ # set up radio buttons in Coeus,
19
+ # we can use this method in our
20
+ # radio button definitions.
21
+ class Radio
22
+ def fit answer
23
+ set unless answer==nil
24
+ end
25
+ end
26
+ end
@@ -1,35 +1,217 @@
1
1
  class BasePage < PageFactory
2
2
 
3
+ action(:use_new_tab) { |b| b.windows.last.use }
4
+ action(:return_to_portal) { |b| b.portal_window.use }
5
+ action(:close_children) { |b| b.windows[1..-1].each{ |w| w.close} }
6
+ action(:close_parents) { |b| b.windows[0..-2].each{ |w| w.close} }
7
+ action(:loading) { |b| b.frm.image(alt: 'working...').wait_while_present }
8
+ element(:logout_button) { |b| b.button(title: 'Click to logout.') }
9
+ action(:logout) { |b| b.logout_button.click }
10
+
11
+ element(:portal_window) { |b| b.windows(title: 'Kuali Portal Index')[0] }
12
+
13
+ action(:form_tab) { |name, b| b.frm.h2(text: /#{name}/) }
14
+ action(:form_status) { |name, b| b.form_tab(name).text[/(?<=\()\w+/] }
15
+
3
16
  class << self
4
17
 
5
- def frame_element
6
- element(:frm) { |b| b.frame(id: "iframeportlet") }
18
+ def glbl(*titles)
19
+ titles.each do |title|
20
+ action(damballa(title)) { |b| b.frm.button(class: 'globalbuttons', title: title).click; b.loading }
21
+ end
7
22
  end
8
23
 
9
24
  def document_header_elements
10
- element(:headerinfo_table) { |b| b.div(class: "headerbox").table(class: "headerinfo") }
11
-
25
+ value(:doc_title) { |b| b.frm.div(id: 'headerarea').h1.text }
26
+ element(:headerinfo_table) { |b| b.frm.div(id: 'headerarea').table(class: 'headerinfo') }
12
27
  value(:document_id) { |p| p.headerinfo_table[0][1].text }
13
28
  alias_method :doc_nbr, :document_id
14
- value(:status) { |p| p.headerinfo_table[0][3].text }
29
+ value(:document_status) { |p| p.headerinfo_table[0][3].text }
15
30
  value(:initiator) { |p| p.headerinfo_table[1][1].text }
31
+ alias_method :disposition, :initiator
16
32
  value(:last_updated) {|p| p.headerinfo_table[1][3].text }
17
33
  alias_method :created, :last_updated
18
34
  value(:committee_id) { |p| p.headerinfo_table[2][1].text }
19
35
  alias_method :sponsor_name, :committee_id
36
+ alias_method :budget_name, :committee_id
20
37
  value(:committee_name) { |p| p.headerinfo_table[2][3].text }
21
38
  alias_method :pi, :committee_name
22
39
  end
23
40
 
41
+ # Included here because this is such a common field in KC
42
+ def description_field
43
+ element(:description) { |b| b.frm.text_field(name: 'document.documentHeader.documentDescription') }
44
+ end
45
+
24
46
  def global_buttons
25
- action(:expand_all) { |b| b.image(name: "methodToCall.showAllTabs").click } # TODO: Think about moving this into its own element group
26
- action(:submit) { |b| b.image(class: "globalbuttons", title: "submit").click }
27
- action(:save) { |b| b.image(class: "globalbuttons", title: "save").click }
28
- action(:blanket_approve) { |b| b.image(class: "globalbuttons", title: "blanket approve").click }
29
- action(:close) { |b| b.image(class: "globalbuttons", title: "close").click }
30
- action(:cancel) { |b| b.image(class: "globalbuttons", title: "cancel").click }
47
+ glbl 'save', 'Reject', 'blanket approve', 'close', 'cancel', 'reload',
48
+ 'Delete Proposal', 'approve', 'disapprove',
49
+ 'Generate All Periods', 'Calculate All Periods', 'Default Periods',
50
+ 'Calculate Current Period', 'submit', 'Send Notification'
51
+ # Explicitly defining the "recall" button to keep the method name at "recall" instead of "recall_current_document"...
52
+ element(:recall_button) { |b| b.frm.button(class: 'globalbuttons', title: 'Recall current document') }
53
+ action(:recall) { |b| b.recall_button.click; b.loading }
54
+ action(:edit) { |b| b.frm.button(name: 'methodToCall.editOrVersion').click; b.loading }
55
+ action(:delete_selected) { |b| b.frm.button(class: 'globalbuttons', name: 'methodToCall.deletePerson').click; b.loading }
56
+ element(:send_button) { |b| b.frm.button(class: 'globalbuttons', name: 'methodToCall.sendNotification', title: 'send') }
57
+ action(:send_fyi) { |b| b.send_button.click; b.loading }
58
+ end
59
+
60
+ def tab_buttons
61
+ action(:expand_all) { |b| b.frm.button(name: 'methodToCall.showAllTabs').click; b.loading }
62
+ end
63
+
64
+ def tiny_buttons
65
+ action(:search) { |b| b.frm.button(title: 'search', value: 'search').click; b.loading }
66
+ action(:clear) { |b| b.frm.button(name: 'methodToCall.clearValues').click; b.loading }
67
+ action(:cancel_button) { |b| b.frm.link(title: 'cancel').click; b.loading }
68
+ action(:yes) { |b| b.frm.button(name: 'methodToCall.rejectYes').click; b.loading }
69
+ action(:no) {|b| b.frm.button(name: 'methodToCall.rejectNo').click; b.loading }
70
+ action(:add) { |b| b.frm.button(name: 'methodToCall.addNotificationRecipient.anchor').click; b.loading }
71
+ end
72
+
73
+ def search_results_table
74
+ element(:results_table) { |b| b.frm.table(id: 'row') }
75
+
76
+ action(:edit_item) { |match, p| p.results_table.row(text: /#{match}/m).link(text: 'edit').click; b.use_new_tab; b.close_parents }
77
+ alias_method :edit_person, :edit_item
78
+
79
+ action(:item_row) { |match, b| b.results_table.row(text: /#{match}/m) }
80
+ action(:open_item) { |match, b| b.item_row(match).link(text: /#{match}/).click; b.use_new_tab; b.close_parents }
81
+ action(:delete_item) { |match, p| p.item_row(match).link(text: 'delete').click; p.use_new_tab; p.close_parents }
82
+
83
+ action(:return_value) { |match, p| p.item_row(match).link(text: 'return value').click }
84
+ action(:return_random) { |b| b.return_value_links[rand(b.return_value_links.length)].click }
85
+ element(:return_value_links) { |b| b.results_table.links(text: 'return value') }
86
+ end
87
+
88
+ def budget_header_elements
89
+ action(:return_to_proposal) { |b| b.frm.button(name: 'methodToCall.returnToProposal').click; b.loading }
90
+ buttons 'Budget Version', 'Parameters', 'Rates', 'Summary', 'Personnel', 'Non-Personnel',
91
+ 'Distribution & Income', 'Budget Actions'
92
+ # Need the _tab suffix because of method collisions
93
+ action(:modular_budget_tab) { |b| b.frm.button(value: 'Modular Budget').click }
94
+ end
95
+
96
+ def budget_versions_elements
97
+ element(:name) { |b| b.frm.text_field(name: 'newBudgetVersionName') }
98
+ action(:add) { |b| b.frm.button(name: 'methodToCall.addBudgetVersion').click }
99
+ action(:version) { |budget, p| p.budgetline(budget).td(class: 'tab-subhead', index: 2).text }
100
+ action(:direct_cost) { |budget, p| p.budgetline(budget).td(class: 'tab-subhead', index: 3).text }
101
+ action(:f_and_a) { |budget, p| p.budgetline(budget).td(class: 'tab-subhead', index: 4).text }
102
+ action(:total) { |budget, p| p.budgetline(budget).td(class: 'tab-subhead', index: 5).text }
103
+ # Called "budget status" to avoid method collision...
104
+ action(:budget_status) { |budget, p| p.budgetline(budget).select(title: 'Budget Status') }
105
+ action(:open) { |budget, p| p.budgetline(budget).button(alt: 'open budget').click }
106
+ action(:copy) { |budget, p| p.budgetline(budget).button(alt: 'copy budget').click }
107
+ action(:f_and_a_rate_type) { |budget, p| p.budget_table(budget)[0][3].text }
108
+ action(:cost_sharing) { |budget, p| p.budget_table(budget)[1][1].text }
109
+ action(:budget_last_updated) { |budget, p| p.budget_table(budget)[1][3].text }
110
+ action(:unrecovered_f_and_a) { |budget, p| p.budget_table(budget)[2][1].text }
111
+ action(:last_updated_by) { |budget, p| p.budget_table(budget)[2][3].text }
112
+ action(:comments) { |budget, p| p.budget_table(budget)[3][1].text }
113
+
114
+ private
115
+ element(:b_v_table) { |b| b.frm.table(id: 'budget-versions-table') }
116
+ action(:budgetline) { |budget, p| p.b_v_table.td(class: 'tab-subhead', text: budget).parent }
117
+ action(:budget_table) { |budget, p| p.b_v_table.tbodys[p.target_index(budget)].table }
118
+ action(:target_index) do |budget, p|
119
+ i=p.b_v_table.tbodys.find_index { |tbody| tbody.td(class: 'tab-subhead', index: 1).text==budget }
120
+ i+1
121
+ end
122
+ end
123
+
124
+ def special_review
125
+ element(:add_type) { |b| b.frm.select(id: 'specialReviewHelper.newSpecialReview.specialReviewTypeCode') }
126
+ element(:add_approval_status) { |b| b.frm.select(id: 'specialReviewHelper.newSpecialReview.approvalTypeCode') }
127
+ element(:add_protocol_number) { |b| b.frm.text_field(id: 'specialReviewHelper.newSpecialReview.protocolNumber') }
128
+ element(:add_application_date) { |b| b.frm.text_field(id: 'specialReviewHelper.newSpecialReview.applicationDate') }
129
+ element(:add_approval_date) { |b| b.frm.text_field(id: 'specialReviewHelper.newSpecialReview.approvalDate') }
130
+ element(:add_expiration_date) { |b| b.frm.text_field(id: 'specialReviewHelper.newSpecialReview.expirationDate') }
131
+ element(:add_exemption_number) { |b| b.frm.select(id: 'specialReviewHelper.newSpecialReview.exemptionTypeCodes') }
132
+
133
+ action(:add) { |b| b.frm.button(name: 'methodToCall.addSpecialReview.anchorSpecialReview').click }
134
+
135
+ element(:save_button) { |b| b.frm.button(name: 'methodToCall.save') }
136
+ end
137
+
138
+ def custom_data
139
+ element(:graduate_student_count) { |b| b.target_row('Graduate Student Count').text_field }
140
+ element(:billing_element) { |b| b.target_row('Billing Element').text_field }
141
+ element(:save_button) { |b| b.frm.button(name: 'methodToCall.save') }
142
+ element(:asdf_tab) { |b| b.frm.div(id: 'tab-asdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdf-div') }
143
+ action(:target_row) { |text, b| b.frm.trs(class: 'datatable').find { |row| row.text.include? text } }
144
+ end
145
+
146
+ def route_log
147
+ element(:route_log_iframe) { |b| b.frm.frame(name: 'routeLogIFrame') }
148
+ element(:actions_taken_table) { |b| b.route_log_iframe.div(id: 'tab-ActionsTaken-div').table }
149
+ value(:actions_taken) { |b| (b.actions_taken_table.rows.collect{ |row| row[1].text }.compact.uniq).reject{ |action| action==''} }
150
+ element(:pnd_act_req_table) { |b| b.route_log_iframe.div(id: 'tab-PendingActionRequests-div').table }
151
+ value(:action_requests) { |b| (b.pnd_act_req_table.rows.collect{ |row| row[1].text}).reject{ |action| action==''} }
152
+ action(:show_future_action_requests) { |b| b.route_log_iframe.h2(text: 'Future Action Requests').parent.parent.image(title: 'show').click }
153
+ element(:future_actions_table) { |b| b.route_log_iframe.div(id: 'tab-FutureActionRequests-div').table }
154
+ action(:requested_action_for) { |name, b| b.future_actions_table.tr(text: /#{name}/).td(index: 2).text }
155
+ end
156
+
157
+ # Gathers all errors on the page and puts them in an array called "errors"
158
+ def error_messages
159
+ element(:errors) do |b|
160
+ errs = []
161
+ b.left_errmsg_tabs.each do |div|
162
+ if div.div.div.exist?
163
+ errs << div.div.divs.collect{ |div| div.text }
164
+ elsif div.li.exist?
165
+ errs << div.lis.collect{ |li| li.text }
166
+ end
167
+ end
168
+ b.left_errmsg.each do |div|
169
+ if div.div.div.exist?
170
+ errs << div.div.divs.collect{ |div| div.text }
171
+ elsif div.li.exist?
172
+ errs << div.lis.collect{ |li| li.text }
173
+ end
174
+ end
175
+ errs.flatten
176
+ end
177
+ element(:left_errmsg_tabs) { |b| b.frm.divs(class: 'left-errmsg-tab') }
178
+ element(:left_errmsg) { |b| b.frm.divs(class: 'left-errmsg') }
179
+ element(:error_messages_div) { |b| b.frm.div(class: 'error') }
180
+ end
181
+
182
+ def validation_elements
183
+ element(:validation_button) { |b| b.frm.button(name: 'methodToCall.activate') }
184
+ action(:show_data_validation) { |b| b.frm.button(id: 'tab-DataValidation-imageToggle').click; b.validation_button.wait_until_present }
185
+ action(:turn_on_validation) { |b| b.validation_button.click; b.special_review_button.wait_until_present }
186
+ element(:validation_errors_and_warnings) { |b| errs = []; b.validation_err_war_fields.each { |field| errs << field.html[/(?<=>).*(?=<)/] }; errs }
187
+ element(:validation_err_war_fields) { |b| b.frm.tds(width: '94%') }
31
188
  end
32
-
33
- end
34
189
 
35
- end
190
+ def links(*links_text)
191
+ links_text.each { |link| elementate(:link, link) }
192
+ end
193
+
194
+ def buttons(*buttons_text)
195
+ buttons_text.each { |button| elementate(:button, button) }
196
+ end
197
+
198
+ private
199
+
200
+ # A helper method that converts the passed string into snake case. See the StringFactory
201
+ # module for more info.
202
+ #
203
+ def damballa(text)
204
+ StringFactory::damballa(text)
205
+ end
206
+
207
+ def elementate(type, text)
208
+ identifiers={:link=>:text, :button=>:value}
209
+ el_name=damballa("#{text}_#{type}")
210
+ act_name=damballa(text)
211
+ element(el_name) { |b| b.frm.send(type, identifiers[type]=>text) }
212
+ action(act_name) { |b| b.frm.send(type, identifiers[type]=>text).click }
213
+ end
214
+
215
+ end # self
216
+
217
+ end # BasePage