curation_concerns 1.6.3 → 1.7.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (236) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +4 -0
  3. data/.travis.yml +2 -8
  4. data/README.md +27 -1
  5. data/app/actors/curation_concerns/actors/base_actor.rb +2 -3
  6. data/app/actors/curation_concerns/actors/file_set_actor.rb +1 -1
  7. data/app/actors/curation_concerns/actors/grant_edit_to_depositor_actor.rb +19 -0
  8. data/app/actors/curation_concerns/actors/initialize_workflow_actor.rb +19 -0
  9. data/app/assets/javascripts/curation_concerns/charts.js +47 -0
  10. data/app/assets/javascripts/curation_concerns/curation_concerns.js +2 -0
  11. data/app/assets/javascripts/curation_concerns/workflow_actions_affix.js +11 -0
  12. data/app/assets/stylesheets/curation_concerns/_admin.scss +18 -0
  13. data/app/assets/stylesheets/curation_concerns/_curation_concerns.scss +1 -0
  14. data/app/assets/stylesheets/curation_concerns/_positioning.scss +11 -0
  15. data/app/controllers/concerns/curation_concerns/act_as_admin_controller.rb +25 -0
  16. data/app/controllers/concerns/curation_concerns/admin_controller_behavior.rb +38 -0
  17. data/app/controllers/concerns/curation_concerns/admin_page.rb +18 -0
  18. data/app/controllers/concerns/curation_concerns/collections_controller_behavior.rb +3 -2
  19. data/app/controllers/concerns/curation_concerns/curation_concern_controller.rb +158 -159
  20. data/app/controllers/concerns/curation_concerns/embargoes_controller_behavior.rb +4 -6
  21. data/app/controllers/concerns/curation_concerns/file_sets_controller_behavior.rb +2 -1
  22. data/app/controllers/concerns/curation_concerns/leases_controller_behavior.rb +4 -6
  23. data/app/controllers/concerns/curation_concerns/single_use_links_viewer_controller_behavior.rb +2 -1
  24. data/app/controllers/curation_concerns/admin/workflow_roles_controller.rb +36 -0
  25. data/app/controllers/curation_concerns/workflow_actions_controller.rb +25 -0
  26. data/app/conversions/power_converters/polymorphic_type.rb +7 -0
  27. data/app/conversions/power_converters/sipity_action.rb +9 -0
  28. data/app/conversions/power_converters/sipity_action_name.rb +8 -0
  29. data/app/conversions/power_converters/sipity_agent.rb +6 -0
  30. data/app/conversions/power_converters/sipity_entity.rb +12 -0
  31. data/app/conversions/power_converters/sipity_role.rb +8 -0
  32. data/app/conversions/power_converters/sipity_workflow_id.rb +16 -0
  33. data/app/conversions/power_converters/sipity_workflow_state.rb +10 -0
  34. data/app/conversions/power_converters.rb +6 -0
  35. data/app/forms/curation_concerns/forms/workflow_action_form.rb +62 -0
  36. data/app/forms/curation_concerns/forms/workflow_responsibility_form.rb +42 -0
  37. data/app/helpers/curation_concerns/charts_helper.rb +23 -0
  38. data/app/helpers/curation_concerns/main_app_helpers.rb +1 -0
  39. data/app/helpers/curation_concerns/url_helper.rb +2 -5
  40. data/app/indexers/curation_concerns/indexes_workflow.rb +44 -0
  41. data/app/indexers/curation_concerns/work_indexer.rb +1 -2
  42. data/app/jobs/import_export_job.rb +46 -0
  43. data/app/models/concerns/curation_concerns/ability.rb +2 -0
  44. data/app/models/concerns/curation_concerns/permissions/writable.rb +7 -8
  45. data/app/models/concerns/curation_concerns/publishable.rb +6 -0
  46. data/app/models/concerns/curation_concerns/solr_document_behavior.rb +8 -0
  47. data/app/models/concerns/curation_concerns/user.rb +5 -0
  48. data/app/models/curation_concerns/group.rb +23 -0
  49. data/app/models/curation_concerns/workflow_action_info.rb +13 -0
  50. data/app/models/sipity/agent.rb +21 -0
  51. data/app/models/sipity/comment.rb +13 -0
  52. data/app/models/sipity/entity.rb +32 -0
  53. data/app/models/sipity/entity_specific_responsibility.rb +21 -0
  54. data/app/models/sipity/method.rb +5 -0
  55. data/app/models/sipity/notifiable_context.rb +26 -0
  56. data/app/models/sipity/notification.rb +28 -0
  57. data/app/models/sipity/notification_recipient.rb +17 -0
  58. data/app/models/sipity/role.rb +43 -0
  59. data/app/models/sipity/workflow.rb +19 -0
  60. data/app/models/sipity/workflow_action.rb +25 -0
  61. data/app/models/sipity/workflow_responsibility.rb +23 -0
  62. data/app/models/sipity/workflow_role.rb +13 -0
  63. data/app/models/sipity/workflow_state.rb +26 -0
  64. data/app/models/sipity/workflow_state_action.rb +9 -0
  65. data/app/models/sipity/workflow_state_action_permission.rb +8 -0
  66. data/app/models/vocab/fedora_resource_status.rb +4 -1
  67. data/app/presenters/curation_concerns/admin/workflow_role_presenter.rb +40 -0
  68. data/app/presenters/curation_concerns/work_show_presenter.rb +4 -0
  69. data/app/presenters/curation_concerns/workflow_presenter.rb +43 -0
  70. data/app/renderers/curation_concerns/renderers/rights_attribute_renderer.rb +1 -1
  71. data/app/search_builders/curation_concerns/search_filters.rb +0 -1
  72. data/app/services/curation_concerns/actors/actor_factory.rb +3 -1
  73. data/app/services/curation_concerns/admin_set_service.rb +13 -4
  74. data/app/services/curation_concerns/work_form_service.rb +11 -0
  75. data/app/services/curation_concerns/workflow/action_taken_service.rb +57 -0
  76. data/app/services/curation_concerns/workflow/activate_object.rb +9 -0
  77. data/app/services/curation_concerns/workflow/deactivate_object.rb +11 -0
  78. data/app/services/curation_concerns/workflow/default_workflow_strategy.rb +13 -0
  79. data/app/services/curation_concerns/workflow/method_generator.rb +55 -0
  80. data/app/services/curation_concerns/workflow/notification_configuration_parameter.rb +42 -0
  81. data/app/services/curation_concerns/workflow/notification_generator.rb +64 -0
  82. data/app/services/curation_concerns/workflow/notification_service.rb +66 -0
  83. data/app/services/curation_concerns/workflow/permission_generator.rb +95 -0
  84. data/app/services/curation_concerns/workflow/permission_query.rb +432 -0
  85. data/app/services/curation_concerns/workflow/remove_depositor_permissions.rb +11 -0
  86. data/app/services/curation_concerns/workflow/sipity_actions_generator.rb +49 -0
  87. data/app/services/curation_concerns/workflow/state_machine_generator.rb +102 -0
  88. data/app/services/curation_concerns/workflow/status_list_service.rb +52 -0
  89. data/app/services/curation_concerns/workflow/workflow_action_service.rb +56 -0
  90. data/app/services/curation_concerns/workflow/workflow_by_model_name_strategy.rb +14 -0
  91. data/app/services/curation_concerns/workflow/workflow_factory.rb +64 -0
  92. data/app/services/curation_concerns/workflow/workflow_importer.rb +103 -0
  93. data/app/services/curation_concerns/workflow/workflow_permissions_generator.rb +49 -0
  94. data/app/services/curation_concerns/workflow/workflow_schema.rb +56 -0
  95. data/app/services/rights_service.rb +1 -1
  96. data/app/services/sipity.rb +2 -0
  97. data/app/sources/curation_concerns/resource_statistics_source.rb +101 -0
  98. data/app/values/curation_concerns/chart_data.rb +61 -0
  99. data/app/views/curation_concerns/admin/_admin_menu.html.erb +5 -0
  100. data/app/views/curation_concerns/admin/_resource_stats.html.erb +43 -0
  101. data/app/views/curation_concerns/admin/_sidebar.html.erb +3 -0
  102. data/app/views/curation_concerns/admin/_total_embargo_visibility.html.erb +21 -0
  103. data/app/views/curation_concerns/admin/_total_objects.html.erb +1 -0
  104. data/app/views/curation_concerns/admin/_total_objects_charts.html.erb +12 -0
  105. data/app/views/curation_concerns/admin/index.html.erb +11 -0
  106. data/app/views/curation_concerns/admin/widgets/_pie.html.erb +1 -0
  107. data/app/views/curation_concerns/admin/workflow.html.erb +31 -0
  108. data/app/views/curation_concerns/admin/workflow_roles/index.html.erb +45 -0
  109. data/app/views/curation_concerns/base/_form_rights.html.erb +1 -1
  110. data/app/views/curation_concerns/base/_workflow_actions.html.erb +39 -0
  111. data/app/views/curation_concerns/base/show.html.erb +2 -0
  112. data/app/views/curation_concerns/file_sets/media_display/_office_document.html.erb +0 -1
  113. data/app/views/layouts/_head_tag_content.html.erb +13 -0
  114. data/app/views/layouts/admin.html.erb +10 -0
  115. data/app/views/shared/_my_actions.html.erb +4 -1
  116. data/config/initializers/precompile_assets.rb +1 -0
  117. data/config/locales/curation_concerns.en.yml +97 -56
  118. data/config/routes.rb +7 -0
  119. data/curation_concerns.gemspec +9 -3
  120. data/db/migrate/20160919151348_create_sipity.rb +163 -0
  121. data/db/migrate/20161012182404_create_sipity_workflow_methods.rb +10 -0
  122. data/lib/curation_concerns/configuration.rb +68 -0
  123. data/lib/curation_concerns/engine.rb +9 -1
  124. data/lib/curation_concerns/rails/routes.rb +1 -0
  125. data/lib/curation_concerns/version.rb +1 -1
  126. data/lib/curation_concerns.rb +1 -1
  127. data/lib/generators/curation_concerns/admin_dashboard_generator.rb +15 -0
  128. data/lib/generators/curation_concerns/install_generator.rb +7 -0
  129. data/lib/generators/curation_concerns/sample_data_generator.rb +12 -0
  130. data/lib/generators/curation_concerns/templates/app/controllers/curation_concerns/admin_controller.rb +61 -0
  131. data/lib/generators/curation_concerns/templates/catalog_controller.rb +1 -3
  132. data/lib/generators/curation_concerns/templates/config/curation_concerns.rb +39 -0
  133. data/lib/generators/curation_concerns/templates/db/seeds.rb +94 -0
  134. data/lib/generators/curation_concerns/templates/spec/models/collection_spec.rb +1 -1
  135. data/lib/generators/curation_concerns/templates/spec/models/file_set_spec.rb +1 -1
  136. data/lib/generators/curation_concerns/templates/workflow.json.erb +19 -0
  137. data/lib/generators/curation_concerns/work/USAGE +1 -0
  138. data/lib/generators/curation_concerns/work/templates/actor_spec.rb.erb +1 -1
  139. data/lib/generators/curation_concerns/work/templates/controller_spec.rb.erb +1 -1
  140. data/lib/generators/curation_concerns/work/templates/feature_spec.rb.erb +1 -1
  141. data/lib/generators/curation_concerns/work/templates/form_spec.rb.erb +1 -1
  142. data/lib/generators/curation_concerns/work/templates/model_spec.rb.erb +1 -1
  143. data/spec/abilities/admin_ability_spec.rb +15 -0
  144. data/spec/actors/curation_concerns/file_set_actor_spec.rb +24 -0
  145. data/spec/actors/curation_concerns/grant_edit_to_depositor_actor_spec.rb +32 -0
  146. data/spec/actors/curation_concerns/initialize_workflow_actor_spec.rb +33 -0
  147. data/spec/actors/curation_concerns/interpret_visibility_actor_spec.rb +1 -0
  148. data/spec/actors/curation_concerns/work_actor_spec.rb +10 -5
  149. data/spec/controllers/curation_concerns/acts_as_admin_controller_spec.rb +22 -0
  150. data/spec/controllers/curation_concerns/admin/workflow_roles_controller_spec.rb +26 -0
  151. data/spec/controllers/curation_concerns/admin_controller_spec.rb +64 -0
  152. data/spec/controllers/curation_concerns/generic_works_controller_json_spec.rb +11 -3
  153. data/spec/controllers/curation_concerns/generic_works_controller_spec.rb +4 -4
  154. data/spec/controllers/curation_concerns/workflow_actions_controller_spec.rb +36 -0
  155. data/spec/conversions/power_converters/polymorphic_type_spec.rb +22 -0
  156. data/spec/conversions/power_converters/sipity_action_name_spec.rb +32 -0
  157. data/spec/conversions/power_converters/sipity_action_spec.rb +43 -0
  158. data/spec/conversions/power_converters/sipity_agent_spec.rb +20 -0
  159. data/spec/conversions/power_converters/sipity_entity_spec.rb +46 -0
  160. data/spec/conversions/power_converters/sipity_role_spec.rb +33 -0
  161. data/spec/conversions/power_converters/sipity_workflow_id_spec.rb +28 -0
  162. data/spec/conversions/power_converters/sipity_workflow_state_spec.rb +22 -0
  163. data/spec/factories/generic_works.rb +19 -6
  164. data/spec/factories/sipity_entities.rb +7 -0
  165. data/spec/factories/workflow_actions.rb +6 -0
  166. data/spec/factories/workflow_states.rb +6 -0
  167. data/spec/factories/workflows.rb +5 -0
  168. data/spec/features/admin_spec.rb +14 -0
  169. data/spec/features/create_child_work_spec.rb +1 -1
  170. data/spec/features/create_work_spec.rb +1 -1
  171. data/spec/features/embargo_spec.rb +1 -1
  172. data/spec/features/lease_spec.rb +1 -1
  173. data/spec/features/work_generator_spec.rb +2 -2
  174. data/spec/features/workflow_roles_spec.rb +48 -0
  175. data/spec/forms/curation_concerns/forms/workflow_action_form_spec.rb +111 -0
  176. data/spec/forms/curation_concerns/forms/workflow_responsibility_form_spec.rb +33 -0
  177. data/spec/helpers/curation_concerns/charts_helper_spec.rb +62 -0
  178. data/spec/helpers/url_helper_spec.rb +11 -11
  179. data/spec/indexers/work_indexer_spec.rb +13 -1
  180. data/spec/javascripts/charts_spec.coffee +10 -0
  181. data/spec/javascripts/fixtures/chart_example.html +1 -0
  182. data/spec/jobs/import_export_job_spec.rb +28 -0
  183. data/spec/models/curation_concerns/group_spec.rb +15 -0
  184. data/spec/models/file_set_spec.rb +6 -2
  185. data/spec/models/generic_work_spec.rb +12 -0
  186. data/spec/models/sipity/agent_spec.rb +9 -0
  187. data/spec/models/sipity/comment_spec.rb +16 -0
  188. data/spec/models/sipity/entity_spec.rb +27 -0
  189. data/spec/models/sipity/entity_specific_responsibility_spec.rb +8 -0
  190. data/spec/models/sipity/notifiable_context_spec.rb +8 -0
  191. data/spec/models/sipity/notification_recipient_spec.rb +10 -0
  192. data/spec/models/sipity/notification_spec.rb +15 -0
  193. data/spec/models/sipity/role_spec.rb +30 -0
  194. data/spec/models/sipity/workflow_action_spec.rb +10 -0
  195. data/spec/models/sipity/workflow_responsibility_spec.rb +7 -0
  196. data/spec/models/sipity/workflow_role_spec.rb +7 -0
  197. data/spec/models/sipity/workflow_spec.rb +15 -0
  198. data/spec/models/sipity/workflow_state_action_permission_spec.rb +7 -0
  199. data/spec/models/sipity/workflow_state_action_spec.rb +7 -0
  200. data/spec/models/sipity/workflow_state_spec.rb +7 -0
  201. data/spec/models/user_spec.rb +12 -1
  202. data/spec/presenters/curation_concerns/work_show_presenter_spec.rb +12 -1
  203. data/spec/presenters/curation_concerns/workflow_presenter_spec.rb +39 -0
  204. data/spec/routing/route_spec.rb +13 -0
  205. data/spec/services/curation_concerns/admin_set_service_spec.rb +13 -0
  206. data/spec/services/curation_concerns/qa_select_service_spec.rb +75 -0
  207. data/spec/services/curation_concerns/workflow/action_taken_service_spec.rb +76 -0
  208. data/spec/services/curation_concerns/workflow/activate_object_spec.rb +20 -0
  209. data/spec/services/curation_concerns/workflow/deactivate_object_spec.rb +20 -0
  210. data/spec/services/curation_concerns/workflow/method_generator_spec.rb +43 -0
  211. data/spec/services/curation_concerns/workflow/notification_configuration_parameter_spec.rb +25 -0
  212. data/spec/services/curation_concerns/workflow/notification_generator_spec.rb +27 -0
  213. data/spec/services/curation_concerns/workflow/notification_service_spec.rb +81 -0
  214. data/spec/services/curation_concerns/workflow/permission_generator_spec.rb +52 -0
  215. data/spec/services/curation_concerns/workflow/permission_query_spec.rb +179 -0
  216. data/spec/services/curation_concerns/workflow/remove_depositor_permissions_spec.rb +21 -0
  217. data/spec/services/curation_concerns/workflow/sipity_actions_generator_spec.rb +30 -0
  218. data/spec/services/curation_concerns/workflow/state_machine_generator_spec.rb +46 -0
  219. data/spec/services/curation_concerns/workflow/status_list_service_spec.rb +46 -0
  220. data/spec/services/curation_concerns/workflow/workflow_importer_spec.rb +50 -0
  221. data/spec/services/curation_concerns/workflow/workflow_permissions_generator_spec.rb +37 -0
  222. data/spec/services/curation_concerns/workflow/workflow_schema_spec.rb +85 -0
  223. data/spec/sources/curation_concerns/resource_statistics_source_spec.rb +137 -0
  224. data/spec/spec_helper.rb +8 -1
  225. data/spec/test_app_templates/lib/generators/test_app_generator.rb +11 -0
  226. data/spec/views/curation_concerns/admin/_admin_menu.html.erb_spec.rb +23 -0
  227. data/spec/views/curation_concerns/admin/_resource_stats.html.erb_spec.rb +33 -0
  228. data/spec/views/curation_concerns/admin/_total_objects_charts.html.erb_spec.rb +28 -0
  229. data/spec/views/curation_concerns/admin/index.html.erb_spec.rb +26 -0
  230. data/spec/views/curation_concerns/admin/widgets/_pie.html.erb_spec.rb +17 -0
  231. data/spec/views/curation_concerns/base/file_manager.html.erb_spec.rb +1 -1
  232. data/spec/views/curation_concerns/base/show.html.erb_spec.rb +33 -0
  233. data/spec/views/curation_concerns/permissions/confirm.html.erb_spec.rb +1 -1
  234. data/spec/views/shared/_my_actions.html.erb_spec.rb +1 -0
  235. data/tasks/workflow.rake +8 -0
  236. metadata +335 -21
