kuality-coeus 0.0.3 → 0.0.4

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.
Files changed (59) hide show
  1. checksums.yaml +8 -8
  2. data/features/grants_gov/grants_gov_forms/code_and_form_mapping.feature +3 -3
  3. data/features/grants_gov/grants_gov_forms/forms_validation.feature +5 -1
  4. data/features/grants_gov/grants_gov_forms/s2s_questionnaire.feature +5 -3
  5. data/features/grants_gov/s2s_submission.feature +7 -4
  6. data/features/proposal_development/create_budget_versions.feature +2 -1
  7. data/features/proposal_development/create_proposal.feature +21 -19
  8. data/features/proposal_development/key_personnel_validations.feature +4 -3
  9. data/features/proposal_development/proposal_actions_validations.feature +9 -17
  10. data/features/proposal_development/proposal_permissions.feature +25 -22
  11. data/features/proposal_development/proposal_workflow.feature +8 -37
  12. data/features/step_definitions/{proposal_development → budget_versions}/budget_versions.rb +9 -9
  13. data/features/step_definitions/budget_versions/project_personnel.rb +11 -0
  14. data/features/step_definitions/delete_proposals.rb +9 -0
  15. data/features/step_definitions/grants_gov/forms.rb +27 -0
  16. data/features/step_definitions/grants_gov/s2s_submission.rb +30 -5
  17. data/features/step_definitions/proposal_development/create_proposal.rb +2 -9
  18. data/features/step_definitions/proposal_development/edit_proposal.rb +3 -4
  19. data/features/step_definitions/proposal_development/key_personnel_validations.rb +10 -1
  20. data/features/step_definitions/proposal_development/proposal_actions_validations.rb +7 -6
  21. data/features/step_definitions/proposal_development/proposal_permissions.rb +51 -65
  22. data/features/step_definitions/proposal_development/proposal_workflow.rb +0 -15
  23. data/features/step_definitions/test.rb +1 -3
  24. data/features/step_definitions/users.rb +6 -6
  25. data/features/support/env.rb +1 -1
  26. data/features/test.feature +3 -1
  27. data/kuality-coeus.gemspec +1 -1
  28. data/lib/kuality-coeus.rb +5 -5
  29. data/lib/kuality-coeus/data_objects/budget/budget_periods.rb +5 -4
  30. data/lib/kuality-coeus/data_objects/budget/budget_versions.rb +18 -7
  31. data/lib/kuality-coeus/data_objects/budget/personnel.rb +135 -0
  32. data/lib/kuality-coeus/data_objects/budget/subaward_budget.rb +1 -3
  33. data/lib/kuality-coeus/data_objects/identity/group.rb +19 -0
  34. data/lib/kuality-coeus/data_objects/navigation.rb +23 -0
  35. data/lib/kuality-coeus/data_objects/proposal_development/degrees.rb +1 -2
  36. data/lib/kuality-coeus/data_objects/proposal_development/key_personnel.rb +3 -6
  37. data/lib/kuality-coeus/data_objects/proposal_development/permissions.rb +16 -4
  38. data/lib/kuality-coeus/data_objects/proposal_development/proposal_development.rb +7 -5
  39. data/lib/kuality-coeus/data_objects/user.rb +23 -17
  40. data/lib/kuality-coeus/page_objects/000_base_page.rb +2 -1
  41. data/lib/kuality-coeus/page_objects/budget/non-personnel.rb +0 -2
  42. data/lib/kuality-coeus/page_objects/budget/parameters.rb +4 -1
  43. data/lib/kuality-coeus/page_objects/budget/personnel.rb +18 -26
  44. data/lib/kuality-coeus/page_objects/confirmation.rb +0 -2
  45. data/lib/kuality-coeus/page_objects/identity/group.rb +7 -0
  46. data/lib/kuality-coeus/page_objects/lookup_pages/000_lookups.rb +6 -0
  47. data/lib/kuality-coeus/page_objects/lookup_pages/job_code_lookup.rb +3 -0
  48. data/lib/kuality-coeus/page_objects/lookup_pages/non_org_address_lookup.rb +14 -0
  49. data/lib/kuality-coeus/page_objects/lookup_pages/person_lookup.rb +4 -2
  50. data/lib/kuality-coeus/page_objects/lookup_pages/to_be_named_lookup.rb +9 -0
  51. data/lib/kuality-coeus/page_objects/{institute_rates_maintenance.rb → maintenance/institute_rates_maintenance.rb} +0 -0
  52. data/lib/kuality-coeus/page_objects/proposal_development/permissions.rb +9 -1
  53. data/lib/kuality-coeus/page_objects/system_admin.rb +1 -1
  54. data/lib/kuality-coeus/utilities.rb +5 -6
  55. data/lib/resources/NSF_CoverPage_1_3-V1.3.pdf +0 -0
  56. data/lib/resources/NSF_DATA_MANAGEMENT_PLAN.pdf +0 -0
  57. data/lib/resources/PHS_Fellowship_Supplemental_1_1-V1.1.pdf +0 -0
  58. data/lib/resources/test.pdf +0 -0
  59. metadata +16 -4
