##// END OF EJS Templates
Merged r15202 (#22108)....
Jean-Philippe Lang -
r14844:d09b08046343
parent child
Show More
@@ -1,246 +1,276
1 1 # encoding: utf-8
2 2 #
3 3 # Redmine - project management software
4 4 # Copyright (C) 2006-2015 Jean-Philippe Lang
5 5 #
6 6 # This program is free software; you can redistribute it and/or
7 7 # modify it under the terms of the GNU General Public License
8 8 # as published by the Free Software Foundation; either version 2
9 9 # of the License, or (at your option) any later version.
10 10 #
11 11 # This program is distributed in the hope that it will be useful,
12 12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 14 # GNU General Public License for more details.
15 15 #
16 16 # You should have received a copy of the GNU General Public License
17 17 # along with this program; if not, write to the Free Software
18 18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 19
20 20 module QueriesHelper
21 21 include ApplicationHelper
22 22
23 23 def filters_options_for_select(query)
24 24 ungrouped = []
25 25 grouped = {}
26 26 query.available_filters.map do |field, field_options|
27 27 if [:tree, :relation].include?(field_options[:type])
28 28 group = :label_related_issues
29 29 elsif field =~ /^(.+)\./
30 30 # association filters
31 31 group = "field_#{$1}"
32 32 elsif %w(member_of_group assigned_to_role).include?(field)
33 33 group = :field_assigned_to
34 34 elsif field_options[:type] == :date_past || field_options[:type] == :date
35 35 group = :label_date
36 36 end
37 37 if group
38 38 (grouped[group] ||= []) << [field_options[:name], field]
39 39 else
40 40 ungrouped << [field_options[:name], field]
41 41 end
42 42 end
43 43 # Don't group dates if there's only one (eg. time entries filters)
44 44 if grouped[:label_date].try(:size) == 1
45 45 ungrouped << grouped.delete(:label_date).first
46 46 end
47 47 s = options_for_select([[]] + ungrouped)
48 48 if grouped.present?
49 49 localized_grouped = grouped.map {|k,v| [l(k), v]}
50 50 s << grouped_options_for_select(localized_grouped)
51 51 end
52 52 s
53 53 end
54 54
55 55 def query_filters_hidden_tags(query)
56 56 tags = ''.html_safe
57 57 query.filters.each do |field, options|
58 58 tags << hidden_field_tag("f[]", field, :id => nil)
59 59 tags << hidden_field_tag("op[#{field}]", options[:operator], :id => nil)
60 60 options[:values].each do |value|
61 61 tags << hidden_field_tag("v[#{field}][]", value, :id => nil)
62 62 end
63 63 end
64 64 tags
65 65 end
66 66
67 67 def query_columns_hidden_tags(query)
68 68 tags = ''.html_safe
69 69 query.columns.each do |column|
70 70 tags << hidden_field_tag("c[]", column.name, :id => nil)
71 71 end
72 72 tags
73 73 end
74 74
75 75 def query_hidden_tags(query)
76 76 query_filters_hidden_tags(query) + query_columns_hidden_tags(query)
77 77 end
78 78
79 79 def available_block_columns_tags(query)
80 80 tags = ''.html_safe
81 81 query.available_block_columns.each do |column|
82 82 tags << content_tag('label', check_box_tag('c[]', column.name.to_s, query.has_column?(column), :id => nil) + " #{column.caption}", :class => 'inline')
83 83 end
84 84 tags
85 85 end
86 86
87 87 def available_totalable_columns_tags(query)
88 88 tags = ''.html_safe
89 89 query.available_totalable_columns.each do |column|
90 90 tags << content_tag('label', check_box_tag('t[]', column.name.to_s, query.totalable_columns.include?(column), :id => nil) + " #{column.caption}", :class => 'inline')
91 91 end
92 92 tags
93 93 end
94 94
95 95 def query_available_inline_columns_options(query)
96 96 (query.available_inline_columns - query.columns).reject(&:frozen?).collect {|column| [column.caption, column.name]}
97 97 end
98 98
99 99 def query_selected_inline_columns_options(query)
100 100 (query.inline_columns & query.available_inline_columns).reject(&:frozen?).collect {|column| [column.caption, column.name]}
101 101 end
102 102
103 103 def render_query_columns_selection(query, options={})
104 104 tag_name = (options[:name] || 'c') + '[]'
105 105 render :partial => 'queries/columns', :locals => {:query => query, :tag_name => tag_name}
106 106 end
107 107
108 108 def render_query_totals(query)
109 109 return unless query.totalable_columns.present?
110 110 totals = query.totalable_columns.map do |column|
111 111 total_tag(column, query.total_for(column))
112 112 end
113 113 content_tag('p', totals.join(" ").html_safe, :class => "query-totals")
114 114 end
115 115
116 116 def total_tag(column, value)
117 117 label = content_tag('span', "#{column.caption}:")
118 118 value = content_tag('span', format_object(value), :class => 'value')
119 119 content_tag('span', label + " " + value, :class => "total-for-#{column.name.to_s.dasherize}")
120 120 end
121 121
122 122 def column_header(column)
123 123 column.sortable ? sort_header_tag(column.name.to_s, :caption => column.caption,
124 124 :default_order => column.default_order) :
125 125 content_tag('th', h(column.caption))
126 126 end
127 127
128 128 def column_content(column, issue)
129 129 value = column.value_object(issue)
130 130 if value.is_a?(Array)
131 131 value.collect {|v| column_value(column, issue, v)}.compact.join(', ').html_safe
132 132 else
133 133 column_value(column, issue, value)
134 134 end
135 135 end
136 136
137 137 def column_value(column, issue, value)
138 138 case column.name
139 139 when :id
140 140 link_to value, issue_path(issue)
141 141 when :subject
142 142 link_to value, issue_path(issue)
143 143 when :parent
144 144 value ? (value.visible? ? link_to_issue(value, :subject => false) : "##{value.id}") : ''
145 145 when :description
146 146 issue.description? ? content_tag('div', textilizable(issue, :description), :class => "wiki") : ''
147 147 when :done_ratio
148 148 progress_bar(value)
149 149 when :relations
150 150 content_tag('span',
151 151 value.to_s(issue) {|other| link_to_issue(other, :subject => false, :tracker => false)}.html_safe,
152 152 :class => value.css_classes_for(issue))
153 153 else
154 154 format_object(value)
155 155 end
156 156 end
157 157
158 158 def csv_content(column, issue)
159 159 value = column.value_object(issue)
160 160 if value.is_a?(Array)
161 161 value.collect {|v| csv_value(column, issue, v)}.compact.join(', ')
162 162 else
163 163 csv_value(column, issue, value)
164 164 end
165 165 end
166 166
167 167 def csv_value(column, object, value)
168 168 format_object(value, false) do |value|
169 169 case value.class.name
170 170 when 'Float'
171 171 sprintf("%.2f", value).gsub('.', l(:general_csv_decimal_separator))
172 172 when 'IssueRelation'
173 173 value.to_s(object)
174 174 when 'Issue'
175 175 if object.is_a?(TimeEntry)
176 176 "#{value.tracker} ##{value.id}: #{value.subject}"
177 177 else
178 178 value.id
179 179 end
180 180 else
181 181 value
182 182 end
183 183 end
184 184 end
185 185
186 186 def query_to_csv(items, query, options={})
187 187 options ||= {}
188 188 columns = (options[:columns] == 'all' ? query.available_inline_columns : query.inline_columns)
189 189 query.available_block_columns.each do |column|
190 190 if options[column.name].present?
191 191 columns << column
192 192 end
193 193 end
194 194
195 195 Redmine::Export::CSV.generate do |csv|
196 196 # csv header fields
197 197 csv << columns.map {|c| c.caption.to_s}
198 198 # csv lines
199 199 items.each do |item|
200 200 csv << columns.map {|c| csv_content(c, item)}
201 201 end
202 202 end
203 203 end
204 204
205 205 # Retrieve query from session or build a new query
206 206 def retrieve_query
207 207 if !params[:query_id].blank?
208 208 cond = "project_id IS NULL"
209 209 cond << " OR project_id = #{@project.id}" if @project
210 210 @query = IssueQuery.where(cond).find(params[:query_id])
211 211 raise ::Unauthorized unless @query.visible?
212 212 @query.project = @project
213 213 session[:query] = {:id => @query.id, :project_id => @query.project_id}
214 214 sort_clear
215 215 elsif api_request? || params[:set_filter] || session[:query].nil? || session[:query][:project_id] != (@project ? @project.id : nil)
216 216 # Give it a name, required to be valid
217 217 @query = IssueQuery.new(:name => "_")
218 218 @query.project = @project
219 219 @query.build_from_params(params)
220 220 session[:query] = {:project_id => @query.project_id, :filters => @query.filters, :group_by => @query.group_by, :column_names => @query.column_names, :totalable_names => @query.totalable_names}
221 221 else
222 222 # retrieve from session
223 223 @query = nil
224 224 @query = IssueQuery.find_by_id(session[:query][:id]) if session[:query][:id]
225 225 @query ||= IssueQuery.new(:name => "_", :filters => session[:query][:filters], :group_by => session[:query][:group_by], :column_names => session[:query][:column_names], :totalable_names => session[:query][:totalable_names])
226 226 @query.project = @project
227 227 end
228 228 end
229 229
230 230 def retrieve_query_from_session
231 231 if session[:query]
232 232 if session[:query][:id]
233 233 @query = IssueQuery.find_by_id(session[:query][:id])
234 234 return unless @query
235 235 else
236 236 @query = IssueQuery.new(:name => "_", :filters => session[:query][:filters], :group_by => session[:query][:group_by], :column_names => session[:query][:column_names], :totalable_names => session[:query][:totalable_names])
237 237 end
238 238 if session[:query].has_key?(:project_id)
239 239 @query.project_id = session[:query][:project_id]
240 240 else
241 241 @query.project = @project
242 242 end
243 243 @query
244 244 end
245 245 end
246
247 # Returns the query definition as hidden field tags
248 def query_as_hidden_field_tags(query)
249 tags = hidden_field_tag("set_filter", "1", :id => nil)
250
251 if query.filters.present?
252 query.filters.each do |field, filter|
253 tags << hidden_field_tag("f[]", field, :id => nil)
254 tags << hidden_field_tag("op[#{field}]", filter[:operator], :id => nil)
255 filter[:values].each do |value|
256 tags << hidden_field_tag("v[#{field}][]", value, :id => nil)
257 end
258 end
259 end
260 if query.column_names.present?
261 query.column_names.each do |name|
262 tags << hidden_field_tag("c[]", name, :id => nil)
263 end
264 end
265 if query.totalable_names.present?
266 query.totalable_names.each do |name|
267 tags << hidden_field_tag("t[]", name, :id => nil)
268 end
269 end
270 if query.group_by.present?
271 tags << hidden_field_tag("group_by", query.group_by, :id => nil)
272 end
273
274 tags
275 end
246 276 end
@@ -1,119 +1,121
1 1 <div class="contextual">
2 2 <% if !@query.new_record? && @query.editable_by?(User.current) %>
3 3 <%= link_to l(:button_edit), edit_query_path(@query), :class => 'icon icon-edit' %>
4 4 <%= delete_link query_path(@query) %>
5 5 <% end %>
6 6 </div>
7 7
8 8 <h2><%= @query.new_record? ? l(:label_issue_plural) : @query.name %></h2>
9 9 <% html_title(@query.new_record? ? l(:label_issue_plural) : @query.name) %>
10 10
11 11 <%= form_tag({ :controller => 'issues', :action => 'index', :project_id => @project },
12 12 :method => :get, :id => 'query_form') do %>
13 13 <div id="query_form_with_buttons" class="hide-when-print">
14 14 <%= hidden_field_tag 'set_filter', '1' %>
15 15 <div id="query_form_content">
16 16 <fieldset id="filters" class="collapsible <%= @query.new_record? ? "" : "collapsed" %>">
17 17 <legend onclick="toggleFieldset(this);"><%= l(:label_filter_plural) %></legend>
18 18 <div style="<%= @query.new_record? ? "" : "display: none;" %>">
19 19 <%= render :partial => 'queries/filters', :locals => {:query => @query} %>
20 20 </div>
21 21 </fieldset>
22 22 <fieldset class="collapsible collapsed">
23 23 <legend onclick="toggleFieldset(this);"><%= l(:label_options) %></legend>
24 24 <div style="display: none;">
25 25 <table>
26 26 <tr>
27 27 <td><%= l(:field_column_names) %></td>
28 28 <td><%= render_query_columns_selection(@query) %></td>
29 29 </tr>
30 30 <tr>
31 31 <td><label for='group_by'><%= l(:field_group_by) %></label></td>
32 32 <td><%= select_tag('group_by',
33 33 options_for_select(
34 34 [[]] + @query.groupable_columns.collect {|c| [c.caption, c.name.to_s]},
35 35 @query.group_by)
36 36 ) %></td>
37 37 </tr>
38 38 <tr>
39 39 <td><%= l(:button_show) %></td>
40 40 <td><%= available_block_columns_tags(@query) %></td>
41 41 </tr>
42 42 <tr>
43 43 <td><%= l(:label_total_plural) %></td>
44 44 <td><%= available_totalable_columns_tags(@query) %></td>
45 45 </tr>
46 46 </table>
47 47 </div>
48 48 </fieldset>
49 49 </div>
50 50 <p class="buttons">
51 51 <%= link_to_function l(:button_apply), '$("#query_form").submit()', :class => 'icon icon-checked' %>
52 52 <%= link_to l(:button_clear), { :set_filter => 1, :project_id => @project }, :class => 'icon icon-reload' %>
53 53 <% if @query.new_record? && User.current.allowed_to?(:save_queries, @project, :global => true) %>
54 54 <%= link_to_function l(:button_save),
55 55 "$('#query_form').attr('action', '#{ @project ? new_project_query_path(@project) : new_query_path }').submit()",
56 56 :class => 'icon icon-save' %>
57 57 <% end %>
58 58 </p>
59 59 </div>
60 60 <% end %>
61 61
62 62 <%= error_messages_for 'query' %>
63 63 <% if @query.valid? %>
64 64 <% if @issues.empty? %>
65 65 <p class="nodata"><%= l(:label_no_data) %></p>
66 66 <% else %>
67 67 <%= render_query_totals(@query) %>
68 68 <%= render :partial => 'issues/list', :locals => {:issues => @issues, :query => @query} %>
69 69 <span class="pagination"><%= pagination_links_full @issue_pages, @issue_count %></span>
70 70 <% end %>
71 71
72 72 <% other_formats_links do |f| %>
73 73 <%= f.link_to 'Atom', :url => params.merge(:key => User.current.rss_key) %>
74 74 <%= f.link_to 'CSV', :url => params, :onclick => "showModal('csv-export-options', '350px'); return false;" %>
75 75 <%= f.link_to 'PDF', :url => params %>
76 76 <% end %>
77 77
78 78 <div id="csv-export-options" style="display:none;">
79 <h3 class="title"><%= l(:label_export_options, :export_format => 'CSV') %></h3>
80 <%= form_tag(params.merge({:format => 'csv',:page=>nil}), :method => :get, :id => 'csv-export-form') do %>
79 <h3 class="title"><%= l(:label_export_options, :export_format => 'CSV') %></h3>
80 <%= form_tag(_project_issues_path(@project, :format => 'csv'), :method => :get, :id => 'csv-export-form') do %>
81 <%= query_as_hidden_field_tags(@query) %>
82 <%= hidden_field_tag 'sort', params[:sort], :id => nil %>
81 83 <p>
82 84 <label><%= radio_button_tag 'csv[columns]', '', true %> <%= l(:description_selected_columns) %></label><br />
83 85 <label><%= radio_button_tag 'csv[columns]', 'all' %> <%= l(:description_all_columns) %></label>
84 86 </p>
85 87 <p>
86 88 <label><%= check_box_tag 'csv[description]', '1', @query.has_column?(:description) %> <%= l(:field_description) %></label>
87 89 </p>
88 90 <% if @issue_count > Setting.issues_export_limit.to_i %>
89 91 <p class="icon icon-warning">
90 92 <%= l(:setting_issues_export_limit) %>: <%= Setting.issues_export_limit.to_i %>
91 93 </p>
92 94 <% end %>
93 95 <p class="buttons">
94 96 <%= submit_tag l(:button_export), :name => nil, :onclick => "hideModal(this);" %>
95 97 <%= submit_tag l(:button_cancel), :name => nil, :onclick => "hideModal(this);", :type => 'button' %>
96 98 </p>
97 99 <% end %>
98 100 </div>
99 101
100 102 <% end %>
101 103 <%= call_hook(:view_issues_index_bottom, { :issues => @issues, :project => @project, :query => @query }) %>
102 104
103 105 <% content_for :sidebar do %>
104 106 <%= render :partial => 'issues/sidebar' %>
105 107 <% end %>
106 108
107 109 <% content_for :header_tags do %>
108 110 <%= auto_discovery_link_tag(:atom,
109 111 {:query_id => @query, :format => 'atom',
110 112 :page => nil, :key => User.current.rss_key},
111 113 :title => l(:label_issue_plural)) %>
112 114 <%= auto_discovery_link_tag(:atom,
113 115 {:controller => 'journals', :action => 'index',
114 116 :query_id => @query, :format => 'atom',
115 117 :page => nil, :key => User.current.rss_key},
116 118 :title => l(:label_changes_details)) %>
117 119 <% end %>
118 120
119 121 <%= context_menu issues_context_menu_path %>
@@ -1,4466 +1,4486
1 1 # Redmine - project management software
2 2 # Copyright (C) 2006-2015 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 IssuesControllerTest < ActionController::TestCase
21 21 fixtures :projects,
22 22 :users, :email_addresses,
23 23 :roles,
24 24 :members,
25 25 :member_roles,
26 26 :issues,
27 27 :issue_statuses,
28 28 :issue_relations,
29 29 :versions,
30 30 :trackers,
31 31 :projects_trackers,
32 32 :issue_categories,
33 33 :enabled_modules,
34 34 :enumerations,
35 35 :attachments,
36 36 :workflows,
37 37 :custom_fields,
38 38 :custom_values,
39 39 :custom_fields_projects,
40 40 :custom_fields_trackers,
41 41 :time_entries,
42 42 :journals,
43 43 :journal_details,
44 44 :queries,
45 45 :repositories,
46 46 :changesets
47 47
48 48 include Redmine::I18n
49 49
50 50 def setup
51 51 User.current = nil
52 52 end
53 53
54 54 def test_index
55 55 with_settings :default_language => "en" do
56 56 get :index
57 57 assert_response :success
58 58 assert_template 'index'
59 59 assert_not_nil assigns(:issues)
60 60 assert_nil assigns(:project)
61 61
62 62 # links to visible issues
63 63 assert_select 'a[href="/issues/1"]', :text => /Cannot print recipes/
64 64 assert_select 'a[href="/issues/5"]', :text => /Subproject issue/
65 65 # private projects hidden
66 66 assert_select 'a[href="/issues/6"]', 0
67 67 assert_select 'a[href="/issues/4"]', 0
68 68 # project column
69 69 assert_select 'th', :text => /Project/
70 70 end
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'
78 78 assert_not_nil assigns(:issues)
79 79 assert_nil assigns(:project)
80 80
81 81 assert_select 'a[href="/issues/1"]', 0
82 82 assert_select 'a[href="/issues/5"]', :text => /Subproject issue/
83 83 end
84 84
85 85 def test_index_should_list_visible_issues_only
86 86 get :index, :per_page => 100
87 87 assert_response :success
88 88 assert_not_nil assigns(:issues)
89 89 assert_nil assigns(:issues).detect {|issue| !issue.visible?}
90 90 end
91 91
92 92 def test_index_with_project
93 93 Setting.display_subprojects_issues = 0
94 94 get :index, :project_id => 1
95 95 assert_response :success
96 96 assert_template 'index'
97 97 assert_not_nil assigns(:issues)
98 98
99 99 assert_select 'a[href="/issues/1"]', :text => /Cannot print recipes/
100 100 assert_select 'a[href="/issues/5"]', 0
101 101 end
102 102
103 103 def test_index_with_project_and_subprojects
104 104 Setting.display_subprojects_issues = 1
105 105 get :index, :project_id => 1
106 106 assert_response :success
107 107 assert_template 'index'
108 108 assert_not_nil assigns(:issues)
109 109
110 110 assert_select 'a[href="/issues/1"]', :text => /Cannot print recipes/
111 111 assert_select 'a[href="/issues/5"]', :text => /Subproject issue/
112 112 assert_select 'a[href="/issues/6"]', 0
113 113 end
114 114
115 115 def test_index_with_project_and_subprojects_should_show_private_subprojects_with_permission
116 116 @request.session[:user_id] = 2
117 117 Setting.display_subprojects_issues = 1
118 118 get :index, :project_id => 1
119 119 assert_response :success
120 120 assert_template 'index'
121 121 assert_not_nil assigns(:issues)
122 122
123 123 assert_select 'a[href="/issues/1"]', :text => /Cannot print recipes/
124 124 assert_select 'a[href="/issues/5"]', :text => /Subproject issue/
125 125 assert_select 'a[href="/issues/6"]', :text => /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'
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'
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_short_filters
155 155 to_test = {
156 156 'status_id' => {
157 157 'o' => { :op => 'o', :values => [''] },
158 158 'c' => { :op => 'c', :values => [''] },
159 159 '7' => { :op => '=', :values => ['7'] },
160 160 '7|3|4' => { :op => '=', :values => ['7', '3', '4'] },
161 161 '=7' => { :op => '=', :values => ['7'] },
162 162 '!3' => { :op => '!', :values => ['3'] },
163 163 '!7|3|4' => { :op => '!', :values => ['7', '3', '4'] }},
164 164 'subject' => {
165 165 'This is a subject' => { :op => '=', :values => ['This is a subject'] },
166 166 'o' => { :op => '=', :values => ['o'] },
167 167 '~This is part of a subject' => { :op => '~', :values => ['This is part of a subject'] },
168 168 '!~This is part of a subject' => { :op => '!~', :values => ['This is part of a subject'] }},
169 169 'tracker_id' => {
170 170 '3' => { :op => '=', :values => ['3'] },
171 171 '=3' => { :op => '=', :values => ['3'] }},
172 172 'start_date' => {
173 173 '2011-10-12' => { :op => '=', :values => ['2011-10-12'] },
174 174 '=2011-10-12' => { :op => '=', :values => ['2011-10-12'] },
175 175 '>=2011-10-12' => { :op => '>=', :values => ['2011-10-12'] },
176 176 '<=2011-10-12' => { :op => '<=', :values => ['2011-10-12'] },
177 177 '><2011-10-01|2011-10-30' => { :op => '><', :values => ['2011-10-01', '2011-10-30'] },
178 178 '<t+2' => { :op => '<t+', :values => ['2'] },
179 179 '>t+2' => { :op => '>t+', :values => ['2'] },
180 180 't+2' => { :op => 't+', :values => ['2'] },
181 181 't' => { :op => 't', :values => [''] },
182 182 'w' => { :op => 'w', :values => [''] },
183 183 '>t-2' => { :op => '>t-', :values => ['2'] },
184 184 '<t-2' => { :op => '<t-', :values => ['2'] },
185 185 't-2' => { :op => 't-', :values => ['2'] }},
186 186 'created_on' => {
187 187 '>=2011-10-12' => { :op => '>=', :values => ['2011-10-12'] },
188 188 '<t-2' => { :op => '<t-', :values => ['2'] },
189 189 '>t-2' => { :op => '>t-', :values => ['2'] },
190 190 't-2' => { :op => 't-', :values => ['2'] }},
191 191 'cf_1' => {
192 192 'c' => { :op => '=', :values => ['c'] },
193 193 '!c' => { :op => '!', :values => ['c'] },
194 194 '!*' => { :op => '!*', :values => [''] },
195 195 '*' => { :op => '*', :values => [''] }},
196 196 'estimated_hours' => {
197 197 '=13.4' => { :op => '=', :values => ['13.4'] },
198 198 '>=45' => { :op => '>=', :values => ['45'] },
199 199 '<=125' => { :op => '<=', :values => ['125'] },
200 200 '><10.5|20.5' => { :op => '><', :values => ['10.5', '20.5'] },
201 201 '!*' => { :op => '!*', :values => [''] },
202 202 '*' => { :op => '*', :values => [''] }}
203 203 }
204 204
205 205 default_filter = { 'status_id' => {:operator => 'o', :values => [''] }}
206 206
207 207 to_test.each do |field, expression_and_expected|
208 208 expression_and_expected.each do |filter_expression, expected|
209 209
210 210 get :index, :set_filter => 1, field => filter_expression
211 211
212 212 assert_response :success
213 213 assert_template 'index'
214 214 assert_not_nil assigns(:issues)
215 215
216 216 query = assigns(:query)
217 217 assert_not_nil query
218 218 assert query.has_filter?(field)
219 219 assert_equal(default_filter.merge({field => {:operator => expected[:op], :values => expected[:values]}}), query.filters)
220 220 end
221 221 end
222 222 end
223 223
224 224 def test_index_with_project_and_empty_filters
225 225 get :index, :project_id => 1, :set_filter => 1, :fields => ['']
226 226 assert_response :success
227 227 assert_template 'index'
228 228 assert_not_nil assigns(:issues)
229 229
230 230 query = assigns(:query)
231 231 assert_not_nil query
232 232 # no filter
233 233 assert_equal({}, query.filters)
234 234 end
235 235
236 236 def test_index_with_project_custom_field_filter
237 237 field = ProjectCustomField.create!(:name => 'Client', :is_filter => true, :field_format => 'string')
238 238 CustomValue.create!(:custom_field => field, :customized => Project.find(3), :value => 'Foo')
239 239 CustomValue.create!(:custom_field => field, :customized => Project.find(5), :value => 'Foo')
240 240 filter_name = "project.cf_#{field.id}"
241 241 @request.session[:user_id] = 1
242 242
243 243 get :index, :set_filter => 1,
244 244 :f => [filter_name],
245 245 :op => {filter_name => '='},
246 246 :v => {filter_name => ['Foo']}
247 247 assert_response :success
248 248 assert_template 'index'
249 249 assert_equal [3, 5], assigns(:issues).map(&:project_id).uniq.sort
250 250 end
251 251
252 252 def test_index_with_query
253 253 get :index, :project_id => 1, :query_id => 5
254 254 assert_response :success
255 255 assert_template 'index'
256 256 assert_not_nil assigns(:issues)
257 257 assert_nil assigns(:issue_count_by_group)
258 258 end
259 259
260 260 def test_index_with_query_grouped_by_tracker
261 261 get :index, :project_id => 1, :query_id => 6
262 262 assert_response :success
263 263 assert_template 'index'
264 264 assert_not_nil assigns(:issues)
265 265 assert_not_nil assigns(:issue_count_by_group)
266 266 end
267 267
268 268 def test_index_with_query_grouped_and_sorted_by_category
269 269 get :index, :project_id => 1, :set_filter => 1, :group_by => "category", :sort => "category"
270 270 assert_response :success
271 271 assert_template 'index'
272 272 assert_not_nil assigns(:issues)
273 273 assert_not_nil assigns(:issue_count_by_group)
274 274 end
275 275
276 276 def test_index_with_query_grouped_by_list_custom_field
277 277 get :index, :project_id => 1, :query_id => 9
278 278 assert_response :success
279 279 assert_template 'index'
280 280 assert_not_nil assigns(:issues)
281 281 assert_not_nil assigns(:issue_count_by_group)
282 282 end
283 283
284 284 def test_index_with_query_grouped_by_user_custom_field
285 285 cf = IssueCustomField.create!(:name => 'User', :is_for_all => true, :tracker_ids => [1,2,3], :field_format => 'user')
286 286 CustomValue.create!(:custom_field => cf, :customized => Issue.find(1), :value => '2')
287 287 CustomValue.create!(:custom_field => cf, :customized => Issue.find(2), :value => '3')
288 288 CustomValue.create!(:custom_field => cf, :customized => Issue.find(3), :value => '3')
289 289 CustomValue.create!(:custom_field => cf, :customized => Issue.find(5), :value => '')
290 290
291 291 get :index, :project_id => 1, :set_filter => 1, :group_by => "cf_#{cf.id}"
292 292 assert_response :success
293 293
294 294 assert_select 'tr.group', 3
295 295 assert_select 'tr.group' do
296 296 assert_select 'a', :text => 'John Smith'
297 297 assert_select 'span.count', :text => '1'
298 298 end
299 299 assert_select 'tr.group' do
300 300 assert_select 'a', :text => 'Dave Lopper'
301 301 assert_select 'span.count', :text => '2'
302 302 end
303 303 end
304 304
305 305 def test_index_grouped_by_boolean_custom_field_should_distinguish_blank_and_false_values
306 306 cf = IssueCustomField.create!(:name => 'Bool', :is_for_all => true, :tracker_ids => [1,2,3], :field_format => 'bool')
307 307 CustomValue.create!(:custom_field => cf, :customized => Issue.find(1), :value => '1')
308 308 CustomValue.create!(:custom_field => cf, :customized => Issue.find(2), :value => '0')
309 309 CustomValue.create!(:custom_field => cf, :customized => Issue.find(3), :value => '')
310 310
311 311 with_settings :default_language => 'en' do
312 312 get :index, :project_id => 1, :set_filter => 1, :group_by => "cf_#{cf.id}"
313 313 assert_response :success
314 314 end
315 315
316 316 assert_select 'tr.group', 3
317 317 assert_select 'tr.group', :text => /Yes/
318 318 assert_select 'tr.group', :text => /No/
319 319 assert_select 'tr.group', :text => /blank/
320 320 end
321 321
322 322 def test_index_grouped_by_boolean_custom_field_with_false_group_in_first_position_should_show_the_group
323 323 cf = IssueCustomField.create!(:name => 'Bool', :is_for_all => true, :tracker_ids => [1,2,3], :field_format => 'bool', :is_filter => true)
324 324 CustomValue.create!(:custom_field => cf, :customized => Issue.find(1), :value => '0')
325 325 CustomValue.create!(:custom_field => cf, :customized => Issue.find(2), :value => '0')
326 326
327 327 with_settings :default_language => 'en' do
328 328 get :index, :project_id => 1, :set_filter => 1, "cf_#{cf.id}" => "*", :group_by => "cf_#{cf.id}"
329 329 assert_response :success
330 330 assert_equal [1, 2], assigns(:issues).map(&:id).sort
331 331 end
332 332
333 333 assert_select 'tr.group', 1
334 334 assert_select 'tr.group', :text => /No/
335 335 end
336 336
337 337 def test_index_with_query_grouped_by_tracker_in_normal_order
338 338 3.times {|i| Issue.generate!(:tracker_id => (i + 1))}
339 339
340 340 get :index, :set_filter => 1, :group_by => 'tracker', :sort => 'id:desc'
341 341 assert_response :success
342 342
343 343 trackers = assigns(:issues).map(&:tracker).uniq
344 344 assert_equal [1, 2, 3], trackers.map(&:id)
345 345 end
346 346
347 347 def test_index_with_query_grouped_by_tracker_in_reverse_order
348 348 3.times {|i| Issue.generate!(:tracker_id => (i + 1))}
349 349
350 350 get :index, :set_filter => 1, :group_by => 'tracker', :sort => 'id:desc,tracker:desc'
351 351 assert_response :success
352 352
353 353 trackers = assigns(:issues).map(&:tracker).uniq
354 354 assert_equal [3, 2, 1], trackers.map(&:id)
355 355 end
356 356
357 357 def test_index_with_query_id_and_project_id_should_set_session_query
358 358 get :index, :project_id => 1, :query_id => 4
359 359 assert_response :success
360 360 assert_kind_of Hash, session[:query]
361 361 assert_equal 4, session[:query][:id]
362 362 assert_equal 1, session[:query][:project_id]
363 363 end
364 364
365 365 def test_index_with_invalid_query_id_should_respond_404
366 366 get :index, :project_id => 1, :query_id => 999
367 367 assert_response 404
368 368 end
369 369
370 370 def test_index_with_cross_project_query_in_session_should_show_project_issues
371 371 q = IssueQuery.create!(:name => "test", :user_id => 2, :visibility => IssueQuery::VISIBILITY_PRIVATE, :project => nil)
372 372 @request.session[:query] = {:id => q.id, :project_id => 1}
373 373
374 374 with_settings :display_subprojects_issues => '0' do
375 375 get :index, :project_id => 1
376 376 end
377 377 assert_response :success
378 378 assert_not_nil assigns(:query)
379 379 assert_equal q.id, assigns(:query).id
380 380 assert_equal 1, assigns(:query).project_id
381 381 assert_equal [1], assigns(:issues).map(&:project_id).uniq
382 382 end
383 383
384 384 def test_private_query_should_not_be_available_to_other_users
385 385 q = IssueQuery.create!(:name => "private", :user => User.find(2), :visibility => IssueQuery::VISIBILITY_PRIVATE, :project => nil)
386 386 @request.session[:user_id] = 3
387 387
388 388 get :index, :query_id => q.id
389 389 assert_response 403
390 390 end
391 391
392 392 def test_private_query_should_be_available_to_its_user
393 393 q = IssueQuery.create!(:name => "private", :user => User.find(2), :visibility => IssueQuery::VISIBILITY_PRIVATE, :project => nil)
394 394 @request.session[:user_id] = 2
395 395
396 396 get :index, :query_id => q.id
397 397 assert_response :success
398 398 end
399 399
400 400 def test_public_query_should_be_available_to_other_users
401 401 q = IssueQuery.create!(:name => "public", :user => User.find(2), :visibility => IssueQuery::VISIBILITY_PUBLIC, :project => nil)
402 402 @request.session[:user_id] = 3
403 403
404 404 get :index, :query_id => q.id
405 405 assert_response :success
406 406 end
407 407
408 408 def test_index_should_omit_page_param_in_export_links
409 409 get :index, :page => 2
410 410 assert_response :success
411 411 assert_select 'a.atom[href="/issues.atom"]'
412 412 assert_select 'a.csv[href="/issues.csv"]'
413 413 assert_select 'a.pdf[href="/issues.pdf"]'
414 414 assert_select 'form#csv-export-form[action="/issues.csv"]'
415 415 end
416 416
417 417 def test_index_should_not_warn_when_not_exceeding_export_limit
418 418 with_settings :issues_export_limit => 200 do
419 419 get :index
420 420 assert_select '#csv-export-options p.icon-warning', 0
421 421 end
422 422 end
423 423
424 424 def test_index_should_warn_when_exceeding_export_limit
425 425 with_settings :issues_export_limit => 2 do
426 426 get :index
427 427 assert_select '#csv-export-options p.icon-warning', :text => %r{limit: 2}
428 428 end
429 429 end
430 430
431 def test_index_should_include_query_params_as_hidden_fields_in_csv_export_form
432 get :index, :project_id => 1, :set_filter => "1", :tracker_id => "2", :sort => 'status', :c => ["status", "priority"]
433
434 assert_select '#csv-export-form[action=?]', '/projects/ecookbook/issues.csv'
435 assert_select '#csv-export-form[method=?]', 'get'
436
437 assert_select '#csv-export-form' do
438 assert_select 'input[name=?][value=?]', 'set_filter', '1'
439
440 assert_select 'input[name=?][value=?]', 'f[]', 'tracker_id'
441 assert_select 'input[name=?][value=?]', 'op[tracker_id]', '='
442 assert_select 'input[name=?][value=?]', 'v[tracker_id][]', '2'
443
444 assert_select 'input[name=?][value=?]', 'c[]', 'status'
445 assert_select 'input[name=?][value=?]', 'c[]', 'priority'
446
447 assert_select 'input[name=?][value=?]', 'sort', 'status'
448 end
449 end
450
431 451 def test_index_csv
432 452 get :index, :format => 'csv'
433 453 assert_response :success
434 454 assert_not_nil assigns(:issues)
435 455 assert_equal 'text/csv; header=present', @response.content_type
436 456 assert @response.body.starts_with?("#,")
437 457 lines = @response.body.chomp.split("\n")
438 458 assert_equal assigns(:query).columns.size, lines[0].split(',').size
439 459 end
440 460
441 461 def test_index_csv_with_project
442 462 get :index, :project_id => 1, :format => 'csv'
443 463 assert_response :success
444 464 assert_not_nil assigns(:issues)
445 465 assert_equal 'text/csv; header=present', @response.content_type
446 466 end
447 467
448 468 def test_index_csv_with_description
449 469 Issue.generate!(:description => 'test_index_csv_with_description')
450 470
451 471 with_settings :default_language => 'en' do
452 472 get :index, :format => 'csv', :csv => {:description => '1'}
453 473 assert_response :success
454 474 assert_not_nil assigns(:issues)
455 475 end
456 476
457 477 assert_equal 'text/csv; header=present', response.content_type
458 478 headers = response.body.chomp.split("\n").first.split(',')
459 479 assert_include 'Description', headers
460 480 assert_include 'test_index_csv_with_description', response.body
461 481 end
462 482
463 483 def test_index_csv_with_spent_time_column
464 484 issue = Issue.create!(:project_id => 1, :tracker_id => 1, :subject => 'test_index_csv_with_spent_time_column', :author_id => 2)
465 485 TimeEntry.create!(:project => issue.project, :issue => issue, :hours => 7.33, :user => User.find(2), :spent_on => Date.today)
466 486
467 487 get :index, :format => 'csv', :set_filter => '1', :c => %w(subject spent_hours)
468 488 assert_response :success
469 489 assert_equal 'text/csv; header=present', @response.content_type
470 490 lines = @response.body.chomp.split("\n")
471 491 assert_include "#{issue.id},#{issue.subject},7.33", lines
472 492 end
473 493
474 494 def test_index_csv_with_all_columns
475 495 get :index, :format => 'csv', :csv => {:columns => 'all'}
476 496 assert_response :success
477 497 assert_not_nil assigns(:issues)
478 498 assert_equal 'text/csv; header=present', @response.content_type
479 499 assert_match /\A#,/, response.body
480 500 lines = response.body.chomp.split("\n")
481 501 assert_equal assigns(:query).available_inline_columns.size, lines[0].split(',').size
482 502 end
483 503
484 504 def test_index_csv_with_multi_column_field
485 505 CustomField.find(1).update_attribute :multiple, true
486 506 issue = Issue.find(1)
487 507 issue.custom_field_values = {1 => ['MySQL', 'Oracle']}
488 508 issue.save!
489 509
490 510 get :index, :format => 'csv', :csv => {:columns => 'all'}
491 511 assert_response :success
492 512 lines = @response.body.chomp.split("\n")
493 513 assert lines.detect {|line| line.include?('"MySQL, Oracle"')}
494 514 end
495 515
496 516 def test_index_csv_should_format_float_custom_fields_with_csv_decimal_separator
497 517 field = IssueCustomField.create!(:name => 'Float', :is_for_all => true, :tracker_ids => [1], :field_format => 'float')
498 518 issue = Issue.generate!(:project_id => 1, :tracker_id => 1, :custom_field_values => {field.id => '185.6'})
499 519
500 520 with_settings :default_language => 'fr' do
501 521 get :index, :format => 'csv', :csv => {:columns => 'all'}
502 522 assert_response :success
503 523 issue_line = response.body.chomp.split("\n").map {|line| line.split(';')}.detect {|line| line[0]==issue.id.to_s}
504 524 assert_include '185,60', issue_line
505 525 end
506 526
507 527 with_settings :default_language => 'en' do
508 528 get :index, :format => 'csv', :csv => {:columns => 'all'}
509 529 assert_response :success
510 530 issue_line = response.body.chomp.split("\n").map {|line| line.split(',')}.detect {|line| line[0]==issue.id.to_s}
511 531 assert_include '185.60', issue_line
512 532 end
513 533 end
514 534
515 535 def test_index_csv_should_fill_parent_column_with_parent_id
516 536 Issue.delete_all
517 537 parent = Issue.generate!
518 538 child = Issue.generate!(:parent_issue_id => parent.id)
519 539
520 540 with_settings :default_language => 'en' do
521 541 get :index, :format => 'csv', :c => %w(parent)
522 542 end
523 543 lines = response.body.split("\n")
524 544 assert_include "#{child.id},#{parent.id}", lines
525 545 end
526 546
527 547 def test_index_csv_big_5
528 548 with_settings :default_language => "zh-TW" do
529 549 str_utf8 = "\xe4\xb8\x80\xe6\x9c\x88".force_encoding('UTF-8')
530 550 str_big5 = "\xa4@\xa4\xeb".force_encoding('Big5')
531 551 issue = Issue.generate!(:subject => str_utf8)
532 552
533 553 get :index, :project_id => 1,
534 554 :f => ['subject'],
535 555 :op => '=', :values => [str_utf8],
536 556 :format => 'csv'
537 557 assert_equal 'text/csv; header=present', @response.content_type
538 558 lines = @response.body.chomp.split("\n")
539 559 header = lines[0]
540 560 status = "\xaa\xac\xbaA".force_encoding('Big5')
541 561 assert header.include?(status)
542 562 issue_line = lines.find {|l| l =~ /^#{issue.id},/}
543 563 assert issue_line.include?(str_big5)
544 564 end
545 565 end
546 566
547 567 def test_index_csv_cannot_convert_should_be_replaced_big_5
548 568 with_settings :default_language => "zh-TW" do
549 569 str_utf8 = "\xe4\xbb\xa5\xe5\x86\x85".force_encoding('UTF-8')
550 570 issue = Issue.generate!(:subject => str_utf8)
551 571
552 572 get :index, :project_id => 1,
553 573 :f => ['subject'],
554 574 :op => '=', :values => [str_utf8],
555 575 :c => ['status', 'subject'],
556 576 :format => 'csv',
557 577 :set_filter => 1
558 578 assert_equal 'text/csv; header=present', @response.content_type
559 579 lines = @response.body.chomp.split("\n")
560 580 header = lines[0]
561 581 issue_line = lines.find {|l| l =~ /^#{issue.id},/}
562 582 s1 = "\xaa\xac\xbaA".force_encoding('Big5') # status
563 583 assert header.include?(s1)
564 584 s2 = issue_line.split(",")[2]
565 585 s3 = "\xa5H?".force_encoding('Big5') # subject
566 586 assert_equal s3, s2
567 587 end
568 588 end
569 589
570 590 def test_index_csv_tw
571 591 with_settings :default_language => "zh-TW" do
572 592 str1 = "test_index_csv_tw"
573 593 issue = Issue.generate!(:subject => str1, :estimated_hours => '1234.5')
574 594
575 595 get :index, :project_id => 1,
576 596 :f => ['subject'],
577 597 :op => '=', :values => [str1],
578 598 :c => ['estimated_hours', 'subject'],
579 599 :format => 'csv',
580 600 :set_filter => 1
581 601 assert_equal 'text/csv; header=present', @response.content_type
582 602 lines = @response.body.chomp.split("\n")
583 603 assert_include "#{issue.id},1234.50,#{str1}", lines
584 604 end
585 605 end
586 606
587 607 def test_index_csv_fr
588 608 with_settings :default_language => "fr" do
589 609 str1 = "test_index_csv_fr"
590 610 issue = Issue.generate!(:subject => str1, :estimated_hours => '1234.5')
591 611
592 612 get :index, :project_id => 1,
593 613 :f => ['subject'],
594 614 :op => '=', :values => [str1],
595 615 :c => ['estimated_hours', 'subject'],
596 616 :format => 'csv',
597 617 :set_filter => 1
598 618 assert_equal 'text/csv; header=present', @response.content_type
599 619 lines = @response.body.chomp.split("\n")
600 620 assert_include "#{issue.id};1234,50;#{str1}", lines
601 621 end
602 622 end
603 623
604 624 def test_index_pdf
605 625 ["en", "zh", "zh-TW", "ja", "ko"].each do |lang|
606 626 with_settings :default_language => lang do
607 627
608 628 get :index
609 629 assert_response :success
610 630 assert_template 'index'
611 631
612 632 get :index, :format => 'pdf'
613 633 assert_response :success
614 634 assert_not_nil assigns(:issues)
615 635 assert_equal 'application/pdf', @response.content_type
616 636
617 637 get :index, :project_id => 1, :format => 'pdf'
618 638 assert_response :success
619 639 assert_not_nil assigns(:issues)
620 640 assert_equal 'application/pdf', @response.content_type
621 641
622 642 get :index, :project_id => 1, :query_id => 6, :format => 'pdf'
623 643 assert_response :success
624 644 assert_not_nil assigns(:issues)
625 645 assert_equal 'application/pdf', @response.content_type
626 646 end
627 647 end
628 648 end
629 649
630 650 def test_index_pdf_with_query_grouped_by_list_custom_field
631 651 get :index, :project_id => 1, :query_id => 9, :format => 'pdf'
632 652 assert_response :success
633 653 assert_not_nil assigns(:issues)
634 654 assert_not_nil assigns(:issue_count_by_group)
635 655 assert_equal 'application/pdf', @response.content_type
636 656 end
637 657
638 658 def test_index_atom
639 659 get :index, :project_id => 'ecookbook', :format => 'atom'
640 660 assert_response :success
641 661 assert_template 'common/feed'
642 662 assert_equal 'application/atom+xml', response.content_type
643 663
644 664 assert_select 'feed' do
645 665 assert_select 'link[rel=self][href=?]', 'http://test.host/projects/ecookbook/issues.atom'
646 666 assert_select 'link[rel=alternate][href=?]', 'http://test.host/projects/ecookbook/issues'
647 667 assert_select 'entry link[href=?]', 'http://test.host/issues/1'
648 668 end
649 669 end
650 670
651 671 def test_index_sort
652 672 get :index, :sort => 'tracker,id:desc'
653 673 assert_response :success
654 674
655 675 sort_params = @request.session['issues_index_sort']
656 676 assert sort_params.is_a?(String)
657 677 assert_equal 'tracker,id:desc', sort_params
658 678
659 679 issues = assigns(:issues)
660 680 assert_not_nil issues
661 681 assert !issues.empty?
662 682 assert_equal issues.sort {|a,b| a.tracker == b.tracker ? b.id <=> a.id : a.tracker <=> b.tracker }.collect(&:id), issues.collect(&:id)
663 683 assert_select 'table.issues.sort-by-tracker.sort-asc'
664 684 end
665 685
666 686 def test_index_sort_by_field_not_included_in_columns
667 687 Setting.issue_list_default_columns = %w(subject author)
668 688 get :index, :sort => 'tracker'
669 689 end
670 690
671 691 def test_index_sort_by_assigned_to
672 692 get :index, :sort => 'assigned_to'
673 693 assert_response :success
674 694 assignees = assigns(:issues).collect(&:assigned_to).compact
675 695 assert_equal assignees.sort, assignees
676 696 assert_select 'table.issues.sort-by-assigned-to.sort-asc'
677 697 end
678 698
679 699 def test_index_sort_by_assigned_to_desc
680 700 get :index, :sort => 'assigned_to:desc'
681 701 assert_response :success
682 702 assignees = assigns(:issues).collect(&:assigned_to).compact
683 703 assert_equal assignees.sort.reverse, assignees
684 704 assert_select 'table.issues.sort-by-assigned-to.sort-desc'
685 705 end
686 706
687 707 def test_index_group_by_assigned_to
688 708 get :index, :group_by => 'assigned_to', :sort => 'priority'
689 709 assert_response :success
690 710 end
691 711
692 712 def test_index_sort_by_author
693 713 get :index, :sort => 'author'
694 714 assert_response :success
695 715 authors = assigns(:issues).collect(&:author)
696 716 assert_equal authors.sort, authors
697 717 end
698 718
699 719 def test_index_sort_by_author_desc
700 720 get :index, :sort => 'author:desc'
701 721 assert_response :success
702 722 authors = assigns(:issues).collect(&:author)
703 723 assert_equal authors.sort.reverse, authors
704 724 end
705 725
706 726 def test_index_group_by_author
707 727 get :index, :group_by => 'author', :sort => 'priority'
708 728 assert_response :success
709 729 end
710 730
711 731 def test_index_sort_by_spent_hours
712 732 get :index, :sort => 'spent_hours:desc'
713 733 assert_response :success
714 734 hours = assigns(:issues).collect(&:spent_hours)
715 735 assert_equal hours.sort.reverse, hours
716 736 end
717 737
718 738 def test_index_sort_by_total_spent_hours
719 739 get :index, :sort => 'total_spent_hours:desc'
720 740 assert_response :success
721 741 hours = assigns(:issues).collect(&:total_spent_hours)
722 742 assert_equal hours.sort.reverse, hours
723 743 end
724 744
725 745 def test_index_sort_by_total_estimated_hours
726 746 get :index, :sort => 'total_estimated_hours:desc'
727 747 assert_response :success
728 748 hours = assigns(:issues).collect(&:total_estimated_hours)
729 749 assert_equal hours.sort.reverse, hours
730 750 end
731 751
732 752 def test_index_sort_by_user_custom_field
733 753 cf = IssueCustomField.create!(:name => 'User', :is_for_all => true, :tracker_ids => [1,2,3], :field_format => 'user')
734 754 CustomValue.create!(:custom_field => cf, :customized => Issue.find(1), :value => '2')
735 755 CustomValue.create!(:custom_field => cf, :customized => Issue.find(2), :value => '3')
736 756 CustomValue.create!(:custom_field => cf, :customized => Issue.find(3), :value => '3')
737 757 CustomValue.create!(:custom_field => cf, :customized => Issue.find(5), :value => '')
738 758
739 759 get :index, :project_id => 1, :set_filter => 1, :sort => "cf_#{cf.id},id"
740 760 assert_response :success
741 761
742 762 assert_equal [2, 3, 1], assigns(:issues).select {|issue| issue.custom_field_value(cf).present?}.map(&:id)
743 763 end
744 764
745 765 def test_index_with_columns
746 766 columns = ['tracker', 'subject', 'assigned_to']
747 767 get :index, :set_filter => 1, :c => columns
748 768 assert_response :success
749 769
750 770 # query should use specified columns
751 771 query = assigns(:query)
752 772 assert_kind_of IssueQuery, query
753 773 assert_equal columns, query.column_names.map(&:to_s)
754 774
755 775 # columns should be stored in session
756 776 assert_kind_of Hash, session[:query]
757 777 assert_kind_of Array, session[:query][:column_names]
758 778 assert_equal columns, session[:query][:column_names].map(&:to_s)
759 779
760 780 # ensure only these columns are kept in the selected columns list
761 781 assert_select 'select#selected_columns option' do
762 782 assert_select 'option', 3
763 783 assert_select 'option[value=tracker]'
764 784 assert_select 'option[value=project]', 0
765 785 end
766 786 end
767 787
768 788 def test_index_without_project_should_implicitly_add_project_column_to_default_columns
769 789 Setting.issue_list_default_columns = ['tracker', 'subject', 'assigned_to']
770 790 get :index, :set_filter => 1
771 791
772 792 # query should use specified columns
773 793 query = assigns(:query)
774 794 assert_kind_of IssueQuery, query
775 795 assert_equal [:id, :project, :tracker, :subject, :assigned_to], query.columns.map(&:name)
776 796 end
777 797
778 798 def test_index_without_project_and_explicit_default_columns_should_not_add_project_column
779 799 Setting.issue_list_default_columns = ['tracker', 'subject', 'assigned_to']
780 800 columns = ['id', 'tracker', 'subject', 'assigned_to']
781 801 get :index, :set_filter => 1, :c => columns
782 802
783 803 # query should use specified columns
784 804 query = assigns(:query)
785 805 assert_kind_of IssueQuery, query
786 806 assert_equal columns.map(&:to_sym), query.columns.map(&:name)
787 807 end
788 808
789 809 def test_index_with_default_columns_should_respect_default_columns_order
790 810 columns = ['assigned_to', 'subject', 'status', 'tracker']
791 811 with_settings :issue_list_default_columns => columns do
792 812 get :index, :project_id => 1, :set_filter => 1
793 813
794 814 query = assigns(:query)
795 815 assert_equal (['id'] + columns).map(&:to_sym), query.columns.map(&:name)
796 816 end
797 817 end
798 818
799 819 def test_index_with_custom_field_column
800 820 columns = %w(tracker subject cf_2)
801 821 get :index, :set_filter => 1, :c => columns
802 822 assert_response :success
803 823
804 824 # query should use specified columns
805 825 query = assigns(:query)
806 826 assert_kind_of IssueQuery, query
807 827 assert_equal columns, query.column_names.map(&:to_s)
808 828
809 829 assert_select 'table.issues td.cf_2.string'
810 830 end
811 831
812 832 def test_index_with_multi_custom_field_column
813 833 field = CustomField.find(1)
814 834 field.update_attribute :multiple, true
815 835 issue = Issue.find(1)
816 836 issue.custom_field_values = {1 => ['MySQL', 'Oracle']}
817 837 issue.save!
818 838
819 839 get :index, :set_filter => 1, :c => %w(tracker subject cf_1)
820 840 assert_response :success
821 841
822 842 assert_select 'table.issues td.cf_1', :text => 'MySQL, Oracle'
823 843 end
824 844
825 845 def test_index_with_multi_user_custom_field_column
826 846 field = IssueCustomField.create!(:name => 'Multi user', :field_format => 'user', :multiple => true,
827 847 :tracker_ids => [1], :is_for_all => true)
828 848 issue = Issue.find(1)
829 849 issue.custom_field_values = {field.id => ['2', '3']}
830 850 issue.save!
831 851
832 852 get :index, :set_filter => 1, :c => ['tracker', 'subject', "cf_#{field.id}"]
833 853 assert_response :success
834 854
835 855 assert_select "table.issues td.cf_#{field.id}" do
836 856 assert_select 'a', 2
837 857 assert_select 'a[href=?]', '/users/2', :text => 'John Smith'
838 858 assert_select 'a[href=?]', '/users/3', :text => 'Dave Lopper'
839 859 end
840 860 end
841 861
842 862 def test_index_with_date_column
843 863 with_settings :date_format => '%d/%m/%Y' do
844 864 Issue.find(1).update_attribute :start_date, '1987-08-24'
845 865 get :index, :set_filter => 1, :c => %w(start_date)
846 866 assert_select "table.issues td.start_date", :text => '24/08/1987'
847 867 end
848 868 end
849 869
850 870 def test_index_with_done_ratio_column
851 871 Issue.find(1).update_attribute :done_ratio, 40
852 872 get :index, :set_filter => 1, :c => %w(done_ratio)
853 873 assert_select 'table.issues td.done_ratio' do
854 874 assert_select 'table.progress' do
855 875 assert_select 'td.closed[style=?]', 'width: 40%;'
856 876 end
857 877 end
858 878 end
859 879
860 880 def test_index_with_spent_hours_column
861 881 Issue.expects(:load_visible_spent_hours).once
862 882 get :index, :set_filter => 1, :c => %w(subject spent_hours)
863 883 assert_select 'table.issues tr#issue-3 td.spent_hours', :text => '1.00'
864 884 end
865 885
866 886 def test_index_with_total_spent_hours_column
867 887 Issue.expects(:load_visible_total_spent_hours).once
868 888 get :index, :set_filter => 1, :c => %w(subject total_spent_hours)
869 889 assert_select 'table.issues tr#issue-3 td.total_spent_hours', :text => '1.00'
870 890 end
871 891
872 892 def test_index_with_total_estimated_hours_column
873 893 get :index, :set_filter => 1, :c => %w(subject total_estimated_hours)
874 894 assert_select 'table.issues td.total_estimated_hours'
875 895 end
876 896
877 897 def test_index_should_not_show_spent_hours_column_without_permission
878 898 Role.anonymous.remove_permission! :view_time_entries
879 899 get :index, :set_filter => 1, :c => %w(subject spent_hours)
880 900 assert_select 'td.spent_hours', 0
881 901 end
882 902
883 903 def test_index_with_fixed_version_column
884 904 get :index, :set_filter => 1, :c => %w(fixed_version)
885 905 assert_select 'table.issues td.fixed_version' do
886 906 assert_select 'a[href=?]', '/versions/2', :text => 'eCookbook - 1.0'
887 907 end
888 908 end
889 909
890 910 def test_index_with_relations_column
891 911 IssueRelation.delete_all
892 912 IssueRelation.create!(:relation_type => "relates", :issue_from => Issue.find(1), :issue_to => Issue.find(7))
893 913 IssueRelation.create!(:relation_type => "relates", :issue_from => Issue.find(8), :issue_to => Issue.find(1))
894 914 IssueRelation.create!(:relation_type => "blocks", :issue_from => Issue.find(1), :issue_to => Issue.find(11))
895 915 IssueRelation.create!(:relation_type => "blocks", :issue_from => Issue.find(12), :issue_to => Issue.find(2))
896 916
897 917 get :index, :set_filter => 1, :c => %w(subject relations)
898 918 assert_response :success
899 919 assert_select "tr#issue-1 td.relations" do
900 920 assert_select "span", 3
901 921 assert_select "span", :text => "Related to #7"
902 922 assert_select "span", :text => "Related to #8"
903 923 assert_select "span", :text => "Blocks #11"
904 924 end
905 925 assert_select "tr#issue-2 td.relations" do
906 926 assert_select "span", 1
907 927 assert_select "span", :text => "Blocked by #12"
908 928 end
909 929 assert_select "tr#issue-3 td.relations" do
910 930 assert_select "span", 0
911 931 end
912 932
913 933 get :index, :set_filter => 1, :c => %w(relations), :format => 'csv'
914 934 assert_response :success
915 935 assert_equal 'text/csv; header=present', response.content_type
916 936 lines = response.body.chomp.split("\n")
917 937 assert_include '1,"Related to #7, Related to #8, Blocks #11"', lines
918 938 assert_include '2,Blocked by #12', lines
919 939 assert_include '3,""', lines
920 940
921 941 get :index, :set_filter => 1, :c => %w(subject relations), :format => 'pdf'
922 942 assert_response :success
923 943 assert_equal 'application/pdf', response.content_type
924 944 end
925 945
926 946 def test_index_with_description_column
927 947 get :index, :set_filter => 1, :c => %w(subject description)
928 948
929 949 assert_select 'table.issues thead th', 3 # columns: chekbox + id + subject
930 950 assert_select 'td.description[colspan="3"]', :text => 'Unable to print recipes'
931 951
932 952 get :index, :set_filter => 1, :c => %w(subject description), :format => 'pdf'
933 953 assert_response :success
934 954 assert_equal 'application/pdf', response.content_type
935 955 end
936 956
937 957 def test_index_with_parent_column
938 958 Issue.delete_all
939 959 parent = Issue.generate!
940 960 child = Issue.generate!(:parent_issue_id => parent.id)
941 961
942 962 get :index, :c => %w(parent)
943 963
944 964 assert_select 'td.parent', :text => "#{parent.tracker} ##{parent.id}"
945 965 assert_select 'td.parent a[title=?]', parent.subject
946 966 end
947 967
948 968 def test_index_with_estimated_hours_total
949 969 Issue.delete_all
950 970 Issue.generate!(:estimated_hours => 5.5)
951 971 Issue.generate!(:estimated_hours => 1.1)
952 972
953 973 get :index, :t => %w(estimated_hours)
954 974 assert_response :success
955 975 assert_select '.query-totals'
956 976 assert_select '.total-for-estimated-hours span.value', :text => '6.60'
957 977 assert_select 'input[type=checkbox][name=?][value=estimated_hours][checked=checked]', 't[]'
958 978 end
959 979
960 980 def test_index_with_grouped_query_and_estimated_hours_total
961 981 Issue.delete_all
962 982 Issue.generate!(:estimated_hours => 5.5, :category_id => 1)
963 983 Issue.generate!(:estimated_hours => 2.3, :category_id => 1)
964 984 Issue.generate!(:estimated_hours => 1.1, :category_id => 2)
965 985 Issue.generate!(:estimated_hours => 4.6)
966 986
967 987 get :index, :t => %w(estimated_hours), :group_by => 'category'
968 988 assert_response :success
969 989 assert_select '.query-totals'
970 990 assert_select '.query-totals .total-for-estimated-hours span.value', :text => '13.50'
971 991 assert_select 'tr.group', :text => /Printing/ do
972 992 assert_select '.total-for-estimated-hours span.value', :text => '7.80'
973 993 end
974 994 assert_select 'tr.group', :text => /Recipes/ do
975 995 assert_select '.total-for-estimated-hours span.value', :text => '1.10'
976 996 end
977 997 assert_select 'tr.group', :text => /blank/ do
978 998 assert_select '.total-for-estimated-hours span.value', :text => '4.60'
979 999 end
980 1000 end
981 1001
982 1002 def test_index_with_int_custom_field_total
983 1003 field = IssueCustomField.generate!(:field_format => 'int', :is_for_all => true)
984 1004 CustomValue.create!(:customized => Issue.find(1), :custom_field => field, :value => '2')
985 1005 CustomValue.create!(:customized => Issue.find(2), :custom_field => field, :value => '7')
986 1006
987 1007 get :index, :t => ["cf_#{field.id}"]
988 1008 assert_response :success
989 1009 assert_select '.query-totals'
990 1010 assert_select ".total-for-cf-#{field.id} span.value", :text => '9'
991 1011 end
992 1012
993 1013 def test_index_totals_should_default_to_settings
994 1014 with_settings :issue_list_default_totals => ['estimated_hours'] do
995 1015 get :index
996 1016 assert_response :success
997 1017 assert_select '.total-for-estimated-hours span.value'
998 1018 assert_select '.query-totals>span', 1
999 1019 end
1000 1020 end
1001 1021
1002 1022 def test_index_send_html_if_query_is_invalid
1003 1023 get :index, :f => ['start_date'], :op => {:start_date => '='}
1004 1024 assert_equal 'text/html', @response.content_type
1005 1025 assert_template 'index'
1006 1026 end
1007 1027
1008 1028 def test_index_send_nothing_if_query_is_invalid
1009 1029 get :index, :f => ['start_date'], :op => {:start_date => '='}, :format => 'csv'
1010 1030 assert_equal 'text/csv', @response.content_type
1011 1031 assert @response.body.blank?
1012 1032 end
1013 1033
1014 1034 def test_show_by_anonymous
1015 1035 get :show, :id => 1
1016 1036 assert_response :success
1017 1037 assert_template 'show'
1018 1038 assert_equal Issue.find(1), assigns(:issue)
1019 1039 assert_select 'div.issue div.description', :text => /Unable to print recipes/
1020 1040 # anonymous role is allowed to add a note
1021 1041 assert_select 'form#issue-form' do
1022 1042 assert_select 'fieldset' do
1023 1043 assert_select 'legend', :text => 'Notes'
1024 1044 assert_select 'textarea[name=?]', 'issue[notes]'
1025 1045 end
1026 1046 end
1027 1047 assert_select 'title', :text => "Bug #1: Cannot print recipes - eCookbook - Redmine"
1028 1048 end
1029 1049
1030 1050 def test_show_by_manager
1031 1051 @request.session[:user_id] = 2
1032 1052 get :show, :id => 1
1033 1053 assert_response :success
1034 1054 assert_select 'a', :text => /Quote/
1035 1055 assert_select 'form#issue-form' do
1036 1056 assert_select 'fieldset' do
1037 1057 assert_select 'legend', :text => 'Change properties'
1038 1058 assert_select 'input[name=?]', 'issue[subject]'
1039 1059 end
1040 1060 assert_select 'fieldset' do
1041 1061 assert_select 'legend', :text => 'Log time'
1042 1062 assert_select 'input[name=?]', 'time_entry[hours]'
1043 1063 end
1044 1064 assert_select 'fieldset' do
1045 1065 assert_select 'legend', :text => 'Notes'
1046 1066 assert_select 'textarea[name=?]', 'issue[notes]'
1047 1067 end
1048 1068 end
1049 1069 end
1050 1070
1051 1071 def test_show_should_display_update_form
1052 1072 @request.session[:user_id] = 2
1053 1073 get :show, :id => 1
1054 1074 assert_response :success
1055 1075
1056 1076 assert_select 'form#issue-form' do
1057 1077 assert_select 'input[name=?]', 'issue[is_private]'
1058 1078 assert_select 'select[name=?]', 'issue[project_id]'
1059 1079 assert_select 'select[name=?]', 'issue[tracker_id]'
1060 1080 assert_select 'input[name=?]', 'issue[subject]'
1061 1081 assert_select 'textarea[name=?]', 'issue[description]'
1062 1082 assert_select 'select[name=?]', 'issue[status_id]'
1063 1083 assert_select 'select[name=?]', 'issue[priority_id]'
1064 1084 assert_select 'select[name=?]', 'issue[assigned_to_id]'
1065 1085 assert_select 'select[name=?]', 'issue[category_id]'
1066 1086 assert_select 'select[name=?]', 'issue[fixed_version_id]'
1067 1087 assert_select 'input[name=?]', 'issue[parent_issue_id]'
1068 1088 assert_select 'input[name=?]', 'issue[start_date]'
1069 1089 assert_select 'input[name=?]', 'issue[due_date]'
1070 1090 assert_select 'select[name=?]', 'issue[done_ratio]'
1071 1091 assert_select 'input[name=?]', 'issue[custom_field_values][2]'
1072 1092 assert_select 'input[name=?]', 'issue[watcher_user_ids][]', 0
1073 1093 assert_select 'textarea[name=?]', 'issue[notes]'
1074 1094 end
1075 1095 end
1076 1096
1077 1097 def test_show_should_display_update_form_with_minimal_permissions
1078 1098 Role.find(1).update_attribute :permissions, [:view_issues, :add_issue_notes]
1079 1099 WorkflowTransition.delete_all :role_id => 1
1080 1100
1081 1101 @request.session[:user_id] = 2
1082 1102 get :show, :id => 1
1083 1103 assert_response :success
1084 1104
1085 1105 assert_select 'form#issue-form' do
1086 1106 assert_select 'input[name=?]', 'issue[is_private]', 0
1087 1107 assert_select 'select[name=?]', 'issue[project_id]', 0
1088 1108 assert_select 'select[name=?]', 'issue[tracker_id]', 0
1089 1109 assert_select 'input[name=?]', 'issue[subject]', 0
1090 1110 assert_select 'textarea[name=?]', 'issue[description]', 0
1091 1111 assert_select 'select[name=?]', 'issue[status_id]', 0
1092 1112 assert_select 'select[name=?]', 'issue[priority_id]', 0
1093 1113 assert_select 'select[name=?]', 'issue[assigned_to_id]', 0
1094 1114 assert_select 'select[name=?]', 'issue[category_id]', 0
1095 1115 assert_select 'select[name=?]', 'issue[fixed_version_id]', 0
1096 1116 assert_select 'input[name=?]', 'issue[parent_issue_id]', 0
1097 1117 assert_select 'input[name=?]', 'issue[start_date]', 0
1098 1118 assert_select 'input[name=?]', 'issue[due_date]', 0
1099 1119 assert_select 'select[name=?]', 'issue[done_ratio]', 0
1100 1120 assert_select 'input[name=?]', 'issue[custom_field_values][2]', 0
1101 1121 assert_select 'input[name=?]', 'issue[watcher_user_ids][]', 0
1102 1122 assert_select 'textarea[name=?]', 'issue[notes]'
1103 1123 end
1104 1124 end
1105 1125
1106 1126 def test_show_should_not_display_update_form_without_permissions
1107 1127 Role.find(1).update_attribute :permissions, [:view_issues]
1108 1128
1109 1129 @request.session[:user_id] = 2
1110 1130 get :show, :id => 1
1111 1131 assert_response :success
1112 1132
1113 1133 assert_select 'form#issue-form', 0
1114 1134 end
1115 1135
1116 1136 def test_update_form_should_not_display_inactive_enumerations
1117 1137 assert !IssuePriority.find(15).active?
1118 1138
1119 1139 @request.session[:user_id] = 2
1120 1140 get :show, :id => 1
1121 1141 assert_response :success
1122 1142
1123 1143 assert_select 'form#issue-form' do
1124 1144 assert_select 'select[name=?]', 'issue[priority_id]' do
1125 1145 assert_select 'option[value="4"]'
1126 1146 assert_select 'option[value="15"]', 0
1127 1147 end
1128 1148 end
1129 1149 end
1130 1150
1131 1151 def test_update_form_should_allow_attachment_upload
1132 1152 @request.session[:user_id] = 2
1133 1153 get :show, :id => 1
1134 1154
1135 1155 assert_select 'form#issue-form[method=post][enctype="multipart/form-data"]' do
1136 1156 assert_select 'input[type=file][name=?]', 'attachments[dummy][file]'
1137 1157 end
1138 1158 end
1139 1159
1140 1160 def test_show_should_deny_anonymous_access_without_permission
1141 1161 Role.anonymous.remove_permission!(:view_issues)
1142 1162 get :show, :id => 1
1143 1163 assert_response :redirect
1144 1164 end
1145 1165
1146 1166 def test_show_should_deny_anonymous_access_to_private_issue
1147 1167 Issue.where(:id => 1).update_all(["is_private = ?", true])
1148 1168 get :show, :id => 1
1149 1169 assert_response :redirect
1150 1170 end
1151 1171
1152 1172 def test_show_should_deny_non_member_access_without_permission
1153 1173 Role.non_member.remove_permission!(:view_issues)
1154 1174 @request.session[:user_id] = 9
1155 1175 get :show, :id => 1
1156 1176 assert_response 403
1157 1177 end
1158 1178
1159 1179 def test_show_should_deny_non_member_access_to_private_issue
1160 1180 Issue.where(:id => 1).update_all(["is_private = ?", true])
1161 1181 @request.session[:user_id] = 9
1162 1182 get :show, :id => 1
1163 1183 assert_response 403
1164 1184 end
1165 1185
1166 1186 def test_show_should_deny_member_access_without_permission
1167 1187 Role.find(1).remove_permission!(:view_issues)
1168 1188 @request.session[:user_id] = 2
1169 1189 get :show, :id => 1
1170 1190 assert_response 403
1171 1191 end
1172 1192
1173 1193 def test_show_should_deny_member_access_to_private_issue_without_permission
1174 1194 Issue.where(:id => 1).update_all(["is_private = ?", true])
1175 1195 @request.session[:user_id] = 3
1176 1196 get :show, :id => 1
1177 1197 assert_response 403
1178 1198 end
1179 1199
1180 1200 def test_show_should_allow_author_access_to_private_issue
1181 1201 Issue.where(:id => 1).update_all(["is_private = ?, author_id = 3", true])
1182 1202 @request.session[:user_id] = 3
1183 1203 get :show, :id => 1
1184 1204 assert_response :success
1185 1205 end
1186 1206
1187 1207 def test_show_should_allow_assignee_access_to_private_issue
1188 1208 Issue.where(:id => 1).update_all(["is_private = ?, assigned_to_id = 3", true])
1189 1209 @request.session[:user_id] = 3
1190 1210 get :show, :id => 1
1191 1211 assert_response :success
1192 1212 end
1193 1213
1194 1214 def test_show_should_allow_member_access_to_private_issue_with_permission
1195 1215 Issue.where(:id => 1).update_all(["is_private = ?", true])
1196 1216 User.find(3).roles_for_project(Project.find(1)).first.update_attribute :issues_visibility, 'all'
1197 1217 @request.session[:user_id] = 3
1198 1218 get :show, :id => 1
1199 1219 assert_response :success
1200 1220 end
1201 1221
1202 1222 def test_show_should_not_disclose_relations_to_invisible_issues
1203 1223 Setting.cross_project_issue_relations = '1'
1204 1224 IssueRelation.create!(:issue_from => Issue.find(1), :issue_to => Issue.find(2), :relation_type => 'relates')
1205 1225 # Relation to a private project issue
1206 1226 IssueRelation.create!(:issue_from => Issue.find(1), :issue_to => Issue.find(4), :relation_type => 'relates')
1207 1227
1208 1228 get :show, :id => 1
1209 1229 assert_response :success
1210 1230
1211 1231 assert_select 'div#relations' do
1212 1232 assert_select 'a', :text => /#2$/
1213 1233 assert_select 'a', :text => /#4$/, :count => 0
1214 1234 end
1215 1235 end
1216 1236
1217 1237 def test_show_should_list_subtasks
1218 1238 Issue.create!(:project_id => 1, :author_id => 1, :tracker_id => 1, :parent_issue_id => 1, :subject => 'Child Issue')
1219 1239
1220 1240 get :show, :id => 1
1221 1241 assert_response :success
1222 1242
1223 1243 assert_select 'div#issue_tree' do
1224 1244 assert_select 'td.subject', :text => /Child Issue/
1225 1245 end
1226 1246 end
1227 1247
1228 1248 def test_show_should_list_parents
1229 1249 issue = Issue.create!(:project_id => 1, :author_id => 1, :tracker_id => 1, :parent_issue_id => 1, :subject => 'Child Issue')
1230 1250
1231 1251 get :show, :id => issue.id
1232 1252 assert_response :success
1233 1253
1234 1254 assert_select 'div.subject' do
1235 1255 assert_select 'h3', 'Child Issue'
1236 1256 assert_select 'a[href="/issues/1"]'
1237 1257 end
1238 1258 end
1239 1259
1240 1260 def test_show_should_not_display_prev_next_links_without_query_in_session
1241 1261 get :show, :id => 1
1242 1262 assert_response :success
1243 1263 assert_nil assigns(:prev_issue_id)
1244 1264 assert_nil assigns(:next_issue_id)
1245 1265
1246 1266 assert_select 'div.next-prev-links', 0
1247 1267 end
1248 1268
1249 1269 def test_show_should_display_prev_next_links_with_query_in_session
1250 1270 @request.session[:query] = {:filters => {'status_id' => {:values => [''], :operator => 'o'}}, :project_id => nil}
1251 1271 @request.session['issues_index_sort'] = 'id'
1252 1272
1253 1273 with_settings :display_subprojects_issues => '0' do
1254 1274 get :show, :id => 3
1255 1275 end
1256 1276
1257 1277 assert_response :success
1258 1278 # Previous and next issues for all projects
1259 1279 assert_equal 2, assigns(:prev_issue_id)
1260 1280 assert_equal 5, assigns(:next_issue_id)
1261 1281
1262 1282 count = Issue.open.visible.count
1263 1283
1264 1284 assert_select 'div.next-prev-links' do
1265 1285 assert_select 'a[href="/issues/2"]', :text => /Previous/
1266 1286 assert_select 'a[href="/issues/5"]', :text => /Next/
1267 1287 assert_select 'span.position', :text => "3 of #{count}"
1268 1288 end
1269 1289 end
1270 1290
1271 1291 def test_show_should_display_prev_next_links_with_saved_query_in_session
1272 1292 query = IssueQuery.create!(:name => 'test', :visibility => IssueQuery::VISIBILITY_PUBLIC, :user_id => 1,
1273 1293 :filters => {'status_id' => {:values => ['5'], :operator => '='}},
1274 1294 :sort_criteria => [['id', 'asc']])
1275 1295 @request.session[:query] = {:id => query.id, :project_id => nil}
1276 1296
1277 1297 get :show, :id => 11
1278 1298
1279 1299 assert_response :success
1280 1300 assert_equal query, assigns(:query)
1281 1301 # Previous and next issues for all projects
1282 1302 assert_equal 8, assigns(:prev_issue_id)
1283 1303 assert_equal 12, assigns(:next_issue_id)
1284 1304
1285 1305 assert_select 'div.next-prev-links' do
1286 1306 assert_select 'a[href="/issues/8"]', :text => /Previous/
1287 1307 assert_select 'a[href="/issues/12"]', :text => /Next/
1288 1308 end
1289 1309 end
1290 1310
1291 1311 def test_show_should_display_prev_next_links_with_query_and_sort_on_association
1292 1312 @request.session[:query] = {:filters => {'status_id' => {:values => [''], :operator => 'o'}}, :project_id => nil}
1293 1313
1294 1314 %w(project tracker status priority author assigned_to category fixed_version).each do |assoc_sort|
1295 1315 @request.session['issues_index_sort'] = assoc_sort
1296 1316
1297 1317 get :show, :id => 3
1298 1318 assert_response :success, "Wrong response status for #{assoc_sort} sort"
1299 1319
1300 1320 assert_select 'div.next-prev-links' do
1301 1321 assert_select 'a', :text => /(Previous|Next)/
1302 1322 end
1303 1323 end
1304 1324 end
1305 1325
1306 1326 def test_show_should_display_prev_next_links_with_project_query_in_session
1307 1327 @request.session[:query] = {:filters => {'status_id' => {:values => [''], :operator => 'o'}}, :project_id => 1}
1308 1328 @request.session['issues_index_sort'] = 'id'
1309 1329
1310 1330 with_settings :display_subprojects_issues => '0' do
1311 1331 get :show, :id => 3
1312 1332 end
1313 1333
1314 1334 assert_response :success
1315 1335 # Previous and next issues inside project
1316 1336 assert_equal 2, assigns(:prev_issue_id)
1317 1337 assert_equal 7, assigns(:next_issue_id)
1318 1338
1319 1339 assert_select 'div.next-prev-links' do
1320 1340 assert_select 'a[href="/issues/2"]', :text => /Previous/
1321 1341 assert_select 'a[href="/issues/7"]', :text => /Next/
1322 1342 end
1323 1343 end
1324 1344
1325 1345 def test_show_should_not_display_prev_link_for_first_issue
1326 1346 @request.session[:query] = {:filters => {'status_id' => {:values => [''], :operator => 'o'}}, :project_id => 1}
1327 1347 @request.session['issues_index_sort'] = 'id'
1328 1348
1329 1349 with_settings :display_subprojects_issues => '0' do
1330 1350 get :show, :id => 1
1331 1351 end
1332 1352
1333 1353 assert_response :success
1334 1354 assert_nil assigns(:prev_issue_id)
1335 1355 assert_equal 2, assigns(:next_issue_id)
1336 1356
1337 1357 assert_select 'div.next-prev-links' do
1338 1358 assert_select 'a', :text => /Previous/, :count => 0
1339 1359 assert_select 'a[href="/issues/2"]', :text => /Next/
1340 1360 end
1341 1361 end
1342 1362
1343 1363 def test_show_should_not_display_prev_next_links_for_issue_not_in_query_results
1344 1364 @request.session[:query] = {:filters => {'status_id' => {:values => [''], :operator => 'c'}}, :project_id => 1}
1345 1365 @request.session['issues_index_sort'] = 'id'
1346 1366
1347 1367 get :show, :id => 1
1348 1368
1349 1369 assert_response :success
1350 1370 assert_nil assigns(:prev_issue_id)
1351 1371 assert_nil assigns(:next_issue_id)
1352 1372
1353 1373 assert_select 'a', :text => /Previous/, :count => 0
1354 1374 assert_select 'a', :text => /Next/, :count => 0
1355 1375 end
1356 1376
1357 1377 def test_show_show_should_display_prev_next_links_with_query_sort_by_user_custom_field
1358 1378 cf = IssueCustomField.create!(:name => 'User', :is_for_all => true, :tracker_ids => [1,2,3], :field_format => 'user')
1359 1379 CustomValue.create!(:custom_field => cf, :customized => Issue.find(1), :value => '2')
1360 1380 CustomValue.create!(:custom_field => cf, :customized => Issue.find(2), :value => '3')
1361 1381 CustomValue.create!(:custom_field => cf, :customized => Issue.find(3), :value => '3')
1362 1382 CustomValue.create!(:custom_field => cf, :customized => Issue.find(5), :value => '')
1363 1383
1364 1384 query = IssueQuery.create!(:name => 'test', :visibility => IssueQuery::VISIBILITY_PUBLIC, :user_id => 1, :filters => {},
1365 1385 :sort_criteria => [["cf_#{cf.id}", 'asc'], ['id', 'asc']])
1366 1386 @request.session[:query] = {:id => query.id, :project_id => nil}
1367 1387
1368 1388 get :show, :id => 3
1369 1389 assert_response :success
1370 1390
1371 1391 assert_equal 2, assigns(:prev_issue_id)
1372 1392 assert_equal 1, assigns(:next_issue_id)
1373 1393
1374 1394 assert_select 'div.next-prev-links' do
1375 1395 assert_select 'a[href="/issues/2"]', :text => /Previous/
1376 1396 assert_select 'a[href="/issues/1"]', :text => /Next/
1377 1397 end
1378 1398 end
1379 1399
1380 1400 def test_show_should_display_category_field_if_categories_are_defined
1381 1401 Issue.update_all :category_id => nil
1382 1402
1383 1403 get :show, :id => 1
1384 1404 assert_response :success
1385 1405 assert_select '.attributes .category'
1386 1406 end
1387 1407
1388 1408 def test_show_should_not_display_category_field_if_no_categories_are_defined
1389 1409 Project.find(1).issue_categories.delete_all
1390 1410
1391 1411 get :show, :id => 1
1392 1412 assert_response :success
1393 1413 assert_select 'table.attributes .category', 0
1394 1414 end
1395 1415
1396 1416 def test_show_should_display_link_to_the_assignee
1397 1417 get :show, :id => 2
1398 1418 assert_response :success
1399 1419 assert_select '.assigned-to' do
1400 1420 assert_select 'a[href="/users/3"]'
1401 1421 end
1402 1422 end
1403 1423
1404 1424 def test_show_should_display_visible_changesets_from_other_projects
1405 1425 project = Project.find(2)
1406 1426 issue = project.issues.first
1407 1427 issue.changeset_ids = [102]
1408 1428 issue.save!
1409 1429 # changesets from other projects should be displayed even if repository
1410 1430 # is disabled on issue's project
1411 1431 project.disable_module! :repository
1412 1432
1413 1433 @request.session[:user_id] = 2
1414 1434 get :show, :id => issue.id
1415 1435
1416 1436 assert_select 'a[href=?]', '/projects/ecookbook/repository/revisions/3'
1417 1437 end
1418 1438
1419 1439 def test_show_should_display_watchers
1420 1440 @request.session[:user_id] = 2
1421 1441 Issue.find(1).add_watcher User.find(2)
1422 1442
1423 1443 get :show, :id => 1
1424 1444 assert_select 'div#watchers ul' do
1425 1445 assert_select 'li' do
1426 1446 assert_select 'a[href="/users/2"]'
1427 1447 assert_select 'a img[alt=Delete]'
1428 1448 end
1429 1449 end
1430 1450 end
1431 1451
1432 1452 def test_show_should_display_watchers_with_gravatars
1433 1453 @request.session[:user_id] = 2
1434 1454 Issue.find(1).add_watcher User.find(2)
1435 1455
1436 1456 with_settings :gravatar_enabled => '1' do
1437 1457 get :show, :id => 1
1438 1458 end
1439 1459
1440 1460 assert_select 'div#watchers ul' do
1441 1461 assert_select 'li' do
1442 1462 assert_select 'img.gravatar'
1443 1463 assert_select 'a[href="/users/2"]'
1444 1464 assert_select 'a img[alt=Delete]'
1445 1465 end
1446 1466 end
1447 1467 end
1448 1468
1449 1469 def test_show_with_thumbnails_enabled_should_display_thumbnails
1450 1470 @request.session[:user_id] = 2
1451 1471
1452 1472 with_settings :thumbnails_enabled => '1' do
1453 1473 get :show, :id => 14
1454 1474 assert_response :success
1455 1475 end
1456 1476
1457 1477 assert_select 'div.thumbnails' do
1458 1478 assert_select 'a[href="/attachments/16/testfile.png"]' do
1459 1479 assert_select 'img[src="/attachments/thumbnail/16"]'
1460 1480 end
1461 1481 end
1462 1482 end
1463 1483
1464 1484 def test_show_with_thumbnails_disabled_should_not_display_thumbnails
1465 1485 @request.session[:user_id] = 2
1466 1486
1467 1487 with_settings :thumbnails_enabled => '0' do
1468 1488 get :show, :id => 14
1469 1489 assert_response :success
1470 1490 end
1471 1491
1472 1492 assert_select 'div.thumbnails', 0
1473 1493 end
1474 1494
1475 1495 def test_show_with_multi_custom_field
1476 1496 field = CustomField.find(1)
1477 1497 field.update_attribute :multiple, true
1478 1498 issue = Issue.find(1)
1479 1499 issue.custom_field_values = {1 => ['MySQL', 'Oracle']}
1480 1500 issue.save!
1481 1501
1482 1502 get :show, :id => 1
1483 1503 assert_response :success
1484 1504
1485 1505 assert_select ".cf_1 .value", :text => 'MySQL, Oracle'
1486 1506 end
1487 1507
1488 1508 def test_show_with_multi_user_custom_field
1489 1509 field = IssueCustomField.create!(:name => 'Multi user', :field_format => 'user', :multiple => true,
1490 1510 :tracker_ids => [1], :is_for_all => true)
1491 1511 issue = Issue.find(1)
1492 1512 issue.custom_field_values = {field.id => ['2', '3']}
1493 1513 issue.save!
1494 1514
1495 1515 get :show, :id => 1
1496 1516 assert_response :success
1497 1517
1498 1518 assert_select ".cf_#{field.id} .value", :text => 'Dave Lopper, John Smith' do
1499 1519 assert_select 'a', :text => 'Dave Lopper'
1500 1520 assert_select 'a', :text => 'John Smith'
1501 1521 end
1502 1522 end
1503 1523
1504 1524 def test_show_should_display_private_notes_with_permission_only
1505 1525 journal = Journal.create!(:journalized => Issue.find(2), :notes => 'Privates notes', :private_notes => true, :user_id => 1)
1506 1526 @request.session[:user_id] = 2
1507 1527
1508 1528 get :show, :id => 2
1509 1529 assert_response :success
1510 1530 assert_include journal, assigns(:journals)
1511 1531
1512 1532 Role.find(1).remove_permission! :view_private_notes
1513 1533 get :show, :id => 2
1514 1534 assert_response :success
1515 1535 assert_not_include journal, assigns(:journals)
1516 1536 end
1517 1537
1518 1538 def test_show_atom
1519 1539 get :show, :id => 2, :format => 'atom'
1520 1540 assert_response :success
1521 1541 assert_template 'journals/index'
1522 1542 # Inline image
1523 1543 assert_select 'content', :text => Regexp.new(Regexp.quote('http://test.host/attachments/download/10'))
1524 1544 end
1525 1545
1526 1546 def test_show_export_to_pdf
1527 1547 issue = Issue.find(3)
1528 1548 assert issue.relations.select{|r| r.other_issue(issue).visible?}.present?
1529 1549 get :show, :id => 3, :format => 'pdf'
1530 1550 assert_response :success
1531 1551 assert_equal 'application/pdf', @response.content_type
1532 1552 assert @response.body.starts_with?('%PDF')
1533 1553 assert_not_nil assigns(:issue)
1534 1554 end
1535 1555
1536 1556 def test_export_to_pdf_with_utf8_u_fffd
1537 1557 # U+FFFD
1538 1558 s = "\xef\xbf\xbd"
1539 1559 s.force_encoding('UTF-8') if s.respond_to?(:force_encoding)
1540 1560 issue = Issue.generate!(:subject => s)
1541 1561 ["en", "zh", "zh-TW", "ja", "ko"].each do |lang|
1542 1562 with_settings :default_language => lang do
1543 1563 get :show, :id => issue.id, :format => 'pdf'
1544 1564 assert_response :success
1545 1565 assert_equal 'application/pdf', @response.content_type
1546 1566 assert @response.body.starts_with?('%PDF')
1547 1567 assert_not_nil assigns(:issue)
1548 1568 end
1549 1569 end
1550 1570 end
1551 1571
1552 1572 def test_show_export_to_pdf_with_ancestors
1553 1573 issue = Issue.generate!(:project_id => 1, :author_id => 2, :tracker_id => 1, :subject => 'child', :parent_issue_id => 1)
1554 1574
1555 1575 get :show, :id => issue.id, :format => 'pdf'
1556 1576 assert_response :success
1557 1577 assert_equal 'application/pdf', @response.content_type
1558 1578 assert @response.body.starts_with?('%PDF')
1559 1579 end
1560 1580
1561 1581 def test_show_export_to_pdf_with_descendants
1562 1582 c1 = Issue.generate!(:project_id => 1, :author_id => 2, :tracker_id => 1, :subject => 'child', :parent_issue_id => 1)
1563 1583 c2 = Issue.generate!(:project_id => 1, :author_id => 2, :tracker_id => 1, :subject => 'child', :parent_issue_id => 1)
1564 1584 c3 = Issue.generate!(:project_id => 1, :author_id => 2, :tracker_id => 1, :subject => 'child', :parent_issue_id => c1.id)
1565 1585
1566 1586 get :show, :id => 1, :format => 'pdf'
1567 1587 assert_response :success
1568 1588 assert_equal 'application/pdf', @response.content_type
1569 1589 assert @response.body.starts_with?('%PDF')
1570 1590 end
1571 1591
1572 1592 def test_show_export_to_pdf_with_journals
1573 1593 get :show, :id => 1, :format => 'pdf'
1574 1594 assert_response :success
1575 1595 assert_equal 'application/pdf', @response.content_type
1576 1596 assert @response.body.starts_with?('%PDF')
1577 1597 end
1578 1598
1579 1599 def test_show_export_to_pdf_with_changesets
1580 1600 [[100], [100, 101], [100, 101, 102]].each do |cs|
1581 1601 issue1 = Issue.find(3)
1582 1602 issue1.changesets = Changeset.find(cs)
1583 1603 issue1.save!
1584 1604 issue = Issue.find(3)
1585 1605 assert_equal issue.changesets.count, cs.size
1586 1606 get :show, :id => 3, :format => 'pdf'
1587 1607 assert_response :success
1588 1608 assert_equal 'application/pdf', @response.content_type
1589 1609 assert @response.body.starts_with?('%PDF')
1590 1610 end
1591 1611 end
1592 1612
1593 1613 def test_show_invalid_should_respond_with_404
1594 1614 get :show, :id => 999
1595 1615 assert_response 404
1596 1616 end
1597 1617
1598 1618 def test_get_new
1599 1619 @request.session[:user_id] = 2
1600 1620 get :new, :project_id => 1, :tracker_id => 1
1601 1621 assert_response :success
1602 1622 assert_template 'new'
1603 1623
1604 1624 assert_select 'form#issue-form[action=?]', '/projects/ecookbook/issues'
1605 1625 assert_select 'form#issue-form' do
1606 1626 assert_select 'input[name=?]', 'issue[is_private]'
1607 1627 assert_select 'select[name=?]', 'issue[project_id]', 0
1608 1628 assert_select 'select[name=?]', 'issue[tracker_id]'
1609 1629 assert_select 'input[name=?]', 'issue[subject]'
1610 1630 assert_select 'textarea[name=?]', 'issue[description]'
1611 1631 assert_select 'select[name=?]', 'issue[status_id]'
1612 1632 assert_select 'select[name=?]', 'issue[priority_id]'
1613 1633 assert_select 'select[name=?]', 'issue[assigned_to_id]'
1614 1634 assert_select 'select[name=?]', 'issue[category_id]'
1615 1635 assert_select 'select[name=?]', 'issue[fixed_version_id]'
1616 1636 assert_select 'input[name=?]', 'issue[parent_issue_id]'
1617 1637 assert_select 'input[name=?]', 'issue[start_date]'
1618 1638 assert_select 'input[name=?]', 'issue[due_date]'
1619 1639 assert_select 'select[name=?]', 'issue[done_ratio]'
1620 1640 assert_select 'input[name=?][value=?]', 'issue[custom_field_values][2]', 'Default string'
1621 1641 assert_select 'input[name=?]', 'issue[watcher_user_ids][]'
1622 1642 end
1623 1643
1624 1644 # Be sure we don't display inactive IssuePriorities
1625 1645 assert ! IssuePriority.find(15).active?
1626 1646 assert_select 'select[name=?]', 'issue[priority_id]' do
1627 1647 assert_select 'option[value="15"]', 0
1628 1648 end
1629 1649 end
1630 1650
1631 1651 def test_get_new_with_minimal_permissions
1632 1652 Role.find(1).update_attribute :permissions, [:add_issues]
1633 1653 WorkflowTransition.delete_all :role_id => 1
1634 1654
1635 1655 @request.session[:user_id] = 2
1636 1656 get :new, :project_id => 1, :tracker_id => 1
1637 1657 assert_response :success
1638 1658 assert_template 'new'
1639 1659
1640 1660 assert_select 'form#issue-form' do
1641 1661 assert_select 'input[name=?]', 'issue[is_private]', 0
1642 1662 assert_select 'select[name=?]', 'issue[project_id]', 0
1643 1663 assert_select 'select[name=?]', 'issue[tracker_id]'
1644 1664 assert_select 'input[name=?]', 'issue[subject]'
1645 1665 assert_select 'textarea[name=?]', 'issue[description]'
1646 1666 assert_select 'select[name=?]', 'issue[status_id]'
1647 1667 assert_select 'select[name=?]', 'issue[priority_id]'
1648 1668 assert_select 'select[name=?]', 'issue[assigned_to_id]'
1649 1669 assert_select 'select[name=?]', 'issue[category_id]'
1650 1670 assert_select 'select[name=?]', 'issue[fixed_version_id]'
1651 1671 assert_select 'input[name=?]', 'issue[parent_issue_id]', 0
1652 1672 assert_select 'input[name=?]', 'issue[start_date]'
1653 1673 assert_select 'input[name=?]', 'issue[due_date]'
1654 1674 assert_select 'select[name=?]', 'issue[done_ratio]'
1655 1675 assert_select 'input[name=?][value=?]', 'issue[custom_field_values][2]', 'Default string'
1656 1676 assert_select 'input[name=?]', 'issue[watcher_user_ids][]', 0
1657 1677 end
1658 1678 end
1659 1679
1660 1680 def test_new_without_project_id
1661 1681 @request.session[:user_id] = 2
1662 1682 get :new
1663 1683 assert_response :success
1664 1684 assert_template 'new'
1665 1685
1666 1686 assert_select 'form#issue-form[action=?]', '/issues'
1667 1687 assert_select 'form#issue-form' do
1668 1688 assert_select 'select[name=?]', 'issue[project_id]'
1669 1689 end
1670 1690
1671 1691 assert_nil assigns(:project)
1672 1692 assert_not_nil assigns(:issue)
1673 1693 end
1674 1694
1675 1695 def test_new_should_select_default_status
1676 1696 @request.session[:user_id] = 2
1677 1697
1678 1698 get :new, :project_id => 1
1679 1699 assert_response :success
1680 1700 assert_template 'new'
1681 1701 assert_select 'select[name=?]', 'issue[status_id]' do
1682 1702 assert_select 'option[value="1"][selected=selected]'
1683 1703 end
1684 1704 assert_select 'input[name=was_default_status][value="1"]'
1685 1705 end
1686 1706
1687 1707 def test_new_should_propose_allowed_statuses
1688 1708 WorkflowTransition.delete_all
1689 1709 WorkflowTransition.create!(:tracker_id => 1, :role_id => 1, :old_status_id => 0, :new_status_id => 1)
1690 1710 WorkflowTransition.create!(:tracker_id => 1, :role_id => 1, :old_status_id => 0, :new_status_id => 3)
1691 1711 @request.session[:user_id] = 2
1692 1712
1693 1713 get :new, :project_id => 1
1694 1714 assert_response :success
1695 1715 assert_select 'select[name=?]', 'issue[status_id]' do
1696 1716 assert_select 'option[value="1"]'
1697 1717 assert_select 'option[value="3"]'
1698 1718 assert_select 'option', 2
1699 1719 assert_select 'option[value="1"][selected=selected]'
1700 1720 end
1701 1721 end
1702 1722
1703 1723 def test_new_should_propose_allowed_statuses_without_default_status_allowed
1704 1724 WorkflowTransition.delete_all
1705 1725 WorkflowTransition.create!(:tracker_id => 1, :role_id => 1, :old_status_id => 0, :new_status_id => 2)
1706 1726 assert_equal 1, Tracker.find(1).default_status_id
1707 1727 @request.session[:user_id] = 2
1708 1728
1709 1729 get :new, :project_id => 1
1710 1730 assert_response :success
1711 1731 assert_select 'select[name=?]', 'issue[status_id]' do
1712 1732 assert_select 'option[value="2"]'
1713 1733 assert_select 'option', 1
1714 1734 assert_select 'option[value="2"][selected=selected]'
1715 1735 end
1716 1736 end
1717 1737
1718 1738 def test_new_should_preselect_default_version
1719 1739 version = Version.generate!(:project_id => 1)
1720 1740 Project.find(1).update_attribute :default_version_id, version.id
1721 1741 @request.session[:user_id] = 2
1722 1742
1723 1743 get :new, :project_id => 1
1724 1744 assert_response :success
1725 1745 assert_equal version, assigns(:issue).fixed_version
1726 1746 assert_select 'select[name=?]', 'issue[fixed_version_id]' do
1727 1747 assert_select 'option[value=?][selected=selected]', version.id.to_s
1728 1748 end
1729 1749 end
1730 1750
1731 1751 def test_get_new_with_list_custom_field
1732 1752 @request.session[:user_id] = 2
1733 1753 get :new, :project_id => 1, :tracker_id => 1
1734 1754 assert_response :success
1735 1755 assert_template 'new'
1736 1756
1737 1757 assert_select 'select.list_cf[name=?]', 'issue[custom_field_values][1]' do
1738 1758 assert_select 'option', 4
1739 1759 assert_select 'option[value=MySQL]', :text => 'MySQL'
1740 1760 end
1741 1761 end
1742 1762
1743 1763 def test_get_new_with_multi_custom_field
1744 1764 field = IssueCustomField.find(1)
1745 1765 field.update_attribute :multiple, true
1746 1766
1747 1767 @request.session[:user_id] = 2
1748 1768 get :new, :project_id => 1, :tracker_id => 1
1749 1769 assert_response :success
1750 1770 assert_template 'new'
1751 1771
1752 1772 assert_select 'select[name=?][multiple=multiple]', 'issue[custom_field_values][1][]' do
1753 1773 assert_select 'option', 3
1754 1774 assert_select 'option[value=MySQL]', :text => 'MySQL'
1755 1775 end
1756 1776 assert_select 'input[name=?][type=hidden][value=?]', 'issue[custom_field_values][1][]', ''
1757 1777 end
1758 1778
1759 1779 def test_get_new_with_multi_user_custom_field
1760 1780 field = IssueCustomField.create!(:name => 'Multi user', :field_format => 'user', :multiple => true,
1761 1781 :tracker_ids => [1], :is_for_all => true)
1762 1782
1763 1783 @request.session[:user_id] = 2
1764 1784 get :new, :project_id => 1, :tracker_id => 1
1765 1785 assert_response :success
1766 1786 assert_template 'new'
1767 1787
1768 1788 assert_select 'select[name=?][multiple=multiple]', "issue[custom_field_values][#{field.id}][]" do
1769 1789 assert_select 'option', Project.find(1).users.count
1770 1790 assert_select 'option[value="2"]', :text => 'John Smith'
1771 1791 end
1772 1792 assert_select 'input[name=?][type=hidden][value=?]', "issue[custom_field_values][#{field.id}][]", ''
1773 1793 end
1774 1794
1775 1795 def test_get_new_with_date_custom_field
1776 1796 field = IssueCustomField.create!(:name => 'Date', :field_format => 'date', :tracker_ids => [1], :is_for_all => true)
1777 1797
1778 1798 @request.session[:user_id] = 2
1779 1799 get :new, :project_id => 1, :tracker_id => 1
1780 1800 assert_response :success
1781 1801
1782 1802 assert_select 'input[name=?]', "issue[custom_field_values][#{field.id}]"
1783 1803 end
1784 1804
1785 1805 def test_get_new_with_text_custom_field
1786 1806 field = IssueCustomField.create!(:name => 'Text', :field_format => 'text', :tracker_ids => [1], :is_for_all => true)
1787 1807
1788 1808 @request.session[:user_id] = 2
1789 1809 get :new, :project_id => 1, :tracker_id => 1
1790 1810 assert_response :success
1791 1811
1792 1812 assert_select 'textarea[name=?]', "issue[custom_field_values][#{field.id}]"
1793 1813 end
1794 1814
1795 1815 def test_get_new_without_default_start_date_is_creation_date
1796 1816 with_settings :default_issue_start_date_to_creation_date => 0 do
1797 1817 @request.session[:user_id] = 2
1798 1818 get :new, :project_id => 1, :tracker_id => 1
1799 1819 assert_response :success
1800 1820 assert_template 'new'
1801 1821 assert_select 'input[name=?]', 'issue[start_date]'
1802 1822 assert_select 'input[name=?][value]', 'issue[start_date]', 0
1803 1823 end
1804 1824 end
1805 1825
1806 1826 def test_get_new_with_default_start_date_is_creation_date
1807 1827 with_settings :default_issue_start_date_to_creation_date => 1 do
1808 1828 @request.session[:user_id] = 2
1809 1829 get :new, :project_id => 1, :tracker_id => 1
1810 1830 assert_response :success
1811 1831 assert_template 'new'
1812 1832 assert_select 'input[name=?][value=?]', 'issue[start_date]',
1813 1833 Date.today.to_s
1814 1834 end
1815 1835 end
1816 1836
1817 1837 def test_get_new_form_should_allow_attachment_upload
1818 1838 @request.session[:user_id] = 2
1819 1839 get :new, :project_id => 1, :tracker_id => 1
1820 1840
1821 1841 assert_select 'form[id=issue-form][method=post][enctype="multipart/form-data"]' do
1822 1842 assert_select 'input[name=?][type=file]', 'attachments[dummy][file]'
1823 1843 end
1824 1844 end
1825 1845
1826 1846 def test_get_new_should_prefill_the_form_from_params
1827 1847 @request.session[:user_id] = 2
1828 1848 get :new, :project_id => 1,
1829 1849 :issue => {:tracker_id => 3, :description => 'Prefilled', :custom_field_values => {'2' => 'Custom field value'}}
1830 1850
1831 1851 issue = assigns(:issue)
1832 1852 assert_equal 3, issue.tracker_id
1833 1853 assert_equal 'Prefilled', issue.description
1834 1854 assert_equal 'Custom field value', issue.custom_field_value(2)
1835 1855
1836 1856 assert_select 'select[name=?]', 'issue[tracker_id]' do
1837 1857 assert_select 'option[value="3"][selected=selected]'
1838 1858 end
1839 1859 assert_select 'textarea[name=?]', 'issue[description]', :text => /Prefilled/
1840 1860 assert_select 'input[name=?][value=?]', 'issue[custom_field_values][2]', 'Custom field value'
1841 1861 end
1842 1862
1843 1863 def test_get_new_should_mark_required_fields
1844 1864 cf1 = IssueCustomField.create!(:name => 'Foo', :field_format => 'string', :is_for_all => true, :tracker_ids => [1, 2])
1845 1865 cf2 = IssueCustomField.create!(:name => 'Bar', :field_format => 'string', :is_for_all => true, :tracker_ids => [1, 2])
1846 1866 WorkflowPermission.delete_all
1847 1867 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1, :role_id => 1, :field_name => 'due_date', :rule => 'required')
1848 1868 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1, :role_id => 1, :field_name => cf2.id.to_s, :rule => 'required')
1849 1869 @request.session[:user_id] = 2
1850 1870
1851 1871 get :new, :project_id => 1
1852 1872 assert_response :success
1853 1873 assert_template 'new'
1854 1874
1855 1875 assert_select 'label[for=issue_start_date]' do
1856 1876 assert_select 'span[class=required]', 0
1857 1877 end
1858 1878 assert_select 'label[for=issue_due_date]' do
1859 1879 assert_select 'span[class=required]'
1860 1880 end
1861 1881 assert_select 'label[for=?]', "issue_custom_field_values_#{cf1.id}" do
1862 1882 assert_select 'span[class=required]', 0
1863 1883 end
1864 1884 assert_select 'label[for=?]', "issue_custom_field_values_#{cf2.id}" do
1865 1885 assert_select 'span[class=required]'
1866 1886 end
1867 1887 end
1868 1888
1869 1889 def test_get_new_should_not_display_readonly_fields
1870 1890 cf1 = IssueCustomField.create!(:name => 'Foo', :field_format => 'string', :is_for_all => true, :tracker_ids => [1, 2])
1871 1891 cf2 = IssueCustomField.create!(:name => 'Bar', :field_format => 'string', :is_for_all => true, :tracker_ids => [1, 2])
1872 1892 WorkflowPermission.delete_all
1873 1893 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1, :role_id => 1, :field_name => 'due_date', :rule => 'readonly')
1874 1894 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 1, :role_id => 1, :field_name => cf2.id.to_s, :rule => 'readonly')
1875 1895 @request.session[:user_id] = 2
1876 1896
1877 1897 get :new, :project_id => 1
1878 1898 assert_response :success
1879 1899 assert_template 'new'
1880 1900
1881 1901 assert_select 'input[name=?]', 'issue[start_date]'
1882 1902 assert_select 'input[name=?]', 'issue[due_date]', 0
1883 1903 assert_select 'input[name=?]', "issue[custom_field_values][#{cf1.id}]"
1884 1904 assert_select 'input[name=?]', "issue[custom_field_values][#{cf2.id}]", 0
1885 1905 end
1886 1906
1887 1907 def test_new_with_tracker_set_as_readonly_should_accept_status
1888 1908 WorkflowPermission.delete_all
1889 1909 [1, 2].each do |status_id|
1890 1910 WorkflowPermission.create!(:tracker_id => 1, :old_status_id => status_id, :role_id => 1, :field_name => 'tracker_id', :rule => 'readonly')
1891 1911 end
1892 1912 @request.session[:user_id] = 2
1893 1913
1894 1914 get :new, :project_id => 1, :issue => {:status_id => 2}
1895 1915 assert_select 'select[name=?]', 'issue[tracker_id]', 0
1896 1916 assert_equal 2, assigns(:issue).status_id
1897 1917 end
1898 1918
1899 1919 def test_get_new_without_tracker_id
1900 1920 @request.session[:user_id] = 2
1901 1921 get :new, :project_id => 1
1902 1922 assert_response :success
1903 1923 assert_template 'new'
1904 1924
1905 1925 issue = assigns(:issue)
1906 1926 assert_not_nil issue
1907 1927 assert_equal Project.find(1).trackers.first, issue.tracker
1908 1928 end
1909 1929
1910 1930 def test_get_new_with_no_default_status_should_display_an_error
1911 1931 @request.session[:user_id] = 2
1912 1932 IssueStatus.delete_all
1913 1933
1914 1934 get :new, :project_id => 1
1915 1935 assert_response 500
1916 1936 assert_select_error /No default issue/
1917 1937 end
1918 1938
1919 1939 def test_get_new_with_no_tracker_should_display_an_error
1920 1940 @request.session[:user_id] = 2
1921 1941 Tracker.delete_all
1922 1942
1923 1943 get :new, :project_id => 1
1924 1944 assert_response 500
1925 1945 assert_select_error /No tracker/
1926 1946 end
1927 1947
1928 1948 def test_new_with_invalid_project_id
1929 1949 @request.session[:user_id] = 1
1930 1950 get :new, :project_id => 'invalid'
1931 1951 assert_response 404
1932 1952 end
1933 1953
1934 1954 def test_update_form_for_new_issue
1935 1955 @request.session[:user_id] = 2
1936 1956 xhr :post, :new, :project_id => 1,
1937 1957 :issue => {:tracker_id => 2,
1938 1958 :subject => 'This is the test_new issue',
1939 1959 :description => 'This is the description',
1940 1960 :priority_id => 5}
1941 1961 assert_response :success
1942 1962 assert_template 'new'
1943 1963 assert_template :partial => '_form'
1944 1964 assert_equal 'text/javascript', response.content_type
1945 1965
1946 1966 issue = assigns(:issue)
1947 1967 assert_kind_of Issue, issue
1948 1968 assert_equal 1, issue.project_id
1949 1969 assert_equal 2, issue.tracker_id
1950 1970 assert_equal 'This is the test_new issue', issue.subject
1951 1971 end
1952 1972
1953 1973 def test_update_form_for_new_issue_should_propose_transitions_based_on_initial_status
1954 1974 @request.session[:user_id] = 2
1955 1975 WorkflowTransition.delete_all
1956 1976 WorkflowTransition.create!(:role_id => 1, :tracker_id => 1, :old_status_id => 0, :new_status_id => 2)
1957 1977 WorkflowTransition.create!(:role_id => 1, :tracker_id => 1, :old_status_id => 0, :new_status_id => 5)
1958 1978 WorkflowTransition.create!(:role_id => 1, :tracker_id => 1, :old_status_id => 5, :new_status_id => 4)
1959 1979
1960 1980 xhr :post, :new, :project_id => 1,
1961 1981 :issue => {:tracker_id => 1,
1962 1982 :status_id => 5,
1963 1983 :subject => 'This is an issue'}
1964 1984
1965 1985 assert_equal 5, assigns(:issue).status_id
1966 1986 assert_equal [2,5], assigns(:allowed_statuses).map(&:id).sort
1967 1987 end
1968 1988
1969 1989 def test_update_form_with_default_status_should_ignore_submitted_status_id_if_equals
1970 1990 @request.session[:user_id] = 2
1971 1991 tracker = Tracker.find(2)
1972 1992 tracker.update! :default_status_id => 2
1973 1993 tracker.generate_transitions! 2, 1, :clear => true
1974 1994
1975 1995 xhr :post, :new, :project_id => 1,
1976 1996 :issue => {:tracker_id => 2,
1977 1997 :status_id => 1},
1978 1998 :was_default_status => 1
1979 1999
1980 2000 assert_equal 2, assigns(:issue).status_id
1981 2001 end
1982 2002
1983 2003 def test_update_form_for_new_issue_should_ignore_version_when_changing_project
1984 2004 version = Version.generate!(:project_id => 1)
1985 2005 Project.find(1).update_attribute :default_version_id, version.id
1986 2006 @request.session[:user_id] = 2
1987 2007
1988 2008 xhr :post, :new, :issue => {:project_id => 1,
1989 2009 :fixed_version_id => ''},
1990 2010 :form_update_triggered_by => 'issue_project_id'
1991 2011 assert_response :success
1992 2012 assert_template 'new'
1993 2013
1994 2014 issue = assigns(:issue)
1995 2015 assert_equal 1, issue.project_id
1996 2016 assert_equal version, issue.fixed_version
1997 2017 end
1998 2018
1999 2019 def test_post_create
2000 2020 @request.session[:user_id] = 2
2001 2021 assert_difference 'Issue.count' do
2002 2022 assert_no_difference 'Journal.count' do
2003 2023 post :create, :project_id => 1,
2004 2024 :issue => {:tracker_id => 3,
2005 2025 :status_id => 2,
2006 2026 :subject => 'This is the test_new issue',
2007 2027 :description => 'This is the description',
2008 2028 :priority_id => 5,
2009 2029 :start_date => '2010-11-07',
2010 2030 :estimated_hours => '',
2011 2031 :custom_field_values => {'2' => 'Value for field 2'}}
2012 2032 end
2013 2033 end
2014 2034 assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id
2015 2035
2016 2036 issue = Issue.find_by_subject('This is the test_new issue')
2017 2037 assert_not_nil issue
2018 2038 assert_equal 2, issue.author_id
2019 2039 assert_equal 3, issue.tracker_id
2020 2040 assert_equal 2, issue.status_id
2021 2041 assert_equal Date.parse('2010-11-07'), issue.start_date
2022 2042 assert_nil issue.estimated_hours
2023 2043 v = issue.custom_values.where(:custom_field_id => 2).first
2024 2044 assert_not_nil v
2025 2045 assert_equal 'Value for field 2', v.value
2026 2046 end
2027 2047
2028 2048 def test_post_new_with_group_assignment
2029 2049 group = Group.find(11)
2030 2050 project = Project.find(1)
2031 2051 project.members << Member.new(:principal => group, :roles => [Role.givable.first])
2032 2052
2033 2053 with_settings :issue_group_assignment => '1' do
2034 2054 @request.session[:user_id] = 2
2035 2055 assert_difference 'Issue.count' do
2036 2056 post :create, :project_id => project.id,
2037 2057 :issue => {:tracker_id => 3,
2038 2058 :status_id => 1,
2039 2059 :subject => 'This is the test_new_with_group_assignment issue',
2040 2060 :assigned_to_id => group.id}
2041 2061 end
2042 2062 end
2043 2063 assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id
2044 2064
2045 2065 issue = Issue.find_by_subject('This is the test_new_with_group_assignment issue')
2046 2066 assert_not_nil issue
2047 2067 assert_equal group, issue.assigned_to
2048 2068 end
2049 2069
2050 2070 def test_post_create_without_start_date_and_default_start_date_is_not_creation_date
2051 2071 with_settings :default_issue_start_date_to_creation_date => 0 do
2052 2072 @request.session[:user_id] = 2
2053 2073 assert_difference 'Issue.count' do
2054 2074 post :create, :project_id => 1,
2055 2075 :issue => {:tracker_id => 3,
2056 2076 :status_id => 2,
2057 2077 :subject => 'This is the test_new issue',
2058 2078 :description => 'This is the description',
2059 2079 :priority_id => 5,
2060 2080 :estimated_hours => '',
2061 2081 :custom_field_values => {'2' => 'Value for field 2'}}
2062 2082 end
2063 2083 assert_redirected_to :controller => 'issues', :action => 'show',
2064 2084 :id => Issue.last.id
2065 2085 issue = Issue.find_by_subject('This is the test_new issue')
2066 2086 assert_not_nil issue
2067 2087 assert_nil issue.start_date
2068 2088 end
2069 2089 end
2070 2090
2071 2091 def test_post_create_without_start_date_and_default_start_date_is_creation_date
2072 2092 with_settings :default_issue_start_date_to_creation_date => 1 do
2073 2093 @request.session[:user_id] = 2
2074 2094 assert_difference 'Issue.count' do
2075 2095 post :create, :project_id => 1,
2076 2096 :issue => {:tracker_id => 3,
2077 2097 :status_id => 2,
2078 2098 :subject => 'This is the test_new issue',
2079 2099 :description => 'This is the description',
2080 2100 :priority_id => 5,
2081 2101 :estimated_hours => '',
2082 2102 :custom_field_values => {'2' => 'Value for field 2'}}
2083 2103 end
2084 2104 assert_redirected_to :controller => 'issues', :action => 'show',
2085 2105 :id => Issue.last.id
2086 2106 issue = Issue.find_by_subject('This is the test_new issue')
2087 2107 assert_not_nil issue
2088 2108 assert_equal Date.today, issue.start_date
2089 2109 end
2090 2110 end
2091 2111
2092 2112 def test_post_create_and_continue
2093 2113 @request.session[:user_id] = 2
2094 2114 assert_difference 'Issue.count' do
2095 2115 post :create, :project_id => 1,
2096 2116 :issue => {:tracker_id => 3, :subject => 'This is first issue', :priority_id => 5},
2097 2117 :continue => ''
2098 2118 end
2099 2119
2100 2120 issue = Issue.order('id DESC').first
2101 2121 assert_redirected_to :controller => 'issues', :action => 'new', :project_id => 'ecookbook', :issue => {:tracker_id => 3}
2102 2122 assert_not_nil flash[:notice], "flash was not set"
2103 2123 assert_select_in flash[:notice],
2104 2124 'a[href=?][title=?]', "/issues/#{issue.id}", "This is first issue", :text => "##{issue.id}"
2105 2125 end
2106 2126
2107 2127 def test_post_create_without_custom_fields_param
2108 2128 @request.session[:user_id] = 2
2109 2129 assert_difference 'Issue.count' do
2110 2130 post :create, :project_id => 1,
2111 2131 :issue => {:tracker_id => 1,
2112 2132 :subject => 'This is the test_new issue',
2113 2133 :description => 'This is the description',
2114 2134 :priority_id => 5}
2115 2135 end
2116 2136 assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id
2117 2137 end
2118 2138
2119 2139 def test_post_create_with_multi_custom_field
2120 2140 field = IssueCustomField.find_by_name('Database')
2121 2141 field.update_attribute(:multiple, true)
2122 2142
2123 2143 @request.session[:user_id] = 2
2124 2144 assert_difference 'Issue.count' do
2125 2145 post :create, :project_id => 1,
2126 2146 :issue => {:tracker_id => 1,
2127 2147 :subject => 'This is the test_new issue',
2128 2148 :description => 'This is the description',
2129 2149 :priority_id => 5,
2130 2150 :custom_field_values => {'1' => ['', 'MySQL', 'Oracle']}}
2131 2151 end
2132 2152 assert_response 302
2133 2153 issue = Issue.order('id DESC').first
2134 2154 assert_equal ['MySQL', 'Oracle'], issue.custom_field_value(1).sort
2135 2155 end
2136 2156
2137 2157 def test_post_create_with_empty_multi_custom_field
2138 2158 field = IssueCustomField.find_by_name('Database')
2139 2159 field.update_attribute(:multiple, true)
2140 2160
2141 2161 @request.session[:user_id] = 2
2142 2162 assert_difference 'Issue.count' do
2143 2163 post :create, :project_id => 1,
2144 2164 :issue => {:tracker_id => 1,
2145 2165 :subject => 'This is the test_new issue',
2146 2166 :description => 'This is the description',
2147 2167 :priority_id => 5,
2148 2168 :custom_field_values => {'1' => ['']}}
2149 2169 end
2150 2170 assert_response 302
2151 2171 issue = Issue.order('id DESC').first
2152 2172 assert_equal [''], issue.custom_field_value(1).sort
2153 2173 end
2154 2174
2155 2175 def test_post_create_with_multi_user_custom_field
2156 2176 field = IssueCustomField.create!(:name => 'Multi user', :field_format => 'user', :multiple => true,
2157 2177 :tracker_ids => [1], :is_for_all => true)
2158 2178
2159 2179 @request.session[:user_id] = 2
2160 2180 assert_difference 'Issue.count' do
2161 2181 post :create, :project_id => 1,
2162 2182 :issue => {:tracker_id => 1,
2163 2183 :subject => 'This is the test_new issue',
2164 2184 :description => 'This is the description',
2165 2185 :priority_id => 5,
2166 2186 :custom_field_values => {field.id.to_s => ['', '2', '3']}}
2167 2187 end
2168 2188 assert_response 302
2169 2189 issue = Issue.order('id DESC').first
2170 2190 assert_equal ['2', '3'], issue.custom_field_value(field).sort
2171 2191 end
2172 2192
2173 2193 def test_post_create_with_required_custom_field_and_without_custom_fields_param
2174 2194 field = IssueCustomField.find_by_name('Database')
2175 2195 field.update_attribute(:is_required, true)
2176 2196
2177 2197 @request.session[:user_id] = 2
2178 2198 assert_no_difference 'Issue.count' do
2179 2199 post :create, :project_id => 1,
2180 2200 :issue => {:tracker_id => 1,
2181 2201 :subject => 'This is the test_new issue',
2182 2202 :description => 'This is the description',
2183 2203 :priority_id => 5}
2184 2204 end
2185 2205 assert_response :success
2186 2206 assert_template 'new'
2187 2207 issue = assigns(:issue)
2188 2208 assert_not_nil issue
2189 2209 assert_select_error /Database cannot be blank/
2190 2210 end
2191 2211
2192 2212 def test_create_should_validate_required_fields
2193 2213 cf1 = IssueCustomField.create!(:name => 'Foo', :field_format => 'string', :is_for_all => true, :tracker_ids => [1, 2])
2194 2214 cf2 = IssueCustomField.create!(:name => 'Bar', :field_format => 'string', :is_for_all => true, :tracker_ids => [1, 2])
2195 2215 WorkflowPermission.delete_all
2196 2216 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 2, :role_id => 1, :field_name => 'due_date', :rule => 'required')
2197 2217 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 2, :role_id => 1, :field_name => cf2.id.to_s, :rule => 'required')
2198 2218 @request.session[:user_id] = 2
2199 2219
2200 2220 assert_no_difference 'Issue.count' do
2201 2221 post :create, :project_id => 1, :issue => {
2202 2222 :tracker_id => 2,
2203 2223 :status_id => 1,
2204 2224 :subject => 'Test',
2205 2225 :start_date => '',
2206 2226 :due_date => '',
2207 2227 :custom_field_values => {cf1.id.to_s => '', cf2.id.to_s => ''}
2208 2228 }
2209 2229 assert_response :success
2210 2230 assert_template 'new'
2211 2231 end
2212 2232
2213 2233 assert_select_error /Due date cannot be blank/i
2214 2234 assert_select_error /Bar cannot be blank/i
2215 2235 end
2216 2236
2217 2237 def test_create_should_validate_required_list_fields
2218 2238 cf1 = IssueCustomField.create!(:name => 'Foo', :field_format => 'list', :is_for_all => true, :tracker_ids => [1, 2], :multiple => false, :possible_values => ['a', 'b'])
2219 2239 cf2 = IssueCustomField.create!(:name => 'Bar', :field_format => 'list', :is_for_all => true, :tracker_ids => [1, 2], :multiple => true, :possible_values => ['a', 'b'])
2220 2240 WorkflowPermission.delete_all
2221 2241 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 2, :role_id => 1, :field_name => cf1.id.to_s, :rule => 'required')
2222 2242 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 2, :role_id => 1, :field_name => cf2.id.to_s, :rule => 'required')
2223 2243 @request.session[:user_id] = 2
2224 2244
2225 2245 assert_no_difference 'Issue.count' do
2226 2246 post :create, :project_id => 1, :issue => {
2227 2247 :tracker_id => 2,
2228 2248 :status_id => 1,
2229 2249 :subject => 'Test',
2230 2250 :start_date => '',
2231 2251 :due_date => '',
2232 2252 :custom_field_values => {cf1.id.to_s => '', cf2.id.to_s => ['']}
2233 2253 }
2234 2254 assert_response :success
2235 2255 assert_template 'new'
2236 2256 end
2237 2257
2238 2258 assert_select_error /Foo cannot be blank/i
2239 2259 assert_select_error /Bar cannot be blank/i
2240 2260 end
2241 2261
2242 2262 def test_create_should_ignore_readonly_fields
2243 2263 cf1 = IssueCustomField.create!(:name => 'Foo', :field_format => 'string', :is_for_all => true, :tracker_ids => [1, 2])
2244 2264 cf2 = IssueCustomField.create!(:name => 'Bar', :field_format => 'string', :is_for_all => true, :tracker_ids => [1, 2])
2245 2265 WorkflowPermission.delete_all
2246 2266 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 2, :role_id => 1, :field_name => 'due_date', :rule => 'readonly')
2247 2267 WorkflowPermission.create!(:old_status_id => 1, :tracker_id => 2, :role_id => 1, :field_name => cf2.id.to_s, :rule => 'readonly')
2248 2268 @request.session[:user_id] = 2
2249 2269
2250 2270 assert_difference 'Issue.count' do
2251 2271 post :create, :project_id => 1, :issue => {
2252 2272 :tracker_id => 2,
2253 2273 :status_id => 1,
2254 2274 :subject => 'Test',
2255 2275 :start_date => '2012-07-14',
2256 2276 :due_date => '2012-07-16',
2257 2277 :custom_field_values => {cf1.id.to_s => 'value1', cf2.id.to_s => 'value2'}
2258 2278 }
2259 2279 assert_response 302
2260 2280 end
2261 2281
2262 2282 issue = Issue.order('id DESC').first
2263 2283 assert_equal Date.parse('2012-07-14'), issue.start_date
2264 2284 assert_nil issue.due_date
2265 2285 assert_equal 'value1', issue.custom_field_value(cf1)
2266 2286 assert_nil issue.custom_field_value(cf2)
2267 2287 end
2268 2288
2269 2289 def test_post_create_with_watchers
2270 2290 @request.session[:user_id] = 2
2271 2291 ActionMailer::Base.deliveries.clear
2272 2292
2273 2293 with_settings :notified_events => %w(issue_added) do
2274 2294 assert_difference 'Watcher.count', 2 do
2275 2295 post :create, :project_id => 1,
2276 2296 :issue => {:tracker_id => 1,
2277 2297 :subject => 'This is a new issue with watchers',
2278 2298 :description => 'This is the description',
2279 2299 :priority_id => 5,
2280 2300 :watcher_user_ids => ['2', '3']}
2281 2301 end
2282 2302 end
2283 2303 issue = Issue.find_by_subject('This is a new issue with watchers')
2284 2304 assert_not_nil issue
2285 2305 assert_redirected_to :controller => 'issues', :action => 'show', :id => issue
2286 2306
2287 2307 # Watchers added
2288 2308 assert_equal [2, 3], issue.watcher_user_ids.sort
2289 2309 assert issue.watched_by?(User.find(3))
2290 2310 # Watchers notified
2291 2311 mail = ActionMailer::Base.deliveries.last
2292 2312 assert_not_nil mail
2293 2313 assert [mail.bcc, mail.cc].flatten.include?(User.find(3).mail)
2294 2314 end
2295 2315
2296 2316 def test_post_create_subissue
2297 2317 @request.session[:user_id] = 2
2298 2318
2299 2319 assert_difference 'Issue.count' do
2300 2320 post :create, :project_id => 1,
2301 2321 :issue => {:tracker_id => 1,
2302 2322 :subject => 'This is a child issue',
2303 2323 :parent_issue_id => '2'}
2304 2324 assert_response 302
2305 2325 end
2306 2326 issue = Issue.order('id DESC').first
2307 2327 assert_equal Issue.find(2), issue.parent
2308 2328 end
2309 2329
2310 2330 def test_post_create_subissue_with_sharp_parent_id
2311 2331 @request.session[:user_id] = 2
2312 2332
2313 2333 assert_difference 'Issue.count' do
2314 2334 post :create, :project_id => 1,
2315 2335 :issue => {:tracker_id => 1,
2316 2336 :subject => 'This is a child issue',
2317 2337 :parent_issue_id => '#2'}
2318 2338 assert_response 302
2319 2339 end
2320 2340 issue = Issue.order('id DESC').first
2321 2341 assert_equal Issue.find(2), issue.parent
2322 2342 end
2323 2343
2324 2344 def test_post_create_subissue_with_non_visible_parent_id_should_not_validate
2325 2345 @request.session[:user_id] = 2
2326 2346
2327 2347 assert_no_difference 'Issue.count' do
2328 2348 post :create, :project_id => 1,
2329 2349 :issue => {:tracker_id => 1,
2330 2350 :subject => 'This is a child issue',
2331 2351 :parent_issue_id => '4'}
2332 2352
2333 2353 assert_response :success
2334 2354 assert_select 'input[name=?][value=?]', 'issue[parent_issue_id]', '4'
2335 2355 assert_select_error /Parent task is invalid/i
2336 2356 end
2337 2357 end
2338 2358
2339 2359 def test_post_create_subissue_with_non_numeric_parent_id_should_not_validate
2340 2360 @request.session[:user_id] = 2
2341 2361
2342 2362 assert_no_difference 'Issue.count' do
2343 2363 post :create, :project_id => 1,
2344 2364 :issue => {:tracker_id => 1,
2345 2365 :subject => 'This is a child issue',
2346 2366 :parent_issue_id => '01ABC'}
2347 2367
2348 2368 assert_response :success
2349 2369 assert_select 'input[name=?][value=?]', 'issue[parent_issue_id]', '01ABC'
2350 2370 assert_select_error /Parent task is invalid/i
2351 2371 end
2352 2372 end
2353 2373
2354 2374 def test_post_create_private
2355 2375 @request.session[:user_id] = 2
2356 2376
2357 2377 assert_difference 'Issue.count' do
2358 2378 post :create, :project_id => 1,
2359 2379 :issue => {:tracker_id => 1,
2360 2380 :subject => 'This is a private issue',
2361 2381 :is_private => '1'}
2362 2382 end
2363 2383 issue = Issue.order('id DESC').first
2364 2384 assert issue.is_private?
2365 2385 end
2366 2386
2367 2387 def test_post_create_private_with_set_own_issues_private_permission
2368 2388 role = Role.find(1)
2369 2389 role.remove_permission! :set_issues_private
2370 2390 role.add_permission! :set_own_issues_private
2371 2391
2372 2392 @request.session[:user_id] = 2
2373 2393
2374 2394 assert_difference 'Issue.count' do
2375 2395 post :create, :project_id => 1,
2376 2396 :issue => {:tracker_id => 1,
2377 2397 :subject => 'This is a private issue',
2378 2398 :is_private => '1'}
2379 2399 end
2380 2400 issue = Issue.order('id DESC').first
2381 2401 assert issue.is_private?
2382 2402 end
2383 2403
2384 2404 def test_create_without_project_id
2385 2405 @request.session[:user_id] = 2
2386 2406
2387 2407 assert_difference 'Issue.count' do
2388 2408 post :create,
2389 2409 :issue => {:project_id => 3,
2390 2410 :tracker_id => 2,
2391 2411 :subject => 'Foo'}
2392 2412 assert_response 302
2393 2413 end
2394 2414 issue = Issue.order('id DESC').first
2395 2415 assert_equal 3, issue.project_id
2396 2416 assert_equal 2, issue.tracker_id
2397 2417 end
2398 2418
2399 2419 def test_create_without_project_id_and_continue_should_redirect_without_project_id
2400 2420 @request.session[:user_id] = 2
2401 2421
2402 2422 assert_difference 'Issue.count' do
2403 2423 post :create,
2404 2424 :issue => {:project_id => 3,
2405 2425 :tracker_id => 2,
2406 2426 :subject => 'Foo'},
2407 2427 :continue => '1'
2408 2428 assert_redirected_to '/issues/new?issue%5Bproject_id%5D=3&issue%5Btracker_id%5D=2'
2409 2429 end
2410 2430 end
2411 2431
2412 2432 def test_create_without_project_id_should_be_denied_without_permission
2413 2433 Role.non_member.remove_permission! :add_issues
2414 2434 Role.anonymous.remove_permission! :add_issues
2415 2435 @request.session[:user_id] = 2
2416 2436
2417 2437 assert_no_difference 'Issue.count' do
2418 2438 post :create,
2419 2439 :issue => {:project_id => 3,
2420 2440 :tracker_id => 2,
2421 2441 :subject => 'Foo'}
2422 2442 assert_response 422
2423 2443 end
2424 2444 end
2425 2445
2426 2446 def test_create_without_project_id_with_failure
2427 2447 @request.session[:user_id] = 2
2428 2448
2429 2449 post :create,
2430 2450 :issue => {:project_id => 3,
2431 2451 :tracker_id => 2,
2432 2452 :subject => ''}
2433 2453 assert_response :success
2434 2454 assert_nil assigns(:project)
2435 2455 end
2436 2456
2437 2457 def test_post_create_should_send_a_notification
2438 2458 ActionMailer::Base.deliveries.clear
2439 2459 @request.session[:user_id] = 2
2440 2460 with_settings :notified_events => %w(issue_added) do
2441 2461 assert_difference 'Issue.count' do
2442 2462 post :create, :project_id => 1,
2443 2463 :issue => {:tracker_id => 3,
2444 2464 :subject => 'This is the test_new issue',
2445 2465 :description => 'This is the description',
2446 2466 :priority_id => 5,
2447 2467 :estimated_hours => '',
2448 2468 :custom_field_values => {'2' => 'Value for field 2'}}
2449 2469 end
2450 2470 assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id
2451 2471
2452 2472 assert_equal 1, ActionMailer::Base.deliveries.size
2453 2473 end
2454 2474 end
2455 2475
2456 2476 def test_post_create_should_preserve_fields_values_on_validation_failure
2457 2477 @request.session[:user_id] = 2
2458 2478 post :create, :project_id => 1,
2459 2479 :issue => {:tracker_id => 1,
2460 2480 # empty subject
2461 2481 :subject => '',
2462 2482 :description => 'This is a description',
2463 2483 :priority_id => 6,
2464 2484 :custom_field_values => {'1' => 'Oracle', '2' => 'Value for field 2'}}
2465 2485 assert_response :success
2466 2486 assert_template 'new'
2467 2487
2468 2488 assert_select 'textarea[name=?]', 'issue[description]', :text => 'This is a description'
2469 2489 assert_select 'select[name=?]', 'issue[priority_id]' do
2470 2490 assert_select 'option[value="6"][selected=selected]', :text => 'High'
2471 2491 end
2472 2492 # Custom fields
2473 2493 assert_select 'select[name=?]', 'issue[custom_field_values][1]' do
2474 2494 assert_select 'option[value=Oracle][selected=selected]', :text => 'Oracle'
2475 2495 end
2476 2496 assert_select 'input[name=?][value=?]', 'issue[custom_field_values][2]', 'Value for field 2'
2477 2497 end
2478 2498
2479 2499 def test_post_create_with_failure_should_preserve_watchers
2480 2500 assert !User.find(8).member_of?(Project.find(1))
2481 2501
2482 2502 @request.session[:user_id] = 2
2483 2503 post :create, :project_id => 1,
2484 2504 :issue => {:tracker_id => 1,
2485 2505 :watcher_user_ids => ['3', '8']}
2486 2506 assert_response :success
2487 2507 assert_template 'new'
2488 2508
2489 2509 assert_select 'input[name=?][value="2"]:not(checked)', 'issue[watcher_user_ids][]'
2490 2510 assert_select 'input[name=?][value="3"][checked=checked]', 'issue[watcher_user_ids][]'
2491 2511 assert_select 'input[name=?][value="8"][checked=checked]', 'issue[watcher_user_ids][]'
2492 2512 end
2493 2513
2494 2514 def test_post_create_should_ignore_non_safe_attributes
2495 2515 @request.session[:user_id] = 2
2496 2516 assert_nothing_raised do
2497 2517 post :create, :project_id => 1, :issue => { :tracker => "A param can not be a Tracker" }
2498 2518 end
2499 2519 end
2500 2520
2501 2521 def test_post_create_with_attachment
2502 2522 set_tmp_attachments_directory
2503 2523 @request.session[:user_id] = 2
2504 2524
2505 2525 assert_difference 'Issue.count' do
2506 2526 assert_difference 'Attachment.count' do
2507 2527 assert_no_difference 'Journal.count' do
2508 2528 post :create, :project_id => 1,
2509 2529 :issue => { :tracker_id => '1', :subject => 'With attachment' },
2510 2530 :attachments => {'1' => {'file' => uploaded_test_file('testfile.txt', 'text/plain'), 'description' => 'test file'}}
2511 2531 end
2512 2532 end
2513 2533 end
2514 2534
2515 2535 issue = Issue.order('id DESC').first
2516 2536 attachment = Attachment.order('id DESC').first
2517 2537
2518 2538 assert_equal issue, attachment.container
2519 2539 assert_equal 2, attachment.author_id
2520 2540 assert_equal 'testfile.txt', attachment.filename
2521 2541 assert_equal 'text/plain', attachment.content_type
2522 2542 assert_equal 'test file', attachment.description
2523 2543 assert_equal 59, attachment.filesize
2524 2544 assert File.exists?(attachment.diskfile)
2525 2545 assert_equal 59, File.size(attachment.diskfile)
2526 2546 end
2527 2547
2528 2548 def test_post_create_with_attachment_should_notify_with_attachments
2529 2549 ActionMailer::Base.deliveries.clear
2530 2550 set_tmp_attachments_directory
2531 2551 @request.session[:user_id] = 2
2532 2552
2533 2553 with_settings :host_name => 'mydomain.foo', :protocol => 'http', :notified_events => %w(issue_added) do
2534 2554 assert_difference 'Issue.count' do
2535 2555 post :create, :project_id => 1,
2536 2556 :issue => { :tracker_id => '1', :subject => 'With attachment' },
2537 2557 :attachments => {'1' => {'file' => uploaded_test_file('testfile.txt', 'text/plain'), 'description' => 'test file'}}
2538 2558 end
2539 2559 end
2540 2560
2541 2561 assert_not_nil ActionMailer::Base.deliveries.last
2542 2562 assert_select_email do
2543 2563 assert_select 'a[href^=?]', 'http://mydomain.foo/attachments/download', 'testfile.txt'
2544 2564 end
2545 2565 end
2546 2566
2547 2567 def test_post_create_with_failure_should_save_attachments
2548 2568 set_tmp_attachments_directory
2549 2569 @request.session[:user_id] = 2
2550 2570
2551 2571 assert_no_difference 'Issue.count' do
2552 2572 assert_difference 'Attachment.count' do
2553 2573 post :create, :project_id => 1,
2554 2574 :issue => { :tracker_id => '1', :subject => '' },
2555 2575 :attachments => {'1' => {'file' => uploaded_test_file('testfile.txt', 'text/plain'), 'description' => 'test file'}}
2556 2576 assert_response :success
2557 2577 assert_template 'new'
2558 2578 end
2559 2579 end
2560 2580
2561 2581 attachment = Attachment.order('id DESC').first
2562 2582 assert_equal 'testfile.txt', attachment.filename
2563 2583 assert File.exists?(attachment.diskfile)
2564 2584 assert_nil attachment.container
2565 2585
2566 2586 assert_select 'input[name=?][value=?]', 'attachments[p0][token]', attachment.token
2567 2587 assert_select 'input[name=?][value=?]', 'attachments[p0][filename]', 'testfile.txt'
2568 2588 end
2569 2589
2570 2590 def test_post_create_with_failure_should_keep_saved_attachments
2571 2591 set_tmp_attachments_directory
2572 2592 attachment = Attachment.create!(:file => uploaded_test_file("testfile.txt", "text/plain"), :author_id => 2)
2573 2593 @request.session[:user_id] = 2
2574 2594
2575 2595 assert_no_difference 'Issue.count' do
2576 2596 assert_no_difference 'Attachment.count' do
2577 2597 post :create, :project_id => 1,
2578 2598 :issue => { :tracker_id => '1', :subject => '' },
2579 2599 :attachments => {'p0' => {'token' => attachment.token}}
2580 2600 assert_response :success
2581 2601 assert_template 'new'
2582 2602 end
2583 2603 end
2584 2604
2585 2605 assert_select 'input[name=?][value=?]', 'attachments[p0][token]', attachment.token
2586 2606 assert_select 'input[name=?][value=?]', 'attachments[p0][filename]', 'testfile.txt'
2587 2607 end
2588 2608
2589 2609 def test_post_create_should_attach_saved_attachments
2590 2610 set_tmp_attachments_directory
2591 2611 attachment = Attachment.create!(:file => uploaded_test_file("testfile.txt", "text/plain"), :author_id => 2)
2592 2612 @request.session[:user_id] = 2
2593 2613
2594 2614 assert_difference 'Issue.count' do
2595 2615 assert_no_difference 'Attachment.count' do
2596 2616 post :create, :project_id => 1,
2597 2617 :issue => { :tracker_id => '1', :subject => 'Saved attachments' },
2598 2618 :attachments => {'p0' => {'token' => attachment.token}}
2599 2619 assert_response 302
2600 2620 end
2601 2621 end
2602 2622
2603 2623 issue = Issue.order('id DESC').first
2604 2624 assert_equal 1, issue.attachments.count
2605 2625
2606 2626 attachment.reload
2607 2627 assert_equal issue, attachment.container
2608 2628 end
2609 2629
2610 2630 def setup_without_workflow_privilege
2611 2631 WorkflowTransition.delete_all(["role_id = ?", Role.anonymous.id])
2612 2632 Role.anonymous.add_permission! :add_issues, :add_issue_notes
2613 2633 end
2614 2634 private :setup_without_workflow_privilege
2615 2635
2616 2636 test "without workflow privilege #new should propose default status only" do
2617 2637 setup_without_workflow_privilege
2618 2638 get :new, :project_id => 1
2619 2639 assert_response :success
2620 2640 assert_template 'new'
2621 2641
2622 2642 issue = assigns(:issue)
2623 2643 assert_not_nil issue.default_status
2624 2644
2625 2645 assert_select 'select[name=?]', 'issue[status_id]' do
2626 2646 assert_select 'option', 1
2627 2647 assert_select 'option[value=?]', issue.default_status.id.to_s
2628 2648 end
2629 2649 end
2630 2650
2631 2651 test "without workflow privilege #create should accept default status" do
2632 2652 setup_without_workflow_privilege
2633 2653 assert_difference 'Issue.count' do
2634 2654 post :create, :project_id => 1,
2635 2655 :issue => {:tracker_id => 1,
2636 2656 :subject => 'This is an issue',
2637 2657 :status_id => 1}
2638 2658 end
2639 2659 issue = Issue.order('id').last
2640 2660 assert_not_nil issue.default_status
2641 2661 assert_equal issue.default_status, issue.status
2642 2662 end
2643 2663
2644 2664 test "without workflow privilege #create should ignore unauthorized status" do
2645 2665 setup_without_workflow_privilege
2646 2666 assert_difference 'Issue.count' do
2647 2667 post :create, :project_id => 1,
2648 2668 :issue => {:tracker_id => 1,
2649 2669 :subject => 'This is an issue',
2650 2670 :status_id => 3}
2651 2671 end
2652 2672 issue = Issue.order('id').last
2653 2673 assert_not_nil issue.default_status
2654 2674 assert_equal issue.default_status, issue.status
2655 2675 end
2656 2676
2657 2677 test "without workflow privilege #update should ignore status change" do
2658 2678 setup_without_workflow_privilege
2659 2679 assert_difference 'Journal.count' do
2660 2680 put :update, :id => 1, :issue => {:status_id => 3, :notes => 'just trying'}
2661 2681 end
2662 2682 assert_equal 1, Issue.find(1).status_id
2663 2683 end
2664 2684
2665 2685 test "without workflow privilege #update ignore attributes changes" do
2666 2686 setup_without_workflow_privilege
2667 2687 assert_difference 'Journal.count' do
2668 2688 put :update, :id => 1,
2669 2689 :issue => {:subject => 'changed', :assigned_to_id => 2,
2670 2690 :notes => 'just trying'}
2671 2691 end
2672 2692 issue = Issue.find(1)
2673 2693 assert_equal "Cannot print recipes", issue.subject
2674 2694 assert_nil issue.assigned_to
2675 2695 end
2676 2696
2677 2697 def setup_with_workflow_privilege
2678 2698 WorkflowTransition.delete_all(["role_id = ?", Role.anonymous.id])
2679 2699 WorkflowTransition.create!(:role => Role.anonymous, :tracker_id => 1,
2680 2700 :old_status_id => 1, :new_status_id => 3)
2681 2701 WorkflowTransition.create!(:role => Role.anonymous, :tracker_id => 1,
2682 2702 :old_status_id => 1, :new_status_id => 4)
2683 2703 Role.anonymous.add_permission! :add_issues, :add_issue_notes
2684 2704 end
2685 2705 private :setup_with_workflow_privilege
2686 2706
2687 2707 def setup_with_workflow_privilege_and_edit_issues_permission
2688 2708 setup_with_workflow_privilege
2689 2709 Role.anonymous.add_permission! :add_issues, :edit_issues
2690 2710 end
2691 2711 private :setup_with_workflow_privilege_and_edit_issues_permission
2692 2712
2693 2713 test "with workflow privilege and :edit_issues permission should accept authorized status" do
2694 2714 setup_with_workflow_privilege_and_edit_issues_permission
2695 2715 assert_difference 'Journal.count' do
2696 2716 put :update, :id => 1, :issue => {:status_id => 3, :notes => 'just trying'}
2697 2717 end
2698 2718 assert_equal 3, Issue.find(1).status_id
2699 2719 end
2700 2720
2701 2721 test "with workflow privilege and :edit_issues permission should ignore unauthorized status" do
2702 2722 setup_with_workflow_privilege_and_edit_issues_permission
2703 2723 assert_difference 'Journal.count' do
2704 2724 put :update, :id => 1, :issue => {:status_id => 2, :notes => 'just trying'}
2705 2725 end
2706 2726 assert_equal 1, Issue.find(1).status_id
2707 2727 end
2708 2728
2709 2729 test "with workflow privilege and :edit_issues permission should accept authorized attributes changes" do
2710 2730 setup_with_workflow_privilege_and_edit_issues_permission
2711 2731 assert_difference 'Journal.count' do
2712 2732 put :update, :id => 1,
2713 2733 :issue => {:subject => 'changed', :assigned_to_id => 2,
2714 2734 :notes => 'just trying'}
2715 2735 end
2716 2736 issue = Issue.find(1)
2717 2737 assert_equal "changed", issue.subject
2718 2738 assert_equal 2, issue.assigned_to_id
2719 2739 end
2720 2740
2721 2741 def test_new_as_copy
2722 2742 @request.session[:user_id] = 2
2723 2743 get :new, :project_id => 1, :copy_from => 1
2724 2744
2725 2745 assert_response :success
2726 2746 assert_template 'new'
2727 2747
2728 2748 assert_not_nil assigns(:issue)
2729 2749 orig = Issue.find(1)
2730 2750 assert_equal 1, assigns(:issue).project_id
2731 2751 assert_equal orig.subject, assigns(:issue).subject
2732 2752 assert assigns(:issue).copy?
2733 2753
2734 2754 assert_select 'form[id=issue-form][action="/projects/ecookbook/issues"]' do
2735 2755 assert_select 'select[name=?]', 'issue[project_id]' do
2736 2756 assert_select 'option[value="1"][selected=selected]', :text => 'eCookbook'
2737 2757 assert_select 'option[value="2"]:not([selected])', :text => 'OnlineStore'
2738 2758 end
2739 2759 assert_select 'input[name=copy_from][value="1"]'
2740 2760 end
2741 2761
2742 2762 # "New issue" menu item should not link to copy
2743 2763 assert_select '#main-menu a.new-issue[href="/projects/ecookbook/issues/new"]'
2744 2764 end
2745 2765
2746 2766 def test_new_as_copy_without_add_issues_permission_should_not_propose_current_project_as_target
2747 2767 user = setup_user_with_copy_but_not_add_permission
2748 2768
2749 2769 @request.session[:user_id] = user.id
2750 2770 get :new, :project_id => 1, :copy_from => 1
2751 2771
2752 2772 assert_response :success
2753 2773 assert_template 'new'
2754 2774 assert_select 'select[name=?]', 'issue[project_id]' do
2755 2775 assert_select 'option[value="1"]', 0
2756 2776 assert_select 'option[value="2"]', :text => 'OnlineStore'
2757 2777 end
2758 2778 end
2759 2779
2760 2780 def test_new_as_copy_with_attachments_should_show_copy_attachments_checkbox
2761 2781 @request.session[:user_id] = 2
2762 2782 issue = Issue.find(3)
2763 2783 assert issue.attachments.count > 0
2764 2784 get :new, :project_id => 1, :copy_from => 3
2765 2785
2766 2786 assert_select 'input[name=copy_attachments][type=checkbox][checked=checked][value="1"]'
2767 2787 end
2768 2788
2769 2789 def test_new_as_copy_without_attachments_should_not_show_copy_attachments_checkbox
2770 2790 @request.session[:user_id] = 2
2771 2791 issue = Issue.find(3)
2772 2792 issue.attachments.delete_all
2773 2793 get :new, :project_id => 1, :copy_from => 3
2774 2794
2775 2795 assert_select 'input[name=copy_attachments]', 0
2776 2796 end
2777 2797
2778 2798 def test_new_as_copy_with_subtasks_should_show_copy_subtasks_checkbox
2779 2799 @request.session[:user_id] = 2
2780 2800 issue = Issue.generate_with_descendants!
2781 2801 get :new, :project_id => 1, :copy_from => issue.id
2782 2802
2783 2803 assert_select 'input[type=checkbox][name=copy_subtasks][checked=checked][value="1"]'
2784 2804 end
2785 2805
2786 2806 def test_new_as_copy_with_invalid_issue_should_respond_with_404
2787 2807 @request.session[:user_id] = 2
2788 2808 get :new, :project_id => 1, :copy_from => 99999
2789 2809 assert_response 404
2790 2810 end
2791 2811
2792 2812 def test_create_as_copy_on_different_project
2793 2813 @request.session[:user_id] = 2
2794 2814 assert_difference 'Issue.count' do
2795 2815 post :create, :project_id => 1, :copy_from => 1,
2796 2816 :issue => {:project_id => '2', :tracker_id => '3', :status_id => '1', :subject => 'Copy'}
2797 2817
2798 2818 assert_not_nil assigns(:issue)
2799 2819 assert assigns(:issue).copy?
2800 2820 end
2801 2821 issue = Issue.order('id DESC').first
2802 2822 assert_redirected_to "/issues/#{issue.id}"
2803 2823
2804 2824 assert_equal 2, issue.project_id
2805 2825 assert_equal 3, issue.tracker_id
2806 2826 assert_equal 'Copy', issue.subject
2807 2827 end
2808 2828
2809 2829 def test_create_as_copy_should_allow_status_to_be_set_to_default
2810 2830 copied = Issue.generate! :status_id => 2
2811 2831 assert_equal 2, copied.reload.status_id
2812 2832
2813 2833 @request.session[:user_id] = 2
2814 2834 assert_difference 'Issue.count' do
2815 2835 post :create, :project_id => 1, :copy_from => copied.id,
2816 2836 :issue => {:project_id => '1', :tracker_id => '1', :status_id => '1'},
2817 2837 :was_default_status => '1'
2818 2838 end
2819 2839 issue = Issue.order('id DESC').first
2820 2840 assert_equal 1, issue.status_id
2821 2841 end
2822 2842
2823 2843 def test_create_as_copy_should_copy_attachments
2824 2844 @request.session[:user_id] = 2
2825 2845 issue = Issue.find(3)
2826 2846 count = issue.attachments.count
2827 2847 assert count > 0
2828 2848 assert_difference 'Issue.count' do
2829 2849 assert_difference 'Attachment.count', count do
2830 2850 post :create, :project_id => 1, :copy_from => 3,
2831 2851 :issue => {:project_id => '1', :tracker_id => '3',
2832 2852 :status_id => '1', :subject => 'Copy with attachments'},
2833 2853 :copy_attachments => '1'
2834 2854 end
2835 2855 end
2836 2856 copy = Issue.order('id DESC').first
2837 2857 assert_equal count, copy.attachments.count
2838 2858 assert_equal issue.attachments.map(&:filename).sort, copy.attachments.map(&:filename).sort
2839 2859 end
2840 2860
2841 2861 def test_create_as_copy_without_copy_attachments_option_should_not_copy_attachments
2842 2862 @request.session[:user_id] = 2
2843 2863 issue = Issue.find(3)
2844 2864 count = issue.attachments.count
2845 2865 assert count > 0
2846 2866 assert_difference 'Issue.count' do
2847 2867 assert_no_difference 'Attachment.count' do
2848 2868 post :create, :project_id => 1, :copy_from => 3,
2849 2869 :issue => {:project_id => '1', :tracker_id => '3',
2850 2870 :status_id => '1', :subject => 'Copy with attachments'}
2851 2871 end
2852 2872 end
2853 2873 copy = Issue.order('id DESC').first
2854 2874 assert_equal 0, copy.attachments.count
2855 2875 end
2856 2876
2857 2877 def test_create_as_copy_with_attachments_should_also_add_new_files
2858 2878 @request.session[:user_id] = 2
2859 2879 issue = Issue.find(3)
2860 2880 count = issue.attachments.count
2861 2881 assert count > 0
2862 2882 assert_difference 'Issue.count' do
2863 2883 assert_difference 'Attachment.count', count + 1 do
2864 2884 post :create, :project_id => 1, :copy_from => 3,
2865 2885 :issue => {:project_id => '1', :tracker_id => '3',
2866 2886 :status_id => '1', :subject => 'Copy with attachments'},
2867 2887 :copy_attachments => '1',
2868 2888 :attachments => {'1' =>
2869 2889 {'file' => uploaded_test_file('testfile.txt', 'text/plain'),
2870 2890 'description' => 'test file'}}
2871 2891 end
2872 2892 end
2873 2893 copy = Issue.order('id DESC').first
2874 2894 assert_equal count + 1, copy.attachments.count
2875 2895 end
2876 2896
2877 2897 def test_create_as_copy_should_add_relation_with_copied_issue
2878 2898 @request.session[:user_id] = 2
2879 2899 assert_difference 'Issue.count' do
2880 2900 assert_difference 'IssueRelation.count' do
2881 2901 post :create, :project_id => 1, :copy_from => 1, :link_copy => '1',
2882 2902 :issue => {:project_id => '1', :tracker_id => '3',
2883 2903 :status_id => '1', :subject => 'Copy'}
2884 2904 end
2885 2905 end
2886 2906 copy = Issue.order('id DESC').first
2887 2907 assert_equal 1, copy.relations.size
2888 2908 end
2889 2909
2890 2910 def test_create_as_copy_should_allow_not_to_add_relation_with_copied_issue
2891 2911 @request.session[:user_id] = 2
2892 2912 assert_difference 'Issue.count' do
2893 2913 assert_no_difference 'IssueRelation.count' do
2894 2914 post :create, :project_id => 1, :copy_from => 1,
2895 2915 :issue => {:subject => 'Copy'}
2896 2916 end
2897 2917 end
2898 2918 end
2899 2919
2900 2920 def test_create_as_copy_should_always_add_relation_with_copied_issue_by_setting
2901 2921 with_settings :link_copied_issue => 'yes' do
2902 2922 @request.session[:user_id] = 2
2903 2923 assert_difference 'Issue.count' do
2904 2924 assert_difference 'IssueRelation.count' do
2905 2925 post :create, :project_id => 1, :copy_from => 1,
2906 2926 :issue => {:subject => 'Copy'}
2907 2927 end
2908 2928 end
2909 2929 end
2910 2930 end
2911 2931
2912 2932 def test_create_as_copy_should_never_add_relation_with_copied_issue_by_setting
2913 2933 with_settings :link_copied_issue => 'no' do
2914 2934 @request.session[:user_id] = 2
2915 2935 assert_difference 'Issue.count' do
2916 2936 assert_no_difference 'IssueRelation.count' do
2917 2937 post :create, :project_id => 1, :copy_from => 1, :link_copy => '1',
2918 2938 :issue => {:subject => 'Copy'}
2919 2939 end
2920 2940 end
2921 2941 end
2922 2942 end
2923 2943
2924 2944 def test_create_as_copy_should_copy_subtasks
2925 2945 @request.session[:user_id] = 2
2926 2946 issue = Issue.generate_with_descendants!
2927 2947 count = issue.descendants.count
2928 2948 assert_difference 'Issue.count', count + 1 do
2929 2949 post :create, :project_id => 1, :copy_from => issue.id,
2930 2950 :issue => {:project_id => '1', :tracker_id => '3',
2931 2951 :status_id => '1', :subject => 'Copy with subtasks'},
2932 2952 :copy_subtasks => '1'
2933 2953 end
2934 2954 copy = Issue.where(:parent_id => nil).order('id DESC').first
2935 2955 assert_equal count, copy.descendants.count
2936 2956 assert_equal issue.descendants.map(&:subject).sort, copy.descendants.map(&:subject).sort
2937 2957 end
2938 2958
2939 2959 def test_create_as_copy_without_copy_subtasks_option_should_not_copy_subtasks
2940 2960 @request.session[:user_id] = 2
2941 2961 issue = Issue.generate_with_descendants!
2942 2962 assert_difference 'Issue.count', 1 do
2943 2963 post :create, :project_id => 1, :copy_from => 3,
2944 2964 :issue => {:project_id => '1', :tracker_id => '3',
2945 2965 :status_id => '1', :subject => 'Copy with subtasks'}
2946 2966 end
2947 2967 copy = Issue.where(:parent_id => nil).order('id DESC').first
2948 2968 assert_equal 0, copy.descendants.count
2949 2969 end
2950 2970
2951 2971 def test_create_as_copy_with_failure
2952 2972 @request.session[:user_id] = 2
2953 2973 post :create, :project_id => 1, :copy_from => 1,
2954 2974 :issue => {:project_id => '2', :tracker_id => '3', :status_id => '1', :subject => ''}
2955 2975
2956 2976 assert_response :success
2957 2977 assert_template 'new'
2958 2978
2959 2979 assert_not_nil assigns(:issue)
2960 2980 assert assigns(:issue).copy?
2961 2981
2962 2982 assert_select 'form#issue-form[action="/projects/ecookbook/issues"]' do
2963 2983 assert_select 'select[name=?]', 'issue[project_id]' do
2964 2984 assert_select 'option[value="1"]:not([selected])', :text => 'eCookbook'
2965 2985 assert_select 'option[value="2"][selected=selected]', :text => 'OnlineStore'
2966 2986 end
2967 2987 assert_select 'input[name=copy_from][value="1"]'
2968 2988 end
2969 2989 end
2970 2990
2971 2991 def test_create_as_copy_on_project_without_permission_should_ignore_target_project
2972 2992 @request.session[:user_id] = 2
2973 2993 assert !User.find(2).member_of?(Project.find(4))
2974 2994
2975 2995 assert_difference 'Issue.count' do
2976 2996 post :create, :project_id => 1, :copy_from => 1,
2977 2997 :issue => {:project_id => '4', :tracker_id => '3', :status_id => '1', :subject => 'Copy'}
2978 2998 end
2979 2999 issue = Issue.order('id DESC').first
2980 3000 assert_equal 1, issue.project_id
2981 3001 end
2982 3002
2983 3003 def test_get_edit
2984 3004 @request.session[:user_id] = 2
2985 3005 get :edit, :id => 1
2986 3006 assert_response :success
2987 3007 assert_template 'edit'
2988 3008 assert_not_nil assigns(:issue)
2989 3009 assert_equal Issue.find(1), assigns(:issue)
2990 3010
2991 3011 # Be sure we don't display inactive IssuePriorities
2992 3012 assert ! IssuePriority.find(15).active?
2993 3013 assert_select 'select[name=?]', 'issue[priority_id]' do
2994 3014 assert_select 'option[value="15"]', 0
2995 3015 end
2996 3016 end
2997 3017
2998 3018 def test_get_edit_should_display_the_time_entry_form_with_log_time_permission
2999 3019 @request.session[:user_id] = 2
3000 3020 Role.find_by_name('Manager').update_attribute :permissions, [:view_issues, :edit_issues, :log_time]
3001 3021
3002 3022 get :edit, :id => 1
3003 3023 assert_select 'input[name=?]', 'time_entry[hours]'
3004 3024 end
3005 3025
3006 3026 def test_get_edit_should_not_display_the_time_entry_form_without_log_time_permission
3007 3027 @request.session[:user_id] = 2
3008 3028 Role.find_by_name('Manager').remove_permission! :log_time
3009 3029
3010 3030 get :edit, :id => 1
3011 3031 assert_select 'input[name=?]', 'time_entry[hours]', 0
3012 3032 end
3013 3033
3014 3034 def test_get_edit_with_params
3015 3035 @request.session[:user_id] = 2
3016 3036 get :edit, :id => 1, :issue => { :status_id => 5, :priority_id => 7 },
3017 3037 :time_entry => { :hours => '2.5', :comments => 'test_get_edit_with_params', :activity_id => 10 }
3018 3038 assert_response :success
3019 3039 assert_template 'edit'
3020 3040
3021 3041 issue = assigns(:issue)
3022 3042 assert_not_nil issue
3023 3043
3024 3044 assert_equal 5, issue.status_id
3025 3045 assert_select 'select[name=?]', 'issue[status_id]' do
3026 3046 assert_select 'option[value="5"][selected=selected]', :text => 'Closed'
3027 3047 end
3028 3048
3029 3049 assert_equal 7, issue.priority_id
3030 3050 assert_select 'select[name=?]', 'issue[priority_id]' do
3031 3051 assert_select 'option[value="7"][selected=selected]', :text => 'Urgent'
3032 3052 end
3033 3053
3034 3054 assert_select 'input[name=?][value="2.5"]', 'time_entry[hours]'
3035 3055 assert_select 'select[name=?]', 'time_entry[activity_id]' do
3036 3056 assert_select 'option[value="10"][selected=selected]', :text => 'Development'
3037 3057 end
3038 3058 assert_select 'input[name=?][value=test_get_edit_with_params]', 'time_entry[comments]'
3039 3059 end
3040 3060
3041 3061 def test_get_edit_with_multi_custom_field
3042 3062 field = CustomField.find(1)
3043 3063 field.update_attribute :multiple, true
3044 3064 issue = Issue.find(1)
3045 3065 issue.custom_field_values = {1 => ['MySQL', 'Oracle']}
3046 3066 issue.save!
3047 3067
3048 3068 @request.session[:user_id] = 2
3049 3069 get :edit, :id => 1
3050 3070 assert_response :success
3051 3071 assert_template 'edit'
3052 3072
3053 3073 assert_select 'select[name=?][multiple=multiple]', 'issue[custom_field_values][1][]' do
3054 3074 assert_select 'option', 3
3055 3075 assert_select 'option[value=MySQL][selected=selected]'
3056 3076 assert_select 'option[value=Oracle][selected=selected]'
3057 3077 assert_select 'option[value=PostgreSQL]:not([selected])'
3058 3078 end
3059 3079 end
3060 3080
3061 3081 def test_update_form_for_existing_issue
3062 3082 @request.session[:user_id] = 2
3063 3083 xhr :patch, :edit, :id => 1,
3064 3084 :issue => {:tracker_id => 2,
3065 3085 :subject => 'This is the test_new issue',
3066 3086 :description => 'This is the description',
3067 3087 :priority_id => 5}
3068 3088 assert_response :success
3069 3089 assert_equal 'text/javascript', response.content_type
3070 3090 assert_template 'edit'
3071 3091 assert_template :partial => '_form'
3072 3092
3073 3093 issue = assigns(:issue)
3074 3094 assert_kind_of Issue, issue
3075 3095 assert_equal 1, issue.id
3076 3096 assert_equal 1, issue.project_id
3077 3097 assert_equal 2, issue.tracker_id
3078 3098 assert_equal 'This is the test_new issue', issue.subject
3079 3099 end
3080 3100
3081 3101 def test_update_form_for_existing_issue_should_keep_issue_author
3082 3102 @request.session[:user_id] = 3
3083 3103 xhr :patch, :edit, :id => 1, :issue => {:subject => 'Changed'}
3084 3104 assert_response :success
3085 3105 assert_equal 'text/javascript', response.content_type
3086 3106
3087 3107 issue = assigns(:issue)
3088 3108 assert_equal User.find(2), issue.author
3089 3109 assert_equal 2, issue.author_id
3090 3110 assert_not_equal User.current, issue.author
3091 3111 end
3092 3112
3093 3113 def test_update_form_for_existing_issue_should_propose_transitions_based_on_initial_status
3094 3114 @request.session[:user_id] = 2
3095 3115 WorkflowTransition.delete_all
3096 3116 WorkflowTransition.create!(:role_id => 1, :tracker_id => 2, :old_status_id => 2, :new_status_id => 1)
3097 3117 WorkflowTransition.create!(:role_id => 1, :tracker_id => 2, :old_status_id => 2, :new_status_id => 5)
3098 3118 WorkflowTransition.create!(:role_id => 1, :tracker_id => 2, :old_status_id => 5, :new_status_id => 4)
3099 3119
3100 3120 xhr :patch, :edit, :id => 2,
3101 3121 :issue => {:tracker_id => 2,
3102 3122 :status_id => 5,
3103 3123 :subject => 'This is an issue'}
3104 3124
3105 3125 assert_equal 5, assigns(:issue).status_id
3106 3126 assert_equal [1,2,5], assigns(:allowed_statuses).map(&:id).sort
3107 3127 end
3108 3128
3109 3129 def test_update_form_for_existing_issue_with_project_change
3110 3130 @request.session[:user_id] = 2
3111 3131 xhr :patch, :edit, :id => 1,
3112 3132 :issue => {:project_id => 2,
3113 3133 :tracker_id => 2,
3114 3134 :subject => 'This is the test_new issue',
3115 3135 :description => 'This is the description',
3116 3136 :priority_id => 5}
3117 3137 assert_response :success
3118 3138 assert_template :partial => '_form'
3119 3139
3120 3140 issue = assigns(:issue)
3121 3141 assert_kind_of Issue, issue
3122 3142 assert_equal 1, issue.id
3123 3143 assert_equal 2, issue.project_id
3124 3144 assert_equal 2, issue.tracker_id
3125 3145 assert_equal 'This is the test_new issue', issue.subject
3126 3146 end
3127 3147
3128 3148 def test_update_form_should_keep_category_with_same_when_changing_project
3129 3149 source = Project.generate!
3130 3150 target = Project.generate!
3131 3151 source_category = IssueCategory.create!(:name => 'Foo', :project => source)
3132 3152 target_category = IssueCategory.create!(:name => 'Foo', :project => target)
3133 3153 issue = Issue.generate!(:project => source, :category => source_category)
3134 3154
3135 3155 @request.session[:user_id] = 1
3136 3156 patch :edit, :id => issue.id,
3137 3157 :issue => {:project_id => target.id, :category_id => source_category.id}
3138 3158 assert_response :success
3139 3159
3140 3160 issue = assigns(:issue)
3141 3161 assert_equal target_category, issue.category
3142 3162 end
3143 3163
3144 3164 def test_update_form_should_propose_default_status_for_existing_issue
3145 3165 @request.session[:user_id] = 2
3146 3166 WorkflowTransition.delete_all
3147 3167 WorkflowTransition.create!(:role_id => 1, :tracker_id => 2, :old_status_id => 2, :new_status_id => 3)
3148 3168
3149 3169 xhr :patch, :edit, :id => 2
3150 3170 assert_response :success
3151 3171 assert_equal [2,3], assigns(:allowed_statuses).map(&:id).sort
3152 3172 end
3153 3173
3154 3174 def test_put_update_without_custom_fields_param
3155 3175 @request.session[:user_id] = 2
3156 3176
3157 3177 issue = Issue.find(1)
3158 3178 assert_equal '125', issue.custom_value_for(2).value
3159 3179
3160 3180 assert_difference('Journal.count') do
3161 3181 assert_difference('JournalDetail.count') do
3162 3182 put :update, :id => 1, :issue => {:subject => 'New subject'}
3163 3183 end
3164 3184 end
3165 3185 assert_redirected_to :action => 'show', :id => '1'
3166 3186 issue.reload
3167 3187 assert_equal 'New subject', issue.subject
3168 3188 # Make sure custom fields were not cleared
3169 3189 assert_equal '125', issue.custom_value_for(2).value
3170 3190 end
3171 3191
3172 3192 def test_put_update_with_project_change
3173 3193 @request.session[:user_id] = 2
3174 3194 ActionMailer::Base.deliveries.clear
3175 3195
3176 3196 with_settings :notified_events => %w(issue_updated) do
3177 3197 assert_difference('Journal.count') do
3178 3198 assert_difference('JournalDetail.count', 3) do
3179 3199 put :update, :id => 1, :issue => {:project_id => '2',
3180 3200 :tracker_id => '1', # no change
3181 3201 :priority_id => '6',
3182 3202 :category_id => '3'
3183 3203 }
3184 3204 end
3185 3205 end
3186 3206 end
3187 3207 assert_redirected_to :action => 'show', :id => '1'
3188 3208 issue = Issue.find(1)
3189 3209 assert_equal 2, issue.project_id
3190 3210 assert_equal 1, issue.tracker_id
3191 3211 assert_equal 6, issue.priority_id
3192 3212 assert_equal 3, issue.category_id
3193 3213
3194 3214 mail = ActionMailer::Base.deliveries.last
3195 3215 assert_not_nil mail
3196 3216 assert mail.subject.starts_with?("[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}]")
3197 3217 assert_mail_body_match "Project changed from eCookbook to OnlineStore", mail
3198 3218 end
3199 3219
3200 3220 def test_put_update_trying_to_move_issue_to_project_without_tracker_should_not_error
3201 3221 target = Project.generate!(:tracker_ids => [])
3202 3222 assert target.trackers.empty?
3203 3223 issue = Issue.generate!
3204 3224 @request.session[:user_id] = 1
3205 3225
3206 3226 put :update, :id => issue.id, :issue => {:project_id => target.id}
3207 3227 assert_response 302
3208 3228 end
3209 3229
3210 3230 def test_put_update_with_tracker_change
3211 3231 @request.session[:user_id] = 2
3212 3232 ActionMailer::Base.deliveries.clear
3213 3233
3214 3234 with_settings :notified_events => %w(issue_updated) do
3215 3235 assert_difference('Journal.count') do
3216 3236 assert_difference('JournalDetail.count', 2) do
3217 3237 put :update, :id => 1, :issue => {:project_id => '1',
3218 3238 :tracker_id => '2',
3219 3239 :priority_id => '6'
3220 3240 }
3221 3241 end
3222 3242 end
3223 3243 end
3224 3244 assert_redirected_to :action => 'show', :id => '1'
3225 3245 issue = Issue.find(1)
3226 3246 assert_equal 1, issue.project_id
3227 3247 assert_equal 2, issue.tracker_id
3228 3248 assert_equal 6, issue.priority_id
3229 3249 assert_equal 1, issue.category_id
3230 3250
3231 3251 mail = ActionMailer::Base.deliveries.last
3232 3252 assert_not_nil mail
3233 3253 assert mail.subject.starts_with?("[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}]")
3234 3254 assert_mail_body_match "Tracker changed from Bug to Feature request", mail
3235 3255 end
3236 3256
3237 3257 def test_put_update_with_custom_field_change
3238 3258 @request.session[:user_id] = 2
3239 3259 issue = Issue.find(1)
3240 3260 assert_equal '125', issue.custom_value_for(2).value
3241 3261
3242 3262 with_settings :notified_events => %w(issue_updated) do
3243 3263 assert_difference('Journal.count') do
3244 3264 assert_difference('JournalDetail.count', 3) do
3245 3265 put :update, :id => 1, :issue => {:subject => 'Custom field change',
3246 3266 :priority_id => '6',
3247 3267 :category_id => '1', # no change
3248 3268 :custom_field_values => { '2' => 'New custom value' }
3249 3269 }
3250 3270 end
3251 3271 end
3252 3272 end
3253 3273 assert_redirected_to :action => 'show', :id => '1'
3254 3274 issue.reload
3255 3275 assert_equal 'New custom value', issue.custom_value_for(2).value
3256 3276
3257 3277 mail = ActionMailer::Base.deliveries.last
3258 3278 assert_not_nil mail
3259 3279 assert_mail_body_match "Searchable field changed from 125 to New custom value", mail
3260 3280 end
3261 3281
3262 3282 def test_put_update_with_multi_custom_field_change
3263 3283 field = CustomField.find(1)
3264 3284 field.update_attribute :multiple, true
3265 3285 issue = Issue.find(1)
3266 3286 issue.custom_field_values = {1 => ['MySQL', 'Oracle']}
3267 3287 issue.save!
3268 3288
3269 3289 @request.session[:user_id] = 2
3270 3290 assert_difference('Journal.count') do
3271 3291 assert_difference('JournalDetail.count', 3) do
3272 3292 put :update, :id => 1,
3273 3293 :issue => {
3274 3294 :subject => 'Custom field change',
3275 3295 :custom_field_values => { '1' => ['', 'Oracle', 'PostgreSQL'] }
3276 3296 }
3277 3297 end
3278 3298 end
3279 3299 assert_redirected_to :action => 'show', :id => '1'
3280 3300 assert_equal ['Oracle', 'PostgreSQL'], Issue.find(1).custom_field_value(1).sort
3281 3301 end
3282 3302
3283 3303 def test_put_update_with_status_and_assignee_change
3284 3304 issue = Issue.find(1)
3285 3305 assert_equal 1, issue.status_id
3286 3306 @request.session[:user_id] = 2
3287 3307
3288 3308 with_settings :notified_events => %w(issue_updated) do
3289 3309 assert_difference('TimeEntry.count', 0) do
3290 3310 put :update,
3291 3311 :id => 1,
3292 3312 :issue => { :status_id => 2, :assigned_to_id => 3, :notes => 'Assigned to dlopper' },
3293 3313 :time_entry => { :hours => '', :comments => '', :activity_id => TimeEntryActivity.first }
3294 3314 end
3295 3315 end
3296 3316 assert_redirected_to :action => 'show', :id => '1'
3297 3317 issue.reload
3298 3318 assert_equal 2, issue.status_id
3299 3319 j = Journal.order('id DESC').first
3300 3320 assert_equal 'Assigned to dlopper', j.notes
3301 3321 assert_equal 2, j.details.size
3302 3322
3303 3323 mail = ActionMailer::Base.deliveries.last
3304 3324 assert_mail_body_match "Status changed from New to Assigned", mail
3305 3325 # subject should contain the new status
3306 3326 assert mail.subject.include?("(#{ IssueStatus.find(2).name })")
3307 3327 end
3308 3328
3309 3329 def test_put_update_with_note_only
3310 3330 notes = 'Note added by IssuesControllerTest#test_update_with_note_only'
3311 3331
3312 3332 with_settings :notified_events => %w(issue_updated) do
3313 3333 # anonymous user
3314 3334 put :update,
3315 3335 :id => 1,
3316 3336 :issue => { :notes => notes }
3317 3337 end
3318 3338 assert_redirected_to :action => 'show', :id => '1'
3319 3339 j = Journal.order('id DESC').first
3320 3340 assert_equal notes, j.notes
3321 3341 assert_equal 0, j.details.size
3322 3342 assert_equal User.anonymous, j.user
3323 3343
3324 3344 mail = ActionMailer::Base.deliveries.last
3325 3345 assert_mail_body_match notes, mail
3326 3346 end
3327 3347
3328 3348 def test_put_update_with_private_note_only
3329 3349 notes = 'Private note'
3330 3350 @request.session[:user_id] = 2
3331 3351
3332 3352 assert_difference 'Journal.count' do
3333 3353 put :update, :id => 1, :issue => {:notes => notes, :private_notes => '1'}
3334 3354 assert_redirected_to :action => 'show', :id => '1'
3335 3355 end
3336 3356
3337 3357 j = Journal.order('id DESC').first
3338 3358 assert_equal notes, j.notes
3339 3359 assert_equal true, j.private_notes
3340 3360 end
3341 3361
3342 3362 def test_put_update_with_private_note_and_changes
3343 3363 notes = 'Private note'
3344 3364 @request.session[:user_id] = 2
3345 3365
3346 3366 assert_difference 'Journal.count', 2 do
3347 3367 put :update, :id => 1, :issue => {:subject => 'New subject', :notes => notes, :private_notes => '1'}
3348 3368 assert_redirected_to :action => 'show', :id => '1'
3349 3369 end
3350 3370
3351 3371 j = Journal.order('id DESC').first
3352 3372 assert_equal notes, j.notes
3353 3373 assert_equal true, j.private_notes
3354 3374 assert_equal 0, j.details.count
3355 3375
3356 3376 j = Journal.order('id DESC').offset(1).first
3357 3377 assert_nil j.notes
3358 3378 assert_equal false, j.private_notes
3359 3379 assert_equal 1, j.details.count
3360 3380 end
3361 3381
3362 3382 def test_put_update_with_note_and_spent_time
3363 3383 @request.session[:user_id] = 2
3364 3384 spent_hours_before = Issue.find(1).spent_hours
3365 3385 assert_difference('TimeEntry.count') do
3366 3386 put :update,
3367 3387 :id => 1,
3368 3388 :issue => { :notes => '2.5 hours added' },
3369 3389 :time_entry => { :hours => '2.5', :comments => 'test_put_update_with_note_and_spent_time', :activity_id => TimeEntryActivity.first.id }
3370 3390 end
3371 3391 assert_redirected_to :action => 'show', :id => '1'
3372 3392
3373 3393 issue = Issue.find(1)
3374 3394
3375 3395 j = Journal.order('id DESC').first
3376 3396 assert_equal '2.5 hours added', j.notes
3377 3397 assert_equal 0, j.details.size
3378 3398
3379 3399 t = issue.time_entries.find_by_comments('test_put_update_with_note_and_spent_time')
3380 3400 assert_not_nil t
3381 3401 assert_equal 2.5, t.hours
3382 3402 assert_equal spent_hours_before + 2.5, issue.spent_hours
3383 3403 end
3384 3404
3385 3405 def test_put_update_should_preserve_parent_issue_even_if_not_visible
3386 3406 parent = Issue.generate!(:project_id => 1, :is_private => true)
3387 3407 issue = Issue.generate!(:parent_issue_id => parent.id)
3388 3408 assert !parent.visible?(User.find(3))
3389 3409 @request.session[:user_id] = 3
3390 3410
3391 3411 get :edit, :id => issue.id
3392 3412 assert_select 'input[name=?][value=?]', 'issue[parent_issue_id]', parent.id.to_s
3393 3413
3394 3414 put :update, :id => issue.id, :issue => {:subject => 'New subject', :parent_issue_id => parent.id.to_s}
3395 3415 assert_response 302
3396 3416 assert_equal parent, issue.parent
3397 3417 end
3398 3418
3399 3419 def test_put_update_with_attachment_only
3400 3420 set_tmp_attachments_directory
3401 3421
3402 3422 # Delete all fixtured journals, a race condition can occur causing the wrong
3403 3423 # journal to get fetched in the next find.
3404 3424 Journal.delete_all
3405 3425
3406 3426 with_settings :notified_events => %w(issue_updated) do
3407 3427 # anonymous user
3408 3428 assert_difference 'Attachment.count' do
3409 3429 put :update, :id => 1,
3410 3430 :issue => {:notes => ''},
3411 3431 :attachments => {'1' => {'file' => uploaded_test_file('testfile.txt', 'text/plain'), 'description' => 'test file'}}
3412 3432 end
3413 3433 end
3414 3434
3415 3435 assert_redirected_to :action => 'show', :id => '1'
3416 3436 j = Issue.find(1).journals.reorder('id DESC').first
3417 3437 assert j.notes.blank?
3418 3438 assert_equal 1, j.details.size
3419 3439 assert_equal 'testfile.txt', j.details.first.value
3420 3440 assert_equal User.anonymous, j.user
3421 3441
3422 3442 attachment = Attachment.order('id DESC').first
3423 3443 assert_equal Issue.find(1), attachment.container
3424 3444 assert_equal User.anonymous, attachment.author
3425 3445 assert_equal 'testfile.txt', attachment.filename
3426 3446 assert_equal 'text/plain', attachment.content_type
3427 3447 assert_equal 'test file', attachment.description
3428 3448 assert_equal 59, attachment.filesize
3429 3449 assert File.exists?(attachment.diskfile)
3430 3450 assert_equal 59, File.size(attachment.diskfile)
3431 3451
3432 3452 mail = ActionMailer::Base.deliveries.last
3433 3453 assert_mail_body_match 'testfile.txt', mail
3434 3454 end
3435 3455
3436 3456 def test_put_update_with_failure_should_save_attachments
3437 3457 set_tmp_attachments_directory
3438 3458 @request.session[:user_id] = 2
3439 3459
3440 3460 assert_no_difference 'Journal.count' do
3441 3461 assert_difference 'Attachment.count' do
3442 3462 put :update, :id => 1,
3443 3463 :issue => { :subject => '' },
3444 3464 :attachments => {'1' => {'file' => uploaded_test_file('testfile.txt', 'text/plain'), 'description' => 'test file'}}
3445 3465 assert_response :success
3446 3466 assert_template 'edit'
3447 3467 end
3448 3468 end
3449 3469
3450 3470 attachment = Attachment.order('id DESC').first
3451 3471 assert_equal 'testfile.txt', attachment.filename
3452 3472 assert File.exists?(attachment.diskfile)
3453 3473 assert_nil attachment.container
3454 3474
3455 3475 assert_select 'input[name=?][value=?]', 'attachments[p0][token]', attachment.token
3456 3476 assert_select 'input[name=?][value=?]', 'attachments[p0][filename]', 'testfile.txt'
3457 3477 end
3458 3478
3459 3479 def test_put_update_with_failure_should_keep_saved_attachments
3460 3480 set_tmp_attachments_directory
3461 3481 attachment = Attachment.create!(:file => uploaded_test_file("testfile.txt", "text/plain"), :author_id => 2)
3462 3482 @request.session[:user_id] = 2
3463 3483
3464 3484 assert_no_difference 'Journal.count' do
3465 3485 assert_no_difference 'Attachment.count' do
3466 3486 put :update, :id => 1,
3467 3487 :issue => { :subject => '' },
3468 3488 :attachments => {'p0' => {'token' => attachment.token}}
3469 3489 assert_response :success
3470 3490 assert_template 'edit'
3471 3491 end
3472 3492 end
3473 3493
3474 3494 assert_select 'input[name=?][value=?]', 'attachments[p0][token]', attachment.token
3475 3495 assert_select 'input[name=?][value=?]', 'attachments[p0][filename]', 'testfile.txt'
3476 3496 end
3477 3497
3478 3498 def test_put_update_should_attach_saved_attachments
3479 3499 set_tmp_attachments_directory
3480 3500 attachment = Attachment.create!(:file => uploaded_test_file("testfile.txt", "text/plain"), :author_id => 2)
3481 3501 @request.session[:user_id] = 2
3482 3502
3483 3503 assert_difference 'Journal.count' do
3484 3504 assert_difference 'JournalDetail.count' do
3485 3505 assert_no_difference 'Attachment.count' do
3486 3506 put :update, :id => 1,
3487 3507 :issue => {:notes => 'Attachment added'},
3488 3508 :attachments => {'p0' => {'token' => attachment.token}}
3489 3509 assert_redirected_to '/issues/1'
3490 3510 end
3491 3511 end
3492 3512 end
3493 3513
3494 3514 attachment.reload
3495 3515 assert_equal Issue.find(1), attachment.container
3496 3516
3497 3517 journal = Journal.order('id DESC').first
3498 3518 assert_equal 1, journal.details.size
3499 3519 assert_equal 'testfile.txt', journal.details.first.value
3500 3520 end
3501 3521
3502 3522 def test_put_update_with_attachment_that_fails_to_save
3503 3523 set_tmp_attachments_directory
3504 3524
3505 3525 # anonymous user
3506 3526 with_settings :attachment_max_size => 0 do
3507 3527 put :update,
3508 3528 :id => 1,
3509 3529 :issue => {:notes => ''},
3510 3530 :attachments => {'1' => {'file' => uploaded_test_file('testfile.txt', 'text/plain')}}
3511 3531 assert_redirected_to :action => 'show', :id => '1'
3512 3532 assert_equal '1 file(s) could not be saved.', flash[:warning]
3513 3533 end
3514 3534 end
3515 3535
3516 3536 def test_put_update_with_no_change
3517 3537 issue = Issue.find(1)
3518 3538 issue.journals.clear
3519 3539 ActionMailer::Base.deliveries.clear
3520 3540
3521 3541 put :update,
3522 3542 :id => 1,
3523 3543 :issue => {:notes => ''}
3524 3544 assert_redirected_to :action => 'show', :id => '1'
3525 3545
3526 3546 issue.reload
3527 3547 assert issue.journals.empty?
3528 3548 # No email should be sent
3529 3549 assert ActionMailer::Base.deliveries.empty?
3530 3550 end
3531 3551
3532 3552 def test_put_update_should_send_a_notification
3533 3553 @request.session[:user_id] = 2
3534 3554 ActionMailer::Base.deliveries.clear
3535 3555 issue = Issue.find(1)
3536 3556 old_subject = issue.subject
3537 3557 new_subject = 'Subject modified by IssuesControllerTest#test_post_edit'
3538 3558
3539 3559 with_settings :notified_events => %w(issue_updated) do
3540 3560 put :update, :id => 1, :issue => {:subject => new_subject,
3541 3561 :priority_id => '6',
3542 3562 :category_id => '1' # no change
3543 3563 }
3544 3564 assert_equal 1, ActionMailer::Base.deliveries.size
3545 3565 end
3546 3566 end
3547 3567
3548 3568 def test_put_update_with_invalid_spent_time_hours_only
3549 3569 @request.session[:user_id] = 2
3550 3570 notes = 'Note added by IssuesControllerTest#test_post_edit_with_invalid_spent_time'
3551 3571
3552 3572 assert_no_difference('Journal.count') do
3553 3573 put :update,
3554 3574 :id => 1,
3555 3575 :issue => {:notes => notes},
3556 3576 :time_entry => {"comments"=>"", "activity_id"=>"", "hours"=>"2z"}
3557 3577 end
3558 3578 assert_response :success
3559 3579 assert_template 'edit'
3560 3580
3561 3581 assert_select_error /Activity cannot be blank/
3562 3582 assert_select 'textarea[name=?]', 'issue[notes]', :text => notes
3563 3583 assert_select 'input[name=?][value=?]', 'time_entry[hours]', '2z'
3564 3584 end
3565 3585
3566 3586 def test_put_update_with_invalid_spent_time_comments_only
3567 3587 @request.session[:user_id] = 2
3568 3588 notes = 'Note added by IssuesControllerTest#test_post_edit_with_invalid_spent_time'
3569 3589
3570 3590 assert_no_difference('Journal.count') do
3571 3591 put :update,
3572 3592 :id => 1,
3573 3593 :issue => {:notes => notes},
3574 3594 :time_entry => {"comments"=>"this is my comment", "activity_id"=>"", "hours"=>""}
3575 3595 end
3576 3596 assert_response :success
3577 3597 assert_template 'edit'
3578 3598
3579 3599 assert_select_error /Activity cannot be blank/
3580 3600 assert_select_error /Hours cannot be blank/
3581 3601 assert_select 'textarea[name=?]', 'issue[notes]', :text => notes
3582 3602 assert_select 'input[name=?][value=?]', 'time_entry[comments]', 'this is my comment'
3583 3603 end
3584 3604
3585 3605 def test_put_update_should_allow_fixed_version_to_be_set_to_a_subproject
3586 3606 issue = Issue.find(2)
3587 3607 @request.session[:user_id] = 2
3588 3608
3589 3609 put :update,
3590 3610 :id => issue.id,
3591 3611 :issue => {
3592 3612 :fixed_version_id => 4
3593 3613 }
3594 3614
3595 3615 assert_response :redirect
3596 3616 issue.reload
3597 3617 assert_equal 4, issue.fixed_version_id
3598 3618 assert_not_equal issue.project_id, issue.fixed_version.project_id
3599 3619 end
3600 3620
3601 3621 def test_put_update_should_redirect_back_using_the_back_url_parameter
3602 3622 issue = Issue.find(2)
3603 3623 @request.session[:user_id] = 2
3604 3624
3605 3625 put :update,
3606 3626 :id => issue.id,
3607 3627 :issue => {
3608 3628 :fixed_version_id => 4
3609 3629 },
3610 3630 :back_url => '/issues'
3611 3631
3612 3632 assert_response :redirect
3613 3633 assert_redirected_to '/issues'
3614 3634 end
3615 3635
3616 3636 def test_put_update_should_not_redirect_back_using_the_back_url_parameter_off_the_host
3617 3637 issue = Issue.find(2)
3618 3638 @request.session[:user_id] = 2
3619 3639
3620 3640 put :update,
3621 3641 :id => issue.id,
3622 3642 :issue => {
3623 3643 :fixed_version_id => 4
3624 3644 },
3625 3645 :back_url => 'http://google.com'
3626 3646
3627 3647 assert_response :redirect
3628 3648 assert_redirected_to :controller => 'issues', :action => 'show', :id => issue.id
3629 3649 end
3630 3650
3631 3651 def test_get_bulk_edit
3632 3652 @request.session[:user_id] = 2
3633 3653 get :bulk_edit, :ids => [1, 3]
3634 3654 assert_response :success
3635 3655 assert_template 'bulk_edit'
3636 3656
3637 3657 assert_select 'ul#bulk-selection' do
3638 3658 assert_select 'li', 2
3639 3659 assert_select 'li a', :text => 'Bug #1'
3640 3660 end
3641 3661
3642 3662 assert_select 'form#bulk_edit_form[action=?]', '/issues/bulk_update' do
3643 3663 assert_select 'input[name=?]', 'ids[]', 2
3644 3664 assert_select 'input[name=?][value="1"][type=hidden]', 'ids[]'
3645 3665
3646 3666 assert_select 'select[name=?]', 'issue[project_id]'
3647 3667 assert_select 'input[name=?]', 'issue[parent_issue_id]'
3648 3668
3649 3669 # Project specific custom field, date type
3650 3670 field = CustomField.find(9)
3651 3671 assert !field.is_for_all?
3652 3672 assert_equal 'date', field.field_format
3653 3673 assert_select 'input[name=?]', 'issue[custom_field_values][9]'
3654 3674
3655 3675 # System wide custom field
3656 3676 assert CustomField.find(1).is_for_all?
3657 3677 assert_select 'select[name=?]', 'issue[custom_field_values][1]'
3658 3678
3659 3679 # Be sure we don't display inactive IssuePriorities
3660 3680 assert ! IssuePriority.find(15).active?
3661 3681 assert_select 'select[name=?]', 'issue[priority_id]' do
3662 3682 assert_select 'option[value="15"]', 0
3663 3683 end
3664 3684 end
3665 3685 end
3666 3686
3667 3687 def test_get_bulk_edit_on_different_projects
3668 3688 @request.session[:user_id] = 2
3669 3689 get :bulk_edit, :ids => [1, 2, 6]
3670 3690 assert_response :success
3671 3691 assert_template 'bulk_edit'
3672 3692
3673 3693 # Can not set issues from different projects as children of an issue
3674 3694 assert_select 'input[name=?]', 'issue[parent_issue_id]', 0
3675 3695
3676 3696 # Project specific custom field, date type
3677 3697 field = CustomField.find(9)
3678 3698 assert !field.is_for_all?
3679 3699 assert !field.project_ids.include?(Issue.find(6).project_id)
3680 3700 assert_select 'input[name=?]', 'issue[custom_field_values][9]', 0
3681 3701 end
3682 3702
3683 3703 def test_get_bulk_edit_with_user_custom_field
3684 3704 field = IssueCustomField.create!(:name => 'Tester', :field_format => 'user', :is_for_all => true, :tracker_ids => [1,2,3])
3685 3705
3686 3706 @request.session[:user_id] = 2
3687 3707 get :bulk_edit, :ids => [1, 2]
3688 3708 assert_response :success
3689 3709 assert_template 'bulk_edit'
3690 3710
3691 3711 assert_select 'select.user_cf[name=?]', "issue[custom_field_values][#{field.id}]" do
3692 3712 assert_select 'option', Project.find(1).users.count + 2 # "no change" + "none" options
3693 3713 end
3694 3714 end
3695 3715
3696 3716 def test_get_bulk_edit_with_version_custom_field
3697 3717 field = IssueCustomField.create!(:name => 'Affected version', :field_format => 'version', :is_for_all => true, :tracker_ids => [1,2,3])
3698 3718
3699 3719 @request.session[:user_id] = 2
3700 3720 get :bulk_edit, :ids => [1, 2]
3701 3721 assert_response :success
3702 3722 assert_template 'bulk_edit'
3703 3723
3704 3724 assert_select 'select.version_cf[name=?]', "issue[custom_field_values][#{field.id}]" do
3705 3725 assert_select 'option', Project.find(1).shared_versions.count + 2 # "no change" + "none" options
3706 3726 end
3707 3727 end
3708 3728
3709 3729 def test_get_bulk_edit_with_multi_custom_field
3710 3730 field = CustomField.find(1)
3711 3731 field.update_attribute :multiple, true
3712 3732
3713 3733 @request.session[:user_id] = 2
3714 3734 get :bulk_edit, :ids => [1, 3]
3715 3735 assert_response :success
3716 3736 assert_template 'bulk_edit'
3717 3737
3718 3738 assert_select 'select[name=?]', 'issue[custom_field_values][1][]' do
3719 3739 assert_select 'option', field.possible_values.size + 1 # "none" options
3720 3740 end
3721 3741 end
3722 3742
3723 3743 def test_bulk_edit_should_propose_to_clear_text_custom_fields
3724 3744 @request.session[:user_id] = 2
3725 3745 get :bulk_edit, :ids => [1, 3]
3726 3746 assert_select 'input[name=?][value=?]', 'issue[custom_field_values][2]', '__none__'
3727 3747 end
3728 3748
3729 3749 def test_bulk_edit_should_only_propose_statuses_allowed_for_all_issues
3730 3750 WorkflowTransition.delete_all
3731 3751 WorkflowTransition.create!(:role_id => 1, :tracker_id => 1,
3732 3752 :old_status_id => 1, :new_status_id => 1)
3733 3753 WorkflowTransition.create!(:role_id => 1, :tracker_id => 1,
3734 3754 :old_status_id => 1, :new_status_id => 3)
3735 3755 WorkflowTransition.create!(:role_id => 1, :tracker_id => 1,
3736 3756 :old_status_id => 1, :new_status_id => 4)
3737 3757 WorkflowTransition.create!(:role_id => 1, :tracker_id => 2,
3738 3758 :old_status_id => 2, :new_status_id => 1)
3739 3759 WorkflowTransition.create!(:role_id => 1, :tracker_id => 2,
3740 3760 :old_status_id => 2, :new_status_id => 3)
3741 3761 WorkflowTransition.create!(:role_id => 1, :tracker_id => 2,
3742 3762 :old_status_id => 2, :new_status_id => 5)
3743 3763 @request.session[:user_id] = 2
3744 3764 get :bulk_edit, :ids => [1, 2]
3745 3765
3746 3766 assert_response :success
3747 3767 statuses = assigns(:available_statuses)
3748 3768 assert_not_nil statuses
3749 3769 assert_equal [1, 3], statuses.map(&:id).sort
3750 3770
3751 3771 assert_select 'select[name=?]', 'issue[status_id]' do
3752 3772 assert_select 'option', 3 # 2 statuses + "no change" option
3753 3773 end
3754 3774 end
3755 3775
3756 3776 def test_bulk_edit_should_propose_target_project_open_shared_versions
3757 3777 @request.session[:user_id] = 2
3758 3778 post :bulk_edit, :ids => [1, 2, 6], :issue => {:project_id => 1}
3759 3779 assert_response :success
3760 3780 assert_template 'bulk_edit'
3761 3781 assert_equal Project.find(1).shared_versions.open.to_a.sort, assigns(:versions).sort
3762 3782
3763 3783 assert_select 'select[name=?]', 'issue[fixed_version_id]' do
3764 3784 assert_select 'option', :text => '2.0'
3765 3785 end
3766 3786 end
3767 3787
3768 3788 def test_bulk_edit_should_propose_target_project_categories
3769 3789 @request.session[:user_id] = 2
3770 3790 post :bulk_edit, :ids => [1, 2, 6], :issue => {:project_id => 1}
3771 3791 assert_response :success
3772 3792 assert_template 'bulk_edit'
3773 3793 assert_equal Project.find(1).issue_categories.sort, assigns(:categories).sort
3774 3794
3775 3795 assert_select 'select[name=?]', 'issue[category_id]' do
3776 3796 assert_select 'option', :text => 'Recipes'
3777 3797 end
3778 3798 end
3779 3799
3780 3800 def test_bulk_edit_should_only_propose_issues_trackers_custom_fields
3781 3801 IssueCustomField.delete_all
3782 3802 field = IssueCustomField.generate!(:tracker_ids => [1], :is_for_all => true)
3783 3803 IssueCustomField.generate!(:tracker_ids => [2], :is_for_all => true)
3784 3804 @request.session[:user_id] = 2
3785 3805
3786 3806 issue_ids = Issue.where(:project_id => 1, :tracker_id => 1).limit(2).ids
3787 3807 get :bulk_edit, :ids => issue_ids
3788 3808 assert_equal [field], assigns(:custom_fields)
3789 3809 end
3790 3810
3791 3811 def test_bulk_update
3792 3812 @request.session[:user_id] = 2
3793 3813 # update issues priority
3794 3814 post :bulk_update, :ids => [1, 2], :notes => 'Bulk editing',
3795 3815 :issue => {:priority_id => 7,
3796 3816 :assigned_to_id => '',
3797 3817 :custom_field_values => {'2' => ''}}
3798 3818
3799 3819 assert_response 302
3800 3820 # check that the issues were updated
3801 3821 assert_equal [7, 7], Issue.where(:id =>[1, 2]).collect {|i| i.priority.id}
3802 3822
3803 3823 issue = Issue.find(1)
3804 3824 journal = issue.journals.reorder('created_on DESC').first
3805 3825 assert_equal '125', issue.custom_value_for(2).value
3806 3826 assert_equal 'Bulk editing', journal.notes
3807 3827 assert_equal 1, journal.details.size
3808 3828 end
3809 3829
3810 3830 def test_bulk_update_with_group_assignee
3811 3831 group = Group.find(11)
3812 3832 project = Project.find(1)
3813 3833 project.members << Member.new(:principal => group, :roles => [Role.givable.first])
3814 3834
3815 3835 @request.session[:user_id] = 2
3816 3836 # update issues assignee
3817 3837 post :bulk_update, :ids => [1, 2], :notes => 'Bulk editing',
3818 3838 :issue => {:priority_id => '',
3819 3839 :assigned_to_id => group.id,
3820 3840 :custom_field_values => {'2' => ''}}
3821 3841
3822 3842 assert_response 302
3823 3843 assert_equal [group, group], Issue.where(:id => [1, 2]).collect {|i| i.assigned_to}
3824 3844 end
3825 3845
3826 3846 def test_bulk_update_on_different_projects
3827 3847 @request.session[:user_id] = 2
3828 3848 # update issues priority
3829 3849 post :bulk_update, :ids => [1, 2, 6], :notes => 'Bulk editing',
3830 3850 :issue => {:priority_id => 7,
3831 3851 :assigned_to_id => '',
3832 3852 :custom_field_values => {'2' => ''}}
3833 3853
3834 3854 assert_response 302
3835 3855 # check that the issues were updated
3836 3856 assert_equal [7, 7, 7], Issue.find([1,2,6]).map(&:priority_id)
3837 3857
3838 3858 issue = Issue.find(1)
3839 3859 journal = issue.journals.reorder('created_on DESC').first
3840 3860 assert_equal '125', issue.custom_value_for(2).value
3841 3861 assert_equal 'Bulk editing', journal.notes
3842 3862 assert_equal 1, journal.details.size
3843 3863 end
3844 3864
3845 3865 def test_bulk_update_on_different_projects_without_rights
3846 3866 @request.session[:user_id] = 3
3847 3867 user = User.find(3)
3848 3868 action = { :controller => "issues", :action => "bulk_update" }
3849 3869 assert user.allowed_to?(action, Issue.find(1).project)
3850 3870 assert ! user.allowed_to?(action, Issue.find(6).project)
3851 3871 post :bulk_update, :ids => [1, 6], :notes => 'Bulk should fail',
3852 3872 :issue => {:priority_id => 7,
3853 3873 :assigned_to_id => '',
3854 3874 :custom_field_values => {'2' => ''}}
3855 3875 assert_response 403
3856 3876 assert_not_equal "Bulk should fail", Journal.last.notes
3857 3877 end
3858 3878
3859 3879 def test_bullk_update_should_send_a_notification
3860 3880 @request.session[:user_id] = 2
3861 3881 ActionMailer::Base.deliveries.clear
3862 3882 with_settings :notified_events => %w(issue_updated) do
3863 3883 post(:bulk_update,
3864 3884 {
3865 3885 :ids => [1, 2],
3866 3886 :notes => 'Bulk editing',
3867 3887 :issue => {
3868 3888 :priority_id => 7,
3869 3889 :assigned_to_id => '',
3870 3890 :custom_field_values => {'2' => ''}
3871 3891 }
3872 3892 })
3873 3893 assert_response 302
3874 3894 assert_equal 2, ActionMailer::Base.deliveries.size
3875 3895 end
3876 3896 end
3877 3897
3878 3898 def test_bulk_update_project
3879 3899 @request.session[:user_id] = 2
3880 3900 post :bulk_update, :ids => [1, 2], :issue => {:project_id => '2'}
3881 3901 assert_redirected_to :controller => 'issues', :action => 'index', :project_id => 'ecookbook'
3882 3902 # Issues moved to project 2
3883 3903 assert_equal 2, Issue.find(1).project_id
3884 3904 assert_equal 2, Issue.find(2).project_id
3885 3905 # No tracker change
3886 3906 assert_equal 1, Issue.find(1).tracker_id
3887 3907 assert_equal 2, Issue.find(2).tracker_id
3888 3908 end
3889 3909
3890 3910 def test_bulk_update_project_on_single_issue_should_follow_when_needed
3891 3911 @request.session[:user_id] = 2
3892 3912 post :bulk_update, :id => 1, :issue => {:project_id => '2'}, :follow => '1'
3893 3913 assert_redirected_to '/issues/1'
3894 3914 end
3895 3915
3896 3916 def test_bulk_update_project_on_multiple_issues_should_follow_when_needed
3897 3917 @request.session[:user_id] = 2
3898 3918 post :bulk_update, :id => [1, 2], :issue => {:project_id => '2'}, :follow => '1'
3899 3919 assert_redirected_to '/projects/onlinestore/issues'
3900 3920 end
3901 3921
3902 3922 def test_bulk_update_tracker
3903 3923 @request.session[:user_id] = 2
3904 3924 post :bulk_update, :ids => [1, 2], :issue => {:tracker_id => '2'}
3905 3925 assert_redirected_to :controller => 'issues', :action => 'index', :project_id => 'ecookbook'
3906 3926 assert_equal 2, Issue.find(1).tracker_id
3907 3927 assert_equal 2, Issue.find(2).tracker_id
3908 3928 end
3909 3929
3910 3930 def test_bulk_update_status
3911 3931 @request.session[:user_id] = 2
3912 3932 # update issues priority
3913 3933 post :bulk_update, :ids => [1, 2], :notes => 'Bulk editing status',
3914 3934 :issue => {:priority_id => '',
3915 3935 :assigned_to_id => '',
3916 3936 :status_id => '5'}
3917 3937
3918 3938 assert_response 302
3919 3939 issue = Issue.find(1)
3920 3940 assert issue.closed?
3921 3941 end
3922 3942
3923 3943 def test_bulk_update_priority
3924 3944 @request.session[:user_id] = 2
3925 3945 post :bulk_update, :ids => [1, 2], :issue => {:priority_id => 6}
3926 3946
3927 3947 assert_redirected_to :controller => 'issues', :action => 'index', :project_id => 'ecookbook'
3928 3948 assert_equal 6, Issue.find(1).priority_id
3929 3949 assert_equal 6, Issue.find(2).priority_id
3930 3950 end
3931 3951
3932 3952 def test_bulk_update_with_notes
3933 3953 @request.session[:user_id] = 2
3934 3954 post :bulk_update, :ids => [1, 2], :notes => 'Moving two issues'
3935 3955
3936 3956 assert_redirected_to :controller => 'issues', :action => 'index', :project_id => 'ecookbook'
3937 3957 assert_equal 'Moving two issues', Issue.find(1).journals.sort_by(&:id).last.notes
3938 3958 assert_equal 'Moving two issues', Issue.find(2).journals.sort_by(&:id).last.notes
3939 3959 end
3940 3960
3941 3961 def test_bulk_update_parent_id
3942 3962 IssueRelation.delete_all
3943 3963 @request.session[:user_id] = 2
3944 3964 post :bulk_update, :ids => [1, 3],
3945 3965 :notes => 'Bulk editing parent',
3946 3966 :issue => {:priority_id => '', :assigned_to_id => '',
3947 3967 :status_id => '', :parent_issue_id => '2'}
3948 3968 assert_response 302
3949 3969 parent = Issue.find(2)
3950 3970 assert_equal parent.id, Issue.find(1).parent_id
3951 3971 assert_equal parent.id, Issue.find(3).parent_id
3952 3972 assert_equal [1, 3], parent.children.collect(&:id).sort
3953 3973 end
3954 3974
3955 3975 def test_bulk_update_custom_field
3956 3976 @request.session[:user_id] = 2
3957 3977 # update issues priority
3958 3978 post :bulk_update, :ids => [1, 2], :notes => 'Bulk editing custom field',
3959 3979 :issue => {:priority_id => '',
3960 3980 :assigned_to_id => '',
3961 3981 :custom_field_values => {'2' => '777'}}
3962 3982
3963 3983 assert_response 302
3964 3984
3965 3985 issue = Issue.find(1)
3966 3986 journal = issue.journals.reorder('created_on DESC').first
3967 3987 assert_equal '777', issue.custom_value_for(2).value
3968 3988 assert_equal 1, journal.details.size
3969 3989 assert_equal '125', journal.details.first.old_value
3970 3990 assert_equal '777', journal.details.first.value
3971 3991 end
3972 3992
3973 3993 def test_bulk_update_custom_field_to_blank
3974 3994 @request.session[:user_id] = 2
3975 3995 post :bulk_update, :ids => [1, 3], :notes => 'Bulk editing custom field',
3976 3996 :issue => {:priority_id => '',
3977 3997 :assigned_to_id => '',
3978 3998 :custom_field_values => {'1' => '__none__'}}
3979 3999 assert_response 302
3980 4000 assert_equal '', Issue.find(1).custom_field_value(1)
3981 4001 assert_equal '', Issue.find(3).custom_field_value(1)
3982 4002 end
3983 4003
3984 4004 def test_bulk_update_multi_custom_field
3985 4005 field = CustomField.find(1)
3986 4006 field.update_attribute :multiple, true
3987 4007
3988 4008 @request.session[:user_id] = 2
3989 4009 post :bulk_update, :ids => [1, 2, 3], :notes => 'Bulk editing multi custom field',
3990 4010 :issue => {:priority_id => '',
3991 4011 :assigned_to_id => '',
3992 4012 :custom_field_values => {'1' => ['MySQL', 'Oracle']}}
3993 4013
3994 4014 assert_response 302
3995 4015
3996 4016 assert_equal ['MySQL', 'Oracle'], Issue.find(1).custom_field_value(1).sort
3997 4017 assert_equal ['MySQL', 'Oracle'], Issue.find(3).custom_field_value(1).sort
3998 4018 # the custom field is not associated with the issue tracker
3999 4019 assert_nil Issue.find(2).custom_field_value(1)
4000 4020 end
4001 4021
4002 4022 def test_bulk_update_multi_custom_field_to_blank
4003 4023 field = CustomField.find(1)
4004 4024 field.update_attribute :multiple, true
4005 4025
4006 4026 @request.session[:user_id] = 2
4007 4027 post :bulk_update, :ids => [1, 3], :notes => 'Bulk editing multi custom field',
4008 4028 :issue => {:priority_id => '',
4009 4029 :assigned_to_id => '',
4010 4030 :custom_field_values => {'1' => ['__none__']}}
4011 4031 assert_response 302
4012 4032 assert_equal [''], Issue.find(1).custom_field_value(1)
4013 4033 assert_equal [''], Issue.find(3).custom_field_value(1)
4014 4034 end
4015 4035
4016 4036 def test_bulk_update_unassign
4017 4037 assert_not_nil Issue.find(2).assigned_to
4018 4038 @request.session[:user_id] = 2
4019 4039 # unassign issues
4020 4040 post :bulk_update, :ids => [1, 2], :notes => 'Bulk unassigning', :issue => {:assigned_to_id => 'none'}
4021 4041 assert_response 302
4022 4042 # check that the issues were updated
4023 4043 assert_nil Issue.find(2).assigned_to
4024 4044 end
4025 4045
4026 4046 def test_post_bulk_update_should_allow_fixed_version_to_be_set_to_a_subproject
4027 4047 @request.session[:user_id] = 2
4028 4048
4029 4049 post :bulk_update, :ids => [1,2], :issue => {:fixed_version_id => 4}
4030 4050
4031 4051 assert_response :redirect
4032 4052 issues = Issue.find([1,2])
4033 4053 issues.each do |issue|
4034 4054 assert_equal 4, issue.fixed_version_id
4035 4055 assert_not_equal issue.project_id, issue.fixed_version.project_id
4036 4056 end
4037 4057 end
4038 4058
4039 4059 def test_post_bulk_update_should_redirect_back_using_the_back_url_parameter
4040 4060 @request.session[:user_id] = 2
4041 4061 post :bulk_update, :ids => [1,2], :back_url => '/issues'
4042 4062
4043 4063 assert_response :redirect
4044 4064 assert_redirected_to '/issues'
4045 4065 end
4046 4066
4047 4067 def test_post_bulk_update_should_not_redirect_back_using_the_back_url_parameter_off_the_host
4048 4068 @request.session[:user_id] = 2
4049 4069 post :bulk_update, :ids => [1,2], :back_url => 'http://google.com'
4050 4070
4051 4071 assert_response :redirect
4052 4072 assert_redirected_to :controller => 'issues', :action => 'index', :project_id => Project.find(1).identifier
4053 4073 end
4054 4074
4055 4075 def test_bulk_update_with_all_failures_should_show_errors
4056 4076 @request.session[:user_id] = 2
4057 4077 post :bulk_update, :ids => [1, 2], :issue => {:start_date => 'foo'}
4058 4078
4059 4079 assert_response :success
4060 4080 assert_template 'bulk_edit'
4061 4081 assert_select '#errorExplanation span', :text => 'Failed to save 2 issue(s) on 2 selected: #1, #2.'
4062 4082 assert_select '#errorExplanation ul li', :text => 'Start date is not a valid date: #1, #2'
4063 4083
4064 4084 assert_equal [1, 2], assigns[:issues].map(&:id)
4065 4085 end
4066 4086
4067 4087 def test_bulk_update_with_some_failures_should_show_errors
4068 4088 issue1 = Issue.generate!(:start_date => '2013-05-12')
4069 4089 issue2 = Issue.generate!(:start_date => '2013-05-15')
4070 4090 issue3 = Issue.generate!
4071 4091 @request.session[:user_id] = 2
4072 4092 post :bulk_update, :ids => [issue1.id, issue2.id, issue3.id],
4073 4093 :issue => {:due_date => '2013-05-01'}
4074 4094 assert_response :success
4075 4095 assert_template 'bulk_edit'
4076 4096 assert_select '#errorExplanation span',
4077 4097 :text => "Failed to save 2 issue(s) on 3 selected: ##{issue1.id}, ##{issue2.id}."
4078 4098 assert_select '#errorExplanation ul li',
4079 4099 :text => "Due date must be greater than start date: ##{issue1.id}, ##{issue2.id}"
4080 4100 assert_equal [issue1.id, issue2.id], assigns[:issues].map(&:id)
4081 4101 end
4082 4102
4083 4103 def test_bulk_update_with_failure_should_preserved_form_values
4084 4104 @request.session[:user_id] = 2
4085 4105 post :bulk_update, :ids => [1, 2], :issue => {:tracker_id => '2', :start_date => 'foo'}
4086 4106
4087 4107 assert_response :success
4088 4108 assert_template 'bulk_edit'
4089 4109 assert_select 'select[name=?]', 'issue[tracker_id]' do
4090 4110 assert_select 'option[value="2"][selected=selected]'
4091 4111 end
4092 4112 assert_select 'input[name=?][value=?]', 'issue[start_date]', 'foo'
4093 4113 end
4094 4114
4095 4115 def test_get_bulk_copy
4096 4116 @request.session[:user_id] = 2
4097 4117 get :bulk_edit, :ids => [1, 2, 3], :copy => '1'
4098 4118 assert_response :success
4099 4119 assert_template 'bulk_edit'
4100 4120
4101 4121 issues = assigns(:issues)
4102 4122 assert_not_nil issues
4103 4123 assert_equal [1, 2, 3], issues.map(&:id).sort
4104 4124
4105 4125 assert_select 'select[name=?]', 'issue[project_id]' do
4106 4126 assert_select 'option[value=""]'
4107 4127 end
4108 4128 assert_select 'input[name=copy_attachments]'
4109 4129 end
4110 4130
4111 4131 def test_get_bulk_copy_without_add_issues_permission_should_not_propose_current_project_as_target
4112 4132 user = setup_user_with_copy_but_not_add_permission
4113 4133 @request.session[:user_id] = user.id
4114 4134
4115 4135 get :bulk_edit, :ids => [1, 2, 3], :copy => '1'
4116 4136 assert_response :success
4117 4137 assert_template 'bulk_edit'
4118 4138
4119 4139 assert_select 'select[name=?]', 'issue[project_id]' do
4120 4140 assert_select 'option[value=""]', 0
4121 4141 assert_select 'option[value="2"]'
4122 4142 end
4123 4143 end
4124 4144
4125 4145 def test_bulk_copy_to_another_project
4126 4146 @request.session[:user_id] = 2
4127 4147 assert_difference 'Issue.count', 2 do
4128 4148 assert_no_difference 'Project.find(1).issues.count' do
4129 4149 post :bulk_update, :ids => [1, 2], :issue => {:project_id => '2'}, :copy => '1'
4130 4150 end
4131 4151 end
4132 4152 assert_redirected_to '/projects/ecookbook/issues'
4133 4153
4134 4154 copies = Issue.order('id DESC').limit(issues.size)
4135 4155 copies.each do |copy|
4136 4156 assert_equal 2, copy.project_id
4137 4157 end
4138 4158 end
4139 4159
4140 4160 def test_bulk_copy_without_add_issues_permission_should_be_allowed_on_project_with_permission
4141 4161 user = setup_user_with_copy_but_not_add_permission
4142 4162 @request.session[:user_id] = user.id
4143 4163
4144 4164 assert_difference 'Issue.count', 3 do
4145 4165 post :bulk_update, :ids => [1, 2, 3], :issue => {:project_id => '2'}, :copy => '1'
4146 4166 assert_response 302
4147 4167 end
4148 4168 end
4149 4169
4150 4170 def test_bulk_copy_on_same_project_without_add_issues_permission_should_be_denied
4151 4171 user = setup_user_with_copy_but_not_add_permission
4152 4172 @request.session[:user_id] = user.id
4153 4173
4154 4174 post :bulk_update, :ids => [1, 2, 3], :issue => {:project_id => ''}, :copy => '1'
4155 4175 assert_response 403
4156 4176 end
4157 4177
4158 4178 def test_bulk_copy_on_different_project_without_add_issues_permission_should_be_denied
4159 4179 user = setup_user_with_copy_but_not_add_permission
4160 4180 @request.session[:user_id] = user.id
4161 4181
4162 4182 post :bulk_update, :ids => [1, 2, 3], :issue => {:project_id => '1'}, :copy => '1'
4163 4183 assert_response 403
4164 4184 end
4165 4185
4166 4186 def test_bulk_copy_should_allow_not_changing_the_issue_attributes
4167 4187 @request.session[:user_id] = 2
4168 4188 issues = [
4169 4189 Issue.create!(:project_id => 1, :tracker_id => 1, :status_id => 1,
4170 4190 :priority_id => 2, :subject => 'issue 1', :author_id => 1,
4171 4191 :assigned_to_id => nil),
4172 4192 Issue.create!(:project_id => 2, :tracker_id => 3, :status_id => 2,
4173 4193 :priority_id => 1, :subject => 'issue 2', :author_id => 2,
4174 4194 :assigned_to_id => 3)
4175 4195 ]
4176 4196 assert_difference 'Issue.count', issues.size do
4177 4197 post :bulk_update, :ids => issues.map(&:id), :copy => '1',
4178 4198 :issue => {
4179 4199 :project_id => '', :tracker_id => '', :assigned_to_id => '',
4180 4200 :status_id => '', :start_date => '', :due_date => ''
4181 4201 }
4182 4202 end
4183 4203
4184 4204 copies = Issue.order('id DESC').limit(issues.size)
4185 4205 issues.each do |orig|
4186 4206 copy = copies.detect {|c| c.subject == orig.subject}
4187 4207 assert_not_nil copy
4188 4208 assert_equal orig.project_id, copy.project_id
4189 4209 assert_equal orig.tracker_id, copy.tracker_id
4190 4210 assert_equal orig.status_id, copy.status_id
4191 4211 assert_equal orig.assigned_to_id, copy.assigned_to_id
4192 4212 assert_equal orig.priority_id, copy.priority_id
4193 4213 end
4194 4214 end
4195 4215
4196 4216 def test_bulk_copy_should_allow_changing_the_issue_attributes
4197 4217 # Fixes random test failure with Mysql
4198 4218 # where Issue.where(:project_id => 2).limit(2).order('id desc')
4199 4219 # doesn't return the expected results
4200 4220 Issue.delete_all("project_id=2")
4201 4221
4202 4222 @request.session[:user_id] = 2
4203 4223 assert_difference 'Issue.count', 2 do
4204 4224 assert_no_difference 'Project.find(1).issues.count' do
4205 4225 post :bulk_update, :ids => [1, 2], :copy => '1',
4206 4226 :issue => {
4207 4227 :project_id => '2', :tracker_id => '', :assigned_to_id => '4',
4208 4228 :status_id => '1', :start_date => '2009-12-01', :due_date => '2009-12-31'
4209 4229 }
4210 4230 end
4211 4231 end
4212 4232
4213 4233 copied_issues = Issue.where(:project_id => 2).limit(2).order('id desc').to_a
4214 4234 assert_equal 2, copied_issues.size
4215 4235 copied_issues.each do |issue|
4216 4236 assert_equal 2, issue.project_id, "Project is incorrect"
4217 4237 assert_equal 4, issue.assigned_to_id, "Assigned to is incorrect"
4218 4238 assert_equal 1, issue.status_id, "Status is incorrect"
4219 4239 assert_equal '2009-12-01', issue.start_date.to_s, "Start date is incorrect"
4220 4240 assert_equal '2009-12-31', issue.due_date.to_s, "Due date is incorrect"
4221 4241 end
4222 4242 end
4223 4243
4224 4244 def test_bulk_copy_should_allow_adding_a_note
4225 4245 @request.session[:user_id] = 2
4226 4246 assert_difference 'Issue.count', 1 do
4227 4247 post :bulk_update, :ids => [1], :copy => '1',
4228 4248 :notes => 'Copying one issue',
4229 4249 :issue => {
4230 4250 :project_id => '', :tracker_id => '', :assigned_to_id => '4',
4231 4251 :status_id => '3', :start_date => '2009-12-01', :due_date => '2009-12-31'
4232 4252 }
4233 4253 end
4234 4254 issue = Issue.order('id DESC').first
4235 4255 assert_equal 1, issue.journals.size
4236 4256 journal = issue.journals.first
4237 4257 assert_equal 'Copying one issue', journal.notes
4238 4258 end
4239 4259
4240 4260 def test_bulk_copy_should_allow_not_copying_the_attachments
4241 4261 attachment_count = Issue.find(3).attachments.size
4242 4262 assert attachment_count > 0
4243 4263 @request.session[:user_id] = 2
4244 4264
4245 4265 assert_difference 'Issue.count', 1 do
4246 4266 assert_no_difference 'Attachment.count' do
4247 4267 post :bulk_update, :ids => [3], :copy => '1', :copy_attachments => '0',
4248 4268 :issue => {
4249 4269 :project_id => ''
4250 4270 }
4251 4271 end
4252 4272 end
4253 4273 end
4254 4274
4255 4275 def test_bulk_copy_should_allow_copying_the_attachments
4256 4276 attachment_count = Issue.find(3).attachments.size
4257 4277 assert attachment_count > 0
4258 4278 @request.session[:user_id] = 2
4259 4279
4260 4280 assert_difference 'Issue.count', 1 do
4261 4281 assert_difference 'Attachment.count', attachment_count do
4262 4282 post :bulk_update, :ids => [3], :copy => '1', :copy_attachments => '1',
4263 4283 :issue => {
4264 4284 :project_id => ''
4265 4285 }
4266 4286 end
4267 4287 end
4268 4288 end
4269 4289
4270 4290 def test_bulk_copy_should_add_relations_with_copied_issues
4271 4291 @request.session[:user_id] = 2
4272 4292
4273 4293 assert_difference 'Issue.count', 2 do
4274 4294 assert_difference 'IssueRelation.count', 2 do
4275 4295 post :bulk_update, :ids => [1, 3], :copy => '1', :link_copy => '1',
4276 4296 :issue => {
4277 4297 :project_id => '1'
4278 4298 }
4279 4299 end
4280 4300 end
4281 4301 end
4282 4302
4283 4303 def test_bulk_copy_should_allow_not_copying_the_subtasks
4284 4304 issue = Issue.generate_with_descendants!
4285 4305 @request.session[:user_id] = 2
4286 4306
4287 4307 assert_difference 'Issue.count', 1 do
4288 4308 post :bulk_update, :ids => [issue.id], :copy => '1', :copy_subtasks => '0',
4289 4309 :issue => {
4290 4310 :project_id => ''
4291 4311 }
4292 4312 end
4293 4313 end
4294 4314
4295 4315 def test_bulk_copy_should_allow_copying_the_subtasks
4296 4316 issue = Issue.generate_with_descendants!
4297 4317 count = issue.descendants.count
4298 4318 @request.session[:user_id] = 2
4299 4319
4300 4320 assert_difference 'Issue.count', count+1 do
4301 4321 post :bulk_update, :ids => [issue.id], :copy => '1', :copy_subtasks => '1',
4302 4322 :issue => {
4303 4323 :project_id => ''
4304 4324 }
4305 4325 end
4306 4326 copy = Issue.where(:parent_id => nil).order("id DESC").first
4307 4327 assert_equal count, copy.descendants.count
4308 4328 end
4309 4329
4310 4330 def test_bulk_copy_should_not_copy_selected_subtasks_twice
4311 4331 issue = Issue.generate_with_descendants!
4312 4332 count = issue.descendants.count
4313 4333 @request.session[:user_id] = 2
4314 4334
4315 4335 assert_difference 'Issue.count', count+1 do
4316 4336 post :bulk_update, :ids => issue.self_and_descendants.map(&:id), :copy => '1', :copy_subtasks => '1',
4317 4337 :issue => {
4318 4338 :project_id => ''
4319 4339 }
4320 4340 end
4321 4341 copy = Issue.where(:parent_id => nil).order("id DESC").first
4322 4342 assert_equal count, copy.descendants.count
4323 4343 end
4324 4344
4325 4345 def test_bulk_copy_to_another_project_should_follow_when_needed
4326 4346 @request.session[:user_id] = 2
4327 4347 post :bulk_update, :ids => [1], :copy => '1', :issue => {:project_id => 2}, :follow => '1'
4328 4348 issue = Issue.order('id DESC').first
4329 4349 assert_redirected_to :controller => 'issues', :action => 'show', :id => issue
4330 4350 end
4331 4351
4332 4352 def test_bulk_copy_with_all_failures_should_display_errors
4333 4353 @request.session[:user_id] = 2
4334 4354 post :bulk_update, :ids => [1, 2], :copy => '1', :issue => {:start_date => 'foo'}
4335 4355
4336 4356 assert_response :success
4337 4357 end
4338 4358
4339 4359 def test_destroy_issue_with_no_time_entries
4340 4360 assert_nil TimeEntry.find_by_issue_id(2)
4341 4361 @request.session[:user_id] = 2
4342 4362
4343 4363 assert_difference 'Issue.count', -1 do
4344 4364 delete :destroy, :id => 2
4345 4365 end
4346 4366 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
4347 4367 assert_nil Issue.find_by_id(2)
4348 4368 end
4349 4369
4350 4370 def test_destroy_issues_with_time_entries
4351 4371 @request.session[:user_id] = 2
4352 4372
4353 4373 assert_no_difference 'Issue.count' do
4354 4374 delete :destroy, :ids => [1, 3]
4355 4375 end
4356 4376 assert_response :success
4357 4377 assert_template 'destroy'
4358 4378 assert_not_nil assigns(:hours)
4359 4379 assert Issue.find_by_id(1) && Issue.find_by_id(3)
4360 4380
4361 4381 assert_select 'form' do
4362 4382 assert_select 'input[name=_method][value=delete]'
4363 4383 end
4364 4384 end
4365 4385
4366 4386 def test_destroy_issues_and_destroy_time_entries
4367 4387 @request.session[:user_id] = 2
4368 4388
4369 4389 assert_difference 'Issue.count', -2 do
4370 4390 assert_difference 'TimeEntry.count', -3 do
4371 4391 delete :destroy, :ids => [1, 3], :todo => 'destroy'
4372 4392 end
4373 4393 end
4374 4394 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
4375 4395 assert !(Issue.find_by_id(1) || Issue.find_by_id(3))
4376 4396 assert_nil TimeEntry.find_by_id([1, 2])
4377 4397 end
4378 4398
4379 4399 def test_destroy_issues_and_assign_time_entries_to_project
4380 4400 @request.session[:user_id] = 2
4381 4401
4382 4402 assert_difference 'Issue.count', -2 do
4383 4403 assert_no_difference 'TimeEntry.count' do
4384 4404 delete :destroy, :ids => [1, 3], :todo => 'nullify'
4385 4405 end
4386 4406 end
4387 4407 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
4388 4408 assert !(Issue.find_by_id(1) || Issue.find_by_id(3))
4389 4409 assert_nil TimeEntry.find(1).issue_id
4390 4410 assert_nil TimeEntry.find(2).issue_id
4391 4411 end
4392 4412
4393 4413 def test_destroy_issues_and_reassign_time_entries_to_another_issue
4394 4414 @request.session[:user_id] = 2
4395 4415
4396 4416 assert_difference 'Issue.count', -2 do
4397 4417 assert_no_difference 'TimeEntry.count' do
4398 4418 delete :destroy, :ids => [1, 3], :todo => 'reassign', :reassign_to_id => 2
4399 4419 end
4400 4420 end
4401 4421 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
4402 4422 assert !(Issue.find_by_id(1) || Issue.find_by_id(3))
4403 4423 assert_equal 2, TimeEntry.find(1).issue_id
4404 4424 assert_equal 2, TimeEntry.find(2).issue_id
4405 4425 end
4406 4426
4407 4427 def test_destroy_issues_and_reassign_time_entries_to_an_invalid_issue_should_fail
4408 4428 @request.session[:user_id] = 2
4409 4429
4410 4430 assert_no_difference 'Issue.count' do
4411 4431 assert_no_difference 'TimeEntry.count' do
4412 4432 # try to reassign time to an issue of another project
4413 4433 delete :destroy, :ids => [1, 3], :todo => 'reassign', :reassign_to_id => 4
4414 4434 end
4415 4435 end
4416 4436 assert_response :success
4417 4437 assert_template 'destroy'
4418 4438 end
4419 4439
4420 4440 def test_destroy_issues_from_different_projects
4421 4441 @request.session[:user_id] = 2
4422 4442
4423 4443 assert_difference 'Issue.count', -3 do
4424 4444 delete :destroy, :ids => [1, 2, 6], :todo => 'destroy'
4425 4445 end
4426 4446 assert_redirected_to :controller => 'issues', :action => 'index'
4427 4447 assert !(Issue.find_by_id(1) || Issue.find_by_id(2) || Issue.find_by_id(6))
4428 4448 end
4429 4449
4430 4450 def test_destroy_parent_and_child_issues
4431 4451 parent = Issue.create!(:project_id => 1, :author_id => 1, :tracker_id => 1, :subject => 'Parent Issue')
4432 4452 child = Issue.create!(:project_id => 1, :author_id => 1, :tracker_id => 1, :subject => 'Child Issue', :parent_issue_id => parent.id)
4433 4453 assert child.is_descendant_of?(parent.reload)
4434 4454
4435 4455 @request.session[:user_id] = 2
4436 4456 assert_difference 'Issue.count', -2 do
4437 4457 delete :destroy, :ids => [parent.id, child.id], :todo => 'destroy'
4438 4458 end
4439 4459 assert_response 302
4440 4460 end
4441 4461
4442 4462 def test_destroy_invalid_should_respond_with_404
4443 4463 @request.session[:user_id] = 2
4444 4464 assert_no_difference 'Issue.count' do
4445 4465 delete :destroy, :id => 999
4446 4466 end
4447 4467 assert_response 404
4448 4468 end
4449 4469
4450 4470 def test_default_search_scope
4451 4471 get :index
4452 4472
4453 4473 assert_select 'div#quick-search form' do
4454 4474 assert_select 'input[name=issues][value="1"][type=hidden]'
4455 4475 end
4456 4476 end
4457 4477
4458 4478 def setup_user_with_copy_but_not_add_permission
4459 4479 Role.all.each {|r| r.remove_permission! :add_issues}
4460 4480 Role.find_by_name('Manager').add_permission! :add_issues
4461 4481 user = User.generate!
4462 4482 User.add_to_project(user, Project.find(1), Role.find_by_name('Developer'))
4463 4483 User.add_to_project(user, Project.find(2), Role.find_by_name('Manager'))
4464 4484 user
4465 4485 end
4466 4486 end
General Comments 0
You need to be logged in to leave comments. Login now