##// END OF EJS Templates
Fixed: empty list for user/version custom fields on bulk edit form (#2096)....
Jean-Philippe Lang -
r5234:d0ea5fae62b1
parent child
Show More
@@ -1,118 +1,118
1 1 # Redmine - project management software
2 2 # Copyright (C) 2006-2011 Jean-Philippe Lang
3 3 #
4 4 # This program is free software; you can redistribute it and/or
5 5 # modify it under the terms of the GNU General Public License
6 6 # as published by the Free Software Foundation; either version 2
7 7 # of the License, or (at your option) any later version.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU General Public License
15 15 # along with this program; if not, write to the Free Software
16 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 17
18 18 module CustomFieldsHelper
19 19
20 20 def custom_fields_tabs
21 21 tabs = [{:name => 'IssueCustomField', :partial => 'custom_fields/index', :label => :label_issue_plural},
22 22 {:name => 'TimeEntryCustomField', :partial => 'custom_fields/index', :label => :label_spent_time},
23 23 {:name => 'ProjectCustomField', :partial => 'custom_fields/index', :label => :label_project_plural},
24 24 {:name => 'VersionCustomField', :partial => 'custom_fields/index', :label => :label_version_plural},
25 25 {:name => 'UserCustomField', :partial => 'custom_fields/index', :label => :label_user_plural},
26 26 {:name => 'GroupCustomField', :partial => 'custom_fields/index', :label => :label_group_plural},
27 27 {:name => 'TimeEntryActivityCustomField', :partial => 'custom_fields/index', :label => TimeEntryActivity::OptionName},
28 28 {:name => 'IssuePriorityCustomField', :partial => 'custom_fields/index', :label => IssuePriority::OptionName},
29 29 {:name => 'DocumentCategoryCustomField', :partial => 'custom_fields/index', :label => DocumentCategory::OptionName}
30 30 ]
31 31 end
32 32
33 33 # Return custom field html tag corresponding to its format
34 34 def custom_field_tag(name, custom_value)
35 35 custom_field = custom_value.custom_field
36 36 field_name = "#{name}[custom_field_values][#{custom_field.id}]"
37 37 field_id = "#{name}_custom_field_values_#{custom_field.id}"
38 38
39 39 field_format = Redmine::CustomFieldFormat.find_by_name(custom_field.field_format)
40 40 case field_format.try(:edit_as)
41 41 when "date"
42 42 text_field_tag(field_name, custom_value.value, :id => field_id, :size => 10) +
43 43 calendar_for(field_id)
44 44 when "text"
45 45 text_area_tag(field_name, custom_value.value, :id => field_id, :rows => 3, :style => 'width:90%')
46 46 when "bool"
47 47 hidden_field_tag(field_name, '0') + check_box_tag(field_name, '1', custom_value.true?, :id => field_id)
48 48 when "list"
49 49 blank_option = custom_field.is_required? ?
50 50 (custom_field.default_value.blank? ? "<option value=\"\">--- #{l(:actionview_instancetag_blank_option)} ---</option>" : '') :
51 51 '<option></option>'
52 52 select_tag(field_name, blank_option + options_for_select(custom_field.possible_values_options(custom_value.customized), custom_value.value), :id => field_id)
53 53 else
54 54 text_field_tag(field_name, custom_value.value, :id => field_id)
55 55 end
56 56 end
57 57
58 58 # Return custom field label tag
59 59 def custom_field_label_tag(name, custom_value)
60 60 content_tag "label", custom_value.custom_field.name +
61 61 (custom_value.custom_field.is_required? ? " <span class=\"required\">*</span>" : ""),
62 62 :for => "#{name}_custom_field_values_#{custom_value.custom_field.id}",
63 63 :class => (custom_value.errors.empty? ? nil : "error" )
64 64 end
65 65
66 66 # Return custom field tag with its label tag
67 67 def custom_field_tag_with_label(name, custom_value)
68 68 custom_field_label_tag(name, custom_value) + custom_field_tag(name, custom_value)
69 69 end
70 70
71 def custom_field_tag_for_bulk_edit(name, custom_field)
71 def custom_field_tag_for_bulk_edit(name, custom_field, projects)
72 72 field_name = "#{name}[custom_field_values][#{custom_field.id}]"
73 73 field_id = "#{name}_custom_field_values_#{custom_field.id}"
74 74 field_format = Redmine::CustomFieldFormat.find_by_name(custom_field.field_format)
75 75 case field_format.try(:edit_as)
76 76 when "date"
77 77 text_field_tag(field_name, '', :id => field_id, :size => 10) +
78 78 calendar_for(field_id)
79 79 when "text"
80 80 text_area_tag(field_name, '', :id => field_id, :rows => 3, :style => 'width:90%')
81 81 when "bool"
82 82 select_tag(field_name, options_for_select([[l(:label_no_change_option), ''],
83 83 [l(:general_text_yes), '1'],
84 84 [l(:general_text_no), '0']]), :id => field_id)
85 85 when "list"
86 select_tag(field_name, options_for_select([[l(:label_no_change_option), '']] + custom_field.possible_values_options), :id => field_id)
86 select_tag(field_name, options_for_select([[l(:label_no_change_option), '']] + custom_field.possible_values_options(projects)), :id => field_id)
87 87 else
88 88 text_field_tag(field_name, '', :id => field_id)
89 89 end
90 90 end
91 91
92 92 # Return a string used to display a custom value
93 93 def show_value(custom_value)
94 94 return "" unless custom_value
95 95 format_value(custom_value.value, custom_value.custom_field.field_format)
96 96 end
97 97
98 98 # Return a string used to display a custom value
99 99 def format_value(value, field_format)
100 100 Redmine::CustomFieldFormat.format_value(value, field_format) # Proxy
101 101 end
102 102
103 103 # Return an array of custom field formats which can be used in select_tag
104 104 def custom_field_formats_for_select(custom_field)
105 105 Redmine::CustomFieldFormat.as_select(custom_field.class.customized_class.name)
106 106 end
107 107
108 108 # Renders the custom_values in api views
109 109 def render_api_custom_values(custom_values, api)
110 110 api.array :custom_fields do
111 111 custom_values.each do |custom_value|
112 112 api.custom_field :id => custom_value.custom_field_id, :name => custom_value.custom_field.name do
113 113 api.value custom_value.value
114 114 end
115 115 end
116 116 end unless custom_values.empty?
117 117 end
118 118 end
@@ -1,149 +1,151
1 1 # Redmine - project management software
2 2 # Copyright (C) 2006-2011 Jean-Philippe Lang
3 3 #
4 4 # This program is free software; you can redistribute it and/or
5 5 # modify it under the terms of the GNU General Public License
6 6 # as published by the Free Software Foundation; either version 2
7 7 # of the License, or (at your option) any later version.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU General Public License
15 15 # along with this program; if not, write to the Free Software
16 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 17
18 18 class CustomField < ActiveRecord::Base
19 19 has_many :custom_values, :dependent => :delete_all
20 20 acts_as_list :scope => 'type = \'#{self.class}\''
21 21 serialize :possible_values
22 22
23 23 validates_presence_of :name, :field_format
24 24 validates_uniqueness_of :name, :scope => :type
25 25 validates_length_of :name, :maximum => 30
26 26 validates_inclusion_of :field_format, :in => Redmine::CustomFieldFormat.available_formats
27 27
28 28 def initialize(attributes = nil)
29 29 super
30 30 self.possible_values ||= []
31 31 end
32 32
33 33 def before_validation
34 34 # make sure these fields are not searchable
35 35 self.searchable = false if %w(int float date bool).include?(field_format)
36 36 true
37 37 end
38 38
39 39 def validate
40 40 if self.field_format == "list"
41 41 errors.add(:possible_values, :blank) if self.possible_values.nil? || self.possible_values.empty?
42 42 errors.add(:possible_values, :invalid) unless self.possible_values.is_a? Array
43 43 end
44 44
45 45 # validate default value
46 46 v = CustomValue.new(:custom_field => self.clone, :value => default_value, :customized => nil)
47 47 v.custom_field.is_required = false
48 48 errors.add(:default_value, :invalid) unless v.valid?
49 49 end
50 50
51 51 def possible_values_options(obj=nil)
52 52 case field_format
53 53 when 'user', 'version'
54 54 if obj.respond_to?(:project) && obj.project
55 55 case field_format
56 56 when 'user'
57 57 obj.project.users.sort.collect {|u| [u.to_s, u.id.to_s]}
58 58 when 'version'
59 59 obj.project.versions.sort.collect {|u| [u.to_s, u.id.to_s]}
60 60 end
61 elsif obj.is_a?(Array)
62 obj.collect {|o| possible_values_options(o)}.inject {|memo, v| memo & v}
61 63 else
62 64 []
63 65 end
64 66 else
65 67 read_attribute :possible_values
66 68 end
67 69 end
68 70
69 71 def possible_values(obj=nil)
70 72 case field_format
71 73 when 'user', 'version'
72 74 possible_values_options(obj).collect(&:last)
73 75 else
74 76 read_attribute :possible_values
75 77 end
76 78 end
77 79
78 80 # Makes possible_values accept a multiline string
79 81 def possible_values=(arg)
80 82 if arg.is_a?(Array)
81 83 write_attribute(:possible_values, arg.compact.collect(&:strip).select {|v| !v.blank?})
82 84 else
83 85 self.possible_values = arg.to_s.split(/[\n\r]+/)
84 86 end
85 87 end
86 88
87 89 def cast_value(value)
88 90 casted = nil
89 91 unless value.blank?
90 92 case field_format
91 93 when 'string', 'text', 'list'
92 94 casted = value
93 95 when 'date'
94 96 casted = begin; value.to_date; rescue; nil end
95 97 when 'bool'
96 98 casted = (value == '1' ? true : false)
97 99 when 'int'
98 100 casted = value.to_i
99 101 when 'float'
100 102 casted = value.to_f
101 103 when 'user', 'version'
102 104 casted = (value.blank? ? nil : field_format.classify.constantize.find_by_id(value.to_i))
103 105 end
104 106 end
105 107 casted
106 108 end
107 109
108 110 # Returns a ORDER BY clause that can used to sort customized
109 111 # objects by their value of the custom field.
110 112 # Returns false, if the custom field can not be used for sorting.
111 113 def order_statement
112 114 case field_format
113 115 when 'string', 'text', 'list', 'date', 'bool'
114 116 # COALESCE is here to make sure that blank and NULL values are sorted equally
115 117 "COALESCE((SELECT cv_sort.value FROM #{CustomValue.table_name} cv_sort" +
116 118 " WHERE cv_sort.customized_type='#{self.class.customized_class.name}'" +
117 119 " AND cv_sort.customized_id=#{self.class.customized_class.table_name}.id" +
118 120 " AND cv_sort.custom_field_id=#{id} LIMIT 1), '')"
119 121 when 'int', 'float'
120 122 # Make the database cast values into numeric
121 123 # Postgresql will raise an error if a value can not be casted!
122 124 # CustomValue validations should ensure that it doesn't occur
123 125 "(SELECT CAST(cv_sort.value AS decimal(60,3)) FROM #{CustomValue.table_name} cv_sort" +
124 126 " WHERE cv_sort.customized_type='#{self.class.customized_class.name}'" +
125 127 " AND cv_sort.customized_id=#{self.class.customized_class.table_name}.id" +
126 128 " AND cv_sort.custom_field_id=#{id} AND cv_sort.value <> '' AND cv_sort.value IS NOT NULL LIMIT 1)"
127 129 else
128 130 nil
129 131 end
130 132 end
131 133
132 134 def <=>(field)
133 135 position <=> field.position
134 136 end
135 137
136 138 def self.customized_class
137 139 self.name =~ /^(.+)CustomField$/
138 140 begin; $1.constantize; rescue nil; end
139 141 end
140 142
141 143 # to move in project_custom_field
142 144 def self.for_all
143 145 find(:all, :conditions => ["is_for_all=?", true], :order => 'position')
144 146 end
145 147
146 148 def type_name
147 149 nil
148 150 end
149 151 end
@@ -1,91 +1,91
1 1 <h2><%= l(:label_bulk_edit_selected_issues) %></h2>
2 2
3 3 <ul><%= @issues.collect {|i| content_tag('li', link_to(h("#{i.tracker} ##{i.id}"), { :action => 'show', :id => i }) + h(": #{i.subject}")) }.join("\n") %></ul>
4 4
5 5 <% form_tag(:action => 'bulk_update') do %>
6 6 <%= @issues.collect {|i| hidden_field_tag('ids[]', i.id)}.join %>
7 7 <div class="box tabular">
8 8 <fieldset class="attributes">
9 9 <legend><%= l(:label_change_properties) %></legend>
10 10
11 11 <div class="splitcontentleft">
12 12 <p>
13 13 <label><%= l(:field_tracker) %></label>
14 14 <%= select_tag('issue[tracker_id]', "<option value=\"\">#{l(:label_no_change_option)}</option>" + options_from_collection_for_select(@trackers, :id, :name)) %>
15 15 </p>
16 16 <% if @available_statuses.any? %>
17 17 <p>
18 18 <label><%= l(:field_status) %></label>
19 19 <%= select_tag('issue[status_id]', "<option value=\"\">#{l(:label_no_change_option)}</option>" + options_from_collection_for_select(@available_statuses, :id, :name)) %>
20 20 </p>
21 21 <% end %>
22 22 <p>
23 23 <label><%= l(:field_priority) %></label>
24 24 <%= select_tag('issue[priority_id]', "<option value=\"\">#{l(:label_no_change_option)}</option>" + options_from_collection_for_select(IssuePriority.all, :id, :name)) %>
25 25 </p>
26 26 <p>
27 27 <label><%= l(:field_assigned_to) %></label>
28 28 <%= select_tag('issue[assigned_to_id]', content_tag('option', l(:label_no_change_option), :value => '') +
29 29 content_tag('option', l(:label_nobody), :value => 'none') +
30 30 options_from_collection_for_select(@assignables, :id, :name)) %>
31 31 </p>
32 32 <% if @project %>
33 33 <p>
34 34 <label><%= l(:field_category) %></label>
35 35 <%= select_tag('issue[category_id]', content_tag('option', l(:label_no_change_option), :value => '') +
36 36 content_tag('option', l(:label_none), :value => 'none') +
37 37 options_from_collection_for_select(@project.issue_categories, :id, :name)) %>
38 38 </p>
39 39 <% end %>
40 40 <% #TODO: allow editing versions when multiple projects %>
41 41 <% if @project %>
42 42 <p>
43 43 <label><%= l(:field_fixed_version) %></label>
44 44 <%= select_tag('issue[fixed_version_id]', content_tag('option', l(:label_no_change_option), :value => '') +
45 45 content_tag('option', l(:label_none), :value => 'none') +
46 46 version_options_for_select(@project.shared_versions.open.sort)) %>
47 47 </p>
48 48 <% end %>
49 49
50 50 <% @custom_fields.each do |custom_field| %>
51 <p><label><%= h(custom_field.name) %></label> <%= custom_field_tag_for_bulk_edit('issue', custom_field) %></p>
51 <p><label><%= h(custom_field.name) %></label> <%= custom_field_tag_for_bulk_edit('issue', custom_field, @projects) %></p>
52 52 <% end %>
53 53
54 54 <%= call_hook(:view_issues_bulk_edit_details_bottom, { :issues => @issues }) %>
55 55 </div>
56 56
57 57 <div class="splitcontentright">
58 58 <% if @project && User.current.allowed_to?(:manage_subtasks, @project) %>
59 59 <p>
60 60 <label><%= l(:field_parent_issue) %></label>
61 61 <%= text_field_tag 'issue[parent_issue_id]', '', :size => 10 %>
62 62 </p>
63 63 <div id="parent_issue_candidates" class="autocomplete"></div>
64 64 <%= javascript_tag "observeParentIssueField('#{auto_complete_issues_path(:project_id => @project) }')" %>
65 65 <% end %>
66 66 <p>
67 67 <label><%= l(:field_start_date) %></label>
68 68 <%= text_field_tag 'issue[start_date]', '', :size => 10 %><%= calendar_for('issue_start_date') %>
69 69 </p>
70 70 <p>
71 71 <label><%= l(:field_due_date) %></label>
72 72 <%= text_field_tag 'issue[due_date]', '', :size => 10 %><%= calendar_for('issue_due_date') %>
73 73 </p>
74 74 <% if Issue.use_field_for_done_ratio? %>
75 75 <p>
76 76 <label><%= l(:field_done_ratio) %></label>
77 77 <%= select_tag 'issue[done_ratio]', options_for_select([[l(:label_no_change_option), '']] + (0..10).to_a.collect {|r| ["#{r*10} %", r*10] }) %>
78 78 </p>
79 79 <% end %>
80 80 </div>
81 81
82 82 </fieldset>
83 83
84 84 <fieldset><legend><%= l(:field_notes) %></legend>
85 85 <%= text_area_tag 'notes', @notes, :cols => 60, :rows => 10, :class => 'wiki-edit' %>
86 86 <%= wikitoolbar_for 'notes' %>
87 87 </fieldset>
88 88 </div>
89 89
90 90 <p><%= submit_tag l(:button_submit) %></p>
91 91 <% end %>
@@ -1,49 +1,49
1 1 <h2><%= l(:label_bulk_edit_selected_time_entries) %></h2>
2 2
3 3 <ul><%= @time_entries.collect {|i| content_tag('li', link_to(h("#{i.spent_on.strftime("%Y-%m-%d")} -- #{i.project}: #{l(:label_f_hour_plural, :value => i.hours)}"), { :action => 'edit', :id => i }))} %></ul>
4 4
5 5 <% form_tag(:action => 'bulk_update') do %>
6 6 <%= @time_entries.collect {|i| hidden_field_tag('ids[]', i.id)}.join %>
7 7 <div class="box tabular">
8 8 <fieldset class="attributes">
9 9 <legend><%= l(:label_change_properties) %></legend>
10 10 <div>
11 11 <p>
12 12 <label><%= l(:field_issue) %></label>
13 13 <%= text_field :time_entry, :issue_id, :size => 6 %>
14 14 </p>
15 15
16 16 <p>
17 17 <label><%= l(:field_spent_on) %></label>
18 18 <%= text_field :time_entry, :spent_on, :size => 10 %><%= calendar_for('time_entry_spent_on') %>
19 19 </p>
20 20
21 21 <p>
22 22 <label><%= l(:field_hours) %></label>
23 23 <%= text_field :time_entry, :hours, :size => 6 %>
24 24 </p>
25 25
26 26 <% if @available_activities.any? %>
27 27 <p>
28 28 <label><%= l(:field_activity) %></label>
29 29 <%= select_tag('time_entry[activity_id]', "<option value=\"\">#{l(:label_no_change_option)}</option>" + options_from_collection_for_select(@available_activities, :id, :name)) %>
30 30 </p>
31 31 <% end %>
32 32
33 33 <p>
34 34 <label><%= l(:field_comments) %></label>
35 35 <%= text_field(:time_entry, :comments, :size => 100) %>
36 36 </p>
37 37
38 38 <% @custom_fields.each do |custom_field| %>
39 <p><label><%= h(custom_field.name) %></label> <%= custom_field_tag_for_bulk_edit('time_entry', custom_field) %></p>
39 <p><label><%= h(custom_field.name) %></label> <%= custom_field_tag_for_bulk_edit('time_entry', custom_field, @projects) %></p>
40 40 <% end %>
41 41
42 42 <%= call_hook(:view_time_entries_bulk_edit_details_bottom, { :time_entries => @time_entries }) %>
43 43 </div>
44 44
45 45 </fieldset>
46 46 </div>
47 47
48 48 <p><%= submit_tag l(:button_submit) %></p>
49 49 <% end %>
@@ -1,1348 +1,1380
1 1 # Redmine - project management software
2 # Copyright (C) 2006-2008 Jean-Philippe Lang
2 # Copyright (C) 2006-2011 Jean-Philippe Lang
3 3 #
4 4 # This program is free software; you can redistribute it and/or
5 5 # modify it under the terms of the GNU General Public License
6 6 # as published by the Free Software Foundation; either version 2
7 7 # of the License, or (at your option) any later version.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU General Public License
15 15 # along with this program; if not, write to the Free Software
16 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 17
18 18 require File.expand_path('../../test_helper', __FILE__)
19 19 require 'issues_controller'
20 20
21 21 # Re-raise errors caught by the controller.
22 22 class IssuesController; def rescue_action(e) raise e end; end
23 23
24 24 class IssuesControllerTest < ActionController::TestCase
25 25 fixtures :projects,
26 26 :users,
27 27 :roles,
28 28 :members,
29 29 :member_roles,
30 30 :issues,
31 31 :issue_statuses,
32 32 :versions,
33 33 :trackers,
34 34 :projects_trackers,
35 35 :issue_categories,
36 36 :enabled_modules,
37 37 :enumerations,
38 38 :attachments,
39 39 :workflows,
40 40 :custom_fields,
41 41 :custom_values,
42 42 :custom_fields_projects,
43 43 :custom_fields_trackers,
44 44 :time_entries,
45 45 :journals,
46 46 :journal_details,
47 47 :queries
48 48
49 49 def setup
50 50 @controller = IssuesController.new
51 51 @request = ActionController::TestRequest.new
52 52 @response = ActionController::TestResponse.new
53 53 User.current = nil
54 54 end
55 55
56 56 def test_index
57 57 Setting.default_language = 'en'
58 58
59 59 get :index
60 60 assert_response :success
61 61 assert_template 'index.rhtml'
62 62 assert_not_nil assigns(:issues)
63 63 assert_nil assigns(:project)
64 64 assert_tag :tag => 'a', :content => /Can't print recipes/
65 65 assert_tag :tag => 'a', :content => /Subproject issue/
66 66 # private projects hidden
67 67 assert_no_tag :tag => 'a', :content => /Issue of a private subproject/
68 68 assert_no_tag :tag => 'a', :content => /Issue on project 2/
69 69 # project column
70 70 assert_tag :tag => 'th', :content => /Project/
71 71 end
72 72
73 73 def test_index_should_not_list_issues_when_module_disabled
74 74 EnabledModule.delete_all("name = 'issue_tracking' AND project_id = 1")
75 75 get :index
76 76 assert_response :success
77 77 assert_template 'index.rhtml'
78 78 assert_not_nil assigns(:issues)
79 79 assert_nil assigns(:project)
80 80 assert_no_tag :tag => 'a', :content => /Can't print recipes/
81 81 assert_tag :tag => 'a', :content => /Subproject issue/
82 82 end
83 83
84 84 def test_index_should_not_list_issues_when_module_disabled
85 85 EnabledModule.delete_all("name = 'issue_tracking' AND project_id = 1")
86 86 get :index
87 87 assert_response :success
88 88 assert_template 'index.rhtml'
89 89 assert_not_nil assigns(:issues)
90 90 assert_nil assigns(:project)
91 91 assert_no_tag :tag => 'a', :content => /Can't print recipes/
92 92 assert_tag :tag => 'a', :content => /Subproject issue/
93 93 end
94 94
95 95 def test_index_with_project
96 96 Setting.display_subprojects_issues = 0
97 97 get :index, :project_id => 1
98 98 assert_response :success
99 99 assert_template 'index.rhtml'
100 100 assert_not_nil assigns(:issues)
101 101 assert_tag :tag => 'a', :content => /Can't print recipes/
102 102 assert_no_tag :tag => 'a', :content => /Subproject issue/
103 103 end
104 104
105 105 def test_index_with_project_and_subprojects
106 106 Setting.display_subprojects_issues = 1
107 107 get :index, :project_id => 1
108 108 assert_response :success
109 109 assert_template 'index.rhtml'
110 110 assert_not_nil assigns(:issues)
111 111 assert_tag :tag => 'a', :content => /Can't print recipes/
112 112 assert_tag :tag => 'a', :content => /Subproject issue/
113 113 assert_no_tag :tag => 'a', :content => /Issue of a private subproject/
114 114 end
115 115
116 116 def test_index_with_project_and_subprojects_should_show_private_subprojects
117 117 @request.session[:user_id] = 2
118 118 Setting.display_subprojects_issues = 1
119 119 get :index, :project_id => 1
120 120 assert_response :success
121 121 assert_template 'index.rhtml'
122 122 assert_not_nil assigns(:issues)
123 123 assert_tag :tag => 'a', :content => /Can't print recipes/
124 124 assert_tag :tag => 'a', :content => /Subproject issue/
125 125 assert_tag :tag => 'a', :content => /Issue of a private subproject/
126 126 end
127 127
128 128 def test_index_with_project_and_default_filter
129 129 get :index, :project_id => 1, :set_filter => 1
130 130 assert_response :success
131 131 assert_template 'index.rhtml'
132 132 assert_not_nil assigns(:issues)
133 133
134 134 query = assigns(:query)
135 135 assert_not_nil query
136 136 # default filter
137 137 assert_equal({'status_id' => {:operator => 'o', :values => ['']}}, query.filters)
138 138 end
139 139
140 140 def test_index_with_project_and_filter
141 141 get :index, :project_id => 1, :set_filter => 1,
142 142 :f => ['tracker_id'],
143 143 :op => {'tracker_id' => '='},
144 144 :v => {'tracker_id' => ['1']}
145 145 assert_response :success
146 146 assert_template 'index.rhtml'
147 147 assert_not_nil assigns(:issues)
148 148
149 149 query = assigns(:query)
150 150 assert_not_nil query
151 151 assert_equal({'tracker_id' => {:operator => '=', :values => ['1']}}, query.filters)
152 152 end
153 153
154 154 def test_index_with_project_and_empty_filters
155 155 get :index, :project_id => 1, :set_filter => 1, :fields => ['']
156 156 assert_response :success
157 157 assert_template 'index.rhtml'
158 158 assert_not_nil assigns(:issues)
159 159
160 160 query = assigns(:query)
161 161 assert_not_nil query
162 162 # no filter
163 163 assert_equal({}, query.filters)
164 164 end
165 165
166 166 def test_index_with_query
167 167 get :index, :project_id => 1, :query_id => 5
168 168 assert_response :success
169 169 assert_template 'index.rhtml'
170 170 assert_not_nil assigns(:issues)
171 171 assert_nil assigns(:issue_count_by_group)
172 172 end
173 173
174 174 def test_index_with_query_grouped_by_tracker
175 175 get :index, :project_id => 1, :query_id => 6
176 176 assert_response :success
177 177 assert_template 'index.rhtml'
178 178 assert_not_nil assigns(:issues)
179 179 assert_not_nil assigns(:issue_count_by_group)
180 180 end
181 181
182 182 def test_index_with_query_grouped_by_list_custom_field
183 183 get :index, :project_id => 1, :query_id => 9
184 184 assert_response :success
185 185 assert_template 'index.rhtml'
186 186 assert_not_nil assigns(:issues)
187 187 assert_not_nil assigns(:issue_count_by_group)
188 188 end
189 189
190 190 def test_index_sort_by_field_not_included_in_columns
191 191 Setting.issue_list_default_columns = %w(subject author)
192 192 get :index, :sort => 'tracker'
193 193 end
194 194
195 195 def test_index_csv_with_project
196 196 Setting.default_language = 'en'
197 197
198 198 get :index, :format => 'csv'
199 199 assert_response :success
200 200 assert_not_nil assigns(:issues)
201 201 assert_equal 'text/csv', @response.content_type
202 202 assert @response.body.starts_with?("#,")
203 203
204 204 get :index, :project_id => 1, :format => 'csv'
205 205 assert_response :success
206 206 assert_not_nil assigns(:issues)
207 207 assert_equal 'text/csv', @response.content_type
208 208 end
209 209
210 210 def test_index_pdf
211 211 get :index, :format => 'pdf'
212 212 assert_response :success
213 213 assert_not_nil assigns(:issues)
214 214 assert_equal 'application/pdf', @response.content_type
215 215
216 216 get :index, :project_id => 1, :format => 'pdf'
217 217 assert_response :success
218 218 assert_not_nil assigns(:issues)
219 219 assert_equal 'application/pdf', @response.content_type
220 220
221 221 get :index, :project_id => 1, :query_id => 6, :format => 'pdf'
222 222 assert_response :success
223 223 assert_not_nil assigns(:issues)
224 224 assert_equal 'application/pdf', @response.content_type
225 225 end
226 226
227 227 def test_index_pdf_with_query_grouped_by_list_custom_field
228 228 get :index, :project_id => 1, :query_id => 9, :format => 'pdf'
229 229 assert_response :success
230 230 assert_not_nil assigns(:issues)
231 231 assert_not_nil assigns(:issue_count_by_group)
232 232 assert_equal 'application/pdf', @response.content_type
233 233 end
234 234
235 235 def test_index_sort
236 236 get :index, :sort => 'tracker,id:desc'
237 237 assert_response :success
238 238
239 239 sort_params = @request.session['issues_index_sort']
240 240 assert sort_params.is_a?(String)
241 241 assert_equal 'tracker,id:desc', sort_params
242 242
243 243 issues = assigns(:issues)
244 244 assert_not_nil issues
245 245 assert !issues.empty?
246 246 assert_equal issues.sort {|a,b| a.tracker == b.tracker ? b.id <=> a.id : a.tracker <=> b.tracker }.collect(&:id), issues.collect(&:id)
247 247 end
248 248
249 249 def test_index_with_columns
250 250 columns = ['tracker', 'subject', 'assigned_to']
251 251 get :index, :set_filter => 1, :c => columns
252 252 assert_response :success
253 253
254 254 # query should use specified columns
255 255 query = assigns(:query)
256 256 assert_kind_of Query, query
257 257 assert_equal columns, query.column_names.map(&:to_s)
258 258
259 259 # columns should be stored in session
260 260 assert_kind_of Hash, session[:query]
261 261 assert_kind_of Array, session[:query][:column_names]
262 262 assert_equal columns, session[:query][:column_names].map(&:to_s)
263 263 end
264 264
265 265 def test_index_with_custom_field_column
266 266 columns = %w(tracker subject cf_2)
267 267 get :index, :set_filter => 1, :c => columns
268 268 assert_response :success
269 269
270 270 # query should use specified columns
271 271 query = assigns(:query)
272 272 assert_kind_of Query, query
273 273 assert_equal columns, query.column_names.map(&:to_s)
274 274
275 275 assert_tag :td,
276 276 :attributes => {:class => 'cf_2 string'},
277 277 :ancestor => {:tag => 'table', :attributes => {:class => /issues/}}
278 278 end
279 279
280 280 def test_show_by_anonymous
281 281 get :show, :id => 1
282 282 assert_response :success
283 283 assert_template 'show.rhtml'
284 284 assert_not_nil assigns(:issue)
285 285 assert_equal Issue.find(1), assigns(:issue)
286 286
287 287 # anonymous role is allowed to add a note
288 288 assert_tag :tag => 'form',
289 289 :descendant => { :tag => 'fieldset',
290 290 :child => { :tag => 'legend',
291 291 :content => /Notes/ } }
292 292 end
293 293
294 294 def test_show_by_manager
295 295 @request.session[:user_id] = 2
296 296 get :show, :id => 1
297 297 assert_response :success
298 298
299 299 assert_tag :tag => 'a',
300 300 :content => /Quote/
301 301
302 302 assert_tag :tag => 'form',
303 303 :descendant => { :tag => 'fieldset',
304 304 :child => { :tag => 'legend',
305 305 :content => /Change properties/ } },
306 306 :descendant => { :tag => 'fieldset',
307 307 :child => { :tag => 'legend',
308 308 :content => /Log time/ } },
309 309 :descendant => { :tag => 'fieldset',
310 310 :child => { :tag => 'legend',
311 311 :content => /Notes/ } }
312 312 end
313 313
314 314 def test_show_should_deny_anonymous_access_without_permission
315 315 Role.anonymous.remove_permission!(:view_issues)
316 316 get :show, :id => 1
317 317 assert_response :redirect
318 318 end
319 319
320 320 def test_show_should_deny_non_member_access_without_permission
321 321 Role.non_member.remove_permission!(:view_issues)
322 322 @request.session[:user_id] = 9
323 323 get :show, :id => 1
324 324 assert_response 403
325 325 end
326 326
327 327 def test_show_should_deny_member_access_without_permission
328 328 Role.find(1).remove_permission!(:view_issues)
329 329 @request.session[:user_id] = 2
330 330 get :show, :id => 1
331 331 assert_response 403
332 332 end
333 333
334 334 def test_show_should_not_disclose_relations_to_invisible_issues
335 335 Setting.cross_project_issue_relations = '1'
336 336 IssueRelation.create!(:issue_from => Issue.find(1), :issue_to => Issue.find(2), :relation_type => 'relates')
337 337 # Relation to a private project issue
338 338 IssueRelation.create!(:issue_from => Issue.find(1), :issue_to => Issue.find(4), :relation_type => 'relates')
339 339
340 340 get :show, :id => 1
341 341 assert_response :success
342 342
343 343 assert_tag :div, :attributes => { :id => 'relations' },
344 344 :descendant => { :tag => 'a', :content => /#2$/ }
345 345 assert_no_tag :div, :attributes => { :id => 'relations' },
346 346 :descendant => { :tag => 'a', :content => /#4$/ }
347 347 end
348 348
349 349 def test_show_atom
350 350 get :show, :id => 2, :format => 'atom'
351 351 assert_response :success
352 352 assert_template 'journals/index.rxml'
353 353 # Inline image
354 354 assert_select 'content', :text => Regexp.new(Regexp.quote('http://test.host/attachments/download/10'))
355 355 end
356 356
357 357 def test_show_export_to_pdf
358 358 get :show, :id => 3, :format => 'pdf'
359 359 assert_response :success
360 360 assert_equal 'application/pdf', @response.content_type
361 361 assert @response.body.starts_with?('%PDF')
362 362 assert_not_nil assigns(:issue)
363 363 end
364 364
365 365 def test_get_new
366 366 @request.session[:user_id] = 2
367 367 get :new, :project_id => 1, :tracker_id => 1
368 368 assert_response :success
369 369 assert_template 'new'
370 370
371 371 assert_tag :tag => 'input', :attributes => { :name => 'issue[custom_field_values][2]',
372 372 :value => 'Default string' }
373 373 end
374 374
375 375 def test_get_new_without_tracker_id
376 376 @request.session[:user_id] = 2
377 377 get :new, :project_id => 1
378 378 assert_response :success
379 379 assert_template 'new'
380 380
381 381 issue = assigns(:issue)
382 382 assert_not_nil issue
383 383 assert_equal Project.find(1).trackers.first, issue.tracker
384 384 end
385 385
386 386 def test_get_new_with_no_default_status_should_display_an_error
387 387 @request.session[:user_id] = 2
388 388 IssueStatus.delete_all
389 389
390 390 get :new, :project_id => 1
391 391 assert_response 500
392 392 assert_error_tag :content => /No default issue/
393 393 end
394 394
395 395 def test_get_new_with_no_tracker_should_display_an_error
396 396 @request.session[:user_id] = 2
397 397 Tracker.delete_all
398 398
399 399 get :new, :project_id => 1
400 400 assert_response 500
401 401 assert_error_tag :content => /No tracker/
402 402 end
403 403
404 404 def test_update_new_form
405 405 @request.session[:user_id] = 2
406 406 xhr :post, :new, :project_id => 1,
407 407 :issue => {:tracker_id => 2,
408 408 :subject => 'This is the test_new issue',
409 409 :description => 'This is the description',
410 410 :priority_id => 5}
411 411 assert_response :success
412 412 assert_template 'attributes'
413 413
414 414 issue = assigns(:issue)
415 415 assert_kind_of Issue, issue
416 416 assert_equal 1, issue.project_id
417 417 assert_equal 2, issue.tracker_id
418 418 assert_equal 'This is the test_new issue', issue.subject
419 419 end
420 420
421 421 def test_post_create
422 422 @request.session[:user_id] = 2
423 423 assert_difference 'Issue.count' do
424 424 post :create, :project_id => 1,
425 425 :issue => {:tracker_id => 3,
426 426 :status_id => 2,
427 427 :subject => 'This is the test_new issue',
428 428 :description => 'This is the description',
429 429 :priority_id => 5,
430 430 :start_date => '2010-11-07',
431 431 :estimated_hours => '',
432 432 :custom_field_values => {'2' => 'Value for field 2'}}
433 433 end
434 434 assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id
435 435
436 436 issue = Issue.find_by_subject('This is the test_new issue')
437 437 assert_not_nil issue
438 438 assert_equal 2, issue.author_id
439 439 assert_equal 3, issue.tracker_id
440 440 assert_equal 2, issue.status_id
441 441 assert_equal Date.parse('2010-11-07'), issue.start_date
442 442 assert_nil issue.estimated_hours
443 443 v = issue.custom_values.find(:first, :conditions => {:custom_field_id => 2})
444 444 assert_not_nil v
445 445 assert_equal 'Value for field 2', v.value
446 446 end
447 447
448 448 def test_post_create_without_start_date
449 449 @request.session[:user_id] = 2
450 450 assert_difference 'Issue.count' do
451 451 post :create, :project_id => 1,
452 452 :issue => {:tracker_id => 3,
453 453 :status_id => 2,
454 454 :subject => 'This is the test_new issue',
455 455 :description => 'This is the description',
456 456 :priority_id => 5,
457 457 :start_date => '',
458 458 :estimated_hours => '',
459 459 :custom_field_values => {'2' => 'Value for field 2'}}
460 460 end
461 461 assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id
462 462
463 463 issue = Issue.find_by_subject('This is the test_new issue')
464 464 assert_not_nil issue
465 465 assert_nil issue.start_date
466 466 end
467 467
468 468 def test_post_create_and_continue
469 469 @request.session[:user_id] = 2
470 470 post :create, :project_id => 1,
471 471 :issue => {:tracker_id => 3,
472 472 :subject => 'This is first issue',
473 473 :priority_id => 5},
474 474 :continue => ''
475 475 assert_redirected_to :controller => 'issues', :action => 'new', :project_id => 'ecookbook',
476 476 :issue => {:tracker_id => 3}
477 477 end
478 478
479 479 def test_post_create_without_custom_fields_param
480 480 @request.session[:user_id] = 2
481 481 assert_difference 'Issue.count' do
482 482 post :create, :project_id => 1,
483 483 :issue => {:tracker_id => 1,
484 484 :subject => 'This is the test_new issue',
485 485 :description => 'This is the description',
486 486 :priority_id => 5}
487 487 end
488 488 assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id
489 489 end
490 490
491 491 def test_post_create_with_required_custom_field_and_without_custom_fields_param
492 492 field = IssueCustomField.find_by_name('Database')
493 493 field.update_attribute(:is_required, true)
494 494
495 495 @request.session[:user_id] = 2
496 496 post :create, :project_id => 1,
497 497 :issue => {:tracker_id => 1,
498 498 :subject => 'This is the test_new issue',
499 499 :description => 'This is the description',
500 500 :priority_id => 5}
501 501 assert_response :success
502 502 assert_template 'new'
503 503 issue = assigns(:issue)
504 504 assert_not_nil issue
505 505 assert_equal I18n.translate('activerecord.errors.messages.invalid'), issue.errors.on(:custom_values)
506 506 end
507 507
508 508 def test_post_create_with_watchers
509 509 @request.session[:user_id] = 2
510 510 ActionMailer::Base.deliveries.clear
511 511
512 512 assert_difference 'Watcher.count', 2 do
513 513 post :create, :project_id => 1,
514 514 :issue => {:tracker_id => 1,
515 515 :subject => 'This is a new issue with watchers',
516 516 :description => 'This is the description',
517 517 :priority_id => 5,
518 518 :watcher_user_ids => ['2', '3']}
519 519 end
520 520 issue = Issue.find_by_subject('This is a new issue with watchers')
521 521 assert_not_nil issue
522 522 assert_redirected_to :controller => 'issues', :action => 'show', :id => issue
523 523
524 524 # Watchers added
525 525 assert_equal [2, 3], issue.watcher_user_ids.sort
526 526 assert issue.watched_by?(User.find(3))
527 527 # Watchers notified
528 528 mail = ActionMailer::Base.deliveries.last
529 529 assert_kind_of TMail::Mail, mail
530 530 assert [mail.bcc, mail.cc].flatten.include?(User.find(3).mail)
531 531 end
532 532
533 533 def test_post_create_subissue
534 534 @request.session[:user_id] = 2
535 535
536 536 assert_difference 'Issue.count' do
537 537 post :create, :project_id => 1,
538 538 :issue => {:tracker_id => 1,
539 539 :subject => 'This is a child issue',
540 540 :parent_issue_id => 2}
541 541 end
542 542 issue = Issue.find_by_subject('This is a child issue')
543 543 assert_not_nil issue
544 544 assert_equal Issue.find(2), issue.parent
545 545 end
546 546
547 547 def test_post_create_subissue_with_non_numeric_parent_id
548 548 @request.session[:user_id] = 2
549 549
550 550 assert_difference 'Issue.count' do
551 551 post :create, :project_id => 1,
552 552 :issue => {:tracker_id => 1,
553 553 :subject => 'This is a child issue',
554 554 :parent_issue_id => 'ABC'}
555 555 end
556 556 issue = Issue.find_by_subject('This is a child issue')
557 557 assert_not_nil issue
558 558 assert_nil issue.parent
559 559 end
560 560
561 561 def test_post_create_should_send_a_notification
562 562 ActionMailer::Base.deliveries.clear
563 563 @request.session[:user_id] = 2
564 564 assert_difference 'Issue.count' do
565 565 post :create, :project_id => 1,
566 566 :issue => {:tracker_id => 3,
567 567 :subject => 'This is the test_new issue',
568 568 :description => 'This is the description',
569 569 :priority_id => 5,
570 570 :estimated_hours => '',
571 571 :custom_field_values => {'2' => 'Value for field 2'}}
572 572 end
573 573 assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id
574 574
575 575 assert_equal 1, ActionMailer::Base.deliveries.size
576 576 end
577 577
578 578 def test_post_create_should_preserve_fields_values_on_validation_failure
579 579 @request.session[:user_id] = 2
580 580 post :create, :project_id => 1,
581 581 :issue => {:tracker_id => 1,
582 582 # empty subject
583 583 :subject => '',
584 584 :description => 'This is a description',
585 585 :priority_id => 6,
586 586 :custom_field_values => {'1' => 'Oracle', '2' => 'Value for field 2'}}
587 587 assert_response :success
588 588 assert_template 'new'
589 589
590 590 assert_tag :textarea, :attributes => { :name => 'issue[description]' },
591 591 :content => 'This is a description'
592 592 assert_tag :select, :attributes => { :name => 'issue[priority_id]' },
593 593 :child => { :tag => 'option', :attributes => { :selected => 'selected',
594 594 :value => '6' },
595 595 :content => 'High' }
596 596 # Custom fields
597 597 assert_tag :select, :attributes => { :name => 'issue[custom_field_values][1]' },
598 598 :child => { :tag => 'option', :attributes => { :selected => 'selected',
599 599 :value => 'Oracle' },
600 600 :content => 'Oracle' }
601 601 assert_tag :input, :attributes => { :name => 'issue[custom_field_values][2]',
602 602 :value => 'Value for field 2'}
603 603 end
604 604
605 605 def test_post_create_should_ignore_non_safe_attributes
606 606 @request.session[:user_id] = 2
607 607 assert_nothing_raised do
608 608 post :create, :project_id => 1, :issue => { :tracker => "A param can not be a Tracker" }
609 609 end
610 610 end
611 611
612 612 context "without workflow privilege" do
613 613 setup do
614 614 Workflow.delete_all(["role_id = ?", Role.anonymous.id])
615 615 Role.anonymous.add_permission! :add_issues, :add_issue_notes
616 616 end
617 617
618 618 context "#new" do
619 619 should "propose default status only" do
620 620 get :new, :project_id => 1
621 621 assert_response :success
622 622 assert_template 'new'
623 623 assert_tag :tag => 'select',
624 624 :attributes => {:name => 'issue[status_id]'},
625 625 :children => {:count => 1},
626 626 :child => {:tag => 'option', :attributes => {:value => IssueStatus.default.id.to_s}}
627 627 end
628 628
629 629 should "accept default status" do
630 630 assert_difference 'Issue.count' do
631 631 post :create, :project_id => 1,
632 632 :issue => {:tracker_id => 1,
633 633 :subject => 'This is an issue',
634 634 :status_id => 1}
635 635 end
636 636 issue = Issue.last(:order => 'id')
637 637 assert_equal IssueStatus.default, issue.status
638 638 end
639 639
640 640 should "ignore unauthorized status" do
641 641 assert_difference 'Issue.count' do
642 642 post :create, :project_id => 1,
643 643 :issue => {:tracker_id => 1,
644 644 :subject => 'This is an issue',
645 645 :status_id => 3}
646 646 end
647 647 issue = Issue.last(:order => 'id')
648 648 assert_equal IssueStatus.default, issue.status
649 649 end
650 650 end
651 651
652 652 context "#update" do
653 653 should "ignore status change" do
654 654 assert_difference 'Journal.count' do
655 655 put :update, :id => 1, :notes => 'just trying', :issue => {:status_id => 3}
656 656 end
657 657 assert_equal 1, Issue.find(1).status_id
658 658 end
659 659
660 660 should "ignore attributes changes" do
661 661 assert_difference 'Journal.count' do
662 662 put :update, :id => 1, :notes => 'just trying', :issue => {:subject => 'changed', :assigned_to_id => 2}
663 663 end
664 664 issue = Issue.find(1)
665 665 assert_equal "Can't print recipes", issue.subject
666 666 assert_nil issue.assigned_to
667 667 end
668 668 end
669 669 end
670 670
671 671 context "with workflow privilege" do
672 672 setup do
673 673 Workflow.delete_all(["role_id = ?", Role.anonymous.id])
674 674 Workflow.create!(:role => Role.anonymous, :tracker_id => 1, :old_status_id => 1, :new_status_id => 3)
675 675 Workflow.create!(:role => Role.anonymous, :tracker_id => 1, :old_status_id => 1, :new_status_id => 4)
676 676 Role.anonymous.add_permission! :add_issues, :add_issue_notes
677 677 end
678 678
679 679 context "#update" do
680 680 should "accept authorized status" do
681 681 assert_difference 'Journal.count' do
682 682 put :update, :id => 1, :notes => 'just trying', :issue => {:status_id => 3}
683 683 end
684 684 assert_equal 3, Issue.find(1).status_id
685 685 end
686 686
687 687 should "ignore unauthorized status" do
688 688 assert_difference 'Journal.count' do
689 689 put :update, :id => 1, :notes => 'just trying', :issue => {:status_id => 2}
690 690 end
691 691 assert_equal 1, Issue.find(1).status_id
692 692 end
693 693
694 694 should "accept authorized attributes changes" do
695 695 assert_difference 'Journal.count' do
696 696 put :update, :id => 1, :notes => 'just trying', :issue => {:assigned_to_id => 2}
697 697 end
698 698 issue = Issue.find(1)
699 699 assert_equal 2, issue.assigned_to_id
700 700 end
701 701
702 702 should "ignore unauthorized attributes changes" do
703 703 assert_difference 'Journal.count' do
704 704 put :update, :id => 1, :notes => 'just trying', :issue => {:subject => 'changed'}
705 705 end
706 706 issue = Issue.find(1)
707 707 assert_equal "Can't print recipes", issue.subject
708 708 end
709 709 end
710 710
711 711 context "and :edit_issues permission" do
712 712 setup do
713 713 Role.anonymous.add_permission! :add_issues, :edit_issues
714 714 end
715 715
716 716 should "accept authorized status" do
717 717 assert_difference 'Journal.count' do
718 718 put :update, :id => 1, :notes => 'just trying', :issue => {:status_id => 3}
719 719 end
720 720 assert_equal 3, Issue.find(1).status_id
721 721 end
722 722
723 723 should "ignore unauthorized status" do
724 724 assert_difference 'Journal.count' do
725 725 put :update, :id => 1, :notes => 'just trying', :issue => {:status_id => 2}
726 726 end
727 727 assert_equal 1, Issue.find(1).status_id
728 728 end
729 729
730 730 should "accept authorized attributes changes" do
731 731 assert_difference 'Journal.count' do
732 732 put :update, :id => 1, :notes => 'just trying', :issue => {:subject => 'changed', :assigned_to_id => 2}
733 733 end
734 734 issue = Issue.find(1)
735 735 assert_equal "changed", issue.subject
736 736 assert_equal 2, issue.assigned_to_id
737 737 end
738 738 end
739 739 end
740 740
741 741 def test_copy_issue
742 742 @request.session[:user_id] = 2
743 743 get :new, :project_id => 1, :copy_from => 1
744 744 assert_template 'new'
745 745 assert_not_nil assigns(:issue)
746 746 orig = Issue.find(1)
747 747 assert_equal orig.subject, assigns(:issue).subject
748 748 end
749 749
750 750 def test_get_edit
751 751 @request.session[:user_id] = 2
752 752 get :edit, :id => 1
753 753 assert_response :success
754 754 assert_template 'edit'
755 755 assert_not_nil assigns(:issue)
756 756 assert_equal Issue.find(1), assigns(:issue)
757 757 end
758 758
759 759 def test_get_edit_with_params
760 760 @request.session[:user_id] = 2
761 761 get :edit, :id => 1, :issue => { :status_id => 5, :priority_id => 7 },
762 762 :time_entry => { :hours => '2.5', :comments => 'test_get_edit_with_params', :activity_id => TimeEntryActivity.first.id }
763 763 assert_response :success
764 764 assert_template 'edit'
765 765
766 766 issue = assigns(:issue)
767 767 assert_not_nil issue
768 768
769 769 assert_equal 5, issue.status_id
770 770 assert_tag :select, :attributes => { :name => 'issue[status_id]' },
771 771 :child => { :tag => 'option',
772 772 :content => 'Closed',
773 773 :attributes => { :selected => 'selected' } }
774 774
775 775 assert_equal 7, issue.priority_id
776 776 assert_tag :select, :attributes => { :name => 'issue[priority_id]' },
777 777 :child => { :tag => 'option',
778 778 :content => 'Urgent',
779 779 :attributes => { :selected => 'selected' } }
780 780
781 781 assert_tag :input, :attributes => { :name => 'time_entry[hours]', :value => '2.5' }
782 782 assert_tag :select, :attributes => { :name => 'time_entry[activity_id]' },
783 783 :child => { :tag => 'option',
784 784 :attributes => { :selected => 'selected', :value => TimeEntryActivity.first.id } }
785 785 assert_tag :input, :attributes => { :name => 'time_entry[comments]', :value => 'test_get_edit_with_params' }
786 786 end
787 787
788 788 def test_update_edit_form
789 789 @request.session[:user_id] = 2
790 790 xhr :post, :new, :project_id => 1,
791 791 :id => 1,
792 792 :issue => {:tracker_id => 2,
793 793 :subject => 'This is the test_new issue',
794 794 :description => 'This is the description',
795 795 :priority_id => 5}
796 796 assert_response :success
797 797 assert_template 'attributes'
798 798
799 799 issue = assigns(:issue)
800 800 assert_kind_of Issue, issue
801 801 assert_equal 1, issue.id
802 802 assert_equal 1, issue.project_id
803 803 assert_equal 2, issue.tracker_id
804 804 assert_equal 'This is the test_new issue', issue.subject
805 805 end
806 806
807 807 def test_update_using_invalid_http_verbs
808 808 @request.session[:user_id] = 2
809 809 subject = 'Updated by an invalid http verb'
810 810
811 811 get :update, :id => 1, :issue => {:subject => subject}
812 812 assert_not_equal subject, Issue.find(1).subject
813 813
814 814 post :update, :id => 1, :issue => {:subject => subject}
815 815 assert_not_equal subject, Issue.find(1).subject
816 816
817 817 delete :update, :id => 1, :issue => {:subject => subject}
818 818 assert_not_equal subject, Issue.find(1).subject
819 819 end
820 820
821 821 def test_put_update_without_custom_fields_param
822 822 @request.session[:user_id] = 2
823 823 ActionMailer::Base.deliveries.clear
824 824
825 825 issue = Issue.find(1)
826 826 assert_equal '125', issue.custom_value_for(2).value
827 827 old_subject = issue.subject
828 828 new_subject = 'Subject modified by IssuesControllerTest#test_post_edit'
829 829
830 830 assert_difference('Journal.count') do
831 831 assert_difference('JournalDetail.count', 2) do
832 832 put :update, :id => 1, :issue => {:subject => new_subject,
833 833 :priority_id => '6',
834 834 :category_id => '1' # no change
835 835 }
836 836 end
837 837 end
838 838 assert_redirected_to :action => 'show', :id => '1'
839 839 issue.reload
840 840 assert_equal new_subject, issue.subject
841 841 # Make sure custom fields were not cleared
842 842 assert_equal '125', issue.custom_value_for(2).value
843 843
844 844 mail = ActionMailer::Base.deliveries.last
845 845 assert_kind_of TMail::Mail, mail
846 846 assert mail.subject.starts_with?("[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}]")
847 847 assert mail.body.include?("Subject changed from #{old_subject} to #{new_subject}")
848 848 end
849 849
850 850 def test_put_update_with_custom_field_change
851 851 @request.session[:user_id] = 2
852 852 issue = Issue.find(1)
853 853 assert_equal '125', issue.custom_value_for(2).value
854 854
855 855 assert_difference('Journal.count') do
856 856 assert_difference('JournalDetail.count', 3) do
857 857 put :update, :id => 1, :issue => {:subject => 'Custom field change',
858 858 :priority_id => '6',
859 859 :category_id => '1', # no change
860 860 :custom_field_values => { '2' => 'New custom value' }
861 861 }
862 862 end
863 863 end
864 864 assert_redirected_to :action => 'show', :id => '1'
865 865 issue.reload
866 866 assert_equal 'New custom value', issue.custom_value_for(2).value
867 867
868 868 mail = ActionMailer::Base.deliveries.last
869 869 assert_kind_of TMail::Mail, mail
870 870 assert mail.body.include?("Searchable field changed from 125 to New custom value")
871 871 end
872 872
873 873 def test_put_update_with_status_and_assignee_change
874 874 issue = Issue.find(1)
875 875 assert_equal 1, issue.status_id
876 876 @request.session[:user_id] = 2
877 877 assert_difference('TimeEntry.count', 0) do
878 878 put :update,
879 879 :id => 1,
880 880 :issue => { :status_id => 2, :assigned_to_id => 3 },
881 881 :notes => 'Assigned to dlopper',
882 882 :time_entry => { :hours => '', :comments => '', :activity_id => TimeEntryActivity.first }
883 883 end
884 884 assert_redirected_to :action => 'show', :id => '1'
885 885 issue.reload
886 886 assert_equal 2, issue.status_id
887 887 j = Journal.find(:first, :order => 'id DESC')
888 888 assert_equal 'Assigned to dlopper', j.notes
889 889 assert_equal 2, j.details.size
890 890
891 891 mail = ActionMailer::Base.deliveries.last
892 892 assert mail.body.include?("Status changed from New to Assigned")
893 893 # subject should contain the new status
894 894 assert mail.subject.include?("(#{ IssueStatus.find(2).name })")
895 895 end
896 896
897 897 def test_put_update_with_note_only
898 898 notes = 'Note added by IssuesControllerTest#test_update_with_note_only'
899 899 # anonymous user
900 900 put :update,
901 901 :id => 1,
902 902 :notes => notes
903 903 assert_redirected_to :action => 'show', :id => '1'
904 904 j = Journal.find(:first, :order => 'id DESC')
905 905 assert_equal notes, j.notes
906 906 assert_equal 0, j.details.size
907 907 assert_equal User.anonymous, j.user
908 908
909 909 mail = ActionMailer::Base.deliveries.last
910 910 assert mail.body.include?(notes)
911 911 end
912 912
913 913 def test_put_update_with_note_and_spent_time
914 914 @request.session[:user_id] = 2
915 915 spent_hours_before = Issue.find(1).spent_hours
916 916 assert_difference('TimeEntry.count') do
917 917 put :update,
918 918 :id => 1,
919 919 :notes => '2.5 hours added',
920 920 :time_entry => { :hours => '2.5', :comments => 'test_put_update_with_note_and_spent_time', :activity_id => TimeEntryActivity.first.id }
921 921 end
922 922 assert_redirected_to :action => 'show', :id => '1'
923 923
924 924 issue = Issue.find(1)
925 925
926 926 j = Journal.find(:first, :order => 'id DESC')
927 927 assert_equal '2.5 hours added', j.notes
928 928 assert_equal 0, j.details.size
929 929
930 930 t = issue.time_entries.find_by_comments('test_put_update_with_note_and_spent_time')
931 931 assert_not_nil t
932 932 assert_equal 2.5, t.hours
933 933 assert_equal spent_hours_before + 2.5, issue.spent_hours
934 934 end
935 935
936 936 def test_put_update_with_attachment_only
937 937 set_tmp_attachments_directory
938 938
939 939 # Delete all fixtured journals, a race condition can occur causing the wrong
940 940 # journal to get fetched in the next find.
941 941 Journal.delete_all
942 942
943 943 # anonymous user
944 944 put :update,
945 945 :id => 1,
946 946 :notes => '',
947 947 :attachments => {'1' => {'file' => uploaded_test_file('testfile.txt', 'text/plain')}}
948 948 assert_redirected_to :action => 'show', :id => '1'
949 949 j = Issue.find(1).journals.find(:first, :order => 'id DESC')
950 950 assert j.notes.blank?
951 951 assert_equal 1, j.details.size
952 952 assert_equal 'testfile.txt', j.details.first.value
953 953 assert_equal User.anonymous, j.user
954 954
955 955 mail = ActionMailer::Base.deliveries.last
956 956 assert mail.body.include?('testfile.txt')
957 957 end
958 958
959 959 def test_put_update_with_attachment_that_fails_to_save
960 960 set_tmp_attachments_directory
961 961
962 962 # Delete all fixtured journals, a race condition can occur causing the wrong
963 963 # journal to get fetched in the next find.
964 964 Journal.delete_all
965 965
966 966 # Mock out the unsaved attachment
967 967 Attachment.any_instance.stubs(:create).returns(Attachment.new)
968 968
969 969 # anonymous user
970 970 put :update,
971 971 :id => 1,
972 972 :notes => '',
973 973 :attachments => {'1' => {'file' => uploaded_test_file('testfile.txt', 'text/plain')}}
974 974 assert_redirected_to :action => 'show', :id => '1'
975 975 assert_equal '1 file(s) could not be saved.', flash[:warning]
976 976
977 977 end if Object.const_defined?(:Mocha)
978 978
979 979 def test_put_update_with_no_change
980 980 issue = Issue.find(1)
981 981 issue.journals.clear
982 982 ActionMailer::Base.deliveries.clear
983 983
984 984 put :update,
985 985 :id => 1,
986 986 :notes => ''
987 987 assert_redirected_to :action => 'show', :id => '1'
988 988
989 989 issue.reload
990 990 assert issue.journals.empty?
991 991 # No email should be sent
992 992 assert ActionMailer::Base.deliveries.empty?
993 993 end
994 994
995 995 def test_put_update_should_send_a_notification
996 996 @request.session[:user_id] = 2
997 997 ActionMailer::Base.deliveries.clear
998 998 issue = Issue.find(1)
999 999 old_subject = issue.subject
1000 1000 new_subject = 'Subject modified by IssuesControllerTest#test_post_edit'
1001 1001
1002 1002 put :update, :id => 1, :issue => {:subject => new_subject,
1003 1003 :priority_id => '6',
1004 1004 :category_id => '1' # no change
1005 1005 }
1006 1006 assert_equal 1, ActionMailer::Base.deliveries.size
1007 1007 end
1008 1008
1009 1009 def test_put_update_with_invalid_spent_time_hours_only
1010 1010 @request.session[:user_id] = 2
1011 1011 notes = 'Note added by IssuesControllerTest#test_post_edit_with_invalid_spent_time'
1012 1012
1013 1013 assert_no_difference('Journal.count') do
1014 1014 put :update,
1015 1015 :id => 1,
1016 1016 :notes => notes,
1017 1017 :time_entry => {"comments"=>"", "activity_id"=>"", "hours"=>"2z"}
1018 1018 end
1019 1019 assert_response :success
1020 1020 assert_template 'edit'
1021 1021
1022 1022 assert_error_tag :descendant => {:content => /Activity can't be blank/}
1023 1023 assert_tag :textarea, :attributes => { :name => 'notes' }, :content => notes
1024 1024 assert_tag :input, :attributes => { :name => 'time_entry[hours]', :value => "2z" }
1025 1025 end
1026 1026
1027 1027 def test_put_update_with_invalid_spent_time_comments_only
1028 1028 @request.session[:user_id] = 2
1029 1029 notes = 'Note added by IssuesControllerTest#test_post_edit_with_invalid_spent_time'
1030 1030
1031 1031 assert_no_difference('Journal.count') do
1032 1032 put :update,
1033 1033 :id => 1,
1034 1034 :notes => notes,
1035 1035 :time_entry => {"comments"=>"this is my comment", "activity_id"=>"", "hours"=>""}
1036 1036 end
1037 1037 assert_response :success
1038 1038 assert_template 'edit'
1039 1039
1040 1040 assert_error_tag :descendant => {:content => /Activity can't be blank/}
1041 1041 assert_error_tag :descendant => {:content => /Hours can't be blank/}
1042 1042 assert_tag :textarea, :attributes => { :name => 'notes' }, :content => notes
1043 1043 assert_tag :input, :attributes => { :name => 'time_entry[comments]', :value => "this is my comment" }
1044 1044 end
1045 1045
1046 1046 def test_put_update_should_allow_fixed_version_to_be_set_to_a_subproject
1047 1047 issue = Issue.find(2)
1048 1048 @request.session[:user_id] = 2
1049 1049
1050 1050 put :update,
1051 1051 :id => issue.id,
1052 1052 :issue => {
1053 1053 :fixed_version_id => 4
1054 1054 }
1055 1055
1056 1056 assert_response :redirect
1057 1057 issue.reload
1058 1058 assert_equal 4, issue.fixed_version_id
1059 1059 assert_not_equal issue.project_id, issue.fixed_version.project_id
1060 1060 end
1061 1061
1062 1062 def test_put_update_should_redirect_back_using_the_back_url_parameter
1063 1063 issue = Issue.find(2)
1064 1064 @request.session[:user_id] = 2
1065 1065
1066 1066 put :update,
1067 1067 :id => issue.id,
1068 1068 :issue => {
1069 1069 :fixed_version_id => 4
1070 1070 },
1071 1071 :back_url => '/issues'
1072 1072
1073 1073 assert_response :redirect
1074 1074 assert_redirected_to '/issues'
1075 1075 end
1076 1076
1077 1077 def test_put_update_should_not_redirect_back_using_the_back_url_parameter_off_the_host
1078 1078 issue = Issue.find(2)
1079 1079 @request.session[:user_id] = 2
1080 1080
1081 1081 put :update,
1082 1082 :id => issue.id,
1083 1083 :issue => {
1084 1084 :fixed_version_id => 4
1085 1085 },
1086 1086 :back_url => 'http://google.com'
1087 1087
1088 1088 assert_response :redirect
1089 1089 assert_redirected_to :controller => 'issues', :action => 'show', :id => issue.id
1090 1090 end
1091 1091
1092 1092 def test_get_bulk_edit
1093 1093 @request.session[:user_id] = 2
1094 1094 get :bulk_edit, :ids => [1, 2]
1095 1095 assert_response :success
1096 1096 assert_template 'bulk_edit'
1097 1097
1098 1098 assert_tag :input, :attributes => {:name => 'issue[parent_issue_id]'}
1099 1099
1100 1100 # Project specific custom field, date type
1101 1101 field = CustomField.find(9)
1102 1102 assert !field.is_for_all?
1103 1103 assert_equal 'date', field.field_format
1104 1104 assert_tag :input, :attributes => {:name => 'issue[custom_field_values][9]'}
1105 1105
1106 1106 # System wide custom field
1107 1107 assert CustomField.find(1).is_for_all?
1108 1108 assert_tag :select, :attributes => {:name => 'issue[custom_field_values][1]'}
1109 1109 end
1110 1110
1111 1111 def test_get_bulk_edit_on_different_projects
1112 1112 @request.session[:user_id] = 2
1113 1113 get :bulk_edit, :ids => [1, 2, 6]
1114 1114 assert_response :success
1115 1115 assert_template 'bulk_edit'
1116 1116
1117 1117 # Can not set issues from different projects as children of an issue
1118 1118 assert_no_tag :input, :attributes => {:name => 'issue[parent_issue_id]'}
1119 1119
1120 1120 # Project specific custom field, date type
1121 1121 field = CustomField.find(9)
1122 1122 assert !field.is_for_all?
1123 1123 assert !field.project_ids.include?(Issue.find(6).project_id)
1124 1124 assert_no_tag :input, :attributes => {:name => 'issue[custom_field_values][9]'}
1125 1125 end
1126
1127 def test_get_bulk_edit_with_user_custom_field
1128 field = IssueCustomField.create!(:name => 'Tester', :field_format => 'user', :is_for_all => true)
1129
1130 @request.session[:user_id] = 2
1131 get :bulk_edit, :ids => [1, 2]
1132 assert_response :success
1133 assert_template 'bulk_edit'
1134
1135 assert_tag :select,
1136 :attributes => {:name => "issue[custom_field_values][#{field.id}]"},
1137 :children => {
1138 :only => {:tag => 'option'},
1139 :count => Project.find(1).users.count + 1
1140 }
1141 end
1142
1143 def test_get_bulk_edit_with_version_custom_field
1144 field = IssueCustomField.create!(:name => 'Affected version', :field_format => 'version', :is_for_all => true)
1145
1146 @request.session[:user_id] = 2
1147 get :bulk_edit, :ids => [1, 2]
1148 assert_response :success
1149 assert_template 'bulk_edit'
1150
1151 assert_tag :select,
1152 :attributes => {:name => "issue[custom_field_values][#{field.id}]"},
1153 :children => {
1154 :only => {:tag => 'option'},
1155 :count => Project.find(1).versions.count + 1
1156 }
1157 end
1126 1158
1127 1159 def test_bulk_update
1128 1160 @request.session[:user_id] = 2
1129 1161 # update issues priority
1130 1162 post :bulk_update, :ids => [1, 2], :notes => 'Bulk editing',
1131 1163 :issue => {:priority_id => 7,
1132 1164 :assigned_to_id => '',
1133 1165 :custom_field_values => {'2' => ''}}
1134 1166
1135 1167 assert_response 302
1136 1168 # check that the issues were updated
1137 1169 assert_equal [7, 7], Issue.find_all_by_id([1, 2]).collect {|i| i.priority.id}
1138 1170
1139 1171 issue = Issue.find(1)
1140 1172 journal = issue.journals.find(:first, :order => 'created_on DESC')
1141 1173 assert_equal '125', issue.custom_value_for(2).value
1142 1174 assert_equal 'Bulk editing', journal.notes
1143 1175 assert_equal 1, journal.details.size
1144 1176 end
1145 1177
1146 1178 def test_bulk_update_on_different_projects
1147 1179 @request.session[:user_id] = 2
1148 1180 # update issues priority
1149 1181 post :bulk_update, :ids => [1, 2, 6], :notes => 'Bulk editing',
1150 1182 :issue => {:priority_id => 7,
1151 1183 :assigned_to_id => '',
1152 1184 :custom_field_values => {'2' => ''}}
1153 1185
1154 1186 assert_response 302
1155 1187 # check that the issues were updated
1156 1188 assert_equal [7, 7, 7], Issue.find([1,2,6]).map(&:priority_id)
1157 1189
1158 1190 issue = Issue.find(1)
1159 1191 journal = issue.journals.find(:first, :order => 'created_on DESC')
1160 1192 assert_equal '125', issue.custom_value_for(2).value
1161 1193 assert_equal 'Bulk editing', journal.notes
1162 1194 assert_equal 1, journal.details.size
1163 1195 end
1164 1196
1165 1197 def test_bulk_update_on_different_projects_without_rights
1166 1198 @request.session[:user_id] = 3
1167 1199 user = User.find(3)
1168 1200 action = { :controller => "issues", :action => "bulk_update" }
1169 1201 assert user.allowed_to?(action, Issue.find(1).project)
1170 1202 assert ! user.allowed_to?(action, Issue.find(6).project)
1171 1203 post :bulk_update, :ids => [1, 6], :notes => 'Bulk should fail',
1172 1204 :issue => {:priority_id => 7,
1173 1205 :assigned_to_id => '',
1174 1206 :custom_field_values => {'2' => ''}}
1175 1207 assert_response 403
1176 1208 assert_not_equal "Bulk should fail", Journal.last.notes
1177 1209 end
1178 1210
1179 1211 def test_bullk_update_should_send_a_notification
1180 1212 @request.session[:user_id] = 2
1181 1213 ActionMailer::Base.deliveries.clear
1182 1214 post(:bulk_update,
1183 1215 {
1184 1216 :ids => [1, 2],
1185 1217 :notes => 'Bulk editing',
1186 1218 :issue => {
1187 1219 :priority_id => 7,
1188 1220 :assigned_to_id => '',
1189 1221 :custom_field_values => {'2' => ''}
1190 1222 }
1191 1223 })
1192 1224
1193 1225 assert_response 302
1194 1226 assert_equal 2, ActionMailer::Base.deliveries.size
1195 1227 end
1196 1228
1197 1229 def test_bulk_update_status
1198 1230 @request.session[:user_id] = 2
1199 1231 # update issues priority
1200 1232 post :bulk_update, :ids => [1, 2], :notes => 'Bulk editing status',
1201 1233 :issue => {:priority_id => '',
1202 1234 :assigned_to_id => '',
1203 1235 :status_id => '5'}
1204 1236
1205 1237 assert_response 302
1206 1238 issue = Issue.find(1)
1207 1239 assert issue.closed?
1208 1240 end
1209 1241
1210 1242 def test_bulk_update_parent_id
1211 1243 @request.session[:user_id] = 2
1212 1244 post :bulk_update, :ids => [1, 3],
1213 1245 :notes => 'Bulk editing parent',
1214 1246 :issue => {:priority_id => '', :assigned_to_id => '', :status_id => '', :parent_issue_id => '2'}
1215 1247
1216 1248 assert_response 302
1217 1249 parent = Issue.find(2)
1218 1250 assert_equal parent.id, Issue.find(1).parent_id
1219 1251 assert_equal parent.id, Issue.find(3).parent_id
1220 1252 assert_equal [1, 3], parent.children.collect(&:id).sort
1221 1253 end
1222 1254
1223 1255 def test_bulk_update_custom_field
1224 1256 @request.session[:user_id] = 2
1225 1257 # update issues priority
1226 1258 post :bulk_update, :ids => [1, 2], :notes => 'Bulk editing custom field',
1227 1259 :issue => {:priority_id => '',
1228 1260 :assigned_to_id => '',
1229 1261 :custom_field_values => {'2' => '777'}}
1230 1262
1231 1263 assert_response 302
1232 1264
1233 1265 issue = Issue.find(1)
1234 1266 journal = issue.journals.find(:first, :order => 'created_on DESC')
1235 1267 assert_equal '777', issue.custom_value_for(2).value
1236 1268 assert_equal 1, journal.details.size
1237 1269 assert_equal '125', journal.details.first.old_value
1238 1270 assert_equal '777', journal.details.first.value
1239 1271 end
1240 1272
1241 1273 def test_bulk_update_unassign
1242 1274 assert_not_nil Issue.find(2).assigned_to
1243 1275 @request.session[:user_id] = 2
1244 1276 # unassign issues
1245 1277 post :bulk_update, :ids => [1, 2], :notes => 'Bulk unassigning', :issue => {:assigned_to_id => 'none'}
1246 1278 assert_response 302
1247 1279 # check that the issues were updated
1248 1280 assert_nil Issue.find(2).assigned_to
1249 1281 end
1250 1282
1251 1283 def test_post_bulk_update_should_allow_fixed_version_to_be_set_to_a_subproject
1252 1284 @request.session[:user_id] = 2
1253 1285
1254 1286 post :bulk_update, :ids => [1,2], :issue => {:fixed_version_id => 4}
1255 1287
1256 1288 assert_response :redirect
1257 1289 issues = Issue.find([1,2])
1258 1290 issues.each do |issue|
1259 1291 assert_equal 4, issue.fixed_version_id
1260 1292 assert_not_equal issue.project_id, issue.fixed_version.project_id
1261 1293 end
1262 1294 end
1263 1295
1264 1296 def test_post_bulk_update_should_redirect_back_using_the_back_url_parameter
1265 1297 @request.session[:user_id] = 2
1266 1298 post :bulk_update, :ids => [1,2], :back_url => '/issues'
1267 1299
1268 1300 assert_response :redirect
1269 1301 assert_redirected_to '/issues'
1270 1302 end
1271 1303
1272 1304 def test_post_bulk_update_should_not_redirect_back_using_the_back_url_parameter_off_the_host
1273 1305 @request.session[:user_id] = 2
1274 1306 post :bulk_update, :ids => [1,2], :back_url => 'http://google.com'
1275 1307
1276 1308 assert_response :redirect
1277 1309 assert_redirected_to :controller => 'issues', :action => 'index', :project_id => Project.find(1).identifier
1278 1310 end
1279 1311
1280 1312 def test_destroy_issue_with_no_time_entries
1281 1313 assert_nil TimeEntry.find_by_issue_id(2)
1282 1314 @request.session[:user_id] = 2
1283 1315 post :destroy, :id => 2
1284 1316 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
1285 1317 assert_nil Issue.find_by_id(2)
1286 1318 end
1287 1319
1288 1320 def test_destroy_issues_with_time_entries
1289 1321 @request.session[:user_id] = 2
1290 1322 post :destroy, :ids => [1, 3]
1291 1323 assert_response :success
1292 1324 assert_template 'destroy'
1293 1325 assert_not_nil assigns(:hours)
1294 1326 assert Issue.find_by_id(1) && Issue.find_by_id(3)
1295 1327 end
1296 1328
1297 1329 def test_destroy_issues_and_destroy_time_entries
1298 1330 @request.session[:user_id] = 2
1299 1331 post :destroy, :ids => [1, 3], :todo => 'destroy'
1300 1332 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
1301 1333 assert !(Issue.find_by_id(1) || Issue.find_by_id(3))
1302 1334 assert_nil TimeEntry.find_by_id([1, 2])
1303 1335 end
1304 1336
1305 1337 def test_destroy_issues_and_assign_time_entries_to_project
1306 1338 @request.session[:user_id] = 2
1307 1339 post :destroy, :ids => [1, 3], :todo => 'nullify'
1308 1340 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
1309 1341 assert !(Issue.find_by_id(1) || Issue.find_by_id(3))
1310 1342 assert_nil TimeEntry.find(1).issue_id
1311 1343 assert_nil TimeEntry.find(2).issue_id
1312 1344 end
1313 1345
1314 1346 def test_destroy_issues_and_reassign_time_entries_to_another_issue
1315 1347 @request.session[:user_id] = 2
1316 1348 post :destroy, :ids => [1, 3], :todo => 'reassign', :reassign_to_id => 2
1317 1349 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
1318 1350 assert !(Issue.find_by_id(1) || Issue.find_by_id(3))
1319 1351 assert_equal 2, TimeEntry.find(1).issue_id
1320 1352 assert_equal 2, TimeEntry.find(2).issue_id
1321 1353 end
1322 1354
1323 1355 def test_destroy_issues_from_different_projects
1324 1356 @request.session[:user_id] = 2
1325 1357 post :destroy, :ids => [1, 2, 6], :todo => 'destroy'
1326 1358 assert_redirected_to :controller => 'issues', :action => 'index'
1327 1359 assert !(Issue.find_by_id(1) || Issue.find_by_id(2) || Issue.find_by_id(6))
1328 1360 end
1329 1361
1330 1362 def test_destroy_parent_and_child_issues
1331 1363 parent = Issue.generate!(:project_id => 1, :tracker_id => 1)
1332 1364 child = Issue.generate!(:project_id => 1, :tracker_id => 1, :parent_issue_id => parent.id)
1333 1365 assert child.is_descendant_of?(parent.reload)
1334 1366
1335 1367 @request.session[:user_id] = 2
1336 1368 assert_difference 'Issue.count', -2 do
1337 1369 post :destroy, :ids => [parent.id, child.id], :todo => 'destroy'
1338 1370 end
1339 1371 assert_response 302
1340 1372 end
1341 1373
1342 1374 def test_default_search_scope
1343 1375 get :index
1344 1376 assert_tag :div, :attributes => {:id => 'quick-search'},
1345 1377 :child => {:tag => 'form',
1346 1378 :child => {:tag => 'input', :attributes => {:name => 'issues', :type => 'hidden', :value => '1'}}}
1347 1379 end
1348 1380 end
@@ -1,70 +1,77
1 1 # Redmine - project management software
2 2 # Copyright (C) 2006-2011 Jean-Philippe Lang
3 3 #
4 4 # This program is free software; you can redistribute it and/or
5 5 # modify it under the terms of the GNU General Public License
6 6 # as published by the Free Software Foundation; either version 2
7 7 # of the License, or (at your option) any later version.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU General Public License
15 15 # along with this program; if not, write to the Free Software
16 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 17
18 18 require File.expand_path('../../test_helper', __FILE__)
19 19
20 20 class CustomFieldUserFormatTest < ActiveSupport::TestCase
21 21 fixtures :custom_fields, :projects, :members, :users, :member_roles, :trackers, :issues
22 22
23 23 def setup
24 24 @field = IssueCustomField.create!(:name => 'Tester', :field_format => 'user')
25 25 end
26 26
27 27 def test_possible_values_with_no_arguments
28 28 assert_equal [], @field.possible_values
29 29 assert_equal [], @field.possible_values(nil)
30 30 end
31 31
32 32 def test_possible_values_with_project_resource
33 33 project = Project.find(1)
34 34 possible_values = @field.possible_values(project.issues.first)
35 35 assert possible_values.any?
36 36 assert_equal project.users.sort.collect(&:id).map(&:to_s), possible_values
37 37 end
38 38
39 39 def test_possible_values_with_nil_project_resource
40 40 project = Project.find(1)
41 41 assert_equal [], @field.possible_values(Issue.new)
42 42 end
43 43
44 44 def test_possible_values_options_with_no_arguments
45 45 assert_equal [], @field.possible_values_options
46 46 assert_equal [], @field.possible_values_options(nil)
47 47 end
48 48
49 49 def test_possible_values_options_with_project_resource
50 50 project = Project.find(1)
51 51 possible_values_options = @field.possible_values_options(project.issues.first)
52 52 assert possible_values_options.any?
53 53 assert_equal project.users.sort.map {|u| [u.name, u.id.to_s]}, possible_values_options
54 54 end
55 55
56 def test_possible_values_options_with_array
57 projects = Project.find([1, 2])
58 possible_values_options = @field.possible_values_options(projects)
59 assert possible_values_options.any?
60 assert_equal (projects.first.users & projects.last.users).sort.map {|u| [u.name, u.id.to_s]}, possible_values_options
61 end
62
56 63 def test_cast_blank_value
57 64 assert_equal nil, @field.cast_value(nil)
58 65 assert_equal nil, @field.cast_value("")
59 66 end
60 67
61 68 def test_cast_valid_value
62 69 user = @field.cast_value("2")
63 70 assert_kind_of User, user
64 71 assert_equal User.find(2), user
65 72 end
66 73
67 74 def test_cast_invalid_value
68 75 assert_equal nil, @field.cast_value("187")
69 76 end
70 77 end
General Comments 0
You need to be logged in to leave comments. Login now