@@ -5,9 +5,10 @@ class BudgetPeriodObject
5
5
  include StringFactory
6
6
  include Navigation
7
7
 
8
- attr_accessor :document_id, :budget_name, :number, :start_date, :end_date,
9
- :total_sponsor_cost, :direct_cost, :f_and_a_cost, :unrecovered_f_and_a,
10
- :cost_sharing, :cost_limit, :direct_cost_limit, :datified
8
+ attr_accessor :number, :start_date, :end_date, :total_sponsor_cost,
9
+ :direct_cost, :f_and_a_cost, :unrecovered_f_and_a,
10
+ :cost_sharing, :cost_limit, :direct_cost_limit, :datified,
11
+ :budget_name
11
12
 
12
13
  def initialize(browser, opts={})
13
14
  @browser = browser
@@ -17,7 +18,7 @@ class BudgetPeriodObject
17
18
  }
18
19
 
19
20
  set_options(defaults.merge(opts))
20
- requires :document_id, :budget_name, :start_date
21
+ requires :start_date, :budget_name
21
22
  datify
22
23
  end
23
24
 
@@ -14,7 +14,7 @@ class BudgetVersionsObject
14
14
  :project_start_date, :project_end_date, :total_direct_cost_limit,
15
15
  :budget_periods, :unrecovered_fa_rate_type, :f_and_a_rate_type,
16
16
  :submit_cost_sharing, :residual_funds, :total_cost_limit,
17
- :subaward_budgets
17
+ :subaward_budgets, :personnel
18
18
 
19
19
 
20
20
  def initialize(browser, opts={})
@@ -25,7 +25,8 @@ class BudgetVersionsObject
25
25
  cost_sharing: '0.00',
26
26
  f_and_a: '0.00',
27
27
  budget_periods: BudgetPeriodsCollection.new,
28
- subaward_budgets: SubawardBudgetCollection.new
28
+ subaward_budgets: SubawardBudgetCollection.new,
29
+ personnel: BudgetPersonnelCollection.new
29
30
  }
30
31
 
31
32
  set_options(defaults.merge(opts))
@@ -67,7 +68,6 @@ class BudgetVersionsObject
67
68
 
68
69
  def add_period opts={}
69
70
  defaults={
70
- document_id: @document_id,
71
71
  budget_name: @name,
72
72
  doc_type: @doc_header
73
73
  }
@@ -94,10 +94,13 @@ class BudgetVersionsObject
94
94
  # Use it for editing the Budget Version while on the Proposal, but not the Periods
95
95
  def edit opts={}
96
96
  navigate
97
- on BudgetVersions do |edit|
98
- edit.final(@name).fit opts[:final]
99
- edit.budget_status(@name).fit opts[:budget_status]
100
- # TODO: More here as needed...
97
+ on(BudgetVersions).open @name
98
+ confirmation
99
+ on Parameters do |edit|
100
+ edit.final.fit opts[:final]
101
+ edit.budget_status.fit opts[:budget_status]
102
+ edit.total_direct_cost_limit.fit opts[:total_direct_cost_limit]
103
+ # TODO: More to add here...
101
104
  edit.save
102
105
  end
103
106
  set_options(opts)
@@ -153,6 +156,14 @@ class BudgetVersionsObject
153
156
  @subaward_budgets << sab
154
157
  end
155
158
 
159
+ def add_project_personnel(opts={})
160
+ open_budget
161
+ on(Parameters).personnel
162
+ person = make BudgetPersonnelObject, opts
163
+ person.create
164
+ @personnel << person
165
+ end
166
+
156
167
  # =======
157
168
  private
158
169
  # =======
