765f7abc60
Patch supplied by commits from Gerrit Kaiser on Github. Existing routes will still work (backwards compatible) but any new urls will be generated using the new routing rules. Changes listed below: * made the URLs for some project tabs and project settings follow the new rails RESTful conventions of /collection/:id/subcollection/:sub_id * prettier URL for project roadmap * more nice project URLs * use GET for filtering form * prettified URLs used on issues tab * custom route for activity atom feeds * prettier repository urls * fixed broken route definition * fixed failing tests for issuecontroller that were hardcoding the url string * more RESTful routes for boards and messages * RESTful routes for wiki pages * RESTful routes for documents * moved old routes that are retained for compatibility to the bottom and grouped them together * added RESTful URIs for issues * RESTfulness for the news section * fixed route order * changed hardcoded URLs in tests * fixed badly written tests * fixed forgotten parameter in routes * changed hardcoded URLS to new scheme * changed project add url to the standard POST to collection * create new issue by POSTing to collection * changed hardcoded URLs in integrations tests * made project add form work again * restful routes for project deletion * prettier routes for project (un)archival * made routes table more readable * fixed note quoting * user routing * fixed bug * always sort by GET * Fixed: cross-project issue list should not show issues of projects for which the issue tracking module was disabled. * prettified URLs used on issues tab * urls for time log * fixed reply routing * eliminate revision query paremeter for diff and entry actions * fixed test failures with hard-coded urls * ensure ajax links always use get * refactored ajax link generation into separate method #1901 git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@2317 e93f8b46-1217-0410-a6f0-8f06a7374b81
949 lines
34 KiB
Ruby
949 lines
34 KiB
Ruby
# Redmine - project management software
|
|
# Copyright (C) 2006-2008 Jean-Philippe Lang
|
|
#
|
|
# This program is free software; you can redistribute it and/or
|
|
# modify it under the terms of the GNU General Public License
|
|
# as published by the Free Software Foundation; either version 2
|
|
# of the License, or (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program; if not, write to the Free Software
|
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
require File.dirname(__FILE__) + '/../test_helper'
|
|
require 'issues_controller'
|
|
|
|
# Re-raise errors caught by the controller.
|
|
class IssuesController; def rescue_action(e) raise e end; end
|
|
|
|
class IssuesControllerTest < Test::Unit::TestCase
|
|
fixtures :projects,
|
|
:users,
|
|
:roles,
|
|
:members,
|
|
:issues,
|
|
:issue_statuses,
|
|
:versions,
|
|
:trackers,
|
|
:projects_trackers,
|
|
:issue_categories,
|
|
:enabled_modules,
|
|
:enumerations,
|
|
:attachments,
|
|
:workflows,
|
|
:custom_fields,
|
|
:custom_values,
|
|
:custom_fields_trackers,
|
|
:time_entries,
|
|
:journals,
|
|
:journal_details
|
|
|
|
def setup
|
|
@controller = IssuesController.new
|
|
@request = ActionController::TestRequest.new
|
|
@response = ActionController::TestResponse.new
|
|
User.current = nil
|
|
end
|
|
|
|
def test_index_routing
|
|
assert_routing(
|
|
{:method => :get, :path => '/issues'},
|
|
:controller => 'issues', :action => 'index'
|
|
)
|
|
end
|
|
|
|
def test_index
|
|
get :index
|
|
assert_response :success
|
|
assert_template 'index.rhtml'
|
|
assert_not_nil assigns(:issues)
|
|
assert_nil assigns(:project)
|
|
assert_tag :tag => 'a', :content => /Can't print recipes/
|
|
assert_tag :tag => 'a', :content => /Subproject issue/
|
|
# private projects hidden
|
|
assert_no_tag :tag => 'a', :content => /Issue of a private subproject/
|
|
assert_no_tag :tag => 'a', :content => /Issue on project 2/
|
|
end
|
|
|
|
def test_index_should_not_list_issues_when_module_disabled
|
|
EnabledModule.delete_all("name = 'issue_tracking' AND project_id = 1")
|
|
get :index
|
|
assert_response :success
|
|
assert_template 'index.rhtml'
|
|
assert_not_nil assigns(:issues)
|
|
assert_nil assigns(:project)
|
|
assert_no_tag :tag => 'a', :content => /Can't print recipes/
|
|
assert_tag :tag => 'a', :content => /Subproject issue/
|
|
end
|
|
|
|
def test_index_with_project_routing
|
|
assert_routing(
|
|
{:method => :get, :path => '/projects/23/issues'},
|
|
:controller => 'issues', :action => 'index', :project_id => '23'
|
|
)
|
|
end
|
|
|
|
def test_index_should_not_list_issues_when_module_disabled
|
|
EnabledModule.delete_all("name = 'issue_tracking' AND project_id = 1")
|
|
get :index
|
|
assert_response :success
|
|
assert_template 'index.rhtml'
|
|
assert_not_nil assigns(:issues)
|
|
assert_nil assigns(:project)
|
|
assert_no_tag :tag => 'a', :content => /Can't print recipes/
|
|
assert_tag :tag => 'a', :content => /Subproject issue/
|
|
end
|
|
|
|
def test_index_with_project_routing
|
|
assert_routing(
|
|
{:method => :get, :path => 'projects/23/issues'},
|
|
:controller => 'issues', :action => 'index', :project_id => '23'
|
|
)
|
|
end
|
|
|
|
def test_index_with_project
|
|
Setting.display_subprojects_issues = 0
|
|
get :index, :project_id => 1
|
|
assert_response :success
|
|
assert_template 'index.rhtml'
|
|
assert_not_nil assigns(:issues)
|
|
assert_tag :tag => 'a', :content => /Can't print recipes/
|
|
assert_no_tag :tag => 'a', :content => /Subproject issue/
|
|
end
|
|
|
|
def test_index_with_project_and_subprojects
|
|
Setting.display_subprojects_issues = 1
|
|
get :index, :project_id => 1
|
|
assert_response :success
|
|
assert_template 'index.rhtml'
|
|
assert_not_nil assigns(:issues)
|
|
assert_tag :tag => 'a', :content => /Can't print recipes/
|
|
assert_tag :tag => 'a', :content => /Subproject issue/
|
|
assert_no_tag :tag => 'a', :content => /Issue of a private subproject/
|
|
end
|
|
|
|
def test_index_with_project_and_subprojects_should_show_private_subprojects
|
|
@request.session[:user_id] = 2
|
|
Setting.display_subprojects_issues = 1
|
|
get :index, :project_id => 1
|
|
assert_response :success
|
|
assert_template 'index.rhtml'
|
|
assert_not_nil assigns(:issues)
|
|
assert_tag :tag => 'a', :content => /Can't print recipes/
|
|
assert_tag :tag => 'a', :content => /Subproject issue/
|
|
assert_tag :tag => 'a', :content => /Issue of a private subproject/
|
|
end
|
|
|
|
def test_index_with_project_routing_formatted
|
|
assert_routing(
|
|
{:method => :get, :path => 'projects/23/issues.pdf'},
|
|
:controller => 'issues', :action => 'index', :project_id => '23', :format => 'pdf'
|
|
)
|
|
assert_routing(
|
|
{:method => :get, :path => 'projects/23/issues.atom'},
|
|
:controller => 'issues', :action => 'index', :project_id => '23', :format => 'atom'
|
|
)
|
|
end
|
|
|
|
def test_index_with_project_and_filter
|
|
get :index, :project_id => 1, :set_filter => 1
|
|
assert_response :success
|
|
assert_template 'index.rhtml'
|
|
assert_not_nil assigns(:issues)
|
|
end
|
|
|
|
def test_index_csv_with_project
|
|
get :index, :format => 'csv'
|
|
assert_response :success
|
|
assert_not_nil assigns(:issues)
|
|
assert_equal 'text/csv', @response.content_type
|
|
|
|
get :index, :project_id => 1, :format => 'csv'
|
|
assert_response :success
|
|
assert_not_nil assigns(:issues)
|
|
assert_equal 'text/csv', @response.content_type
|
|
end
|
|
|
|
def test_index_formatted
|
|
assert_routing(
|
|
{:method => :get, :path => 'issues.pdf'},
|
|
:controller => 'issues', :action => 'index', :format => 'pdf'
|
|
)
|
|
assert_routing(
|
|
{:method => :get, :path => 'issues.atom'},
|
|
:controller => 'issues', :action => 'index', :format => 'atom'
|
|
)
|
|
end
|
|
|
|
def test_index_pdf
|
|
get :index, :format => 'pdf'
|
|
assert_response :success
|
|
assert_not_nil assigns(:issues)
|
|
assert_equal 'application/pdf', @response.content_type
|
|
|
|
get :index, :project_id => 1, :format => 'pdf'
|
|
assert_response :success
|
|
assert_not_nil assigns(:issues)
|
|
assert_equal 'application/pdf', @response.content_type
|
|
end
|
|
|
|
def test_index_sort
|
|
get :index, :sort_key => 'tracker'
|
|
assert_response :success
|
|
|
|
sort_params = @request.session['issuesindex_sort']
|
|
assert sort_params.is_a?(Hash)
|
|
assert_equal 'tracker', sort_params[:key]
|
|
assert_equal 'ASC', sort_params[:order]
|
|
end
|
|
|
|
def test_gantt
|
|
get :gantt, :project_id => 1
|
|
assert_response :success
|
|
assert_template 'gantt.rhtml'
|
|
assert_not_nil assigns(:gantt)
|
|
events = assigns(:gantt).events
|
|
assert_not_nil events
|
|
# Issue with start and due dates
|
|
i = Issue.find(1)
|
|
assert_not_nil i.due_date
|
|
assert events.include?(Issue.find(1))
|
|
# Issue with without due date but targeted to a version with date
|
|
i = Issue.find(2)
|
|
assert_nil i.due_date
|
|
assert events.include?(i)
|
|
end
|
|
|
|
def test_cross_project_gantt
|
|
get :gantt
|
|
assert_response :success
|
|
assert_template 'gantt.rhtml'
|
|
assert_not_nil assigns(:gantt)
|
|
events = assigns(:gantt).events
|
|
assert_not_nil events
|
|
end
|
|
|
|
def test_gantt_export_to_pdf
|
|
get :gantt, :project_id => 1, :format => 'pdf'
|
|
assert_response :success
|
|
assert_equal 'application/pdf', @response.content_type
|
|
assert @response.body.starts_with?('%PDF')
|
|
assert_not_nil assigns(:gantt)
|
|
end
|
|
|
|
def test_cross_project_gantt_export_to_pdf
|
|
get :gantt, :format => 'pdf'
|
|
assert_response :success
|
|
assert_equal 'application/pdf', @response.content_type
|
|
assert @response.body.starts_with?('%PDF')
|
|
assert_not_nil assigns(:gantt)
|
|
end
|
|
|
|
if Object.const_defined?(:Magick)
|
|
def test_gantt_image
|
|
get :gantt, :project_id => 1, :format => 'png'
|
|
assert_response :success
|
|
assert_equal 'image/png', @response.content_type
|
|
end
|
|
else
|
|
puts "RMagick not installed. Skipping tests !!!"
|
|
end
|
|
|
|
def test_calendar
|
|
get :calendar, :project_id => 1
|
|
assert_response :success
|
|
assert_template 'calendar'
|
|
assert_not_nil assigns(:calendar)
|
|
end
|
|
|
|
def test_cross_project_calendar
|
|
get :calendar
|
|
assert_response :success
|
|
assert_template 'calendar'
|
|
assert_not_nil assigns(:calendar)
|
|
end
|
|
|
|
def test_changes
|
|
get :changes, :project_id => 1
|
|
assert_response :success
|
|
assert_not_nil assigns(:journals)
|
|
assert_equal 'application/atom+xml', @response.content_type
|
|
end
|
|
|
|
def test_show_routing
|
|
assert_routing(
|
|
{:method => :get, :path => '/issues/64'},
|
|
:controller => 'issues', :action => 'show', :id => '64'
|
|
)
|
|
end
|
|
|
|
def test_show_routing_formatted
|
|
assert_routing(
|
|
{:method => :get, :path => '/issues/2332.pdf'},
|
|
:controller => 'issues', :action => 'show', :id => '2332', :format => 'pdf'
|
|
)
|
|
assert_routing(
|
|
{:method => :get, :path => '/issues/23123.atom'},
|
|
:controller => 'issues', :action => 'show', :id => '23123', :format => 'atom'
|
|
)
|
|
end
|
|
|
|
def test_show_by_anonymous
|
|
get :show, :id => 1
|
|
assert_response :success
|
|
assert_template 'show.rhtml'
|
|
assert_not_nil assigns(:issue)
|
|
assert_equal Issue.find(1), assigns(:issue)
|
|
|
|
# anonymous role is allowed to add a note
|
|
assert_tag :tag => 'form',
|
|
:descendant => { :tag => 'fieldset',
|
|
:child => { :tag => 'legend',
|
|
:content => /Notes/ } }
|
|
end
|
|
|
|
def test_show_by_manager
|
|
@request.session[:user_id] = 2
|
|
get :show, :id => 1
|
|
assert_response :success
|
|
|
|
assert_tag :tag => 'form',
|
|
:descendant => { :tag => 'fieldset',
|
|
:child => { :tag => 'legend',
|
|
:content => /Change properties/ } },
|
|
:descendant => { :tag => 'fieldset',
|
|
:child => { :tag => 'legend',
|
|
:content => /Log time/ } },
|
|
:descendant => { :tag => 'fieldset',
|
|
:child => { :tag => 'legend',
|
|
:content => /Notes/ } }
|
|
end
|
|
|
|
def test_new_routing
|
|
assert_routing(
|
|
{:method => :get, :path => '/projects/1/issues/new'},
|
|
:controller => 'issues', :action => 'new', :project_id => '1'
|
|
)
|
|
assert_recognizes(
|
|
{:controller => 'issues', :action => 'new', :project_id => '1'},
|
|
{:method => :post, :path => '/projects/1/issues'}
|
|
)
|
|
end
|
|
|
|
def test_show_export_to_pdf
|
|
get :show, :id => 3, :format => 'pdf'
|
|
assert_response :success
|
|
assert_equal 'application/pdf', @response.content_type
|
|
assert @response.body.starts_with?('%PDF')
|
|
assert_not_nil assigns(:issue)
|
|
end
|
|
|
|
def test_get_new
|
|
@request.session[:user_id] = 2
|
|
get :new, :project_id => 1, :tracker_id => 1
|
|
assert_response :success
|
|
assert_template 'new'
|
|
|
|
assert_tag :tag => 'input', :attributes => { :name => 'issue[custom_field_values][2]',
|
|
:value => 'Default string' }
|
|
end
|
|
|
|
def test_get_new_without_tracker_id
|
|
@request.session[:user_id] = 2
|
|
get :new, :project_id => 1
|
|
assert_response :success
|
|
assert_template 'new'
|
|
|
|
issue = assigns(:issue)
|
|
assert_not_nil issue
|
|
assert_equal Project.find(1).trackers.first, issue.tracker
|
|
end
|
|
|
|
def test_update_new_form
|
|
@request.session[:user_id] = 2
|
|
xhr :post, :new, :project_id => 1,
|
|
:issue => {:tracker_id => 2,
|
|
:subject => 'This is the test_new issue',
|
|
:description => 'This is the description',
|
|
:priority_id => 5}
|
|
assert_response :success
|
|
assert_template 'new'
|
|
end
|
|
|
|
def test_post_new
|
|
@request.session[:user_id] = 2
|
|
post :new, :project_id => 1,
|
|
:issue => {:tracker_id => 3,
|
|
:subject => 'This is the test_new issue',
|
|
:description => 'This is the description',
|
|
:priority_id => 5,
|
|
:estimated_hours => '',
|
|
:custom_field_values => {'2' => 'Value for field 2'}}
|
|
assert_redirected_to :action => 'show'
|
|
|
|
issue = Issue.find_by_subject('This is the test_new issue')
|
|
assert_not_nil issue
|
|
assert_equal 2, issue.author_id
|
|
assert_equal 3, issue.tracker_id
|
|
assert_nil issue.estimated_hours
|
|
v = issue.custom_values.find(:first, :conditions => {:custom_field_id => 2})
|
|
assert_not_nil v
|
|
assert_equal 'Value for field 2', v.value
|
|
end
|
|
|
|
def test_post_new_and_continue
|
|
@request.session[:user_id] = 2
|
|
post :new, :project_id => 1,
|
|
:issue => {:tracker_id => 3,
|
|
:subject => 'This is first issue',
|
|
:priority_id => 5},
|
|
:continue => ''
|
|
assert_redirected_to :controller => 'issues', :action => 'new', :tracker_id => 3
|
|
end
|
|
|
|
def test_post_new_without_custom_fields_param
|
|
@request.session[:user_id] = 2
|
|
post :new, :project_id => 1,
|
|
:issue => {:tracker_id => 1,
|
|
:subject => 'This is the test_new issue',
|
|
:description => 'This is the description',
|
|
:priority_id => 5}
|
|
assert_redirected_to :action => 'show'
|
|
end
|
|
|
|
def test_post_new_with_required_custom_field_and_without_custom_fields_param
|
|
field = IssueCustomField.find_by_name('Database')
|
|
field.update_attribute(:is_required, true)
|
|
|
|
@request.session[:user_id] = 2
|
|
post :new, :project_id => 1,
|
|
:issue => {:tracker_id => 1,
|
|
:subject => 'This is the test_new issue',
|
|
:description => 'This is the description',
|
|
:priority_id => 5}
|
|
assert_response :success
|
|
assert_template 'new'
|
|
issue = assigns(:issue)
|
|
assert_not_nil issue
|
|
assert_equal 'activerecord_error_invalid', issue.errors.on(:custom_values)
|
|
end
|
|
|
|
def test_post_new_with_watchers
|
|
@request.session[:user_id] = 2
|
|
ActionMailer::Base.deliveries.clear
|
|
|
|
assert_difference 'Watcher.count', 2 do
|
|
post :new, :project_id => 1,
|
|
:issue => {:tracker_id => 1,
|
|
:subject => 'This is a new issue with watchers',
|
|
:description => 'This is the description',
|
|
:priority_id => 5,
|
|
:watcher_user_ids => ['2', '3']}
|
|
end
|
|
issue = Issue.find_by_subject('This is a new issue with watchers')
|
|
assert_not_nil issue
|
|
assert_redirected_to :controller => 'issues', :action => 'show', :id => issue
|
|
|
|
# Watchers added
|
|
assert_equal [2, 3], issue.watcher_user_ids.sort
|
|
assert issue.watched_by?(User.find(3))
|
|
# Watchers notified
|
|
mail = ActionMailer::Base.deliveries.last
|
|
assert_kind_of TMail::Mail, mail
|
|
assert [mail.bcc, mail.cc].flatten.include?(User.find(3).mail)
|
|
end
|
|
|
|
def test_post_should_preserve_fields_values_on_validation_failure
|
|
@request.session[:user_id] = 2
|
|
post :new, :project_id => 1,
|
|
:issue => {:tracker_id => 1,
|
|
# empty subject
|
|
:subject => '',
|
|
:description => 'This is a description',
|
|
:priority_id => 6,
|
|
:custom_field_values => {'1' => 'Oracle', '2' => 'Value for field 2'}}
|
|
assert_response :success
|
|
assert_template 'new'
|
|
|
|
assert_tag :textarea, :attributes => { :name => 'issue[description]' },
|
|
:content => 'This is a description'
|
|
assert_tag :select, :attributes => { :name => 'issue[priority_id]' },
|
|
:child => { :tag => 'option', :attributes => { :selected => 'selected',
|
|
:value => '6' },
|
|
:content => 'High' }
|
|
# Custom fields
|
|
assert_tag :select, :attributes => { :name => 'issue[custom_field_values][1]' },
|
|
:child => { :tag => 'option', :attributes => { :selected => 'selected',
|
|
:value => 'Oracle' },
|
|
:content => 'Oracle' }
|
|
assert_tag :input, :attributes => { :name => 'issue[custom_field_values][2]',
|
|
:value => 'Value for field 2'}
|
|
end
|
|
|
|
def test_copy_routing
|
|
assert_routing(
|
|
{:method => :get, :path => '/projects/world_domination/issues/567/copy'},
|
|
:controller => 'issues', :action => 'new', :project_id => 'world_domination', :copy_from => '567'
|
|
)
|
|
end
|
|
|
|
def test_copy_issue
|
|
@request.session[:user_id] = 2
|
|
get :new, :project_id => 1, :copy_from => 1
|
|
assert_template 'new'
|
|
assert_not_nil assigns(:issue)
|
|
orig = Issue.find(1)
|
|
assert_equal orig.subject, assigns(:issue).subject
|
|
end
|
|
|
|
def test_edit_routing
|
|
assert_routing(
|
|
{:method => :get, :path => '/issues/1/edit'},
|
|
:controller => 'issues', :action => 'edit', :id => '1'
|
|
)
|
|
assert_recognizes( #TODO: use a PUT on the issue URI isntead, need to adjust form
|
|
{:controller => 'issues', :action => 'edit', :id => '1'},
|
|
{:method => :post, :path => '/issues/1/edit'}
|
|
)
|
|
end
|
|
|
|
def test_get_edit
|
|
@request.session[:user_id] = 2
|
|
get :edit, :id => 1
|
|
assert_response :success
|
|
assert_template 'edit'
|
|
assert_not_nil assigns(:issue)
|
|
assert_equal Issue.find(1), assigns(:issue)
|
|
end
|
|
|
|
def test_get_edit_with_params
|
|
@request.session[:user_id] = 2
|
|
get :edit, :id => 1, :issue => { :status_id => 5, :priority_id => 7 }
|
|
assert_response :success
|
|
assert_template 'edit'
|
|
|
|
issue = assigns(:issue)
|
|
assert_not_nil issue
|
|
|
|
assert_equal 5, issue.status_id
|
|
assert_tag :select, :attributes => { :name => 'issue[status_id]' },
|
|
:child => { :tag => 'option',
|
|
:content => 'Closed',
|
|
:attributes => { :selected => 'selected' } }
|
|
|
|
assert_equal 7, issue.priority_id
|
|
assert_tag :select, :attributes => { :name => 'issue[priority_id]' },
|
|
:child => { :tag => 'option',
|
|
:content => 'Urgent',
|
|
:attributes => { :selected => 'selected' } }
|
|
end
|
|
|
|
def test_reply_routing
|
|
assert_routing(
|
|
{:method => :post, :path => '/issues/1/quoted'},
|
|
:controller => 'issues', :action => 'reply', :id => '1'
|
|
)
|
|
end
|
|
|
|
def test_reply_to_issue
|
|
@request.session[:user_id] = 2
|
|
get :reply, :id => 1
|
|
assert_response :success
|
|
assert_select_rjs :show, "update"
|
|
end
|
|
|
|
def test_reply_to_note
|
|
@request.session[:user_id] = 2
|
|
get :reply, :id => 1, :journal_id => 2
|
|
assert_response :success
|
|
assert_select_rjs :show, "update"
|
|
end
|
|
|
|
def test_post_edit_without_custom_fields_param
|
|
@request.session[:user_id] = 2
|
|
ActionMailer::Base.deliveries.clear
|
|
|
|
issue = Issue.find(1)
|
|
assert_equal '125', issue.custom_value_for(2).value
|
|
old_subject = issue.subject
|
|
new_subject = 'Subject modified by IssuesControllerTest#test_post_edit'
|
|
|
|
assert_difference('Journal.count') do
|
|
assert_difference('JournalDetail.count', 2) do
|
|
post :edit, :id => 1, :issue => {:subject => new_subject,
|
|
:priority_id => '6',
|
|
:category_id => '1' # no change
|
|
}
|
|
end
|
|
end
|
|
assert_redirected_to :action => 'show', :id => '1'
|
|
issue.reload
|
|
assert_equal new_subject, issue.subject
|
|
# Make sure custom fields were not cleared
|
|
assert_equal '125', issue.custom_value_for(2).value
|
|
|
|
mail = ActionMailer::Base.deliveries.last
|
|
assert_kind_of TMail::Mail, mail
|
|
assert mail.subject.starts_with?("[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}]")
|
|
assert mail.body.include?("Subject changed from #{old_subject} to #{new_subject}")
|
|
end
|
|
|
|
def test_post_edit_with_custom_field_change
|
|
@request.session[:user_id] = 2
|
|
issue = Issue.find(1)
|
|
assert_equal '125', issue.custom_value_for(2).value
|
|
|
|
assert_difference('Journal.count') do
|
|
assert_difference('JournalDetail.count', 3) do
|
|
post :edit, :id => 1, :issue => {:subject => 'Custom field change',
|
|
:priority_id => '6',
|
|
:category_id => '1', # no change
|
|
:custom_field_values => { '2' => 'New custom value' }
|
|
}
|
|
end
|
|
end
|
|
assert_redirected_to :action => 'show', :id => '1'
|
|
issue.reload
|
|
assert_equal 'New custom value', issue.custom_value_for(2).value
|
|
|
|
mail = ActionMailer::Base.deliveries.last
|
|
assert_kind_of TMail::Mail, mail
|
|
assert mail.body.include?("Searchable field changed from 125 to New custom value")
|
|
end
|
|
|
|
def test_post_edit_with_status_and_assignee_change
|
|
issue = Issue.find(1)
|
|
assert_equal 1, issue.status_id
|
|
@request.session[:user_id] = 2
|
|
assert_difference('TimeEntry.count', 0) do
|
|
post :edit,
|
|
:id => 1,
|
|
:issue => { :status_id => 2, :assigned_to_id => 3 },
|
|
:notes => 'Assigned to dlopper',
|
|
:time_entry => { :hours => '', :comments => '', :activity_id => Enumeration.get_values('ACTI').first }
|
|
end
|
|
assert_redirected_to :action => 'show', :id => '1'
|
|
issue.reload
|
|
assert_equal 2, issue.status_id
|
|
j = issue.journals.find(:first, :order => 'id DESC')
|
|
assert_equal 'Assigned to dlopper', j.notes
|
|
assert_equal 2, j.details.size
|
|
|
|
mail = ActionMailer::Base.deliveries.last
|
|
assert mail.body.include?("Status changed from New to Assigned")
|
|
end
|
|
|
|
def test_post_edit_with_note_only
|
|
notes = 'Note added by IssuesControllerTest#test_update_with_note_only'
|
|
# anonymous user
|
|
post :edit,
|
|
:id => 1,
|
|
:notes => notes
|
|
assert_redirected_to :action => 'show', :id => '1'
|
|
j = Issue.find(1).journals.find(:first, :order => 'id DESC')
|
|
assert_equal notes, j.notes
|
|
assert_equal 0, j.details.size
|
|
assert_equal User.anonymous, j.user
|
|
|
|
mail = ActionMailer::Base.deliveries.last
|
|
assert mail.body.include?(notes)
|
|
end
|
|
|
|
def test_post_edit_with_note_and_spent_time
|
|
@request.session[:user_id] = 2
|
|
spent_hours_before = Issue.find(1).spent_hours
|
|
assert_difference('TimeEntry.count') do
|
|
post :edit,
|
|
:id => 1,
|
|
:notes => '2.5 hours added',
|
|
:time_entry => { :hours => '2.5', :comments => '', :activity_id => Enumeration.get_values('ACTI').first }
|
|
end
|
|
assert_redirected_to :action => 'show', :id => '1'
|
|
|
|
issue = Issue.find(1)
|
|
|
|
j = issue.journals.find(:first, :order => 'id DESC')
|
|
assert_equal '2.5 hours added', j.notes
|
|
assert_equal 0, j.details.size
|
|
|
|
t = issue.time_entries.find(:first, :order => 'id DESC')
|
|
assert_not_nil t
|
|
assert_equal 2.5, t.hours
|
|
assert_equal spent_hours_before + 2.5, issue.spent_hours
|
|
end
|
|
|
|
def test_post_edit_with_attachment_only
|
|
set_tmp_attachments_directory
|
|
|
|
# Delete all fixtured journals, a race condition can occur causing the wrong
|
|
# journal to get fetched in the next find.
|
|
Journal.delete_all
|
|
|
|
# anonymous user
|
|
post :edit,
|
|
:id => 1,
|
|
:notes => '',
|
|
:attachments => {'1' => {'file' => test_uploaded_file('testfile.txt', 'text/plain')}}
|
|
assert_redirected_to :action => 'show', :id => '1'
|
|
j = Issue.find(1).journals.find(:first, :order => 'id DESC')
|
|
assert j.notes.blank?
|
|
assert_equal 1, j.details.size
|
|
assert_equal 'testfile.txt', j.details.first.value
|
|
assert_equal User.anonymous, j.user
|
|
|
|
mail = ActionMailer::Base.deliveries.last
|
|
assert mail.body.include?('testfile.txt')
|
|
end
|
|
|
|
def test_post_edit_with_no_change
|
|
issue = Issue.find(1)
|
|
issue.journals.clear
|
|
ActionMailer::Base.deliveries.clear
|
|
|
|
post :edit,
|
|
:id => 1,
|
|
:notes => ''
|
|
assert_redirected_to :action => 'show', :id => '1'
|
|
|
|
issue.reload
|
|
assert issue.journals.empty?
|
|
# No email should be sent
|
|
assert ActionMailer::Base.deliveries.empty?
|
|
end
|
|
|
|
def test_post_edit_with_invalid_spent_time
|
|
@request.session[:user_id] = 2
|
|
notes = 'Note added by IssuesControllerTest#test_post_edit_with_invalid_spent_time'
|
|
|
|
assert_no_difference('Journal.count') do
|
|
post :edit,
|
|
:id => 1,
|
|
:notes => notes,
|
|
:time_entry => {"comments"=>"", "activity_id"=>"", "hours"=>"2z"}
|
|
end
|
|
assert_response :success
|
|
assert_template 'edit'
|
|
|
|
assert_tag :textarea, :attributes => { :name => 'notes' },
|
|
:content => notes
|
|
assert_tag :input, :attributes => { :name => 'time_entry[hours]', :value => "2z" }
|
|
end
|
|
|
|
def test_bulk_edit
|
|
@request.session[:user_id] = 2
|
|
# update issues priority
|
|
post :bulk_edit, :ids => [1, 2], :priority_id => 7,
|
|
:assigned_to_id => '',
|
|
:custom_field_values => {'2' => ''},
|
|
:notes => 'Bulk editing'
|
|
assert_response 302
|
|
# check that the issues were updated
|
|
assert_equal [7, 7], Issue.find_all_by_id([1, 2]).collect {|i| i.priority.id}
|
|
|
|
issue = Issue.find(1)
|
|
journal = issue.journals.find(:first, :order => 'created_on DESC')
|
|
assert_equal '125', issue.custom_value_for(2).value
|
|
assert_equal 'Bulk editing', journal.notes
|
|
assert_equal 1, journal.details.size
|
|
end
|
|
|
|
def test_bulk_edit_custom_field
|
|
@request.session[:user_id] = 2
|
|
# update issues priority
|
|
post :bulk_edit, :ids => [1, 2], :priority_id => '',
|
|
:assigned_to_id => '',
|
|
:custom_field_values => {'2' => '777'},
|
|
:notes => 'Bulk editing custom field'
|
|
assert_response 302
|
|
|
|
issue = Issue.find(1)
|
|
journal = issue.journals.find(:first, :order => 'created_on DESC')
|
|
assert_equal '777', issue.custom_value_for(2).value
|
|
assert_equal 1, journal.details.size
|
|
assert_equal '125', journal.details.first.old_value
|
|
assert_equal '777', journal.details.first.value
|
|
end
|
|
|
|
def test_bulk_unassign
|
|
assert_not_nil Issue.find(2).assigned_to
|
|
@request.session[:user_id] = 2
|
|
# unassign issues
|
|
post :bulk_edit, :ids => [1, 2], :notes => 'Bulk unassigning', :assigned_to_id => 'none'
|
|
assert_response 302
|
|
# check that the issues were updated
|
|
assert_nil Issue.find(2).assigned_to
|
|
end
|
|
|
|
def test_move_routing
|
|
assert_routing(
|
|
{:method => :get, :path => '/issues/1/move'},
|
|
:controller => 'issues', :action => 'move', :id => '1'
|
|
)
|
|
assert_recognizes(
|
|
{:controller => 'issues', :action => 'move', :id => '1'},
|
|
{:method => :post, :path => '/issues/1/move'}
|
|
)
|
|
end
|
|
|
|
def test_move_one_issue_to_another_project
|
|
@request.session[:user_id] = 1
|
|
post :move, :id => 1, :new_project_id => 2
|
|
assert_redirected_to :action => 'index', :project_id => 'ecookbook'
|
|
assert_equal 2, Issue.find(1).project_id
|
|
end
|
|
|
|
def test_bulk_move_to_another_project
|
|
@request.session[:user_id] = 1
|
|
post :move, :ids => [1, 2], :new_project_id => 2
|
|
assert_redirected_to :action => 'index', :project_id => 'ecookbook'
|
|
# Issues moved to project 2
|
|
assert_equal 2, Issue.find(1).project_id
|
|
assert_equal 2, Issue.find(2).project_id
|
|
# No tracker change
|
|
assert_equal 1, Issue.find(1).tracker_id
|
|
assert_equal 2, Issue.find(2).tracker_id
|
|
end
|
|
|
|
def test_bulk_move_to_another_tracker
|
|
@request.session[:user_id] = 1
|
|
post :move, :ids => [1, 2], :new_tracker_id => 2
|
|
assert_redirected_to :action => 'index', :project_id => 'ecookbook'
|
|
assert_equal 2, Issue.find(1).tracker_id
|
|
assert_equal 2, Issue.find(2).tracker_id
|
|
end
|
|
|
|
def test_bulk_copy_to_another_project
|
|
@request.session[:user_id] = 1
|
|
assert_difference 'Issue.count', 2 do
|
|
assert_no_difference 'Project.find(1).issues.count' do
|
|
post :move, :ids => [1, 2], :new_project_id => 2, :copy_options => {:copy => '1'}
|
|
end
|
|
end
|
|
assert_redirected_to 'projects/ecookbook/issues'
|
|
end
|
|
|
|
def test_context_menu_one_issue
|
|
@request.session[:user_id] = 2
|
|
get :context_menu, :ids => [1]
|
|
assert_response :success
|
|
assert_template 'context_menu'
|
|
assert_tag :tag => 'a', :content => 'Edit',
|
|
:attributes => { :href => '/issues/1/edit',
|
|
:class => 'icon-edit' }
|
|
assert_tag :tag => 'a', :content => 'Closed',
|
|
:attributes => { :href => '/issues/1/edit?issue%5Bstatus_id%5D=5',
|
|
:class => '' }
|
|
assert_tag :tag => 'a', :content => 'Immediate',
|
|
:attributes => { :href => '/issues/bulk_edit?ids%5B%5D=1&priority_id=8',
|
|
:class => '' }
|
|
assert_tag :tag => 'a', :content => 'Dave Lopper',
|
|
:attributes => { :href => '/issues/bulk_edit?assigned_to_id=3&ids%5B%5D=1',
|
|
:class => '' }
|
|
assert_tag :tag => 'a', :content => 'Copy',
|
|
:attributes => { :href => '/projects/ecookbook/issues/1/copy',
|
|
:class => 'icon-copy' }
|
|
assert_tag :tag => 'a', :content => 'Move',
|
|
:attributes => { :href => '/issues/move?ids%5B%5D=1',
|
|
:class => 'icon-move' }
|
|
assert_tag :tag => 'a', :content => 'Delete',
|
|
:attributes => { :href => '/issues/destroy?ids%5B%5D=1',
|
|
:class => 'icon-del' }
|
|
end
|
|
|
|
def test_context_menu_one_issue_by_anonymous
|
|
get :context_menu, :ids => [1]
|
|
assert_response :success
|
|
assert_template 'context_menu'
|
|
assert_tag :tag => 'a', :content => 'Delete',
|
|
:attributes => { :href => '#',
|
|
:class => 'icon-del disabled' }
|
|
end
|
|
|
|
def test_context_menu_multiple_issues_of_same_project
|
|
@request.session[:user_id] = 2
|
|
get :context_menu, :ids => [1, 2]
|
|
assert_response :success
|
|
assert_template 'context_menu'
|
|
assert_tag :tag => 'a', :content => 'Edit',
|
|
:attributes => { :href => '/issues/bulk_edit?ids%5B%5D=1&ids%5B%5D=2',
|
|
:class => 'icon-edit' }
|
|
assert_tag :tag => 'a', :content => 'Immediate',
|
|
:attributes => { :href => '/issues/bulk_edit?ids%5B%5D=1&ids%5B%5D=2&priority_id=8',
|
|
:class => '' }
|
|
assert_tag :tag => 'a', :content => 'Dave Lopper',
|
|
:attributes => { :href => '/issues/bulk_edit?assigned_to_id=3&ids%5B%5D=1&ids%5B%5D=2',
|
|
:class => '' }
|
|
assert_tag :tag => 'a', :content => 'Move',
|
|
:attributes => { :href => '/issues/move?ids%5B%5D=1&ids%5B%5D=2',
|
|
:class => 'icon-move' }
|
|
assert_tag :tag => 'a', :content => 'Delete',
|
|
:attributes => { :href => '/issues/destroy?ids%5B%5D=1&ids%5B%5D=2',
|
|
:class => 'icon-del' }
|
|
end
|
|
|
|
def test_context_menu_multiple_issues_of_different_project
|
|
@request.session[:user_id] = 2
|
|
get :context_menu, :ids => [1, 2, 4]
|
|
assert_response :success
|
|
assert_template 'context_menu'
|
|
assert_tag :tag => 'a', :content => 'Delete',
|
|
:attributes => { :href => '#',
|
|
:class => 'icon-del disabled' }
|
|
end
|
|
|
|
def test_destroy_routing
|
|
assert_recognizes( #TODO: use DELETE on issue URI (need to change forms)
|
|
{:controller => 'issues', :action => 'destroy', :id => '1'},
|
|
{:method => :post, :path => '/issues/1/destroy'}
|
|
)
|
|
end
|
|
|
|
def test_destroy_issue_with_no_time_entries
|
|
assert_nil TimeEntry.find_by_issue_id(2)
|
|
@request.session[:user_id] = 2
|
|
post :destroy, :id => 2
|
|
assert_redirected_to :action => 'index', :project_id => 'ecookbook'
|
|
assert_nil Issue.find_by_id(2)
|
|
end
|
|
|
|
def test_destroy_issues_with_time_entries
|
|
@request.session[:user_id] = 2
|
|
post :destroy, :ids => [1, 3]
|
|
assert_response :success
|
|
assert_template 'destroy'
|
|
assert_not_nil assigns(:hours)
|
|
assert Issue.find_by_id(1) && Issue.find_by_id(3)
|
|
end
|
|
|
|
def test_destroy_issues_and_destroy_time_entries
|
|
@request.session[:user_id] = 2
|
|
post :destroy, :ids => [1, 3], :todo => 'destroy'
|
|
assert_redirected_to :action => 'index', :project_id => 'ecookbook'
|
|
assert !(Issue.find_by_id(1) || Issue.find_by_id(3))
|
|
assert_nil TimeEntry.find_by_id([1, 2])
|
|
end
|
|
|
|
def test_destroy_issues_and_assign_time_entries_to_project
|
|
@request.session[:user_id] = 2
|
|
post :destroy, :ids => [1, 3], :todo => 'nullify'
|
|
assert_redirected_to :action => 'index', :project_id => 'ecookbook'
|
|
assert !(Issue.find_by_id(1) || Issue.find_by_id(3))
|
|
assert_nil TimeEntry.find(1).issue_id
|
|
assert_nil TimeEntry.find(2).issue_id
|
|
end
|
|
|
|
def test_destroy_issues_and_reassign_time_entries_to_another_issue
|
|
@request.session[:user_id] = 2
|
|
post :destroy, :ids => [1, 3], :todo => 'reassign', :reassign_to_id => 2
|
|
assert_redirected_to :action => 'index', :project_id => 'ecookbook'
|
|
assert !(Issue.find_by_id(1) || Issue.find_by_id(3))
|
|
assert_equal 2, TimeEntry.find(1).issue_id
|
|
assert_equal 2, TimeEntry.find(2).issue_id
|
|
end
|
|
end
|