@@ -0,0 +1,179 @@
1
+ require 'spec_helper'
2
+
3
+ module CurationConcerns
4
+ module Workflow
5
+ RSpec.describe PermissionQuery, slow_test: true, no_clean: true do
6
+ let(:reviewing_user) { create(:user) }
7
+ let(:completing_user) { create(:user) }
8
+ let(:workflow_config) do
9
+ {
10
+ workflows: [{
11
+ name: 'testing',
12
+ actions: [{
13
+ name: "forward", from_states: [{ names: ["initial"], roles: ["reviewing"] }], transition_to: 'forwarded'
14
+ }, {
15
+ name: "complete", from_states: [{ names: ["forwarded"], roles: ["completing"] }], transition_to: 'completed'
16
+ }]
17
+ }]
18
+ }
19
+ end
20
+ before { CurationConcerns::Workflow::WorkflowImporter.new(data: workflow_config).call }
21
+ let(:sipity_entity) do
22
+ Sipity::Entity.create!(proxy_for_global_id: 'gid://internal/Mock/1',
23
+ workflow: sipity_workflow,
24
+ workflow_state: PowerConverter.convert_to_sipity_workflow_state('initial', scope: sipity_workflow)
25
+ )
26
+ end
27
+ let(:sipity_workflow) { Sipity::Workflow.first }
28
+
29
+ def expect_actions_for(user:, entity:, actions:)
30
+ actions = Array.wrap(actions).map { |action| PowerConverter.convert_to_sipity_action(action, scope: entity.workflow) }
31
+ expect(described_class.scope_permitted_workflow_actions_available_for_current_state(user: user, entity: entity)).to eq(actions)
32
+ end
33
+
34
+ def expect_agents_for(agents:, entity:, role:)
35
+ agents = Array.wrap(agents).map { |agent| PowerConverter.convert_to_sipity_agent(agent) }
36
+ expect(described_class.scope_agents_associated_with_entity_and_role(role: role, entity: entity)).to eq(agents)
37
+ end
38
+
39
+ def expect_roles_for(entity:, roles:)
40
+ roles = Array.wrap(roles).map { |role| PowerConverter.convert_to_sipity_role(role) }
41
+ expect(described_class.scope_roles_associated_with_the_given_entity(entity: entity)).to eq(roles)
42
+ end
43
+
44
+ def expect_users_for(entity:, roles:, users:)
45
+ expect(described_class.scope_users_for_entity_and_roles(entity: entity, roles: roles)).to eq(Array.wrap(users))
46
+ end
47
+
48
+ def expect_to_be_authorized(user:, entity:, action:, message: 'should be authorized')
49
+ expect(described_class.authorized_for_processing?(user: user, entity: entity, action: action)).to be_truthy, message
50
+ end
51
+
52
+ def expect_to_not_be_authorized(user:, entity:, action:, message: 'should not be authorized')
53
+ expect(described_class.authorized_for_processing?(user: user, entity: entity, action: action)).to be_falsey, message
54
+ end
55
+
56
+ def expect_entities_for(user:, entities:)
57
+ entities = Array.wrap(entities).map { |entity| PowerConverter.convert(entity, to: :sipity_entity) }
58
+ expect(described_class.scope_entities_for_the_user(user: user)).to eq(entities)
59
+ end
60
+
61
+ describe 'permissions assigned at the workflow level' do
62
+ let(:reviewing_group_member) { create(:user) }
63
+ let(:reviewing_group) { Group.new('librarians') }
64
+ before do
65
+ allow(reviewing_group_member).to receive(:groups).and_return(['librarians'])
66
+ PermissionGenerator.call(roles: 'reviewing', workflow: sipity_workflow, agents: reviewing_user)
67
+ PermissionGenerator.call(roles: 'reviewing', workflow: sipity_workflow, agents: reviewing_group)
68
+ PermissionGenerator.call(roles: 'completing', workflow: sipity_workflow, agents: completing_user)
69
+ end
70
+
71
+ it 'will fullfil the battery of tests (of which they are nested because setup is expensive)' do
72
+ expect_agents_for(entity: sipity_entity, role: 'reviewing', agents: [reviewing_user, reviewing_group])
73
+ expect_agents_for(entity: sipity_entity, role: 'completing', agents: [completing_user])
74
+
75
+ expect_actions_for(user: reviewing_user, entity: sipity_entity, actions: ['forward'])
76
+ expect_actions_for(user: reviewing_group_member, entity: sipity_entity, actions: ['forward'])
77
+ expect_actions_for(user: completing_user, entity: sipity_entity, actions: [])
78
+
79
+ expect_users_for(users: reviewing_user, entity: sipity_entity, roles: 'reviewing')
80
+ expect_users_for(users: completing_user, entity: sipity_entity, roles: 'completing')
81
+
82
+ expect_entities_for(user: reviewing_user, entities: [sipity_entity])
83
+ expect_entities_for(user: completing_user, entities: [])
84
+
85
+ expect_roles_for(entity: sipity_entity, roles: ['reviewing', 'completing'])
86
+
87
+ expect_to_be_authorized(user: reviewing_user, entity: sipity_entity, action: 'forward')
88
+ expect_to_not_be_authorized(user: reviewing_user, entity: sipity_entity, action: 'complete')
89
+ expect_to_not_be_authorized(user: completing_user, entity: sipity_entity, action: 'forward')
90
+ expect_to_not_be_authorized user: completing_user, entity: sipity_entity, action: 'complete',
91
+ message: 'should be unauthorized because the action is not available in this state'
92
+
93
+ # Then transition to Sipity::Entity
94
+ sipity_entity.update_attribute(
95
+ :workflow_state, PowerConverter.convert_to_sipity_workflow_state('forwarded', scope: sipity_workflow)
96
+ )
97
+
98
+ # Now permissions have changed
99
+ expect_actions_for(user: reviewing_user, entity: sipity_entity, actions: [])
100
+ expect_actions_for(user: completing_user, entity: sipity_entity, actions: ['complete'])
101
+
102
+ expect_to_not_be_authorized user: reviewing_user, entity: sipity_entity, action: 'forward',
103
+ message: 'should be unauthorized because the action is not available in this state'
104
+ expect_to_not_be_authorized(user: reviewing_user, entity: sipity_entity, action: 'complete')
105
+ expect_to_not_be_authorized(user: completing_user, entity: sipity_entity, action: 'forward')
106
+ expect_to_be_authorized(user: completing_user, entity: sipity_entity, action: 'complete')
107
+
108
+ expect_entities_for(user: reviewing_user, entities: [])
109
+ expect_entities_for(user: completing_user, entities: [sipity_entity])
110
+ end
111
+ end
112
+
113
+ # NOTE: I am stacking up expectations because these tests are non-trivial to build (lots of database interactions)
114
+ describe 'permissions assigned at the entity level' do
115
+ it 'will fullfil the battery of tests (of which they are nested because setup is expensive)' do
116
+ PermissionGenerator.call(roles: 'reviewing', entity: sipity_entity, workflow: sipity_workflow, agents: reviewing_user)
117
+ PermissionGenerator.call(roles: 'completing', entity: sipity_entity, workflow: sipity_workflow, agents: completing_user)
118
+
119
+ expect_agents_for(entity: sipity_entity, role: 'reviewing', agents: [reviewing_user])
120
+ expect_agents_for(entity: sipity_entity, role: 'completing', agents: [completing_user])
121
+
122
+ expect_actions_for(user: reviewing_user, entity: sipity_entity, actions: ['forward'])
123
+ expect_actions_for(user: completing_user, entity: sipity_entity, actions: [])
124
+
125
+ expect_users_for(users: reviewing_user, entity: sipity_entity, roles: 'reviewing')
126
+ expect_users_for(users: completing_user, entity: sipity_entity, roles: 'completing')
127
+
128
+ expect_entities_for(user: reviewing_user, entities: [sipity_entity])
129
+ expect_entities_for(user: completing_user, entities: [])
130
+
131
+ expect_roles_for(entity: sipity_entity, roles: ['reviewing', 'completing'])
132
+
133
+ expect_to_be_authorized(user: reviewing_user, entity: sipity_entity, action: 'forward')
134
+ expect_to_not_be_authorized(user: reviewing_user, entity: sipity_entity, action: 'complete')
135
+ expect_to_not_be_authorized(user: completing_user, entity: sipity_entity, action: 'forward')
136
+ expect_to_not_be_authorized user: completing_user, entity: sipity_entity, action: 'complete',
137
+ message: 'should be unauthorized because the action is not available in this state'
138
+
139
+ # Then transition to Sipity::Entity
140
+ sipity_entity.update_attribute(
141
+ :workflow_state, PowerConverter.convert_to_sipity_workflow_state('forwarded', scope: sipity_workflow)
142
+ )
143
+
144
+ # Now permissions have changed
145
+ expect_actions_for(user: reviewing_user, entity: sipity_entity, actions: [])
146
+ expect_actions_for(user: completing_user, entity: sipity_entity, actions: ['complete'])
147
+
148
+ expect_to_not_be_authorized user: reviewing_user, entity: sipity_entity, action: 'forward',
149
+ message: 'should be unauthorized because the action is not available in this state'
150
+ expect_to_not_be_authorized(user: reviewing_user, entity: sipity_entity, action: 'complete')
151
+ expect_to_not_be_authorized(user: completing_user, entity: sipity_entity, action: 'forward')
152
+ expect_to_be_authorized(user: completing_user, entity: sipity_entity, action: 'complete')
153
+
154
+ expect_entities_for(user: reviewing_user, entities: [])
155
+ expect_entities_for(user: completing_user, entities: [sipity_entity])
156
+ end
157
+ end
158
+
159
+ describe '.scope_processing_agents_for', no_clean: true do
160
+ context 'when user is not persisted' do
161
+ subject { described_class.scope_processing_agents_for(user: ::User.new) }
162
+ it { is_expected.to eq([]) }
163
+ end
164
+ context 'when user is non-trivial' do
165
+ subject { described_class.scope_processing_agents_for(user: nil) }
166
+ it { is_expected.to eq([]) }
167
+ end
168
+ context 'when user is persisted' do
169
+ let(:user) { create(:user) }
170
+ subject { described_class.scope_processing_agents_for(user: user) }
171
+ it 'will equal [kind_of(Sipity::Agent)]' do
172
+ is_expected.to eq([PowerConverter.convert_to_sipity_agent(user),
173
+ PowerConverter.convert_to_sipity_agent(Group.new('registered'))])
174
+ end
175
+ end
176
+ end
177
+ end
178
+ end
179
+ end
@@ -0,0 +1,21 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe CurationConcerns::Workflow::RemoveDepositorPermissions do
4
+ let(:work) { create(:work) }
5
+ let(:entity) { instance_double(Sipity::Entity, id: 9999, proxy_for: work) }
6
+ let(:user) { User.new }
7
+
8
+ describe ".call" do
9
+ subject do
10
+ described_class.call(entity: entity,
11
+ comment: "A pleasant read",
12
+ user: user)
13
+ end
14
+
15
+ it "strips edit access " do
16
+ subject
17
+ expect(work).to be_valid
18
+ expect(work.edit_users).to eq []
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,30 @@
1
+ require 'spec_helper'
2
+
3
+ module CurationConcerns
4
+ module Workflow
5
+ RSpec.describe SipityActionsGenerator do
6
+ let(:workflow) { Sipity::Workflow.new(name: 'Hello') }
7
+ let(:actions_configuration) do
8
+ [
9
+ {
10
+ name: "start_a_submission", transition_to: "new", emails: [
11
+ { name: "confirmation_of_ulra_submission_started", to: "creating_user" }
12
+ ]
13
+ }, { name: ["start", "potpie"] }
14
+ ]
15
+ end
16
+
17
+ it 'exposes .call as a convenience method' do
18
+ expect_any_instance_of(described_class).to receive(:call)
19
+ described_class.call(workflow: workflow, actions_configuration: actions_configuration)
20
+ end
21
+
22
+ subject { described_class.new(workflow: workflow, actions_configuration: actions_configuration) }
23
+
24
+ it 'parses the actions_configuration and calls the underlying DataGenerators::StateMachineGenerator' do
25
+ allow_any_instance_of(StateMachineGenerator).to receive(:call)
26
+ subject.call
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,46 @@
1
+ require 'spec_helper'
2
+
3
+ module CurationConcerns
4
+ RSpec.describe Workflow::StateMachineGenerator, :no_clean do
5
+ let(:workflow) { Sipity::Workflow.create!(name: 'hello') }
6
+ let(:action_name) { 'do_it' }
7
+ before do
8
+ class ConfirmSubmission
9
+ end
10
+ end
11
+ after { CurationConcerns.send(:remove_const, :ConfirmSubmission) }
12
+ it 'exposes .generate_from_schema as a convenience method' do
13
+ expect_any_instance_of(described_class).to receive(:call)
14
+ described_class.generate_from_schema(workflow: workflow, name: action_name, config: {})
15
+ end
16
+
17
+ let(:config) do
18
+ {
19
+ from_states: [
20
+ { names: ["pending_student_completion"], roles: ['creating_user'] },
21
+ { names: ["pending_advisor_completion"], roles: ['advising'] }
22
+ ],
23
+ transition_to: :under_review,
24
+ notifications: [
25
+ { notification_type: 'email', name: 'CurationConcerns::ConfirmSubmission', to: 'creating_user', cc: 'advising' }
26
+ ]
27
+ }
28
+ end
29
+
30
+ context '#call' do
31
+ subject { described_class.new(workflow: workflow, action_name: action_name, config: config) }
32
+ it 'will generate the various data entries (but only once)' do
33
+ expect do
34
+ subject.call
35
+ end.to change { Sipity::Notification.count }
36
+ .and change { Sipity::WorkflowAction.count }
37
+
38
+ # It can be called repeatedly without updating things
39
+ [:update_attribute, :update_attributes, :update_attributes!, :save, :save!, :update, :update!].each do |method_names|
40
+ expect_any_instance_of(ActiveRecord::Base).to_not receive(method_names)
41
+ end
42
+ subject.call
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,46 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe CurationConcerns::Workflow::StatusListService do
4
+ describe "#each" do
5
+ let(:user) { create(:user) }
6
+ let(:service) { described_class.new(user) }
7
+ let(:document) { { id: '33333',
8
+ has_model_ssim: ['GenericWork'],
9
+ actionable_workflow_roles_ssim: ["generic_work-approving", "generic_work-rejecting"],
10
+ workflow_state_name_ssim: ["initial"],
11
+ title_tesim: ['Hey dood!'] } }
12
+ let(:ability) { { id: '44444',
13
+ has_model_ssim: ['GenericWork'],
14
+ title_tesim: ['bad result'] } }
15
+ let(:workflow_role) { instance_double(Sipity::Role, name: 'approving') }
16
+ let(:workflow_roles) { [instance_double(Sipity::WorkflowRole, role: workflow_role)] }
17
+ before do
18
+ create(:sipity_entity)
19
+ ActiveFedora::SolrService.add([document, ability], commit: true)
20
+ end
21
+
22
+ let(:results) { service.each.to_a }
23
+
24
+ context "when user has roles" do
25
+ before do
26
+ allow(CurationConcerns::Workflow::PermissionQuery).to receive(:scope_processing_workflow_roles_for_user_and_workflow).and_return(workflow_roles)
27
+ end
28
+
29
+ it "returns status rows" do
30
+ expect(results.size).to eq 1
31
+ expect(results.first).to be_kind_of(SolrDocument)
32
+ expect(results.first.to_s).to eq 'Hey dood!'
33
+ expect(results.first.workflow_state).to eq 'initial'
34
+ end
35
+ end
36
+
37
+ context "when user doesn't have roles" do
38
+ before do
39
+ allow(CurationConcerns::Workflow::PermissionQuery).to receive(:scope_processing_workflow_roles_for_user_and_workflow).and_return([])
40
+ end
41
+ it "returns nothing" do
42
+ expect(results).to be_empty
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,50 @@
1
+ require "spec_helper"
2
+
3
+ RSpec.describe CurationConcerns::Workflow::WorkflowImporter do
4
+ let(:path) { double(read: json) }
5
+ let(:json) do
6
+ doc = <<-HERE
7
+ {
8
+ "workflows": [
9
+ {
10
+ "name": "ulra_submission",
11
+ "label": "This is the label",
12
+ "description": "This description could get really long",
13
+ "actions": [{
14
+ "name": "approve",
15
+ "transition_to": "reviewed",
16
+ "from_states": [{ "names": ["under_review"], "roles": ["ulra_reviewing"] }]
17
+ }]
18
+ }
19
+ ]
20
+ }
21
+ HERE
22
+ doc.strip
23
+ end
24
+ let(:validator) { double(call: true) }
25
+
26
+ subject { described_class.new(data: {}, validator: validator) }
27
+
28
+ its(:default_validator) { is_expected.to respond_to(:call) }
29
+ its(:default_schema) { is_expected.to respond_to(:call) }
30
+
31
+ it 'validates the data against the schema' do
32
+ subject
33
+ expect(validator).to have_received(:call).with(data: subject.send(:data), schema: subject.send(:schema))
34
+ end
35
+
36
+ context 'data generation' do
37
+ let(:path) { Rails.root.join('config/workflows/default_workflow.json').to_s }
38
+ it 'creates the requisite data from the configuration' do
39
+ expect(CurationConcerns::Workflow::WorkflowPermissionsGenerator).to receive(:call).and_call_original
40
+ expect(CurationConcerns::Workflow::SipityActionsGenerator).to receive(:call).and_call_original
41
+ result = nil
42
+ expect do
43
+ result = described_class.generate_from_json_file(path: path)
44
+ end.to change { Sipity::Workflow.count }.by(1)
45
+ expect(result).to match_array(kind_of(Sipity::Workflow))
46
+ expect(result.first.label).to eq "Default workflow"
47
+ expect(result.first.description).to eq "A single submission step, default workflow"
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,37 @@
1
+ require "spec_helper"
2
+
3
+ module CurationConcerns
4
+ module Workflow
5
+ RSpec.describe WorkflowPermissionsGenerator do
6
+ let(:workflow) { Sipity::Workflow.new(name: 'Hello') }
7
+ let(:workflow_permissions_configuration) do
8
+ [
9
+ { role: "work_submitting" },
10
+ { role: "etd_reviewing" }
11
+ ]
12
+ end
13
+ before do
14
+ workflow_permissions_configuration.each do |config|
15
+ Sipity::Role.find_or_create_by!(name: config.fetch(:role))
16
+ end
17
+ end
18
+
19
+ it 'exposes .call as a convenience method' do
20
+ expect_any_instance_of(described_class).to receive(:call)
21
+ described_class.call(workflow: workflow, workflow_permissions_configuration: workflow_permissions_configuration)
22
+ end
23
+
24
+ subject { described_class.new(workflow: workflow, workflow_permissions_configuration: workflow_permissions_configuration) }
25
+ it 'will create groups and assign permissions accordingly' do
26
+ allow_any_instance_of(PermissionGenerator).to receive(:call)
27
+ subject.call
28
+
29
+ # And it won't keep creating things
30
+ [:update_attribute, :update_attributes, :update_attributes!, :save, :save!, :update, :update!].each do |method_names|
31
+ expect_any_instance_of(ActiveRecord::Base).to_not receive(method_names)
32
+ end
33
+ subject.call
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,85 @@
1
+ require 'spec_helper'
2
+
3
+ module CurationConcerns
4
+ module Workflow
5
+ RSpec.describe 'WorkflowSchema', no_clean: true do
6
+ let(:valid_data) do
7
+ {
8
+ workflows: [
9
+ {
10
+ name: "valid",
11
+ actions: [
12
+ {
13
+ name: "finalize_digitization",
14
+ from_states: [{ names: ["pending"], roles: ['finalizing_digitation_review'] }],
15
+ transition_to: "metadata_review"
16
+ }, {
17
+ name: "finalize_metadata",
18
+ from_states: [{ names: ["metadata_review"], roles: ['finalizing_metadata_review'] }],
19
+ transition_to: "final_review",
20
+ notifications: [
21
+ {
22
+ name: notification_name, notification_type: Sipity::Notification::NOTIFICATION_TYPE_EMAIL, to: ['finalizing_metadata_review']
23
+ }
24
+ ]
25
+ }
26
+ ]
27
+ }
28
+ ]
29
+ }
30
+ end
31
+
32
+ let(:notification_name) { 'DoTheThing' }
33
+
34
+ let(:invalid_data) do
35
+ {
36
+ workflows: [
37
+ {
38
+ actions: [
39
+ { name: "finalize_digitization", from_states: [{ names: ["pending"], roles: [] }], transition_to: "metadata_review" }
40
+ ]
41
+ }
42
+ ]
43
+ }
44
+ end
45
+
46
+ before do
47
+ class ::DoTheThing
48
+ end
49
+ end
50
+
51
+ after do
52
+ Object.send(:remove_const, :DoTheThing)
53
+ end
54
+
55
+ it 'validates valid data by returning an empty message' do
56
+ expect(WorkflowSchema.call(valid_data).messages).to be_empty
57
+ end
58
+
59
+ it 'reports invalid data via the returned messages' do
60
+ expect(WorkflowSchema.call(invalid_data).messages).not_to be_empty
61
+ end
62
+
63
+ describe 'notification names' do
64
+ context 'with an uninitialized constant' do
65
+ let(:notification_name) { 'FooBar' }
66
+ it 'is invalid' do
67
+ expect(WorkflowSchema.call(valid_data).messages).not_to be_empty
68
+ end
69
+ end
70
+
71
+ context 'within a namespace' do
72
+ before do
73
+ class DoTheThing
74
+ end
75
+ end
76
+ after { CurationConcerns::Workflow.send(:remove_const, :DoTheThing) }
77
+ let(:notification_name) { 'CurationConcerns::Workflow::DoTheThing' }
78
+ it 'returns an empty message because valid' do
79
+ expect(WorkflowSchema.call(valid_data).messages).to be_empty
80
+ end
81
+ end
82
+ end
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,137 @@
1
+ require 'spec_helper'
2
+
3
+ describe CurationConcerns::ResourceStatisticsSource do
4
+ subject { described_class.new }
5
+ describe "#open_concerns_count" do
6
+ it "returns the number of open concerns" do
7
+ create :private_generic_work
8
+ expect(subject.open_concerns_count).to eq(0)
9
+ end
10
+
11
+ context "when I have concerns" do
12
+ before do
13
+ create :public_generic_work
14
+ end
15
+ it "returns the number of open concerns" do
16
+ expect(subject.open_concerns_count).to eq(1)
17
+ end
18
+ end
19
+ end
20
+
21
+ describe "#authenticated_concerns_count" do
22
+ context "when I have concerns" do
23
+ before do
24
+ create :authenticated_generic_work
25
+ end
26
+ it "returns the number of open concerns" do
27
+ expect(subject.authenticated_concerns_count).to eq(1)
28
+ end
29
+ end
30
+ end
31
+
32
+ describe "#restricted_concerns_count" do
33
+ context "when I have concerns" do
34
+ before do
35
+ create :authenticated_generic_work
36
+ create :generic_work
37
+ create :generic_work, read_groups: ['foo']
38
+ end
39
+ it "returns the number of open concerns" do
40
+ expect(subject.restricted_concerns_count).to eq(2)
41
+ end
42
+ end
43
+ end
44
+
45
+ describe "embargoes" do
46
+ before do
47
+ create :embargoed_work, embargo_date: embargo_date, current_state: current_state, future_state: future_state
48
+ create :public_generic_work
49
+ create :authenticated_generic_work
50
+ create :private_generic_work
51
+ end
52
+
53
+ describe "#active_embargo_now_authenticated_concerns_count" do
54
+ before do
55
+ create :embargoed_work, embargo_date: Date.yesterday.to_s, current_state: current_state, future_state: future_state
56
+ end
57
+ let(:embargo_date) { Date.tomorrow.to_s }
58
+ let(:current_state) { Hydra::AccessControls::AccessRight::VISIBILITY_TEXT_VALUE_AUTHENTICATED }
59
+ let(:future_state) { Hydra::AccessControls::AccessRight::VISIBILITY_TEXT_VALUE_PUBLIC }
60
+ it "returns the number of embargo concerns" do
61
+ expect(subject.active_embargo_now_authenticated_concerns_count).to eq(1)
62
+ end
63
+ end
64
+
65
+ describe "#active_embargo_now_restricted_concerns_count" do
66
+ let(:embargo_date) { Date.tomorrow.to_s }
67
+ let(:current_state) { Hydra::AccessControls::AccessRight::VISIBILITY_TEXT_VALUE_PRIVATE }
68
+ let(:future_state) { Hydra::AccessControls::AccessRight::VISIBILITY_TEXT_VALUE_AUTHENTICATED }
69
+ it "returns the number of embargo concerns" do
70
+ expect(subject.active_embargo_now_restricted_concerns_count).to eq(1)
71
+ end
72
+ end
73
+
74
+ describe "#expired_embargo_now_authenticated_concerns_count" do
75
+ let(:embargo_date) { Date.yesterday.to_s }
76
+ let(:current_state) { Hydra::AccessControls::AccessRight::VISIBILITY_TEXT_VALUE_PRIVATE }
77
+ let(:future_state) { Hydra::AccessControls::AccessRight::VISIBILITY_TEXT_VALUE_AUTHENTICATED }
78
+ it "returns the number of embargo concerns" do
79
+ expect(subject.expired_embargo_now_authenticated_concerns_count).to eq(1)
80
+ end
81
+ end
82
+
83
+ describe "#expired_embargo_now_open_concerns_count" do
84
+ let(:embargo_date) { Date.yesterday.to_s }
85
+ let(:current_state) { Hydra::AccessControls::AccessRight::VISIBILITY_TEXT_VALUE_AUTHENTICATED }
86
+ let(:future_state) { Hydra::AccessControls::AccessRight::VISIBILITY_TEXT_VALUE_PUBLIC }
87
+ it "returns the number of embargo concerns" do
88
+ expect(subject.expired_embargo_now_open_concerns_count).to eq(1)
89
+ end
90
+ end
91
+ end
92
+
93
+ describe "leases" do
94
+ before do
95
+ create :leased_work, lease_date: lease_date, current_state: current_state, future_state: future_state
96
+ create :public_generic_work
97
+ create :authenticated_generic_work
98
+ create :private_generic_work
99
+ end
100
+
101
+ describe "#active_lease_now_authenticated_concerns_count" do
102
+ let(:lease_date) { Date.tomorrow.to_s }
103
+ let(:current_state) { Hydra::AccessControls::AccessRight::VISIBILITY_TEXT_VALUE_AUTHENTICATED }
104
+ let(:future_state) { Hydra::AccessControls::AccessRight::VISIBILITY_TEXT_VALUE_PRIVATE }
105
+ it "returns the number of lease concerns" do
106
+ expect(subject.active_lease_now_authenticated_concerns_count).to eq(1)
107
+ end
108
+ end
109
+
110
+ describe "#active_lease_now_open_concerns_count" do
111
+ let(:lease_date) { Date.tomorrow.to_s }
112
+ let(:current_state) { Hydra::AccessControls::AccessRight::VISIBILITY_TEXT_VALUE_PUBLIC }
113
+ let(:future_state) { Hydra::AccessControls::AccessRight::VISIBILITY_TEXT_VALUE_AUTHENTICATED }
114
+ it "returns the number of lease concerns" do
115
+ expect(subject.active_lease_now_open_concerns_count).to eq(1)
116
+ end
117
+ end
118
+
119
+ describe "#expired_lease_now_authenticated_concerns_count" do
120
+ let(:lease_date) { Date.yesterday.to_s }
121
+ let(:current_state) { Hydra::AccessControls::AccessRight::VISIBILITY_TEXT_VALUE_PUBLIC }
122
+ let(:future_state) { Hydra::AccessControls::AccessRight::VISIBILITY_TEXT_VALUE_AUTHENTICATED }
123
+ it "returns the number of lease concerns" do
124
+ expect(subject.expired_lease_now_authenticated_concerns_count).to eq(1)
125
+ end
126
+ end
127
+
128
+ describe "#expired_lease_now_restricted_concerns_count" do
129
+ let(:lease_date) { Date.yesterday.to_s }
130
+ let(:current_state) { Hydra::AccessControls::AccessRight::VISIBILITY_TEXT_VALUE_AUTHENTICATED }
131
+ let(:future_state) { Hydra::AccessControls::AccessRight::VISIBILITY_TEXT_VALUE_PRIVATE }
132
+ it "returns the number of lease concerns" do
133
+ expect(subject.expired_lease_now_restricted_concerns_count).to eq(1)
134
+ end
135
+ end
136
+ end
137
+ end
data/spec/spec_helper.rb CHANGED
@@ -13,6 +13,7 @@ require 'devise'
13
13
  require 'mida'