@@ -0,0 +1,135 @@
1
+ class BudgetPersonnelObject
2
+
3
+ include Foundry
4
+ include DataFactory
5
+ include StringFactory
6
+ include Navigation
7
+ include Utilities
8
+
9
+ attr_accessor :type, :name, :job_code, :appointment_type, :base_salary,
10
+ :salary_effective_date, :salary_anniversary_date,
11
+ # TODO: Some day we are going to have to allow for multiple codes and periods, here...
12
+ :object_code_name, :start_date, :end_date, :percent_effort, :percent_charged,
13
+ :period_type, :requested_salary, :calculated_fringe
14
+ #TODO: Add more variables here - "apply inflation", "submit cost sharing", etc.
15
+
16
+ def initialize(browser, opts={})
17
+ @browser = browser
18
+
19
+ defaults = {
20
+ # Note: 'type' must be one of:
21
+ # 'employee', 'non_employee', or 'to_be_named'
22
+ type: 'employee',
23
+ base_salary: random_dollar_value(1000000),
24
+ appointment_type: '12M DURATION',
25
+ object_code_name: '::random::',
26
+ percent_effort: random_percentage,
27
+ period_type: '::random::'
28
+ }
29
+
30
+ set_options(defaults.merge(opts))
31
+ @percent_charged ||= (@percent_effort.to_f/2).round(2)
32
+ end
33
+
34
+ def create
35
+ # Navigation is handled by the BudgetVersionsObject method
36
+ if on(Personnel).job_code(@name).present?
37
+ # The person is already listed so do nothing
38
+ else
39
+ get_person
40
+ end
41
+ set_job_code
42
+ on Personnel do |page|
43
+ @salary_effective_date ||= page.salary_effective_date(@name).value
44
+ fill_out_item @name, page, :appointment_type, :base_salary, :salary_effective_date,
45
+ :salary_anniversary_date
46
+ page.save
47
+ page.expand_all
48
+ page.person.select "#{@name} - #{@job_code}"
49
+ sleep 1 # this is required because the select list contents get updated when the person is selected.
50
+ page.object_code_name.pick! @object_code_name
51
+ page.add_details
52
+ page.expand_all
53
+ set_dates page
54
+ fill_out_item @name, page, :percent_effort, :percent_charged, :period_type
55
+ page.calculate @name
56
+ @requested_salary=page.requested_salary @name
57
+ @calculated_fringe=page.calculated_fringe @name
58
+ page.save
59
+ end
60
+ end
61
+
62
+ # ========
63
+ private
64
+ # ========
65
+
66
+ def set_job_code
67
+ unless @job_code.nil?
68
+ on(Personnel).job_code(@name).set @job_code
69
+ else
70
+ on(Personnel).lookup_job_code(@name)
71
+ on JobCodeLookup do |page|
72
+ page.search
73
+ page.return_random
74
+ end
75
+ @job_code=on(Personnel).job_code(@name).value
76
+ end
77
+ end
78
+
79
+ def get_person
80
+ on(Personnel).send("#{@type}_search")
81
+ if @name.nil?
82
+ on lookup_page do |page|
83
+ page.search
84
+ @name=page.returned_full_names.sample
85
+ end
86
+ end
87
+ on lookup_page do |page|
88
+ case(@type)
89
+ when 'employee'
90
+ page.select_person @name
91
+ when 'non_employee'
92
+ page.first_name.set @name[/^\S+/]
93
+ page.last_name.set @name[/\S+$/]
94
+ page.search
95
+ page.select_person @name[/\S+$/]
96
+ when 'to_be_named'
97
+ page.person_name.set @name
98
+ page.search
99
+ page.select_person @name
100
+ end
101
+ page.return_selected
102
+ end
103
+ end
104
+
105
+ # TODO: WOW! This desperately needs to be dryed up!
106
+ # It might be a good idea to make a new method in
107
+ # TestFactory for this.
108
+ def set_dates(page)
109
+ if @start_date.nil?
110
+ @start_date=page.start_date(@name).value
111
+ else
112
+ page.start_date(@name).set @start_date
113
+ end
114
+ if @end_date.nil?
115
+ @end_date=page.end_date(@name).value
116
+ else
117
+ page.end_date(@name).set @end_date
118
+ end
119
+ end
120
+
121
+ def lookup_page
122
+ Kernel.const_get({
123
+ employee: 'PersonLookup',
124
+ non_employee: 'NonOrgAddressBookLookup',
125
+ to_be_named: 'ToBeNamedPersonsLookup'
126
+ }[@type.to_sym])
127
+ end
128
+
129
+ end
130
+
131
+ class BudgetPersonnelCollection < Array
132
+
133
+
134
+
135
+ end
@@ -48,9 +48,7 @@ class SubawardBudgetObject
48
48
  add.add_file_name.set($file_folder+@file_name)
