##// END OF EJS Templates
Previous/Next navigation on a issue is not displayed on r15639 and later (#23781)....
Jean-Philippe Lang -
r15468:7daa5b750fe6
parent child
Show More
@@ -1,345 +1,348
1 1 # encoding: utf-8
2 2 #
3 3 # Redmine - project management software
4 4 # Copyright (C) 2006-2016 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 field_options[:type] == :relation
28 28 group = :label_relations
29 29 elsif field_options[:type] == :tree
30 30 group = query.is_a?(IssueQuery) ? :label_relations : nil
31 31 elsif field =~ /^(.+)\./
32 32 # association filters
33 33 group = "field_#{$1}"
34 34 elsif %w(member_of_group assigned_to_role).include?(field)
35 35 group = :field_assigned_to
36 36 elsif field_options[:type] == :date_past || field_options[:type] == :date
37 37 group = :label_date
38 38 end
39 39 if group
40 40 (grouped[group] ||= []) << [field_options[:name], field]
41 41 else
42 42 ungrouped << [field_options[:name], field]
43 43 end
44 44 end
45 45 # Don't group dates if there's only one (eg. time entries filters)
46 46 if grouped[:label_date].try(:size) == 1
47 47 ungrouped << grouped.delete(:label_date).first
48 48 end
49 49 s = options_for_select([[]] + ungrouped)
50 50 if grouped.present?
51 51 localized_grouped = grouped.map {|k,v| [l(k), v]}
52 52 s << grouped_options_for_select(localized_grouped)
53 53 end
54 54 s
55 55 end
56 56
57 57 def query_filters_hidden_tags(query)
58 58 tags = ''.html_safe
59 59 query.filters.each do |field, options|
60 60 tags << hidden_field_tag("f[]", field, :id => nil)
61 61 tags << hidden_field_tag("op[#{field}]", options[:operator], :id => nil)
62 62 options[:values].each do |value|
63 63 tags << hidden_field_tag("v[#{field}][]", value, :id => nil)
64 64 end
65 65 end
66 66 tags
67 67 end
68 68
69 69 def query_columns_hidden_tags(query)
70 70 tags = ''.html_safe
71 71 query.columns.each do |column|
72 72 tags << hidden_field_tag("c[]", column.name, :id => nil)
73 73 end
74 74 tags
75 75 end
76 76
77 77 def query_hidden_tags(query)
78 78 query_filters_hidden_tags(query) + query_columns_hidden_tags(query)
79 79 end
80 80
81 81 def group_by_column_select_tag(query)
82 82 options = [[]] + query.groupable_columns.collect {|c| [c.caption, c.name.to_s]}
83 83 select_tag('group_by', options_for_select(options, @query.group_by))
84 84 end
85 85
86 86 def available_block_columns_tags(query)
87 87 tags = ''.html_safe
88 88 query.available_block_columns.each do |column|
89 89 tags << content_tag('label', check_box_tag('c[]', column.name.to_s, query.has_column?(column), :id => nil) + " #{column.caption}", :class => 'inline')
90 90 end
91 91 tags
92 92 end
93 93
94 94 def available_totalable_columns_tags(query)
95 95 tags = ''.html_safe
96 96 query.available_totalable_columns.each do |column|
97 97 tags << content_tag('label', check_box_tag('t[]', column.name.to_s, query.totalable_columns.include?(column), :id => nil) + " #{column.caption}", :class => 'inline')
98 98 end
99 99 tags << hidden_field_tag('t[]', '')
100 100 tags
101 101 end
102 102
103 103 def query_available_inline_columns_options(query)
104 104 (query.available_inline_columns - query.columns).reject(&:frozen?).collect {|column| [column.caption, column.name]}
105 105 end
106 106
107 107 def query_selected_inline_columns_options(query)
108 108 (query.inline_columns & query.available_inline_columns).reject(&:frozen?).collect {|column| [column.caption, column.name]}
109 109 end
110 110
111 111 def render_query_columns_selection(query, options={})
112 112 tag_name = (options[:name] || 'c') + '[]'
113 113 render :partial => 'queries/columns', :locals => {:query => query, :tag_name => tag_name}
114 114 end
115 115
116 116 def grouped_query_results(items, query, item_count_by_group, &block)
117 117 previous_group, first = false, true
118 118 totals_by_group = query.totalable_columns.inject({}) do |h, column|
119 119 h[column] = query.total_by_group_for(column)
120 120 h
121 121 end
122 122 items.each do |item|
123 123 group_name = group_count = nil
124 124 if query.grouped?
125 125 group = query.group_by_column.value(item)
126 126 if first || group != previous_group
127 127 if group.blank? && group != false
128 128 group_name = "(#{l(:label_blank_value)})"
129 129 else
130 130 group_name = format_object(group)
131 131 end
132 132 group_name ||= ""
133 133 group_count = item_count_by_group ? item_count_by_group[group] : nil
134 134 group_totals = totals_by_group.map {|column, t| total_tag(column, t[group] || 0)}.join(" ").html_safe
135 135 end
136 136 end
137 137 yield item, group_name, group_count, group_totals
138 138 previous_group, first = group, false
139 139 end
140 140 end
141 141
142 142 def render_query_totals(query)
143 143 return unless query.totalable_columns.present?
144 144 totals = query.totalable_columns.map do |column|
145 145 total_tag(column, query.total_for(column))
146 146 end
147 147 content_tag('p', totals.join(" ").html_safe, :class => "query-totals")
148 148 end
149 149
150 150 def total_tag(column, value)
151 151 label = content_tag('span', "#{column.caption}:")
152 152 value = content_tag('span', format_object(value), :class => 'value')
153 153 content_tag('span', label + " " + value, :class => "total-for-#{column.name.to_s.dasherize}")
154 154 end
155 155
156 156 def column_header(column)
157 157 column.sortable ? sort_header_tag(column.name.to_s, :caption => column.caption,
158 158 :default_order => column.default_order) :
159 159 content_tag('th', h(column.caption))
160 160 end
161 161
162 162 def column_content(column, issue)
163 163 value = column.value_object(issue)
164 164 if value.is_a?(Array)
165 165 value.collect {|v| column_value(column, issue, v)}.compact.join(', ').html_safe
166 166 else
167 167 column_value(column, issue, value)
168 168 end
169 169 end
170 170
171 171 def column_value(column, issue, value)
172 172 case column.name
173 173 when :id
174 174 link_to value, issue_path(issue)
175 175 when :subject
176 176 link_to value, issue_path(issue)
177 177 when :parent
178 178 value ? (value.visible? ? link_to_issue(value, :subject => false) : "##{value.id}") : ''
179 179 when :description
180 180 issue.description? ? content_tag('div', textilizable(issue, :description), :class => "wiki") : ''
181 181 when :done_ratio
182 182 progress_bar(value)
183 183 when :relations
184 184 content_tag('span',
185 185 value.to_s(issue) {|other| link_to_issue(other, :subject => false, :tracker => false)}.html_safe,
186 186 :class => value.css_classes_for(issue))
187 187 else
188 188 format_object(value)
189 189 end
190 190 end
191 191
192 192 def csv_content(column, issue)
193 193 value = column.value_object(issue)
194 194 if value.is_a?(Array)
195 195 value.collect {|v| csv_value(column, issue, v)}.compact.join(', ')
196 196 else
197 197 csv_value(column, issue, value)
198 198 end
199 199 end
200 200
201 201 def csv_value(column, object, value)
202 202 format_object(value, false) do |value|
203 203 case value.class.name
204 204 when 'Float'
205 205 sprintf("%.2f", value).gsub('.', l(:general_csv_decimal_separator))
206 206 when 'IssueRelation'
207 207 value.to_s(object)
208 208 when 'Issue'
209 209 if object.is_a?(TimeEntry)
210 210 "#{value.tracker} ##{value.id}: #{value.subject}"
211 211 else
212 212 value.id
213 213 end
214 214 else
215 215 value
216 216 end
217 217 end
218 218 end
219 219
220 220 def query_to_csv(items, query, options={})
221 221 options ||= {}
222 222 columns = (options[:columns] == 'all' ? query.available_inline_columns : query.inline_columns)
223 223 query.available_block_columns.each do |column|
224 224 if options[column.name].present?
225 225 columns << column
226 226 end
227 227 end
228 228
229 229 Redmine::Export::CSV.generate do |csv|
230 230 # csv header fields
231 231 csv << columns.map {|c| c.caption.to_s}
232 232 # csv lines
233 233 items.each do |item|
234 234 csv << columns.map {|c| csv_content(c, item)}
235 235 end
236 236 end
237 237 end
238 238
239 239 # Retrieve query from session or build a new query
240 240 def retrieve_query(klass=IssueQuery, use_session=true)
241 241 session_key = klass.name.underscore.to_sym
242 242
243 243 if params[:query_id].present?
244 244 cond = "project_id IS NULL"
245 245 cond << " OR project_id = #{@project.id}" if @project
246 246 @query = klass.where(cond).find(params[:query_id])
247 247 raise ::Unauthorized unless @query.visible?
248 248 @query.project = @project
249 249 session[session_key] = {:id => @query.id, :project_id => @query.project_id} if use_session
250 250 sort_clear
251 251 elsif api_request? || params[:set_filter] || !use_session || session[session_key].nil? || session[session_key][:project_id] != (@project ? @project.id : nil)
252 252 # Give it a name, required to be valid
253 253 @query = klass.new(:name => "_", :project => @project)
254 254 @query.build_from_params(params)
255 255 session[session_key] = {:project_id => @query.project_id, :filters => @query.filters, :group_by => @query.group_by, :column_names => @query.column_names, :totalable_names => @query.totalable_names} if use_session
256 256 else
257 257 # retrieve from session
258 258 @query = nil
259 259 @query = klass.find_by_id(session[session_key][:id]) if session[session_key][:id]
260 260 @query ||= klass.new(:name => "_", :filters => session[session_key][:filters], :group_by => session[session_key][:group_by], :column_names => session[session_key][:column_names], :totalable_names => session[session_key][:totalable_names])
261 261 @query.project = @project
262 262 end
263 263 end
264 264
265 def retrieve_query_from_session
266 if session[:query]
267 if session[:query][:id]
268 @query = IssueQuery.find_by_id(session[:query][:id])
265 def retrieve_query_from_session(klass=IssueQuery)
266 session_key = klass.name.underscore.to_sym
267 session_data = session[session_key]
268
269 if session_data
270 if session_data[:id]
271 @query = IssueQuery.find_by_id(session_data[:id])
269 272 return unless @query
270 273 else
271 @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])
274 @query = IssueQuery.new(:name => "_", :filters => session_data[:filters], :group_by => session_data[:group_by], :column_names => session_data[:column_names], :totalable_names => session_data[:totalable_names])
272 275 end
273 if session[:query].has_key?(:project_id)
274 @query.project_id = session[:query][:project_id]
276 if session_data.has_key?(:project_id)
277 @query.project_id = session_data[:project_id]
275 278 else
276 279 @query.project = @project
277 280 end
278 281 @query
279 282 end
280 283 end
281 284
282 285 # Returns the query definition as hidden field tags
283 286 def query_as_hidden_field_tags(query)
284 287 tags = hidden_field_tag("set_filter", "1", :id => nil)
285 288
286 289 if query.filters.present?
287 290 query.filters.each do |field, filter|
288 291 tags << hidden_field_tag("f[]", field, :id => nil)
289 292 tags << hidden_field_tag("op[#{field}]", filter[:operator], :id => nil)
290 293 filter[:values].each do |value|
291 294 tags << hidden_field_tag("v[#{field}][]", value, :id => nil)
292 295 end
293 296 end
294 297 else
295 298 tags << hidden_field_tag("f[]", "", :id => nil)
296 299 end
297 300 if query.column_names.present?
298 301 query.column_names.each do |name|
299 302 tags << hidden_field_tag("c[]", name, :id => nil)
300 303 end
301 304 end
302 305 if query.totalable_names.present?
303 306 query.totalable_names.each do |name|
304 307 tags << hidden_field_tag("t[]", name, :id => nil)
305 308 end
306 309 end
307 310 if query.group_by.present?
308 311 tags << hidden_field_tag("group_by", query.group_by, :id => nil)
309 312 end
310 313
311 314 tags
312 315 end
313 316
314 317 # Returns the queries that are rendered in the sidebar
315 318 def sidebar_queries(klass, project)
316 319 klass.visible.global_or_on_project(@project).sorted.to_a
317 320 end
318 321
319 322 # Renders a group of queries
320 323 def query_links(title, queries)
321 324 return '' if queries.empty?
322 325 # links to #index on issues/show
323 326 url_params = controller_name == 'issues' ? {:controller => 'issues', :action => 'index', :project_id => @project} : {}
324 327
325 328 content_tag('h3', title) + "\n" +
326 329 content_tag('ul',
327 330 queries.collect {|query|
328 331 css = 'query'
329 332 css << ' selected' if query == @query
330 333 content_tag('li', link_to(query.name, url_params.merge(:query_id => query), :class => css))
331 334 }.join("\n").html_safe,
332 335 :class => 'queries'
333 336 ) + "\n"
334 337 end
335 338
336 339 # Renders the list of queries for the sidebar
337 340 def render_sidebar_queries(klass, project)
338 341 queries = sidebar_queries(klass, project)
339 342
340 343 out = ''.html_safe
341 344 out << query_links(l(:label_my_queries), queries.select(&:is_private?))
342 345 out << query_links(l(:label_query_plural), queries.reject(&:is_private?))
343 346 out
344 347 end
345 348 end
@@ -1,242 +1,271
1 1 # Redmine - project management software
2 2 # Copyright (C) 2006-2016 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 IssuesTest < Redmine::IntegrationTest
21 21 fixtures :projects,
22 22 :users, :email_addresses,
23 23 :roles,
24 24 :members,
25 25 :member_roles,
26 26 :trackers,
27 27 :projects_trackers,
28 28 :enabled_modules,
29 29 :issue_statuses,
30 30 :issues,
31 31 :enumerations,
32 32 :custom_fields,
33 33 :custom_values,
34 34 :custom_fields_trackers,
35 35 :attachments
36 36
37 37 # create an issue
38 38 def test_add_issue
39 39 log_user('jsmith', 'jsmith')
40 40
41 41 get '/projects/ecookbook/issues/new'
42 42 assert_response :success
43 43
44 44 issue = new_record(Issue) do
45 45 post '/projects/ecookbook/issues',
46 46 :issue => { :tracker_id => "1",
47 47 :start_date => "2006-12-26",
48 48 :priority_id => "4",
49 49 :subject => "new test issue",
50 50 :category_id => "",
51 51 :description => "new issue",
52 52 :done_ratio => "0",
53 53 :due_date => "",
54 54 :assigned_to_id => "" },
55 55 :custom_fields => {'2' => 'Value for field 2'}
56 56 end
57 57 # check redirection
58 58 assert_redirected_to :controller => 'issues', :action => 'show', :id => issue
59 59 follow_redirect!
60 60
61 61 # check issue attributes
62 62 assert_equal 'jsmith', issue.author.login
63 63 assert_equal 1, issue.project.id
64 64 assert_equal 1, issue.status.id
65 65 end
66 66
67 67 def test_create_issue_by_anonymous_without_permission_should_fail
68 68 Role.anonymous.remove_permission! :add_issues
69 69
70 70 assert_no_difference 'Issue.count' do
71 71 post '/projects/1/issues', :tracker_id => "1", :issue => {:subject => "new test issue"}
72 72 end
73 73 assert_response 302
74 74 end
75 75
76 76 def test_create_issue_by_anonymous_with_custom_permission_should_succeed
77 77 Role.anonymous.remove_permission! :add_issues
78 78 Member.create!(:project_id => 1, :principal => Group.anonymous, :role_ids => [3])
79 79
80 80 issue = new_record(Issue) do
81 81 post '/projects/1/issues', :tracker_id => "1", :issue => {:subject => "new test issue"}
82 82 assert_response 302
83 83 end
84 84 assert_equal User.anonymous, issue.author
85 85 end
86 86
87 87 # add then remove 2 attachments to an issue
88 88 def test_issue_attachments
89 89 log_user('jsmith', 'jsmith')
90 90 set_tmp_attachments_directory
91 91
92 92 attachment = new_record(Attachment) do
93 93 put '/issues/1',
94 94 :notes => 'Some notes',
95 95 :attachments => {'1' => {'file' => uploaded_test_file('testfile.txt', 'text/plain'), 'description' => 'This is an attachment'}}
96 96 assert_redirected_to "/issues/1"
97 97 end
98 98
99 99 assert_equal Issue.find(1), attachment.container
100 100 assert_equal 'testfile.txt', attachment.filename
101 101 assert_equal 'This is an attachment', attachment.description
102 102 # verify the size of the attachment stored in db
103 103 #assert_equal file_data_1.length, attachment.filesize
104 104 # verify that the attachment was written to disk
105 105 assert File.exist?(attachment.diskfile)
106 106
107 107 # remove the attachments
108 108 Issue.find(1).attachments.each(&:destroy)
109 109 assert_equal 0, Issue.find(1).attachments.length
110 110 end
111 111
112 def test_next_and_previous_links_should_be_displayed_after_filter
113 with_settings :default_language => 'en' do
114 get '/projects/ecookbook/issues?set_filter=1&tracker_id=1'
115 assert_response :success
116 assert_select 'td.id', :text => '5'
117
118 get '/issues/5'
119 assert_response :success
120 assert_select '.next-prev-links .position', :text => '3 of 5'
121 end
122 end
123
124 def test_next_and_previous_links_should_be_displayed_after_saved_query
125 query = IssueQuery.create!(:name => 'Calendar Query',
126 :visibility => IssueQuery::VISIBILITY_PUBLIC,
127 :filters => {'tracker_id' => {:operator => '=', :values => ['1']}}
128 )
129
130 with_settings :default_language => 'en' do
131 get "/projects/ecookbook/issues?set_filter=1&query_id=#{query.id}"
132 assert_response :success
133 assert_select 'td.id', :text => '5'
134
135 get '/issues/5'
136 assert_response :success
137 assert_select '.next-prev-links .position', :text => '6 of 8'
138 end
139 end
140
112 141 def test_other_formats_links_on_index
113 142 get '/projects/ecookbook/issues'
114 143
115 144 %w(Atom PDF CSV).each do |format|
116 145 assert_select 'a[rel=nofollow][href=?]', "/projects/ecookbook/issues.#{format.downcase}", :text => format
117 146 end
118 147 end
119 148
120 149 def test_other_formats_links_on_index_without_project_id_in_url
121 150 get '/issues', :project_id => 'ecookbook'
122 151
123 152 %w(Atom PDF CSV).each do |format|
124 153 assert_select 'a[rel=nofollow][href=?]', "/issues.#{format.downcase}?project_id=ecookbook", :text => format
125 154 end
126 155 end
127 156
128 157 def test_pagination_links_on_index
129 158 with_settings :per_page_options => '2' do
130 159 get '/projects/ecookbook/issues'
131 160
132 161 assert_select 'a[href=?]', '/projects/ecookbook/issues?page=2', :text => '2'
133 162 end
134 163 end
135 164
136 165 def test_pagination_links_should_preserve_query_parameters
137 166 with_settings :per_page_options => '2' do
138 167 get '/projects/ecookbook/issues?foo=bar'
139 168
140 169 assert_select 'a[href=?]', '/projects/ecookbook/issues?foo=bar&page=2', :text => '2'
141 170 end
142 171 end
143 172
144 173 def test_pagination_links_should_not_use_params_as_url_options
145 174 with_settings :per_page_options => '2' do
146 175 get '/projects/ecookbook/issues?host=foo'
147 176
148 177 assert_select 'a[href=?]', '/projects/ecookbook/issues?host=foo&page=2', :text => '2'
149 178 end
150 179 end
151 180
152 181 def test_sort_links_on_index
153 182 get '/projects/ecookbook/issues'
154 183
155 184 assert_select 'a[href=?]', '/projects/ecookbook/issues?sort=subject%2Cid%3Adesc', :text => 'Subject'
156 185 end
157 186
158 187 def test_sort_links_should_preserve_query_parameters
159 188 get '/projects/ecookbook/issues?foo=bar'
160 189
161 190 assert_select 'a[href=?]', '/projects/ecookbook/issues?foo=bar&sort=subject%2Cid%3Adesc', :text => 'Subject'
162 191 end
163 192
164 193 def test_sort_links_should_not_use_params_as_url_options
165 194 get '/projects/ecookbook/issues?host=foo'
166 195
167 196 assert_select 'a[href=?]', '/projects/ecookbook/issues?host=foo&sort=subject%2Cid%3Adesc', :text => 'Subject'
168 197 end
169 198
170 199 def test_issue_with_user_custom_field
171 200 @field = IssueCustomField.create!(:name => 'Tester', :field_format => 'user', :is_for_all => true, :trackers => Tracker.all)
172 201 Role.anonymous.add_permission! :add_issues, :edit_issues
173 202 users = Project.find(1).users.sort
174 203 tester = users.first
175 204
176 205 # Issue form
177 206 get '/projects/ecookbook/issues/new'
178 207 assert_response :success
179 208 assert_select 'select[name=?]', "issue[custom_field_values][#{@field.id}]" do
180 209 assert_select 'option', users.size + 1 # +1 for blank value
181 210 assert_select 'option[value=?]', tester.id.to_s, :text => tester.name
182 211 end
183 212
184 213 # Create issue
185 214 issue = new_record(Issue) do
186 215 post '/projects/ecookbook/issues',
187 216 :issue => {
188 217 :tracker_id => '1',
189 218 :priority_id => '4',
190 219 :subject => 'Issue with user custom field',
191 220 :custom_field_values => {@field.id.to_s => users.first.id.to_s}
192 221 }
193 222 assert_response 302
194 223 end
195 224
196 225 # Issue view
197 226 follow_redirect!
198 227 assert_select ".cf_#{@field.id}" do
199 228 assert_select '.label', :text => 'Tester:'
200 229 assert_select '.value', :text => tester.name
201 230 end
202 231 assert_select 'select[name=?]', "issue[custom_field_values][#{@field.id}]" do
203 232 assert_select 'option', users.size + 1 # +1 for blank value
204 233 assert_select 'option[value=?][selected=selected]', tester.id.to_s, :text => tester.name
205 234 end
206 235
207 236 new_tester = users[1]
208 237 with_settings :default_language => 'en' do
209 238 # Update issue
210 239 assert_difference 'Journal.count' do
211 240 put "/issues/#{issue.id}",
212 241 :notes => 'Updating custom field',
213 242 :issue => {
214 243 :custom_field_values => {@field.id.to_s => new_tester.id.to_s}
215 244 }
216 245 assert_redirected_to "/issues/#{issue.id}"
217 246 end
218 247 # Issue view
219 248 follow_redirect!
220 249 assert_select 'ul.details li', :text => "Tester changed from #{tester} to #{new_tester}"
221 250 end
222 251 end
223 252
224 253 def test_update_using_invalid_http_verbs
225 254 subject = 'Updated by an invalid http verb'
226 255
227 256 get '/issues/update/1', {:issue => {:subject => subject}}, credentials('jsmith')
228 257 assert_response 404
229 258 assert_not_equal subject, Issue.find(1).subject
230 259
231 260 post '/issues/1', {:issue => {:subject => subject}}, credentials('jsmith')
232 261 assert_response 404
233 262 assert_not_equal subject, Issue.find(1).subject
234 263 end
235 264
236 265 def test_get_watch_should_be_invalid
237 266 assert_no_difference 'Watcher.count' do
238 267 get '/watchers/watch?object_type=issue&object_id=1', {}, credentials('jsmith')
239 268 assert_response 404
240 269 end
241 270 end
242 271 end
General Comments 0
You need to be logged in to leave comments. Login now