14
14
 
15
15
  require 'rspec/matchers'
16
+ require 'shoulda/matchers'
16
17
  require 'equivalent-xml/rspec_matchers'
17
18
  require 'rspec/its'
18
19
  require 'rspec/rails'
@@ -70,9 +71,15 @@ RSpec.configure do |config|
70
71
  unless example.metadata[:type] == :view || example.metadata[:no_clean]
71
72
  ActiveFedora::Cleaner.clean!
72
73
  end
74
+
75
+ # This is a speedup for workflow specs. If we don't have this, it will import the
76
+ # full workflow configuration files from config/workflows/*
77
+ FactoryGirl.create(:workflow_action) if example.metadata[:workflow]
73
78
  end
74
79
 
75
80
  config.include FactoryGirl::Syntax::Methods
81
+ config.include Shoulda::Matchers::Independent
82
+
76
83
  if defined? Devise::Test::ControllerHelpers
77
84
  config.include Devise::Test::ControllerHelpers, type: :controller
78
85
  config.include Devise::Test::ControllerHelpers, type: :view
@@ -82,6 +89,7 @@ RSpec.configure do |config|
82
89
  end
83
90
 
84
91
  config.include TestViewHelpers, type: :view
92
+ config.include Capybara::DSL, type: :view
85
93
 
86
94
  config.include Warden::Test::Helpers, type: :feature
87
95
  config.after(:each, type: :feature) { Warden.test_reset! }
@@ -98,7 +106,6 @@ RSpec.configure do |config|
98
106
  config.include ::Rails.application.routes.url_helpers
99
107
 
100
108
  config.include Rails.application.routes.url_helpers, type: :routing
101
- config.include Capybara::DSL
102
109
  config.include InputSupport, type: :input
103
110
  config.include Capybara::RSpecMatchers, type: :input
104
111
  config.infer_spec_type_from_file_location!