49
49
  add.add_subaward_budget
50
50
  add.show_details @organization_name
51
- add.direct_cost(@organization_name).fit @direct_cost
52
- add.f_and_a_cost(@organization_name).fit @f_and_a_cost
53
- add.cost_sharing(@organization_name).fit @cost_sharing
51
+ fill_out_item @organization_name, add, :direct_cost, :f_and_a_cost, :cost_sharing
54
52
  @total_cost=add.total_cost(@organization_name)
55
53
  add.save
56
54
  end
@@ -0,0 +1,19 @@
1
+ class GroupObject
2
+
3
+ include Foundry
4
+ include DataFactory
5
+ include Navigation
6
+
7
+ attr_accessor :id, :namespace, :name, :description, :type,
8
+ :principal_name, :assignees
9
+
10
+ def initialize(browser, opts={})
11
+ @browser = browser
12
+
13
+ end
14
+
15
+ def create
16
+
17
+ end
18
+
19
+ end
@@ -61,4 +61,27 @@ module Navigation
61
61
  end
62
62
  alias_method :fill_in, :fill_out
63
63
 
64
+ # Same as the above method, but used with methods that take a
65
+ # parameter to identify the target element...
66
+ def fill_out_item(name, page, *fields)
67
+ methods={
68
+ 'Watir::TextField' => lambda{|n, p, f| p.send(f, n).fit(get f)},
69
+ 'Watir::Select' => lambda{|n, p, f| p.send(f, n).pick!(get f)},
70
+ 'Watir::Radio' => lambda{|n, p, f| p.send(f, n, get(f)) unless get(f)==nil },
71
+ 'Watir::CheckBox' => lambda{|n, p, f| p.send(f, n).fit(get f) }
72
+ }
73
+ fields.shuffle.each do |field|
74
+ # TODO: Someday see if there's a way to fix things so this rescue isn't necessary...
75
+ # It's here because the radio button "element" definitions are *actions* that
76
+ # require a parameter, so just sending the method to the page
77
+ # is not going to work.
78
+ begin
79
+ key = page.send(field, name).class.to_s
80
+ rescue NoMethodError
81
+ key = 'Watir::Radio'
82
+ end
83
+ methods[key].call(name, page, field)
84
+ end
85
+ end
86
+
64
87
  end
@@ -25,8 +25,7 @@ class DegreeObject
25
25
  degrees.expand_all
26
26
  degrees.degree_type(@person).pick! @type
27
27
  degrees.degree_description(@person).fit @description
28
- degrees.graduation_year(@person).fit @graduation_year
29
- degrees.school(@person).fit @school
28
+ fill_out_item @person, degrees, :graduation_year, :school
30
29
  degrees.add_degree(@person)
31
30
  end
32
31
  end
@@ -44,8 +44,8 @@ class KeyPersonObject
44
44
  end
45
45
  on KeyPersonnel do |person|
46
46
  @full_name=person.person_name
47
- @first_name=@full_name[/^\w+/]
48
47
  @last_name=@full_name[/\w+$/]
48
+ @first_name=$~.pre_match.strip
49
49
  end
50
50
  else
51
51
  on PersonLookup do |look|
@@ -109,10 +109,7 @@ class KeyPersonObject
109
109
  # If it's a key person without units then they won't have credit splits,
110
110
  # otherwise, the person will, so fill them out...
111
111
  if @key_person_role==nil || !@units.empty?
112
- person.space(@full_name).fit @space
113
- person.responsibility(@full_name).fit @responsibility
114
- person.financial(@full_name).fit @financial
115
- person.recognition(@full_name).fit @recognition
112
+ fill_out_item @full_name, person, :space, :responsibility, :financial, :recognition
116
113
  end
117
114
 
118
115
  # Proposal Person Certification
@@ -124,7 +121,7 @@ class KeyPersonObject
124
121
  end
125
122
 
126
123
  # Add gathering/setting of more attributes here as needed
127
- person.era_commons_name(@full_name).fit @era_commons_name
124
+ fill_out_item @full_name, person, :era_commons_name
128
125
  person.save
129
126
  end
130
127
  end
@@ -26,23 +26,35 @@ class PermissionsObject
26
26
  # users to roles, but does not check who is already
27
27
  # assigned. You need to make sure that the values
28
28
  # used in the instantiation of the class are
29
- # an accurate reflection of what exists in the site.
29
+ # an accurate reflection of what exists in the site,
30
+ # if that's important to the test.
30
31
  def assign
