You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

workflows_controller_test.rb 19KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474
  1. # frozen_string_literal: true
  2. # Redmine - project management software
  3. # Copyright (C) 2006- Jean-Philippe Lang
  4. #
  5. # This program is free software; you can redistribute it and/or
  6. # modify it under the terms of the GNU General Public License
  7. # as published by the Free Software Foundation; either version 2
  8. # of the License, or (at your option) any later version.
  9. #
  10. # This program is distributed in the hope that it will be useful,
  11. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. # GNU General Public License for more details.
  14. #
  15. # You should have received a copy of the GNU General Public License
  16. # along with this program; if not, write to the Free Software
  17. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  18. require_relative '../test_helper'
  19. class WorkflowsControllerTest < Redmine::ControllerTest
  20. fixtures :roles, :trackers, :workflows, :users, :issue_statuses, :custom_fields
  21. def setup
  22. User.current = nil
  23. @request.session[:user_id] = 1 # admin
  24. end
  25. def test_index
  26. get :index
  27. assert_response :success
  28. count = WorkflowTransition.where(:role_id => 1, :tracker_id => 2).count
  29. assert_select 'a[href=?]', '/workflows/edit?role_id=1&tracker_id=2', :content => count.to_s
  30. end
  31. def test_get_edit
  32. get :edit
  33. assert_response :success
  34. end
  35. def test_get_edit_with_role_and_tracker
  36. WorkflowTransition.delete_all
  37. WorkflowTransition.create!(:role_id => 1, :tracker_id => 1, :old_status_id => 2, :new_status_id => 3)
  38. WorkflowTransition.create!(:role_id => 2, :tracker_id => 1, :old_status_id => 3, :new_status_id => 5)
  39. get :edit, :params => {:role_id => 2, :tracker_id => 1}
  40. assert_response :success
  41. # used status only
  42. statuses = IssueStatus.where(:id => [2, 3, 5]).sorted.pluck(:name)
  43. assert_equal(
  44. ["New issue"] + statuses,
  45. css_select('table.workflows.transitions-always tbody tr td:first').map {|e| e.text.strip}
  46. )
  47. # allowed transitions
  48. assert_select 'input[type=checkbox][name=?][value="1"][checked=checked]', 'transitions[3][5][always]'
  49. # not allowed
  50. assert_select 'input[type=checkbox][name=?][value="1"]:not([checked=checked])', 'transitions[3][2][always]'
  51. # unused
  52. assert_select 'input[type=checkbox][name=?]', 'transitions[1][1][always]', 0
  53. end
  54. def test_get_edit_with_role_and_tracker_should_not_include_statuses_from_roles_without_workflow_permissions
  55. WorkflowTransition.delete_all
  56. WorkflowTransition.create!(:role_id => 1, :tracker_id => 1, :old_status_id => 2, :new_status_id => 3)
  57. reporter = Role.find(3)
  58. reporter.remove_permission! :edit_issues
  59. reporter.remove_permission! :add_issues
  60. assert !reporter.consider_workflow?
  61. WorkflowTransition.create!(:role_id => 3, :tracker_id => 1, :old_status_id => 1, :new_status_id => 5)
  62. get :edit, :params => {:role_id => 2, :tracker_id => 1}
  63. assert_response :success
  64. # statuses 1 and 5 not displayed
  65. statuses = IssueStatus.where(:id => [2, 3]).sorted.pluck(:name)
  66. assert_equal(
  67. ["New issue"] + statuses,
  68. css_select('table.workflows.transitions-always tbody tr td:first').map {|e| e.text.strip}
  69. )
  70. end
  71. def test_get_edit_with_role_and_tracker_should_not_include_only_identity_workflows
  72. WorkflowTransition.delete_all
  73. WorkflowTransition.create!(:role_id => 1, :tracker_id => 1, :old_status_id => 1, :new_status_id => 1)
  74. WorkflowTransition.create!(:role_id => 1, :tracker_id => 1, :old_status_id => 2, :new_status_id => 3)
  75. get :edit, :params => {:role_id => 1, :tracker_id => 1}
  76. assert_response :success
  77. # statuses 1 and 5 not displayed
  78. statuses = IssueStatus.where(:id => [2, 3]).sorted.pluck(:name)
  79. assert_equal(
  80. ["New issue"] + statuses,
  81. css_select('table.workflows.transitions-always tbody tr td:first').map {|e| e.text.strip}
  82. )
  83. end
  84. def test_get_edit_should_include_allowed_statuses_for_new_issues
  85. WorkflowTransition.delete_all
  86. WorkflowTransition.create!(:role_id => 1, :tracker_id => 1, :old_status_id => 0, :new_status_id => 1)
  87. get :edit, :params => {:role_id => 1, :tracker_id => 1}
  88. assert_response :success
  89. assert_select 'td', 'New issue'
  90. assert_select 'input[type=checkbox][name=?][value="1"][checked=checked]', 'transitions[0][1][always]'
  91. end
  92. def test_get_edit_with_all_roles_and_all_trackers
  93. get :edit, :params => {:role_id => 'all', :tracker_id => 'all'}
  94. assert_response :success
  95. assert_select 'select[name=?]', 'role_id[]' do
  96. assert_select 'option[selected=selected][value=all]'
  97. end
  98. assert_select 'select[name=?]', 'tracker_id[]' do
  99. assert_select 'option[selected=selected][value=all]'
  100. end
  101. end
  102. def test_get_edit_with_role_and_tracker_and_all_statuses
  103. WorkflowTransition.delete_all
  104. get :edit, :params => {:role_id => 2, :tracker_id => 1, :used_statuses_only => '0'}
  105. assert_response :success
  106. statuses = IssueStatus.all.sorted.pluck(:name)
  107. assert_equal(
  108. ["New issue"] + statuses,
  109. css_select('table.workflows.transitions-always tbody tr td:first').map {|e| e.text.strip}
  110. )
  111. assert_select 'input[type=checkbox][name=?]', 'transitions[0][1][always]'
  112. end
  113. def test_get_edit_should_show_checked_disabled_transition_checkbox_between_same_statuses
  114. get :edit, :params => {:role_id => 2, :tracker_id => 1}
  115. assert_response :success
  116. assert_select 'table.workflows.transitions-always tbody tr:nth-child(2)' do
  117. assert_select 'td.name', :text => 'New'
  118. # assert that the td is enabled
  119. assert_select "td.enabled[title='New » New']"
  120. # assert that the checkbox is disabled and checked
  121. assert_select "input[name='transitions[1][1][always]'][checked=?][disabled=?]", 'checked', 'disabled', 1
  122. end
  123. end
  124. def test_post_edit
  125. WorkflowTransition.delete_all
  126. patch :update, :params => {
  127. :role_id => 2,
  128. :tracker_id => 1,
  129. :transitions => {
  130. '4' => {'5' => {'always' => '1'}},
  131. '3' => {'1' => {'always' => '1'}, '2' => {'always' => '1'}}
  132. }
  133. }
  134. assert_response 302
  135. assert_equal 3, WorkflowTransition.where(:tracker_id => 1, :role_id => 2).count
  136. assert WorkflowTransition.where(:role_id => 2, :tracker_id => 1, :old_status_id => 3, :new_status_id => 2).exists?
  137. assert_not WorkflowTransition.where(:role_id => 2, :tracker_id => 1, :old_status_id => 5, :new_status_id => 4).exists?
  138. end
  139. def test_post_edit_with_allowed_statuses_for_new_issues
  140. WorkflowTransition.delete_all
  141. patch :update, :params => {
  142. :role_id => 2,
  143. :tracker_id => 1,
  144. :transitions => {
  145. '0' => {'1' => {'always' => '1'}, '2' => {'always' => '1'}}
  146. }
  147. }
  148. assert_response 302
  149. assert WorkflowTransition.where(:role_id => 2, :tracker_id => 1, :old_status_id => 0, :new_status_id => 1).any?
  150. assert WorkflowTransition.where(:role_id => 2, :tracker_id => 1, :old_status_id => 0, :new_status_id => 2).any?
  151. assert_equal 2, WorkflowTransition.where(:tracker_id => 1, :role_id => 2).count
  152. end
  153. def test_post_edit_with_additional_transitions
  154. WorkflowTransition.delete_all
  155. patch :update, :params => {
  156. :role_id => 2,
  157. :tracker_id => 1,
  158. :transitions => {
  159. '4' => {'5' => {'always' => '1', 'author' => '0', 'assignee' => '0'}},
  160. '3' => {'1' => {'always' => '0', 'author' => '1', 'assignee' => '0'},
  161. '2' => {'always' => '0', 'author' => '0', 'assignee' => '1'},
  162. '4' => {'always' => '0', 'author' => '1', 'assignee' => '1'}}
  163. }
  164. }
  165. assert_response 302
  166. assert_equal 4, WorkflowTransition.where(:tracker_id => 1, :role_id => 2).count
  167. w = WorkflowTransition.where(:role_id => 2, :tracker_id => 1, :old_status_id => 4, :new_status_id => 5).first
  168. assert ! w.author
  169. assert ! w.assignee
  170. w = WorkflowTransition.where(:role_id => 2, :tracker_id => 1, :old_status_id => 3, :new_status_id => 1).first
  171. assert w.author
  172. assert ! w.assignee
  173. w = WorkflowTransition.where(:role_id => 2, :tracker_id => 1, :old_status_id => 3, :new_status_id => 2).first
  174. assert ! w.author
  175. assert w.assignee
  176. w = WorkflowTransition.where(:role_id => 2, :tracker_id => 1, :old_status_id => 3, :new_status_id => 4).first
  177. assert w.author
  178. assert w.assignee
  179. end
  180. def test_get_permissions
  181. get :permissions
  182. assert_response :success
  183. end
  184. def test_get_permissions_with_role_and_tracker
  185. WorkflowPermission.delete_all
  186. WorkflowPermission.create!(:role_id => 1, :tracker_id => 2, :old_status_id => 2, :field_name => 'assigned_to_id', :rule => 'required')
  187. WorkflowPermission.create!(:role_id => 1, :tracker_id => 2, :old_status_id => 2, :field_name => 'fixed_version_id', :rule => 'required')
  188. WorkflowPermission.create!(:role_id => 1, :tracker_id => 2, :old_status_id => 3, :field_name => 'fixed_version_id', :rule => 'readonly')
  189. get :permissions, :params => {:role_id => 1, :tracker_id => 2}
  190. assert_response :success
  191. assert_select 'input[name=?][value="1"]', 'role_id[]'
  192. assert_select 'input[name=?][value="2"]', 'tracker_id[]'
  193. # Required field
  194. assert_select 'select[name=?]', 'permissions[2][assigned_to_id]' do
  195. assert_select 'option[value=""]'
  196. assert_select 'option[value=""][selected=selected]', 0
  197. assert_select 'option[value=readonly]', :text => 'Read-only'
  198. assert_select 'option[value=readonly][selected=selected]', 0
  199. assert_select 'option[value=required]', :text => 'Required'
  200. assert_select 'option[value=required][selected=selected]'
  201. end
  202. # Read-only field
  203. assert_select 'select[name=?]', 'permissions[3][fixed_version_id]' do
  204. assert_select 'option[value=""]'
  205. assert_select 'option[value=""][selected=selected]', 0
  206. assert_select 'option[value=readonly]', :text => 'Read-only'
  207. assert_select 'option[value=readonly][selected=selected]'
  208. assert_select 'option[value=required]', :text => 'Required'
  209. assert_select 'option[value=required][selected=selected]', 0
  210. end
  211. # Other field
  212. assert_select 'select[name=?]', 'permissions[3][due_date]' do
  213. assert_select 'option[value=""]'
  214. assert_select 'option[value=""][selected=selected]', 0
  215. assert_select 'option[value=readonly]', :text => 'Read-only'
  216. assert_select 'option[value=readonly][selected=selected]', 0
  217. assert_select 'option[value=required]', :text => 'Required'
  218. assert_select 'option[value=required][selected=selected]', 0
  219. end
  220. end
  221. def test_get_permissions_with_required_custom_field_should_not_show_required_option
  222. cf = IssueCustomField.create!(:name => 'Foo', :field_format => 'string', :tracker_ids => [1], :is_required => true)
  223. get :permissions, :params => {:role_id => 1, :tracker_id => 1}
  224. assert_response :success
  225. # Custom field that is always required
  226. # The default option is "(Required)"
  227. assert_select 'select[name=?]', "permissions[3][#{cf.id}]" do
  228. assert_select 'option[value=""]'
  229. assert_select 'option[value=readonly]', :text => 'Read-only'
  230. assert_select 'option[value=required]', 0
  231. end
  232. end
  233. def test_get_permissions_should_disable_hidden_custom_fields
  234. cf1 = IssueCustomField.generate!(:tracker_ids => [1], :visible => true)
  235. cf2 = IssueCustomField.generate!(:tracker_ids => [1], :visible => false, :role_ids => [1])
  236. cf3 = IssueCustomField.generate!(:tracker_ids => [1], :visible => false, :role_ids => [1, 2])
  237. get :permissions, :params => {:role_id => 2, :tracker_id => 1}
  238. assert_response :success
  239. assert_select 'select[name=?]:not(.disabled)', "permissions[1][#{cf1.id}]"
  240. assert_select 'select[name=?]:not(.disabled)', "permissions[1][#{cf3.id}]"
  241. assert_select 'select[name=?][disabled=disabled]', "permissions[1][#{cf2.id}]" do
  242. assert_select 'option[value=""][selected=selected]', :text => 'Hidden'
  243. end
  244. end
  245. def test_get_permissions_with_missing_permissions_for_roles_should_default_to_no_change
  246. WorkflowPermission.delete_all
  247. WorkflowPermission.create!(:role_id => 1, :tracker_id => 2, :old_status_id => 1, :field_name => 'assigned_to_id', :rule => 'required')
  248. get :permissions, :params => {:role_id => [1, 2], :tracker_id => 2}
  249. assert_response :success
  250. assert_select 'select[name=?]', 'permissions[1][assigned_to_id]' do
  251. assert_select 'option[selected]', 1
  252. assert_select 'option[selected][value=no_change]'
  253. end
  254. end
  255. def test_get_permissions_with_different_permissions_for_roles_should_default_to_no_change
  256. WorkflowPermission.delete_all
  257. WorkflowPermission.create!(:role_id => 1, :tracker_id => 2, :old_status_id => 1, :field_name => 'assigned_to_id', :rule => 'required')
  258. WorkflowPermission.create!(:role_id => 2, :tracker_id => 2, :old_status_id => 1, :field_name => 'assigned_to_id', :rule => 'readonly')
  259. get :permissions, :params => {:role_id => [1, 2], :tracker_id => 2}
  260. assert_response :success
  261. assert_select 'select[name=?]', 'permissions[1][assigned_to_id]' do
  262. assert_select 'option[selected]', 1
  263. assert_select 'option[selected][value=no_change]'
  264. end
  265. end
  266. def test_get_permissions_with_same_permissions_for_roles_should_default_to_permission
  267. WorkflowPermission.delete_all
  268. WorkflowPermission.create!(:role_id => 1, :tracker_id => 2, :old_status_id => 1, :field_name => 'assigned_to_id', :rule => 'required')
  269. WorkflowPermission.create!(:role_id => 2, :tracker_id => 2, :old_status_id => 1, :field_name => 'assigned_to_id', :rule => 'required')
  270. get :permissions, :params => {:role_id => [1, 2], :tracker_id => 2}
  271. assert_response :success
  272. assert_select 'select[name=?]', 'permissions[1][assigned_to_id]' do
  273. assert_select 'option[selected]', 1
  274. assert_select 'option[selected][value=required]'
  275. end
  276. end
  277. def test_get_permissions_with_role_and_tracker_and_all_statuses_should_show_all_statuses
  278. WorkflowTransition.delete_all
  279. get :permissions, :params => {:role_id => 1, :tracker_id => 2, :used_statuses_only => '0'}
  280. assert_response :success
  281. statuses = IssueStatus.all.sorted.pluck(:name)
  282. assert_equal(
  283. statuses,
  284. css_select('table.workflows.fields_permissions thead tr:nth-child(2) td:not(:first-child)').map {|e| e.text.strip}
  285. )
  286. end
  287. def test_get_permissions_should_set_css_class
  288. WorkflowPermission.delete_all
  289. WorkflowPermission.create!(:role_id => 1, :tracker_id => 2, :old_status_id => 1, :field_name => 'assigned_to_id', :rule => 'required')
  290. cf = IssueCustomField.create!(:name => 'Foo', :field_format => 'string', :tracker_ids => [2])
  291. WorkflowPermission.create!(:role_id => 1, :tracker_id => 2, :old_status_id => 1, :field_name => cf.id, :rule => 'required')
  292. get :permissions, :params => {:role_id => 1, :tracker_id => 2}
  293. assert_response :success
  294. assert_select 'td.required > select[name=?]', 'permissions[1][assigned_to_id]'
  295. assert_select 'td.required > select[name=?]', "permissions[1][#{cf.id}]"
  296. end
  297. def test_post_permissions
  298. WorkflowPermission.delete_all
  299. patch :update_permissions, :params => {
  300. :role_id => 1,
  301. :tracker_id => 2,
  302. :permissions => {
  303. '1' => {'assigned_to_id' => '', 'fixed_version_id' => 'required', 'due_date' => ''},
  304. '2' => {'assigned_to_id' => 'readonly', 'fixed_version_id' => 'readonly', 'due_date' => ''},
  305. '3' => {'assigned_to_id' => '', 'fixed_version_id' => '', 'due_date' => ''}
  306. }
  307. }
  308. assert_response 302
  309. workflows = WorkflowPermission.all
  310. assert_equal 3, workflows.size
  311. workflows.each do |workflow|
  312. assert_equal 1, workflow.role_id
  313. assert_equal 2, workflow.tracker_id
  314. end
  315. assert workflows.detect {|wf| wf.old_status_id == 2 && wf.field_name == 'assigned_to_id' && wf.rule == 'readonly'}
  316. assert workflows.detect {|wf| wf.old_status_id == 1 && wf.field_name == 'fixed_version_id' && wf.rule == 'required'}
  317. assert workflows.detect {|wf| wf.old_status_id == 2 && wf.field_name == 'fixed_version_id' && wf.rule == 'readonly'}
  318. end
  319. def test_get_copy
  320. get :copy
  321. assert_response :success
  322. assert_select 'select[name=source_tracker_id]' do
  323. assert_select 'option[value="1"]', :text => 'Bug'
  324. end
  325. assert_select 'select[name=source_role_id]' do
  326. assert_select 'option[value="2"]', :text => 'Developer'
  327. end
  328. assert_select 'select[name=?]', 'target_tracker_ids[]' do
  329. assert_select 'option[value="3"]', :text => 'Support request'
  330. end
  331. assert_select 'select[name=?]', 'target_role_ids[]' do
  332. assert_select 'option[value="1"]', :text => 'Manager'
  333. end
  334. end
  335. def test_post_copy_one_to_one
  336. source_transitions = status_transitions(:tracker_id => 1, :role_id => 2)
  337. post :duplicate, :params => {
  338. :source_tracker_id => '1', :source_role_id => '2',
  339. :target_tracker_ids => ['3'], :target_role_ids => ['1']
  340. }
  341. assert_response 302
  342. assert_equal source_transitions, status_transitions(:tracker_id => 3, :role_id => 1)
  343. end
  344. def test_post_copy_one_to_many
  345. source_transitions = status_transitions(:tracker_id => 1, :role_id => 2)
  346. post :duplicate, :params => {
  347. :source_tracker_id => '1', :source_role_id => '2',
  348. :target_tracker_ids => ['2', '3'], :target_role_ids => ['1', '3']
  349. }
  350. assert_response 302
  351. assert_equal source_transitions, status_transitions(:tracker_id => 2, :role_id => 1)
  352. assert_equal source_transitions, status_transitions(:tracker_id => 3, :role_id => 1)
  353. assert_equal source_transitions, status_transitions(:tracker_id => 2, :role_id => 3)
  354. assert_equal source_transitions, status_transitions(:tracker_id => 3, :role_id => 3)
  355. end
  356. def test_post_copy_many_to_many
  357. source_t2 = status_transitions(:tracker_id => 2, :role_id => 2)
  358. source_t3 = status_transitions(:tracker_id => 3, :role_id => 2)
  359. post :duplicate, :params => {
  360. :source_tracker_id => 'any', :source_role_id => '2',
  361. :target_tracker_ids => ['2', '3'], :target_role_ids => ['1', '3']
  362. }
  363. assert_response 302
  364. assert_equal source_t2, status_transitions(:tracker_id => 2, :role_id => 1)
  365. assert_equal source_t3, status_transitions(:tracker_id => 3, :role_id => 1)
  366. assert_equal source_t2, status_transitions(:tracker_id => 2, :role_id => 3)
  367. assert_equal source_t3, status_transitions(:tracker_id => 3, :role_id => 3)
  368. end
  369. def test_post_copy_with_incomplete_source_specification_should_fail
  370. assert_no_difference 'WorkflowRule.count' do
  371. post :duplicate, :params => {
  372. :source_tracker_id => '', :source_role_id => '2',
  373. :target_tracker_ids => ['2', '3'], :target_role_ids => ['1', '3']
  374. }
  375. assert_response 200
  376. assert_select 'div.flash.error', :text => 'Please select a source tracker or role'
  377. end
  378. end
  379. def test_post_copy_with_incomplete_target_specification_should_fail
  380. assert_no_difference 'WorkflowRule.count' do
  381. post :duplicate, :params => {
  382. :source_tracker_id => '1', :source_role_id => '2',
  383. :target_tracker_ids => ['2', '3']
  384. }
  385. assert_response 200
  386. assert_select 'div.flash.error', :text => 'Please select target tracker(s) and role(s)'
  387. end
  388. end
  389. # Returns an array of status transitions that can be compared
  390. def status_transitions(conditions)
  391. WorkflowTransition.
  392. where(conditions).
  393. order('tracker_id, role_id, old_status_id, new_status_id').
  394. collect {|w| [w.old_status, w.new_status_id]}
  395. end
  396. end