Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

issues_test.rb 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341
  1. # Redmine - project management software
  2. # Copyright (C) 2006-2017 Jean-Philippe Lang
  3. #
  4. # This program is free software; you can redistribute it and/or
  5. # modify it under the terms of the GNU General Public License
  6. # as published by the Free Software Foundation; either version 2
  7. # of the License, or (at your option) any later version.
  8. #
  9. # This program is distributed in the hope that it will be useful,
  10. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. # GNU General Public License for more details.
  13. #
  14. # You should have received a copy of the GNU General Public License
  15. # along with this program; if not, write to the Free Software
  16. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  17. require File.expand_path('../../application_system_test_case', __FILE__)
  18. class IssuesTest < ApplicationSystemTestCase
  19. fixtures :projects, :users, :email_addresses, :roles, :members, :member_roles,
  20. :trackers, :projects_trackers, :enabled_modules, :issue_statuses, :issues,
  21. :enumerations, :custom_fields, :custom_values, :custom_fields_trackers,
  22. :watchers, :journals, :journal_details, :versions
  23. def test_create_issue
  24. log_user('jsmith', 'jsmith')
  25. visit '/projects/ecookbook/issues/new'
  26. within('form#issue-form') do
  27. select 'Bug', :from => 'Tracker'
  28. select 'Low', :from => 'Priority'
  29. fill_in 'Subject', :with => 'new test issue'
  30. fill_in 'Description', :with => 'new issue'
  31. select '0 %', :from => 'Done'
  32. fill_in 'Searchable field', :with => 'Value for field 2'
  33. # click_button 'Create' would match both 'Create' and 'Create and continue' buttons
  34. find('input[name=commit]').click
  35. end
  36. # find created issue
  37. issue = Issue.find_by_subject("new test issue")
  38. assert_kind_of Issue, issue
  39. # check redirection
  40. find 'div#flash_notice', :visible => true, :text => "Issue \##{issue.id} created."
  41. assert_equal issue_path(:id => issue), current_path
  42. # check issue attributes
  43. assert_equal 'jsmith', issue.author.login
  44. assert_equal 1, issue.project.id
  45. assert_equal IssueStatus.find_by_name('New'), issue.status
  46. assert_equal Tracker.find_by_name('Bug'), issue.tracker
  47. assert_equal IssuePriority.find_by_name('Low'), issue.priority
  48. assert_equal 'Value for field 2', issue.custom_field_value(CustomField.find_by_name('Searchable field'))
  49. end
  50. def test_create_issue_with_form_update
  51. field1 = IssueCustomField.create!(
  52. :field_format => 'string',
  53. :name => 'Field1',
  54. :is_for_all => true,
  55. :trackers => Tracker.where(:id => [1, 2])
  56. )
  57. field2 = IssueCustomField.create!(
  58. :field_format => 'string',
  59. :name => 'Field2',
  60. :is_for_all => true,
  61. :trackers => Tracker.where(:id => 2)
  62. )
  63. Role.non_member.add_permission! :add_issues
  64. Role.non_member.remove_permission! :edit_issues, :add_issue_notes
  65. log_user('someone', 'foo')
  66. visit '/projects/ecookbook/issues/new'
  67. assert page.has_no_content?(field2.name)
  68. assert page.has_content?(field1.name)
  69. fill_in 'Subject', :with => 'New test issue'
  70. fill_in 'Description', :with => 'New test issue description'
  71. fill_in field1.name, :with => 'CF1 value'
  72. select 'Low', :from => 'Priority'
  73. # field2 should show up when changing tracker
  74. select 'Feature request', :from => 'Tracker'
  75. assert page.has_content?(field2.name)
  76. assert page.has_content?(field1.name)
  77. fill_in field2.name, :with => 'CF2 value'
  78. assert_difference 'Issue.count' do
  79. page.first(:button, 'Create').click
  80. end
  81. issue = Issue.order('id desc').first
  82. assert_equal 'New test issue', issue.subject
  83. assert_equal 'New test issue description', issue.description
  84. assert_equal 'Low', issue.priority.name
  85. assert_equal 'CF1 value', issue.custom_field_value(field1)
  86. assert_equal 'CF2 value', issue.custom_field_value(field2)
  87. end
  88. def test_create_issue_with_watchers
  89. user = User.generate!(:firstname => 'Some', :lastname => 'Watcher')
  90. assert_equal 'Some Watcher', user.name
  91. log_user('jsmith', 'jsmith')
  92. visit '/projects/ecookbook/issues/new'
  93. fill_in 'Subject', :with => 'Issue with watchers'
  94. # Add a project member as watcher
  95. check 'Dave Lopper'
  96. # Search for another user
  97. assert page.has_no_css?('form#new-watcher-form')
  98. assert page.has_no_content?('Some Watcher')
  99. click_link 'Search for watchers to add'
  100. within('form#new-watcher-form') do
  101. fill_in 'user_search', :with => 'watch'
  102. assert page.has_content?('Some Watcher')
  103. check 'Some Watcher'
  104. click_button 'Add'
  105. end
  106. assert page.has_css?('form#issue-form')
  107. assert page.has_css?('p#watchers_form')
  108. using_wait_time(30) do
  109. within('span#watchers_inputs') do
  110. within("label#issue_watcher_user_ids_#{user.id}") do
  111. assert has_content?('Some Watcher'), "No watcher content"
  112. end
  113. end
  114. end
  115. assert_difference 'Issue.count' do
  116. find('input[name=commit]').click
  117. end
  118. issue = Issue.order('id desc').first
  119. assert_equal ['Dave Lopper', 'Some Watcher'], issue.watcher_users.map(&:name).sort
  120. end
  121. def test_create_issue_with_attachment
  122. set_tmp_attachments_directory
  123. log_user('jsmith', 'jsmith')
  124. issue = new_record(Issue) do
  125. visit '/projects/ecookbook/issues/new'
  126. fill_in 'Subject', :with => 'Issue with attachment'
  127. attach_file 'attachments[dummy][file]', Rails.root.join('test/fixtures/files/testfile.txt')
  128. fill_in 'attachments[1][description]', :with => 'Some description'
  129. click_on 'Create'
  130. end
  131. assert_equal 1, issue.attachments.count
  132. assert_equal 'Some description', issue.attachments.first.description
  133. ensure
  134. set_fixtures_attachments_directory
  135. end
  136. def test_create_issue_with_new_target_version
  137. log_user('jsmith', 'jsmith')
  138. assert_difference 'Issue.count' do
  139. assert_difference 'Version.count' do
  140. visit '/projects/ecookbook/issues/new'
  141. fill_in 'Subject', :with => 'With a new version'
  142. click_on 'New version'
  143. within '#ajax-modal' do
  144. fill_in 'Name', :with => '4.0'
  145. click_on 'Create'
  146. end
  147. click_on 'Create'
  148. end
  149. end
  150. issue = Issue.order('id desc').first
  151. assert_not_nil issue.fixed_version
  152. assert_equal '4.0', issue.fixed_version.name
  153. end
  154. def test_preview_issue_description
  155. log_user('jsmith', 'jsmith')
  156. visit '/projects/ecookbook/issues/new'
  157. within('form#issue-form') do
  158. fill_in 'Subject', :with => 'new issue subject'
  159. fill_in 'Description', :with => 'new issue description'
  160. click_link 'Preview'
  161. find 'div.wiki-preview', :visible => true, :text => 'new issue description'
  162. end
  163. assert_difference 'Issue.count' do
  164. click_button('Create')
  165. end
  166. issue = Issue.order('id desc').first
  167. assert_equal 'new issue description', issue.description
  168. end
  169. def test_update_issue_with_form_update
  170. field = IssueCustomField.create!(
  171. :field_format => 'string',
  172. :name => 'Form update CF',
  173. :is_for_all => true,
  174. :trackers => Tracker.where(:name => 'Feature request')
  175. )
  176. Role.non_member.add_permission! :edit_issues, :add_issues
  177. Role.non_member.remove_permission! :add_issue_notes
  178. log_user('someone', 'foo')
  179. visit '/issues/1'
  180. assert page.has_no_content?('Form update CF')
  181. page.first(:link, 'Edit').click
  182. # the custom field should show up when changing tracker
  183. select 'Feature request', :from => 'Tracker'
  184. assert page.has_content?('Form update CF')
  185. fill_in 'Form update', :with => 'CF value'
  186. assert_no_difference 'Issue.count' do
  187. page.first(:button, 'Submit').click
  188. end
  189. issue = Issue.find(1)
  190. assert_equal 'CF value', issue.custom_field_value(field)
  191. end
  192. def test_remove_issue_watcher_from_sidebar
  193. user = User.find(3)
  194. Watcher.create!(:watchable => Issue.find(1), :user => user)
  195. log_user('jsmith', 'jsmith')
  196. visit '/issues/1'
  197. assert page.first('#sidebar').has_content?('Watchers (1)')
  198. assert page.first('#sidebar').has_content?(user.name)
  199. assert_difference 'Watcher.count', -1 do
  200. page.first('ul.watchers .user-3 a.delete').click
  201. assert page.first('#sidebar').has_content?('Watchers (0)')
  202. end
  203. assert page.first('#sidebar').has_no_content?(user.name)
  204. end
  205. def test_watch_should_update_watchers_list
  206. user = User.find(2)
  207. log_user('jsmith', 'jsmith')
  208. visit '/issues/1'
  209. assert page.first('#sidebar').has_content?('Watchers (0)')
  210. page.first('a.issue-1-watcher').click
  211. assert page.first('#sidebar').has_content?('Watchers (1)')
  212. assert page.first('#sidebar').has_content?(user.name)
  213. end
  214. def test_watch_issue_via_context_menu
  215. log_user('jsmith', 'jsmith')
  216. visit '/issues'
  217. assert page.has_css?('tr#issue-1')
  218. find('tr#issue-1 td.updated_on').click
  219. page.execute_script "$('tr#issue-1 td.updated_on').trigger('contextmenu');"
  220. assert_difference 'Watcher.count' do
  221. within('#context-menu') do
  222. click_link 'Watch'
  223. end
  224. # wait for ajax response
  225. assert page.has_css?('#context-menu .issue-1-watcher.icon-fav')
  226. assert page.has_css?('tr#issue-1')
  227. end
  228. assert Issue.find(1).watched_by?(User.find_by_login('jsmith'))
  229. end
  230. def test_bulk_watch_issues_via_context_menu
  231. log_user('jsmith', 'jsmith')
  232. visit '/issues'
  233. assert page.has_css?('tr#issue-1')
  234. assert page.has_css?('tr#issue-4')
  235. find('tr#issue-1 input[type=checkbox]').click
  236. find('tr#issue-4 input[type=checkbox]').click
  237. page.execute_script "$('tr#issue-1 td.updated_on').trigger('contextmenu');"
  238. assert_difference 'Watcher.count', 2 do
  239. within('#context-menu') do
  240. click_link 'Watch'
  241. end
  242. # wait for ajax response
  243. assert page.has_css?('#context-menu .issue-bulk-watcher.icon-fav')
  244. assert page.has_css?('tr#issue-1')
  245. assert page.has_css?('tr#issue-4')
  246. end
  247. assert Issue.find(1).watched_by?(User.find_by_login('jsmith'))
  248. assert Issue.find(4).watched_by?(User.find_by_login('jsmith'))
  249. end
  250. def test_issue_list_with_default_totalable_columns
  251. log_user('admin', 'admin')
  252. with_settings :issue_list_default_totals => ['estimated_hours'] do
  253. visit '/projects/ecookbook/issues'
  254. # Check that the page shows the Estimated hours total
  255. assert page.has_css?('p.query-totals')
  256. assert page.has_css?('span.total-for-estimated-hours')
  257. # Open the Options of the form (necessary for having the totalable columns options clickable)
  258. page.all('legend')[1].click
  259. # Deselect the default totalable column (none should be left)
  260. page.first('input[name="t[]"][value="estimated_hours"]').click
  261. within('#query_form') do
  262. click_link 'Apply'
  263. end
  264. # Check that Totals are not present in the reloaded page
  265. assert !page.has_css?('p.query-totals')
  266. assert !page.has_css?('span.total-for-estimated-hours')
  267. end
  268. end
  269. def test_update_journal_notes_with_preview
  270. log_user('admin', 'admin')
  271. visit '/issues/1'
  272. # Click on the edit button
  273. page.first('#change-2 a.icon-edit').click
  274. # Check that the textarea is displayed
  275. assert page.has_css?('#change-2 textarea')
  276. assert page.first('#change-2 textarea').has_content?('Some notes with Redmine links')
  277. # Update the notes
  278. fill_in 'Notes', :with => 'Updated notes'
  279. # Preview the change
  280. page.first('#change-2 a.tab-preview').click
  281. assert page.has_css?('#preview_journal_2_notes')
  282. assert page.first('#preview_journal_2_notes').has_content?('Updated notes')
  283. # Save
  284. click_on 'Save'
  285. sleep 1
  286. assert_equal 'Updated notes', Journal.find(2).notes
  287. end
  288. def test_index_as_csv_should_reflect_sort
  289. log_user('admin', 'admin')
  290. visit '/issues'
  291. # Sort issues by subject
  292. click_on 'Subject'
  293. click_on 'CSV'
  294. click_on 'Export'
  295. csv = CSV.read(downloaded_file)
  296. subject_index = csv.shift.index('Subject')
  297. subjects = csv.map {|row| row[subject_index]}
  298. assert_equal subjects.sort, subjects
  299. end
  300. end