1 # Redmine - project management software
2 # Copyright (C) 2006-2008 Jean-Philippe Lang
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.
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.
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.
18 require File.dirname(__FILE__) + '/../test_helper'
19 require 'issues_controller'
21 # Re-raise errors caught by the controller.
22 class IssuesController; def rescue_action(e) raise e end; end
24 class IssuesControllerTest < Test::Unit::TestCase
41 :custom_fields_trackers,
47 @controller = IssuesController.new
48 @request = ActionController::TestRequest.new
49 @response = ActionController::TestResponse.new
53 def test_index_routing
55 {:method => :get, :path => '/issues'},
56 :controller => 'issues', :action => 'index'
61 Setting.default_language = 'en'
64 assert_response :success
65 assert_template 'index.rhtml'
66 assert_not_nil assigns(:issues)
67 assert_nil assigns(:project)
68 assert_tag :tag => 'a', :content => /Can't print recipes/
69 assert_tag :tag => 'a', :content => /Subproject issue/
70 # private projects hidden
71 assert_no_tag :tag => 'a', :content => /Issue of a private subproject/
72 assert_no_tag :tag => 'a', :content => /Issue on project 2/
74 assert_tag :tag => 'th', :content => /Project/
77 def test_index_should_not_list_issues_when_module_disabled
78 EnabledModule.delete_all("name = 'issue_tracking' AND project_id = 1")
80 assert_response :success
81 assert_template 'index.rhtml'
82 assert_not_nil assigns(:issues)
83 assert_nil assigns(:project)
84 assert_no_tag :tag => 'a', :content => /Can't print recipes/
85 assert_tag :tag => 'a', :content => /Subproject issue/
88 def test_index_with_project_routing
90 {:method => :get, :path => '/projects/23/issues'},
91 :controller => 'issues', :action => 'index', :project_id => '23'
95 def test_index_should_not_list_issues_when_module_disabled
96 EnabledModule.delete_all("name = 'issue_tracking' AND project_id = 1")
98 assert_response :success
99 assert_template 'index.rhtml'
100 assert_not_nil assigns(:issues)
101 assert_nil assigns(:project)
102 assert_no_tag :tag => 'a', :content => /Can't print recipes/
103 assert_tag :tag => 'a', :content => /Subproject issue/
106 def test_index_with_project_routing
108 {:method => :get, :path => 'projects/23/issues'},
109 :controller => 'issues', :action => 'index', :project_id => '23'
113 def test_index_with_project
114 Setting.display_subprojects_issues = 0
115 get :index, :project_id => 1
116 assert_response :success
117 assert_template 'index.rhtml'
118 assert_not_nil assigns(:issues)
119 assert_tag :tag => 'a', :content => /Can't print recipes/
120 assert_no_tag :tag => 'a', :content => /Subproject issue/
123 def test_index_with_project_and_subprojects
124 Setting.display_subprojects_issues = 1
125 get :index, :project_id => 1
126 assert_response :success
127 assert_template 'index.rhtml'
128 assert_not_nil assigns(:issues)
129 assert_tag :tag => 'a', :content => /Can't print recipes/
130 assert_tag :tag => 'a', :content => /Subproject issue/
131 assert_no_tag :tag => 'a', :content => /Issue of a private subproject/
134 def test_index_with_project_and_subprojects_should_show_private_subprojects
135 @request.session[:user_id] = 2
136 Setting.display_subprojects_issues = 1
137 get :index, :project_id => 1
138 assert_response :success
139 assert_template 'index.rhtml'
140 assert_not_nil assigns(:issues)
141 assert_tag :tag => 'a', :content => /Can't print recipes/
142 assert_tag :tag => 'a', :content => /Subproject issue/
143 assert_tag :tag => 'a', :content => /Issue of a private subproject/
146 def test_index_with_project_routing_formatted
148 {:method => :get, :path => 'projects/23/issues.pdf'},
149 :controller => 'issues', :action => 'index', :project_id => '23', :format => 'pdf'
152 {:method => :get, :path => 'projects/23/issues.atom'},
153 :controller => 'issues', :action => 'index', :project_id => '23', :format => 'atom'
157 def test_index_with_project_and_filter
158 get :index, :project_id => 1, :set_filter => 1
159 assert_response :success
160 assert_template 'index.rhtml'
161 assert_not_nil assigns(:issues)
164 def test_index_csv_with_project
165 get :index, :format => 'csv'
166 assert_response :success
167 assert_not_nil assigns(:issues)
168 assert_equal 'text/csv', @response.content_type
170 get :index, :project_id => 1, :format => 'csv'
171 assert_response :success
172 assert_not_nil assigns(:issues)
173 assert_equal 'text/csv', @response.content_type
176 def test_index_formatted
178 {:method => :get, :path => 'issues.pdf'},
179 :controller => 'issues', :action => 'index', :format => 'pdf'
182 {:method => :get, :path => 'issues.atom'},
183 :controller => 'issues', :action => 'index', :format => 'atom'
188 get :index, :format => 'pdf'
189 assert_response :success
190 assert_not_nil assigns(:issues)
191 assert_equal 'application/pdf', @response.content_type
193 get :index, :project_id => 1, :format => 'pdf'
194 assert_response :success
195 assert_not_nil assigns(:issues)
196 assert_equal 'application/pdf', @response.content_type
200 get :index, :sort_key => 'tracker'
201 assert_response :success
203 sort_params = @request.session['issuesindex_sort']
204 assert sort_params.is_a?(Hash)
205 assert_equal 'tracker', sort_params[:key]
206 assert_equal 'ASC', sort_params[:order]
210 get :gantt, :project_id => 1
211 assert_response :success
212 assert_template 'gantt.rhtml'
213 assert_not_nil assigns(:gantt)
214 events = assigns(:gantt).events
215 assert_not_nil events
216 # Issue with start and due dates
218 assert_not_nil i.due_date
219 assert events.include?(Issue.find(1))
220 # Issue with without due date but targeted to a version with date
222 assert_nil i.due_date
223 assert events.include?(i)
226 def test_cross_project_gantt
228 assert_response :success
229 assert_template 'gantt.rhtml'
230 assert_not_nil assigns(:gantt)
231 events = assigns(:gantt).events
232 assert_not_nil events
235 def test_gantt_export_to_pdf
236 get :gantt, :project_id => 1, :format => 'pdf'
237 assert_response :success
238 assert_equal 'application/pdf', @response.content_type
239 assert @response.body.starts_with?('%PDF')
240 assert_not_nil assigns(:gantt)
243 def test_cross_project_gantt_export_to_pdf
244 get :gantt, :format => 'pdf'
245 assert_response :success
246 assert_equal 'application/pdf', @response.content_type
247 assert @response.body.starts_with?('%PDF')
248 assert_not_nil assigns(:gantt)
251 if Object.const_defined?(:Magick)
253 get :gantt, :project_id => 1, :format => 'png'
254 assert_response :success
255 assert_equal 'image/png', @response.content_type
258 puts "RMagick not installed. Skipping tests !!!"
262 get :calendar, :project_id => 1
263 assert_response :success
264 assert_template 'calendar'
265 assert_not_nil assigns(:calendar)
268 def test_cross_project_calendar
270 assert_response :success
271 assert_template 'calendar'
272 assert_not_nil assigns(:calendar)
276 get :changes, :project_id => 1
277 assert_response :success
278 assert_not_nil assigns(:journals)
279 assert_equal 'application/atom+xml', @response.content_type
282 def test_show_routing
284 {:method => :get, :path => '/issues/64'},
285 :controller => 'issues', :action => 'show', :id => '64'
289 def test_show_routing_formatted
291 {:method => :get, :path => '/issues/2332.pdf'},
292 :controller => 'issues', :action => 'show', :id => '2332', :format => 'pdf'
295 {:method => :get, :path => '/issues/23123.atom'},
296 :controller => 'issues', :action => 'show', :id => '23123', :format => 'atom'
300 def test_show_by_anonymous
302 assert_response :success
303 assert_template 'show.rhtml'
304 assert_not_nil assigns(:issue)
305 assert_equal Issue.find(1), assigns(:issue)
307 # anonymous role is allowed to add a note
308 assert_tag :tag => 'form',
309 :descendant => { :tag => 'fieldset',
310 :child => { :tag => 'legend',
311 :content => /Notes/ } }
314 def test_show_by_manager
315 @request.session[:user_id] = 2
317 assert_response :success
319 assert_tag :tag => 'form',
320 :descendant => { :tag => 'fieldset',
321 :child => { :tag => 'legend',
322 :content => /Change properties/ } },
323 :descendant => { :tag => 'fieldset',
324 :child => { :tag => 'legend',
325 :content => /Log time/ } },
326 :descendant => { :tag => 'fieldset',
327 :child => { :tag => 'legend',
328 :content => /Notes/ } }
331 def test_show_should_not_disclose_relations_to_invisible_issues
332 Setting.cross_project_issue_relations = '1'
333 IssueRelation.create!(:issue_from => Issue.find(1), :issue_to => Issue.find(2), :relation_type => 'relates')
334 # Relation to a private project issue
335 IssueRelation.create!(:issue_from => Issue.find(1), :issue_to => Issue.find(4), :relation_type => 'relates')
338 assert_response :success
340 assert_tag :div, :attributes => { :id => 'relations' },
341 :descendant => { :tag => 'a', :content => /#2$/ }
342 assert_no_tag :div, :attributes => { :id => 'relations' },
343 :descendant => { :tag => 'a', :content => /#4$/ }
348 {:method => :get, :path => '/projects/1/issues/new'},
349 :controller => 'issues', :action => 'new', :project_id => '1'
352 {:controller => 'issues', :action => 'new', :project_id => '1'},
353 {:method => :post, :path => '/projects/1/issues'}
357 def test_show_export_to_pdf
358 get :show, :id => 3, :format => 'pdf'
359 assert_response :success
360 assert_equal 'application/pdf', @response.content_type
361 assert @response.body.starts_with?('%PDF')
362 assert_not_nil assigns(:issue)
366 @request.session[:user_id] = 2
367 get :new, :project_id => 1, :tracker_id => 1
368 assert_response :success
369 assert_template 'new'
371 assert_tag :tag => 'input', :attributes => { :name => 'issue[custom_field_values][2]',
372 :value => 'Default string' }
375 def test_get_new_without_tracker_id
376 @request.session[:user_id] = 2
377 get :new, :project_id => 1
378 assert_response :success
379 assert_template 'new'
381 issue = assigns(:issue)
383 assert_equal Project.find(1).trackers.first, issue.tracker
386 def test_get_new_with_no_default_status_should_display_an_error
387 @request.session[:user_id] = 2
388 IssueStatus.delete_all
390 get :new, :project_id => 1
392 assert_not_nil flash[:error]
393 assert_tag :tag => 'div', :attributes => { :class => /error/ },
394 :content => /No default issue/
397 def test_get_new_with_no_tracker_should_display_an_error
398 @request.session[:user_id] = 2
401 get :new, :project_id => 1
403 assert_not_nil flash[:error]
404 assert_tag :tag => 'div', :attributes => { :class => /error/ },
405 :content => /No tracker/
408 def test_update_new_form
409 @request.session[:user_id] = 2
410 xhr :post, :new, :project_id => 1,
411 :issue => {:tracker_id => 2,
412 :subject => 'This is the test_new issue',
413 :description => 'This is the description',
415 assert_response :success
416 assert_template 'new'
420 @request.session[:user_id] = 2
421 post :new, :project_id => 1,
422 :issue => {:tracker_id => 3,
423 :subject => 'This is the test_new issue',
424 :description => 'This is the description',
426 :estimated_hours => '',
427 :custom_field_values => {'2' => 'Value for field 2'}}
428 assert_redirected_to :action => 'show'
430 issue = Issue.find_by_subject('This is the test_new issue')
432 assert_equal 2, issue.author_id
433 assert_equal 3, issue.tracker_id
434 assert_nil issue.estimated_hours
435 v = issue.custom_values.find(:first, :conditions => {:custom_field_id => 2})
437 assert_equal 'Value for field 2', v.value
440 def test_post_new_and_continue
441 @request.session[:user_id] = 2
442 post :new, :project_id => 1,
443 :issue => {:tracker_id => 3,
444 :subject => 'This is first issue',
447 assert_redirected_to :controller => 'issues', :action => 'new', :tracker_id => 3
450 def test_post_new_without_custom_fields_param
451 @request.session[:user_id] = 2
452 post :new, :project_id => 1,
453 :issue => {:tracker_id => 1,
454 :subject => 'This is the test_new issue',
455 :description => 'This is the description',
457 assert_redirected_to :action => 'show'
460 def test_post_new_with_required_custom_field_and_without_custom_fields_param
461 field = IssueCustomField.find_by_name('Database')
462 field.update_attribute(:is_required, true)
464 @request.session[:user_id] = 2
465 post :new, :project_id => 1,
466 :issue => {:tracker_id => 1,
467 :subject => 'This is the test_new issue',
468 :description => 'This is the description',
470 assert_response :success
471 assert_template 'new'
472 issue = assigns(:issue)
474 assert_equal I18n.translate('activerecord.errors.messages.invalid'), issue.errors.on(:custom_values)
477 def test_post_new_with_watchers
478 @request.session[:user_id] = 2
479 ActionMailer::Base.deliveries.clear
481 assert_difference 'Watcher.count', 2 do
482 post :new, :project_id => 1,
483 :issue => {:tracker_id => 1,
484 :subject => 'This is a new issue with watchers',
485 :description => 'This is the description',
487 :watcher_user_ids => ['2', '3']}
489 issue = Issue.find_by_subject('This is a new issue with watchers')
491 assert_redirected_to :controller => 'issues', :action => 'show', :id => issue
494 assert_equal [2, 3], issue.watcher_user_ids.sort
495 assert issue.watched_by?(User.find(3))
497 mail = ActionMailer::Base.deliveries.last
498 assert_kind_of TMail::Mail, mail
499 assert [mail.bcc, mail.cc].flatten.include?(User.find(3).mail)
502 def test_post_should_preserve_fields_values_on_validation_failure
503 @request.session[:user_id] = 2
504 post :new, :project_id => 1,
505 :issue => {:tracker_id => 1,
508 :description => 'This is a description',
510 :custom_field_values => {'1' => 'Oracle', '2' => 'Value for field 2'}}
511 assert_response :success
512 assert_template 'new'
514 assert_tag :textarea, :attributes => { :name => 'issue[description]' },
515 :content => 'This is a description'
516 assert_tag :select, :attributes => { :name => 'issue[priority_id]' },
517 :child => { :tag => 'option', :attributes => { :selected => 'selected',
521 assert_tag :select, :attributes => { :name => 'issue[custom_field_values][1]' },
522 :child => { :tag => 'option', :attributes => { :selected => 'selected',
523 :value => 'Oracle' },
524 :content => 'Oracle' }
525 assert_tag :input, :attributes => { :name => 'issue[custom_field_values][2]',
526 :value => 'Value for field 2'}
529 def test_copy_routing
531 {:method => :get, :path => '/projects/world_domination/issues/567/copy'},
532 :controller => 'issues', :action => 'new', :project_id => 'world_domination', :copy_from => '567'
537 @request.session[:user_id] = 2
538 get :new, :project_id => 1, :copy_from => 1
539 assert_template 'new'
540 assert_not_nil assigns(:issue)
542 assert_equal orig.subject, assigns(:issue).subject
545 def test_edit_routing
547 {:method => :get, :path => '/issues/1/edit'},
548 :controller => 'issues', :action => 'edit', :id => '1'
550 assert_recognizes( #TODO: use a PUT on the issue URI isntead, need to adjust form
551 {:controller => 'issues', :action => 'edit', :id => '1'},
552 {:method => :post, :path => '/issues/1/edit'}
557 @request.session[:user_id] = 2
559 assert_response :success
560 assert_template 'edit'
561 assert_not_nil assigns(:issue)
562 assert_equal Issue.find(1), assigns(:issue)
565 def test_get_edit_with_params
566 @request.session[:user_id] = 2
567 get :edit, :id => 1, :issue => { :status_id => 5, :priority_id => 7 }
568 assert_response :success
569 assert_template 'edit'
571 issue = assigns(:issue)
574 assert_equal 5, issue.status_id
575 assert_tag :select, :attributes => { :name => 'issue[status_id]' },
576 :child => { :tag => 'option',
577 :content => 'Closed',
578 :attributes => { :selected => 'selected' } }
580 assert_equal 7, issue.priority_id
581 assert_tag :select, :attributes => { :name => 'issue[priority_id]' },
582 :child => { :tag => 'option',
583 :content => 'Urgent',
584 :attributes => { :selected => 'selected' } }
587 def test_reply_routing
589 {:method => :post, :path => '/issues/1/quoted'},
590 :controller => 'issues', :action => 'reply', :id => '1'
594 def test_reply_to_issue
595 @request.session[:user_id] = 2
597 assert_response :success
598 assert_select_rjs :show, "update"
601 def test_reply_to_note
602 @request.session[:user_id] = 2
603 get :reply, :id => 1, :journal_id => 2
604 assert_response :success
605 assert_select_rjs :show, "update"
608 def test_post_edit_without_custom_fields_param
609 @request.session[:user_id] = 2
610 ActionMailer::Base.deliveries.clear
612 issue = Issue.find(1)
613 assert_equal '125', issue.custom_value_for(2).value
614 old_subject = issue.subject
615 new_subject = 'Subject modified by IssuesControllerTest#test_post_edit'
617 assert_difference('Journal.count') do
618 assert_difference('JournalDetail.count', 2) do
619 post :edit, :id => 1, :issue => {:subject => new_subject,
621 :category_id => '1' # no change
625 assert_redirected_to :action => 'show', :id => '1'
627 assert_equal new_subject, issue.subject
628 # Make sure custom fields were not cleared
629 assert_equal '125', issue.custom_value_for(2).value
631 mail = ActionMailer::Base.deliveries.last
632 assert_kind_of TMail::Mail, mail
633 assert mail.subject.starts_with?("[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}]")
634 assert mail.body.include?("Subject changed from #{old_subject} to #{new_subject}")
637 def test_post_edit_with_custom_field_change
638 @request.session[:user_id] = 2
639 issue = Issue.find(1)
640 assert_equal '125', issue.custom_value_for(2).value
642 assert_difference('Journal.count') do
643 assert_difference('JournalDetail.count', 3) do
644 post :edit, :id => 1, :issue => {:subject => 'Custom field change',
646 :category_id => '1', # no change
647 :custom_field_values => { '2' => 'New custom value' }
651 assert_redirected_to :action => 'show', :id => '1'
653 assert_equal 'New custom value', issue.custom_value_for(2).value
655 mail = ActionMailer::Base.deliveries.last
656 assert_kind_of TMail::Mail, mail
657 assert mail.body.include?("Searchable field changed from 125 to New custom value")
660 def test_post_edit_with_status_and_assignee_change
661 issue = Issue.find(1)
662 assert_equal 1, issue.status_id
663 @request.session[:user_id] = 2
664 assert_difference('TimeEntry.count', 0) do
667 :issue => { :status_id => 2, :assigned_to_id => 3 },
668 :notes => 'Assigned to dlopper',
669 :time_entry => { :hours => '', :comments => '', :activity_id => Enumeration.activities.first }
671 assert_redirected_to :action => 'show', :id => '1'
673 assert_equal 2, issue.status_id
674 j = issue.journals.find(:first, :order => 'id DESC')
675 assert_equal 'Assigned to dlopper', j.notes
676 assert_equal 2, j.details.size
678 mail = ActionMailer::Base.deliveries.last
679 assert mail.body.include?("Status changed from New to Assigned")
682 def test_post_edit_with_note_only
683 notes = 'Note added by IssuesControllerTest#test_update_with_note_only'
688 assert_redirected_to :action => 'show', :id => '1'
689 j = Issue.find(1).journals.find(:first, :order => 'id DESC')
690 assert_equal notes, j.notes
691 assert_equal 0, j.details.size
692 assert_equal User.anonymous, j.user
694 mail = ActionMailer::Base.deliveries.last
695 assert mail.body.include?(notes)
698 def test_post_edit_with_note_and_spent_time
699 @request.session[:user_id] = 2
700 spent_hours_before = Issue.find(1).spent_hours
701 assert_difference('TimeEntry.count') do
704 :notes => '2.5 hours added',
705 :time_entry => { :hours => '2.5', :comments => '', :activity_id => Enumeration.activities.first }
707 assert_redirected_to :action => 'show', :id => '1'
709 issue = Issue.find(1)
711 j = issue.journals.find(:first, :order => 'id DESC')
712 assert_equal '2.5 hours added', j.notes
713 assert_equal 0, j.details.size
715 t = issue.time_entries.find(:first, :order => 'id DESC')
717 assert_equal 2.5, t.hours
718 assert_equal spent_hours_before + 2.5, issue.spent_hours
721 def test_post_edit_with_attachment_only
722 set_tmp_attachments_directory
724 # Delete all fixtured journals, a race condition can occur causing the wrong
725 # journal to get fetched in the next find.
732 :attachments => {'1' => {'file' => test_uploaded_file('testfile.txt', 'text/plain')}}
733 assert_redirected_to :action => 'show', :id => '1'
734 j = Issue.find(1).journals.find(:first, :order => 'id DESC')
735 assert j.notes.blank?
736 assert_equal 1, j.details.size
737 assert_equal 'testfile.txt', j.details.first.value
738 assert_equal User.anonymous, j.user
740 mail = ActionMailer::Base.deliveries.last
741 assert mail.body.include?('testfile.txt')
744 def test_post_edit_with_no_change
745 issue = Issue.find(1)
747 ActionMailer::Base.deliveries.clear
752 assert_redirected_to :action => 'show', :id => '1'
755 assert issue.journals.empty?
756 # No email should be sent
757 assert ActionMailer::Base.deliveries.empty?
760 def test_post_edit_with_invalid_spent_time
761 @request.session[:user_id] = 2
762 notes = 'Note added by IssuesControllerTest#test_post_edit_with_invalid_spent_time'
764 assert_no_difference('Journal.count') do
768 :time_entry => {"comments"=>"", "activity_id"=>"", "hours"=>"2z"}
770 assert_response :success
771 assert_template 'edit'
773 assert_tag :textarea, :attributes => { :name => 'notes' },
775 assert_tag :input, :attributes => { :name => 'time_entry[hours]', :value => "2z" }
779 @request.session[:user_id] = 2
780 # update issues priority
781 post :bulk_edit, :ids => [1, 2], :priority_id => 7,
782 :assigned_to_id => '',
783 :custom_field_values => {'2' => ''},
784 :notes => 'Bulk editing'
786 # check that the issues were updated
787 assert_equal [7, 7], Issue.find_all_by_id([1, 2]).collect {|i| i.priority.id}
789 issue = Issue.find(1)
790 journal = issue.journals.find(:first, :order => 'created_on DESC')
791 assert_equal '125', issue.custom_value_for(2).value
792 assert_equal 'Bulk editing', journal.notes
793 assert_equal 1, journal.details.size
796 def test_bulk_edit_custom_field
797 @request.session[:user_id] = 2
798 # update issues priority
799 post :bulk_edit, :ids => [1, 2], :priority_id => '',
800 :assigned_to_id => '',
801 :custom_field_values => {'2' => '777'},
802 :notes => 'Bulk editing custom field'
805 issue = Issue.find(1)
806 journal = issue.journals.find(:first, :order => 'created_on DESC')
807 assert_equal '777', issue.custom_value_for(2).value
808 assert_equal 1, journal.details.size
809 assert_equal '125', journal.details.first.old_value
810 assert_equal '777', journal.details.first.value
813 def test_bulk_unassign
814 assert_not_nil Issue.find(2).assigned_to
815 @request.session[:user_id] = 2
817 post :bulk_edit, :ids => [1, 2], :notes => 'Bulk unassigning', :assigned_to_id => 'none'
819 # check that the issues were updated
820 assert_nil Issue.find(2).assigned_to
823 def test_move_routing
825 {:method => :get, :path => '/issues/1/move'},
826 :controller => 'issues', :action => 'move', :id => '1'
829 {:controller => 'issues', :action => 'move', :id => '1'},
830 {:method => :post, :path => '/issues/1/move'}
834 def test_move_one_issue_to_another_project
835 @request.session[:user_id] = 1
836 post :move, :id => 1, :new_project_id => 2
837 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
838 assert_equal 2, Issue.find(1).project_id
841 def test_bulk_move_to_another_project
842 @request.session[:user_id] = 1
843 post :move, :ids => [1, 2], :new_project_id => 2
844 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
845 # Issues moved to project 2
846 assert_equal 2, Issue.find(1).project_id
847 assert_equal 2, Issue.find(2).project_id
849 assert_equal 1, Issue.find(1).tracker_id
850 assert_equal 2, Issue.find(2).tracker_id
853 def test_bulk_move_to_another_tracker
854 @request.session[:user_id] = 1
855 post :move, :ids => [1, 2], :new_tracker_id => 2
856 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
857 assert_equal 2, Issue.find(1).tracker_id
858 assert_equal 2, Issue.find(2).tracker_id
861 def test_bulk_copy_to_another_project
862 @request.session[:user_id] = 1
863 assert_difference 'Issue.count', 2 do
864 assert_no_difference 'Project.find(1).issues.count' do
865 post :move, :ids => [1, 2], :new_project_id => 2, :copy_options => {:copy => '1'}
868 assert_redirected_to 'projects/ecookbook/issues'
871 def test_context_menu_one_issue
872 @request.session[:user_id] = 2
873 get :context_menu, :ids => [1]
874 assert_response :success
875 assert_template 'context_menu'
876 assert_tag :tag => 'a', :content => 'Edit',
877 :attributes => { :href => '/issues/1/edit',
878 :class => 'icon-edit' }
879 assert_tag :tag => 'a', :content => 'Closed',
880 :attributes => { :href => '/issues/1/edit?issue%5Bstatus_id%5D=5',
882 assert_tag :tag => 'a', :content => 'Immediate',
883 :attributes => { :href => '/issues/bulk_edit?ids%5B%5D=1&priority_id=8',
885 assert_tag :tag => 'a', :content => 'Dave Lopper',
886 :attributes => { :href => '/issues/bulk_edit?assigned_to_id=3&ids%5B%5D=1',
888 assert_tag :tag => 'a', :content => 'Copy',
889 :attributes => { :href => '/projects/ecookbook/issues/1/copy',
890 :class => 'icon-copy' }
891 assert_tag :tag => 'a', :content => 'Move',
892 :attributes => { :href => '/issues/move?ids%5B%5D=1',
893 :class => 'icon-move' }
894 assert_tag :tag => 'a', :content => 'Delete',
895 :attributes => { :href => '/issues/destroy?ids%5B%5D=1',
896 :class => 'icon-del' }
899 def test_context_menu_one_issue_by_anonymous
900 get :context_menu, :ids => [1]
901 assert_response :success
902 assert_template 'context_menu'
903 assert_tag :tag => 'a', :content => 'Delete',
904 :attributes => { :href => '#',
905 :class => 'icon-del disabled' }
908 def test_context_menu_multiple_issues_of_same_project
909 @request.session[:user_id] = 2
910 get :context_menu, :ids => [1, 2]
911 assert_response :success
912 assert_template 'context_menu'
913 assert_tag :tag => 'a', :content => 'Edit',
914 :attributes => { :href => '/issues/bulk_edit?ids%5B%5D=1&ids%5B%5D=2',
915 :class => 'icon-edit' }
916 assert_tag :tag => 'a', :content => 'Immediate',
917 :attributes => { :href => '/issues/bulk_edit?ids%5B%5D=1&ids%5B%5D=2&priority_id=8',
919 assert_tag :tag => 'a', :content => 'Dave Lopper',
920 :attributes => { :href => '/issues/bulk_edit?assigned_to_id=3&ids%5B%5D=1&ids%5B%5D=2',
922 assert_tag :tag => 'a', :content => 'Move',
923 :attributes => { :href => '/issues/move?ids%5B%5D=1&ids%5B%5D=2',
924 :class => 'icon-move' }
925 assert_tag :tag => 'a', :content => 'Delete',
926 :attributes => { :href => '/issues/destroy?ids%5B%5D=1&ids%5B%5D=2',
927 :class => 'icon-del' }
930 def test_context_menu_multiple_issues_of_different_project
931 @request.session[:user_id] = 2
932 get :context_menu, :ids => [1, 2, 4]
933 assert_response :success
934 assert_template 'context_menu'
935 assert_tag :tag => 'a', :content => 'Delete',
936 :attributes => { :href => '#',
937 :class => 'icon-del disabled' }
940 def test_destroy_routing
941 assert_recognizes( #TODO: use DELETE on issue URI (need to change forms)
942 {:controller => 'issues', :action => 'destroy', :id => '1'},
943 {:method => :post, :path => '/issues/1/destroy'}
947 def test_destroy_issue_with_no_time_entries
948 assert_nil TimeEntry.find_by_issue_id(2)
949 @request.session[:user_id] = 2
950 post :destroy, :id => 2
951 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
952 assert_nil Issue.find_by_id(2)
955 def test_destroy_issues_with_time_entries
956 @request.session[:user_id] = 2
957 post :destroy, :ids => [1, 3]
958 assert_response :success
959 assert_template 'destroy'
960 assert_not_nil assigns(:hours)
961 assert Issue.find_by_id(1) && Issue.find_by_id(3)
964 def test_destroy_issues_and_destroy_time_entries
965 @request.session[:user_id] = 2
966 post :destroy, :ids => [1, 3], :todo => 'destroy'
967 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
968 assert !(Issue.find_by_id(1) || Issue.find_by_id(3))
969 assert_nil TimeEntry.find_by_id([1, 2])
972 def test_destroy_issues_and_assign_time_entries_to_project
973 @request.session[:user_id] = 2
974 post :destroy, :ids => [1, 3], :todo => 'nullify'
975 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
976 assert !(Issue.find_by_id(1) || Issue.find_by_id(3))
977 assert_nil TimeEntry.find(1).issue_id
978 assert_nil TimeEntry.find(2).issue_id
981 def test_destroy_issues_and_reassign_time_entries_to_another_issue
982 @request.session[:user_id] = 2
983 post :destroy, :ids => [1, 3], :todo => 'reassign', :reassign_to_id => 2
984 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
985 assert !(Issue.find_by_id(1) || Issue.find_by_id(3))
986 assert_equal 2, TimeEntry.find(1).issue_id
987 assert_equal 2, TimeEntry.find(2).issue_id