31
32
  navigate
32
33
  on Permissions do |add|
33
34
  # See the roles method defined below...
34
35
  roles.each do |inst_var, role|
35
36
  get(inst_var).each do |username|
36
- unless add.user_row(username).present? && add.assigned_role(username).include?(role)
37
+ if add.assigned_users.include?(username)
38
+ unless add.assigned_role(username).include?(role)
39
+ add.edit_role username
40
+ on Roles do |roles|
41
+ roles.use_new_tab
42
+ roles.send(StringFactory.damballa(role)).set
43
+ roles.save
44
+ sleep 1.2 # Need to wait for the window to close
45
+ roles.use_new_tab
46
+ end
47
+ add.save
48
+ end
49
+ else
37
50
  add.user_name.set username
38
51
  add.role.select role
39
52
  add.add
40
53
  add.user_row(username).wait_until_present
54
+ add.save
41
55
  end
42
56
  end
43
57
  end
44
- add.save
45
- # TODO: Add some logic here to use in case the user is already added to the list (so use add_roles)
46
58
  end
47
59
  end
48
60
 
@@ -73,6 +73,7 @@ class ProposalDevelopmentObject
73
73
  on Proposal do |edit|
74
74
  edit.proposal
75
75
  edit.expand_all
76
+ edit.project_title.fit opts[:project_title]
76
77
  edit.project_start_date.fit opts[:project_start_date]
77
78
  edit.opportunity_id.fit opts[:opportunity_id]
78
79
  edit.proposal_type.fit opts[:proposal_type]
@@ -185,15 +186,16 @@ class ProposalDevelopmentObject
185
186
  end
186
187
  end
187
188
 
188
- def recall(type, reason=random_alphanums)
189
- types={:revision=>:recall_to_action_list, :cancel=>:recall_and_cancel}
189
+ def recall(reason=random_alphanums)
190
190
  @recall_reason=reason
191
191
  open_proposal
192
192
  on(Proposal).recall
193
193
  on Confirmation do |conf|
194
194
  conf.reason.set @recall_reason
195
- conf.send(types[type])
195
+ conf.yes
196
196
  end
197
+ open_proposal
198
+ @status=on(Proposal).document_status
197
199
  end
198
200
 
199
201
  def close
@@ -203,8 +205,8 @@ class ProposalDevelopmentObject
203
205
 
204
206
  def view(tab)
205
207
  open_proposal
206
- unless @status=='CANCELED' || on(Proposal).send((tab.to_s+'_button').to_sym).parent.class_name=~/tabcurrent$/
207
- on(Proposal).send(tab)
208
+ unless @status=='CANCELED' || on(Proposal).send(StringFactory.damballa("#{tab}_button")).parent.class_name=~/tabcurrent$/
209
+ on(Proposal).send(StringFactory.damballa(tab.to_s))
208
210
  end
209
211
  end
210
212
 
@@ -93,31 +93,34 @@ class UserObject
93
93
  def initialize(browser, opts={})
94
94
  @browser = browser
95
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
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
103
  defaults = USERS[@user_name]
104
- defaults.nil? ? options=opts : options=defaults.merge(opts)
104
+ options = defaults.nil? ? opts : defaults.merge(opts)
105
105
  set_options options
106
106
  end
107
107
 
108
108
  def create
109
109
  # First we have to make sure we're logged in with
110
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
111
+ @browser.windows[0].use
112
+ visit SystemAdmin do |page|
113
+ page.close_children
114
+ if @logged_in_user_name=='admin'
115
+ page.person
116
+ else
117
+ s_o.click
118
+ visit Login do |log_in|
119
+ log_in.username.set 'admin'
120
+ log_in.login
121
+ end
122
+ visit(SystemAdmin).person
119
123
  end
120
- visit(SystemAdmin).person
121
124
  end
122
125
  # Now we're certain the create button will be there, so...
123
126
  on(PersonLookup).create
@@ -208,6 +211,7 @@ class UserObject
208
211
  log_in.username.set @logged_in_user_name
209
212
  log_in.login
210
213
  end
214
+ @logged_in_user_name=nil
211
215
  end
212
216
  end
213
217
 
@@ -265,6 +269,8 @@ class UserObject
265
269
  visit SystemAdmin do |page|
266
270
  if username_field.present?
267
271
  UserObject.new(@browser).log_in
272
+ else
273
+ @logged_in_user_name=login_info_div.text[/\w+$/]
268
274
  end
269
275
  page.person
270
276
  end