##// END OF EJS Templates
Pass parameters with :params in controller tests....
Jean-Philippe Lang -
r15284:6cc6a918b4f3
parent child
Show More
@@ -1,224 +1,244
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2016 Jean-Philippe Lang
2 # Copyright (C) 2006-2016 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 require File.expand_path('../../test_helper', __FILE__)
18 require File.expand_path('../../test_helper', __FILE__)
19
19
20 class RolesControllerTest < Redmine::ControllerTest
20 class RolesControllerTest < Redmine::ControllerTest
21 fixtures :roles, :users, :members, :member_roles, :workflows, :trackers
21 fixtures :roles, :users, :members, :member_roles, :workflows, :trackers
22
22
23 def setup
23 def setup
24 User.current = nil
24 User.current = nil
25 @request.session[:user_id] = 1 # admin
25 @request.session[:user_id] = 1 # admin
26 end
26 end
27
27
28 def test_index
28 def test_index
29 get :index
29 get :index
30 assert_response :success
30 assert_response :success
31 assert_template 'index'
31 assert_template 'index'
32
32
33 assert_not_nil assigns(:roles)
33 assert_not_nil assigns(:roles)
34 assert_equal Role.order('builtin, position').to_a, assigns(:roles)
34 assert_equal Role.order('builtin, position').to_a, assigns(:roles)
35
35
36 assert_select 'a[href="/roles/1/edit"]', :text => 'Manager'
36 assert_select 'a[href="/roles/1/edit"]', :text => 'Manager'
37 end
37 end
38
38
39 def test_new
39 def test_new
40 get :new
40 get :new
41 assert_response :success
41 assert_response :success
42 assert_template 'new'
42 assert_template 'new'
43 end
43 end
44
44
45 def test_new_with_copy
45 def test_new_with_copy
46 copy_from = Role.find(2)
46 copy_from = Role.find(2)
47
47
48 get :new, :copy => copy_from.id.to_s
48 get :new, :params => {:copy => copy_from.id.to_s}
49 assert_response :success
49 assert_response :success
50 assert_template 'new'
50 assert_template 'new'
51
51
52 role = assigns(:role)
52 role = assigns(:role)
53 assert_equal copy_from.permissions, role.permissions
53 assert_equal copy_from.permissions, role.permissions
54
54
55 assert_select 'form' do
55 assert_select 'form' do
56 # blank name
56 # blank name
57 assert_select 'input[name=?][value=""]', 'role[name]'
57 assert_select 'input[name=?][value=""]', 'role[name]'
58 # edit_project permission checked
58 # edit_project permission checked
59 assert_select 'input[type=checkbox][name=?][value=edit_project][checked=checked]', 'role[permissions][]'
59 assert_select 'input[type=checkbox][name=?][value=edit_project][checked=checked]', 'role[permissions][]'
60 # add_project permission not checked
60 # add_project permission not checked
61 assert_select 'input[type=checkbox][name=?][value=add_project]', 'role[permissions][]'
61 assert_select 'input[type=checkbox][name=?][value=add_project]', 'role[permissions][]'
62 assert_select 'input[type=checkbox][name=?][value=add_project][checked=checked]', 'role[permissions][]', 0
62 assert_select 'input[type=checkbox][name=?][value=add_project][checked=checked]', 'role[permissions][]', 0
63 # workflow copy selected
63 # workflow copy selected
64 assert_select 'select[name=?]', 'copy_workflow_from' do
64 assert_select 'select[name=?]', 'copy_workflow_from' do
65 assert_select 'option[value="2"][selected=selected]'
65 assert_select 'option[value="2"][selected=selected]'
66 end
66 end
67 end
67 end
68 end
68 end
69
69
70 def test_create_with_validaton_failure
70 def test_create_with_validaton_failure
71 post :create, :role => {:name => '',
71 post :create, :params => {
72 :permissions => ['add_issues', 'edit_issues', 'log_time', ''],
72 :role => {
73 :assignable => '0'}
73 :name => '',
74
74 :permissions => ['add_issues', 'edit_issues', 'log_time', ''],
75 :assignable => '0'
76 }
77 }
75 assert_response :success
78 assert_response :success
76 assert_template 'new'
79 assert_template 'new'
77 assert_select 'div#errorExplanation'
80 assert_select 'div#errorExplanation'
78 end
81 end
79
82
80 def test_create_without_workflow_copy
83 def test_create_without_workflow_copy
81 post :create, :role => {:name => 'RoleWithoutWorkflowCopy',
84 post :create, :params => {
82 :permissions => ['add_issues', 'edit_issues', 'log_time', ''],
85 :role => {
83 :assignable => '0'}
86 :name => 'RoleWithoutWorkflowCopy',
84
87 :permissions => ['add_issues', 'edit_issues', 'log_time', ''],
88 :assignable => '0'
89 }
90 }
85 assert_redirected_to '/roles'
91 assert_redirected_to '/roles'
86 role = Role.find_by_name('RoleWithoutWorkflowCopy')
92 role = Role.find_by_name('RoleWithoutWorkflowCopy')
87 assert_not_nil role
93 assert_not_nil role
88 assert_equal [:add_issues, :edit_issues, :log_time], role.permissions
94 assert_equal [:add_issues, :edit_issues, :log_time], role.permissions
89 assert !role.assignable?
95 assert !role.assignable?
90 end
96 end
91
97
92 def test_create_with_workflow_copy
98 def test_create_with_workflow_copy
93 post :create, :role => {:name => 'RoleWithWorkflowCopy',
99 post :create, :params => {
94 :permissions => ['add_issues', 'edit_issues', 'log_time', ''],
100 :role => {
95 :assignable => '0'},
101 :name => 'RoleWithWorkflowCopy',
96 :copy_workflow_from => '1'
102 :permissions => ['add_issues', 'edit_issues', 'log_time', ''],
97
103 :assignable => '0'
104 },
105 :copy_workflow_from => '1'
106 }
98 assert_redirected_to '/roles'
107 assert_redirected_to '/roles'
99 role = Role.find_by_name('RoleWithWorkflowCopy')
108 role = Role.find_by_name('RoleWithWorkflowCopy')
100 assert_not_nil role
109 assert_not_nil role
101 assert_equal Role.find(1).workflow_rules.size, role.workflow_rules.size
110 assert_equal Role.find(1).workflow_rules.size, role.workflow_rules.size
102 end
111 end
103
112
104 def test_edit
113 def test_edit
105 get :edit, :id => 1
114 get :edit, :params => {:id => 1}
106 assert_response :success
115 assert_response :success
107 assert_template 'edit'
116 assert_template 'edit'
108 assert_equal Role.find(1), assigns(:role)
117 assert_equal Role.find(1), assigns(:role)
109 assert_select 'select[name=?]', 'role[issues_visibility]'
118 assert_select 'select[name=?]', 'role[issues_visibility]'
110 end
119 end
111
120
112 def test_edit_anonymous
121 def test_edit_anonymous
113 get :edit, :id => Role.anonymous.id
122 get :edit, :params => {:id => Role.anonymous.id}
114 assert_response :success
123 assert_response :success
115 assert_template 'edit'
124 assert_template 'edit'
116 assert_select 'select[name=?]', 'role[issues_visibility]', 0
125 assert_select 'select[name=?]', 'role[issues_visibility]', 0
117 end
126 end
118
127
119 def test_edit_invalid_should_respond_with_404
128 def test_edit_invalid_should_respond_with_404
120 get :edit, :id => 999
129 get :edit, :params => {:id => 999}
121 assert_response 404
130 assert_response 404
122 end
131 end
123
132
124 def test_update
133 def test_update
125 put :update, :id => 1,
134 put :update, :params => {
126 :role => {:name => 'Manager',
135 :id => 1,
127 :permissions => ['edit_project', ''],
136 :role => {
128 :assignable => '0'}
137 :name => 'Manager',
129
138 :permissions => ['edit_project', ''],
139 :assignable => '0'
140 }
141 }
130 assert_redirected_to '/roles'
142 assert_redirected_to '/roles'
131 role = Role.find(1)
143 role = Role.find(1)
132 assert_equal [:edit_project], role.permissions
144 assert_equal [:edit_project], role.permissions
133 end
145 end
134
146
135 def test_update_trackers_permissions
147 def test_update_trackers_permissions
136 put :update, :id => 1, :role => {
148 put :update, :params => {
137 :permissions_all_trackers => {'add_issues' => '0'},
149 :id => 1,
138 :permissions_tracker_ids => {'add_issues' => ['1', '3', '']}
150 :role => {
151 :permissions_all_trackers => {'add_issues' => '0'},
152 :permissions_tracker_ids => {'add_issues' => ['1', '3', '']}
153 }
139 }
154 }
140
141 assert_redirected_to '/roles'
155 assert_redirected_to '/roles'
142 role = Role.find(1)
156 role = Role.find(1)
143
157
144 assert_equal({'add_issues' => '0'}, role.permissions_all_trackers)
158 assert_equal({'add_issues' => '0'}, role.permissions_all_trackers)
145 assert_equal({'add_issues' => ['1', '3']}, role.permissions_tracker_ids)
159 assert_equal({'add_issues' => ['1', '3']}, role.permissions_tracker_ids)
146
160
147 assert_equal false, role.permissions_all_trackers?(:add_issues)
161 assert_equal false, role.permissions_all_trackers?(:add_issues)
148 assert_equal [1, 3], role.permissions_tracker_ids(:add_issues).sort
162 assert_equal [1, 3], role.permissions_tracker_ids(:add_issues).sort
149 end
163 end
150
164
151 def test_update_with_failure
165 def test_update_with_failure
152 put :update, :id => 1, :role => {:name => ''}
166 put :update, :params => {:id => 1, :role => {:name => ''}}
153 assert_response :success
167 assert_response :success
154 assert_template 'edit'
168 assert_template 'edit'
155 end
169 end
156
170
157 def test_destroy
171 def test_destroy
158 r = Role.create!(:name => 'ToBeDestroyed', :permissions => [:view_wiki_pages])
172 r = Role.create!(:name => 'ToBeDestroyed', :permissions => [:view_wiki_pages])
159
173
160 delete :destroy, :id => r
174 delete :destroy, :params => {:id => r}
161 assert_redirected_to '/roles'
175 assert_redirected_to '/roles'
162 assert_nil Role.find_by_id(r.id)
176 assert_nil Role.find_by_id(r.id)
163 end
177 end
164
178
165 def test_destroy_role_in_use
179 def test_destroy_role_in_use
166 delete :destroy, :id => 1
180 delete :destroy, :params => {:id => 1}
167 assert_redirected_to '/roles'
181 assert_redirected_to '/roles'
168 assert_equal 'This role is in use and cannot be deleted.', flash[:error]
182 assert_equal 'This role is in use and cannot be deleted.', flash[:error]
169 assert_not_nil Role.find_by_id(1)
183 assert_not_nil Role.find_by_id(1)
170 end
184 end
171
185
172 def test_get_permissions
186 def test_get_permissions
173 get :permissions
187 get :permissions
174 assert_response :success
188 assert_response :success
175 assert_template 'permissions'
189 assert_template 'permissions'
176
190
177 assert_not_nil assigns(:roles)
191 assert_not_nil assigns(:roles)
178 assert_equal Role.order('builtin, position').to_a, assigns(:roles)
192 assert_equal Role.order('builtin, position').to_a, assigns(:roles)
179
193
180 assert_select 'input[name=?][type=checkbox][value=add_issues][checked=checked]', 'permissions[3][]'
194 assert_select 'input[name=?][type=checkbox][value=add_issues][checked=checked]', 'permissions[3][]'
181 assert_select 'input[name=?][type=checkbox][value=delete_issues]:not([checked])', 'permissions[3][]'
195 assert_select 'input[name=?][type=checkbox][value=delete_issues]:not([checked])', 'permissions[3][]'
182 end
196 end
183
197
184 def test_post_permissions
198 def test_post_permissions
185 post :permissions, :permissions => { '0' => '', '1' => ['edit_issues'], '3' => ['add_issues', 'delete_issues']}
199 post :permissions, :params => {
200 :permissions => {
201 '0' => '',
202 '1' => ['edit_issues'],
203 '3' => ['add_issues', 'delete_issues']
204 }
205 }
186 assert_redirected_to '/roles'
206 assert_redirected_to '/roles'
187
207
188 assert_equal [:edit_issues], Role.find(1).permissions
208 assert_equal [:edit_issues], Role.find(1).permissions
189 assert_equal [:add_issues, :delete_issues], Role.find(3).permissions
209 assert_equal [:add_issues, :delete_issues], Role.find(3).permissions
190 assert Role.find(2).permissions.empty?
210 assert Role.find(2).permissions.empty?
191 end
211 end
192
212
193 def test_clear_all_permissions
213 def test_clear_all_permissions
194 post :permissions, :permissions => { '0' => '' }
214 post :permissions, :params => {:permissions => { '0' => '' }}
195 assert_redirected_to '/roles'
215 assert_redirected_to '/roles'
196 assert Role.find(1).permissions.empty?
216 assert Role.find(1).permissions.empty?
197 end
217 end
198
218
199 def test_move_highest
219 def test_move_highest
200 put :update, :id => 3, :role => {:position => 1}
220 put :update, :params => {:id => 3, :role => {:position => 1}}
201 assert_redirected_to '/roles'
221 assert_redirected_to '/roles'
202 assert_equal 1, Role.find(3).position
222 assert_equal 1, Role.find(3).position
203 end
223 end
204
224
205 def test_move_higher
225 def test_move_higher
206 position = Role.find(3).position
226 position = Role.find(3).position
207 put :update, :id => 3, :role => {:position => position - 1}
227 put :update, :params => {:id => 3, :role => {:position => position - 1}}
208 assert_redirected_to '/roles'
228 assert_redirected_to '/roles'
209 assert_equal position - 1, Role.find(3).position
229 assert_equal position - 1, Role.find(3).position
210 end
230 end
211
231
212 def test_move_lower
232 def test_move_lower
213 position = Role.find(2).position
233 position = Role.find(2).position
214 put :update, :id => 2, :role => {:position => position + 1}
234 put :update, :params => {:id => 2, :role => {:position => position + 1}}
215 assert_redirected_to '/roles'
235 assert_redirected_to '/roles'
216 assert_equal position + 1, Role.find(2).position
236 assert_equal position + 1, Role.find(2).position
217 end
237 end
218
238
219 def test_move_lowest
239 def test_move_lowest
220 put :update, :id => 2, :role => {:position => Role.givable.count}
240 put :update, :params => {:id => 2, :role => {:position => Role.givable.count}}
221 assert_redirected_to '/roles'
241 assert_redirected_to '/roles'
222 assert_equal Role.givable.count, Role.find(2).position
242 assert_equal Role.givable.count, Role.find(2).position
223 end
243 end
224 end
244 end
@@ -1,332 +1,333
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2016 Jean-Philippe Lang
2 # Copyright (C) 2006-2016 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 require File.expand_path('../../test_helper', __FILE__)
18 require File.expand_path('../../test_helper', __FILE__)
19
19
20 class SearchControllerTest < Redmine::ControllerTest
20 class SearchControllerTest < Redmine::ControllerTest
21 fixtures :projects, :projects_trackers,
21 fixtures :projects, :projects_trackers,
22 :enabled_modules, :roles, :users, :members, :member_roles,
22 :enabled_modules, :roles, :users, :members, :member_roles,
23 :issues, :trackers, :issue_statuses, :enumerations,
23 :issues, :trackers, :issue_statuses, :enumerations,
24 :workflows,
24 :workflows,
25 :custom_fields, :custom_values,
25 :custom_fields, :custom_values,
26 :custom_fields_projects, :custom_fields_trackers,
26 :custom_fields_projects, :custom_fields_trackers,
27 :repositories, :changesets
27 :repositories, :changesets
28
28
29 def setup
29 def setup
30 User.current = nil
30 User.current = nil
31 end
31 end
32
32
33 def test_search_for_projects
33 def test_search_for_projects
34 get :index
34 get :index
35 assert_response :success
35 assert_response :success
36 assert_template 'index'
36 assert_template 'index'
37
37
38 get :index, :q => "cook"
38 get :index, :params => {:q => "cook"}
39 assert_response :success
39 assert_response :success
40 assert_template 'index'
40 assert_template 'index'
41 assert assigns(:results).include?(Project.find(1))
41 assert assigns(:results).include?(Project.find(1))
42 end
42 end
43
43
44 def test_search_on_archived_project_should_return_404
44 def test_search_on_archived_project_should_return_404
45 Project.find(3).archive
45 Project.find(3).archive
46 get :index, :id => 3
46 get :index, :params => {:id => 3}
47 assert_response 404
47 assert_response 404
48 end
48 end
49
49
50 def test_search_on_invisible_project_by_user_should_be_denied
50 def test_search_on_invisible_project_by_user_should_be_denied
51 @request.session[:user_id] = 7
51 @request.session[:user_id] = 7
52 get :index, :id => 2
52 get :index, :params => {:id => 2}
53 assert_response 403
53 assert_response 403
54 end
54 end
55
55
56 def test_search_on_invisible_project_by_anonymous_user_should_redirect
56 def test_search_on_invisible_project_by_anonymous_user_should_redirect
57 get :index, :id => 2
57 get :index, :params => {:id => 2}
58 assert_response 302
58 assert_response 302
59 end
59 end
60
60
61 def test_search_on_private_project_by_member_should_succeed
61 def test_search_on_private_project_by_member_should_succeed
62 @request.session[:user_id] = 2
62 @request.session[:user_id] = 2
63 get :index, :id => 2
63 get :index, :params => {:id => 2}
64 assert_response :success
64 assert_response :success
65 end
65 end
66
66
67 def test_search_all_projects
67 def test_search_all_projects
68 with_settings :default_language => 'en' do
68 with_settings :default_language => 'en' do
69 get :index, :q => 'recipe subproject commit', :all_words => ''
69 get :index, :params => {:q => 'recipe subproject commit', :all_words => ''}
70 end
70 end
71 assert_response :success
71 assert_response :success
72 assert_template 'index'
72 assert_template 'index'
73
73
74 assert assigns(:results).include?(Issue.find(2))
74 assert assigns(:results).include?(Issue.find(2))
75 assert assigns(:results).include?(Issue.find(5))
75 assert assigns(:results).include?(Issue.find(5))
76 assert assigns(:results).include?(Changeset.find(101))
76 assert assigns(:results).include?(Changeset.find(101))
77 assert_select 'dt.issue a', :text => /Add ingredients categories/
77 assert_select 'dt.issue a', :text => /Add ingredients categories/
78 assert_select 'dd', :text => /should be classified by categories/
78 assert_select 'dd', :text => /should be classified by categories/
79
79
80 assert assigns(:result_count_by_type).is_a?(Hash)
80 assert assigns(:result_count_by_type).is_a?(Hash)
81 assert_equal 5, assigns(:result_count_by_type)['changesets']
81 assert_equal 5, assigns(:result_count_by_type)['changesets']
82 assert_select 'a', :text => 'Changesets (5)'
82 assert_select 'a', :text => 'Changesets (5)'
83 end
83 end
84
84
85 def test_search_issues
85 def test_search_issues
86 get :index, :q => 'issue', :issues => 1
86 get :index, :params => {:q => 'issue', :issues => 1}
87 assert_response :success
87 assert_response :success
88 assert_template 'index'
88 assert_template 'index'
89
89
90 assert_equal true, assigns(:all_words)
90 assert_equal true, assigns(:all_words)
91 assert_equal false, assigns(:titles_only)
91 assert_equal false, assigns(:titles_only)
92 assert assigns(:results).include?(Issue.find(8))
92 assert assigns(:results).include?(Issue.find(8))
93 assert assigns(:results).include?(Issue.find(5))
93 assert assigns(:results).include?(Issue.find(5))
94 assert_select 'dt.issue.closed a', :text => /Closed/
94 assert_select 'dt.issue.closed a', :text => /Closed/
95 end
95 end
96
96
97 def test_search_issues_should_search_notes
97 def test_search_issues_should_search_notes
98 Journal.create!(:journalized => Issue.find(2), :notes => 'Issue notes with searchkeyword')
98 Journal.create!(:journalized => Issue.find(2), :notes => 'Issue notes with searchkeyword')
99
99
100 get :index, :q => 'searchkeyword', :issues => 1
100 get :index, :params => {:q => 'searchkeyword', :issues => 1}
101 assert_response :success
101 assert_response :success
102 assert_include Issue.find(2), assigns(:results)
102 assert_include Issue.find(2), assigns(:results)
103 end
103 end
104
104
105 def test_search_issues_with_multiple_matches_in_journals_should_return_issue_once
105 def test_search_issues_with_multiple_matches_in_journals_should_return_issue_once
106 Journal.create!(:journalized => Issue.find(2), :notes => 'Issue notes with searchkeyword')
106 Journal.create!(:journalized => Issue.find(2), :notes => 'Issue notes with searchkeyword')
107 Journal.create!(:journalized => Issue.find(2), :notes => 'Issue notes with searchkeyword')
107 Journal.create!(:journalized => Issue.find(2), :notes => 'Issue notes with searchkeyword')
108
108
109 get :index, :q => 'searchkeyword', :issues => 1
109 get :index, :params => {:q => 'searchkeyword', :issues => 1}
110 assert_response :success
110 assert_response :success
111 assert_include Issue.find(2), assigns(:results)
111 assert_include Issue.find(2), assigns(:results)
112 assert_equal 1, assigns(:results).size
112 assert_equal 1, assigns(:results).size
113 end
113 end
114
114
115 def test_search_issues_should_search_private_notes_with_permission_only
115 def test_search_issues_should_search_private_notes_with_permission_only
116 Journal.create!(:journalized => Issue.find(2), :notes => 'Private notes with searchkeyword', :private_notes => true)
116 Journal.create!(:journalized => Issue.find(2), :notes => 'Private notes with searchkeyword', :private_notes => true)
117 @request.session[:user_id] = 2
117 @request.session[:user_id] = 2
118
118
119 Role.find(1).add_permission! :view_private_notes
119 Role.find(1).add_permission! :view_private_notes
120 get :index, :q => 'searchkeyword', :issues => 1
120 get :index, :params => {:q => 'searchkeyword', :issues => 1}
121 assert_response :success
121 assert_response :success
122 assert_include Issue.find(2), assigns(:results)
122 assert_include Issue.find(2), assigns(:results)
123
123
124 Role.find(1).remove_permission! :view_private_notes
124 Role.find(1).remove_permission! :view_private_notes
125 get :index, :q => 'searchkeyword', :issues => 1
125 get :index, :params => {:q => 'searchkeyword', :issues => 1}
126 assert_response :success
126 assert_response :success
127 assert_not_include Issue.find(2), assigns(:results)
127 assert_not_include Issue.find(2), assigns(:results)
128 end
128 end
129
129
130 def test_search_all_projects_with_scope_param
130 def test_search_all_projects_with_scope_param
131 get :index, :q => 'issue', :scope => 'all'
131 get :index, :params => {:q => 'issue', :scope => 'all'}
132 assert_response :success
132 assert_response :success
133 assert_template 'index'
133 assert_template 'index'
134 assert assigns(:results).present?
134 assert assigns(:results).present?
135 end
135 end
136
136
137 def test_search_my_projects
137 def test_search_my_projects
138 @request.session[:user_id] = 2
138 @request.session[:user_id] = 2
139 get :index, :id => 1, :q => 'recipe subproject', :scope => 'my_projects', :all_words => ''
139 get :index, :params => {:id => 1, :q => 'recipe subproject', :scope => 'my_projects', :all_words => ''}
140 assert_response :success
140 assert_response :success
141 assert_template 'index'
141 assert_template 'index'
142 assert assigns(:results).include?(Issue.find(1))
142 assert assigns(:results).include?(Issue.find(1))
143 assert !assigns(:results).include?(Issue.find(5))
143 assert !assigns(:results).include?(Issue.find(5))
144 end
144 end
145
145
146 def test_search_my_projects_without_memberships
146 def test_search_my_projects_without_memberships
147 # anonymous user has no memberships
147 # anonymous user has no memberships
148 get :index, :id => 1, :q => 'recipe subproject', :scope => 'my_projects', :all_words => ''
148 get :index, :params => {:id => 1, :q => 'recipe subproject', :scope => 'my_projects', :all_words => ''}
149 assert_response :success
149 assert_response :success
150 assert_template 'index'
150 assert_template 'index'
151 assert assigns(:results).empty?
151 assert assigns(:results).empty?
152 end
152 end
153
153
154 def test_search_project_and_subprojects
154 def test_search_project_and_subprojects
155 get :index, :id => 1, :q => 'recipe subproject', :scope => 'subprojects', :all_words => ''
155 get :index, :params => {:id => 1, :q => 'recipe subproject', :scope => 'subprojects', :all_words => ''}
156 assert_response :success
156 assert_response :success
157 assert_template 'index'
157 assert_template 'index'
158 assert assigns(:results).include?(Issue.find(1))
158 assert assigns(:results).include?(Issue.find(1))
159 assert assigns(:results).include?(Issue.find(5))
159 assert assigns(:results).include?(Issue.find(5))
160 end
160 end
161
161
162 def test_search_without_searchable_custom_fields
162 def test_search_without_searchable_custom_fields
163 CustomField.update_all "searchable = #{ActiveRecord::Base.connection.quoted_false}"
163 CustomField.update_all "searchable = #{ActiveRecord::Base.connection.quoted_false}"
164
164
165 get :index, :id => 1
165 get :index, :params => {:id => 1}
166 assert_response :success
166 assert_response :success
167 assert_template 'index'
167 assert_template 'index'
168 assert_not_nil assigns(:project)
168 assert_not_nil assigns(:project)
169
169
170 get :index, :id => 1, :q => "can"
170 get :index, :params => {:id => 1, :q => "can"}
171 assert_response :success
171 assert_response :success
172 assert_template 'index'
172 assert_template 'index'
173 end
173 end
174
174
175 def test_search_with_searchable_custom_fields
175 def test_search_with_searchable_custom_fields
176 get :index, :id => 1, :q => "stringforcustomfield"
176 get :index, :params => {:id => 1, :q => "stringforcustomfield"}
177 assert_response :success
177 assert_response :success
178 results = assigns(:results)
178 results = assigns(:results)
179 assert_not_nil results
179 assert_not_nil results
180 assert_equal 1, results.size
180 assert_equal 1, results.size
181 assert results.include?(Issue.find(7))
181 assert results.include?(Issue.find(7))
182 end
182 end
183
183
184 def test_search_without_attachments
184 def test_search_without_attachments
185 issue = Issue.generate! :subject => 'search_attachments'
185 issue = Issue.generate! :subject => 'search_attachments'
186 attachment = Attachment.generate! :container => Issue.find(1), :filename => 'search_attachments.patch'
186 attachment = Attachment.generate! :container => Issue.find(1), :filename => 'search_attachments.patch'
187
187
188 get :index, :id => 1, :q => 'search_attachments', :attachments => '0'
188 get :index, :params => {:id => 1, :q => 'search_attachments', :attachments => '0'}
189 results = assigns(:results)
189 results = assigns(:results)
190 assert_equal 1, results.size
190 assert_equal 1, results.size
191 assert_equal issue, results.first
191 assert_equal issue, results.first
192 end
192 end
193
193
194 def test_search_attachments_only
194 def test_search_attachments_only
195 issue = Issue.generate! :subject => 'search_attachments'
195 issue = Issue.generate! :subject => 'search_attachments'
196 attachment = Attachment.generate! :container => Issue.find(1), :filename => 'search_attachments.patch'
196 attachment = Attachment.generate! :container => Issue.find(1), :filename => 'search_attachments.patch'
197
197
198 get :index, :id => 1, :q => 'search_attachments', :attachments => 'only'
198 get :index, :params => {:id => 1, :q => 'search_attachments', :attachments => 'only'}
199 results = assigns(:results)
199 results = assigns(:results)
200 assert_equal 1, results.size
200 assert_equal 1, results.size
201 assert_equal attachment.container, results.first
201 assert_equal attachment.container, results.first
202 end
202 end
203
203
204 def test_search_with_attachments
204 def test_search_with_attachments
205 Issue.generate! :subject => 'search_attachments'
205 Issue.generate! :subject => 'search_attachments'
206 Attachment.generate! :container => Issue.find(1), :filename => 'search_attachments.patch'
206 Attachment.generate! :container => Issue.find(1), :filename => 'search_attachments.patch'
207
207
208 get :index, :id => 1, :q => 'search_attachments', :attachments => '1'
208 get :index, :params => {:id => 1, :q => 'search_attachments', :attachments => '1'}
209 results = assigns(:results)
209 results = assigns(:results)
210 assert_equal 2, results.size
210 assert_equal 2, results.size
211 end
211 end
212
212
213 def test_search_open_issues
213 def test_search_open_issues
214 Issue.generate! :subject => 'search_open'
214 Issue.generate! :subject => 'search_open'
215 Issue.generate! :subject => 'search_open', :status_id => 5
215 Issue.generate! :subject => 'search_open', :status_id => 5
216
216
217 get :index, :id => 1, :q => 'search_open', :open_issues => '1'
217 get :index, :params => {:id => 1, :q => 'search_open', :open_issues => '1'}
218 results = assigns(:results)
218 results = assigns(:results)
219 assert_equal 1, results.size
219 assert_equal 1, results.size
220 end
220 end
221
221
222 def test_search_all_words
222 def test_search_all_words
223 # 'all words' is on by default
223 # 'all words' is on by default
224 get :index, :id => 1, :q => 'recipe updating saving', :all_words => '1'
224 get :index, :params => {:id => 1, :q => 'recipe updating saving', :all_words => '1'}
225 assert_equal true, assigns(:all_words)
225 assert_equal true, assigns(:all_words)
226 results = assigns(:results)
226 results = assigns(:results)
227 assert_not_nil results
227 assert_not_nil results
228 assert_equal 1, results.size
228 assert_equal 1, results.size
229 assert results.include?(Issue.find(3))
229 assert results.include?(Issue.find(3))
230 end
230 end
231
231
232 def test_search_one_of_the_words
232 def test_search_one_of_the_words
233 get :index, :id => 1, :q => 'recipe updating saving', :all_words => ''
233 get :index, :params => {:id => 1, :q => 'recipe updating saving', :all_words => ''}
234 assert_equal false, assigns(:all_words)
234 assert_equal false, assigns(:all_words)
235 results = assigns(:results)
235 results = assigns(:results)
236 assert_not_nil results
236 assert_not_nil results
237 assert_equal 3, results.size
237 assert_equal 3, results.size
238 assert results.include?(Issue.find(3))
238 assert results.include?(Issue.find(3))
239 end
239 end
240
240
241 def test_search_titles_only_without_result
241 def test_search_titles_only_without_result
242 get :index, :id => 1, :q => 'recipe updating saving', :titles_only => '1'
242 get :index, :params => {:id => 1, :q => 'recipe updating saving', :titles_only => '1'}
243 results = assigns(:results)
243 results = assigns(:results)
244 assert_not_nil results
244 assert_not_nil results
245 assert_equal 0, results.size
245 assert_equal 0, results.size
246 end
246 end
247
247
248 def test_search_titles_only
248 def test_search_titles_only
249 get :index, :id => 1, :q => 'recipe', :titles_only => '1'
249 get :index, :params => {:id => 1, :q => 'recipe', :titles_only => '1'}
250 assert_equal true, assigns(:titles_only)
250 assert_equal true, assigns(:titles_only)
251 results = assigns(:results)
251 results = assigns(:results)
252 assert_not_nil results
252 assert_not_nil results
253 assert_equal 2, results.size
253 assert_equal 2, results.size
254 end
254 end
255
255
256 def test_search_content
256 def test_search_content
257 Issue.where(:id => 1).update_all("description = 'This is a searchkeywordinthecontent'")
257 Issue.where(:id => 1).update_all("description = 'This is a searchkeywordinthecontent'")
258 get :index, :id => 1, :q => 'searchkeywordinthecontent', :titles_only => ''
258
259 get :index, :params => {:id => 1, :q => 'searchkeywordinthecontent', :titles_only => ''}
259 assert_equal false, assigns(:titles_only)
260 assert_equal false, assigns(:titles_only)
260 results = assigns(:results)
261 results = assigns(:results)
261 assert_not_nil results
262 assert_not_nil results
262 assert_equal 1, results.size
263 assert_equal 1, results.size
263 end
264 end
264
265
265 def test_search_with_pagination
266 def test_search_with_pagination
266 issue = (0..24).map {Issue.generate! :subject => 'search_with_limited_results'}.reverse
267 issue = (0..24).map {Issue.generate! :subject => 'search_with_limited_results'}.reverse
267
268
268 get :index, :q => 'search_with_limited_results'
269 get :index, :params => {:q => 'search_with_limited_results'}
269 assert_response :success
270 assert_response :success
270 assert_equal issue[0..9], assigns(:results)
271 assert_equal issue[0..9], assigns(:results)
271
272
272 get :index, :q => 'search_with_limited_results', :page => 2
273 get :index, :params => {:q => 'search_with_limited_results', :page => 2}
273 assert_response :success
274 assert_response :success
274 assert_equal issue[10..19], assigns(:results)
275 assert_equal issue[10..19], assigns(:results)
275
276
276 get :index, :q => 'search_with_limited_results', :page => 3
277 get :index, :params => {:q => 'search_with_limited_results', :page => 3}
277 assert_response :success
278 assert_response :success
278 assert_equal issue[20..24], assigns(:results)
279 assert_equal issue[20..24], assigns(:results)
279
280
280 get :index, :q => 'search_with_limited_results', :page => 4
281 get :index, :params => {:q => 'search_with_limited_results', :page => 4}
281 assert_response :success
282 assert_response :success
282 assert_equal [], assigns(:results)
283 assert_equal [], assigns(:results)
283 end
284 end
284
285
285 def test_search_with_invalid_project_id
286 def test_search_with_invalid_project_id
286 get :index, :id => 195, :q => 'recipe'
287 get :index, :params => {:id => 195, :q => 'recipe'}
287 assert_response 404
288 assert_response 404
288 assert_nil assigns(:results)
289 assert_nil assigns(:results)
289 end
290 end
290
291
291 def test_quick_jump_to_issue
292 def test_quick_jump_to_issue
292 # issue of a public project
293 # issue of a public project
293 get :index, :q => "3"
294 get :index, :params => {:q => "3"}
294 assert_redirected_to '/issues/3'
295 assert_redirected_to '/issues/3'
295
296
296 # issue of a private project
297 # issue of a private project
297 get :index, :q => "4"
298 get :index, :params => {:q => "4"}
298 assert_response :success
299 assert_response :success
299 assert_template 'index'
300 assert_template 'index'
300 end
301 end
301
302
302 def test_large_integer
303 def test_large_integer
303 get :index, :q => '4615713488'
304 get :index, :params => {:q => '4615713488'}
304 assert_response :success
305 assert_response :success
305 assert_template 'index'
306 assert_template 'index'
306 end
307 end
307
308
308 def test_tokens_with_quotes
309 def test_tokens_with_quotes
309 get :index, :id => 1, :q => '"good bye" hello "bye bye"'
310 get :index, :params => {:id => 1, :q => '"good bye" hello "bye bye"'}
310 assert_equal ["good bye", "hello", "bye bye"], assigns(:tokens)
311 assert_equal ["good bye", "hello", "bye bye"], assigns(:tokens)
311 end
312 end
312
313
313 def test_results_should_be_escaped_once
314 def test_results_should_be_escaped_once
314 assert Issue.find(1).update_attributes(:subject => '<subject> escaped_once', :description => '<description> escaped_once')
315 assert Issue.find(1).update_attributes(:subject => '<subject> escaped_once', :description => '<description> escaped_once')
315 get :index, :q => 'escaped_once'
316 get :index, :params => {:q => 'escaped_once'}
316 assert_response :success
317 assert_response :success
317 assert_select '#search-results' do
318 assert_select '#search-results' do
318 assert_select 'dt.issue a', :text => /<subject>/
319 assert_select 'dt.issue a', :text => /<subject>/
319 assert_select 'dd', :text => /<description>/
320 assert_select 'dd', :text => /<description>/
320 end
321 end
321 end
322 end
322
323
323 def test_keywords_should_be_highlighted
324 def test_keywords_should_be_highlighted
324 assert Issue.find(1).update_attributes(:subject => 'subject highlighted', :description => 'description highlighted')
325 assert Issue.find(1).update_attributes(:subject => 'subject highlighted', :description => 'description highlighted')
325 get :index, :q => 'highlighted'
326 get :index, :params => {:q => 'highlighted'}
326 assert_response :success
327 assert_response :success
327 assert_select '#search-results' do
328 assert_select '#search-results' do
328 assert_select 'dt.issue a span.highlight', :text => 'highlighted'
329 assert_select 'dt.issue a span.highlight', :text => 'highlighted'
329 assert_select 'dd span.highlight', :text => 'highlighted'
330 assert_select 'dd span.highlight', :text => 'highlighted'
330 end
331 end
331 end
332 end
332 end
333 end
@@ -1,78 +1,78
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2016 Jean-Philippe Lang
2 # Copyright (C) 2006-2016 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 require File.expand_path('../../test_helper', __FILE__)
18 require File.expand_path('../../test_helper', __FILE__)
19
19
20 class SearchCustomFieldsVisibilityTest < Redmine::ControllerTest
20 class SearchCustomFieldsVisibilityTest < Redmine::ControllerTest
21 tests SearchController
21 tests SearchController
22 fixtures :projects,
22 fixtures :projects,
23 :users,
23 :users,
24 :roles,
24 :roles,
25 :members,
25 :members,
26 :member_roles,
26 :member_roles,
27 :issue_statuses,
27 :issue_statuses,
28 :trackers,
28 :trackers,
29 :projects_trackers,
29 :projects_trackers,
30 :enabled_modules,
30 :enabled_modules,
31 :enumerations,
31 :enumerations,
32 :workflows
32 :workflows
33
33
34 def setup
34 def setup
35 field_attributes = {:field_format => 'string', :is_for_all => true, :is_filter => true, :searchable => true, :trackers => Tracker.all}
35 field_attributes = {:field_format => 'string', :is_for_all => true, :is_filter => true, :searchable => true, :trackers => Tracker.all}
36 @fields = []
36 @fields = []
37 @fields << (@field1 = IssueCustomField.create!(field_attributes.merge(:name => 'Field 1', :visible => true)))
37 @fields << (@field1 = IssueCustomField.create!(field_attributes.merge(:name => 'Field 1', :visible => true)))
38 @fields << (@field2 = IssueCustomField.create!(field_attributes.merge(:name => 'Field 2', :visible => false, :role_ids => [1, 2])))
38 @fields << (@field2 = IssueCustomField.create!(field_attributes.merge(:name => 'Field 2', :visible => false, :role_ids => [1, 2])))
39 @fields << (@field3 = IssueCustomField.create!(field_attributes.merge(:name => 'Field 3', :visible => false, :role_ids => [1, 3])))
39 @fields << (@field3 = IssueCustomField.create!(field_attributes.merge(:name => 'Field 3', :visible => false, :role_ids => [1, 3])))
40 @issue = Issue.generate!(
40 @issue = Issue.generate!(
41 :author_id => 1,
41 :author_id => 1,
42 :project_id => 1,
42 :project_id => 1,
43 :tracker_id => 1,
43 :tracker_id => 1,
44 :custom_field_values => {@field1.id => 'Value0', @field2.id => 'Value1', @field3.id => 'Value2'}
44 :custom_field_values => {@field1.id => 'Value0', @field2.id => 'Value1', @field3.id => 'Value2'}
45 )
45 )
46
46
47 @user_with_role_on_other_project = User.generate!
47 @user_with_role_on_other_project = User.generate!
48 User.add_to_project(@user_with_role_on_other_project, Project.find(2), Role.find(3))
48 User.add_to_project(@user_with_role_on_other_project, Project.find(2), Role.find(3))
49
49
50 @users_to_test = {
50 @users_to_test = {
51 User.find(1) => [@field1, @field2, @field3],
51 User.find(1) => [@field1, @field2, @field3],
52 User.find(3) => [@field1, @field2],
52 User.find(3) => [@field1, @field2],
53 @user_with_role_on_other_project => [@field1], # should see field1 only on Project 1
53 @user_with_role_on_other_project => [@field1], # should see field1 only on Project 1
54 User.generate! => [@field1],
54 User.generate! => [@field1],
55 User.anonymous => [@field1]
55 User.anonymous => [@field1]
56 }
56 }
57
57
58 Member.where(:project_id => 1).each do |member|
58 Member.where(:project_id => 1).each do |member|
59 member.destroy unless @users_to_test.keys.include?(member.principal)
59 member.destroy unless @users_to_test.keys.include?(member.principal)
60 end
60 end
61 end
61 end
62
62
63 def test_search_should_search_visible_custom_fields_only
63 def test_search_should_search_visible_custom_fields_only
64 @users_to_test.each do |user, fields|
64 @users_to_test.each do |user, fields|
65 @request.session[:user_id] = user.id
65 @request.session[:user_id] = user.id
66 @fields.each_with_index do |field, i|
66 @fields.each_with_index do |field, i|
67 get :index, :q => "value#{i}"
67 get :index, :params => {:q => "value#{i}"}
68 assert_response :success
68 assert_response :success
69 # we should get a result only if the custom field is visible
69 # we should get a result only if the custom field is visible
70 if fields.include?(field)
70 if fields.include?(field)
71 assert_equal 1, assigns(:results).size
71 assert_equal 1, assigns(:results).size
72 else
72 else
73 assert_equal 0, assigns(:results).size
73 assert_equal 0, assigns(:results).size
74 end
74 end
75 end
75 end
76 end
76 end
77 end
77 end
78 end
78 end
@@ -1,138 +1,138
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2016 Jean-Philippe Lang
2 # Copyright (C) 2006-2016 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 require File.expand_path('../../test_helper', __FILE__)
18 require File.expand_path('../../test_helper', __FILE__)
19
19
20 class SessionsControllerTest < Redmine::ControllerTest
20 class SessionsControllerTest < Redmine::ControllerTest
21 include Redmine::I18n
21 include Redmine::I18n
22 tests WelcomeController
22 tests WelcomeController
23
23
24 fixtures :users, :email_addresses
24 fixtures :users, :email_addresses
25
25
26 def setup
26 def setup
27 Rails.application.config.redmine_verify_sessions = true
27 Rails.application.config.redmine_verify_sessions = true
28 end
28 end
29
29
30 def teardown
30 def teardown
31 Rails.application.config.redmine_verify_sessions = false
31 Rails.application.config.redmine_verify_sessions = false
32 end
32 end
33
33
34 def test_session_token_should_be_updated
34 def test_session_token_should_be_updated
35 token = Token.create!(:user_id => 2, :action => 'session', :created_on => 10.hours.ago, :updated_on => 10.hours.ago)
35 token = Token.create!(:user_id => 2, :action => 'session', :created_on => 10.hours.ago, :updated_on => 10.hours.ago)
36 created = token.reload.created_on
36 created = token.reload.created_on
37
37
38 get :index, {}, {:user_id => 2, :tk => token.value}
38 get :index, :session => {:user_id => 2, :tk => token.value}
39 assert_response :success
39 assert_response :success
40 token.reload
40 token.reload
41 assert_equal created.to_i, token.created_on.to_i
41 assert_equal created.to_i, token.created_on.to_i
42 assert_not_equal created.to_i, token.updated_on.to_i
42 assert_not_equal created.to_i, token.updated_on.to_i
43 assert token.updated_on > created
43 assert token.updated_on > created
44 end
44 end
45
45
46 def test_user_session_should_not_be_reset_if_lifetime_and_timeout_disabled
46 def test_user_session_should_not_be_reset_if_lifetime_and_timeout_disabled
47 created = 2.years.ago
47 created = 2.years.ago
48 token = Token.create!(:user_id => 2, :action => 'session', :created_on => created, :updated_on => created)
48 token = Token.create!(:user_id => 2, :action => 'session', :created_on => created, :updated_on => created)
49
49
50 with_settings :session_lifetime => '0', :session_timeout => '0' do
50 with_settings :session_lifetime => '0', :session_timeout => '0' do
51 get :index, {}, {:user_id => 2, :tk => token.value}
51 get :index, :session => {:user_id => 2, :tk => token.value}
52 assert_response :success
52 assert_response :success
53 end
53 end
54 end
54 end
55
55
56 def test_user_session_without_token_should_be_reset
56 def test_user_session_without_token_should_be_reset
57 get :index, {}, {:user_id => 2}
57 get :index, :session => {:user_id => 2}
58 assert_redirected_to 'http://test.host/login?back_url=http%3A%2F%2Ftest.host%2F'
58 assert_redirected_to 'http://test.host/login?back_url=http%3A%2F%2Ftest.host%2F'
59 end
59 end
60
60
61 def test_expired_user_session_should_be_reset_if_lifetime_enabled
61 def test_expired_user_session_should_be_reset_if_lifetime_enabled
62 created = 2.days.ago
62 created = 2.days.ago
63 token = Token.create!(:user_id => 2, :action => 'session', :created_on => created, :updated_on => created)
63 token = Token.create!(:user_id => 2, :action => 'session', :created_on => created, :updated_on => created)
64
64
65 with_settings :session_timeout => '720' do
65 with_settings :session_timeout => '720' do
66 get :index, {}, {:user_id => 2, :tk => token.value}
66 get :index, :session => {:user_id => 2, :tk => token.value}
67 assert_redirected_to 'http://test.host/login?back_url=http%3A%2F%2Ftest.host%2F'
67 assert_redirected_to 'http://test.host/login?back_url=http%3A%2F%2Ftest.host%2F'
68 end
68 end
69 end
69 end
70
70
71 def test_valid_user_session_should_not_be_reset_if_lifetime_enabled
71 def test_valid_user_session_should_not_be_reset_if_lifetime_enabled
72 created = 3.hours.ago
72 created = 3.hours.ago
73 token = Token.create!(:user_id => 2, :action => 'session', :created_on => created, :updated_on => created)
73 token = Token.create!(:user_id => 2, :action => 'session', :created_on => created, :updated_on => created)
74
74
75 with_settings :session_timeout => '720' do
75 with_settings :session_timeout => '720' do
76 get :index, {}, {:user_id => 2, :tk => token.value}
76 get :index, :session => {:user_id => 2, :tk => token.value}
77 assert_response :success
77 assert_response :success
78 end
78 end
79 end
79 end
80
80
81 def test_expired_user_session_should_be_reset_if_timeout_enabled
81 def test_expired_user_session_should_be_reset_if_timeout_enabled
82 created = 4.hours.ago
82 created = 4.hours.ago
83 token = Token.create!(:user_id => 2, :action => 'session', :created_on => created, :updated_on => created)
83 token = Token.create!(:user_id => 2, :action => 'session', :created_on => created, :updated_on => created)
84
84
85 with_settings :session_timeout => '60' do
85 with_settings :session_timeout => '60' do
86 get :index, {}, {:user_id => 2, :tk => token.value}
86 get :index, :session => {:user_id => 2, :tk => token.value}
87 assert_redirected_to 'http://test.host/login?back_url=http%3A%2F%2Ftest.host%2F'
87 assert_redirected_to 'http://test.host/login?back_url=http%3A%2F%2Ftest.host%2F'
88 end
88 end
89 end
89 end
90
90
91 def test_valid_user_session_should_not_be_reset_if_timeout_enabled
91 def test_valid_user_session_should_not_be_reset_if_timeout_enabled
92 created = 10.minutes.ago
92 created = 10.minutes.ago
93 token = Token.create!(:user_id => 2, :action => 'session', :created_on => created, :updated_on => created)
93 token = Token.create!(:user_id => 2, :action => 'session', :created_on => created, :updated_on => created)
94
94
95 with_settings :session_timeout => '60' do
95 with_settings :session_timeout => '60' do
96 get :index, {}, {:user_id => 2, :tk => token.value}
96 get :index, :session => {:user_id => 2, :tk => token.value}
97 assert_response :success
97 assert_response :success
98 end
98 end
99 end
99 end
100
100
101 def test_expired_user_session_should_be_restarted_if_autologin
101 def test_expired_user_session_should_be_restarted_if_autologin
102 created = 2.hours.ago
102 created = 2.hours.ago
103 token = Token.create!(:user_id => 2, :action => 'session', :created_on => created, :updated_on => created)
103 token = Token.create!(:user_id => 2, :action => 'session', :created_on => created, :updated_on => created)
104
104
105 with_settings :session_lifetime => '720', :session_timeout => '60', :autologin => 7 do
105 with_settings :session_lifetime => '720', :session_timeout => '60', :autologin => 7 do
106 autologin_token = Token.create!(:user_id => 2, :action => 'autologin', :created_on => 1.day.ago)
106 autologin_token = Token.create!(:user_id => 2, :action => 'autologin', :created_on => 1.day.ago)
107 @request.cookies['autologin'] = autologin_token.value
107 @request.cookies['autologin'] = autologin_token.value
108
108
109 get :index, {}, {:user_id => 2, :tk => token.value}
109 get :index, :session => {:user_id => 2, :tk => token.value}
110 assert_equal 2, session[:user_id]
110 assert_equal 2, session[:user_id]
111 assert_response :success
111 assert_response :success
112 assert_not_equal token.value, session[:tk]
112 assert_not_equal token.value, session[:tk]
113 end
113 end
114 end
114 end
115
115
116 def test_expired_user_session_should_set_locale
116 def test_expired_user_session_should_set_locale
117 set_language_if_valid 'it'
117 set_language_if_valid 'it'
118 user = User.find(2)
118 user = User.find(2)
119 user.language = 'fr'
119 user.language = 'fr'
120 user.save!
120 user.save!
121 created = 4.hours.ago
121 created = 4.hours.ago
122 token = Token.create!(:user_id => 2, :action => 'session', :created_on => created, :updated_on => created)
122 token = Token.create!(:user_id => 2, :action => 'session', :created_on => created, :updated_on => created)
123
123
124 with_settings :session_timeout => '60' do
124 with_settings :session_timeout => '60' do
125 get :index, {}, {:user_id => user.id, :tk => token.value}
125 get :index, :session => {:user_id => user.id, :tk => token.value}
126 assert_redirected_to 'http://test.host/login?back_url=http%3A%2F%2Ftest.host%2F'
126 assert_redirected_to 'http://test.host/login?back_url=http%3A%2F%2Ftest.host%2F'
127 assert_include "Veuillez vous reconnecter", flash[:error]
127 assert_include "Veuillez vous reconnecter", flash[:error]
128 assert_equal :fr, current_language
128 assert_equal :fr, current_language
129 end
129 end
130 end
130 end
131
131
132 def test_anonymous_session_should_not_be_reset
132 def test_anonymous_session_should_not_be_reset
133 with_settings :session_lifetime => '720', :session_timeout => '60' do
133 with_settings :session_lifetime => '720', :session_timeout => '60' do
134 get :index
134 get :index
135 assert_response :success
135 assert_response :success
136 end
136 end
137 end
137 end
138 end
138 end
@@ -1,234 +1,248
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2016 Jean-Philippe Lang
2 # Copyright (C) 2006-2016 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 require File.expand_path('../../test_helper', __FILE__)
18 require File.expand_path('../../test_helper', __FILE__)
19
19
20 class SettingsControllerTest < Redmine::ControllerTest
20 class SettingsControllerTest < Redmine::ControllerTest
21 fixtures :projects, :trackers, :issue_statuses, :issues,
21 fixtures :projects, :trackers, :issue_statuses, :issues,
22 :users
22 :users
23
23
24 def setup
24 def setup
25 User.current = nil
25 User.current = nil
26 @request.session[:user_id] = 1 # admin
26 @request.session[:user_id] = 1 # admin
27 end
27 end
28
28
29 def teardown
29 def teardown
30 Setting.delete_all
30 Setting.delete_all
31 Setting.clear_cache
31 Setting.clear_cache
32 end
32 end
33
33
34 def test_index
34 def test_index
35 get :index
35 get :index
36 assert_response :success
36 assert_response :success
37 assert_template 'edit'
37 assert_template 'edit'
38 end
38 end
39
39
40 def test_get_edit
40 def test_get_edit
41 get :edit
41 get :edit
42 assert_response :success
42 assert_response :success
43 assert_template 'edit'
43 assert_template 'edit'
44
44
45 assert_select 'input[name=?][value=""]', 'settings[enabled_scm][]'
45 assert_select 'input[name=?][value=""]', 'settings[enabled_scm][]'
46 end
46 end
47
47
48 def test_get_edit_should_preselect_default_issue_list_columns
48 def test_get_edit_should_preselect_default_issue_list_columns
49 with_settings :issue_list_default_columns => %w(tracker subject status updated_on) do
49 with_settings :issue_list_default_columns => %w(tracker subject status updated_on) do
50 get :edit
50 get :edit
51 assert_response :success
51 assert_response :success
52 end
52 end
53
53
54 assert_select 'select[id=selected_columns][name=?]', 'settings[issue_list_default_columns][]' do
54 assert_select 'select[id=selected_columns][name=?]', 'settings[issue_list_default_columns][]' do
55 assert_select 'option', 4
55 assert_select 'option', 4
56 assert_select 'option[value=tracker]', :text => 'Tracker'
56 assert_select 'option[value=tracker]', :text => 'Tracker'
57 assert_select 'option[value=subject]', :text => 'Subject'
57 assert_select 'option[value=subject]', :text => 'Subject'
58 assert_select 'option[value=status]', :text => 'Status'
58 assert_select 'option[value=status]', :text => 'Status'
59 assert_select 'option[value=updated_on]', :text => 'Updated'
59 assert_select 'option[value=updated_on]', :text => 'Updated'
60 end
60 end
61
61
62 assert_select 'select[id=available_columns]' do
62 assert_select 'select[id=available_columns]' do
63 assert_select 'option[value=tracker]', 0
63 assert_select 'option[value=tracker]', 0
64 assert_select 'option[value=priority]', :text => 'Priority'
64 assert_select 'option[value=priority]', :text => 'Priority'
65 end
65 end
66 end
66 end
67
67
68 def test_get_edit_without_trackers_should_succeed
68 def test_get_edit_without_trackers_should_succeed
69 Tracker.delete_all
69 Tracker.delete_all
70
70
71 get :edit
71 get :edit
72 assert_response :success
72 assert_response :success
73 end
73 end
74
74
75 def test_post_edit_notifications
75 def test_post_edit_notifications
76 post :edit, :settings => {:mail_from => 'functional@test.foo',
76 post :edit, :params => {
77 :bcc_recipients => '0',
77 :settings => {
78 :notified_events => %w(issue_added issue_updated news_added),
78 :mail_from => 'functional@test.foo',
79 :emails_footer => 'Test footer'
79 :bcc_recipients => '0',
80 }
80 :notified_events => %w(issue_added issue_updated news_added),
81 :emails_footer => 'Test footer'
82 }
83 }
81 assert_redirected_to '/settings'
84 assert_redirected_to '/settings'
82 assert_equal 'functional@test.foo', Setting.mail_from
85 assert_equal 'functional@test.foo', Setting.mail_from
83 assert !Setting.bcc_recipients?
86 assert !Setting.bcc_recipients?
84 assert_equal %w(issue_added issue_updated news_added), Setting.notified_events
87 assert_equal %w(issue_added issue_updated news_added), Setting.notified_events
85 assert_equal 'Test footer', Setting.emails_footer
88 assert_equal 'Test footer', Setting.emails_footer
86 end
89 end
87
90
88 def test_edit_commit_update_keywords
91 def test_edit_commit_update_keywords
89 with_settings :commit_update_keywords => [
92 with_settings :commit_update_keywords => [
90 {"keywords" => "fixes, resolves", "status_id" => "3"},
93 {"keywords" => "fixes, resolves", "status_id" => "3"},
91 {"keywords" => "closes", "status_id" => "5", "done_ratio" => "100", "if_tracker_id" => "2"}
94 {"keywords" => "closes", "status_id" => "5", "done_ratio" => "100", "if_tracker_id" => "2"}
92 ] do
95 ] do
93 get :edit
96 get :edit
94 end
97 end
95 assert_response :success
98 assert_response :success
96 assert_select 'tr.commit-keywords', 2
99 assert_select 'tr.commit-keywords', 2
97 assert_select 'tr.commit-keywords:nth-child(1)' do
100 assert_select 'tr.commit-keywords:nth-child(1)' do
98 assert_select 'input[name=?][value=?]', 'settings[commit_update_keywords][keywords][]', 'fixes, resolves'
101 assert_select 'input[name=?][value=?]', 'settings[commit_update_keywords][keywords][]', 'fixes, resolves'
99 assert_select 'select[name=?]', 'settings[commit_update_keywords][status_id][]' do
102 assert_select 'select[name=?]', 'settings[commit_update_keywords][status_id][]' do
100 assert_select 'option[value="3"][selected=selected]'
103 assert_select 'option[value="3"][selected=selected]'
101 end
104 end
102 end
105 end
103 assert_select 'tr.commit-keywords:nth-child(2)' do
106 assert_select 'tr.commit-keywords:nth-child(2)' do
104 assert_select 'input[name=?][value=?]', 'settings[commit_update_keywords][keywords][]', 'closes'
107 assert_select 'input[name=?][value=?]', 'settings[commit_update_keywords][keywords][]', 'closes'
105 assert_select 'select[name=?]', 'settings[commit_update_keywords][status_id][]' do
108 assert_select 'select[name=?]', 'settings[commit_update_keywords][status_id][]' do
106 assert_select 'option[value="5"][selected=selected]', :text => 'Closed'
109 assert_select 'option[value="5"][selected=selected]', :text => 'Closed'
107 end
110 end
108 assert_select 'select[name=?]', 'settings[commit_update_keywords][done_ratio][]' do
111 assert_select 'select[name=?]', 'settings[commit_update_keywords][done_ratio][]' do
109 assert_select 'option[value="100"][selected=selected]', :text => '100 %'
112 assert_select 'option[value="100"][selected=selected]', :text => '100 %'
110 end
113 end
111 assert_select 'select[name=?]', 'settings[commit_update_keywords][if_tracker_id][]' do
114 assert_select 'select[name=?]', 'settings[commit_update_keywords][if_tracker_id][]' do
112 assert_select 'option[value="2"][selected=selected]', :text => 'Feature request'
115 assert_select 'option[value="2"][selected=selected]', :text => 'Feature request'
113 end
116 end
114 end
117 end
115 end
118 end
116
119
117 def test_edit_without_commit_update_keywords_should_show_blank_line
120 def test_edit_without_commit_update_keywords_should_show_blank_line
118 with_settings :commit_update_keywords => [] do
121 with_settings :commit_update_keywords => [] do
119 get :edit
122 get :edit
120 end
123 end
121 assert_response :success
124 assert_response :success
122 assert_select 'tr.commit-keywords', 1 do
125 assert_select 'tr.commit-keywords', 1 do
123 assert_select 'input[name=?]:not([value])', 'settings[commit_update_keywords][keywords][]'
126 assert_select 'input[name=?]:not([value])', 'settings[commit_update_keywords][keywords][]'
124 end
127 end
125 end
128 end
126
129
127 def test_post_edit_commit_update_keywords
130 def test_post_edit_commit_update_keywords
128 post :edit, :settings => {
131 post :edit, :params => {
129 :commit_update_keywords => {
132 :settings => {
130 :keywords => ["resolves", "closes"],
133 :commit_update_keywords => {
131 :status_id => ["3", "5"],
134 :keywords => ["resolves", "closes"],
132 :done_ratio => ["", "100"],
135 :status_id => ["3", "5"],
133 :if_tracker_id => ["", "2"]
136 :done_ratio => ["", "100"],
137 :if_tracker_id => ["", "2"]
138 }
134 }
139 }
135 }
140 }
136 assert_redirected_to '/settings'
141 assert_redirected_to '/settings'
137 assert_equal([
142 assert_equal([
138 {"keywords" => "resolves", "status_id" => "3"},
143 {"keywords" => "resolves", "status_id" => "3"},
139 {"keywords" => "closes", "status_id" => "5", "done_ratio" => "100", "if_tracker_id" => "2"}
144 {"keywords" => "closes", "status_id" => "5", "done_ratio" => "100", "if_tracker_id" => "2"}
140 ], Setting.commit_update_keywords)
145 ], Setting.commit_update_keywords)
141 end
146 end
142
147
143 def test_post_edit_should_send_security_notification_for_notified_settings
148 def test_post_edit_should_send_security_notification_for_notified_settings
144 ActionMailer::Base.deliveries.clear
149 ActionMailer::Base.deliveries.clear
145 post :edit, :settings => {
150 post :edit, :params => {
146 :login_required => 1
151 :settings => {
152 :login_required => 1
153 }
147 }
154 }
148
149 assert_not_nil (mail = ActionMailer::Base.deliveries.last)
155 assert_not_nil (mail = ActionMailer::Base.deliveries.last)
150 assert_mail_body_match '0.0.0.0', mail
156 assert_mail_body_match '0.0.0.0', mail
151 assert_mail_body_match I18n.t(:setting_login_required), mail
157 assert_mail_body_match I18n.t(:setting_login_required), mail
152 assert_select_email do
158 assert_select_email do
153 assert_select 'a[href^=?]', 'http://localhost:3000/settings'
159 assert_select 'a[href^=?]', 'http://localhost:3000/settings'
154 end
160 end
155 # All admins should receive this
161 # All admins should receive this
156 recipients = [mail.bcc, mail.cc].flatten
162 recipients = [mail.bcc, mail.cc].flatten
157 User.active.where(admin: true).each do |admin|
163 User.active.where(admin: true).each do |admin|
158 assert_include admin.mail, recipients
164 assert_include admin.mail, recipients
159 end
165 end
160 end
166 end
161
167
162 def test_post_edit_should_not_send_security_notification_for_non_notified_settings
168 def test_post_edit_should_not_send_security_notification_for_non_notified_settings
163 ActionMailer::Base.deliveries.clear
169 ActionMailer::Base.deliveries.clear
164 post :edit, :settings => {
170 post :edit, :params => {
165 :app_title => 'MineRed'
171 :settings => {
172 :app_title => 'MineRed'
173 }
166 }
174 }
167
168 assert_nil (mail = ActionMailer::Base.deliveries.last)
175 assert_nil (mail = ActionMailer::Base.deliveries.last)
169 end
176 end
170
177
171 def test_post_edit_should_not_send_security_notification_for_unchanged_settings
178 def test_post_edit_should_not_send_security_notification_for_unchanged_settings
172 ActionMailer::Base.deliveries.clear
179 ActionMailer::Base.deliveries.clear
173 post :edit, :settings => {
180 post :edit, :params => {
174 :login_required => 0
181 :settings => {
182 :login_required => 0
183 }
175 }
184 }
176
177 assert_nil (mail = ActionMailer::Base.deliveries.last)
185 assert_nil (mail = ActionMailer::Base.deliveries.last)
178 end
186 end
179
187
180
188
181 def test_get_plugin_settings
189 def test_get_plugin_settings
182 ActionController::Base.append_view_path(File.join(Rails.root, "test/fixtures/plugins"))
190 ActionController::Base.append_view_path(File.join(Rails.root, "test/fixtures/plugins"))
183 Redmine::Plugin.register :foo do
191 Redmine::Plugin.register :foo do
184 settings :partial => "foo_plugin/foo_plugin_settings"
192 settings :partial => "foo_plugin/foo_plugin_settings"
185 end
193 end
186 Setting.plugin_foo = {'sample_setting' => 'Plugin setting value'}
194 Setting.plugin_foo = {'sample_setting' => 'Plugin setting value'}
187
195
188 get :plugin, :id => 'foo'
196 get :plugin, :params => {:id => 'foo'}
189 assert_response :success
197 assert_response :success
190 assert_template 'plugin'
198 assert_template 'plugin'
191 assert_select 'form[action="/settings/plugin/foo"]' do
199 assert_select 'form[action="/settings/plugin/foo"]' do
192 assert_select 'input[name=?][value=?]', 'settings[sample_setting]', 'Plugin setting value'
200 assert_select 'input[name=?][value=?]', 'settings[sample_setting]', 'Plugin setting value'
193 end
201 end
194 ensure
202 ensure
195 Redmine::Plugin.unregister(:foo)
203 Redmine::Plugin.unregister(:foo)
196 end
204 end
197
205
198 def test_get_invalid_plugin_settings
206 def test_get_invalid_plugin_settings
199 get :plugin, :id => 'none'
207 get :plugin, :params => {:id => 'none'}
200 assert_response 404
208 assert_response 404
201 end
209 end
202
210
203 def test_get_non_configurable_plugin_settings
211 def test_get_non_configurable_plugin_settings
204 Redmine::Plugin.register(:foo) {}
212 Redmine::Plugin.register(:foo) {}
205
213
206 get :plugin, :id => 'foo'
214 get :plugin, :params => {:id => 'foo'}
207 assert_response 404
215 assert_response 404
208
216
209 ensure
217 ensure
210 Redmine::Plugin.unregister(:foo)
218 Redmine::Plugin.unregister(:foo)
211 end
219 end
212
220
213 def test_post_plugin_settings
221 def test_post_plugin_settings
214 Redmine::Plugin.register(:foo) do
222 Redmine::Plugin.register(:foo) do
215 settings :partial => 'not blank', # so that configurable? is true
223 settings :partial => 'not blank', # so that configurable? is true
216 :default => {'sample_setting' => 'Plugin setting value'}
224 :default => {'sample_setting' => 'Plugin setting value'}
217 end
225 end
218
226
219 post :plugin, :id => 'foo', :settings => {'sample_setting' => 'Value'}
227 post :plugin, :params => {
228 :id => 'foo',
229 :settings => {'sample_setting' => 'Value'}
230 }
220 assert_redirected_to '/settings/plugin/foo'
231 assert_redirected_to '/settings/plugin/foo'
221
232
222 assert_equal({'sample_setting' => 'Value'}, Setting.plugin_foo)
233 assert_equal({'sample_setting' => 'Value'}, Setting.plugin_foo)
223 end
234 end
224
235
225 def test_post_non_configurable_plugin_settings
236 def test_post_non_configurable_plugin_settings
226 Redmine::Plugin.register(:foo) {}
237 Redmine::Plugin.register(:foo) {}
227
238
228 post :plugin, :id => 'foo', :settings => {'sample_setting' => 'Value'}
239 post :plugin, :params => {
240 :id => 'foo',
241 :settings => {'sample_setting' => 'Value'}
242 }
229 assert_response 404
243 assert_response 404
230
244
231 ensure
245 ensure
232 Redmine::Plugin.unregister(:foo)
246 Redmine::Plugin.unregister(:foo)
233 end
247 end
234 end
248 end
@@ -1,128 +1,132
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2016 Jean-Philippe Lang
2 # Copyright (C) 2006-2016 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 require File.expand_path('../../test_helper', __FILE__)
18 require File.expand_path('../../test_helper', __FILE__)
19
19
20 class SysControllerTest < Redmine::ControllerTest
20 class SysControllerTest < Redmine::ControllerTest
21 fixtures :projects, :repositories, :enabled_modules
21 fixtures :projects, :repositories, :enabled_modules
22
22
23 def setup
23 def setup
24 Setting.sys_api_enabled = '1'
24 Setting.sys_api_enabled = '1'
25 Setting.enabled_scm = %w(Subversion Git)
25 Setting.enabled_scm = %w(Subversion Git)
26 end
26 end
27
27
28 def teardown
28 def teardown
29 Setting.clear_cache
29 Setting.clear_cache
30 end
30 end
31
31
32 def test_projects_with_repository_enabled
32 def test_projects_with_repository_enabled
33 get :projects
33 get :projects
34 assert_response :success
34 assert_response :success
35 assert_equal 'application/xml', @response.content_type
35 assert_equal 'application/xml', @response.content_type
36
36
37 assert_select 'projects' do
37 assert_select 'projects' do
38 assert_select 'project', Project.active.has_module(:repository).count
38 assert_select 'project', Project.active.has_module(:repository).count
39 assert_select 'project' do
39 assert_select 'project' do
40 assert_select 'identifier'
40 assert_select 'identifier'
41 assert_select 'is-public'
41 assert_select 'is-public'
42 end
42 end
43 end
43 end
44 assert_select 'extra-info', 0
44 assert_select 'extra-info', 0
45 assert_select 'extra_info', 0
45 assert_select 'extra_info', 0
46 end
46 end
47
47
48 def test_create_project_repository
48 def test_create_project_repository
49 assert_nil Project.find(4).repository
49 assert_nil Project.find(4).repository
50
50
51 post :create_project_repository, :id => 4,
51 post :create_project_repository, :params => {
52 :vendor => 'Subversion',
52 :id => 4,
53 :repository => { :url => 'file:///create/project/repository/subproject2'}
53 :vendor => 'Subversion',
54 :repository => { :url => 'file:///create/project/repository/subproject2'}
55 }
54 assert_response :created
56 assert_response :created
55 assert_equal 'application/xml', @response.content_type
57 assert_equal 'application/xml', @response.content_type
56
58
57 r = Project.find(4).repository
59 r = Project.find(4).repository
58 assert r.is_a?(Repository::Subversion)
60 assert r.is_a?(Repository::Subversion)
59 assert_equal 'file:///create/project/repository/subproject2', r.url
61 assert_equal 'file:///create/project/repository/subproject2', r.url
60
62
61 assert_select 'repository-subversion' do
63 assert_select 'repository-subversion' do
62 assert_select 'id', :text => r.id.to_s
64 assert_select 'id', :text => r.id.to_s
63 assert_select 'url', :text => r.url
65 assert_select 'url', :text => r.url
64 end
66 end
65 assert_select 'extra-info', 0
67 assert_select 'extra-info', 0
66 assert_select 'extra_info', 0
68 assert_select 'extra_info', 0
67 end
69 end
68
70
69 def test_create_already_existing
71 def test_create_already_existing
70 post :create_project_repository, :id => 1,
72 post :create_project_repository, :params => {
73 :id => 1,
71 :vendor => 'Subversion',
74 :vendor => 'Subversion',
72 :repository => { :url => 'file:///create/project/repository/subproject2'}
75 :repository => { :url => 'file:///create/project/repository/subproject2'}
73
76 }
74 assert_response :conflict
77 assert_response :conflict
75 end
78 end
76
79
77 def test_create_with_failure
80 def test_create_with_failure
78 post :create_project_repository, :id => 4,
81 post :create_project_repository, :params => {
82 :id => 4,
79 :vendor => 'Subversion',
83 :vendor => 'Subversion',
80 :repository => { :url => 'invalid url'}
84 :repository => { :url => 'invalid url'}
81
85 }
82 assert_response :unprocessable_entity
86 assert_response :unprocessable_entity
83 end
87 end
84
88
85 def test_fetch_changesets
89 def test_fetch_changesets
86 Repository::Subversion.any_instance.expects(:fetch_changesets).twice.returns(true)
90 Repository::Subversion.any_instance.expects(:fetch_changesets).twice.returns(true)
87 get :fetch_changesets
91 get :fetch_changesets
88 assert_response :success
92 assert_response :success
89 end
93 end
90
94
91 def test_fetch_changesets_one_project_by_identifier
95 def test_fetch_changesets_one_project_by_identifier
92 Repository::Subversion.any_instance.expects(:fetch_changesets).once.returns(true)
96 Repository::Subversion.any_instance.expects(:fetch_changesets).once.returns(true)
93 get :fetch_changesets, :id => 'ecookbook'
97 get :fetch_changesets, :params => {:id => 'ecookbook'}
94 assert_response :success
98 assert_response :success
95 end
99 end
96
100
97 def test_fetch_changesets_one_project_by_id
101 def test_fetch_changesets_one_project_by_id
98 Repository::Subversion.any_instance.expects(:fetch_changesets).once.returns(true)
102 Repository::Subversion.any_instance.expects(:fetch_changesets).once.returns(true)
99 get :fetch_changesets, :id => '1'
103 get :fetch_changesets, :params => {:id => '1'}
100 assert_response :success
104 assert_response :success
101 end
105 end
102
106
103 def test_fetch_changesets_unknown_project
107 def test_fetch_changesets_unknown_project
104 get :fetch_changesets, :id => 'unknown'
108 get :fetch_changesets, :params => {:id => 'unknown'}
105 assert_response 404
109 assert_response 404
106 end
110 end
107
111
108 def test_disabled_ws_should_respond_with_403_error
112 def test_disabled_ws_should_respond_with_403_error
109 with_settings :sys_api_enabled => '0' do
113 with_settings :sys_api_enabled => '0' do
110 get :projects
114 get :projects
111 assert_response 403
115 assert_response 403
112 end
116 end
113 end
117 end
114
118
115 def test_api_key
119 def test_api_key
116 with_settings :sys_api_key => 'my_secret_key' do
120 with_settings :sys_api_key => 'my_secret_key' do
117 get :projects, :key => 'my_secret_key'
121 get :projects, :params => {:key => 'my_secret_key'}
118 assert_response :success
122 assert_response :success
119 end
123 end
120 end
124 end
121
125
122 def test_wrong_key_should_respond_with_403_error
126 def test_wrong_key_should_respond_with_403_error
123 with_settings :sys_api_enabled => 'my_secret_key' do
127 with_settings :sys_api_enabled => 'my_secret_key' do
124 get :projects, :key => 'wrong_key'
128 get :projects, :params => {:key => 'wrong_key'}
125 assert_response 403
129 assert_response 403
126 end
130 end
127 end
131 end
128 end
132 end
@@ -1,345 +1,370
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 # Redmine - project management software
2 # Redmine - project management software
3 # Copyright (C) 2006-2016 Jean-Philippe Lang
3 # Copyright (C) 2006-2016 Jean-Philippe Lang
4 #
4 #
5 # This program is free software; you can redistribute it and/or
5 # This program is free software; you can redistribute it and/or
6 # modify it under the terms of the GNU General Public License
6 # modify it under the terms of the GNU General Public License
7 # as published by the Free Software Foundation; either version 2
7 # as published by the Free Software Foundation; either version 2
8 # of the License, or (at your option) any later version.
8 # of the License, or (at your option) any later version.
9 #
9 #
10 # This program is distributed in the hope that it will be useful,
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
13 # GNU General Public License for more details.
14 #
14 #
15 # You should have received a copy of the GNU General Public License
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software
16 # along with this program; if not, write to the Free Software
17 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18
18
19 require File.expand_path('../../test_helper', __FILE__)
19 require File.expand_path('../../test_helper', __FILE__)
20
20
21 class TimeEntryReportsControllerTest < Redmine::ControllerTest
21 class TimeEntryReportsControllerTest < Redmine::ControllerTest
22 tests TimelogController
22 tests TimelogController
23
23
24 fixtures :projects, :enabled_modules, :roles, :members, :member_roles,
24 fixtures :projects, :enabled_modules, :roles, :members, :member_roles,
25 :email_addresses,
25 :email_addresses,
26 :issues, :time_entries, :users, :trackers, :enumerations,
26 :issues, :time_entries, :users, :trackers, :enumerations,
27 :issue_statuses, :custom_fields, :custom_values,
27 :issue_statuses, :custom_fields, :custom_values,
28 :projects_trackers, :custom_fields_trackers,
28 :projects_trackers, :custom_fields_trackers,
29 :custom_fields_projects
29 :custom_fields_projects
30
30
31 include Redmine::I18n
31 include Redmine::I18n
32
32
33 def setup
33 def setup
34 Setting.default_language = "en"
34 Setting.default_language = "en"
35 end
35 end
36
36
37 def test_report_at_project_level
37 def test_report_at_project_level
38 get :report, :project_id => 'ecookbook'
38 get :report, :params => {:project_id => 'ecookbook'}
39 assert_response :success
39 assert_response :success
40 assert_template 'report'
40 assert_template 'report'
41 assert_select 'form#query_form[action=?]', '/projects/ecookbook/time_entries/report'
41 assert_select 'form#query_form[action=?]', '/projects/ecookbook/time_entries/report'
42 end
42 end
43
43
44 def test_report_all_projects
44 def test_report_all_projects
45 get :report
45 get :report
46 assert_response :success
46 assert_response :success
47 assert_template 'report'
47 assert_template 'report'
48 assert_select 'form#query_form[action=?]', '/time_entries/report'
48 assert_select 'form#query_form[action=?]', '/time_entries/report'
49 end
49 end
50
50
51 def test_report_all_projects_denied
51 def test_report_all_projects_denied
52 r = Role.anonymous
52 r = Role.anonymous
53 r.permissions.delete(:view_time_entries)
53 r.permissions.delete(:view_time_entries)
54 r.permissions_will_change!
54 r.permissions_will_change!
55 r.save
55 r.save
56 get :report
56 get :report
57 assert_redirected_to '/login?back_url=http%3A%2F%2Ftest.host%2Ftime_entries%2Freport'
57 assert_redirected_to '/login?back_url=http%3A%2F%2Ftest.host%2Ftime_entries%2Freport'
58 end
58 end
59
59
60 def test_report_all_projects_one_criteria
60 def test_report_all_projects_one_criteria
61 get :report, :columns => 'week', :from => "2007-04-01", :to => "2007-04-30", :criteria => ['project']
61 get :report, :params => {:columns => 'week', :from => "2007-04-01", :to => "2007-04-30", :criteria => ['project']}
62 assert_response :success
62 assert_response :success
63 assert_template 'report'
63 assert_template 'report'
64 assert_not_nil assigns(:report)
64 assert_not_nil assigns(:report)
65 assert_equal "8.65", "%.2f" % assigns(:report).total_hours
65 assert_equal "8.65", "%.2f" % assigns(:report).total_hours
66 end
66 end
67
67
68 def test_report_all_time
68 def test_report_all_time
69 get :report, :project_id => 1, :criteria => ['project', 'issue']
69 get :report, :params => {:project_id => 1, :criteria => ['project', 'issue']}
70 assert_response :success
70 assert_response :success
71 assert_template 'report'
71 assert_template 'report'
72 assert_not_nil assigns(:report)
72 assert_not_nil assigns(:report)
73 assert_equal "162.90", "%.2f" % assigns(:report).total_hours
73 assert_equal "162.90", "%.2f" % assigns(:report).total_hours
74 end
74 end
75
75
76 def test_report_all_time_by_day
76 def test_report_all_time_by_day
77 get :report, :project_id => 1, :criteria => ['project', 'issue'], :columns => 'day'
77 get :report, :params => {:project_id => 1, :criteria => ['project', 'issue'], :columns => 'day'}
78 assert_response :success
78 assert_response :success
79 assert_template 'report'
79 assert_template 'report'
80 assert_not_nil assigns(:report)
80 assert_not_nil assigns(:report)
81 assert_equal "162.90", "%.2f" % assigns(:report).total_hours
81 assert_equal "162.90", "%.2f" % assigns(:report).total_hours
82 assert_select 'th', :text => '2007-03-12'
82 assert_select 'th', :text => '2007-03-12'
83 end
83 end
84
84
85 def test_report_one_criteria
85 def test_report_one_criteria
86 get :report, :project_id => 1, :columns => 'week', :from => "2007-04-01", :to => "2007-04-30", :criteria => ['project']
86 get :report, :params => {:project_id => 1, :columns => 'week', :from => "2007-04-01", :to => "2007-04-30", :criteria => ['project']}
87 assert_response :success
87 assert_response :success
88 assert_template 'report'
88 assert_template 'report'
89 assert_not_nil assigns(:report)
89 assert_not_nil assigns(:report)
90 assert_equal "8.65", "%.2f" % assigns(:report).total_hours
90 assert_equal "8.65", "%.2f" % assigns(:report).total_hours
91 end
91 end
92
92
93 def test_report_two_criteria
93 def test_report_two_criteria
94 get :report, :project_id => 1, :columns => 'month', :from => "2007-01-01", :to => "2007-12-31", :criteria => ["user", "activity"]
94 get :report, :params => {:project_id => 1, :columns => 'month', :from => "2007-01-01", :to => "2007-12-31", :criteria => ["user", "activity"]}
95 assert_response :success
95 assert_response :success
96 assert_template 'report'
96 assert_template 'report'
97 assert_not_nil assigns(:report)
97 assert_not_nil assigns(:report)
98 assert_equal "162.90", "%.2f" % assigns(:report).total_hours
98 assert_equal "162.90", "%.2f" % assigns(:report).total_hours
99 end
99 end
100
100
101 def test_report_custom_field_criteria_with_multiple_values_on_single_value_custom_field_should_not_fail
101 def test_report_custom_field_criteria_with_multiple_values_on_single_value_custom_field_should_not_fail
102 field = TimeEntryCustomField.create!(:name => 'multi', :field_format => 'list', :possible_values => ['value1', 'value2'])
102 field = TimeEntryCustomField.create!(:name => 'multi', :field_format => 'list', :possible_values => ['value1', 'value2'])
103 entry = TimeEntry.create!(:project => Project.find(1), :hours => 1, :activity_id => 10, :user => User.find(2), :spent_on => Date.today)
103 entry = TimeEntry.create!(:project => Project.find(1), :hours => 1, :activity_id => 10, :user => User.find(2), :spent_on => Date.today)
104 CustomValue.create!(:customized => entry, :custom_field => field, :value => 'value1')
104 CustomValue.create!(:customized => entry, :custom_field => field, :value => 'value1')
105 CustomValue.create!(:customized => entry, :custom_field => field, :value => 'value2')
105 CustomValue.create!(:customized => entry, :custom_field => field, :value => 'value2')
106
106
107 get :report, :project_id => 1, :columns => 'day', :criteria => ["cf_#{field.id}"]
107 get :report, :params => {:project_id => 1, :columns => 'day', :criteria => ["cf_#{field.id}"]}
108 assert_response :success
108 assert_response :success
109 end
109 end
110
110
111 def test_report_multiple_values_custom_fields_should_not_be_proposed
111 def test_report_multiple_values_custom_fields_should_not_be_proposed
112 TimeEntryCustomField.create!(:name => 'Single', :field_format => 'list', :possible_values => ['value1', 'value2'])
112 TimeEntryCustomField.create!(:name => 'Single', :field_format => 'list', :possible_values => ['value1', 'value2'])
113 TimeEntryCustomField.create!(:name => 'Multi', :field_format => 'list', :multiple => true, :possible_values => ['value1', 'value2'])
113 TimeEntryCustomField.create!(:name => 'Multi', :field_format => 'list', :multiple => true, :possible_values => ['value1', 'value2'])
114
114
115 get :report, :project_id => 1
115 get :report, :params => {:project_id => 1}
116 assert_response :success
116 assert_response :success
117 assert_select 'select[name=?]', 'criteria[]' do
117 assert_select 'select[name=?]', 'criteria[]' do
118 assert_select 'option', :text => 'Single'
118 assert_select 'option', :text => 'Single'
119 assert_select 'option', :text => 'Multi', :count => 0
119 assert_select 'option', :text => 'Multi', :count => 0
120 end
120 end
121 end
121 end
122
122
123 def test_report_one_day
123 def test_report_one_day
124 get :report, :project_id => 1, :columns => 'day', :from => "2007-03-23", :to => "2007-03-23", :criteria => ["user", "activity"]
124 get :report, :params => {:project_id => 1, :columns => 'day', :from => "2007-03-23", :to => "2007-03-23", :criteria => ["user", "activity"]}
125 assert_response :success
125 assert_response :success
126 assert_template 'report'
126 assert_template 'report'
127 assert_not_nil assigns(:report)
127 assert_not_nil assigns(:report)
128 assert_equal "4.25", "%.2f" % assigns(:report).total_hours
128 assert_equal "4.25", "%.2f" % assigns(:report).total_hours
129 end
129 end
130
130
131 def test_report_by_week_should_use_commercial_year
131 def test_report_by_week_should_use_commercial_year
132 TimeEntry.delete_all
132 TimeEntry.delete_all
133 TimeEntry.generate!(:hours => '2', :spent_on => '2009-12-25') # 2009-52
133 TimeEntry.generate!(:hours => '2', :spent_on => '2009-12-25') # 2009-52
134 TimeEntry.generate!(:hours => '4', :spent_on => '2009-12-31') # 2009-53
134 TimeEntry.generate!(:hours => '4', :spent_on => '2009-12-31') # 2009-53
135 TimeEntry.generate!(:hours => '8', :spent_on => '2010-01-01') # 2009-53
135 TimeEntry.generate!(:hours => '8', :spent_on => '2010-01-01') # 2009-53
136 TimeEntry.generate!(:hours => '16', :spent_on => '2010-01-05') # 2010-1
136 TimeEntry.generate!(:hours => '16', :spent_on => '2010-01-05') # 2010-1
137
137
138 get :report, :columns => 'week', :from => "2009-12-25", :to => "2010-01-05", :criteria => ["project"]
138 get :report, :params => {:columns => 'week', :from => "2009-12-25", :to => "2010-01-05", :criteria => ["project"]}
139 assert_response :success
139 assert_response :success
140
140
141 assert_select '#time-report thead tr' do
141 assert_select '#time-report thead tr' do
142 assert_select 'th:nth-child(1)', :text => 'Project'
142 assert_select 'th:nth-child(1)', :text => 'Project'
143 assert_select 'th:nth-child(2)', :text => '2009-52'
143 assert_select 'th:nth-child(2)', :text => '2009-52'
144 assert_select 'th:nth-child(3)', :text => '2009-53'
144 assert_select 'th:nth-child(3)', :text => '2009-53'
145 assert_select 'th:nth-child(4)', :text => '2010-1'
145 assert_select 'th:nth-child(4)', :text => '2010-1'
146 assert_select 'th:nth-child(5)', :text => 'Total time'
146 assert_select 'th:nth-child(5)', :text => 'Total time'
147 end
147 end
148 assert_select '#time-report tbody tr' do
148 assert_select '#time-report tbody tr' do
149 assert_select 'td:nth-child(1)', :text => 'eCookbook'
149 assert_select 'td:nth-child(1)', :text => 'eCookbook'
150 assert_select 'td:nth-child(2)', :text => '2.00'
150 assert_select 'td:nth-child(2)', :text => '2.00'
151 assert_select 'td:nth-child(3)', :text => '12.00'
151 assert_select 'td:nth-child(3)', :text => '12.00'
152 assert_select 'td:nth-child(4)', :text => '16.00'
152 assert_select 'td:nth-child(4)', :text => '16.00'
153 assert_select 'td:nth-child(5)', :text => '30.00' # Total
153 assert_select 'td:nth-child(5)', :text => '30.00' # Total
154 end
154 end
155 end
155 end
156
156
157 def test_report_should_propose_association_custom_fields
157 def test_report_should_propose_association_custom_fields
158 get :report
158 get :report
159 assert_response :success
159 assert_response :success
160 assert_template 'report'
160 assert_template 'report'
161
161
162 assert_select 'select[name=?]', 'criteria[]' do
162 assert_select 'select[name=?]', 'criteria[]' do
163 assert_select 'option[value=cf_1]', {:text => 'Database'}, 'Issue custom field not found'
163 assert_select 'option[value=cf_1]', {:text => 'Database'}, 'Issue custom field not found'
164 assert_select 'option[value=cf_3]', {:text => 'Development status'}, 'Project custom field not found'
164 assert_select 'option[value=cf_3]', {:text => 'Development status'}, 'Project custom field not found'
165 assert_select 'option[value=cf_7]', {:text => 'Billable'}, 'TimeEntryActivity custom field not found'
165 assert_select 'option[value=cf_7]', {:text => 'Billable'}, 'TimeEntryActivity custom field not found'
166 end
166 end
167 end
167 end
168
168
169 def test_report_with_association_custom_fields
169 def test_report_with_association_custom_fields
170 get :report, :criteria => ['cf_1', 'cf_3', 'cf_7']
170 get :report, :params => {:criteria => ['cf_1', 'cf_3', 'cf_7']}
171 assert_response :success
171 assert_response :success
172 assert_template 'report'
172 assert_template 'report'
173 assert_not_nil assigns(:report)
173 assert_not_nil assigns(:report)
174 assert_equal 3, assigns(:report).criteria.size
174 assert_equal 3, assigns(:report).criteria.size
175 assert_equal "162.90", "%.2f" % assigns(:report).total_hours
175 assert_equal "162.90", "%.2f" % assigns(:report).total_hours
176
176
177 # Custom fields columns
177 # Custom fields columns
178 assert_select 'th', :text => 'Database'
178 assert_select 'th', :text => 'Database'
179 assert_select 'th', :text => 'Development status'
179 assert_select 'th', :text => 'Development status'
180 assert_select 'th', :text => 'Billable'
180 assert_select 'th', :text => 'Billable'
181
181
182 # Custom field row
182 # Custom field row
183 assert_select 'tr' do
183 assert_select 'tr' do
184 assert_select 'td', :text => 'MySQL'
184 assert_select 'td', :text => 'MySQL'
185 assert_select 'td.hours', :text => '1.00'
185 assert_select 'td.hours', :text => '1.00'
186 end
186 end
187 end
187 end
188
188
189 def test_report_one_criteria_no_result
189 def test_report_one_criteria_no_result
190 get :report, :project_id => 1, :columns => 'week', :from => "1998-04-01", :to => "1998-04-30", :criteria => ['project']
190 get :report, :params => {:project_id => 1, :columns => 'week', :from => "1998-04-01", :to => "1998-04-30", :criteria => ['project']}
191 assert_response :success
191 assert_response :success
192 assert_template 'report'
192 assert_template 'report'
193 assert_not_nil assigns(:report)
193 assert_not_nil assigns(:report)
194 assert_equal "0.00", "%.2f" % assigns(:report).total_hours
194 assert_equal "0.00", "%.2f" % assigns(:report).total_hours
195 end
195 end
196
196
197 def test_report_status_criterion
197 def test_report_status_criterion
198 get :report, :project_id => 1, :criteria => ['status']
198 get :report, :params => {:project_id => 1, :criteria => ['status']}
199 assert_response :success
199 assert_response :success
200 assert_template 'report'
200 assert_template 'report'
201 assert_select 'th', :text => 'Status'
201 assert_select 'th', :text => 'Status'
202 assert_select 'td', :text => 'New'
202 assert_select 'td', :text => 'New'
203 end
203 end
204
204
205 def test_report_all_projects_csv_export
205 def test_report_all_projects_csv_export
206 get :report, :columns => 'month', :from => "2007-01-01", :to => "2007-06-30",
206 get :report, :params => {
207 :criteria => ["project", "user", "activity"], :format => "csv"
207 :columns => 'month',
208 :from => "2007-01-01",
209 :to => "2007-06-30",
210 :criteria => ["project", "user", "activity"],
211 :format => "csv"
212 }
208 assert_response :success
213 assert_response :success
209 assert_equal 'text/csv; header=present', @response.content_type
214 assert_equal 'text/csv; header=present', @response.content_type
210 lines = @response.body.chomp.split("\n")
215 lines = @response.body.chomp.split("\n")
211 # Headers
216 # Headers
212 assert_equal 'Project,User,Activity,2007-3,2007-4,Total time', lines.first
217 assert_equal 'Project,User,Activity,2007-3,2007-4,Total time', lines.first
213 # Total row
218 # Total row
214 assert_equal 'Total time,"","",154.25,8.65,162.90', lines.last
219 assert_equal 'Total time,"","",154.25,8.65,162.90', lines.last
215 end
220 end
216
221
217 def test_report_csv_export
222 def test_report_csv_export
218 get :report, :project_id => 1, :columns => 'month',
223 get :report, :params => {
219 :from => "2007-01-01", :to => "2007-06-30",
224 :project_id => 1,
220 :criteria => ["project", "user", "activity"], :format => "csv"
225 :columns => 'month',
226 :from => "2007-01-01",
227 :to => "2007-06-30",
228 :criteria => ["project", "user", "activity"],
229 :format => "csv"
230 }
221 assert_response :success
231 assert_response :success
222 assert_equal 'text/csv; header=present', @response.content_type
232 assert_equal 'text/csv; header=present', @response.content_type
223 lines = @response.body.chomp.split("\n")
233 lines = @response.body.chomp.split("\n")
224 # Headers
234 # Headers
225 assert_equal 'Project,User,Activity,2007-3,2007-4,Total time', lines.first
235 assert_equal 'Project,User,Activity,2007-3,2007-4,Total time', lines.first
226 # Total row
236 # Total row
227 assert_equal 'Total time,"","",154.25,8.65,162.90', lines.last
237 assert_equal 'Total time,"","",154.25,8.65,162.90', lines.last
228 end
238 end
229
239
230 def test_csv_big_5
240 def test_csv_big_5
231 str_utf8 = "\xe4\xb8\x80\xe6\x9c\x88".force_encoding('UTF-8')
241 str_utf8 = "\xe4\xb8\x80\xe6\x9c\x88".force_encoding('UTF-8')
232 str_big5 = "\xa4@\xa4\xeb".force_encoding('Big5')
242 str_big5 = "\xa4@\xa4\xeb".force_encoding('Big5')
233 user = User.find_by_id(3)
243 user = User.find_by_id(3)
234 user.firstname = str_utf8
244 user.firstname = str_utf8
235 user.lastname = "test-lastname"
245 user.lastname = "test-lastname"
236 assert user.save
246 assert user.save
237 comments = "test_csv_big_5"
247 comments = "test_csv_big_5"
238 te1 = TimeEntry.create(:spent_on => '2011-11-11',
248 te1 = TimeEntry.create(:spent_on => '2011-11-11',
239 :hours => 7.3,
249 :hours => 7.3,
240 :project => Project.find(1),
250 :project => Project.find(1),
241 :user => user,
251 :user => user,
242 :activity => TimeEntryActivity.find_by_name('Design'),
252 :activity => TimeEntryActivity.find_by_name('Design'),
243 :comments => comments)
253 :comments => comments)
244
254
245 te2 = TimeEntry.find_by_comments(comments)
255 te2 = TimeEntry.find_by_comments(comments)
246 assert_not_nil te2
256 assert_not_nil te2
247 assert_equal 7.3, te2.hours
257 assert_equal 7.3, te2.hours
248 assert_equal 3, te2.user_id
258 assert_equal 3, te2.user_id
249
259
250 with_settings :default_language => "zh-TW" do
260 with_settings :default_language => "zh-TW" do
251 get :report, :project_id => 1, :columns => 'day',
261 get :report, :params => {
252 :from => "2011-11-11", :to => "2011-11-11",
262 :project_id => 1,
253 :criteria => ["user"], :format => "csv"
263 :columns => 'day',
264 :from => "2011-11-11",
265 :to => "2011-11-11",
266 :criteria => ["user"],
267 :format => "csv"
268 }
254 end
269 end
255 assert_response :success
270 assert_response :success
256 assert_equal 'text/csv; header=present', @response.content_type
271 assert_equal 'text/csv; header=present', @response.content_type
257 lines = @response.body.chomp.split("\n")
272 lines = @response.body.chomp.split("\n")
258 # Headers
273 # Headers
259 s1 = "\xa5\xce\xa4\xe1,2011-11-11,\xa4u\xae\xc9\xc1`\xadp".force_encoding('Big5')
274 s1 = "\xa5\xce\xa4\xe1,2011-11-11,\xa4u\xae\xc9\xc1`\xadp".force_encoding('Big5')
260 s2 = "\xa4u\xae\xc9\xc1`\xadp".force_encoding('Big5')
275 s2 = "\xa4u\xae\xc9\xc1`\xadp".force_encoding('Big5')
261 assert_equal s1, lines.first
276 assert_equal s1, lines.first
262 # Total row
277 # Total row
263 assert_equal "#{str_big5} #{user.lastname},7.30,7.30", lines[1]
278 assert_equal "#{str_big5} #{user.lastname},7.30,7.30", lines[1]
264 assert_equal "#{s2},7.30,7.30", lines[2]
279 assert_equal "#{s2},7.30,7.30", lines[2]
265
280
266 str_tw = "Traditional Chinese (\xe7\xb9\x81\xe9\xab\x94\xe4\xb8\xad\xe6\x96\x87)".force_encoding('UTF-8')
281 str_tw = "Traditional Chinese (\xe7\xb9\x81\xe9\xab\x94\xe4\xb8\xad\xe6\x96\x87)".force_encoding('UTF-8')
267 assert_equal str_tw, l(:general_lang_name)
282 assert_equal str_tw, l(:general_lang_name)
268 assert_equal 'Big5', l(:general_csv_encoding)
283 assert_equal 'Big5', l(:general_csv_encoding)
269 assert_equal ',', l(:general_csv_separator)
284 assert_equal ',', l(:general_csv_separator)
270 assert_equal '.', l(:general_csv_decimal_separator)
285 assert_equal '.', l(:general_csv_decimal_separator)
271 end
286 end
272
287
273 def test_csv_cannot_convert_should_be_replaced_big_5
288 def test_csv_cannot_convert_should_be_replaced_big_5
274 str_utf8 = "\xe4\xbb\xa5\xe5\x86\x85".force_encoding('UTF-8')
289 str_utf8 = "\xe4\xbb\xa5\xe5\x86\x85".force_encoding('UTF-8')
275 user = User.find_by_id(3)
290 user = User.find_by_id(3)
276 user.firstname = str_utf8
291 user.firstname = str_utf8
277 user.lastname = "test-lastname"
292 user.lastname = "test-lastname"
278 assert user.save
293 assert user.save
279 comments = "test_replaced"
294 comments = "test_replaced"
280 te1 = TimeEntry.create(:spent_on => '2011-11-11',
295 te1 = TimeEntry.create(:spent_on => '2011-11-11',
281 :hours => 7.3,
296 :hours => 7.3,
282 :project => Project.find(1),
297 :project => Project.find(1),
283 :user => user,
298 :user => user,
284 :activity => TimeEntryActivity.find_by_name('Design'),
299 :activity => TimeEntryActivity.find_by_name('Design'),
285 :comments => comments)
300 :comments => comments)
286
301
287 te2 = TimeEntry.find_by_comments(comments)
302 te2 = TimeEntry.find_by_comments(comments)
288 assert_not_nil te2
303 assert_not_nil te2
289 assert_equal 7.3, te2.hours
304 assert_equal 7.3, te2.hours
290 assert_equal 3, te2.user_id
305 assert_equal 3, te2.user_id
291
306
292 with_settings :default_language => "zh-TW" do
307 with_settings :default_language => "zh-TW" do
293 get :report, :project_id => 1, :columns => 'day',
308 get :report, :params => {
294 :from => "2011-11-11", :to => "2011-11-11",
309 :project_id => 1,
295 :criteria => ["user"], :format => "csv"
310 :columns => 'day',
311 :from => "2011-11-11",
312 :to => "2011-11-11",
313 :criteria => ["user"],
314 :format => "csv"
315 }
296 end
316 end
297 assert_response :success
317 assert_response :success
298 assert_equal 'text/csv; header=present', @response.content_type
318 assert_equal 'text/csv; header=present', @response.content_type
299 lines = @response.body.chomp.split("\n")
319 lines = @response.body.chomp.split("\n")
300 # Headers
320 # Headers
301 s1 = "\xa5\xce\xa4\xe1,2011-11-11,\xa4u\xae\xc9\xc1`\xadp".force_encoding('Big5')
321 s1 = "\xa5\xce\xa4\xe1,2011-11-11,\xa4u\xae\xc9\xc1`\xadp".force_encoding('Big5')
302 assert_equal s1, lines.first
322 assert_equal s1, lines.first
303 # Total row
323 # Total row
304 s2 = "\xa5H?".force_encoding('Big5')
324 s2 = "\xa5H?".force_encoding('Big5')
305 assert_equal "#{s2} #{user.lastname},7.30,7.30", lines[1]
325 assert_equal "#{s2} #{user.lastname},7.30,7.30", lines[1]
306 end
326 end
307
327
308 def test_csv_fr
328 def test_csv_fr
309 with_settings :default_language => "fr" do
329 with_settings :default_language => "fr" do
310 str1 = "test_csv_fr"
330 str1 = "test_csv_fr"
311 user = User.find_by_id(3)
331 user = User.find_by_id(3)
312 te1 = TimeEntry.create(:spent_on => '2011-11-11',
332 te1 = TimeEntry.create(:spent_on => '2011-11-11',
313 :hours => 7.3,
333 :hours => 7.3,
314 :project => Project.find(1),
334 :project => Project.find(1),
315 :user => user,
335 :user => user,
316 :activity => TimeEntryActivity.find_by_name('Design'),
336 :activity => TimeEntryActivity.find_by_name('Design'),
317 :comments => str1)
337 :comments => str1)
318
338
319 te2 = TimeEntry.find_by_comments(str1)
339 te2 = TimeEntry.find_by_comments(str1)
320 assert_not_nil te2
340 assert_not_nil te2
321 assert_equal 7.3, te2.hours
341 assert_equal 7.3, te2.hours
322 assert_equal 3, te2.user_id
342 assert_equal 3, te2.user_id
323
343
324 get :report, :project_id => 1, :columns => 'day',
344 get :report, :params => {
325 :from => "2011-11-11", :to => "2011-11-11",
345 :project_id => 1,
326 :criteria => ["user"], :format => "csv"
346 :columns => 'day',
347 :from => "2011-11-11",
348 :to => "2011-11-11",
349 :criteria => ["user"],
350 :format => "csv"
351 }
327 assert_response :success
352 assert_response :success
328 assert_equal 'text/csv; header=present', @response.content_type
353 assert_equal 'text/csv; header=present', @response.content_type
329 lines = @response.body.chomp.split("\n")
354 lines = @response.body.chomp.split("\n")
330 # Headers
355 # Headers
331 s1 = "Utilisateur;2011-11-11;Temps total".force_encoding('ISO-8859-1')
356 s1 = "Utilisateur;2011-11-11;Temps total".force_encoding('ISO-8859-1')
332 s2 = "Temps total".force_encoding('ISO-8859-1')
357 s2 = "Temps total".force_encoding('ISO-8859-1')
333 assert_equal s1, lines.first
358 assert_equal s1, lines.first
334 # Total row
359 # Total row
335 assert_equal "#{user.firstname} #{user.lastname};7,30;7,30", lines[1]
360 assert_equal "#{user.firstname} #{user.lastname};7,30;7,30", lines[1]
336 assert_equal "#{s2};7,30;7,30", lines[2]
361 assert_equal "#{s2};7,30;7,30", lines[2]
337
362
338 str_fr = "French (Fran\xc3\xa7ais)".force_encoding('UTF-8')
363 str_fr = "French (Fran\xc3\xa7ais)".force_encoding('UTF-8')
339 assert_equal str_fr, l(:general_lang_name)
364 assert_equal str_fr, l(:general_lang_name)
340 assert_equal 'ISO-8859-1', l(:general_csv_encoding)
365 assert_equal 'ISO-8859-1', l(:general_csv_encoding)
341 assert_equal ';', l(:general_csv_separator)
366 assert_equal ';', l(:general_csv_separator)
342 assert_equal ',', l(:general_csv_decimal_separator)
367 assert_equal ',', l(:general_csv_decimal_separator)
343 end
368 end
344 end
369 end
345 end
370 end
@@ -1,841 +1,939
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 # Redmine - project management software
2 # Redmine - project management software
3 # Copyright (C) 2006-2016 Jean-Philippe Lang
3 # Copyright (C) 2006-2016 Jean-Philippe Lang
4 #
4 #
5 # This program is free software; you can redistribute it and/or
5 # This program is free software; you can redistribute it and/or
6 # modify it under the terms of the GNU General Public License
6 # modify it under the terms of the GNU General Public License
7 # as published by the Free Software Foundation; either version 2
7 # as published by the Free Software Foundation; either version 2
8 # of the License, or (at your option) any later version.
8 # of the License, or (at your option) any later version.
9 #
9 #
10 # This program is distributed in the hope that it will be useful,
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
13 # GNU General Public License for more details.
14 #
14 #
15 # You should have received a copy of the GNU General Public License
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software
16 # along with this program; if not, write to the Free Software
17 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18
18
19 require File.expand_path('../../test_helper', __FILE__)
19 require File.expand_path('../../test_helper', __FILE__)
20
20
21 class TimelogControllerTest < Redmine::ControllerTest
21 class TimelogControllerTest < Redmine::ControllerTest
22 fixtures :projects, :enabled_modules, :roles, :members,
22 fixtures :projects, :enabled_modules, :roles, :members,
23 :member_roles, :issues, :time_entries, :users,
23 :member_roles, :issues, :time_entries, :users,
24 :trackers, :enumerations, :issue_statuses,
24 :trackers, :enumerations, :issue_statuses,
25 :custom_fields, :custom_values,
25 :custom_fields, :custom_values,
26 :projects_trackers, :custom_fields_trackers,
26 :projects_trackers, :custom_fields_trackers,
27 :custom_fields_projects
27 :custom_fields_projects
28
28
29 include Redmine::I18n
29 include Redmine::I18n
30
30
31 def test_new
31 def test_new
32 @request.session[:user_id] = 3
32 @request.session[:user_id] = 3
33 get :new
33 get :new
34 assert_response :success
34 assert_response :success
35 assert_template 'new'
35 assert_template 'new'
36 assert_select 'input[name=?][type=hidden]', 'project_id', 0
36 assert_select 'input[name=?][type=hidden]', 'project_id', 0
37 assert_select 'input[name=?][type=hidden]', 'issue_id', 0
37 assert_select 'input[name=?][type=hidden]', 'issue_id', 0
38 assert_select 'select[name=?]', 'time_entry[project_id]' do
38 assert_select 'select[name=?]', 'time_entry[project_id]' do
39 # blank option for project
39 # blank option for project
40 assert_select 'option[value=""]'
40 assert_select 'option[value=""]'
41 end
41 end
42 end
42 end
43
43
44 def test_new_with_project_id
44 def test_new_with_project_id
45 @request.session[:user_id] = 3
45 @request.session[:user_id] = 3
46 get :new, :project_id => 1
46 get :new, :params => {:project_id => 1}
47 assert_response :success
47 assert_response :success
48 assert_template 'new'
48 assert_template 'new'
49 assert_select 'input[name=?][type=hidden]', 'project_id'
49 assert_select 'input[name=?][type=hidden]', 'project_id'
50 assert_select 'input[name=?][type=hidden]', 'issue_id', 0
50 assert_select 'input[name=?][type=hidden]', 'issue_id', 0
51 assert_select 'select[name=?]', 'time_entry[project_id]', 0
51 assert_select 'select[name=?]', 'time_entry[project_id]', 0
52 end
52 end
53
53
54 def test_new_with_issue_id
54 def test_new_with_issue_id
55 @request.session[:user_id] = 3
55 @request.session[:user_id] = 3
56 get :new, :issue_id => 2
56 get :new, :params => {:issue_id => 2}
57 assert_response :success
57 assert_response :success
58 assert_template 'new'
58 assert_template 'new'
59 assert_select 'input[name=?][type=hidden]', 'project_id', 0
59 assert_select 'input[name=?][type=hidden]', 'project_id', 0
60 assert_select 'input[name=?][type=hidden]', 'issue_id'
60 assert_select 'input[name=?][type=hidden]', 'issue_id'
61 assert_select 'select[name=?]', 'time_entry[project_id]', 0
61 assert_select 'select[name=?]', 'time_entry[project_id]', 0
62 end
62 end
63
63
64 def test_new_without_project_should_prefill_the_form
64 def test_new_without_project_should_prefill_the_form
65 @request.session[:user_id] = 3
65 @request.session[:user_id] = 3
66 get :new, :time_entry => {:project_id => '1'}
66 get :new, :params => {:time_entry => {:project_id => '1'}}
67 assert_response :success
67 assert_response :success
68 assert_template 'new'
68 assert_template 'new'
69 assert_select 'select[name=?]', 'time_entry[project_id]' do
69 assert_select 'select[name=?]', 'time_entry[project_id]' do
70 assert_select 'option[value="1"][selected=selected]'
70 assert_select 'option[value="1"][selected=selected]'
71 end
71 end
72 end
72 end
73
73
74 def test_new_without_project_should_deny_without_permission
74 def test_new_without_project_should_deny_without_permission
75 Role.all.each {|role| role.remove_permission! :log_time}
75 Role.all.each {|role| role.remove_permission! :log_time}
76 @request.session[:user_id] = 3
76 @request.session[:user_id] = 3
77
77
78 get :new
78 get :new
79 assert_response 403
79 assert_response 403
80 end
80 end
81
81
82 def test_new_should_select_default_activity
82 def test_new_should_select_default_activity
83 @request.session[:user_id] = 3
83 @request.session[:user_id] = 3
84 get :new, :project_id => 1
84 get :new, :params => {:project_id => 1}
85 assert_response :success
85 assert_response :success
86 assert_select 'select[name=?]', 'time_entry[activity_id]' do
86 assert_select 'select[name=?]', 'time_entry[activity_id]' do
87 assert_select 'option[selected=selected]', :text => 'Development'
87 assert_select 'option[selected=selected]', :text => 'Development'
88 end
88 end
89 end
89 end
90
90
91 def test_new_should_only_show_active_time_entry_activities
91 def test_new_should_only_show_active_time_entry_activities
92 @request.session[:user_id] = 3
92 @request.session[:user_id] = 3
93 get :new, :project_id => 1
93 get :new, :params => {:project_id => 1}
94 assert_response :success
94 assert_response :success
95 assert_select 'option', :text => 'Inactive Activity', :count => 0
95 assert_select 'option', :text => 'Inactive Activity', :count => 0
96 end
96 end
97
97
98 def test_post_new_as_js_should_update_activity_options
98 def test_post_new_as_js_should_update_activity_options
99 @request.session[:user_id] = 3
99 @request.session[:user_id] = 3
100 post :new, :time_entry => {:project_id => 1}, :format => 'js'
100 post :new, :params => {:time_entry => {:project_id => 1}, :format => 'js'}
101 assert_response :success
101 assert_response :success
102 assert_include '#time_entry_activity_id', response.body
102 assert_include '#time_entry_activity_id', response.body
103 end
103 end
104
104
105 def test_get_edit_existing_time
105 def test_get_edit_existing_time
106 @request.session[:user_id] = 2
106 @request.session[:user_id] = 2
107 get :edit, :id => 2, :project_id => nil
107 get :edit, :params => {:id => 2, :project_id => nil}
108 assert_response :success
108 assert_response :success
109 assert_template 'edit'
109 assert_template 'edit'
110 assert_select 'form[action=?]', '/time_entries/2'
110 assert_select 'form[action=?]', '/time_entries/2'
111 end
111 end
112
112
113 def test_get_edit_with_an_existing_time_entry_with_inactive_activity
113 def test_get_edit_with_an_existing_time_entry_with_inactive_activity
114 te = TimeEntry.find(1)
114 te = TimeEntry.find(1)
115 te.activity = TimeEntryActivity.find_by_name("Inactive Activity")
115 te.activity = TimeEntryActivity.find_by_name("Inactive Activity")
116 te.save!(:validate => false)
116 te.save!(:validate => false)
117
117
118 @request.session[:user_id] = 1
118 @request.session[:user_id] = 1
119 get :edit, :project_id => 1, :id => 1
119 get :edit, :params => {:project_id => 1, :id => 1}
120 assert_response :success
120 assert_response :success
121 assert_template 'edit'
121 assert_template 'edit'
122 # Blank option since nothing is pre-selected
122 # Blank option since nothing is pre-selected
123 assert_select 'option', :text => '--- Please select ---'
123 assert_select 'option', :text => '--- Please select ---'
124 end
124 end
125
125
126 def test_post_create
126 def test_post_create
127 @request.session[:user_id] = 3
127 @request.session[:user_id] = 3
128 assert_difference 'TimeEntry.count' do
128 assert_difference 'TimeEntry.count' do
129 post :create, :project_id => 1,
129 post :create, :params => {
130 :time_entry => {:comments => 'Some work on TimelogControllerTest',
130 :project_id => 1,
131 # Not the default activity
131 :time_entry => {:comments => 'Some work on TimelogControllerTest',
132 :activity_id => '11',
132 # Not the default activity
133 :spent_on => '2008-03-14',
133 :activity_id => '11',
134 :issue_id => '1',
134 :spent_on => '2008-03-14',
135 :hours => '7.3'}
135 :issue_id => '1',
136 :hours => '7.3'
137 }
138 }
136 assert_redirected_to '/projects/ecookbook/time_entries'
139 assert_redirected_to '/projects/ecookbook/time_entries'
137 end
140 end
138
141
139 t = TimeEntry.order('id DESC').first
142 t = TimeEntry.order('id DESC').first
140 assert_not_nil t
143 assert_not_nil t
141 assert_equal 'Some work on TimelogControllerTest', t.comments
144 assert_equal 'Some work on TimelogControllerTest', t.comments
142 assert_equal 1, t.project_id
145 assert_equal 1, t.project_id
143 assert_equal 1, t.issue_id
146 assert_equal 1, t.issue_id
144 assert_equal 11, t.activity_id
147 assert_equal 11, t.activity_id
145 assert_equal 7.3, t.hours
148 assert_equal 7.3, t.hours
146 assert_equal 3, t.user_id
149 assert_equal 3, t.user_id
147 end
150 end
148
151
149 def test_post_create_with_blank_issue
152 def test_post_create_with_blank_issue
150 @request.session[:user_id] = 3
153 @request.session[:user_id] = 3
151 assert_difference 'TimeEntry.count' do
154 assert_difference 'TimeEntry.count' do
152 post :create, :project_id => 1,
155 post :create, :params => {
153 :time_entry => {:comments => 'Some work on TimelogControllerTest',
156 :project_id => 1,
154 # Not the default activity
157 :time_entry => {
155 :activity_id => '11',
158 :comments => 'Some work on TimelogControllerTest',
156 :issue_id => '',
159 # Not the default activity
157 :spent_on => '2008-03-14',
160 :activity_id => '11',
158 :hours => '7.3'}
161 :issue_id => '',
162 :spent_on => '2008-03-14',
163 :hours => '7.3'
164 }
165 }
159 assert_redirected_to '/projects/ecookbook/time_entries'
166 assert_redirected_to '/projects/ecookbook/time_entries'
160 end
167 end
161
168
162 t = TimeEntry.order('id DESC').first
169 t = TimeEntry.order('id DESC').first
163 assert_not_nil t
170 assert_not_nil t
164 assert_equal 'Some work on TimelogControllerTest', t.comments
171 assert_equal 'Some work on TimelogControllerTest', t.comments
165 assert_equal 1, t.project_id
172 assert_equal 1, t.project_id
166 assert_nil t.issue_id
173 assert_nil t.issue_id
167 assert_equal 11, t.activity_id
174 assert_equal 11, t.activity_id
168 assert_equal 7.3, t.hours
175 assert_equal 7.3, t.hours
169 assert_equal 3, t.user_id
176 assert_equal 3, t.user_id
170 end
177 end
171
178
172 def test_create_on_project_with_time_tracking_disabled_should_fail
179 def test_create_on_project_with_time_tracking_disabled_should_fail
173 Project.find(1).disable_module! :time_tracking
180 Project.find(1).disable_module! :time_tracking
174
181
175 @request.session[:user_id] = 2
182 @request.session[:user_id] = 2
176 assert_no_difference 'TimeEntry.count' do
183 assert_no_difference 'TimeEntry.count' do
177 post :create, :time_entry => {
184 post :create, :params => {
178 :project_id => '1', :issue_id => '',
185 :time_entry => {
179 :activity_id => '11', :spent_on => '2008-03-14', :hours => '7.3'
186 :project_id => '1', :issue_id => '',
187 :activity_id => '11', :spent_on => '2008-03-14', :hours => '7.3'
188 }
180 }
189 }
181 end
190 end
182 end
191 end
183
192
184 def test_create_on_project_without_permission_should_fail
193 def test_create_on_project_without_permission_should_fail
185 Role.find(1).remove_permission! :log_time
194 Role.find(1).remove_permission! :log_time
186
195
187 @request.session[:user_id] = 2
196 @request.session[:user_id] = 2
188 assert_no_difference 'TimeEntry.count' do
197 assert_no_difference 'TimeEntry.count' do
189 post :create, :time_entry => {
198 post :create, :params => {
190 :project_id => '1', :issue_id => '',
199 :time_entry => {
191 :activity_id => '11', :spent_on => '2008-03-14', :hours => '7.3'
200 :project_id => '1', :issue_id => '',
201 :activity_id => '11', :spent_on => '2008-03-14', :hours => '7.3'
202 }
192 }
203 }
193 end
204 end
194 end
205 end
195
206
196 def test_create_on_issue_in_project_with_time_tracking_disabled_should_fail
207 def test_create_on_issue_in_project_with_time_tracking_disabled_should_fail
197 Project.find(1).disable_module! :time_tracking
208 Project.find(1).disable_module! :time_tracking
198
209
199 @request.session[:user_id] = 2
210 @request.session[:user_id] = 2
200 assert_no_difference 'TimeEntry.count' do
211 assert_no_difference 'TimeEntry.count' do
201 post :create, :time_entry => {
212 post :create, :params => {
202 :project_id => '', :issue_id => '1',
213 :time_entry => {
203 :activity_id => '11', :spent_on => '2008-03-14', :hours => '7.3'
214 :project_id => '', :issue_id => '1',
215 :activity_id => '11', :spent_on => '2008-03-14', :hours => '7.3'
216 }
204 }
217 }
205 assert_select_error /Issue is invalid/
218 assert_select_error /Issue is invalid/
206 end
219 end
207 end
220 end
208
221
209 def test_create_on_issue_in_project_without_permission_should_fail
222 def test_create_on_issue_in_project_without_permission_should_fail
210 Role.find(1).remove_permission! :log_time
223 Role.find(1).remove_permission! :log_time
211
224
212 @request.session[:user_id] = 2
225 @request.session[:user_id] = 2
213 assert_no_difference 'TimeEntry.count' do
226 assert_no_difference 'TimeEntry.count' do
214 post :create, :time_entry => {
227 post :create, :params => {
215 :project_id => '', :issue_id => '1',
228 :time_entry => {
216 :activity_id => '11', :spent_on => '2008-03-14', :hours => '7.3'
229 :project_id => '', :issue_id => '1',
230 :activity_id => '11', :spent_on => '2008-03-14', :hours => '7.3'
231 }
217 }
232 }
218 assert_select_error /Issue is invalid/
233 assert_select_error /Issue is invalid/
219 end
234 end
220 end
235 end
221
236
222 def test_create_on_issue_that_is_not_visible_should_not_disclose_subject
237 def test_create_on_issue_that_is_not_visible_should_not_disclose_subject
223 issue = Issue.generate!(:subject => "issue_that_is_not_visible", :is_private => true)
238 issue = Issue.generate!(:subject => "issue_that_is_not_visible", :is_private => true)
224 assert !issue.visible?(User.find(3))
239 assert !issue.visible?(User.find(3))
225
240
226 @request.session[:user_id] = 3
241 @request.session[:user_id] = 3
227 assert_no_difference 'TimeEntry.count' do
242 assert_no_difference 'TimeEntry.count' do
228 post :create, :time_entry => {
243 post :create, :params => {
229 :project_id => '', :issue_id => issue.id.to_s,
244 :time_entry => {
230 :activity_id => '11', :spent_on => '2008-03-14', :hours => '7.3'
245 :project_id => '', :issue_id => issue.id.to_s,
246 :activity_id => '11', :spent_on => '2008-03-14', :hours => '7.3'
247 }
231 }
248 }
232 end
249 end
233 assert_select_error /Issue is invalid/
250 assert_select_error /Issue is invalid/
234 assert_select "input[name=?][value=?]", "time_entry[issue_id]", issue.id.to_s
251 assert_select "input[name=?][value=?]", "time_entry[issue_id]", issue.id.to_s
235 assert_select "#time_entry_issue", 0
252 assert_select "#time_entry_issue", 0
236 assert !response.body.include?('issue_that_is_not_visible')
253 assert !response.body.include?('issue_that_is_not_visible')
237 end
254 end
238
255
239 def test_create_and_continue_at_project_level
256 def test_create_and_continue_at_project_level
240 @request.session[:user_id] = 2
257 @request.session[:user_id] = 2
241 assert_difference 'TimeEntry.count' do
258 assert_difference 'TimeEntry.count' do
242 post :create, :time_entry => {:project_id => '1',
259 post :create, :params => {
243 :activity_id => '11',
260 :time_entry => {
244 :issue_id => '',
261 :project_id => '1',
245 :spent_on => '2008-03-14',
262 :activity_id => '11',
246 :hours => '7.3'},
263 :issue_id => '',
247 :continue => '1'
264 :spent_on => '2008-03-14',
265 :hours => '7.3'
266 },
267 :continue => '1'
268 }
248 assert_redirected_to '/time_entries/new?time_entry%5Bactivity_id%5D=11&time_entry%5Bissue_id%5D=&time_entry%5Bproject_id%5D=1'
269 assert_redirected_to '/time_entries/new?time_entry%5Bactivity_id%5D=11&time_entry%5Bissue_id%5D=&time_entry%5Bproject_id%5D=1'
249 end
270 end
250 end
271 end
251
272
252 def test_create_and_continue_at_issue_level
273 def test_create_and_continue_at_issue_level
253 @request.session[:user_id] = 2
274 @request.session[:user_id] = 2
254 assert_difference 'TimeEntry.count' do
275 assert_difference 'TimeEntry.count' do
255 post :create, :time_entry => {:project_id => '',
276 post :create, :params => {
256 :activity_id => '11',
277 :time_entry => {
257 :issue_id => '1',
278 :project_id => '',
258 :spent_on => '2008-03-14',
279 :activity_id => '11',
259 :hours => '7.3'},
280 :issue_id => '1',
260 :continue => '1'
281 :spent_on => '2008-03-14',
282 :hours => '7.3'
283 },
284 :continue => '1'
285 }
261 assert_redirected_to '/time_entries/new?time_entry%5Bactivity_id%5D=11&time_entry%5Bissue_id%5D=1&time_entry%5Bproject_id%5D='
286 assert_redirected_to '/time_entries/new?time_entry%5Bactivity_id%5D=11&time_entry%5Bissue_id%5D=1&time_entry%5Bproject_id%5D='
262 end
287 end
263 end
288 end
264
289
265 def test_create_and_continue_with_project_id
290 def test_create_and_continue_with_project_id
266 @request.session[:user_id] = 2
291 @request.session[:user_id] = 2
267 assert_difference 'TimeEntry.count' do
292 assert_difference 'TimeEntry.count' do
268 post :create, :project_id => 1,
293 post :create, :params => {
269 :time_entry => {:activity_id => '11',
294 :project_id => 1,
270 :issue_id => '',
295 :time_entry => {
271 :spent_on => '2008-03-14',
296 :activity_id => '11',
272 :hours => '7.3'},
297 :issue_id => '',
273 :continue => '1'
298 :spent_on => '2008-03-14',
299 :hours => '7.3'
300 },
301 :continue => '1'
302 }
274 assert_redirected_to '/projects/ecookbook/time_entries/new?time_entry%5Bactivity_id%5D=11&time_entry%5Bissue_id%5D=&time_entry%5Bproject_id%5D='
303 assert_redirected_to '/projects/ecookbook/time_entries/new?time_entry%5Bactivity_id%5D=11&time_entry%5Bissue_id%5D=&time_entry%5Bproject_id%5D='
275 end
304 end
276 end
305 end
277
306
278 def test_create_and_continue_with_issue_id
307 def test_create_and_continue_with_issue_id
279 @request.session[:user_id] = 2
308 @request.session[:user_id] = 2
280 assert_difference 'TimeEntry.count' do
309 assert_difference 'TimeEntry.count' do
281 post :create, :issue_id => 1,
310 post :create, :params => {
282 :time_entry => {:activity_id => '11',
311 :issue_id => 1,
283 :issue_id => '1',
312 :time_entry => {
284 :spent_on => '2008-03-14',
313 :activity_id => '11',
285 :hours => '7.3'},
314 :issue_id => '1',
286 :continue => '1'
315 :spent_on => '2008-03-14',
316 :hours => '7.3'
317 },
318 :continue => '1'
319 }
287 assert_redirected_to '/issues/1/time_entries/new?time_entry%5Bactivity_id%5D=11&time_entry%5Bissue_id%5D=1&time_entry%5Bproject_id%5D='
320 assert_redirected_to '/issues/1/time_entries/new?time_entry%5Bactivity_id%5D=11&time_entry%5Bissue_id%5D=1&time_entry%5Bproject_id%5D='
288 end
321 end
289 end
322 end
290
323
291 def test_create_without_log_time_permission_should_be_denied
324 def test_create_without_log_time_permission_should_be_denied
292 @request.session[:user_id] = 2
325 @request.session[:user_id] = 2
293 Role.find_by_name('Manager').remove_permission! :log_time
326 Role.find_by_name('Manager').remove_permission! :log_time
294 post :create, :project_id => 1,
327 post :create, :params => {
295 :time_entry => {:activity_id => '11',
328 :project_id => 1,
296 :issue_id => '',
329 :time_entry => {
297 :spent_on => '2008-03-14',
330 :activity_id => '11',
298 :hours => '7.3'}
331 :issue_id => '',
299
332 :spent_on => '2008-03-14',
333 :hours => '7.3'
334 }
335 }
300 assert_response 403
336 assert_response 403
301 end
337 end
302
338
303 def test_create_without_project_and_issue_should_fail
339 def test_create_without_project_and_issue_should_fail
304 @request.session[:user_id] = 2
340 @request.session[:user_id] = 2
305 post :create, :time_entry => {:issue_id => ''}
341 post :create, :params => {:time_entry => {:issue_id => ''}}
306
342
307 assert_response :success
343 assert_response :success
308 assert_template 'new'
344 assert_template 'new'
309 end
345 end
310
346
311 def test_create_with_failure
347 def test_create_with_failure
312 @request.session[:user_id] = 2
348 @request.session[:user_id] = 2
313 post :create, :project_id => 1,
349 post :create, :params => {
314 :time_entry => {:activity_id => '',
350 :project_id => 1,
315 :issue_id => '',
351 :time_entry => {
316 :spent_on => '2008-03-14',
352 :activity_id => '',
317 :hours => '7.3'}
353 :issue_id => '',
318
354 :spent_on => '2008-03-14',
355 :hours => '7.3'
356 }
357 }
319 assert_response :success
358 assert_response :success
320 assert_template 'new'
359 assert_template 'new'
321 end
360 end
322
361
323 def test_create_without_project
362 def test_create_without_project
324 @request.session[:user_id] = 2
363 @request.session[:user_id] = 2
325 assert_difference 'TimeEntry.count' do
364 assert_difference 'TimeEntry.count' do
326 post :create, :time_entry => {:project_id => '1',
365 post :create, :params => {
327 :activity_id => '11',
366 :time_entry => {
328 :issue_id => '',
367 :project_id => '1',
329 :spent_on => '2008-03-14',
368 :activity_id => '11',
330 :hours => '7.3'}
369 :issue_id => '',
370 :spent_on => '2008-03-14',
371 :hours => '7.3'
372 }
373 }
331 end
374 end
332
375
333 assert_redirected_to '/projects/ecookbook/time_entries'
376 assert_redirected_to '/projects/ecookbook/time_entries'
334 time_entry = TimeEntry.order('id DESC').first
377 time_entry = TimeEntry.order('id DESC').first
335 assert_equal 1, time_entry.project_id
378 assert_equal 1, time_entry.project_id
336 end
379 end
337
380
338 def test_create_without_project_should_fail_with_issue_not_inside_project
381 def test_create_without_project_should_fail_with_issue_not_inside_project
339 @request.session[:user_id] = 2
382 @request.session[:user_id] = 2
340 assert_no_difference 'TimeEntry.count' do
383 assert_no_difference 'TimeEntry.count' do
341 post :create, :time_entry => {:project_id => '1',
384 post :create, :params => {
342 :activity_id => '11',
385 :time_entry => {
343 :issue_id => '5',
386 :project_id => '1',
344 :spent_on => '2008-03-14',
387 :activity_id => '11',
345 :hours => '7.3'}
388 :issue_id => '5',
389 :spent_on => '2008-03-14',
390 :hours => '7.3'
391 }
392 }
346 end
393 end
347
394
348 assert_response :success
395 assert_response :success
349 assert assigns(:time_entry).errors[:issue_id].present?
396 assert assigns(:time_entry).errors[:issue_id].present?
350 end
397 end
351
398
352 def test_create_without_project_should_deny_without_permission
399 def test_create_without_project_should_deny_without_permission
353 @request.session[:user_id] = 2
400 @request.session[:user_id] = 2
354 Project.find(3).disable_module!(:time_tracking)
401 Project.find(3).disable_module!(:time_tracking)
355
402
356 assert_no_difference 'TimeEntry.count' do
403 assert_no_difference 'TimeEntry.count' do
357 post :create, :time_entry => {:project_id => '3',
404 post :create, :params => {
358 :activity_id => '11',
405 :time_entry => {
359 :issue_id => '',
406 :project_id => '3',
360 :spent_on => '2008-03-14',
407 :activity_id => '11',
361 :hours => '7.3'}
408 :issue_id => '',
409 :spent_on => '2008-03-14',
410 :hours => '7.3'
411 }
412 }
362 end
413 end
363
414
364 assert_response 403
415 assert_response 403
365 end
416 end
366
417
367 def test_create_without_project_with_failure
418 def test_create_without_project_with_failure
368 @request.session[:user_id] = 2
419 @request.session[:user_id] = 2
369 assert_no_difference 'TimeEntry.count' do
420 assert_no_difference 'TimeEntry.count' do
370 post :create, :time_entry => {:project_id => '1',
421 post :create, :params => {
371 :activity_id => '11',
422 :time_entry => {
372 :issue_id => '',
423 :project_id => '1',
373 :spent_on => '2008-03-14',
424 :activity_id => '11',
374 :hours => ''}
425 :issue_id => '',
426 :spent_on => '2008-03-14',
427 :hours => ''
428 }
429 }
375 end
430 end
376
431
377 assert_response :success
432 assert_response :success
378 assert_select 'select[name=?]', 'time_entry[project_id]' do
433 assert_select 'select[name=?]', 'time_entry[project_id]' do
379 assert_select 'option[value="1"][selected=selected]'
434 assert_select 'option[value="1"][selected=selected]'
380 end
435 end
381 end
436 end
382
437
383 def test_update
438 def test_update
384 entry = TimeEntry.find(1)
439 entry = TimeEntry.find(1)
385 assert_equal 1, entry.issue_id
440 assert_equal 1, entry.issue_id
386 assert_equal 2, entry.user_id
441 assert_equal 2, entry.user_id
387
442
388 @request.session[:user_id] = 1
443 @request.session[:user_id] = 1
389 put :update, :id => 1,
444 put :update, :params => {
390 :time_entry => {:issue_id => '2',
445 :id => 1,
391 :hours => '8'}
446 :time_entry => {
447 :issue_id => '2',
448 :hours => '8'
449 }
450 }
392 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
451 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
393 entry.reload
452 entry.reload
394
453
395 assert_equal 8, entry.hours
454 assert_equal 8, entry.hours
396 assert_equal 2, entry.issue_id
455 assert_equal 2, entry.issue_id
397 assert_equal 2, entry.user_id
456 assert_equal 2, entry.user_id
398 end
457 end
399
458
400 def test_update_should_allow_to_change_issue_to_another_project
459 def test_update_should_allow_to_change_issue_to_another_project
401 entry = TimeEntry.generate!(:issue_id => 1)
460 entry = TimeEntry.generate!(:issue_id => 1)
402
461
403 @request.session[:user_id] = 1
462 @request.session[:user_id] = 1
404 put :update, :id => entry.id, :time_entry => {:issue_id => '5'}
463 put :update, :params => {
464 :id => entry.id,
465 :time_entry => {
466 :issue_id => '5'
467 }
468 }
405 assert_response 302
469 assert_response 302
406 entry.reload
470 entry.reload
407
471
408 assert_equal 5, entry.issue_id
472 assert_equal 5, entry.issue_id
409 assert_equal 3, entry.project_id
473 assert_equal 3, entry.project_id
410 end
474 end
411
475
412 def test_update_should_not_allow_to_change_issue_to_an_invalid_project
476 def test_update_should_not_allow_to_change_issue_to_an_invalid_project
413 entry = TimeEntry.generate!(:issue_id => 1)
477 entry = TimeEntry.generate!(:issue_id => 1)
414 Project.find(3).disable_module!(:time_tracking)
478 Project.find(3).disable_module!(:time_tracking)
415
479
416 @request.session[:user_id] = 1
480 @request.session[:user_id] = 1
417 put :update, :id => entry.id, :time_entry => {:issue_id => '5'}
481 put :update, :params => {
482 :id => entry.id,
483 :time_entry => {
484 :issue_id => '5'
485 }
486 }
418 assert_response 200
487 assert_response 200
419 assert_include "Issue is invalid", assigns(:time_entry).errors.full_messages
488 assert_include "Issue is invalid", assigns(:time_entry).errors.full_messages
420 end
489 end
421
490
422 def test_get_bulk_edit
491 def test_get_bulk_edit
423 @request.session[:user_id] = 2
492 @request.session[:user_id] = 2
424 get :bulk_edit, :ids => [1, 2]
493
494 get :bulk_edit, :params => {:ids => [1, 2]}
425 assert_response :success
495 assert_response :success
426 assert_template 'bulk_edit'
496 assert_template 'bulk_edit'
427
497
428 assert_select 'ul#bulk-selection' do
498 assert_select 'ul#bulk-selection' do
429 assert_select 'li', 2
499 assert_select 'li', 2
430 assert_select 'li a', :text => '03/23/2007 - eCookbook: 4.25 hours'
500 assert_select 'li a', :text => '03/23/2007 - eCookbook: 4.25 hours'
431 end
501 end
432
502
433 assert_select 'form#bulk_edit_form[action=?]', '/time_entries/bulk_update' do
503 assert_select 'form#bulk_edit_form[action=?]', '/time_entries/bulk_update' do
434 # System wide custom field
504 # System wide custom field
435 assert_select 'select[name=?]', 'time_entry[custom_field_values][10]'
505 assert_select 'select[name=?]', 'time_entry[custom_field_values][10]'
436
506
437 # Activities
507 # Activities
438 assert_select 'select[name=?]', 'time_entry[activity_id]' do
508 assert_select 'select[name=?]', 'time_entry[activity_id]' do
439 assert_select 'option[value=""]', :text => '(No change)'
509 assert_select 'option[value=""]', :text => '(No change)'
440 assert_select 'option[value="9"]', :text => 'Design'
510 assert_select 'option[value="9"]', :text => 'Design'
441 end
511 end
442 end
512 end
443 end
513 end
444
514
445 def test_get_bulk_edit_on_different_projects
515 def test_get_bulk_edit_on_different_projects
446 @request.session[:user_id] = 2
516 @request.session[:user_id] = 2
447 get :bulk_edit, :ids => [1, 2, 6]
517
518 get :bulk_edit, :params => {:ids => [1, 2, 6]}
448 assert_response :success
519 assert_response :success
449 assert_template 'bulk_edit'
520 assert_template 'bulk_edit'
450 end
521 end
451
522
452 def test_bulk_edit_with_edit_own_time_entries_permission
523 def test_bulk_edit_with_edit_own_time_entries_permission
453 @request.session[:user_id] = 2
524 @request.session[:user_id] = 2
454 Role.find_by_name('Manager').remove_permission! :edit_time_entries
525 Role.find_by_name('Manager').remove_permission! :edit_time_entries
455 Role.find_by_name('Manager').add_permission! :edit_own_time_entries
526 Role.find_by_name('Manager').add_permission! :edit_own_time_entries
456 ids = (0..1).map {TimeEntry.generate!(:user => User.find(2)).id}
527 ids = (0..1).map {TimeEntry.generate!(:user => User.find(2)).id}
457
528
458 get :bulk_edit, :ids => ids
529 get :bulk_edit, :params => {:ids => ids}
459 assert_response :success
530 assert_response :success
460 end
531 end
461
532
462 def test_bulk_update
533 def test_bulk_update
463 @request.session[:user_id] = 2
534 @request.session[:user_id] = 2
464 # update time entry activity
535 # update time entry activity
465 post :bulk_update, :ids => [1, 2], :time_entry => { :activity_id => 9}
536 post :bulk_update, :params => {:ids => [1, 2], :time_entry => { :activity_id => 9}}
466
537
467 assert_response 302
538 assert_response 302
468 # check that the issues were updated
539 # check that the issues were updated
469 assert_equal [9, 9], TimeEntry.where(:id => [1, 2]).collect {|i| i.activity_id}
540 assert_equal [9, 9], TimeEntry.where(:id => [1, 2]).collect {|i| i.activity_id}
470 end
541 end
471
542
472 def test_bulk_update_with_failure
543 def test_bulk_update_with_failure
473 @request.session[:user_id] = 2
544 @request.session[:user_id] = 2
474 post :bulk_update, :ids => [1, 2], :time_entry => { :hours => 'A'}
545 post :bulk_update, :params => {:ids => [1, 2], :time_entry => { :hours => 'A'}}
475
546
476 assert_response 302
547 assert_response 302
477 assert_match /Failed to save 2 time entrie/, flash[:error]
548 assert_match /Failed to save 2 time entrie/, flash[:error]
478 end
549 end
479
550
480 def test_bulk_update_on_different_projects
551 def test_bulk_update_on_different_projects
481 @request.session[:user_id] = 2
552 @request.session[:user_id] = 2
482 # makes user a manager on the other project
553 # makes user a manager on the other project
483 Member.create!(:user_id => 2, :project_id => 3, :role_ids => [1])
554 Member.create!(:user_id => 2, :project_id => 3, :role_ids => [1])
484
555
485 # update time entry activity
556 # update time entry activity
486 post :bulk_update, :ids => [1, 2, 4], :time_entry => { :activity_id => 9 }
557 post :bulk_update, :params => {:ids => [1, 2, 4], :time_entry => { :activity_id => 9 }}
487
558
488 assert_response 302
559 assert_response 302
489 # check that the issues were updated
560 # check that the issues were updated
490 assert_equal [9, 9, 9], TimeEntry.where(:id => [1, 2, 4]).collect {|i| i.activity_id}
561 assert_equal [9, 9, 9], TimeEntry.where(:id => [1, 2, 4]).collect {|i| i.activity_id}
491 end
562 end
492
563
493 def test_bulk_update_on_different_projects_without_rights
564 def test_bulk_update_on_different_projects_without_rights
494 @request.session[:user_id] = 3
565 @request.session[:user_id] = 3
495 user = User.find(3)
566 user = User.find(3)
496 action = { :controller => "timelog", :action => "bulk_update" }
567 action = { :controller => "timelog", :action => "bulk_update" }
497 assert user.allowed_to?(action, TimeEntry.find(1).project)
568 assert user.allowed_to?(action, TimeEntry.find(1).project)
498 assert ! user.allowed_to?(action, TimeEntry.find(5).project)
569 assert ! user.allowed_to?(action, TimeEntry.find(5).project)
499 post :bulk_update, :ids => [1, 5], :time_entry => { :activity_id => 9 }
570
571 post :bulk_update, :params => {:ids => [1, 5], :time_entry => { :activity_id => 9 }}
500 assert_response 403
572 assert_response 403
501 end
573 end
502
574
503 def test_bulk_update_with_edit_own_time_entries_permission
575 def test_bulk_update_with_edit_own_time_entries_permission
504 @request.session[:user_id] = 2
576 @request.session[:user_id] = 2
505 Role.find_by_name('Manager').remove_permission! :edit_time_entries
577 Role.find_by_name('Manager').remove_permission! :edit_time_entries
506 Role.find_by_name('Manager').add_permission! :edit_own_time_entries
578 Role.find_by_name('Manager').add_permission! :edit_own_time_entries
507 ids = (0..1).map {TimeEntry.generate!(:user => User.find(2)).id}
579 ids = (0..1).map {TimeEntry.generate!(:user => User.find(2)).id}
508
580
509 post :bulk_update, :ids => ids, :time_entry => { :activity_id => 9 }
581 post :bulk_update, :params => {:ids => ids, :time_entry => { :activity_id => 9 }}
510 assert_response 302
582 assert_response 302
511 end
583 end
512
584
513 def test_bulk_update_with_edit_own_time_entries_permissions_should_be_denied_for_time_entries_of_other_user
585 def test_bulk_update_with_edit_own_time_entries_permissions_should_be_denied_for_time_entries_of_other_user
514 @request.session[:user_id] = 2
586 @request.session[:user_id] = 2
515 Role.find_by_name('Manager').remove_permission! :edit_time_entries
587 Role.find_by_name('Manager').remove_permission! :edit_time_entries
516 Role.find_by_name('Manager').add_permission! :edit_own_time_entries
588 Role.find_by_name('Manager').add_permission! :edit_own_time_entries
517
589
518 post :bulk_update, :ids => [1, 2], :time_entry => { :activity_id => 9 }
590 post :bulk_update, :params => {:ids => [1, 2], :time_entry => { :activity_id => 9 }}
519 assert_response 403
591 assert_response 403
520 end
592 end
521
593
522 def test_bulk_update_custom_field
594 def test_bulk_update_custom_field
523 @request.session[:user_id] = 2
595 @request.session[:user_id] = 2
524 post :bulk_update, :ids => [1, 2], :time_entry => { :custom_field_values => {'10' => '0'} }
596 post :bulk_update, :params => {:ids => [1, 2], :time_entry => { :custom_field_values => {'10' => '0'} }}
525
597
526 assert_response 302
598 assert_response 302
527 assert_equal ["0", "0"], TimeEntry.where(:id => [1, 2]).collect {|i| i.custom_value_for(10).value}
599 assert_equal ["0", "0"], TimeEntry.where(:id => [1, 2]).collect {|i| i.custom_value_for(10).value}
528 end
600 end
529
601
530 def test_bulk_update_clear_custom_field
602 def test_bulk_update_clear_custom_field
531 field = TimeEntryCustomField.generate!(:field_format => 'string')
603 field = TimeEntryCustomField.generate!(:field_format => 'string')
532 @request.session[:user_id] = 2
604 @request.session[:user_id] = 2
533 post :bulk_update, :ids => [1, 2], :time_entry => { :custom_field_values => {field.id.to_s => '__none__'} }
605 post :bulk_update, :params => {:ids => [1, 2], :time_entry => { :custom_field_values => {field.id.to_s => '__none__'} }}
534
606
535 assert_response 302
607 assert_response 302
536 assert_equal ["", ""], TimeEntry.where(:id => [1, 2]).collect {|i| i.custom_value_for(field).value}
608 assert_equal ["", ""], TimeEntry.where(:id => [1, 2]).collect {|i| i.custom_value_for(field).value}
537 end
609 end
538
610
539 def test_post_bulk_update_should_redirect_back_using_the_back_url_parameter
611 def test_post_bulk_update_should_redirect_back_using_the_back_url_parameter
540 @request.session[:user_id] = 2
612 @request.session[:user_id] = 2
541 post :bulk_update, :ids => [1,2], :back_url => '/time_entries'
613 post :bulk_update, :params => {:ids => [1,2], :back_url => '/time_entries'}
542
614
543 assert_response :redirect
615 assert_response :redirect
544 assert_redirected_to '/time_entries'
616 assert_redirected_to '/time_entries'
545 end
617 end
546
618
547 def test_post_bulk_update_should_not_redirect_back_using_the_back_url_parameter_off_the_host
619 def test_post_bulk_update_should_not_redirect_back_using_the_back_url_parameter_off_the_host
548 @request.session[:user_id] = 2
620 @request.session[:user_id] = 2
549 post :bulk_update, :ids => [1,2], :back_url => 'http://google.com'
621 post :bulk_update, :params => {:ids => [1,2], :back_url => 'http://google.com'}
550
622
551 assert_response :redirect
623 assert_response :redirect
552 assert_redirected_to :controller => 'timelog', :action => 'index', :project_id => Project.find(1).identifier
624 assert_redirected_to :controller => 'timelog', :action => 'index', :project_id => Project.find(1).identifier
553 end
625 end
554
626
555 def test_post_bulk_update_without_edit_permission_should_be_denied
627 def test_post_bulk_update_without_edit_permission_should_be_denied
556 @request.session[:user_id] = 2
628 @request.session[:user_id] = 2
557 Role.find_by_name('Manager').remove_permission! :edit_time_entries
629 Role.find_by_name('Manager').remove_permission! :edit_time_entries
558 post :bulk_update, :ids => [1,2]
559
630
631 post :bulk_update, :params => {:ids => [1,2]}
560 assert_response 403
632 assert_response 403
561 end
633 end
562
634
563 def test_destroy
635 def test_destroy
564 @request.session[:user_id] = 2
636 @request.session[:user_id] = 2
565 delete :destroy, :id => 1
637
638 delete :destroy, :params => {:id => 1}
566 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
639 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
567 assert_equal I18n.t(:notice_successful_delete), flash[:notice]
640 assert_equal I18n.t(:notice_successful_delete), flash[:notice]
568 assert_nil TimeEntry.find_by_id(1)
641 assert_nil TimeEntry.find_by_id(1)
569 end
642 end
570
643
571 def test_destroy_should_fail
644 def test_destroy_should_fail
572 # simulate that this fails (e.g. due to a plugin), see #5700
645 # simulate that this fails (e.g. due to a plugin), see #5700
573 TimeEntry.any_instance.expects(:destroy).returns(false)
646 TimeEntry.any_instance.expects(:destroy).returns(false)
574
575 @request.session[:user_id] = 2
647 @request.session[:user_id] = 2
576 delete :destroy, :id => 1
648
649 delete :destroy, :params => {:id => 1}
577 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
650 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
578 assert_equal I18n.t(:notice_unable_delete_time_entry), flash[:error]
651 assert_equal I18n.t(:notice_unable_delete_time_entry), flash[:error]
579 assert_not_nil TimeEntry.find_by_id(1)
652 assert_not_nil TimeEntry.find_by_id(1)
580 end
653 end
581
654
582 def test_index_all_projects
655 def test_index_all_projects
583 get :index
656 get :index
584 assert_response :success
657 assert_response :success
585
658
586 assert_select '.total-for-hours', :text => 'Hours: 162.90'
659 assert_select '.total-for-hours', :text => 'Hours: 162.90'
587 assert_select 'form#query_form[action=?]', '/time_entries'
660 assert_select 'form#query_form[action=?]', '/time_entries'
588 end
661 end
589
662
590 def test_index_all_projects_should_show_log_time_link
663 def test_index_all_projects_should_show_log_time_link
591 @request.session[:user_id] = 2
664 @request.session[:user_id] = 2
592 get :index
665 get :index
593 assert_response :success
666 assert_response :success
594 assert_template 'index'
667 assert_template 'index'
595 assert_select 'a[href=?]', '/time_entries/new', :text => /Log time/
668 assert_select 'a[href=?]', '/time_entries/new', :text => /Log time/
596 end
669 end
597
670
598 def test_index_my_spent_time
671 def test_index_my_spent_time
599 @request.session[:user_id] = 2
672 @request.session[:user_id] = 2
600 get :index, :user_id => 'me'
673 get :index, :params => {:user_id => 'me'}
601 assert_response :success
674 assert_response :success
602 assert_template 'index'
675 assert_template 'index'
603 assert assigns(:entries).all? {|entry| entry.user_id == 2}
676 assert assigns(:entries).all? {|entry| entry.user_id == 2}
604 end
677 end
605
678
606 def test_index_at_project_level
679 def test_index_at_project_level
607 get :index, :project_id => 'ecookbook'
680 get :index, :params => {:project_id => 'ecookbook'}
608 assert_response :success
681 assert_response :success
609 assert_template 'index'
682 assert_template 'index'
610 assert_not_nil assigns(:entries)
683 assert_not_nil assigns(:entries)
611 assert_equal 4, assigns(:entries).size
684 assert_equal 4, assigns(:entries).size
612 # project and subproject
685 # project and subproject
613 assert_equal [1, 3], assigns(:entries).collect(&:project_id).uniq.sort
686 assert_equal [1, 3], assigns(:entries).collect(&:project_id).uniq.sort
614
687
615 assert_select '.total-for-hours', :text => 'Hours: 162.90'
688 assert_select '.total-for-hours', :text => 'Hours: 162.90'
616 assert_select 'form#query_form[action=?]', '/projects/ecookbook/time_entries'
689 assert_select 'form#query_form[action=?]', '/projects/ecookbook/time_entries'
617 end
690 end
618
691
619 def test_index_with_display_subprojects_issues_to_false_should_not_include_subproject_entries
692 def test_index_with_display_subprojects_issues_to_false_should_not_include_subproject_entries
620 entry = TimeEntry.generate!(:project => Project.find(3))
693 entry = TimeEntry.generate!(:project => Project.find(3))
621
694
622 with_settings :display_subprojects_issues => '0' do
695 with_settings :display_subprojects_issues => '0' do
623 get :index, :project_id => 'ecookbook'
696 get :index, :params => {:project_id => 'ecookbook'}
624 assert_response :success
697 assert_response :success
625 assert_template 'index'
698 assert_template 'index'
626 assert_not_include entry, assigns(:entries)
699 assert_not_include entry, assigns(:entries)
627 end
700 end
628 end
701 end
629
702
630 def test_index_with_display_subprojects_issues_to_false_and_subproject_filter_should_include_subproject_entries
703 def test_index_with_display_subprojects_issues_to_false_and_subproject_filter_should_include_subproject_entries
631 entry = TimeEntry.generate!(:project => Project.find(3))
704 entry = TimeEntry.generate!(:project => Project.find(3))
632
705
633 with_settings :display_subprojects_issues => '0' do
706 with_settings :display_subprojects_issues => '0' do
634 get :index, :project_id => 'ecookbook', :subproject_id => 3
707 get :index, :params => {:project_id => 'ecookbook', :subproject_id => 3}
635 assert_response :success
708 assert_response :success
636 assert_template 'index'
709 assert_template 'index'
637 assert_include entry, assigns(:entries)
710 assert_include entry, assigns(:entries)
638 end
711 end
639 end
712 end
640
713
641 def test_index_at_project_level_with_issue_id_short_filter
714 def test_index_at_project_level_with_issue_id_short_filter
642 issue = Issue.generate!(:project_id => 1)
715 issue = Issue.generate!(:project_id => 1)
643 TimeEntry.generate!(:issue => issue, :hours => 4)
716 TimeEntry.generate!(:issue => issue, :hours => 4)
644 TimeEntry.generate!(:issue => issue, :hours => 3)
717 TimeEntry.generate!(:issue => issue, :hours => 3)
645 @request.session[:user_id] = 2
718 @request.session[:user_id] = 2
646
719
647 get :index, :project_id => 'ecookbook', :issue_id => issue.id.to_s, :set_filter => 1
720 get :index, :params => {:project_id => 'ecookbook', :issue_id => issue.id.to_s, :set_filter => 1}
648 assert_select '.total-for-hours', :text => 'Hours: 7.00'
721 assert_select '.total-for-hours', :text => 'Hours: 7.00'
649 end
722 end
650
723
651 def test_index_at_project_level_with_issue_fixed_version_id_short_filter
724 def test_index_at_project_level_with_issue_fixed_version_id_short_filter
652 version = Version.generate!(:project_id => 1)
725 version = Version.generate!(:project_id => 1)
653 issue = Issue.generate!(:project_id => 1, :fixed_version => version)
726 issue = Issue.generate!(:project_id => 1, :fixed_version => version)
654 TimeEntry.generate!(:issue => issue, :hours => 2)
727 TimeEntry.generate!(:issue => issue, :hours => 2)
655 TimeEntry.generate!(:issue => issue, :hours => 3)
728 TimeEntry.generate!(:issue => issue, :hours => 3)
656 @request.session[:user_id] = 2
729 @request.session[:user_id] = 2
657
730
658 get :index, :project_id => 'ecookbook', :"issue.fixed_version_id" => version.id.to_s, :set_filter => 1
731 get :index, :params => {:project_id => 'ecookbook', :"issue.fixed_version_id" => version.id.to_s, :set_filter => 1}
659 assert_select '.total-for-hours', :text => 'Hours: 5.00'
732 assert_select '.total-for-hours', :text => 'Hours: 5.00'
660 end
733 end
661
734
662 def test_index_at_project_level_with_date_range
735 def test_index_at_project_level_with_date_range
663 get :index, :project_id => 'ecookbook',
736 get :index, :params => {
737 :project_id => 'ecookbook',
664 :f => ['spent_on'],
738 :f => ['spent_on'],
665 :op => {'spent_on' => '><'},
739 :op => {'spent_on' => '><'},
666 :v => {'spent_on' => ['2007-03-20', '2007-04-30']}
740 :v => {'spent_on' => ['2007-03-20', '2007-04-30']}
741 }
667 assert_response :success
742 assert_response :success
668 assert_template 'index'
743 assert_template 'index'
669 assert_not_nil assigns(:entries)
744 assert_not_nil assigns(:entries)
670 assert_equal 3, assigns(:entries).size
745 assert_equal 3, assigns(:entries).size
671
746
672 assert_select '.total-for-hours', :text => 'Hours: 12.90'
747 assert_select '.total-for-hours', :text => 'Hours: 12.90'
673 assert_select 'form#query_form[action=?]', '/projects/ecookbook/time_entries'
748 assert_select 'form#query_form[action=?]', '/projects/ecookbook/time_entries'
674 end
749 end
675
750
676 def test_index_at_project_level_with_date_range_using_from_and_to_params
751 def test_index_at_project_level_with_date_range_using_from_and_to_params
677 get :index, :project_id => 'ecookbook', :from => '2007-03-20', :to => '2007-04-30'
752 get :index, :params => {
753 :project_id => 'ecookbook',
754 :from => '2007-03-20',
755 :to => '2007-04-30'
756 }
678 assert_response :success
757 assert_response :success
679 assert_template 'index'
758 assert_template 'index'
680 assert_not_nil assigns(:entries)
759 assert_not_nil assigns(:entries)
681 assert_equal 3, assigns(:entries).size
760 assert_equal 3, assigns(:entries).size
682
761
683 assert_select '.total-for-hours', :text => 'Hours: 12.90'
762 assert_select '.total-for-hours', :text => 'Hours: 12.90'
684 assert_select 'form#query_form[action=?]', '/projects/ecookbook/time_entries'
763 assert_select 'form#query_form[action=?]', '/projects/ecookbook/time_entries'
685 end
764 end
686
765
687 def test_index_at_project_level_with_period
766 def test_index_at_project_level_with_period
688 get :index, :project_id => 'ecookbook',
767 get :index, :params => {
768 :project_id => 'ecookbook',
689 :f => ['spent_on'],
769 :f => ['spent_on'],
690 :op => {'spent_on' => '>t-'},
770 :op => {'spent_on' => '>t-'},
691 :v => {'spent_on' => ['7']}
771 :v => {'spent_on' => ['7']}
772 }
692 assert_response :success
773 assert_response :success
693
774
694 assert_select 'form#query_form[action=?]', '/projects/ecookbook/time_entries'
775 assert_select 'form#query_form[action=?]', '/projects/ecookbook/time_entries'
695 end
776 end
696
777
697 def test_index_should_sort_by_spent_on_and_created_on
778 def test_index_should_sort_by_spent_on_and_created_on
698 t1 = TimeEntry.create!(:user => User.find(1), :project => Project.find(1), :hours => 1, :spent_on => '2012-06-16', :created_on => '2012-06-16 20:00:00', :activity_id => 10)
779 t1 = TimeEntry.create!(:user => User.find(1), :project => Project.find(1), :hours => 1, :spent_on => '2012-06-16', :created_on => '2012-06-16 20:00:00', :activity_id => 10)
699 t2 = TimeEntry.create!(:user => User.find(1), :project => Project.find(1), :hours => 1, :spent_on => '2012-06-16', :created_on => '2012-06-16 20:05:00', :activity_id => 10)
780 t2 = TimeEntry.create!(:user => User.find(1), :project => Project.find(1), :hours => 1, :spent_on => '2012-06-16', :created_on => '2012-06-16 20:05:00', :activity_id => 10)
700 t3 = TimeEntry.create!(:user => User.find(1), :project => Project.find(1), :hours => 1, :spent_on => '2012-06-15', :created_on => '2012-06-16 20:10:00', :activity_id => 10)
781 t3 = TimeEntry.create!(:user => User.find(1), :project => Project.find(1), :hours => 1, :spent_on => '2012-06-15', :created_on => '2012-06-16 20:10:00', :activity_id => 10)
701
782
702 get :index, :project_id => 1,
783 get :index, :params => {
784 :project_id => 1,
703 :f => ['spent_on'],
785 :f => ['spent_on'],
704 :op => {'spent_on' => '><'},
786 :op => {'spent_on' => '><'},
705 :v => {'spent_on' => ['2012-06-15', '2012-06-16']}
787 :v => {'spent_on' => ['2012-06-15', '2012-06-16']}
788 }
706 assert_response :success
789 assert_response :success
707 assert_equal [t2, t1, t3], assigns(:entries)
790 assert_equal [t2, t1, t3], assigns(:entries)
708
791
709 get :index, :project_id => 1,
792 get :index, :params => {
793 :project_id => 1,
710 :f => ['spent_on'],
794 :f => ['spent_on'],
711 :op => {'spent_on' => '><'},
795 :op => {'spent_on' => '><'},
712 :v => {'spent_on' => ['2012-06-15', '2012-06-16']},
796 :v => {'spent_on' => ['2012-06-15', '2012-06-16']},
713 :sort => 'spent_on'
797 :sort => 'spent_on'
798 }
714 assert_response :success
799 assert_response :success
715 assert_equal [t3, t1, t2], assigns(:entries)
800 assert_equal [t3, t1, t2], assigns(:entries)
716 end
801 end
717
802
718 def test_index_with_filter_on_issue_custom_field
803 def test_index_with_filter_on_issue_custom_field
719 issue = Issue.generate!(:project_id => 1, :tracker_id => 1, :custom_field_values => {2 => 'filter_on_issue_custom_field'})
804 issue = Issue.generate!(:project_id => 1, :tracker_id => 1, :custom_field_values => {2 => 'filter_on_issue_custom_field'})
720 entry = TimeEntry.generate!(:issue => issue, :hours => 2.5)
805 entry = TimeEntry.generate!(:issue => issue, :hours => 2.5)
721
806
722 get :index, :f => ['issue.cf_2'], :op => {'issue.cf_2' => '='}, :v => {'issue.cf_2' => ['filter_on_issue_custom_field']}
807 get :index, :params => {
808 :f => ['issue.cf_2'],
809 :op => {'issue.cf_2' => '='},
810 :v => {'issue.cf_2' => ['filter_on_issue_custom_field']}
811 }
723 assert_response :success
812 assert_response :success
724 assert_equal [entry], assigns(:entries)
813 assert_equal [entry], assigns(:entries)
725 end
814 end
726
815
727 def test_index_with_issue_custom_field_column
816 def test_index_with_issue_custom_field_column
728 issue = Issue.generate!(:project_id => 1, :tracker_id => 1, :custom_field_values => {2 => 'filter_on_issue_custom_field'})
817 issue = Issue.generate!(:project_id => 1, :tracker_id => 1, :custom_field_values => {2 => 'filter_on_issue_custom_field'})
729 entry = TimeEntry.generate!(:issue => issue, :hours => 2.5)
818 entry = TimeEntry.generate!(:issue => issue, :hours => 2.5)
730
819
731 get :index, :c => %w(project spent_on issue comments hours issue.cf_2)
820 get :index, :params => {
821 :c => %w(project spent_on issue comments hours issue.cf_2)
822 }
732 assert_response :success
823 assert_response :success
733 assert_include :'issue.cf_2', assigns(:query).column_names
824 assert_include :'issue.cf_2', assigns(:query).column_names
734 assert_select 'td.issue_cf_2', :text => 'filter_on_issue_custom_field'
825 assert_select 'td.issue_cf_2', :text => 'filter_on_issue_custom_field'
735 end
826 end
736
827
737 def test_index_with_time_entry_custom_field_column
828 def test_index_with_time_entry_custom_field_column
738 field = TimeEntryCustomField.generate!(:field_format => 'string')
829 field = TimeEntryCustomField.generate!(:field_format => 'string')
739 entry = TimeEntry.generate!(:hours => 2.5, :custom_field_values => {field.id => 'CF Value'})
830 entry = TimeEntry.generate!(:hours => 2.5, :custom_field_values => {field.id => 'CF Value'})
740 field_name = "cf_#{field.id}"
831 field_name = "cf_#{field.id}"
741
832
742 get :index, :c => ["hours", field_name]
833 get :index, :params => {
834 :c => ["hours", field_name]
835 }
743 assert_response :success
836 assert_response :success
744 assert_include field_name.to_sym, assigns(:query).column_names
837 assert_include field_name.to_sym, assigns(:query).column_names
745 assert_select "td.#{field_name}", :text => 'CF Value'
838 assert_select "td.#{field_name}", :text => 'CF Value'
746 end
839 end
747
840
748 def test_index_with_time_entry_custom_field_sorting
841 def test_index_with_time_entry_custom_field_sorting
749 field = TimeEntryCustomField.generate!(:field_format => 'string', :name => 'String Field')
842 field = TimeEntryCustomField.generate!(:field_format => 'string', :name => 'String Field')
750 TimeEntry.generate!(:hours => 2.5, :custom_field_values => {field.id => 'CF Value 1'})
843 TimeEntry.generate!(:hours => 2.5, :custom_field_values => {field.id => 'CF Value 1'})
751 TimeEntry.generate!(:hours => 2.5, :custom_field_values => {field.id => 'CF Value 3'})
844 TimeEntry.generate!(:hours => 2.5, :custom_field_values => {field.id => 'CF Value 3'})
752 TimeEntry.generate!(:hours => 2.5, :custom_field_values => {field.id => 'CF Value 2'})
845 TimeEntry.generate!(:hours => 2.5, :custom_field_values => {field.id => 'CF Value 2'})
753 field_name = "cf_#{field.id}"
846 field_name = "cf_#{field.id}"
754
847
755 get :index, :c => ["hours", field_name], :sort => field_name
848 get :index, :params => {
849 :c => ["hours", field_name],
850 :sort => field_name
851 }
756 assert_response :success
852 assert_response :success
757 assert_include field_name.to_sym, assigns(:query).column_names
853 assert_include field_name.to_sym, assigns(:query).column_names
758 assert_select "th a.sort", :text => 'String Field'
854 assert_select "th a.sort", :text => 'String Field'
759
855
760 # Make sure that values are properly sorted
856 # Make sure that values are properly sorted
761 values = assigns(:entries).map {|e| e.custom_field_value(field)}.compact
857 values = assigns(:entries).map {|e| e.custom_field_value(field)}.compact
762 assert_equal 3, values.size
858 assert_equal 3, values.size
763 assert_equal values.sort, values
859 assert_equal values.sort, values
764 end
860 end
765
861
766 def test_index_with_query
862 def test_index_with_query
767 query = TimeEntryQuery.new(:project_id => 1, :name => 'Time Entry Query', :visibility => 2)
863 query = TimeEntryQuery.new(:project_id => 1, :name => 'Time Entry Query', :visibility => 2)
768 query.save!
864 query.save!
769 @request.session[:user_id] = 2
865 @request.session[:user_id] = 2
770
866
771 get :index, :project_id => 'ecookbook', :query_id => query.id
867 get :index, :params => {:project_id => 'ecookbook', :query_id => query.id}
772 assert_response :success
868 assert_response :success
773 assert_select 'h2', :text => query.name
869 assert_select 'h2', :text => query.name
774 assert_select '#sidebar a.selected', :text => query.name
870 assert_select '#sidebar a.selected', :text => query.name
775 end
871 end
776
872
777 def test_index_atom_feed
873 def test_index_atom_feed
778 get :index, :project_id => 1, :format => 'atom'
874 get :index, :params => {:project_id => 1, :format => 'atom'}
779 assert_response :success
875 assert_response :success
780 assert_equal 'application/atom+xml', @response.content_type
876 assert_equal 'application/atom+xml', @response.content_type
781 assert_not_nil assigns(:items)
877 assert_not_nil assigns(:items)
782 assert assigns(:items).first.is_a?(TimeEntry)
878 assert assigns(:items).first.is_a?(TimeEntry)
783 end
879 end
784
880
785 def test_index_at_project_level_should_include_csv_export_dialog
881 def test_index_at_project_level_should_include_csv_export_dialog
786 get :index, :project_id => 'ecookbook',
882 get :index, :params => {
883 :project_id => 'ecookbook',
787 :f => ['spent_on'],
884 :f => ['spent_on'],
788 :op => {'spent_on' => '>='},
885 :op => {'spent_on' => '>='},
789 :v => {'spent_on' => ['2007-04-01']},
886 :v => {'spent_on' => ['2007-04-01']},
790 :c => ['spent_on', 'user']
887 :c => ['spent_on', 'user']
888 }
791 assert_response :success
889 assert_response :success
792
890
793 assert_select '#csv-export-options' do
891 assert_select '#csv-export-options' do
794 assert_select 'form[action=?][method=get]', '/projects/ecookbook/time_entries.csv' do
892 assert_select 'form[action=?][method=get]', '/projects/ecookbook/time_entries.csv' do
795 # filter
893 # filter
796 assert_select 'input[name=?][value=?]', 'f[]', 'spent_on'
894 assert_select 'input[name=?][value=?]', 'f[]', 'spent_on'
797 assert_select 'input[name=?][value=?]', 'op[spent_on]', '>='
895 assert_select 'input[name=?][value=?]', 'op[spent_on]', '>='
798 assert_select 'input[name=?][value=?]', 'v[spent_on][]', '2007-04-01'
896 assert_select 'input[name=?][value=?]', 'v[spent_on][]', '2007-04-01'
799 # columns
897 # columns
800 assert_select 'input[name=?][value=?]', 'c[]', 'spent_on'
898 assert_select 'input[name=?][value=?]', 'c[]', 'spent_on'
801 assert_select 'input[name=?][value=?]', 'c[]', 'user'
899 assert_select 'input[name=?][value=?]', 'c[]', 'user'
802 assert_select 'input[name=?]', 'c[]', 2
900 assert_select 'input[name=?]', 'c[]', 2
803 end
901 end
804 end
902 end
805 end
903 end
806
904
807 def test_index_cross_project_should_include_csv_export_dialog
905 def test_index_cross_project_should_include_csv_export_dialog
808 get :index
906 get :index
809 assert_response :success
907 assert_response :success
810
908
811 assert_select '#csv-export-options' do
909 assert_select '#csv-export-options' do
812 assert_select 'form[action=?][method=get]', '/time_entries.csv'
910 assert_select 'form[action=?][method=get]', '/time_entries.csv'
813 end
911 end
814 end
912 end
815
913
816 def test_index_csv_all_projects
914 def test_index_csv_all_projects
817 with_settings :date_format => '%m/%d/%Y' do
915 with_settings :date_format => '%m/%d/%Y' do
818 get :index, :format => 'csv'
916 get :index, :params => {:format => 'csv'}
819 assert_response :success
917 assert_response :success
820 assert_equal 'text/csv; header=present', response.content_type
918 assert_equal 'text/csv; header=present', response.content_type
821 end
919 end
822 end
920 end
823
921
824 def test_index_csv
922 def test_index_csv
825 with_settings :date_format => '%m/%d/%Y' do
923 with_settings :date_format => '%m/%d/%Y' do
826 get :index, :project_id => 1, :format => 'csv'
924 get :index, :params => {:project_id => 1, :format => 'csv'}
827 assert_response :success
925 assert_response :success
828 assert_equal 'text/csv; header=present', response.content_type
926 assert_equal 'text/csv; header=present', response.content_type
829 end
927 end
830 end
928 end
831
929
832 def test_index_csv_should_fill_issue_column_with_tracker_id_and_subject
930 def test_index_csv_should_fill_issue_column_with_tracker_id_and_subject
833 issue = Issue.find(1)
931 issue = Issue.find(1)
834 entry = TimeEntry.generate!(:issue => issue, :comments => "Issue column content test")
932 entry = TimeEntry.generate!(:issue => issue, :comments => "Issue column content test")
835
933
836 get :index, :format => 'csv'
934 get :index, :params => {:format => 'csv'}
837 line = response.body.split("\n").detect {|l| l.include?(entry.comments)}
935 line = response.body.split("\n").detect {|l| l.include?(entry.comments)}
838 assert_not_nil line
936 assert_not_nil line
839 assert_include "#{issue.tracker} #1: #{issue.subject}", line
937 assert_include "#{issue.tracker} #1: #{issue.subject}", line
840 end
938 end
841 end
939 end
@@ -1,118 +1,128
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2016 Jean-Philippe Lang
2 # Copyright (C) 2006-2016 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 require File.expand_path('../../test_helper', __FILE__)
18 require File.expand_path('../../test_helper', __FILE__)
19
19
20 class TimelogCustomFieldsVisibilityTest < Redmine::ControllerTest
20 class TimelogCustomFieldsVisibilityTest < Redmine::ControllerTest
21 tests TimelogController
21 tests TimelogController
22 fixtures :projects,
22 fixtures :projects,
23 :users,
23 :users,
24 :roles,
24 :roles,
25 :members,
25 :members,
26 :member_roles,
26 :member_roles,
27 :issue_statuses,
27 :issue_statuses,
28 :trackers,
28 :trackers,
29 :projects_trackers,
29 :projects_trackers,
30 :enabled_modules,
30 :enabled_modules,
31 :enumerations,
31 :enumerations,
32 :workflows
32 :workflows
33
33
34 def setup
34 def setup
35 field_attributes = {:field_format => 'string', :is_for_all => true, :is_filter => true, :trackers => Tracker.all}
35 field_attributes = {:field_format => 'string', :is_for_all => true, :is_filter => true, :trackers => Tracker.all}
36 @fields = []
36 @fields = []
37 @fields << (@field1 = IssueCustomField.create!(field_attributes.merge(:name => 'Field 1', :visible => true)))
37 @fields << (@field1 = IssueCustomField.create!(field_attributes.merge(:name => 'Field 1', :visible => true)))
38 @fields << (@field2 = IssueCustomField.create!(field_attributes.merge(:name => 'Field 2', :visible => false, :role_ids => [1, 2])))
38 @fields << (@field2 = IssueCustomField.create!(field_attributes.merge(:name => 'Field 2', :visible => false, :role_ids => [1, 2])))
39 @fields << (@field3 = IssueCustomField.create!(field_attributes.merge(:name => 'Field 3', :visible => false, :role_ids => [1, 3])))
39 @fields << (@field3 = IssueCustomField.create!(field_attributes.merge(:name => 'Field 3', :visible => false, :role_ids => [1, 3])))
40 @issue = Issue.generate!(
40 @issue = Issue.generate!(
41 :author_id => 1,
41 :author_id => 1,
42 :project_id => 1,
42 :project_id => 1,
43 :tracker_id => 1,
43 :tracker_id => 1,
44 :custom_field_values => {@field1.id => 'Value0', @field2.id => 'Value1', @field3.id => 'Value2'}
44 :custom_field_values => {@field1.id => 'Value0', @field2.id => 'Value1', @field3.id => 'Value2'}
45 )
45 )
46 TimeEntry.generate!(:issue => @issue)
46 TimeEntry.generate!(:issue => @issue)
47
47
48 @user_with_role_on_other_project = User.generate!
48 @user_with_role_on_other_project = User.generate!
49 User.add_to_project(@user_with_role_on_other_project, Project.find(2), Role.find(3))
49 User.add_to_project(@user_with_role_on_other_project, Project.find(2), Role.find(3))
50
50
51 @users_to_test = {
51 @users_to_test = {
52 User.find(1) => [@field1, @field2, @field3],
52 User.find(1) => [@field1, @field2, @field3],
53 User.find(3) => [@field1, @field2],
53 User.find(3) => [@field1, @field2],
54 @user_with_role_on_other_project => [@field1], # should see field1 only on Project 1
54 @user_with_role_on_other_project => [@field1], # should see field1 only on Project 1
55 User.generate! => [@field1],
55 User.generate! => [@field1],
56 User.anonymous => [@field1]
56 User.anonymous => [@field1]
57 }
57 }
58
58
59 Member.where(:project_id => 1).each do |member|
59 Member.where(:project_id => 1).each do |member|
60 member.destroy unless @users_to_test.keys.include?(member.principal)
60 member.destroy unless @users_to_test.keys.include?(member.principal)
61 end
61 end
62 end
62 end
63
63
64 def test_index_should_show_visible_custom_fields_only
64 def test_index_should_show_visible_custom_fields_only
65 @users_to_test.each do |user, fields|
65 @users_to_test.each do |user, fields|
66 @request.session[:user_id] = user.id
66 @request.session[:user_id] = user.id
67 get :index, :project_id => 1, :issue_id => @issue.id, :c => (['hours'] + @fields.map{|f| "issue.cf_#{f.id}"})
67 get :index, :params => {
68 :project_id => 1,
69 :issue_id => @issue.id,
70 :c => (['hours'] + @fields.map{|f| "issue.cf_#{f.id}"})
71 }
68 @fields.each_with_index do |field, i|
72 @fields.each_with_index do |field, i|
69 if fields.include?(field)
73 if fields.include?(field)
70 assert_select 'td', {:text => "Value#{i}", :count => 1}, "User #{user.id} was not able to view #{field.name}"
74 assert_select 'td', {:text => "Value#{i}", :count => 1}, "User #{user.id} was not able to view #{field.name}"
71 else
75 else
72 assert_select 'td', {:text => "Value#{i}", :count => 0}, "User #{user.id} was able to view #{field.name}"
76 assert_select 'td', {:text => "Value#{i}", :count => 0}, "User #{user.id} was able to view #{field.name}"
73 end
77 end
74 end
78 end
75 end
79 end
76 end
80 end
77
81
78 def test_index_as_csv_should_show_visible_custom_fields_only
82 def test_index_as_csv_should_show_visible_custom_fields_only
79 @users_to_test.each do |user, fields|
83 @users_to_test.each do |user, fields|
80 @request.session[:user_id] = user.id
84 @request.session[:user_id] = user.id
81 get :index, :project_id => 1, :issue_id => @issue.id, :c => (['hours'] + @fields.map{|f| "issue.cf_#{f.id}"}), :format => 'csv'
85 get :index, :params => {
86 :project_id => 1,
87 :issue_id => @issue.id,
88 :c => (['hours'] + @fields.map{|f| "issue.cf_#{f.id}"}),
89 :format => 'csv'
90 }
82 @fields.each_with_index do |field, i|
91 @fields.each_with_index do |field, i|
83 if fields.include?(field)
92 if fields.include?(field)
84 assert_include "Value#{i}", response.body, "User #{user.id} was not able to view #{field.name} in CSV"
93 assert_include "Value#{i}", response.body, "User #{user.id} was not able to view #{field.name} in CSV"
85 else
94 else
86 assert_not_include "Value#{i}", response.body, "User #{user.id} was able to view #{field.name} in CSV"
95 assert_not_include "Value#{i}", response.body, "User #{user.id} was able to view #{field.name} in CSV"
87 end
96 end
88 end
97 end
89 end
98 end
90 end
99 end
91
100
92 def test_index_with_partial_custom_field_visibility_should_show_visible_custom_fields_only
101 def test_index_with_partial_custom_field_visibility_should_show_visible_custom_fields_only
93 Issue.delete_all
102 Issue.delete_all
94 TimeEntry.delete_all
103 TimeEntry.delete_all
95 p1 = Project.generate!
104 p1 = Project.generate!
96 p2 = Project.generate!
105 p2 = Project.generate!
97 user = User.generate!
106 user = User.generate!
98 User.add_to_project(user, p1, Role.where(:id => [1, 3]).to_a)
107 User.add_to_project(user, p1, Role.where(:id => [1, 3]).to_a)
99 User.add_to_project(user, p2, Role.where(:id => 3).to_a)
108 User.add_to_project(user, p2, Role.where(:id => 3).to_a)
100 TimeEntry.generate!(
109 TimeEntry.generate!(
101 :issue => Issue.generate!(:project => p1, :tracker_id => 1,
110 :issue => Issue.generate!(:project => p1, :tracker_id => 1,
102 :custom_field_values => {@field2.id => 'ValueA'}))
111 :custom_field_values => {@field2.id => 'ValueA'}))
103 TimeEntry.generate!(
112 TimeEntry.generate!(
104 :issue => Issue.generate!(:project => p2, :tracker_id => 1,
113 :issue => Issue.generate!(:project => p2, :tracker_id => 1,
105 :custom_field_values => {@field2.id => 'ValueB'}))
114 :custom_field_values => {@field2.id => 'ValueB'}))
106 TimeEntry.generate!(
115 TimeEntry.generate!(
107 :issue => Issue.generate!(:project => p1, :tracker_id => 1,
116 :issue => Issue.generate!(:project => p1, :tracker_id => 1,
108 :custom_field_values => {@field2.id => 'ValueC'}))
117 :custom_field_values => {@field2.id => 'ValueC'}))
109 @request.session[:user_id] = user.id
118 @request.session[:user_id] = user.id
110 get :index, :c => ["hours", "issue.cf_#{@field2.id}"]
119
120 get :index, :params => {:c => ["hours", "issue.cf_#{@field2.id}"]}
111 assert_select 'td', {:text => 'ValueA'}, "ValueA not found in:\n#{response.body}"
121 assert_select 'td', {:text => 'ValueA'}, "ValueA not found in:\n#{response.body}"
112 assert_select 'td', :text => 'ValueB', :count => 0
122 assert_select 'td', :text => 'ValueB', :count => 0
113 assert_select 'td', {:text => 'ValueC'}, "ValueC not found in:\n#{response.body}"
123 assert_select 'td', {:text => 'ValueC'}, "ValueC not found in:\n#{response.body}"
114
124
115 get :index, :set_filter => '1', "issue.cf_#{@field2.id}" => '*'
125 get :index, :params => {:set_filter => '1', "issue.cf_#{@field2.id}" => '*'}
116 assert_equal %w(ValueA ValueC), assigns(:entries).map{|i| i.issue.custom_field_value(@field2)}.sort
126 assert_equal %w(ValueA ValueC), assigns(:entries).map{|i| i.issue.custom_field_value(@field2)}.sort
117 end
127 end
118 end
128 end
@@ -1,205 +1,247
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2016 Jean-Philippe Lang
2 # Copyright (C) 2006-2016 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 require File.expand_path('../../test_helper', __FILE__)
18 require File.expand_path('../../test_helper', __FILE__)
19
19
20 class TrackersControllerTest < Redmine::ControllerTest
20 class TrackersControllerTest < Redmine::ControllerTest
21 fixtures :trackers, :projects, :projects_trackers, :users, :issues, :custom_fields, :issue_statuses
21 fixtures :trackers, :projects, :projects_trackers, :users, :issues, :custom_fields, :issue_statuses
22
22
23 def setup
23 def setup
24 User.current = nil
24 User.current = nil
25 @request.session[:user_id] = 1 # admin
25 @request.session[:user_id] = 1 # admin
26 end
26 end
27
27
28 def test_index
28 def test_index
29 get :index
29 get :index
30 assert_response :success
30 assert_response :success
31 assert_template 'index'
31 assert_template 'index'
32 end
32 end
33
33
34 def test_index_by_anonymous_should_redirect_to_login_form
34 def test_index_by_anonymous_should_redirect_to_login_form
35 @request.session[:user_id] = nil
35 @request.session[:user_id] = nil
36 get :index
36 get :index
37 assert_redirected_to '/login?back_url=http%3A%2F%2Ftest.host%2Ftrackers'
37 assert_redirected_to '/login?back_url=http%3A%2F%2Ftest.host%2Ftrackers'
38 end
38 end
39
39
40 def test_index_by_user_should_respond_with_406
40 def test_index_by_user_should_respond_with_406
41 @request.session[:user_id] = 2
41 @request.session[:user_id] = 2
42 get :index
42 get :index
43 assert_response 406
43 assert_response 406
44 end
44 end
45
45
46 def test_new
46 def test_new
47 get :new
47 get :new
48 assert_response :success
48 assert_response :success
49 assert_template 'new'
49 assert_template 'new'
50 end
50 end
51
51
52 def test_create
52 def test_create
53 assert_difference 'Tracker.count' do
53 assert_difference 'Tracker.count' do
54 post :create, :tracker => { :name => 'New tracker', :default_status_id => 1, :project_ids => ['1', '', ''], :custom_field_ids => ['1', '6', ''] }
54 post :create, :params => {
55 :tracker => {
56 :name => 'New tracker',
57 :default_status_id => 1,
58 :project_ids => ['1', '', ''],
59 :custom_field_ids => ['1', '6', '']
60 }
61 }
55 end
62 end
56 assert_redirected_to :action => 'index'
63 assert_redirected_to :action => 'index'
57 tracker = Tracker.order('id DESC').first
64 tracker = Tracker.order('id DESC').first
58 assert_equal 'New tracker', tracker.name
65 assert_equal 'New tracker', tracker.name
59 assert_equal [1], tracker.project_ids.sort
66 assert_equal [1], tracker.project_ids.sort
60 assert_equal Tracker::CORE_FIELDS, tracker.core_fields
67 assert_equal Tracker::CORE_FIELDS, tracker.core_fields
61 assert_equal [1, 6], tracker.custom_field_ids.sort
68 assert_equal [1, 6], tracker.custom_field_ids.sort
62 assert_equal 0, tracker.workflow_rules.count
69 assert_equal 0, tracker.workflow_rules.count
63 end
70 end
64
71
65 def test_create_with_disabled_core_fields
72 def test_create_with_disabled_core_fields
66 assert_difference 'Tracker.count' do
73 assert_difference 'Tracker.count' do
67 post :create, :tracker => { :name => 'New tracker', :default_status_id => 1, :core_fields => ['assigned_to_id', 'fixed_version_id', ''] }
74 post :create, :params => {
75 :tracker => {
76 :name => 'New tracker',
77 :default_status_id => 1,
78 :core_fields => ['assigned_to_id', 'fixed_version_id', '']
79 }
80 }
68 end
81 end
69 assert_redirected_to :action => 'index'
82 assert_redirected_to :action => 'index'
70 tracker = Tracker.order('id DESC').first
83 tracker = Tracker.order('id DESC').first
71 assert_equal 'New tracker', tracker.name
84 assert_equal 'New tracker', tracker.name
72 assert_equal %w(assigned_to_id fixed_version_id), tracker.core_fields
85 assert_equal %w(assigned_to_id fixed_version_id), tracker.core_fields
73 end
86 end
74
87
75 def test_create_new_with_workflow_copy
88 def test_create_new_with_workflow_copy
76 assert_difference 'Tracker.count' do
89 assert_difference 'Tracker.count' do
77 post :create, :tracker => { :name => 'New tracker', :default_status_id => 1 }, :copy_workflow_from => 1
90 post :create, :params => {
91 :tracker => {
92 :name => 'New tracker',
93 :default_status_id => 1
94 },
95 :copy_workflow_from => 1
96 }
78 end
97 end
79 assert_redirected_to :action => 'index'
98 assert_redirected_to :action => 'index'
80 tracker = Tracker.find_by_name('New tracker')
99 tracker = Tracker.find_by_name('New tracker')
81 assert_equal 0, tracker.projects.count
100 assert_equal 0, tracker.projects.count
82 assert_equal Tracker.find(1).workflow_rules.count, tracker.workflow_rules.count
101 assert_equal Tracker.find(1).workflow_rules.count, tracker.workflow_rules.count
83 end
102 end
84
103
85 def test_create_with_failure
104 def test_create_with_failure
86 assert_no_difference 'Tracker.count' do
105 assert_no_difference 'Tracker.count' do
87 post :create, :tracker => { :name => '', :project_ids => ['1', '', ''],
106 post :create, :params => {
88 :custom_field_ids => ['1', '6', ''] }
107 :tracker => {
108 :name => '',
109 :project_ids => ['1', '', ''],
110 :custom_field_ids => ['1', '6', '']
111 }
112 }
89 end
113 end
90 assert_response :success
114 assert_response :success
91 assert_template 'new'
115 assert_template 'new'
92 assert_select_error /name cannot be blank/i
116 assert_select_error /name cannot be blank/i
93 end
117 end
94
118
95 def test_edit
119 def test_edit
96 Tracker.find(1).project_ids = [1, 3]
120 Tracker.find(1).project_ids = [1, 3]
97
121
98 get :edit, :id => 1
122 get :edit, :params => {:id => 1}
99 assert_response :success
123 assert_response :success
100 assert_template 'edit'
124 assert_template 'edit'
101
125
102 assert_select 'input[name=?][value="1"][checked=checked]', 'tracker[project_ids][]'
126 assert_select 'input[name=?][value="1"][checked=checked]', 'tracker[project_ids][]'
103 assert_select 'input[name=?][value="2"]:not([checked])', 'tracker[project_ids][]'
127 assert_select 'input[name=?][value="2"]:not([checked])', 'tracker[project_ids][]'
104
128
105 assert_select 'input[name=?][value=""][type=hidden]', 'tracker[project_ids][]'
129 assert_select 'input[name=?][value=""][type=hidden]', 'tracker[project_ids][]'
106 end
130 end
107
131
108 def test_edit_should_check_core_fields
132 def test_edit_should_check_core_fields
109 tracker = Tracker.find(1)
133 tracker = Tracker.find(1)
110 tracker.core_fields = %w(assigned_to_id fixed_version_id)
134 tracker.core_fields = %w(assigned_to_id fixed_version_id)
111 tracker.save!
135 tracker.save!
112
136
113 get :edit, :id => 1
137 get :edit, :params => {:id => 1}
114 assert_response :success
138 assert_response :success
115 assert_template 'edit'
139 assert_template 'edit'
116
140
117 assert_select 'input[name=?][value=assigned_to_id][checked=checked]', 'tracker[core_fields][]'
141 assert_select 'input[name=?][value=assigned_to_id][checked=checked]', 'tracker[core_fields][]'
118 assert_select 'input[name=?][value=fixed_version_id][checked=checked]', 'tracker[core_fields][]'
142 assert_select 'input[name=?][value=fixed_version_id][checked=checked]', 'tracker[core_fields][]'
119
143
120 assert_select 'input[name=?][value=category_id]', 'tracker[core_fields][]'
144 assert_select 'input[name=?][value=category_id]', 'tracker[core_fields][]'
121 assert_select 'input[name=?][value=category_id][checked=checked]', 'tracker[core_fields][]', 0
145 assert_select 'input[name=?][value=category_id][checked=checked]', 'tracker[core_fields][]', 0
122
146
123 assert_select 'input[name=?][value=""][type=hidden]', 'tracker[core_fields][]'
147 assert_select 'input[name=?][value=""][type=hidden]', 'tracker[core_fields][]'
124 end
148 end
125
149
126 def test_update
150 def test_update
127 put :update, :id => 1, :tracker => { :name => 'Renamed',
151 put :update, :params => {
128 :project_ids => ['1', '2', ''] }
152 :id => 1,
153 :tracker => {
154 :name => 'Renamed',
155 :project_ids => ['1', '2', '']
156 }
157 }
129 assert_redirected_to :action => 'index'
158 assert_redirected_to :action => 'index'
130 assert_equal [1, 2], Tracker.find(1).project_ids.sort
159 assert_equal [1, 2], Tracker.find(1).project_ids.sort
131 end
160 end
132
161
133 def test_update_without_projects
162 def test_update_without_projects
134 put :update, :id => 1, :tracker => { :name => 'Renamed',
163 put :update, :params => {
135 :project_ids => [''] }
164 :id => 1,
165 :tracker => {
166 :name => 'Renamed',
167 :project_ids => ['']
168 }
169 }
136 assert_redirected_to :action => 'index'
170 assert_redirected_to :action => 'index'
137 assert Tracker.find(1).project_ids.empty?
171 assert Tracker.find(1).project_ids.empty?
138 end
172 end
139
173
140 def test_update_without_core_fields
174 def test_update_without_core_fields
141 put :update, :id => 1, :tracker => { :name => 'Renamed', :core_fields => [''] }
175 put :update, :params => {
176 :id => 1,
177 :tracker => {
178 :name => 'Renamed',
179 :core_fields => ['']
180 }
181 }
142 assert_redirected_to :action => 'index'
182 assert_redirected_to :action => 'index'
143 assert Tracker.find(1).core_fields.empty?
183 assert Tracker.find(1).core_fields.empty?
144 end
184 end
145
185
146 def test_update_with_failure
186 def test_update_with_failure
147 put :update, :id => 1, :tracker => { :name => '' }
187 put :update, :params => {:id => 1, :tracker => { :name => '' }}
148 assert_response :success
188 assert_response :success
149 assert_template 'edit'
189 assert_template 'edit'
150 assert_select_error /name cannot be blank/i
190 assert_select_error /name cannot be blank/i
151 end
191 end
152
192
153 def test_move_lower
193 def test_move_lower
154 tracker = Tracker.find_by_position(1)
194 tracker = Tracker.find_by_position(1)
155 put :update, :id => 1, :tracker => { :position => '2' }
195 put :update, :params => {:id => 1, :tracker => { :position => '2' }}
156 assert_equal 2, tracker.reload.position
196 assert_equal 2, tracker.reload.position
157 end
197 end
158
198
159 def test_destroy
199 def test_destroy
160 tracker = Tracker.generate!(:name => 'Destroyable')
200 tracker = Tracker.generate!(:name => 'Destroyable')
161 assert_difference 'Tracker.count', -1 do
201 assert_difference 'Tracker.count', -1 do
162 delete :destroy, :id => tracker.id
202 delete :destroy, :params => {:id => tracker.id}
163 end
203 end
164 assert_redirected_to :action => 'index'
204 assert_redirected_to :action => 'index'
165 assert_nil flash[:error]
205 assert_nil flash[:error]
166 end
206 end
167
207
168 def test_destroy_tracker_in_use
208 def test_destroy_tracker_in_use
169 assert_no_difference 'Tracker.count' do
209 assert_no_difference 'Tracker.count' do
170 delete :destroy, :id => 1
210 delete :destroy, :params => {:id => 1}
171 end
211 end
172 assert_redirected_to :action => 'index'
212 assert_redirected_to :action => 'index'
173 assert_not_nil flash[:error]
213 assert_not_nil flash[:error]
174 end
214 end
175
215
176 def test_get_fields
216 def test_get_fields
177 get :fields
217 get :fields
178 assert_response :success
218 assert_response :success
179 assert_template 'fields'
219 assert_template 'fields'
180
220
181 assert_select 'form' do
221 assert_select 'form' do
182 assert_select 'input[type=checkbox][name=?][value=assigned_to_id]', 'trackers[1][core_fields][]'
222 assert_select 'input[type=checkbox][name=?][value=assigned_to_id]', 'trackers[1][core_fields][]'
183 assert_select 'input[type=checkbox][name=?][value="2"]', 'trackers[1][custom_field_ids][]'
223 assert_select 'input[type=checkbox][name=?][value="2"]', 'trackers[1][custom_field_ids][]'
184
224
185 assert_select 'input[type=hidden][name=?][value=""]', 'trackers[1][core_fields][]'
225 assert_select 'input[type=hidden][name=?][value=""]', 'trackers[1][core_fields][]'
186 assert_select 'input[type=hidden][name=?][value=""]', 'trackers[1][custom_field_ids][]'
226 assert_select 'input[type=hidden][name=?][value=""]', 'trackers[1][custom_field_ids][]'
187 end
227 end
188 end
228 end
189
229
190 def test_post_fields
230 def test_post_fields
191 post :fields, :trackers => {
231 post :fields, :params => {
192 '1' => {'core_fields' => ['assigned_to_id', 'due_date', ''], 'custom_field_ids' => ['1', '2']},
232 :trackers => {
193 '2' => {'core_fields' => [''], 'custom_field_ids' => ['']}
233 '1' => {'core_fields' => ['assigned_to_id', 'due_date', ''], 'custom_field_ids' => ['1', '2']},
234 '2' => {'core_fields' => [''], 'custom_field_ids' => ['']}
235 }
194 }
236 }
195 assert_redirected_to '/trackers/fields'
237 assert_redirected_to '/trackers/fields'
196
238
197 tracker = Tracker.find(1)
239 tracker = Tracker.find(1)
198 assert_equal %w(assigned_to_id due_date), tracker.core_fields
240 assert_equal %w(assigned_to_id due_date), tracker.core_fields
199 assert_equal [1, 2], tracker.custom_field_ids.sort
241 assert_equal [1, 2], tracker.custom_field_ids.sort
200
242
201 tracker = Tracker.find(2)
243 tracker = Tracker.find(2)
202 assert_equal [], tracker.core_fields
244 assert_equal [], tracker.core_fields
203 assert_equal [], tracker.custom_field_ids.sort
245 assert_equal [], tracker.custom_field_ids.sort
204 end
246 end
205 end
247 end
@@ -1,250 +1,258
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2016 Jean-Philippe Lang
2 # Copyright (C) 2006-2016 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 require File.expand_path('../../test_helper', __FILE__)
18 require File.expand_path('../../test_helper', __FILE__)
19
19
20 class VersionsControllerTest < Redmine::ControllerTest
20 class VersionsControllerTest < Redmine::ControllerTest
21 fixtures :projects, :versions, :issues, :users, :roles, :members,
21 fixtures :projects, :versions, :issues, :users, :roles, :members,
22 :member_roles, :enabled_modules, :issue_statuses,
22 :member_roles, :enabled_modules, :issue_statuses,
23 :issue_categories, :enumerations
23 :issue_categories, :enumerations
24
24
25 def setup
25 def setup
26 User.current = nil
26 User.current = nil
27 end
27 end
28
28
29 def test_index
29 def test_index
30 get :index, :project_id => 1
30 get :index, :params => {:project_id => 1}
31 assert_response :success
31 assert_response :success
32 assert_template 'index'
32 assert_template 'index'
33 assert_not_nil assigns(:versions)
33 assert_not_nil assigns(:versions)
34 # Version with no date set appears
34 # Version with no date set appears
35 assert assigns(:versions).include?(Version.find(3))
35 assert assigns(:versions).include?(Version.find(3))
36 # Completed version doesn't appear
36 # Completed version doesn't appear
37 assert !assigns(:versions).include?(Version.find(1))
37 assert !assigns(:versions).include?(Version.find(1))
38 # Context menu on issues
38 # Context menu on issues
39 assert_select "script", :text => Regexp.new(Regexp.escape("contextMenuInit('/issues/context_menu')"))
39 assert_select "script", :text => Regexp.new(Regexp.escape("contextMenuInit('/issues/context_menu')"))
40 assert_select "div#sidebar" do
40 assert_select "div#sidebar" do
41 # Links to versions anchors
41 # Links to versions anchors
42 assert_select 'a[href=?]', '#2.0'
42 assert_select 'a[href=?]', '#2.0'
43 # Links to completed versions in the sidebar
43 # Links to completed versions in the sidebar
44 assert_select 'a[href=?]', '/versions/1'
44 assert_select 'a[href=?]', '/versions/1'
45 end
45 end
46 end
46 end
47
47
48 def test_index_with_completed_versions
48 def test_index_with_completed_versions
49 get :index, :project_id => 1, :completed => 1
49 get :index, :params => {:project_id => 1, :completed => 1}
50 assert_response :success
50 assert_response :success
51 assert_template 'index'
51 assert_template 'index'
52 assert_not_nil assigns(:versions)
52 assert_not_nil assigns(:versions)
53 # Version with no date set appears
53 # Version with no date set appears
54 assert assigns(:versions).include?(Version.find(3))
54 assert assigns(:versions).include?(Version.find(3))
55 # Completed version appears
55 # Completed version appears
56 assert assigns(:versions).include?(Version.find(1))
56 assert assigns(:versions).include?(Version.find(1))
57 end
57 end
58
58
59 def test_index_with_tracker_ids
59 def test_index_with_tracker_ids
60 get :index, :project_id => 1, :tracker_ids => [1, 3]
60 get :index, :params => {:project_id => 1, :tracker_ids => [1, 3]}
61 assert_response :success
61 assert_response :success
62 assert_template 'index'
62 assert_template 'index'
63 assert_not_nil assigns(:issues_by_version)
63 assert_not_nil assigns(:issues_by_version)
64 assert_nil assigns(:issues_by_version).values.flatten.detect {|issue| issue.tracker_id == 2}
64 assert_nil assigns(:issues_by_version).values.flatten.detect {|issue| issue.tracker_id == 2}
65 end
65 end
66
66
67 def test_index_showing_subprojects_versions
67 def test_index_showing_subprojects_versions
68 @subproject_version = Version.create!(:project => Project.find(3), :name => "Subproject version")
68 @subproject_version = Version.create!(:project => Project.find(3), :name => "Subproject version")
69 get :index, :project_id => 1, :with_subprojects => 1
69 get :index, :params => {:project_id => 1, :with_subprojects => 1}
70 assert_response :success
70 assert_response :success
71 assert_template 'index'
71 assert_template 'index'
72 assert_not_nil assigns(:versions)
72 assert_not_nil assigns(:versions)
73
73
74 assert assigns(:versions).include?(Version.find(4)), "Shared version not found"
74 assert assigns(:versions).include?(Version.find(4)), "Shared version not found"
75 assert assigns(:versions).include?(@subproject_version), "Subproject version not found"
75 assert assigns(:versions).include?(@subproject_version), "Subproject version not found"
76 end
76 end
77
77
78 def test_index_should_prepend_shared_versions
78 def test_index_should_prepend_shared_versions
79 get :index, :project_id => 1
79 get :index, :params => {:project_id => 1}
80 assert_response :success
80 assert_response :success
81
81
82 assert_select '#sidebar' do
82 assert_select '#sidebar' do
83 assert_select 'a[href=?]', '#2.0', :text => '2.0'
83 assert_select 'a[href=?]', '#2.0', :text => '2.0'
84 assert_select 'a[href=?]', '#subproject1-2.0', :text => 'eCookbook Subproject 1 - 2.0'
84 assert_select 'a[href=?]', '#subproject1-2.0', :text => 'eCookbook Subproject 1 - 2.0'
85 end
85 end
86 assert_select '#content' do
86 assert_select '#content' do
87 assert_select 'a[name=?]', '2.0', :text => '2.0'
87 assert_select 'a[name=?]', '2.0', :text => '2.0'
88 assert_select 'a[name=?]', 'subproject1-2.0', :text => 'eCookbook Subproject 1 - 2.0'
88 assert_select 'a[name=?]', 'subproject1-2.0', :text => 'eCookbook Subproject 1 - 2.0'
89 end
89 end
90 end
90 end
91
91
92 def test_show
92 def test_show
93 get :show, :id => 2
93 get :show, :params => {:id => 2}
94 assert_response :success
94 assert_response :success
95 assert_template 'show'
95 assert_template 'show'
96 assert_not_nil assigns(:version)
96 assert_not_nil assigns(:version)
97
97
98 assert_select 'h2', :text => /1.0/
98 assert_select 'h2', :text => /1.0/
99 end
99 end
100
100
101 def test_show_should_link_to_spent_time_on_version
101 def test_show_should_link_to_spent_time_on_version
102 version = Version.generate!
102 version = Version.generate!
103 issue = Issue.generate(:fixed_version => version)
103 issue = Issue.generate(:fixed_version => version)
104 TimeEntry.generate!(:issue => issue, :hours => 7.2)
104 TimeEntry.generate!(:issue => issue, :hours => 7.2)
105
105
106 get :show, :id => version.id
106 get :show, :params => {:id => version.id}
107 assert_response :success
107 assert_response :success
108
108
109 assert_select '.total-hours', :text => '7.20 hours'
109 assert_select '.total-hours', :text => '7.20 hours'
110 assert_select '.total-hours a[href=?]', "/projects/ecookbook/time_entries?issue.fixed_version_id=#{version.id}&set_filter=1"
110 assert_select '.total-hours a[href=?]', "/projects/ecookbook/time_entries?issue.fixed_version_id=#{version.id}&set_filter=1"
111 end
111 end
112
112
113 def test_show_should_display_nil_counts
113 def test_show_should_display_nil_counts
114 with_settings :default_language => 'en' do
114 with_settings :default_language => 'en' do
115 get :show, :id => 2, :status_by => 'category'
115 get :show, :params => {:id => 2, :status_by => 'category'}
116 assert_response :success
116 assert_response :success
117 assert_select 'div#status_by' do
117 assert_select 'div#status_by' do
118 assert_select 'select[name=status_by]' do
118 assert_select 'select[name=status_by]' do
119 assert_select 'option[value=category][selected=selected]'
119 assert_select 'option[value=category][selected=selected]'
120 end
120 end
121 assert_select 'a', :text => 'none'
121 assert_select 'a', :text => 'none'
122 end
122 end
123 end
123 end
124 end
124 end
125
125
126 def test_new
126 def test_new
127 @request.session[:user_id] = 2
127 @request.session[:user_id] = 2
128 get :new, :project_id => '1'
128 get :new, :params => {:project_id => '1'}
129 assert_response :success
129 assert_response :success
130 assert_template 'new'
130 assert_template 'new'
131 end
131 end
132
132
133 def test_new_from_issue_form
133 def test_new_from_issue_form
134 @request.session[:user_id] = 2
134 @request.session[:user_id] = 2
135 xhr :get, :new, :project_id => '1'
135 xhr :get, :new, :params => {:project_id => '1'}
136 assert_response :success
136 assert_response :success
137 assert_template 'new'
137 assert_template 'new'
138 assert_equal 'text/javascript', response.content_type
138 assert_equal 'text/javascript', response.content_type
139 end
139 end
140
140
141 def test_create
141 def test_create
142 @request.session[:user_id] = 2 # manager
142 @request.session[:user_id] = 2 # manager
143 assert_difference 'Version.count' do
143 assert_difference 'Version.count' do
144 post :create, :project_id => '1', :version => {:name => 'test_add_version'}
144 post :create, :params => {:project_id => '1', :version => {:name => 'test_add_version'}}
145 end
145 end
146 assert_redirected_to '/projects/ecookbook/settings/versions'
146 assert_redirected_to '/projects/ecookbook/settings/versions'
147 version = Version.find_by_name('test_add_version')
147 version = Version.find_by_name('test_add_version')
148 assert_not_nil version
148 assert_not_nil version
149 assert_equal 1, version.project_id
149 assert_equal 1, version.project_id
150 end
150 end
151
151
152 def test_create_from_issue_form
152 def test_create_from_issue_form
153 @request.session[:user_id] = 2
153 @request.session[:user_id] = 2
154 assert_difference 'Version.count' do
154 assert_difference 'Version.count' do
155 xhr :post, :create, :project_id => '1', :version => {:name => 'test_add_version_from_issue_form'}
155 xhr :post, :create, :params => {:project_id => '1', :version => {:name => 'test_add_version_from_issue_form'}}
156 end
156 end
157 version = Version.find_by_name('test_add_version_from_issue_form')
157 version = Version.find_by_name('test_add_version_from_issue_form')
158 assert_not_nil version
158 assert_not_nil version
159 assert_equal 1, version.project_id
159 assert_equal 1, version.project_id
160
160
161 assert_response :success
161 assert_response :success
162 assert_template 'create'
162 assert_template 'create'
163 assert_equal 'text/javascript', response.content_type
163 assert_equal 'text/javascript', response.content_type
164 assert_include 'test_add_version_from_issue_form', response.body
164 assert_include 'test_add_version_from_issue_form', response.body
165 end
165 end
166
166
167 def test_create_from_issue_form_with_failure
167 def test_create_from_issue_form_with_failure
168 @request.session[:user_id] = 2
168 @request.session[:user_id] = 2
169 assert_no_difference 'Version.count' do
169 assert_no_difference 'Version.count' do
170 xhr :post, :create, :project_id => '1', :version => {:name => ''}
170 xhr :post, :create, :params => {:project_id => '1', :version => {:name => ''}}
171 end
171 end
172 assert_response :success
172 assert_response :success
173 assert_template 'new'
173 assert_template 'new'
174 assert_equal 'text/javascript', response.content_type
174 assert_equal 'text/javascript', response.content_type
175 end
175 end
176
176
177 def test_get_edit
177 def test_get_edit
178 @request.session[:user_id] = 2
178 @request.session[:user_id] = 2
179 get :edit, :id => 2
179 get :edit, :params => {:id => 2}
180 assert_response :success
180 assert_response :success
181 assert_template 'edit'
181 assert_template 'edit'
182 end
182 end
183
183
184 def test_close_completed
184 def test_close_completed
185 Version.update_all("status = 'open'")
185 Version.update_all("status = 'open'")
186 @request.session[:user_id] = 2
186 @request.session[:user_id] = 2
187 put :close_completed, :project_id => 'ecookbook'
187 put :close_completed, :params => {:project_id => 'ecookbook'}
188 assert_redirected_to :controller => 'projects', :action => 'settings',
188 assert_redirected_to :controller => 'projects', :action => 'settings',
189 :tab => 'versions', :id => 'ecookbook'
189 :tab => 'versions', :id => 'ecookbook'
190 assert_not_nil Version.find_by_status('closed')
190 assert_not_nil Version.find_by_status('closed')
191 end
191 end
192
192
193 def test_post_update
193 def test_post_update
194 @request.session[:user_id] = 2
194 @request.session[:user_id] = 2
195 put :update, :id => 2,
195 put :update, :params => {
196 :version => {:name => 'New version name',
196 :id => 2,
197 :effective_date => Date.today.strftime("%Y-%m-%d")}
197 :version => {
198 :name => 'New version name',
199 :effective_date => Date.today.strftime("%Y-%m-%d")
200 }
201 }
198 assert_redirected_to :controller => 'projects', :action => 'settings',
202 assert_redirected_to :controller => 'projects', :action => 'settings',
199 :tab => 'versions', :id => 'ecookbook'
203 :tab => 'versions', :id => 'ecookbook'
200 version = Version.find(2)
204 version = Version.find(2)
201 assert_equal 'New version name', version.name
205 assert_equal 'New version name', version.name
202 assert_equal Date.today, version.effective_date
206 assert_equal Date.today, version.effective_date
203 end
207 end
204
208
205 def test_post_update_with_validation_failure
209 def test_post_update_with_validation_failure
206 @request.session[:user_id] = 2
210 @request.session[:user_id] = 2
207 put :update, :id => 2,
211 put :update, :params => {
208 :version => { :name => '',
212 :id => 2,
209 :effective_date => Date.today.strftime("%Y-%m-%d")}
213 :version => {
214 :name => '',
215 :effective_date => Date.today.strftime("%Y-%m-%d")
216 }
217 }
210 assert_response :success
218 assert_response :success
211 assert_template 'edit'
219 assert_template 'edit'
212 end
220 end
213
221
214 def test_destroy
222 def test_destroy
215 @request.session[:user_id] = 2
223 @request.session[:user_id] = 2
216 assert_difference 'Version.count', -1 do
224 assert_difference 'Version.count', -1 do
217 delete :destroy, :id => 3
225 delete :destroy, :params => {:id => 3}
218 end
226 end
219 assert_redirected_to :controller => 'projects', :action => 'settings',
227 assert_redirected_to :controller => 'projects', :action => 'settings',
220 :tab => 'versions', :id => 'ecookbook'
228 :tab => 'versions', :id => 'ecookbook'
221 assert_nil Version.find_by_id(3)
229 assert_nil Version.find_by_id(3)
222 end
230 end
223
231
224 def test_destroy_version_in_use_should_fail
232 def test_destroy_version_in_use_should_fail
225 @request.session[:user_id] = 2
233 @request.session[:user_id] = 2
226 assert_no_difference 'Version.count' do
234 assert_no_difference 'Version.count' do
227 delete :destroy, :id => 2
235 delete :destroy, :params => {:id => 2}
228 end
236 end
229 assert_redirected_to :controller => 'projects', :action => 'settings',
237 assert_redirected_to :controller => 'projects', :action => 'settings',
230 :tab => 'versions', :id => 'ecookbook'
238 :tab => 'versions', :id => 'ecookbook'
231 assert flash[:error].match(/Unable to delete version/)
239 assert flash[:error].match(/Unable to delete version/)
232 assert Version.find_by_id(2)
240 assert Version.find_by_id(2)
233 end
241 end
234
242
235 def test_issue_status_by
243 def test_issue_status_by
236 xhr :get, :status_by, :id => 2
244 xhr :get, :status_by, :params => {:id => 2}
237 assert_response :success
245 assert_response :success
238 assert_template 'status_by'
246 assert_template 'status_by'
239 assert_template '_issue_counts'
247 assert_template '_issue_counts'
240 end
248 end
241
249
242 def test_issue_status_by_status
250 def test_issue_status_by_status
243 xhr :get, :status_by, :id => 2, :status_by => 'status'
251 xhr :get, :status_by, :params => {:id => 2, :status_by => 'status'}
244 assert_response :success
252 assert_response :success
245 assert_template 'status_by'
253 assert_template 'status_by'
246 assert_template '_issue_counts'
254 assert_template '_issue_counts'
247 assert_include 'Assigned', response.body
255 assert_include 'Assigned', response.body
248 assert_include 'Closed', response.body
256 assert_include 'Closed', response.body
249 end
257 end
250 end
258 end
@@ -1,315 +1,337
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2016 Jean-Philippe Lang
2 # Copyright (C) 2006-2016 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 require File.expand_path('../../test_helper', __FILE__)
18 require File.expand_path('../../test_helper', __FILE__)
19
19
20 class WatchersControllerTest < Redmine::ControllerTest
20 class WatchersControllerTest < Redmine::ControllerTest
21 fixtures :projects, :users, :roles, :members, :member_roles, :enabled_modules,
21 fixtures :projects, :users, :roles, :members, :member_roles, :enabled_modules,
22 :issues, :trackers, :projects_trackers, :issue_statuses, :enumerations, :watchers
22 :issues, :trackers, :projects_trackers, :issue_statuses, :enumerations, :watchers
23
23
24 def setup
24 def setup
25 User.current = nil
25 User.current = nil
26 end
26 end
27
27
28 def test_watch_a_single_object
28 def test_watch_a_single_object
29 @request.session[:user_id] = 3
29 @request.session[:user_id] = 3
30 assert_difference('Watcher.count') do
30 assert_difference('Watcher.count') do
31 xhr :post, :watch, :object_type => 'issue', :object_id => '1'
31 xhr :post, :watch, :params => {:object_type => 'issue', :object_id => '1'}
32 assert_response :success
32 assert_response :success
33 assert_include '$(".issue-1-watcher")', response.body
33 assert_include '$(".issue-1-watcher")', response.body
34 end
34 end
35 assert Issue.find(1).watched_by?(User.find(3))
35 assert Issue.find(1).watched_by?(User.find(3))
36 end
36 end
37
37
38 def test_watch_a_collection_with_a_single_object
38 def test_watch_a_collection_with_a_single_object
39 @request.session[:user_id] = 3
39 @request.session[:user_id] = 3
40 assert_difference('Watcher.count') do
40 assert_difference('Watcher.count') do
41 xhr :post, :watch, :object_type => 'issue', :object_id => ['1']
41 xhr :post, :watch, :params => {:object_type => 'issue', :object_id => ['1']}
42 assert_response :success
42 assert_response :success
43 assert_include '$(".issue-1-watcher")', response.body
43 assert_include '$(".issue-1-watcher")', response.body
44 end
44 end
45 assert Issue.find(1).watched_by?(User.find(3))
45 assert Issue.find(1).watched_by?(User.find(3))
46 end
46 end
47
47
48 def test_watch_a_collection_with_multiple_objects
48 def test_watch_a_collection_with_multiple_objects
49 @request.session[:user_id] = 3
49 @request.session[:user_id] = 3
50 assert_difference('Watcher.count', 2) do
50 assert_difference('Watcher.count', 2) do
51 xhr :post, :watch, :object_type => 'issue', :object_id => ['1', '3']
51 xhr :post, :watch, :params => {:object_type => 'issue', :object_id => ['1', '3']}
52 assert_response :success
52 assert_response :success
53 assert_include '$(".issue-bulk-watcher")', response.body
53 assert_include '$(".issue-bulk-watcher")', response.body
54 end
54 end
55 assert Issue.find(1).watched_by?(User.find(3))
55 assert Issue.find(1).watched_by?(User.find(3))
56 assert Issue.find(3).watched_by?(User.find(3))
56 assert Issue.find(3).watched_by?(User.find(3))
57 end
57 end
58
58
59 def test_watch_a_news_module_should_add_watcher
59 def test_watch_a_news_module_should_add_watcher
60 @request.session[:user_id] = 7
60 @request.session[:user_id] = 7
61 assert_not_nil m = Project.find(1).enabled_module('news')
61 assert_not_nil m = Project.find(1).enabled_module('news')
62
62
63 assert_difference 'Watcher.count' do
63 assert_difference 'Watcher.count' do
64 xhr :post, :watch, :object_type => 'enabled_module', :object_id => m.id.to_s
64 xhr :post, :watch, :params => {:object_type => 'enabled_module', :object_id => m.id.to_s}
65 assert_response :success
65 assert_response :success
66 end
66 end
67 assert m.reload.watched_by?(User.find(7))
67 assert m.reload.watched_by?(User.find(7))
68 end
68 end
69
69
70 def test_watch_a_private_news_module_without_permission_should_fail
70 def test_watch_a_private_news_module_without_permission_should_fail
71 @request.session[:user_id] = 7
71 @request.session[:user_id] = 7
72 assert_not_nil m = Project.find(2).enabled_module('news')
72 assert_not_nil m = Project.find(2).enabled_module('news')
73
73
74 assert_no_difference 'Watcher.count' do
74 assert_no_difference 'Watcher.count' do
75 xhr :post, :watch, :object_type => 'enabled_module', :object_id => m.id.to_s
75 xhr :post, :watch, :params => {:object_type => 'enabled_module', :object_id => m.id.to_s}
76 assert_response 403
76 assert_response 403
77 end
77 end
78 end
78 end
79
79
80 def test_watch_should_be_denied_without_permission
80 def test_watch_should_be_denied_without_permission
81 Role.find(2).remove_permission! :view_issues
81 Role.find(2).remove_permission! :view_issues
82 @request.session[:user_id] = 3
82 @request.session[:user_id] = 3
83 assert_no_difference('Watcher.count') do
83 assert_no_difference('Watcher.count') do
84 xhr :post, :watch, :object_type => 'issue', :object_id => '1'
84 xhr :post, :watch, :params => {:object_type => 'issue', :object_id => '1'}
85 assert_response 403
85 assert_response 403
86 end
86 end
87 end
87 end
88
88
89 def test_watch_invalid_class_should_respond_with_404
89 def test_watch_invalid_class_should_respond_with_404
90 @request.session[:user_id] = 3
90 @request.session[:user_id] = 3
91 assert_no_difference('Watcher.count') do
91 assert_no_difference('Watcher.count') do
92 xhr :post, :watch, :object_type => 'foo', :object_id => '1'
92 xhr :post, :watch, :params => {:object_type => 'foo', :object_id => '1'}
93 assert_response 404
93 assert_response 404
94 end
94 end
95 end
95 end
96
96
97 def test_watch_invalid_object_should_respond_with_404
97 def test_watch_invalid_object_should_respond_with_404
98 @request.session[:user_id] = 3
98 @request.session[:user_id] = 3
99 assert_no_difference('Watcher.count') do
99 assert_no_difference('Watcher.count') do
100 xhr :post, :watch, :object_type => 'issue', :object_id => '999'
100 xhr :post, :watch, :params => {:object_type => 'issue', :object_id => '999'}
101 assert_response 404
101 assert_response 404
102 end
102 end
103 end
103 end
104
104
105 def test_unwatch
105 def test_unwatch
106 @request.session[:user_id] = 3
106 @request.session[:user_id] = 3
107 assert_difference('Watcher.count', -1) do
107 assert_difference('Watcher.count', -1) do
108 xhr :delete, :unwatch, :object_type => 'issue', :object_id => '2'
108 xhr :delete, :unwatch, :params => {:object_type => 'issue', :object_id => '2'}
109 assert_response :success
109 assert_response :success
110 assert_include '$(".issue-2-watcher")', response.body
110 assert_include '$(".issue-2-watcher")', response.body
111 end
111 end
112 assert !Issue.find(1).watched_by?(User.find(3))
112 assert !Issue.find(1).watched_by?(User.find(3))
113 end
113 end
114
114
115 def test_unwatch_a_collection_with_multiple_objects
115 def test_unwatch_a_collection_with_multiple_objects
116 @request.session[:user_id] = 3
116 @request.session[:user_id] = 3
117 Watcher.create!(:user_id => 3, :watchable => Issue.find(1))
117 Watcher.create!(:user_id => 3, :watchable => Issue.find(1))
118 Watcher.create!(:user_id => 3, :watchable => Issue.find(3))
118 Watcher.create!(:user_id => 3, :watchable => Issue.find(3))
119
119
120 assert_difference('Watcher.count', -2) do
120 assert_difference('Watcher.count', -2) do
121 xhr :delete, :unwatch, :object_type => 'issue', :object_id => ['1', '3']
121 xhr :delete, :unwatch, :params => {:object_type => 'issue', :object_id => ['1', '3']}
122 assert_response :success
122 assert_response :success
123 assert_include '$(".issue-bulk-watcher")', response.body
123 assert_include '$(".issue-bulk-watcher")', response.body
124 end
124 end
125 assert !Issue.find(1).watched_by?(User.find(3))
125 assert !Issue.find(1).watched_by?(User.find(3))
126 assert !Issue.find(3).watched_by?(User.find(3))
126 assert !Issue.find(3).watched_by?(User.find(3))
127 end
127 end
128
128
129 def test_new
129 def test_new
130 @request.session[:user_id] = 2
130 @request.session[:user_id] = 2
131 xhr :get, :new, :object_type => 'issue', :object_id => '2'
131 xhr :get, :new, :params => {:object_type => 'issue', :object_id => '2'}
132 assert_response :success
132 assert_response :success
133 assert_match /ajax-modal/, response.body
133 assert_match /ajax-modal/, response.body
134 end
134 end
135
135
136 def test_new_with_multiple_objects
136 def test_new_with_multiple_objects
137 @request.session[:user_id] = 2
137 @request.session[:user_id] = 2
138 xhr :get, :new, :object_type => 'issue', :object_id => ['1', '2']
138 xhr :get, :new, :params => {:object_type => 'issue', :object_id => ['1', '2']}
139 assert_response :success
139 assert_response :success
140 assert_match /ajax-modal/, response.body
140 assert_match /ajax-modal/, response.body
141 end
141 end
142
142
143 def test_new_for_new_record_with_project_id
143 def test_new_for_new_record_with_project_id
144 @request.session[:user_id] = 2
144 @request.session[:user_id] = 2
145 xhr :get, :new, :project_id => 1
145 xhr :get, :new, :params => {:project_id => 1}
146 assert_response :success
146 assert_response :success
147 assert_equal Project.find(1), assigns(:project)
147 assert_equal Project.find(1), assigns(:project)
148 assert_match /ajax-modal/, response.body
148 assert_match /ajax-modal/, response.body
149 end
149 end
150
150
151 def test_new_for_new_record_with_project_identifier
151 def test_new_for_new_record_with_project_identifier
152 @request.session[:user_id] = 2
152 @request.session[:user_id] = 2
153 xhr :get, :new, :project_id => 'ecookbook'
153 xhr :get, :new, :params => {:project_id => 'ecookbook'}
154 assert_response :success
154 assert_response :success
155 assert_equal Project.find(1), assigns(:project)
155 assert_equal Project.find(1), assigns(:project)
156 assert_match /ajax-modal/, response.body
156 assert_match /ajax-modal/, response.body
157 end
157 end
158
158
159 def test_create
159 def test_create
160 @request.session[:user_id] = 2
160 @request.session[:user_id] = 2
161 assert_difference('Watcher.count') do
161 assert_difference('Watcher.count') do
162 xhr :post, :create, :object_type => 'issue', :object_id => '2',
162 xhr :post, :create, :params => {
163 :watcher => {:user_id => '4'}
163 :object_type => 'issue', :object_id => '2',
164 :watcher => {:user_id => '4'}
165 }
164 assert_response :success
166 assert_response :success
165 assert_match /watchers/, response.body
167 assert_match /watchers/, response.body
166 assert_match /ajax-modal/, response.body
168 assert_match /ajax-modal/, response.body
167 end
169 end
168 assert Issue.find(2).watched_by?(User.find(4))
170 assert Issue.find(2).watched_by?(User.find(4))
169 end
171 end
170
172
171 def test_create_with_mutiple_users
173 def test_create_with_mutiple_users
172 @request.session[:user_id] = 2
174 @request.session[:user_id] = 2
173 assert_difference('Watcher.count', 2) do
175 assert_difference('Watcher.count', 2) do
174 xhr :post, :create, :object_type => 'issue', :object_id => '2',
176 xhr :post, :create, :params => {
175 :watcher => {:user_ids => ['4', '7']}
177 :object_type => 'issue', :object_id => '2',
178 :watcher => {:user_ids => ['4', '7']}
179 }
176 assert_response :success
180 assert_response :success
177 assert_match /watchers/, response.body
181 assert_match /watchers/, response.body
178 assert_match /ajax-modal/, response.body
182 assert_match /ajax-modal/, response.body
179 end
183 end
180 assert Issue.find(2).watched_by?(User.find(4))
184 assert Issue.find(2).watched_by?(User.find(4))
181 assert Issue.find(2).watched_by?(User.find(7))
185 assert Issue.find(2).watched_by?(User.find(7))
182 end
186 end
183
187
184 def test_create_with_mutiple_objects
188 def test_create_with_mutiple_objects
185 @request.session[:user_id] = 2
189 @request.session[:user_id] = 2
186 assert_difference('Watcher.count', 4) do
190 assert_difference('Watcher.count', 4) do
187 xhr :post, :create, :object_type => 'issue', :object_id => ['1', '2'],
191 xhr :post, :create, :params => {
188 :watcher => {:user_ids => ['4', '7']}
192 :object_type => 'issue', :object_id => ['1', '2'],
193 :watcher => {:user_ids => ['4', '7']}
194 }
189 assert_response :success
195 assert_response :success
190 assert_match /watchers/, response.body
196 assert_match /watchers/, response.body
191 assert_match /ajax-modal/, response.body
197 assert_match /ajax-modal/, response.body
192 end
198 end
193 assert Issue.find(1).watched_by?(User.find(4))
199 assert Issue.find(1).watched_by?(User.find(4))
194 assert Issue.find(2).watched_by?(User.find(4))
200 assert Issue.find(2).watched_by?(User.find(4))
195 assert Issue.find(1).watched_by?(User.find(7))
201 assert Issue.find(1).watched_by?(User.find(7))
196 assert Issue.find(2).watched_by?(User.find(7))
202 assert Issue.find(2).watched_by?(User.find(7))
197 end
203 end
198
204
199 def test_autocomplete_on_watchable_creation
205 def test_autocomplete_on_watchable_creation
200 @request.session[:user_id] = 2
206 @request.session[:user_id] = 2
201 xhr :get, :autocomplete_for_user, :q => 'mi', :project_id => 'ecookbook'
207 xhr :get, :autocomplete_for_user, :params => {:q => 'mi', :project_id => 'ecookbook'}
202 assert_response :success
208 assert_response :success
203 assert_select 'input', :count => 4
209 assert_select 'input', :count => 4
204 assert_select 'input[name=?][value="1"]', 'watcher[user_ids][]'
210 assert_select 'input[name=?][value="1"]', 'watcher[user_ids][]'
205 assert_select 'input[name=?][value="2"]', 'watcher[user_ids][]'
211 assert_select 'input[name=?][value="2"]', 'watcher[user_ids][]'
206 assert_select 'input[name=?][value="8"]', 'watcher[user_ids][]'
212 assert_select 'input[name=?][value="8"]', 'watcher[user_ids][]'
207 assert_select 'input[name=?][value="9"]', 'watcher[user_ids][]'
213 assert_select 'input[name=?][value="9"]', 'watcher[user_ids][]'
208 end
214 end
209
215
210 def test_search_non_member_on_create
216 def test_search_non_member_on_create
211 @request.session[:user_id] = 2
217 @request.session[:user_id] = 2
212 project = Project.find_by_name("ecookbook")
218 project = Project.find_by_name("ecookbook")
213 user = User.generate!(:firstname => 'issue15622')
219 user = User.generate!(:firstname => 'issue15622')
214 membership = user.membership(project)
220 membership = user.membership(project)
215 assert_nil membership
221 assert_nil membership
216 xhr :get, :autocomplete_for_user, :q => 'issue15622', :project_id => 'ecookbook'
222 xhr :get, :autocomplete_for_user, :params => {:q => 'issue15622', :project_id => 'ecookbook'}
217 assert_response :success
223 assert_response :success
218 assert_select 'input', :count => 1
224 assert_select 'input', :count => 1
219 end
225 end
220
226
221 def test_autocomplete_on_watchable_update
227 def test_autocomplete_on_watchable_update
222 @request.session[:user_id] = 2
228 @request.session[:user_id] = 2
223 xhr :get, :autocomplete_for_user, :q => 'mi', :object_id => '2',
229 xhr :get, :autocomplete_for_user, :params => {
224 :object_type => 'issue', :project_id => 'ecookbook'
230 :object_type => 'issue', :object_id => '2',
231 :project_id => 'ecookbook', :q => 'mi'
232 }
225 assert_response :success
233 assert_response :success
226 assert_select 'input', :count => 3
234 assert_select 'input', :count => 3
227 assert_select 'input[name=?][value="2"]', 'watcher[user_ids][]'
235 assert_select 'input[name=?][value="2"]', 'watcher[user_ids][]'
228 assert_select 'input[name=?][value="8"]', 'watcher[user_ids][]'
236 assert_select 'input[name=?][value="8"]', 'watcher[user_ids][]'
229 assert_select 'input[name=?][value="9"]', 'watcher[user_ids][]'
237 assert_select 'input[name=?][value="9"]', 'watcher[user_ids][]'
230 end
238 end
231
239
232 def test_search_and_add_non_member_on_update
240 def test_search_and_add_non_member_on_update
233 @request.session[:user_id] = 2
241 @request.session[:user_id] = 2
234 project = Project.find_by_name("ecookbook")
242 project = Project.find_by_name("ecookbook")
235 user = User.generate!(:firstname => 'issue15622')
243 user = User.generate!(:firstname => 'issue15622')
236 membership = user.membership(project)
244 membership = user.membership(project)
237 assert_nil membership
245 assert_nil membership
238 xhr :get, :autocomplete_for_user, :q => 'issue15622', :object_id => '2',
246
239 :object_type => 'issue', :project_id => 'ecookbook'
247 xhr :get, :autocomplete_for_user, :params => {
248 :object_type => 'issue', :object_id => '2',
249 :project_id => 'ecookbook', :q => 'issue15622'
250 }
240 assert_response :success
251 assert_response :success
241 assert_select 'input', :count => 1
252 assert_select 'input', :count => 1
253
242 assert_difference('Watcher.count', 1) do
254 assert_difference('Watcher.count', 1) do
243 xhr :post, :create, :object_type => 'issue', :object_id => '2',
255 xhr :post, :create, :params => {
244 :watcher => {:user_ids => ["#{user.id}"]}
256 :object_type => 'issue', :object_id => '2',
257 :watcher => {:user_ids => ["#{user.id}"]}
258 }
245 assert_response :success
259 assert_response :success
246 assert_match /watchers/, response.body
260 assert_match /watchers/, response.body
247 assert_match /ajax-modal/, response.body
261 assert_match /ajax-modal/, response.body
248 end
262 end
249 assert Issue.find(2).watched_by?(user)
263 assert Issue.find(2).watched_by?(user)
250 end
264 end
251
265
252 def test_autocomplete_for_user_should_return_visible_users
266 def test_autocomplete_for_user_should_return_visible_users
253 Role.update_all :users_visibility => 'members_of_visible_projects'
267 Role.update_all :users_visibility => 'members_of_visible_projects'
254
268
255 hidden = User.generate!(:lastname => 'autocomplete')
269 hidden = User.generate!(:lastname => 'autocomplete')
256 visible = User.generate!(:lastname => 'autocomplete')
270 visible = User.generate!(:lastname => 'autocomplete')
257 User.add_to_project(visible, Project.find(1))
271 User.add_to_project(visible, Project.find(1))
258
272
259 @request.session[:user_id] = 2
273 @request.session[:user_id] = 2
260 xhr :get, :autocomplete_for_user, :q => 'autocomp', :project_id => 'ecookbook'
274 xhr :get, :autocomplete_for_user, :params => {:q => 'autocomp', :project_id => 'ecookbook'}
261 assert_response :success
275 assert_response :success
262
276
263 assert_include visible, assigns(:users)
277 assert_include visible, assigns(:users)
264 assert_not_include hidden, assigns(:users)
278 assert_not_include hidden, assigns(:users)
265 end
279 end
266
280
267 def test_append
281 def test_append
268 @request.session[:user_id] = 2
282 @request.session[:user_id] = 2
269 assert_no_difference 'Watcher.count' do
283 assert_no_difference 'Watcher.count' do
270 xhr :post, :append, :watcher => {:user_ids => ['4', '7']}, :project_id => 'ecookbook'
284 xhr :post, :append, :params => {
285 :watcher => {:user_ids => ['4', '7']}, :project_id => 'ecookbook'
286 }
271 assert_response :success
287 assert_response :success
272 assert_include 'watchers_inputs', response.body
288 assert_include 'watchers_inputs', response.body
273 assert_include 'issue[watcher_user_ids][]', response.body
289 assert_include 'issue[watcher_user_ids][]', response.body
274 end
290 end
275 end
291 end
276
292
277 def test_append_without_user_should_render_nothing
293 def test_append_without_user_should_render_nothing
278 @request.session[:user_id] = 2
294 @request.session[:user_id] = 2
279 xhr :post, :append, :project_id => 'ecookbook'
295 xhr :post, :append, :params => {:project_id => 'ecookbook'}
280 assert_response :success
296 assert_response :success
281 assert response.body.blank?
297 assert response.body.blank?
282 end
298 end
283
299
284 def test_destroy
300 def test_destroy
285 @request.session[:user_id] = 2
301 @request.session[:user_id] = 2
286 assert_difference('Watcher.count', -1) do
302 assert_difference('Watcher.count', -1) do
287 xhr :delete, :destroy, :object_type => 'issue', :object_id => '2', :user_id => '3'
303 xhr :delete, :destroy, :params => {
304 :object_type => 'issue', :object_id => '2', :user_id => '3'
305 }
288 assert_response :success
306 assert_response :success
289 assert_match /watchers/, response.body
307 assert_match /watchers/, response.body
290 end
308 end
291 assert !Issue.find(2).watched_by?(User.find(3))
309 assert !Issue.find(2).watched_by?(User.find(3))
292 end
310 end
293
311
294 def test_destroy_locked_user
312 def test_destroy_locked_user
295 user = User.find(3)
313 user = User.find(3)
296 user.lock!
314 user.lock!
297 assert user.reload.locked?
315 assert user.reload.locked?
298
316
299 @request.session[:user_id] = 2
317 @request.session[:user_id] = 2
300 assert_difference('Watcher.count', -1) do
318 assert_difference('Watcher.count', -1) do
301 xhr :delete, :destroy, :object_type => 'issue', :object_id => '2', :user_id => '3'
319 xhr :delete, :destroy, :params => {
320 :object_type => 'issue', :object_id => '2', :user_id => '3'
321 }
302 assert_response :success
322 assert_response :success
303 assert_match /watchers/, response.body
323 assert_match /watchers/, response.body
304 end
324 end
305 assert !Issue.find(2).watched_by?(User.find(3))
325 assert !Issue.find(2).watched_by?(User.find(3))
306 end
326 end
307
327
308 def test_destroy_invalid_user_should_respond_with_404
328 def test_destroy_invalid_user_should_respond_with_404
309 @request.session[:user_id] = 2
329 @request.session[:user_id] = 2
310 assert_no_difference('Watcher.count') do
330 assert_no_difference('Watcher.count') do
311 delete :destroy, :object_type => 'issue', :object_id => '2', :user_id => '999'
331 delete :destroy, :params => {
332 :object_type => 'issue', :object_id => '2', :user_id => '999'
333 }
312 assert_response 404
334 assert_response 404
313 end
335 end
314 end
336 end
315 end
337 end
@@ -1,1022 +1,1117
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2016 Jean-Philippe Lang
2 # Copyright (C) 2006-2016 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 require File.expand_path('../../test_helper', __FILE__)
18 require File.expand_path('../../test_helper', __FILE__)
19
19
20 class WikiControllerTest < Redmine::ControllerTest
20 class WikiControllerTest < Redmine::ControllerTest
21 fixtures :projects, :users, :email_addresses, :roles, :members, :member_roles,
21 fixtures :projects, :users, :email_addresses, :roles, :members, :member_roles,
22 :enabled_modules, :wikis, :wiki_pages, :wiki_contents,
22 :enabled_modules, :wikis, :wiki_pages, :wiki_contents,
23 :wiki_content_versions, :attachments,
23 :wiki_content_versions, :attachments,
24 :issues, :issue_statuses, :trackers
24 :issues, :issue_statuses, :trackers
25
25
26 def setup
26 def setup
27 User.current = nil
27 User.current = nil
28 end
28 end
29
29
30 def test_show_start_page
30 def test_show_start_page
31 get :show, :project_id => 'ecookbook'
31 get :show, :params => {:project_id => 'ecookbook'}
32 assert_response :success
32 assert_response :success
33 assert_template 'show'
33 assert_template 'show'
34 assert_select 'h1', :text => /CookBook documentation/
34 assert_select 'h1', :text => /CookBook documentation/
35
35
36 # child_pages macro
36 # child_pages macro
37 assert_select 'ul.pages-hierarchy>li>a[href=?]', '/projects/ecookbook/wiki/Page_with_an_inline_image',
37 assert_select 'ul.pages-hierarchy>li>a[href=?]', '/projects/ecookbook/wiki/Page_with_an_inline_image',
38 :text => 'Page with an inline image'
38 :text => 'Page with an inline image'
39 end
39 end
40
40
41 def test_export_link
41 def test_export_link
42 Role.anonymous.add_permission! :export_wiki_pages
42 Role.anonymous.add_permission! :export_wiki_pages
43 get :show, :project_id => 'ecookbook'
43 get :show, :params => {:project_id => 'ecookbook'}
44 assert_response :success
44 assert_response :success
45 assert_select 'a[href=?]', '/projects/ecookbook/wiki/CookBook_documentation.txt'
45 assert_select 'a[href=?]', '/projects/ecookbook/wiki/CookBook_documentation.txt'
46 end
46 end
47
47
48 def test_show_page_with_name
48 def test_show_page_with_name
49 get :show, :project_id => 1, :id => 'Another_page'
49 get :show, :params => {:project_id => 1, :id => 'Another_page'}
50 assert_response :success
50 assert_response :success
51 assert_template 'show'
51 assert_template 'show'
52 assert_select 'h1', :text => /Another page/
52 assert_select 'h1', :text => /Another page/
53 # Included page with an inline image
53 # Included page with an inline image
54 assert_select 'p', :text => /This is an inline image/
54 assert_select 'p', :text => /This is an inline image/
55 assert_select 'img[src=?][alt=?]', '/attachments/download/3/logo.gif', 'This is a logo'
55 assert_select 'img[src=?][alt=?]', '/attachments/download/3/logo.gif', 'This is a logo'
56 end
56 end
57
57
58 def test_show_old_version
58 def test_show_old_version
59 with_settings :default_language => 'en' do
59 with_settings :default_language => 'en' do
60 get :show, :project_id => 'ecookbook', :id => 'CookBook_documentation', :version => '2'
60 get :show, :params => {:project_id => 'ecookbook', :id => 'CookBook_documentation', :version => '2'}
61 end
61 end
62 assert_response :success
62 assert_response :success
63 assert_template 'show'
63 assert_template 'show'
64
64
65 assert_select 'a[href=?]', '/projects/ecookbook/wiki/CookBook_documentation/1', :text => /Previous/
65 assert_select 'a[href=?]', '/projects/ecookbook/wiki/CookBook_documentation/1', :text => /Previous/
66 assert_select 'a[href=?]', '/projects/ecookbook/wiki/CookBook_documentation/2/diff', :text => /diff/
66 assert_select 'a[href=?]', '/projects/ecookbook/wiki/CookBook_documentation/2/diff', :text => /diff/
67 assert_select 'a[href=?]', '/projects/ecookbook/wiki/CookBook_documentation/3', :text => /Next/
67 assert_select 'a[href=?]', '/projects/ecookbook/wiki/CookBook_documentation/3', :text => /Next/
68 assert_select 'a[href=?]', '/projects/ecookbook/wiki/CookBook_documentation', :text => /Current version/
68 assert_select 'a[href=?]', '/projects/ecookbook/wiki/CookBook_documentation', :text => /Current version/
69 end
69 end
70
70
71 def test_show_old_version_with_attachments
71 def test_show_old_version_with_attachments
72 page = WikiPage.find(4)
72 page = WikiPage.find(4)
73 assert page.attachments.any?
73 assert page.attachments.any?
74 content = page.content
74 content = page.content
75 content.text = "update"
75 content.text = "update"
76 content.save!
76 content.save!
77
77
78 get :show, :project_id => 'ecookbook', :id => page.title, :version => '1'
78 get :show, :params => {:project_id => 'ecookbook', :id => page.title, :version => '1'}
79 assert_kind_of WikiContent::Version, assigns(:content)
79 assert_kind_of WikiContent::Version, assigns(:content)
80 assert_response :success
80 assert_response :success
81 assert_template 'show'
81 assert_template 'show'
82 end
82 end
83
83
84 def test_show_old_version_without_permission_should_be_denied
84 def test_show_old_version_without_permission_should_be_denied
85 Role.anonymous.remove_permission! :view_wiki_edits
85 Role.anonymous.remove_permission! :view_wiki_edits
86
86
87 get :show, :project_id => 'ecookbook', :id => 'CookBook_documentation', :version => '2'
87 get :show, :params => {:project_id => 'ecookbook', :id => 'CookBook_documentation', :version => '2'}
88 assert_redirected_to '/login?back_url=http%3A%2F%2Ftest.host%2Fprojects%2Fecookbook%2Fwiki%2FCookBook_documentation%2F2'
88 assert_redirected_to '/login?back_url=http%3A%2F%2Ftest.host%2Fprojects%2Fecookbook%2Fwiki%2FCookBook_documentation%2F2'
89 end
89 end
90
90
91 def test_show_first_version
91 def test_show_first_version
92 with_settings :default_language => 'en' do
92 with_settings :default_language => 'en' do
93 get :show, :project_id => 'ecookbook', :id => 'CookBook_documentation', :version => '1'
93 get :show, :params => {:project_id => 'ecookbook', :id => 'CookBook_documentation', :version => '1'}
94 end
94 end
95 assert_response :success
95 assert_response :success
96 assert_template 'show'
96 assert_template 'show'
97
97
98 assert_select 'a', :text => /Previous/, :count => 0
98 assert_select 'a', :text => /Previous/, :count => 0
99 assert_select 'a', :text => /diff/, :count => 0
99 assert_select 'a', :text => /diff/, :count => 0
100 assert_select 'a[href=?]', '/projects/ecookbook/wiki/CookBook_documentation/2', :text => /Next/
100 assert_select 'a[href=?]', '/projects/ecookbook/wiki/CookBook_documentation/2', :text => /Next/
101 assert_select 'a[href=?]', '/projects/ecookbook/wiki/CookBook_documentation', :text => /Current version/
101 assert_select 'a[href=?]', '/projects/ecookbook/wiki/CookBook_documentation', :text => /Current version/
102 end
102 end
103
103
104 def test_show_redirected_page
104 def test_show_redirected_page
105 WikiRedirect.create!(:wiki_id => 1, :title => 'Old_title', :redirects_to => 'Another_page')
105 WikiRedirect.create!(:wiki_id => 1, :title => 'Old_title', :redirects_to => 'Another_page')
106
106
107 get :show, :project_id => 'ecookbook', :id => 'Old_title'
107 get :show, :params => {:project_id => 'ecookbook', :id => 'Old_title'}
108 assert_redirected_to '/projects/ecookbook/wiki/Another_page'
108 assert_redirected_to '/projects/ecookbook/wiki/Another_page'
109 end
109 end
110
110
111 def test_show_with_sidebar
111 def test_show_with_sidebar
112 page = Project.find(1).wiki.pages.new(:title => 'Sidebar')
112 page = Project.find(1).wiki.pages.new(:title => 'Sidebar')
113 page.content = WikiContent.new(:text => 'Side bar content for test_show_with_sidebar')
113 page.content = WikiContent.new(:text => 'Side bar content for test_show_with_sidebar')
114 page.save!
114 page.save!
115
115
116 get :show, :project_id => 1, :id => 'Another_page'
116 get :show, :params => {:project_id => 1, :id => 'Another_page'}
117 assert_response :success
117 assert_response :success
118 assert_select 'div#sidebar', :text => /Side bar content for test_show_with_sidebar/
118 assert_select 'div#sidebar', :text => /Side bar content for test_show_with_sidebar/
119 end
119 end
120
120
121 def test_show_should_display_section_edit_links
121 def test_show_should_display_section_edit_links
122 @request.session[:user_id] = 2
122 @request.session[:user_id] = 2
123 get :show, :project_id => 1, :id => 'Page with sections'
123 get :show, :params => {:project_id => 1, :id => 'Page with sections'}
124
124
125 assert_select 'a[href=?]', '/projects/ecookbook/wiki/Page_with_sections/edit?section=1', 0
125 assert_select 'a[href=?]', '/projects/ecookbook/wiki/Page_with_sections/edit?section=1', 0
126 assert_select 'a[href=?]', '/projects/ecookbook/wiki/Page_with_sections/edit?section=2'
126 assert_select 'a[href=?]', '/projects/ecookbook/wiki/Page_with_sections/edit?section=2'
127 assert_select 'a[href=?]', '/projects/ecookbook/wiki/Page_with_sections/edit?section=3'
127 assert_select 'a[href=?]', '/projects/ecookbook/wiki/Page_with_sections/edit?section=3'
128 end
128 end
129
129
130 def test_show_current_version_should_display_section_edit_links
130 def test_show_current_version_should_display_section_edit_links
131 @request.session[:user_id] = 2
131 @request.session[:user_id] = 2
132 get :show, :project_id => 1, :id => 'Page with sections', :version => 3
132 get :show, :params => {:project_id => 1, :id => 'Page with sections', :version => 3}
133
133
134 assert_select 'a[href=?]', '/projects/ecookbook/wiki/Page_with_sections/edit?section=2'
134 assert_select 'a[href=?]', '/projects/ecookbook/wiki/Page_with_sections/edit?section=2'
135 end
135 end
136
136
137 def test_show_old_version_should_not_display_section_edit_links
137 def test_show_old_version_should_not_display_section_edit_links
138 @request.session[:user_id] = 2
138 @request.session[:user_id] = 2
139 get :show, :project_id => 1, :id => 'Page with sections', :version => 2
139 get :show, :params => {:project_id => 1, :id => 'Page with sections', :version => 2}
140
140
141 assert_select 'a[href=?]', '/projects/ecookbook/wiki/Page_with_sections/edit?section=2', 0
141 assert_select 'a[href=?]', '/projects/ecookbook/wiki/Page_with_sections/edit?section=2', 0
142 end
142 end
143
143
144 def test_show_unexistent_page_without_edit_right
144 def test_show_unexistent_page_without_edit_right
145 get :show, :project_id => 1, :id => 'Unexistent page'
145 get :show, :params => {:project_id => 1, :id => 'Unexistent page'}
146 assert_response 404
146 assert_response 404
147 end
147 end
148
148
149 def test_show_unexistent_page_with_edit_right
149 def test_show_unexistent_page_with_edit_right
150 @request.session[:user_id] = 2
150 @request.session[:user_id] = 2
151 get :show, :project_id => 1, :id => 'Unexistent page'
151 get :show, :params => {:project_id => 1, :id => 'Unexistent page'}
152 assert_response :success
152 assert_response :success
153 assert_template 'edit'
153 assert_template 'edit'
154 end
154 end
155
155
156 def test_show_specific_version_of_an_unexistent_page_without_edit_right
156 def test_show_specific_version_of_an_unexistent_page_without_edit_right
157 get :show, :project_id => 1, :id => 'Unexistent page', :version => 1
157 get :show, :params => {:project_id => 1, :id => 'Unexistent page', :version => 1}
158 assert_response 404
158 assert_response 404
159 end
159 end
160
160
161 def test_show_unexistent_page_with_parent_should_preselect_parent
161 def test_show_unexistent_page_with_parent_should_preselect_parent
162 @request.session[:user_id] = 2
162 @request.session[:user_id] = 2
163 get :show, :project_id => 1, :id => 'Unexistent page', :parent => 'Another_page'
163 get :show, :params => {:project_id => 1, :id => 'Unexistent page', :parent => 'Another_page'}
164 assert_response :success
164 assert_response :success
165 assert_template 'edit'
165 assert_template 'edit'
166 assert_select 'select[name=?] option[value="2"][selected=selected]', 'wiki_page[parent_id]'
166 assert_select 'select[name=?] option[value="2"][selected=selected]', 'wiki_page[parent_id]'
167 end
167 end
168
168
169 def test_show_should_not_show_history_without_permission
169 def test_show_should_not_show_history_without_permission
170 Role.anonymous.remove_permission! :view_wiki_edits
170 Role.anonymous.remove_permission! :view_wiki_edits
171 get :show, :project_id => 1, :id => 'Page with sections', :version => 2
171 get :show, :params => {:project_id => 1, :id => 'Page with sections', :version => 2}
172
172
173 assert_response 302
173 assert_response 302
174 end
174 end
175
175
176 def test_show_page_without_content_should_display_the_edit_form
176 def test_show_page_without_content_should_display_the_edit_form
177 @request.session[:user_id] = 2
177 @request.session[:user_id] = 2
178 WikiPage.create!(:title => 'NoContent', :wiki => Project.find(1).wiki)
178 WikiPage.create!(:title => 'NoContent', :wiki => Project.find(1).wiki)
179
179
180 get :show, :project_id => 1, :id => 'NoContent'
180 get :show, :params => {:project_id => 1, :id => 'NoContent'}
181 assert_response :success
181 assert_response :success
182 assert_template 'edit'
182 assert_template 'edit'
183 assert_select 'textarea[name=?]', 'content[text]'
183 assert_select 'textarea[name=?]', 'content[text]'
184 end
184 end
185
185
186 def test_get_new
186 def test_get_new
187 @request.session[:user_id] = 2
187 @request.session[:user_id] = 2
188
188
189 get :new, :project_id => 'ecookbook'
189 get :new, :params => {:project_id => 'ecookbook'}
190 assert_response :success
190 assert_response :success
191 assert_template 'new'
191 assert_template 'new'
192 end
192 end
193
193
194 def test_get_new_xhr
194 def test_get_new_xhr
195 @request.session[:user_id] = 2
195 @request.session[:user_id] = 2
196
196
197 xhr :get, :new, :project_id => 'ecookbook'
197 xhr :get, :new, :params => {:project_id => 'ecookbook'}
198 assert_response :success
198 assert_response :success
199 assert_template 'new'
199 assert_template 'new'
200 end
200 end
201
201
202 def test_post_new_with_valid_title_should_redirect_to_edit
202 def test_post_new_with_valid_title_should_redirect_to_edit
203 @request.session[:user_id] = 2
203 @request.session[:user_id] = 2
204
204
205 post :new, :project_id => 'ecookbook', :title => 'New Page'
205 post :new, :params => {:project_id => 'ecookbook', :title => 'New Page'}
206 assert_redirected_to '/projects/ecookbook/wiki/New_Page'
206 assert_redirected_to '/projects/ecookbook/wiki/New_Page'
207 end
207 end
208
208
209 def test_post_new_xhr_with_valid_title_should_redirect_to_edit
209 def test_post_new_xhr_with_valid_title_should_redirect_to_edit
210 @request.session[:user_id] = 2
210 @request.session[:user_id] = 2
211
211
212 xhr :post, :new, :project_id => 'ecookbook', :title => 'New Page'
212 xhr :post, :new, :params => {:project_id => 'ecookbook', :title => 'New Page'}
213 assert_response :success
213 assert_response :success
214 assert_equal 'window.location = "/projects/ecookbook/wiki/New_Page"', response.body
214 assert_equal 'window.location = "/projects/ecookbook/wiki/New_Page"', response.body
215 end
215 end
216
216
217 def test_post_new_with_invalid_title_should_display_errors
217 def test_post_new_with_invalid_title_should_display_errors
218 @request.session[:user_id] = 2
218 @request.session[:user_id] = 2
219
219
220 post :new, :project_id => 'ecookbook', :title => 'Another page'
220 post :new, :params => {:project_id => 'ecookbook', :title => 'Another page'}
221 assert_response :success
221 assert_response :success
222 assert_template 'new'
222 assert_template 'new'
223 assert_select_error 'Title has already been taken'
223 assert_select_error 'Title has already been taken'
224 end
224 end
225
225
226 def test_post_new_xhr_with_invalid_title_should_display_errors
226 def test_post_new_xhr_with_invalid_title_should_display_errors
227 @request.session[:user_id] = 2
227 @request.session[:user_id] = 2
228
228
229 xhr :post, :new, :project_id => 'ecookbook', :title => 'Another page'
229 xhr :post, :new, :params => {:project_id => 'ecookbook', :title => 'Another page'}
230 assert_response :success
230 assert_response :success
231 assert_template 'new'
231 assert_template 'new'
232 assert_include 'Title has already been taken', response.body
232 assert_include 'Title has already been taken', response.body
233 end
233 end
234
234
235 def test_create_page
235 def test_create_page
236 @request.session[:user_id] = 2
236 @request.session[:user_id] = 2
237 assert_difference 'WikiPage.count' do
237 assert_difference 'WikiPage.count' do
238 assert_difference 'WikiContent.count' do
238 assert_difference 'WikiContent.count' do
239 put :update, :project_id => 1,
239 put :update, :params => {
240 :id => 'New page',
240 :project_id => 1,
241 :content => {:comments => 'Created the page',
241 :id => 'New page',
242 :text => "h1. New page\n\nThis is a new page",
242 :content => {
243 :version => 0}
243 :comments => 'Created the page',
244 :text => "h1. New page\n\nThis is a new page",
245 :version => 0
246 }
247 }
244 end
248 end
245 end
249 end
246 assert_redirected_to :action => 'show', :project_id => 'ecookbook', :id => 'New_page'
250 assert_redirected_to :action => 'show', :project_id => 'ecookbook', :id => 'New_page'
247 page = Project.find(1).wiki.find_page('New page')
251 page = Project.find(1).wiki.find_page('New page')
248 assert !page.new_record?
252 assert !page.new_record?
249 assert_not_nil page.content
253 assert_not_nil page.content
250 assert_nil page.parent
254 assert_nil page.parent
251 assert_equal 'Created the page', page.content.comments
255 assert_equal 'Created the page', page.content.comments
252 end
256 end
253
257
254 def test_create_page_with_attachments
258 def test_create_page_with_attachments
255 @request.session[:user_id] = 2
259 @request.session[:user_id] = 2
256 assert_difference 'WikiPage.count' do
260 assert_difference 'WikiPage.count' do
257 assert_difference 'Attachment.count' do
261 assert_difference 'Attachment.count' do
258 put :update, :project_id => 1,
262 put :update, :params => {
259 :id => 'New page',
263 :project_id => 1,
260 :content => {:comments => 'Created the page',
264 :id => 'New page',
261 :text => "h1. New page\n\nThis is a new page",
265 :content => {
262 :version => 0},
266 :comments => 'Created the page',
263 :attachments => {'1' => {'file' => uploaded_test_file('testfile.txt', 'text/plain')}}
267 :text => "h1. New page\n\nThis is a new page",
268 :version => 0
269 },
270 :attachments => {'1' => {'file' => uploaded_test_file('testfile.txt', 'text/plain')}}
271 }
264 end
272 end
265 end
273 end
266 page = Project.find(1).wiki.find_page('New page')
274 page = Project.find(1).wiki.find_page('New page')
267 assert_equal 1, page.attachments.count
275 assert_equal 1, page.attachments.count
268 assert_equal 'testfile.txt', page.attachments.first.filename
276 assert_equal 'testfile.txt', page.attachments.first.filename
269 end
277 end
270
278
271 def test_create_page_with_parent
279 def test_create_page_with_parent
272 @request.session[:user_id] = 2
280 @request.session[:user_id] = 2
273 assert_difference 'WikiPage.count' do
281 assert_difference 'WikiPage.count' do
274 put :update, :project_id => 1, :id => 'New page',
282 put :update, :params => {
275 :content => {:text => "h1. New page\n\nThis is a new page", :version => 0},
283 :project_id => 1,
284 :id => 'New page',
285 :content => {
286 :text => "h1. New page\n\nThis is a new page",
287 :version => 0
288 },
276 :wiki_page => {:parent_id => 2}
289 :wiki_page => {:parent_id => 2}
290 }
277 end
291 end
278 page = Project.find(1).wiki.find_page('New page')
292 page = Project.find(1).wiki.find_page('New page')
279 assert_equal WikiPage.find(2), page.parent
293 assert_equal WikiPage.find(2), page.parent
280 end
294 end
281
295
282 def test_edit_page
296 def test_edit_page
283 @request.session[:user_id] = 2
297 @request.session[:user_id] = 2
284 get :edit, :project_id => 'ecookbook', :id => 'Another_page'
298 get :edit, :params => {:project_id => 'ecookbook', :id => 'Another_page'}
285
299
286 assert_response :success
300 assert_response :success
287 assert_template 'edit'
301 assert_template 'edit'
288
302
289 assert_select 'textarea[name=?]', 'content[text]',
303 assert_select 'textarea[name=?]', 'content[text]',
290 :text => WikiPage.find_by_title('Another_page').content.text
304 :text => WikiPage.find_by_title('Another_page').content.text
291 end
305 end
292
306
293 def test_edit_section
307 def test_edit_section
294 @request.session[:user_id] = 2
308 @request.session[:user_id] = 2
295 get :edit, :project_id => 'ecookbook', :id => 'Page_with_sections', :section => 2
309 get :edit, :params => {:project_id => 'ecookbook', :id => 'Page_with_sections', :section => 2}
296
310
297 assert_response :success
311 assert_response :success
298 assert_template 'edit'
312 assert_template 'edit'
299
313
300 page = WikiPage.find_by_title('Page_with_sections')
314 page = WikiPage.find_by_title('Page_with_sections')
301 section, hash = Redmine::WikiFormatting::Textile::Formatter.new(page.content.text).get_section(2)
315 section, hash = Redmine::WikiFormatting::Textile::Formatter.new(page.content.text).get_section(2)
302
316
303 assert_select 'textarea[name=?]', 'content[text]', :text => section
317 assert_select 'textarea[name=?]', 'content[text]', :text => section
304 assert_select 'input[name=section][type=hidden][value="2"]'
318 assert_select 'input[name=section][type=hidden][value="2"]'
305 assert_select 'input[name=section_hash][type=hidden][value=?]', hash
319 assert_select 'input[name=section_hash][type=hidden][value=?]', hash
306 end
320 end
307
321
308 def test_edit_invalid_section_should_respond_with_404
322 def test_edit_invalid_section_should_respond_with_404
309 @request.session[:user_id] = 2
323 @request.session[:user_id] = 2
310 get :edit, :project_id => 'ecookbook', :id => 'Page_with_sections', :section => 10
324 get :edit, :params => {:project_id => 'ecookbook', :id => 'Page_with_sections', :section => 10}
311
325
312 assert_response 404
326 assert_response 404
313 end
327 end
314
328
315 def test_update_page
329 def test_update_page
316 @request.session[:user_id] = 2
330 @request.session[:user_id] = 2
317 assert_no_difference 'WikiPage.count' do
331 assert_no_difference 'WikiPage.count' do
318 assert_no_difference 'WikiContent.count' do
332 assert_no_difference 'WikiContent.count' do
319 assert_difference 'WikiContent::Version.count' do
333 assert_difference 'WikiContent::Version.count' do
320 put :update, :project_id => 1,
334 put :update, :params => {
335 :project_id => 1,
321 :id => 'Another_page',
336 :id => 'Another_page',
322 :content => {
337 :content => {
323 :comments => "my comments",
338 :comments => "my comments",
324 :text => "edited",
339 :text => "edited",
325 :version => 1
340 :version => 1
326 }
341 }
342 }
327 end
343 end
328 end
344 end
329 end
345 end
330 assert_redirected_to '/projects/ecookbook/wiki/Another_page'
346 assert_redirected_to '/projects/ecookbook/wiki/Another_page'
331
347
332 page = Wiki.find(1).pages.find_by_title('Another_page')
348 page = Wiki.find(1).pages.find_by_title('Another_page')
333 assert_equal "edited", page.content.text
349 assert_equal "edited", page.content.text
334 assert_equal 2, page.content.version
350 assert_equal 2, page.content.version
335 assert_equal "my comments", page.content.comments
351 assert_equal "my comments", page.content.comments
336 end
352 end
337
353
338 def test_update_page_with_parent
354 def test_update_page_with_parent
339 @request.session[:user_id] = 2
355 @request.session[:user_id] = 2
340 assert_no_difference 'WikiPage.count' do
356 assert_no_difference 'WikiPage.count' do
341 assert_no_difference 'WikiContent.count' do
357 assert_no_difference 'WikiContent.count' do
342 assert_difference 'WikiContent::Version.count' do
358 assert_difference 'WikiContent::Version.count' do
343 put :update, :project_id => 1,
359 put :update, :params => {
360 :project_id => 1,
344 :id => 'Another_page',
361 :id => 'Another_page',
345 :content => {
362 :content => {
346 :comments => "my comments",
363 :comments => "my comments",
347 :text => "edited",
364 :text => "edited",
348 :version => 1
365 :version => 1
349 },
366 },
350 :wiki_page => {:parent_id => '1'}
367 :wiki_page => {:parent_id => '1'}
368 }
351 end
369 end
352 end
370 end
353 end
371 end
354 assert_redirected_to '/projects/ecookbook/wiki/Another_page'
372 assert_redirected_to '/projects/ecookbook/wiki/Another_page'
355
373
356 page = Wiki.find(1).pages.find_by_title('Another_page')
374 page = Wiki.find(1).pages.find_by_title('Another_page')
357 assert_equal "edited", page.content.text
375 assert_equal "edited", page.content.text
358 assert_equal 2, page.content.version
376 assert_equal 2, page.content.version
359 assert_equal "my comments", page.content.comments
377 assert_equal "my comments", page.content.comments
360 assert_equal WikiPage.find(1), page.parent
378 assert_equal WikiPage.find(1), page.parent
361 end
379 end
362
380
363 def test_update_page_with_failure
381 def test_update_page_with_failure
364 @request.session[:user_id] = 2
382 @request.session[:user_id] = 2
365 assert_no_difference 'WikiPage.count' do
383 assert_no_difference 'WikiPage.count' do
366 assert_no_difference 'WikiContent.count' do
384 assert_no_difference 'WikiContent.count' do
367 assert_no_difference 'WikiContent::Version.count' do
385 assert_no_difference 'WikiContent::Version.count' do
368 put :update, :project_id => 1,
386 put :update, :params => {
387 :project_id => 1,
369 :id => 'Another_page',
388 :id => 'Another_page',
370 :content => {
389 :content => {
371 :comments => 'a' * 1300, # failure here, comment is too long
390 :comments => 'a' * 1300, # failure here, comment is too long
372 :text => 'edited'
391 :text => 'edited'
373 },
392 },
374 :wiki_page => {
393 :wiki_page => {
375 :parent_id => ""
394 :parent_id => ""
376 }
395 }
396 }
377 end
397 end
378 end
398 end
379 end
399 end
380 assert_response :success
400 assert_response :success
381 assert_template 'edit'
401 assert_template 'edit'
382
402
383 assert_select_error /Comment is too long/
403 assert_select_error /Comment is too long/
384 assert_select 'textarea#content_text', :text => "edited"
404 assert_select 'textarea#content_text', :text => "edited"
385 assert_select 'input#content_version[value="1"]'
405 assert_select 'input#content_version[value="1"]'
386 end
406 end
387
407
388 def test_update_page_with_parent_change_only_should_not_create_content_version
408 def test_update_page_with_parent_change_only_should_not_create_content_version
389 @request.session[:user_id] = 2
409 @request.session[:user_id] = 2
390 assert_no_difference 'WikiPage.count' do
410 assert_no_difference 'WikiPage.count' do
391 assert_no_difference 'WikiContent.count' do
411 assert_no_difference 'WikiContent.count' do
392 assert_no_difference 'WikiContent::Version.count' do
412 assert_no_difference 'WikiContent::Version.count' do
393 put :update, :project_id => 1,
413 put :update, :params => {
414 :project_id => 1,
394 :id => 'Another_page',
415 :id => 'Another_page',
395 :content => {
416 :content => {
396 :comments => '',
417 :comments => '',
397 :text => Wiki.find(1).find_page('Another_page').content.text,
418 :text => Wiki.find(1).find_page('Another_page').content.text,
398 :version => 1
419 :version => 1
399 },
420 },
400 :wiki_page => {:parent_id => '1'}
421 :wiki_page => {:parent_id => '1'}
422 }
401 end
423 end
402 end
424 end
403 end
425 end
404 page = Wiki.find(1).pages.find_by_title('Another_page')
426 page = Wiki.find(1).pages.find_by_title('Another_page')
405 assert_equal 1, page.content.version
427 assert_equal 1, page.content.version
406 assert_equal WikiPage.find(1), page.parent
428 assert_equal WikiPage.find(1), page.parent
407 end
429 end
408
430
409 def test_update_page_with_attachments_only_should_not_create_content_version
431 def test_update_page_with_attachments_only_should_not_create_content_version
410 @request.session[:user_id] = 2
432 @request.session[:user_id] = 2
411 assert_no_difference 'WikiPage.count' do
433 assert_no_difference 'WikiPage.count' do
412 assert_no_difference 'WikiContent.count' do
434 assert_no_difference 'WikiContent.count' do
413 assert_no_difference 'WikiContent::Version.count' do
435 assert_no_difference 'WikiContent::Version.count' do
414 assert_difference 'Attachment.count' do
436 assert_difference 'Attachment.count' do
415 put :update, :project_id => 1,
437 put :update, :params => {
438 :project_id => 1,
416 :id => 'Another_page',
439 :id => 'Another_page',
417 :content => {
440 :content => {
418 :comments => '',
441 :comments => '',
419 :text => Wiki.find(1).find_page('Another_page').content.text,
442 :text => Wiki.find(1).find_page('Another_page').content.text,
420 :version => 1
443 :version => 1
421 },
444 },
422 :attachments => {'1' => {'file' => uploaded_test_file('testfile.txt', 'text/plain'), 'description' => 'test file'}}
445 :attachments => {'1' => {'file' => uploaded_test_file('testfile.txt', 'text/plain'), 'description' => 'test file'}}
446 }
423 end
447 end
424 end
448 end
425 end
449 end
426 end
450 end
427 page = Wiki.find(1).pages.find_by_title('Another_page')
451 page = Wiki.find(1).pages.find_by_title('Another_page')
428 assert_equal 1, page.content.version
452 assert_equal 1, page.content.version
429 end
453 end
430
454
431 def test_update_stale_page_should_not_raise_an_error
455 def test_update_stale_page_should_not_raise_an_error
432 @request.session[:user_id] = 2
456 @request.session[:user_id] = 2
433 c = Wiki.find(1).find_page('Another_page').content
457 c = Wiki.find(1).find_page('Another_page').content
434 c.text = 'Previous text'
458 c.text = 'Previous text'
435 c.save!
459 c.save!
436 assert_equal 2, c.version
460 assert_equal 2, c.version
437
461
438 assert_no_difference 'WikiPage.count' do
462 assert_no_difference 'WikiPage.count' do
439 assert_no_difference 'WikiContent.count' do
463 assert_no_difference 'WikiContent.count' do
440 assert_no_difference 'WikiContent::Version.count' do
464 assert_no_difference 'WikiContent::Version.count' do
441 put :update, :project_id => 1,
465 put :update, :params => {
466 :project_id => 1,
442 :id => 'Another_page',
467 :id => 'Another_page',
443 :content => {
468 :content => {
444 :comments => 'My comments',
469 :comments => 'My comments',
445 :text => 'Text should not be lost',
470 :text => 'Text should not be lost',
446 :version => 1
471 :version => 1
447 }
472 }
473 }
448 end
474 end
449 end
475 end
450 end
476 end
451 assert_response :success
477 assert_response :success
452 assert_template 'edit'
478 assert_template 'edit'
453 assert_select 'div.error', :text => /Data has been updated by another user/
479 assert_select 'div.error', :text => /Data has been updated by another user/
454 assert_select 'textarea[name=?]', 'content[text]', :text => /Text should not be lost/
480 assert_select 'textarea[name=?]', 'content[text]', :text => /Text should not be lost/
455 assert_select 'input[name=?][value=?]', 'content[comments]', 'My comments'
481 assert_select 'input[name=?][value=?]', 'content[comments]', 'My comments'
456
482
457 c.reload
483 c.reload
458 assert_equal 'Previous text', c.text
484 assert_equal 'Previous text', c.text
459 assert_equal 2, c.version
485 assert_equal 2, c.version
460 end
486 end
461
487
462 def test_update_page_without_content_should_create_content
488 def test_update_page_without_content_should_create_content
463 @request.session[:user_id] = 2
489 @request.session[:user_id] = 2
464 page = WikiPage.create!(:title => 'NoContent', :wiki => Project.find(1).wiki)
490 page = WikiPage.create!(:title => 'NoContent', :wiki => Project.find(1).wiki)
465
491
466 assert_no_difference 'WikiPage.count' do
492 assert_no_difference 'WikiPage.count' do
467 assert_difference 'WikiContent.count' do
493 assert_difference 'WikiContent.count' do
468 put :update, :project_id => 1, :id => 'NoContent', :content => {:text => 'Some content'}
494 put :update, :params => {
495 :project_id => 1,
496 :id => 'NoContent',
497 :content => {:text => 'Some content'}
498 }
469 assert_response 302
499 assert_response 302
470 end
500 end
471 end
501 end
472 assert_equal 'Some content', page.reload.content.text
502 assert_equal 'Some content', page.reload.content.text
473 end
503 end
474
504
475 def test_update_section
505 def test_update_section
476 @request.session[:user_id] = 2
506 @request.session[:user_id] = 2
477 page = WikiPage.find_by_title('Page_with_sections')
507 page = WikiPage.find_by_title('Page_with_sections')
478 section, hash = Redmine::WikiFormatting::Textile::Formatter.new(page.content.text).get_section(2)
508 section, hash = Redmine::WikiFormatting::Textile::Formatter.new(page.content.text).get_section(2)
479 text = page.content.text
509 text = page.content.text
480
510
481 assert_no_difference 'WikiPage.count' do
511 assert_no_difference 'WikiPage.count' do
482 assert_no_difference 'WikiContent.count' do
512 assert_no_difference 'WikiContent.count' do
483 assert_difference 'WikiContent::Version.count' do
513 assert_difference 'WikiContent::Version.count' do
484 put :update, :project_id => 1, :id => 'Page_with_sections',
514 put :update, :params => {
515 :project_id => 1,
516 :id => 'Page_with_sections',
485 :content => {
517 :content => {
486 :text => "New section content",
518 :text => "New section content",
487 :version => 3
519 :version => 3
488 },
520 },
489 :section => 2,
521 :section => 2,
490 :section_hash => hash
522 :section_hash => hash
523 }
491 end
524 end
492 end
525 end
493 end
526 end
494 assert_redirected_to '/projects/ecookbook/wiki/Page_with_sections#section-2'
527 assert_redirected_to '/projects/ecookbook/wiki/Page_with_sections#section-2'
495 assert_equal Redmine::WikiFormatting::Textile::Formatter.new(text).update_section(2, "New section content"), page.reload.content.text
528 assert_equal Redmine::WikiFormatting::Textile::Formatter.new(text).update_section(2, "New section content"), page.reload.content.text
496 end
529 end
497
530
498 def test_update_section_should_allow_stale_page_update
531 def test_update_section_should_allow_stale_page_update
499 @request.session[:user_id] = 2
532 @request.session[:user_id] = 2
500 page = WikiPage.find_by_title('Page_with_sections')
533 page = WikiPage.find_by_title('Page_with_sections')
501 section, hash = Redmine::WikiFormatting::Textile::Formatter.new(page.content.text).get_section(2)
534 section, hash = Redmine::WikiFormatting::Textile::Formatter.new(page.content.text).get_section(2)
502 text = page.content.text
535 text = page.content.text
503
536
504 assert_no_difference 'WikiPage.count' do
537 assert_no_difference 'WikiPage.count' do
505 assert_no_difference 'WikiContent.count' do
538 assert_no_difference 'WikiContent.count' do
506 assert_difference 'WikiContent::Version.count' do
539 assert_difference 'WikiContent::Version.count' do
507 put :update, :project_id => 1, :id => 'Page_with_sections',
540 put :update, :params => {
541 :project_id => 1,
542 :id => 'Page_with_sections',
508 :content => {
543 :content => {
509 :text => "New section content",
544 :text => "New section content",
510 :version => 2 # Current version is 3
545 :version => 2 # Current version is 3
511 },
546 },
512 :section => 2,
547 :section => 2,
513 :section_hash => hash
548 :section_hash => hash
549 }
514 end
550 end
515 end
551 end
516 end
552 end
517 assert_redirected_to '/projects/ecookbook/wiki/Page_with_sections#section-2'
553 assert_redirected_to '/projects/ecookbook/wiki/Page_with_sections#section-2'
518 page.reload
554 page.reload
519 assert_equal Redmine::WikiFormatting::Textile::Formatter.new(text).update_section(2, "New section content"), page.content.text
555 assert_equal Redmine::WikiFormatting::Textile::Formatter.new(text).update_section(2, "New section content"), page.content.text
520 assert_equal 4, page.content.version
556 assert_equal 4, page.content.version
521 end
557 end
522
558
523 def test_update_section_should_not_allow_stale_section_update
559 def test_update_section_should_not_allow_stale_section_update
524 @request.session[:user_id] = 2
560 @request.session[:user_id] = 2
525
561
526 assert_no_difference 'WikiPage.count' do
562 assert_no_difference 'WikiPage.count' do
527 assert_no_difference 'WikiContent.count' do
563 assert_no_difference 'WikiContent.count' do
528 assert_no_difference 'WikiContent::Version.count' do
564 assert_no_difference 'WikiContent::Version.count' do
529 put :update, :project_id => 1, :id => 'Page_with_sections',
565 put :update, :params => {
566 :project_id => 1,
567 :id => 'Page_with_sections',
530 :content => {
568 :content => {
531 :comments => 'My comments',
569 :comments => 'My comments',
532 :text => "Text should not be lost",
570 :text => "Text should not be lost",
533 :version => 3
571 :version => 3
534 },
572 },
535 :section => 2,
573 :section => 2,
536 :section_hash => Digest::MD5.hexdigest("wrong hash")
574 :section_hash => Digest::MD5.hexdigest("wrong hash")
575 }
537 end
576 end
538 end
577 end
539 end
578 end
540 assert_response :success
579 assert_response :success
541 assert_template 'edit'
580 assert_template 'edit'
542 assert_select 'div.error', :text => /Data has been updated by another user/
581 assert_select 'div.error', :text => /Data has been updated by another user/
543 assert_select 'textarea[name=?]', 'content[text]', :text => /Text should not be lost/
582 assert_select 'textarea[name=?]', 'content[text]', :text => /Text should not be lost/
544 assert_select 'input[name=?][value=?]', 'content[comments]', 'My comments'
583 assert_select 'input[name=?][value=?]', 'content[comments]', 'My comments'
545 end
584 end
546
585
547 def test_preview
586 def test_preview
548 @request.session[:user_id] = 2
587 @request.session[:user_id] = 2
549 xhr :post, :preview, :project_id => 1, :id => 'CookBook_documentation',
588 xhr :post, :preview, :params => {
550 :content => { :comments => '',
589 :project_id => 1,
551 :text => 'this is a *previewed text*',
590 :id => 'CookBook_documentation',
552 :version => 3 }
591 :content => {
592 :comments => '',
593 :text => 'this is a *previewed text*',
594 :version => 3
595 }
596 }
553 assert_response :success
597 assert_response :success
554 assert_template 'common/_preview'
598 assert_template 'common/_preview'
555 assert_select 'strong', :text => /previewed text/
599 assert_select 'strong', :text => /previewed text/
556 end
600 end
557
601
558 def test_preview_new_page
602 def test_preview_new_page
559 @request.session[:user_id] = 2
603 @request.session[:user_id] = 2
560 xhr :post, :preview, :project_id => 1, :id => 'New page',
604 xhr :post, :preview, :params => {
561 :content => { :text => 'h1. New page',
605 :project_id => 1,
562 :comments => '',
606 :id => 'New page',
563 :version => 0 }
607 :content => {
608 :text => 'h1. New page',
609 :comments => '',
610 :version => 0
611 }
612 }
564 assert_response :success
613 assert_response :success
565 assert_template 'common/_preview'
614 assert_template 'common/_preview'
566 assert_select 'h1', :text => /New page/
615 assert_select 'h1', :text => /New page/
567 end
616 end
568
617
569 def test_history
618 def test_history
570 @request.session[:user_id] = 2
619 @request.session[:user_id] = 2
571 get :history, :project_id => 'ecookbook', :id => 'CookBook_documentation'
620 get :history, :params => {:project_id => 'ecookbook', :id => 'CookBook_documentation'}
572 assert_response :success
621 assert_response :success
573 assert_template 'history'
622 assert_template 'history'
574 assert_not_nil assigns(:versions)
623 assert_not_nil assigns(:versions)
575 assert_equal 3, assigns(:versions).size
624 assert_equal 3, assigns(:versions).size
576
625
577 assert_select "input[type=submit][name=commit]"
626 assert_select "input[type=submit][name=commit]"
578 assert_select 'td' do
627 assert_select 'td' do
579 assert_select 'a[href=?]', '/projects/ecookbook/wiki/CookBook_documentation/2', :text => '2'
628 assert_select 'a[href=?]', '/projects/ecookbook/wiki/CookBook_documentation/2', :text => '2'
580 assert_select 'a[href=?]', '/projects/ecookbook/wiki/CookBook_documentation/2/annotate', :text => 'Annotate'
629 assert_select 'a[href=?]', '/projects/ecookbook/wiki/CookBook_documentation/2/annotate', :text => 'Annotate'
581 assert_select 'a[href=?]', '/projects/ecookbook/wiki/CookBook_documentation/2', :text => 'Delete'
630 assert_select 'a[href=?]', '/projects/ecookbook/wiki/CookBook_documentation/2', :text => 'Delete'
582 end
631 end
583 end
632 end
584
633
585 def test_history_with_one_version
634 def test_history_with_one_version
586 @request.session[:user_id] = 2
635 @request.session[:user_id] = 2
587 get :history, :project_id => 'ecookbook', :id => 'Another_page'
636 get :history, :params => {:project_id => 'ecookbook', :id => 'Another_page'}
588 assert_response :success
637 assert_response :success
589 assert_template 'history'
638 assert_template 'history'
590 assert_not_nil assigns(:versions)
639 assert_not_nil assigns(:versions)
591 assert_equal 1, assigns(:versions).size
640 assert_equal 1, assigns(:versions).size
592 assert_select "input[type=submit][name=commit]", false
641 assert_select "input[type=submit][name=commit]", false
593 assert_select 'td' do
642 assert_select 'td' do
594 assert_select 'a[href=?]', '/projects/ecookbook/wiki/Another_page/1', :text => '1'
643 assert_select 'a[href=?]', '/projects/ecookbook/wiki/Another_page/1', :text => '1'
595 assert_select 'a[href=?]', '/projects/ecookbook/wiki/Another_page/1/annotate', :text => 'Annotate'
644 assert_select 'a[href=?]', '/projects/ecookbook/wiki/Another_page/1/annotate', :text => 'Annotate'
596 assert_select 'a[href=?]', '/projects/ecookbook/wiki/Another_page/1', :text => 'Delete', :count => 0
645 assert_select 'a[href=?]', '/projects/ecookbook/wiki/Another_page/1', :text => 'Delete', :count => 0
597 end
646 end
598 end
647 end
599
648
600 def test_diff
649 def test_diff
601 content = WikiPage.find(1).content
650 content = WikiPage.find(1).content
602 assert_difference 'WikiContent::Version.count', 2 do
651 assert_difference 'WikiContent::Version.count', 2 do
603 content.text = "Line removed\nThis is a sample text for testing diffs"
652 content.text = "Line removed\nThis is a sample text for testing diffs"
604 content.save!
653 content.save!
605 content.text = "This is a sample text for testing diffs\nLine added"
654 content.text = "This is a sample text for testing diffs\nLine added"
606 content.save!
655 content.save!
607 end
656 end
608
657
609 get :diff, :project_id => 1, :id => 'CookBook_documentation', :version => content.version, :version_from => (content.version - 1)
658 get :diff, :params => {
659 :project_id => 1, :id => 'CookBook_documentation',
660 :version => content.version,
661 :version_from => (content.version - 1)
662 }
610 assert_response :success
663 assert_response :success
611 assert_template 'diff'
664 assert_template 'diff'
612 assert_select 'span.diff_out', :text => 'Line removed'
665 assert_select 'span.diff_out', :text => 'Line removed'
613 assert_select 'span.diff_in', :text => 'Line added'
666 assert_select 'span.diff_in', :text => 'Line added'
614 end
667 end
615
668
616 def test_diff_with_invalid_version_should_respond_with_404
669 def test_diff_with_invalid_version_should_respond_with_404
617 get :diff, :project_id => 1, :id => 'CookBook_documentation', :version => '99'
670 get :diff, :params => {
671 :project_id => 1, :id => 'CookBook_documentation',
672 :version => '99'
673 }
618 assert_response 404
674 assert_response 404
619 end
675 end
620
676
621 def test_diff_with_invalid_version_from_should_respond_with_404
677 def test_diff_with_invalid_version_from_should_respond_with_404
622 get :diff, :project_id => 1, :id => 'CookBook_documentation', :version => '99', :version_from => '98'
678 get :diff, :params => {
679 :project_id => 1, :id => 'CookBook_documentation',
680 :version => '99',
681 :version_from => '98'
682 }
623 assert_response 404
683 assert_response 404
624 end
684 end
625
685
626 def test_annotate
686 def test_annotate
627 get :annotate, :project_id => 1, :id => 'CookBook_documentation', :version => 2
687 get :annotate, :params => {
688 :project_id => 1, :id => 'CookBook_documentation',
689 :version => 2
690 }
628 assert_response :success
691 assert_response :success
629 assert_template 'annotate'
692 assert_template 'annotate'
630
693
631 # Line 1
694 # Line 1
632 assert_select 'table.annotate tr:nth-child(1)' do
695 assert_select 'table.annotate tr:nth-child(1)' do
633 assert_select 'th.line-num', :text => '1'
696 assert_select 'th.line-num', :text => '1'
634 assert_select 'td.author', :text => /John Smith/
697 assert_select 'td.author', :text => /John Smith/
635 assert_select 'td', :text => /h1\. CookBook documentation/
698 assert_select 'td', :text => /h1\. CookBook documentation/
636 end
699 end
637
700
638 # Line 5
701 # Line 5
639 assert_select 'table.annotate tr:nth-child(5)' do
702 assert_select 'table.annotate tr:nth-child(5)' do
640 assert_select 'th.line-num', :text => '5'
703 assert_select 'th.line-num', :text => '5'
641 assert_select 'td.author', :text => /Redmine Admin/
704 assert_select 'td.author', :text => /Redmine Admin/
642 assert_select 'td', :text => /Some updated \[\[documentation\]\] here/
705 assert_select 'td', :text => /Some updated \[\[documentation\]\] here/
643 end
706 end
644 end
707 end
645
708
646 def test_annotate_with_invalid_version_should_respond_with_404
709 def test_annotate_with_invalid_version_should_respond_with_404
647 get :annotate, :project_id => 1, :id => 'CookBook_documentation', :version => '99'
710 get :annotate, :params => {
711 :project_id => 1, :id => 'CookBook_documentation',
712 :version => '99'
713 }
648 assert_response 404
714 assert_response 404
649 end
715 end
650
716
651 def test_get_rename
717 def test_get_rename
652 @request.session[:user_id] = 2
718 @request.session[:user_id] = 2
653 get :rename, :project_id => 1, :id => 'Another_page'
719 get :rename, :params => {:project_id => 1, :id => 'Another_page'}
654 assert_response :success
720 assert_response :success
655 assert_template 'rename'
721 assert_template 'rename'
656
722
657 assert_select 'select[name=?]', 'wiki_page[parent_id]' do
723 assert_select 'select[name=?]', 'wiki_page[parent_id]' do
658 assert_select 'option[value=""]', :text => ''
724 assert_select 'option[value=""]', :text => ''
659 assert_select 'option[selected=selected]', 0
725 assert_select 'option[selected=selected]', 0
660 end
726 end
661 end
727 end
662
728
663 def test_get_rename_child_page
729 def test_get_rename_child_page
664 @request.session[:user_id] = 2
730 @request.session[:user_id] = 2
665 get :rename, :project_id => 1, :id => 'Child_1'
731 get :rename, :params => {:project_id => 1, :id => 'Child_1'}
666 assert_response :success
732 assert_response :success
667 assert_template 'rename'
733 assert_template 'rename'
668
734
669 assert_select 'select[name=?]', 'wiki_page[parent_id]' do
735 assert_select 'select[name=?]', 'wiki_page[parent_id]' do
670 assert_select 'option[value=""]', :text => ''
736 assert_select 'option[value=""]', :text => ''
671 assert_select 'option[value="2"][selected=selected]', :text => /Another page/
737 assert_select 'option[value="2"][selected=selected]', :text => /Another page/
672 end
738 end
673 end
739 end
674
740
675 def test_rename_with_redirect
741 def test_rename_with_redirect
676 @request.session[:user_id] = 2
742 @request.session[:user_id] = 2
677 post :rename, :project_id => 1, :id => 'Another_page',
743 post :rename, :params => {
678 :wiki_page => { :title => 'Another renamed page',
744 :project_id => 1,
679 :redirect_existing_links => 1 }
745 :id => 'Another_page',
746 :wiki_page => {
747 :title => 'Another renamed page',
748 :redirect_existing_links => 1
749 }
750 }
680 assert_redirected_to :action => 'show', :project_id => 'ecookbook', :id => 'Another_renamed_page'
751 assert_redirected_to :action => 'show', :project_id => 'ecookbook', :id => 'Another_renamed_page'
681 wiki = Project.find(1).wiki
752 wiki = Project.find(1).wiki
682 # Check redirects
753 # Check redirects
683 assert_not_nil wiki.find_page('Another page')
754 assert_not_nil wiki.find_page('Another page')
684 assert_nil wiki.find_page('Another page', :with_redirect => false)
755 assert_nil wiki.find_page('Another page', :with_redirect => false)
685 end
756 end
686
757
687 def test_rename_without_redirect
758 def test_rename_without_redirect
688 @request.session[:user_id] = 2
759 @request.session[:user_id] = 2
689 post :rename, :project_id => 1, :id => 'Another_page',
760 post :rename, :params => {
690 :wiki_page => { :title => 'Another renamed page',
761 :project_id => 1,
691 :redirect_existing_links => "0" }
762 :id => 'Another_page',
763 :wiki_page => {
764 :title => 'Another renamed page',
765 :redirect_existing_links => "0"
766 }
767 }
692 assert_redirected_to :action => 'show', :project_id => 'ecookbook', :id => 'Another_renamed_page'
768 assert_redirected_to :action => 'show', :project_id => 'ecookbook', :id => 'Another_renamed_page'
693 wiki = Project.find(1).wiki
769 wiki = Project.find(1).wiki
694 # Check that there's no redirects
770 # Check that there's no redirects
695 assert_nil wiki.find_page('Another page')
771 assert_nil wiki.find_page('Another page')
696 end
772 end
697
773
698 def test_rename_with_parent_assignment
774 def test_rename_with_parent_assignment
699 @request.session[:user_id] = 2
775 @request.session[:user_id] = 2
700 post :rename, :project_id => 1, :id => 'Another_page',
776 post :rename, :params => {
701 :wiki_page => { :title => 'Another page', :redirect_existing_links => "0", :parent_id => '4' }
777 :project_id => 1,
778 :id => 'Another_page',
779 :wiki_page => {
780 :title => 'Another page',
781 :redirect_existing_links => "0",
782 :parent_id => '4'
783 }
784 }
702 assert_redirected_to :action => 'show', :project_id => 'ecookbook', :id => 'Another_page'
785 assert_redirected_to :action => 'show', :project_id => 'ecookbook', :id => 'Another_page'
703 assert_equal WikiPage.find(4), WikiPage.find_by_title('Another_page').parent
786 assert_equal WikiPage.find(4), WikiPage.find_by_title('Another_page').parent
704 end
787 end
705
788
706 def test_rename_with_parent_unassignment
789 def test_rename_with_parent_unassignment
707 @request.session[:user_id] = 2
790 @request.session[:user_id] = 2
708 post :rename, :project_id => 1, :id => 'Child_1',
791 post :rename, :params => {
709 :wiki_page => { :title => 'Child 1', :redirect_existing_links => "0", :parent_id => '' }
792 :project_id => 1,
793 :id => 'Child_1',
794 :wiki_page => {
795 :title => 'Child 1',
796 :redirect_existing_links => "0",
797 :parent_id => ''
798 }
799 }
710 assert_redirected_to :action => 'show', :project_id => 'ecookbook', :id => 'Child_1'
800 assert_redirected_to :action => 'show', :project_id => 'ecookbook', :id => 'Child_1'
711 assert_nil WikiPage.find_by_title('Child_1').parent
801 assert_nil WikiPage.find_by_title('Child_1').parent
712 end
802 end
713
803
714 def test_get_rename_should_show_target_projects_list
804 def test_get_rename_should_show_target_projects_list
715 @request.session[:user_id] = 2
805 @request.session[:user_id] = 2
716 project = Project.find(5)
806 project = Project.find(5)
717 project.enable_module! :wiki
807 project.enable_module! :wiki
718
808
719 get :rename, :project_id => 1, :id => 'Another_page'
809 get :rename, :params => {:project_id => 1, :id => 'Another_page'}
720 assert_response :success
810 assert_response :success
721 assert_template 'rename'
811 assert_template 'rename'
722
812
723 assert_select 'select[name=?]', 'wiki_page[wiki_id]' do
813 assert_select 'select[name=?]', 'wiki_page[wiki_id]' do
724 assert_select 'option', 2
814 assert_select 'option', 2
725 assert_select 'option[value=?][selected=selected]', '1', :text => /eCookbook/
815 assert_select 'option[value=?][selected=selected]', '1', :text => /eCookbook/
726 assert_select 'option[value=?]', project.wiki.id.to_s, :text => /#{project.name}/
816 assert_select 'option[value=?]', project.wiki.id.to_s, :text => /#{project.name}/
727 end
817 end
728 end
818 end
729
819
730 def test_rename_with_move
820 def test_rename_with_move
731 @request.session[:user_id] = 2
821 @request.session[:user_id] = 2
732 project = Project.find(5)
822 project = Project.find(5)
733 project.enable_module! :wiki
823 project.enable_module! :wiki
734
824
735 post :rename, :project_id => 1, :id => 'Another_page',
825 post :rename, :params => {
826 :project_id => 1,
827 :id => 'Another_page',
736 :wiki_page => {
828 :wiki_page => {
737 :wiki_id => project.wiki.id.to_s,
829 :wiki_id => project.wiki.id.to_s,
738 :title => 'Another renamed page',
830 :title => 'Another renamed page',
739 :redirect_existing_links => 1
831 :redirect_existing_links => 1
740 }
832 }
833 }
741 assert_redirected_to '/projects/private-child/wiki/Another_renamed_page'
834 assert_redirected_to '/projects/private-child/wiki/Another_renamed_page'
742
835
743 page = WikiPage.find(2)
836 page = WikiPage.find(2)
744 assert_equal project.wiki.id, page.wiki_id
837 assert_equal project.wiki.id, page.wiki_id
745 end
838 end
746
839
747 def test_destroy_a_page_without_children_should_not_ask_confirmation
840 def test_destroy_a_page_without_children_should_not_ask_confirmation
748 @request.session[:user_id] = 2
841 @request.session[:user_id] = 2
749 delete :destroy, :project_id => 1, :id => 'Child_2'
842 delete :destroy, :params => {:project_id => 1, :id => 'Child_2'}
750 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
843 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
751 end
844 end
752
845
753 def test_destroy_parent_should_ask_confirmation
846 def test_destroy_parent_should_ask_confirmation
754 @request.session[:user_id] = 2
847 @request.session[:user_id] = 2
755 assert_no_difference('WikiPage.count') do
848 assert_no_difference('WikiPage.count') do
756 delete :destroy, :project_id => 1, :id => 'Another_page'
849 delete :destroy, :params => {:project_id => 1, :id => 'Another_page'}
757 end
850 end
758 assert_response :success
851 assert_response :success
759 assert_template 'destroy'
852 assert_template 'destroy'
760 assert_select 'form' do
853 assert_select 'form' do
761 assert_select 'input[name=todo][value=nullify]'
854 assert_select 'input[name=todo][value=nullify]'
762 assert_select 'input[name=todo][value=destroy]'
855 assert_select 'input[name=todo][value=destroy]'
763 assert_select 'input[name=todo][value=reassign]'
856 assert_select 'input[name=todo][value=reassign]'
764 end
857 end
765 end
858 end
766
859
767 def test_destroy_parent_with_nullify_should_delete_parent_only
860 def test_destroy_parent_with_nullify_should_delete_parent_only
768 @request.session[:user_id] = 2
861 @request.session[:user_id] = 2
769 assert_difference('WikiPage.count', -1) do
862 assert_difference('WikiPage.count', -1) do
770 delete :destroy, :project_id => 1, :id => 'Another_page', :todo => 'nullify'
863 delete :destroy, :params => {:project_id => 1, :id => 'Another_page', :todo => 'nullify'}
771 end
864 end
772 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
865 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
773 assert_nil WikiPage.find_by_id(2)
866 assert_nil WikiPage.find_by_id(2)
774 end
867 end
775
868
776 def test_destroy_parent_with_cascade_should_delete_descendants
869 def test_destroy_parent_with_cascade_should_delete_descendants
777 @request.session[:user_id] = 2
870 @request.session[:user_id] = 2
778 assert_difference('WikiPage.count', -4) do
871 assert_difference('WikiPage.count', -4) do
779 delete :destroy, :project_id => 1, :id => 'Another_page', :todo => 'destroy'
872 delete :destroy, :params => {:project_id => 1, :id => 'Another_page', :todo => 'destroy'}
780 end
873 end
781 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
874 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
782 assert_nil WikiPage.find_by_id(2)
875 assert_nil WikiPage.find_by_id(2)
783 assert_nil WikiPage.find_by_id(5)
876 assert_nil WikiPage.find_by_id(5)
784 end
877 end
785
878
786 def test_destroy_parent_with_reassign
879 def test_destroy_parent_with_reassign
787 @request.session[:user_id] = 2
880 @request.session[:user_id] = 2
788 assert_difference('WikiPage.count', -1) do
881 assert_difference('WikiPage.count', -1) do
789 delete :destroy, :project_id => 1, :id => 'Another_page', :todo => 'reassign', :reassign_to_id => 1
882 delete :destroy, :params => {:project_id => 1, :id => 'Another_page', :todo => 'reassign', :reassign_to_id => 1}
790 end
883 end
791 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
884 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
792 assert_nil WikiPage.find_by_id(2)
885 assert_nil WikiPage.find_by_id(2)
793 assert_equal WikiPage.find(1), WikiPage.find_by_id(5).parent
886 assert_equal WikiPage.find(1), WikiPage.find_by_id(5).parent
794 end
887 end
795
888
796 def test_destroy_version
889 def test_destroy_version
797 @request.session[:user_id] = 2
890 @request.session[:user_id] = 2
798 assert_difference 'WikiContent::Version.count', -1 do
891 assert_difference 'WikiContent::Version.count', -1 do
799 assert_no_difference 'WikiContent.count' do
892 assert_no_difference 'WikiContent.count' do
800 assert_no_difference 'WikiPage.count' do
893 assert_no_difference 'WikiPage.count' do
801 delete :destroy_version, :project_id => 'ecookbook', :id => 'CookBook_documentation', :version => 2
894 delete :destroy_version, :params => {:project_id => 'ecookbook', :id => 'CookBook_documentation', :version => 2}
802 assert_redirected_to '/projects/ecookbook/wiki/CookBook_documentation/history'
895 assert_redirected_to '/projects/ecookbook/wiki/CookBook_documentation/history'
803 end
896 end
804 end
897 end
805 end
898 end
806 end
899 end
807
900
808 def test_destroy_invalid_version_should_respond_with_404
901 def test_destroy_invalid_version_should_respond_with_404
809 @request.session[:user_id] = 2
902 @request.session[:user_id] = 2
810 assert_no_difference 'WikiContent::Version.count' do
903 assert_no_difference 'WikiContent::Version.count' do
811 assert_no_difference 'WikiContent.count' do
904 assert_no_difference 'WikiContent.count' do
812 assert_no_difference 'WikiPage.count' do
905 assert_no_difference 'WikiPage.count' do
813 delete :destroy_version, :project_id => 'ecookbook', :id => 'CookBook_documentation', :version => 99
906 delete :destroy_version, :params => {:project_id => 'ecookbook', :id => 'CookBook_documentation', :version => 99}
814 end
907 end
815 end
908 end
816 end
909 end
817 assert_response 404
910 assert_response 404
818 end
911 end
819
912
820 def test_index
913 def test_index
821 get :index, :project_id => 'ecookbook'
914 get :index, :params => {:project_id => 'ecookbook'}
822 assert_response :success
915 assert_response :success
823 assert_template 'index'
916 assert_template 'index'
824 pages = assigns(:pages)
917 pages = assigns(:pages)
825 assert_not_nil pages
918 assert_not_nil pages
826 assert_equal Project.find(1).wiki.pages.size, pages.size
919 assert_equal Project.find(1).wiki.pages.size, pages.size
827 assert_equal pages.first.content.updated_on, pages.first.updated_on
920 assert_equal pages.first.content.updated_on, pages.first.updated_on
828
921
829 assert_select 'ul.pages-hierarchy' do
922 assert_select 'ul.pages-hierarchy' do
830 assert_select 'li' do
923 assert_select 'li' do
831 assert_select 'a[href=?]', '/projects/ecookbook/wiki/CookBook_documentation', :text => 'CookBook documentation'
924 assert_select 'a[href=?]', '/projects/ecookbook/wiki/CookBook_documentation', :text => 'CookBook documentation'
832 assert_select 'ul li a[href=?]', '/projects/ecookbook/wiki/Page_with_an_inline_image', :text => 'Page with an inline image'
925 assert_select 'ul li a[href=?]', '/projects/ecookbook/wiki/Page_with_an_inline_image', :text => 'Page with an inline image'
833 end
926 end
834 assert_select 'li a[href=?]', '/projects/ecookbook/wiki/Another_page', :text => 'Another page'
927 assert_select 'li a[href=?]', '/projects/ecookbook/wiki/Another_page', :text => 'Another page'
835 end
928 end
836 end
929 end
837
930
838 def test_index_should_include_atom_link
931 def test_index_should_include_atom_link
839 get :index, :project_id => 'ecookbook'
932 get :index, :params => {:project_id => 'ecookbook'}
840 assert_select 'a[href=?]', '/projects/ecookbook/activity.atom?show_wiki_edits=1'
933 assert_select 'a[href=?]', '/projects/ecookbook/activity.atom?show_wiki_edits=1'
841 end
934 end
842
935
843 def test_export_to_html
936 def test_export_to_html
844 @request.session[:user_id] = 2
937 @request.session[:user_id] = 2
845 get :export, :project_id => 'ecookbook'
938 get :export, :params => {:project_id => 'ecookbook'}
846
939
847 assert_response :success
940 assert_response :success
848 assert_not_nil assigns(:pages)
941 assert_not_nil assigns(:pages)
849 assert assigns(:pages).any?
942 assert assigns(:pages).any?
850 assert_equal "text/html", @response.content_type
943 assert_equal "text/html", @response.content_type
851
944
852 assert_select "a[name=?]", "CookBook_documentation"
945 assert_select "a[name=?]", "CookBook_documentation"
853 assert_select "a[name=?]", "Another_page"
946 assert_select "a[name=?]", "Another_page"
854 assert_select "a[name=?]", "Page_with_an_inline_image"
947 assert_select "a[name=?]", "Page_with_an_inline_image"
855 end
948 end
856
949
857 def test_export_to_pdf
950 def test_export_to_pdf
858 @request.session[:user_id] = 2
951 @request.session[:user_id] = 2
859 get :export, :project_id => 'ecookbook', :format => 'pdf'
952 get :export, :params => {:project_id => 'ecookbook', :format => 'pdf'}
860
953
861 assert_response :success
954 assert_response :success
862 assert_not_nil assigns(:pages)
955 assert_not_nil assigns(:pages)
863 assert assigns(:pages).any?
956 assert assigns(:pages).any?
864 assert_equal 'application/pdf', @response.content_type
957 assert_equal 'application/pdf', @response.content_type
865 assert_equal 'attachment; filename="ecookbook.pdf"', @response.headers['Content-Disposition']
958 assert_equal 'attachment; filename="ecookbook.pdf"', @response.headers['Content-Disposition']
866 assert @response.body.starts_with?('%PDF')
959 assert @response.body.starts_with?('%PDF')
867 end
960 end
868
961
869 def test_export_without_permission_should_be_denied
962 def test_export_without_permission_should_be_denied
870 @request.session[:user_id] = 2
963 @request.session[:user_id] = 2
871 Role.find_by_name('Manager').remove_permission! :export_wiki_pages
964 Role.find_by_name('Manager').remove_permission! :export_wiki_pages
872 get :export, :project_id => 'ecookbook'
965 get :export, :params => {:project_id => 'ecookbook'}
873
966
874 assert_response 403
967 assert_response 403
875 end
968 end
876
969
877 def test_date_index
970 def test_date_index
878 get :date_index, :project_id => 'ecookbook'
971 get :date_index, :params => {:project_id => 'ecookbook'}
879
972
880 assert_response :success
973 assert_response :success
881 assert_template 'date_index'
974 assert_template 'date_index'
882 assert_not_nil assigns(:pages)
975 assert_not_nil assigns(:pages)
883 assert_not_nil assigns(:pages_by_date)
976 assert_not_nil assigns(:pages_by_date)
884
977
885 assert_select 'a[href=?]', '/projects/ecookbook/activity.atom?show_wiki_edits=1'
978 assert_select 'a[href=?]', '/projects/ecookbook/activity.atom?show_wiki_edits=1'
886 end
979 end
887
980
888 def test_not_found
981 def test_not_found
889 get :show, :project_id => 999
982 get :show, :params => {:project_id => 999}
890 assert_response 404
983 assert_response 404
891 end
984 end
892
985
893 def test_protect_page
986 def test_protect_page
894 page = WikiPage.find_by_wiki_id_and_title(1, 'Another_page')
987 page = WikiPage.find_by_wiki_id_and_title(1, 'Another_page')
895 assert !page.protected?
988 assert !page.protected?
896 @request.session[:user_id] = 2
989 @request.session[:user_id] = 2
897 post :protect, :project_id => 1, :id => page.title, :protected => '1'
990 post :protect, :params => {:project_id => 1, :id => page.title, :protected => '1'}
898 assert_redirected_to :action => 'show', :project_id => 'ecookbook', :id => 'Another_page'
991 assert_redirected_to :action => 'show', :project_id => 'ecookbook', :id => 'Another_page'
899 assert page.reload.protected?
992 assert page.reload.protected?
900 end
993 end
901
994
902 def test_unprotect_page
995 def test_unprotect_page
903 page = WikiPage.find_by_wiki_id_and_title(1, 'CookBook_documentation')
996 page = WikiPage.find_by_wiki_id_and_title(1, 'CookBook_documentation')
904 assert page.protected?
997 assert page.protected?
905 @request.session[:user_id] = 2
998 @request.session[:user_id] = 2
906 post :protect, :project_id => 1, :id => page.title, :protected => '0'
999 post :protect, :params => {:project_id => 1, :id => page.title, :protected => '0'}
907 assert_redirected_to :action => 'show', :project_id => 'ecookbook', :id => 'CookBook_documentation'
1000 assert_redirected_to :action => 'show', :project_id => 'ecookbook', :id => 'CookBook_documentation'
908 assert !page.reload.protected?
1001 assert !page.reload.protected?
909 end
1002 end
910
1003
911 def test_show_page_with_edit_link
1004 def test_show_page_with_edit_link
912 @request.session[:user_id] = 2
1005 @request.session[:user_id] = 2
913 get :show, :project_id => 1
1006 get :show, :params => {:project_id => 1}
914 assert_response :success
1007 assert_response :success
915 assert_template 'show'
1008 assert_template 'show'
916 assert_select 'a[href=?]', '/projects/1/wiki/CookBook_documentation/edit'
1009 assert_select 'a[href=?]', '/projects/1/wiki/CookBook_documentation/edit'
917 end
1010 end
918
1011
919 def test_show_page_without_edit_link
1012 def test_show_page_without_edit_link
920 @request.session[:user_id] = 4
1013 @request.session[:user_id] = 4
921 get :show, :project_id => 1
1014 get :show, :params => {:project_id => 1}
922 assert_response :success
1015 assert_response :success
923 assert_template 'show'
1016 assert_template 'show'
924 assert_select 'a[href=?]', '/projects/1/wiki/CookBook_documentation/edit', 0
1017 assert_select 'a[href=?]', '/projects/1/wiki/CookBook_documentation/edit', 0
925 end
1018 end
926
1019
927 def test_show_pdf
1020 def test_show_pdf
928 @request.session[:user_id] = 2
1021 @request.session[:user_id] = 2
929 get :show, :project_id => 1, :format => 'pdf'
1022 get :show, :params => {:project_id => 1, :format => 'pdf'}
930 assert_response :success
1023 assert_response :success
931 assert_not_nil assigns(:page)
1024 assert_not_nil assigns(:page)
932 assert_equal 'application/pdf', @response.content_type
1025 assert_equal 'application/pdf', @response.content_type
933 assert_equal 'attachment; filename="CookBook_documentation.pdf"',
1026 assert_equal 'attachment; filename="CookBook_documentation.pdf"',
934 @response.headers['Content-Disposition']
1027 @response.headers['Content-Disposition']
935 end
1028 end
936
1029
937 def test_show_html
1030 def test_show_html
938 @request.session[:user_id] = 2
1031 @request.session[:user_id] = 2
939 get :show, :project_id => 1, :format => 'html'
1032 get :show, :params => {:project_id => 1, :format => 'html'}
940 assert_response :success
1033 assert_response :success
941 assert_not_nil assigns(:page)
1034 assert_not_nil assigns(:page)
942 assert_equal 'text/html', @response.content_type
1035 assert_equal 'text/html', @response.content_type
943 assert_equal 'attachment; filename="CookBook_documentation.html"',
1036 assert_equal 'attachment; filename="CookBook_documentation.html"',
944 @response.headers['Content-Disposition']
1037 @response.headers['Content-Disposition']
945 assert_select 'h1', :text => /CookBook documentation/
1038 assert_select 'h1', :text => /CookBook documentation/
946 end
1039 end
947
1040
948 def test_show_versioned_html
1041 def test_show_versioned_html
949 @request.session[:user_id] = 2
1042 @request.session[:user_id] = 2
950 get :show, :project_id => 1, :format => 'html', :version => 2
1043 get :show, :params => {:project_id => 1, :format => 'html', :version => 2}
951 assert_response :success
1044 assert_response :success
952 assert_not_nil assigns(:content)
1045 assert_not_nil assigns(:content)
953 assert_equal 2, assigns(:content).version
1046 assert_equal 2, assigns(:content).version
954 assert_equal 'text/html', @response.content_type
1047 assert_equal 'text/html', @response.content_type
955 assert_equal 'attachment; filename="CookBook_documentation.html"',
1048 assert_equal 'attachment; filename="CookBook_documentation.html"',
956 @response.headers['Content-Disposition']
1049 @response.headers['Content-Disposition']
957 assert_select 'h1', :text => /CookBook documentation/
1050 assert_select 'h1', :text => /CookBook documentation/
958 end
1051 end
959
1052
960 def test_show_txt
1053 def test_show_txt
961 @request.session[:user_id] = 2
1054 @request.session[:user_id] = 2
962 get :show, :project_id => 1, :format => 'txt'
1055 get :show, :params => {:project_id => 1, :format => 'txt'}
963 assert_response :success
1056 assert_response :success
964 assert_not_nil assigns(:page)
1057 assert_not_nil assigns(:page)
965 assert_equal 'text/plain', @response.content_type
1058 assert_equal 'text/plain', @response.content_type
966 assert_equal 'attachment; filename="CookBook_documentation.txt"',
1059 assert_equal 'attachment; filename="CookBook_documentation.txt"',
967 @response.headers['Content-Disposition']
1060 @response.headers['Content-Disposition']
968 assert_include 'h1. CookBook documentation', @response.body
1061 assert_include 'h1. CookBook documentation', @response.body
969 end
1062 end
970
1063
971 def test_show_versioned_txt
1064 def test_show_versioned_txt
972 @request.session[:user_id] = 2
1065 @request.session[:user_id] = 2
973 get :show, :project_id => 1, :format => 'txt', :version => 2
1066 get :show, :params => {:project_id => 1, :format => 'txt', :version => 2}
974 assert_response :success
1067 assert_response :success
975 assert_not_nil assigns(:content)
1068 assert_not_nil assigns(:content)
976 assert_equal 2, assigns(:content).version
1069 assert_equal 2, assigns(:content).version
977 assert_equal 'text/plain', @response.content_type
1070 assert_equal 'text/plain', @response.content_type
978 assert_equal 'attachment; filename="CookBook_documentation.txt"',
1071 assert_equal 'attachment; filename="CookBook_documentation.txt"',
979 @response.headers['Content-Disposition']
1072 @response.headers['Content-Disposition']
980 assert_include 'h1. CookBook documentation', @response.body
1073 assert_include 'h1. CookBook documentation', @response.body
981 end
1074 end
982
1075
983 def test_edit_unprotected_page
1076 def test_edit_unprotected_page
984 # Non members can edit unprotected wiki pages
1077 # Non members can edit unprotected wiki pages
985 @request.session[:user_id] = 4
1078 @request.session[:user_id] = 4
986 get :edit, :project_id => 1, :id => 'Another_page'
1079 get :edit, :params => {:project_id => 1, :id => 'Another_page'}
987 assert_response :success
1080 assert_response :success
988 assert_template 'edit'
1081 assert_template 'edit'
989 end
1082 end
990
1083
991 def test_edit_protected_page_by_nonmember
1084 def test_edit_protected_page_by_nonmember
992 # Non members cannot edit protected wiki pages
1085 # Non members cannot edit protected wiki pages
993 @request.session[:user_id] = 4
1086 @request.session[:user_id] = 4
994 get :edit, :project_id => 1, :id => 'CookBook_documentation'
1087 get :edit, :params => {:project_id => 1, :id => 'CookBook_documentation'}
995 assert_response 403
1088 assert_response 403
996 end
1089 end
997
1090
998 def test_edit_protected_page_by_member
1091 def test_edit_protected_page_by_member
999 @request.session[:user_id] = 2
1092 @request.session[:user_id] = 2
1000 get :edit, :project_id => 1, :id => 'CookBook_documentation'
1093 get :edit, :params => {:project_id => 1, :id => 'CookBook_documentation'}
1001 assert_response :success
1094 assert_response :success
1002 assert_template 'edit'
1095 assert_template 'edit'
1003 end
1096 end
1004
1097
1005 def test_history_of_non_existing_page_should_return_404
1098 def test_history_of_non_existing_page_should_return_404
1006 get :history, :project_id => 1, :id => 'Unknown_page'
1099 get :history, :params => {:project_id => 1, :id => 'Unknown_page'}
1007 assert_response 404
1100 assert_response 404
1008 end
1101 end
1009
1102
1010 def test_add_attachment
1103 def test_add_attachment
1011 @request.session[:user_id] = 2
1104 @request.session[:user_id] = 2
1012 assert_difference 'Attachment.count' do
1105 assert_difference 'Attachment.count' do
1013 post :add_attachment, :project_id => 1, :id => 'CookBook_documentation',
1106 post :add_attachment, :params => {
1014 :attachments => {
1107 :project_id => 1,
1015 '1' => {'file' => uploaded_test_file('testfile.txt', 'text/plain'),
1108 :id => 'CookBook_documentation',
1016 'description' => 'test file'}
1109 :attachments => {
1017 }
1110 '1' => {'file' => uploaded_test_file('testfile.txt', 'text/plain'), 'description' => 'test file'}
1111 }
1112 }
1018 end
1113 end
1019 attachment = Attachment.order('id DESC').first
1114 attachment = Attachment.order('id DESC').first
1020 assert_equal Wiki.find(1).find_page('CookBook_documentation'), attachment.container
1115 assert_equal Wiki.find(1).find_page('CookBook_documentation'), attachment.container
1021 end
1116 end
1022 end
1117 end
@@ -1,84 +1,84
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2016 Jean-Philippe Lang
2 # Copyright (C) 2006-2016 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 require File.expand_path('../../test_helper', __FILE__)
18 require File.expand_path('../../test_helper', __FILE__)
19
19
20 class WikisControllerTest < Redmine::ControllerTest
20 class WikisControllerTest < Redmine::ControllerTest
21 fixtures :projects, :users, :roles, :members, :member_roles, :enabled_modules, :wikis
21 fixtures :projects, :users, :roles, :members, :member_roles, :enabled_modules, :wikis
22
22
23 def setup
23 def setup
24 User.current = nil
24 User.current = nil
25 end
25 end
26
26
27 def test_create
27 def test_create
28 @request.session[:user_id] = 1
28 @request.session[:user_id] = 1
29 assert_nil Project.find(3).wiki
29 assert_nil Project.find(3).wiki
30
30
31 assert_difference 'Wiki.count' do
31 assert_difference 'Wiki.count' do
32 xhr :post, :edit, :id => 3, :wiki => { :start_page => 'Start page' }
32 xhr :post, :edit, :params => {:id => 3, :wiki => { :start_page => 'Start page' }}
33 assert_response :success
33 assert_response :success
34 assert_template 'edit'
34 assert_template 'edit'
35 assert_equal 'text/javascript', response.content_type
35 assert_equal 'text/javascript', response.content_type
36 end
36 end
37
37
38 wiki = Project.find(3).wiki
38 wiki = Project.find(3).wiki
39 assert_not_nil wiki
39 assert_not_nil wiki
40 assert_equal 'Start page', wiki.start_page
40 assert_equal 'Start page', wiki.start_page
41 end
41 end
42
42
43 def test_create_with_failure
43 def test_create_with_failure
44 @request.session[:user_id] = 1
44 @request.session[:user_id] = 1
45
45
46 assert_no_difference 'Wiki.count' do
46 assert_no_difference 'Wiki.count' do
47 xhr :post, :edit, :id => 3, :wiki => { :start_page => '' }
47 xhr :post, :edit, :params => {:id => 3, :wiki => { :start_page => '' }}
48 assert_response :success
48 assert_response :success
49 assert_template 'edit'
49 assert_template 'edit'
50 assert_equal 'text/javascript', response.content_type
50 assert_equal 'text/javascript', response.content_type
51 end
51 end
52
52
53 assert_include 'errorExplanation', response.body
53 assert_include 'errorExplanation', response.body
54 assert_include "Start page cannot be blank", response.body
54 assert_include "Start page cannot be blank", response.body
55 end
55 end
56
56
57 def test_update
57 def test_update
58 @request.session[:user_id] = 1
58 @request.session[:user_id] = 1
59
59
60 assert_no_difference 'Wiki.count' do
60 assert_no_difference 'Wiki.count' do
61 xhr :post, :edit, :id => 1, :wiki => { :start_page => 'Other start page' }
61 xhr :post, :edit, :params => {:id => 1, :wiki => { :start_page => 'Other start page' }}
62 assert_response :success
62 assert_response :success
63 assert_template 'edit'
63 assert_template 'edit'
64 assert_equal 'text/javascript', response.content_type
64 assert_equal 'text/javascript', response.content_type
65 end
65 end
66
66
67 wiki = Project.find(1).wiki
67 wiki = Project.find(1).wiki
68 assert_equal 'Other start page', wiki.start_page
68 assert_equal 'Other start page', wiki.start_page
69 end
69 end
70
70
71 def test_destroy
71 def test_destroy
72 @request.session[:user_id] = 1
72 @request.session[:user_id] = 1
73 post :destroy, :id => 1, :confirm => 1
73 post :destroy, :params => {:id => 1, :confirm => 1}
74 assert_redirected_to :controller => 'projects',
74 assert_redirected_to :controller => 'projects',
75 :action => 'settings', :id => 'ecookbook', :tab => 'wiki'
75 :action => 'settings', :id => 'ecookbook', :tab => 'wiki'
76 assert_nil Project.find(1).wiki
76 assert_nil Project.find(1).wiki
77 end
77 end
78
78
79 def test_not_found
79 def test_not_found
80 @request.session[:user_id] = 1
80 @request.session[:user_id] = 1
81 post :destroy, :id => 999, :confirm => 1
81 post :destroy, :params => {:id => 999, :confirm => 1}
82 assert_response 404
82 assert_response 404
83 end
83 end
84 end
84 end
@@ -1,396 +1,417
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2016 Jean-Philippe Lang
2 # Copyright (C) 2006-2016 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 require File.expand_path('../../test_helper', __FILE__)
18 require File.expand_path('../../test_helper', __FILE__)
19
19
20 class WorkflowsControllerTest < Redmine::ControllerTest
20 class WorkflowsControllerTest < Redmine::ControllerTest
21 fixtures :roles, :trackers, :workflows, :users, :issue_statuses
21 fixtures :roles, :trackers, :workflows, :users, :issue_statuses
22
22
23 def setup
23 def setup
24 User.current = nil
24 User.current = nil
25 @request.session[:user_id] = 1 # admin
25 @request.session[:user_id] = 1 # admin
26 end
26 end
27
27
28 def test_index
28 def test_index
29 get :index
29 get :index
30 assert_response :success
30 assert_response :success
31 assert_template 'index'
31 assert_template 'index'
32
32
33 count = WorkflowTransition.where(:role_id => 1, :tracker_id => 2).count
33 count = WorkflowTransition.where(:role_id => 1, :tracker_id => 2).count
34 assert_select 'a[href=?]', '/workflows/edit?role_id=1&tracker_id=2', :content => count.to_s
34 assert_select 'a[href=?]', '/workflows/edit?role_id=1&tracker_id=2', :content => count.to_s
35 end
35 end
36
36
37 def test_get_edit
37 def test_get_edit
38 get :edit
38 get :edit
39 assert_response :success
39 assert_response :success
40 assert_template 'edit'
40 assert_template 'edit'
41 end
41 end
42
42
43 def test_get_edit_with_role_and_tracker
43 def test_get_edit_with_role_and_tracker
44 WorkflowTransition.delete_all
44 WorkflowTransition.delete_all
45 WorkflowTransition.create!(:role_id => 1, :tracker_id => 1, :old_status_id => 2, :new_status_id => 3)
45 WorkflowTransition.create!(:role_id => 1, :tracker_id => 1, :old_status_id => 2, :new_status_id => 3)
46 WorkflowTransition.create!(:role_id => 2, :tracker_id => 1, :old_status_id => 3, :new_status_id => 5)
46 WorkflowTransition.create!(:role_id => 2, :tracker_id => 1, :old_status_id => 3, :new_status_id => 5)
47
47
48 get :edit, :role_id => 2, :tracker_id => 1
48 get :edit, :params => {:role_id => 2, :tracker_id => 1}
49 assert_response :success
49 assert_response :success
50 assert_template 'edit'
50 assert_template 'edit'
51
51
52 # used status only
52 # used status only
53 assert_not_nil assigns(:statuses)
53 assert_not_nil assigns(:statuses)
54 assert_equal [2, 3, 5], assigns(:statuses).collect(&:id)
54 assert_equal [2, 3, 5], assigns(:statuses).collect(&:id)
55
55
56 # allowed transitions
56 # allowed transitions
57 assert_select 'input[type=checkbox][name=?][value="1"][checked=checked]', 'transitions[3][5][always]'
57 assert_select 'input[type=checkbox][name=?][value="1"][checked=checked]', 'transitions[3][5][always]'
58 # not allowed
58 # not allowed
59 assert_select 'input[type=checkbox][name=?][value="1"]:not([checked=checked])', 'transitions[3][2][always]'
59 assert_select 'input[type=checkbox][name=?][value="1"]:not([checked=checked])', 'transitions[3][2][always]'
60 # unused
60 # unused
61 assert_select 'input[type=checkbox][name=?]', 'transitions[1][1][always]', 0
61 assert_select 'input[type=checkbox][name=?]', 'transitions[1][1][always]', 0
62 end
62 end
63
63
64 def test_get_edit_should_include_allowed_statuses_for_new_issues
64 def test_get_edit_should_include_allowed_statuses_for_new_issues
65 WorkflowTransition.delete_all
65 WorkflowTransition.delete_all
66 WorkflowTransition.create!(:role_id => 1, :tracker_id => 1, :old_status_id => 0, :new_status_id => 1)
66 WorkflowTransition.create!(:role_id => 1, :tracker_id => 1, :old_status_id => 0, :new_status_id => 1)
67
67
68 get :edit, :role_id => 1, :tracker_id => 1
68 get :edit, :params => {:role_id => 1, :tracker_id => 1}
69 assert_response :success
69 assert_response :success
70 assert_select 'td', 'New issue'
70 assert_select 'td', 'New issue'
71 assert_select 'input[type=checkbox][name=?][value="1"][checked=checked]', 'transitions[0][1][always]'
71 assert_select 'input[type=checkbox][name=?][value="1"][checked=checked]', 'transitions[0][1][always]'
72 end
72 end
73
73
74 def test_get_edit_with_all_roles_and_all_trackers
74 def test_get_edit_with_all_roles_and_all_trackers
75 get :edit, :role_id => 'all', :tracker_id => 'all'
75 get :edit, :params => {:role_id => 'all', :tracker_id => 'all'}
76 assert_response :success
76 assert_response :success
77 assert_equal Role.sorted.to_a, assigns(:roles)
77 assert_equal Role.sorted.to_a, assigns(:roles)
78 assert_equal Tracker.sorted.to_a, assigns(:trackers)
78 assert_equal Tracker.sorted.to_a, assigns(:trackers)
79 end
79 end
80
80
81 def test_get_edit_with_role_and_tracker_and_all_statuses
81 def test_get_edit_with_role_and_tracker_and_all_statuses
82 WorkflowTransition.delete_all
82 WorkflowTransition.delete_all
83
83
84 get :edit, :role_id => 2, :tracker_id => 1, :used_statuses_only => '0'
84 get :edit, :params => {:role_id => 2, :tracker_id => 1, :used_statuses_only => '0'}
85 assert_response :success
85 assert_response :success
86 assert_template 'edit'
86 assert_template 'edit'
87
87
88 assert_not_nil assigns(:statuses)
88 assert_not_nil assigns(:statuses)
89 assert_equal IssueStatus.count, assigns(:statuses).size
89 assert_equal IssueStatus.count, assigns(:statuses).size
90
90
91 assert_select 'input[type=checkbox][name=?]', 'transitions[1][1][always]'
91 assert_select 'input[type=checkbox][name=?]', 'transitions[1][1][always]'
92 end
92 end
93
93
94 def test_post_edit
94 def test_post_edit
95 WorkflowTransition.delete_all
95 WorkflowTransition.delete_all
96
96
97 post :edit, :role_id => 2, :tracker_id => 1,
97 post :edit, :params => {
98 :role_id => 2,
99 :tracker_id => 1,
98 :transitions => {
100 :transitions => {
99 '4' => {'5' => {'always' => '1'}},
101 '4' => {'5' => {'always' => '1'}},
100 '3' => {'1' => {'always' => '1'}, '2' => {'always' => '1'}}
102 '3' => {'1' => {'always' => '1'}, '2' => {'always' => '1'}}
101 }
103 }
104 }
102 assert_response 302
105 assert_response 302
103
106
104 assert_equal 3, WorkflowTransition.where(:tracker_id => 1, :role_id => 2).count
107 assert_equal 3, WorkflowTransition.where(:tracker_id => 1, :role_id => 2).count
105 assert_not_nil WorkflowTransition.where(:role_id => 2, :tracker_id => 1, :old_status_id => 3, :new_status_id => 2).first
108 assert_not_nil WorkflowTransition.where(:role_id => 2, :tracker_id => 1, :old_status_id => 3, :new_status_id => 2).first
106 assert_nil WorkflowTransition.where(:role_id => 2, :tracker_id => 1, :old_status_id => 5, :new_status_id => 4).first
109 assert_nil WorkflowTransition.where(:role_id => 2, :tracker_id => 1, :old_status_id => 5, :new_status_id => 4).first
107 end
110 end
108
111
109 def test_post_edit_with_allowed_statuses_for_new_issues
112 def test_post_edit_with_allowed_statuses_for_new_issues
110 WorkflowTransition.delete_all
113 WorkflowTransition.delete_all
111
114
112 post :edit, :role_id => 2, :tracker_id => 1,
115 post :edit, :params => {
116 :role_id => 2,
117 :tracker_id => 1,
113 :transitions => {
118 :transitions => {
114 '0' => {'1' => {'always' => '1'}, '2' => {'always' => '1'}}
119 '0' => {'1' => {'always' => '1'}, '2' => {'always' => '1'}}
115 }
120 }
121 }
116 assert_response 302
122 assert_response 302
117
123
118 assert WorkflowTransition.where(:role_id => 2, :tracker_id => 1, :old_status_id => 0, :new_status_id => 1).any?
124 assert WorkflowTransition.where(:role_id => 2, :tracker_id => 1, :old_status_id => 0, :new_status_id => 1).any?
119 assert WorkflowTransition.where(:role_id => 2, :tracker_id => 1, :old_status_id => 0, :new_status_id => 2).any?
125 assert WorkflowTransition.where(:role_id => 2, :tracker_id => 1, :old_status_id => 0, :new_status_id => 2).any?
120 assert_equal 2, WorkflowTransition.where(:tracker_id => 1, :role_id => 2).count
126 assert_equal 2, WorkflowTransition.where(:tracker_id => 1, :role_id => 2).count
121 end
127 end
122
128
123 def test_post_edit_with_additional_transitions
129 def test_post_edit_with_additional_transitions
124 WorkflowTransition.delete_all
130 WorkflowTransition.delete_all
125
131
126 post :edit, :role_id => 2, :tracker_id => 1,
132 post :edit, :params => {
133 :role_id => 2,
134 :tracker_id => 1,
127 :transitions => {
135 :transitions => {
128 '4' => {'5' => {'always' => '1', 'author' => '0', 'assignee' => '0'}},
136 '4' => {'5' => {'always' => '1', 'author' => '0', 'assignee' => '0'}},
129 '3' => {'1' => {'always' => '0', 'author' => '1', 'assignee' => '0'},
137 '3' => {'1' => {'always' => '0', 'author' => '1', 'assignee' => '0'},
130 '2' => {'always' => '0', 'author' => '0', 'assignee' => '1'},
138 '2' => {'always' => '0', 'author' => '0', 'assignee' => '1'},
131 '4' => {'always' => '0', 'author' => '1', 'assignee' => '1'}}
139 '4' => {'always' => '0', 'author' => '1', 'assignee' => '1'}}
132 }
140 }
141 }
133 assert_response 302
142 assert_response 302
134
143
135 assert_equal 4, WorkflowTransition.where(:tracker_id => 1, :role_id => 2).count
144 assert_equal 4, WorkflowTransition.where(:tracker_id => 1, :role_id => 2).count
136
145
137 w = WorkflowTransition.where(:role_id => 2, :tracker_id => 1, :old_status_id => 4, :new_status_id => 5).first
146 w = WorkflowTransition.where(:role_id => 2, :tracker_id => 1, :old_status_id => 4, :new_status_id => 5).first
138 assert ! w.author
147 assert ! w.author
139 assert ! w.assignee
148 assert ! w.assignee
140 w = WorkflowTransition.where(:role_id => 2, :tracker_id => 1, :old_status_id => 3, :new_status_id => 1).first
149 w = WorkflowTransition.where(:role_id => 2, :tracker_id => 1, :old_status_id => 3, :new_status_id => 1).first
141 assert w.author
150 assert w.author
142 assert ! w.assignee
151 assert ! w.assignee
143 w = WorkflowTransition.where(:role_id => 2, :tracker_id => 1, :old_status_id => 3, :new_status_id => 2).first
152 w = WorkflowTransition.where(:role_id => 2, :tracker_id => 1, :old_status_id => 3, :new_status_id => 2).first
144 assert ! w.author
153 assert ! w.author
145 assert w.assignee
154 assert w.assignee
146 w = WorkflowTransition.where(:role_id => 2, :tracker_id => 1, :old_status_id => 3, :new_status_id => 4).first
155 w = WorkflowTransition.where(:role_id => 2, :tracker_id => 1, :old_status_id => 3, :new_status_id => 4).first
147 assert w.author
156 assert w.author
148 assert w.assignee
157 assert w.assignee
149 end
158 end
150
159
151 def test_get_permissions
160 def test_get_permissions
152 get :permissions
161 get :permissions
153
162
154 assert_response :success
163 assert_response :success
155 assert_template 'permissions'
164 assert_template 'permissions'
156 end
165 end
157
166
158 def test_get_permissions_with_role_and_tracker
167 def test_get_permissions_with_role_and_tracker
159 WorkflowPermission.delete_all
168 WorkflowPermission.delete_all
160 WorkflowPermission.create!(:role_id => 1, :tracker_id => 2, :old_status_id => 2, :field_name => 'assigned_to_id', :rule => 'required')
169 WorkflowPermission.create!(:role_id => 1, :tracker_id => 2, :old_status_id => 2, :field_name => 'assigned_to_id', :rule => 'required')
161 WorkflowPermission.create!(:role_id => 1, :tracker_id => 2, :old_status_id => 2, :field_name => 'fixed_version_id', :rule => 'required')
170 WorkflowPermission.create!(:role_id => 1, :tracker_id => 2, :old_status_id => 2, :field_name => 'fixed_version_id', :rule => 'required')
162 WorkflowPermission.create!(:role_id => 1, :tracker_id => 2, :old_status_id => 3, :field_name => 'fixed_version_id', :rule => 'readonly')
171 WorkflowPermission.create!(:role_id => 1, :tracker_id => 2, :old_status_id => 3, :field_name => 'fixed_version_id', :rule => 'readonly')
163
172
164 get :permissions, :role_id => 1, :tracker_id => 2
173 get :permissions, :params => {:role_id => 1, :tracker_id => 2}
165 assert_response :success
174 assert_response :success
166 assert_template 'permissions'
175 assert_template 'permissions'
167
176
168 assert_select 'input[name=?][value="1"]', 'role_id[]'
177 assert_select 'input[name=?][value="1"]', 'role_id[]'
169 assert_select 'input[name=?][value="2"]', 'tracker_id[]'
178 assert_select 'input[name=?][value="2"]', 'tracker_id[]'
170
179
171 # Required field
180 # Required field
172 assert_select 'select[name=?]', 'permissions[2][assigned_to_id]' do
181 assert_select 'select[name=?]', 'permissions[2][assigned_to_id]' do
173 assert_select 'option[value=""]'
182 assert_select 'option[value=""]'
174 assert_select 'option[value=""][selected=selected]', 0
183 assert_select 'option[value=""][selected=selected]', 0
175 assert_select 'option[value=readonly]', :text => 'Read-only'
184 assert_select 'option[value=readonly]', :text => 'Read-only'
176 assert_select 'option[value=readonly][selected=selected]', 0
185 assert_select 'option[value=readonly][selected=selected]', 0
177 assert_select 'option[value=required]', :text => 'Required'
186 assert_select 'option[value=required]', :text => 'Required'
178 assert_select 'option[value=required][selected=selected]'
187 assert_select 'option[value=required][selected=selected]'
179 end
188 end
180
189
181 # Read-only field
190 # Read-only field
182 assert_select 'select[name=?]', 'permissions[3][fixed_version_id]' do
191 assert_select 'select[name=?]', 'permissions[3][fixed_version_id]' do
183 assert_select 'option[value=""]'
192 assert_select 'option[value=""]'
184 assert_select 'option[value=""][selected=selected]', 0
193 assert_select 'option[value=""][selected=selected]', 0
185 assert_select 'option[value=readonly]', :text => 'Read-only'
194 assert_select 'option[value=readonly]', :text => 'Read-only'
186 assert_select 'option[value=readonly][selected=selected]'
195 assert_select 'option[value=readonly][selected=selected]'
187 assert_select 'option[value=required]', :text => 'Required'
196 assert_select 'option[value=required]', :text => 'Required'
188 assert_select 'option[value=required][selected=selected]', 0
197 assert_select 'option[value=required][selected=selected]', 0
189 end
198 end
190
199
191 # Other field
200 # Other field
192 assert_select 'select[name=?]', 'permissions[3][due_date]' do
201 assert_select 'select[name=?]', 'permissions[3][due_date]' do
193 assert_select 'option[value=""]'
202 assert_select 'option[value=""]'
194 assert_select 'option[value=""][selected=selected]', 0
203 assert_select 'option[value=""][selected=selected]', 0
195 assert_select 'option[value=readonly]', :text => 'Read-only'
204 assert_select 'option[value=readonly]', :text => 'Read-only'
196 assert_select 'option[value=readonly][selected=selected]', 0
205 assert_select 'option[value=readonly][selected=selected]', 0
197 assert_select 'option[value=required]', :text => 'Required'
206 assert_select 'option[value=required]', :text => 'Required'
198 assert_select 'option[value=required][selected=selected]', 0
207 assert_select 'option[value=required][selected=selected]', 0
199 end
208 end
200 end
209 end
201
210
202 def test_get_permissions_with_required_custom_field_should_not_show_required_option
211 def test_get_permissions_with_required_custom_field_should_not_show_required_option
203 cf = IssueCustomField.create!(:name => 'Foo', :field_format => 'string', :tracker_ids => [1], :is_required => true)
212 cf = IssueCustomField.create!(:name => 'Foo', :field_format => 'string', :tracker_ids => [1], :is_required => true)
204
213
205 get :permissions, :role_id => 1, :tracker_id => 1
214 get :permissions, :params => {:role_id => 1, :tracker_id => 1}
206 assert_response :success
215 assert_response :success
207 assert_template 'permissions'
216 assert_template 'permissions'
208
217
209 # Custom field that is always required
218 # Custom field that is always required
210 # The default option is "(Required)"
219 # The default option is "(Required)"
211 assert_select 'select[name=?]', "permissions[3][#{cf.id}]" do
220 assert_select 'select[name=?]', "permissions[3][#{cf.id}]" do
212 assert_select 'option[value=""]'
221 assert_select 'option[value=""]'
213 assert_select 'option[value=readonly]', :text => 'Read-only'
222 assert_select 'option[value=readonly]', :text => 'Read-only'
214 assert_select 'option[value=required]', 0
223 assert_select 'option[value=required]', 0
215 end
224 end
216 end
225 end
217
226
218 def test_get_permissions_should_disable_hidden_custom_fields
227 def test_get_permissions_should_disable_hidden_custom_fields
219 cf1 = IssueCustomField.generate!(:tracker_ids => [1], :visible => true)
228 cf1 = IssueCustomField.generate!(:tracker_ids => [1], :visible => true)
220 cf2 = IssueCustomField.generate!(:tracker_ids => [1], :visible => false, :role_ids => [1])
229 cf2 = IssueCustomField.generate!(:tracker_ids => [1], :visible => false, :role_ids => [1])
221 cf3 = IssueCustomField.generate!(:tracker_ids => [1], :visible => false, :role_ids => [1, 2])
230 cf3 = IssueCustomField.generate!(:tracker_ids => [1], :visible => false, :role_ids => [1, 2])
222
231
223 get :permissions, :role_id => 2, :tracker_id => 1
232 get :permissions, :params => {:role_id => 2, :tracker_id => 1}
224 assert_response :success
233 assert_response :success
225 assert_template 'permissions'
234 assert_template 'permissions'
226
235
227 assert_select 'select[name=?]:not(.disabled)', "permissions[1][#{cf1.id}]"
236 assert_select 'select[name=?]:not(.disabled)', "permissions[1][#{cf1.id}]"
228 assert_select 'select[name=?]:not(.disabled)', "permissions[1][#{cf3.id}]"
237 assert_select 'select[name=?]:not(.disabled)', "permissions[1][#{cf3.id}]"
229
238
230 assert_select 'select[name=?][disabled=disabled]', "permissions[1][#{cf2.id}]" do
239 assert_select 'select[name=?][disabled=disabled]', "permissions[1][#{cf2.id}]" do
231 assert_select 'option[value=""][selected=selected]', :text => 'Hidden'
240 assert_select 'option[value=""][selected=selected]', :text => 'Hidden'
232 end
241 end
233 end
242 end
234
243
235 def test_get_permissions_with_missing_permissions_for_roles_should_default_to_no_change
244 def test_get_permissions_with_missing_permissions_for_roles_should_default_to_no_change
236 WorkflowPermission.delete_all
245 WorkflowPermission.delete_all
237 WorkflowPermission.create!(:role_id => 1, :tracker_id => 2, :old_status_id => 1, :field_name => 'assigned_to_id', :rule => 'required')
246 WorkflowPermission.create!(:role_id => 1, :tracker_id => 2, :old_status_id => 1, :field_name => 'assigned_to_id', :rule => 'required')
238
247
239 get :permissions, :role_id => [1, 2], :tracker_id => 2
248 get :permissions, :params => {:role_id => [1, 2], :tracker_id => 2}
240 assert_response :success
249 assert_response :success
241
250
242 assert_select 'select[name=?]', 'permissions[1][assigned_to_id]' do
251 assert_select 'select[name=?]', 'permissions[1][assigned_to_id]' do
243 assert_select 'option[selected]', 1
252 assert_select 'option[selected]', 1
244 assert_select 'option[selected][value=no_change]'
253 assert_select 'option[selected][value=no_change]'
245 end
254 end
246 end
255 end
247
256
248 def test_get_permissions_with_different_permissions_for_roles_should_default_to_no_change
257 def test_get_permissions_with_different_permissions_for_roles_should_default_to_no_change
249 WorkflowPermission.delete_all
258 WorkflowPermission.delete_all
250 WorkflowPermission.create!(:role_id => 1, :tracker_id => 2, :old_status_id => 1, :field_name => 'assigned_to_id', :rule => 'required')
259 WorkflowPermission.create!(:role_id => 1, :tracker_id => 2, :old_status_id => 1, :field_name => 'assigned_to_id', :rule => 'required')
251 WorkflowPermission.create!(:role_id => 2, :tracker_id => 2, :old_status_id => 1, :field_name => 'assigned_to_id', :rule => 'readonly')
260 WorkflowPermission.create!(:role_id => 2, :tracker_id => 2, :old_status_id => 1, :field_name => 'assigned_to_id', :rule => 'readonly')
252
261
253 get :permissions, :role_id => [1, 2], :tracker_id => 2
262 get :permissions, :params => {:role_id => [1, 2], :tracker_id => 2}
254 assert_response :success
263 assert_response :success
255
264
256 assert_select 'select[name=?]', 'permissions[1][assigned_to_id]' do
265 assert_select 'select[name=?]', 'permissions[1][assigned_to_id]' do
257 assert_select 'option[selected]', 1
266 assert_select 'option[selected]', 1
258 assert_select 'option[selected][value=no_change]'
267 assert_select 'option[selected][value=no_change]'
259 end
268 end
260 end
269 end
261
270
262 def test_get_permissions_with_same_permissions_for_roles_should_default_to_permission
271 def test_get_permissions_with_same_permissions_for_roles_should_default_to_permission
263 WorkflowPermission.delete_all
272 WorkflowPermission.delete_all
264 WorkflowPermission.create!(:role_id => 1, :tracker_id => 2, :old_status_id => 1, :field_name => 'assigned_to_id', :rule => 'required')
273 WorkflowPermission.create!(:role_id => 1, :tracker_id => 2, :old_status_id => 1, :field_name => 'assigned_to_id', :rule => 'required')
265 WorkflowPermission.create!(:role_id => 2, :tracker_id => 2, :old_status_id => 1, :field_name => 'assigned_to_id', :rule => 'required')
274 WorkflowPermission.create!(:role_id => 2, :tracker_id => 2, :old_status_id => 1, :field_name => 'assigned_to_id', :rule => 'required')
266
275
267 get :permissions, :role_id => [1, 2], :tracker_id => 2
276 get :permissions, :params => {:role_id => [1, 2], :tracker_id => 2}
268 assert_response :success
277 assert_response :success
269
278
270 assert_select 'select[name=?]', 'permissions[1][assigned_to_id]' do
279 assert_select 'select[name=?]', 'permissions[1][assigned_to_id]' do
271 assert_select 'option[selected]', 1
280 assert_select 'option[selected]', 1
272 assert_select 'option[selected][value=required]'
281 assert_select 'option[selected][value=required]'
273 end
282 end
274 end
283 end
275
284
276 def test_get_permissions_with_role_and_tracker_and_all_statuses_should_show_all_statuses
285 def test_get_permissions_with_role_and_tracker_and_all_statuses_should_show_all_statuses
277 WorkflowTransition.delete_all
286 WorkflowTransition.delete_all
278
287
279 get :permissions, :role_id => 1, :tracker_id => 2, :used_statuses_only => '0'
288 get :permissions, :params => {:role_id => 1, :tracker_id => 2, :used_statuses_only => '0'}
280 assert_response :success
289 assert_response :success
281 assert_equal IssueStatus.sorted.to_a, assigns(:statuses)
290 assert_equal IssueStatus.sorted.to_a, assigns(:statuses)
282 end
291 end
283
292
284 def test_get_permissions_should_set_css_class
293 def test_get_permissions_should_set_css_class
285 WorkflowPermission.delete_all
294 WorkflowPermission.delete_all
286 WorkflowPermission.create!(:role_id => 1, :tracker_id => 2, :old_status_id => 1, :field_name => 'assigned_to_id', :rule => 'required')
295 WorkflowPermission.create!(:role_id => 1, :tracker_id => 2, :old_status_id => 1, :field_name => 'assigned_to_id', :rule => 'required')
287 cf = IssueCustomField.create!(:name => 'Foo', :field_format => 'string', :tracker_ids => [2])
296 cf = IssueCustomField.create!(:name => 'Foo', :field_format => 'string', :tracker_ids => [2])
288 WorkflowPermission.create!(:role_id => 1, :tracker_id => 2, :old_status_id => 1, :field_name => cf.id, :rule => 'required')
297 WorkflowPermission.create!(:role_id => 1, :tracker_id => 2, :old_status_id => 1, :field_name => cf.id, :rule => 'required')
289
298
290 get :permissions, :role_id => 1, :tracker_id => 2
299 get :permissions, :params => {:role_id => 1, :tracker_id => 2}
291 assert_response :success
300 assert_response :success
292 assert_select 'td.required > select[name=?]', 'permissions[1][assigned_to_id]'
301 assert_select 'td.required > select[name=?]', 'permissions[1][assigned_to_id]'
293 assert_select 'td.required > select[name=?]', "permissions[1][#{cf.id}]"
302 assert_select 'td.required > select[name=?]', "permissions[1][#{cf.id}]"
294 end
303 end
295
304
296 def test_post_permissions
305 def test_post_permissions
297 WorkflowPermission.delete_all
306 WorkflowPermission.delete_all
298
307
299 post :permissions, :role_id => 1, :tracker_id => 2, :permissions => {
308 post :permissions, :params => {
300 '1' => {'assigned_to_id' => '', 'fixed_version_id' => 'required', 'due_date' => ''},
309 :role_id => 1,
301 '2' => {'assigned_to_id' => 'readonly', 'fixed_version_id' => 'readonly', 'due_date' => ''},
310 :tracker_id => 2,
302 '3' => {'assigned_to_id' => '', 'fixed_version_id' => '', 'due_date' => ''}
311 :permissions => {
312 '1' => {'assigned_to_id' => '', 'fixed_version_id' => 'required', 'due_date' => ''},
313 '2' => {'assigned_to_id' => 'readonly', 'fixed_version_id' => 'readonly', 'due_date' => ''},
314 '3' => {'assigned_to_id' => '', 'fixed_version_id' => '', 'due_date' => ''}
315 }
303 }
316 }
304 assert_response 302
317 assert_response 302
305
318
306 workflows = WorkflowPermission.all
319 workflows = WorkflowPermission.all
307 assert_equal 3, workflows.size
320 assert_equal 3, workflows.size
308 workflows.each do |workflow|
321 workflows.each do |workflow|
309 assert_equal 1, workflow.role_id
322 assert_equal 1, workflow.role_id
310 assert_equal 2, workflow.tracker_id
323 assert_equal 2, workflow.tracker_id
311 end
324 end
312 assert workflows.detect {|wf| wf.old_status_id == 2 && wf.field_name == 'assigned_to_id' && wf.rule == 'readonly'}
325 assert workflows.detect {|wf| wf.old_status_id == 2 && wf.field_name == 'assigned_to_id' && wf.rule == 'readonly'}
313 assert workflows.detect {|wf| wf.old_status_id == 1 && wf.field_name == 'fixed_version_id' && wf.rule == 'required'}
326 assert workflows.detect {|wf| wf.old_status_id == 1 && wf.field_name == 'fixed_version_id' && wf.rule == 'required'}
314 assert workflows.detect {|wf| wf.old_status_id == 2 && wf.field_name == 'fixed_version_id' && wf.rule == 'readonly'}
327 assert workflows.detect {|wf| wf.old_status_id == 2 && wf.field_name == 'fixed_version_id' && wf.rule == 'readonly'}
315 end
328 end
316
329
317 def test_get_copy
330 def test_get_copy
318 get :copy
331 get :copy
319 assert_response :success
332 assert_response :success
320 assert_template 'copy'
333 assert_template 'copy'
321 assert_select 'select[name=source_tracker_id]' do
334 assert_select 'select[name=source_tracker_id]' do
322 assert_select 'option[value="1"]', :text => 'Bug'
335 assert_select 'option[value="1"]', :text => 'Bug'
323 end
336 end
324 assert_select 'select[name=source_role_id]' do
337 assert_select 'select[name=source_role_id]' do
325 assert_select 'option[value="2"]', :text => 'Developer'
338 assert_select 'option[value="2"]', :text => 'Developer'
326 end
339 end
327 assert_select 'select[name=?]', 'target_tracker_ids[]' do
340 assert_select 'select[name=?]', 'target_tracker_ids[]' do
328 assert_select 'option[value="3"]', :text => 'Support request'
341 assert_select 'option[value="3"]', :text => 'Support request'
329 end
342 end
330 assert_select 'select[name=?]', 'target_role_ids[]' do
343 assert_select 'select[name=?]', 'target_role_ids[]' do
331 assert_select 'option[value="1"]', :text => 'Manager'
344 assert_select 'option[value="1"]', :text => 'Manager'
332 end
345 end
333 end
346 end
334
347
335 def test_post_copy_one_to_one
348 def test_post_copy_one_to_one
336 source_transitions = status_transitions(:tracker_id => 1, :role_id => 2)
349 source_transitions = status_transitions(:tracker_id => 1, :role_id => 2)
337
350
338 post :copy, :source_tracker_id => '1', :source_role_id => '2',
351 post :copy, :params => {
339 :target_tracker_ids => ['3'], :target_role_ids => ['1']
352 :source_tracker_id => '1', :source_role_id => '2',
353 :target_tracker_ids => ['3'], :target_role_ids => ['1']
354 }
340 assert_response 302
355 assert_response 302
341 assert_equal source_transitions, status_transitions(:tracker_id => 3, :role_id => 1)
356 assert_equal source_transitions, status_transitions(:tracker_id => 3, :role_id => 1)
342 end
357 end
343
358
344 def test_post_copy_one_to_many
359 def test_post_copy_one_to_many
345 source_transitions = status_transitions(:tracker_id => 1, :role_id => 2)
360 source_transitions = status_transitions(:tracker_id => 1, :role_id => 2)
346
361
347 post :copy, :source_tracker_id => '1', :source_role_id => '2',
362 post :copy, :params => {
348 :target_tracker_ids => ['2', '3'], :target_role_ids => ['1', '3']
363 :source_tracker_id => '1', :source_role_id => '2',
364 :target_tracker_ids => ['2', '3'], :target_role_ids => ['1', '3']
365 }
349 assert_response 302
366 assert_response 302
350 assert_equal source_transitions, status_transitions(:tracker_id => 2, :role_id => 1)
367 assert_equal source_transitions, status_transitions(:tracker_id => 2, :role_id => 1)
351 assert_equal source_transitions, status_transitions(:tracker_id => 3, :role_id => 1)
368 assert_equal source_transitions, status_transitions(:tracker_id => 3, :role_id => 1)
352 assert_equal source_transitions, status_transitions(:tracker_id => 2, :role_id => 3)
369 assert_equal source_transitions, status_transitions(:tracker_id => 2, :role_id => 3)
353 assert_equal source_transitions, status_transitions(:tracker_id => 3, :role_id => 3)
370 assert_equal source_transitions, status_transitions(:tracker_id => 3, :role_id => 3)
354 end
371 end
355
372
356 def test_post_copy_many_to_many
373 def test_post_copy_many_to_many
357 source_t2 = status_transitions(:tracker_id => 2, :role_id => 2)
374 source_t2 = status_transitions(:tracker_id => 2, :role_id => 2)
358 source_t3 = status_transitions(:tracker_id => 3, :role_id => 2)
375 source_t3 = status_transitions(:tracker_id => 3, :role_id => 2)
359
376
360 post :copy, :source_tracker_id => 'any', :source_role_id => '2',
377 post :copy, :params => {
361 :target_tracker_ids => ['2', '3'], :target_role_ids => ['1', '3']
378 :source_tracker_id => 'any', :source_role_id => '2',
379 :target_tracker_ids => ['2', '3'], :target_role_ids => ['1', '3']
380 }
362 assert_response 302
381 assert_response 302
363 assert_equal source_t2, status_transitions(:tracker_id => 2, :role_id => 1)
382 assert_equal source_t2, status_transitions(:tracker_id => 2, :role_id => 1)
364 assert_equal source_t3, status_transitions(:tracker_id => 3, :role_id => 1)
383 assert_equal source_t3, status_transitions(:tracker_id => 3, :role_id => 1)
365 assert_equal source_t2, status_transitions(:tracker_id => 2, :role_id => 3)
384 assert_equal source_t2, status_transitions(:tracker_id => 2, :role_id => 3)
366 assert_equal source_t3, status_transitions(:tracker_id => 3, :role_id => 3)
385 assert_equal source_t3, status_transitions(:tracker_id => 3, :role_id => 3)
367 end
386 end
368
387
369 def test_post_copy_with_incomplete_source_specification_should_fail
388 def test_post_copy_with_incomplete_source_specification_should_fail
370 assert_no_difference 'WorkflowRule.count' do
389 assert_no_difference 'WorkflowRule.count' do
371 post :copy,
390 post :copy, :params => {
372 :source_tracker_id => '', :source_role_id => '2',
391 :source_tracker_id => '', :source_role_id => '2',
373 :target_tracker_ids => ['2', '3'], :target_role_ids => ['1', '3']
392 :target_tracker_ids => ['2', '3'], :target_role_ids => ['1', '3']
393 }
374 assert_response 200
394 assert_response 200
375 assert_select 'div.flash.error', :text => 'Please select a source tracker or role'
395 assert_select 'div.flash.error', :text => 'Please select a source tracker or role'
376 end
396 end
377 end
397 end
378
398
379 def test_post_copy_with_incomplete_target_specification_should_fail
399 def test_post_copy_with_incomplete_target_specification_should_fail
380 assert_no_difference 'WorkflowRule.count' do
400 assert_no_difference 'WorkflowRule.count' do
381 post :copy,
401 post :copy, :params => {
382 :source_tracker_id => '1', :source_role_id => '2',
402 :source_tracker_id => '1', :source_role_id => '2',
383 :target_tracker_ids => ['2', '3']
403 :target_tracker_ids => ['2', '3']
404 }
384 assert_response 200
405 assert_response 200
385 assert_select 'div.flash.error', :text => 'Please select target tracker(s) and role(s)'
406 assert_select 'div.flash.error', :text => 'Please select target tracker(s) and role(s)'
386 end
407 end
387 end
408 end
388
409
389 # Returns an array of status transitions that can be compared
410 # Returns an array of status transitions that can be compared
390 def status_transitions(conditions)
411 def status_transitions(conditions)
391 WorkflowTransition.
412 WorkflowTransition.
392 where(conditions).
413 where(conditions).
393 order('tracker_id, role_id, old_status_id, new_status_id').
414 order('tracker_id, role_id, old_status_id, new_status_id').
394 collect {|w| [w.old_status, w.new_status_id]}
415 collect {|w| [w.old_status, w.new_status_id]}
395 end
416 end
396 end
417 end
@@ -1,374 +1,374
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2016 Jean-Philippe Lang
2 # Copyright (C) 2006-2016 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 if ENV["COVERAGE"]
18 if ENV["COVERAGE"]
19 require 'simplecov'
19 require 'simplecov'
20 require File.expand_path(File.dirname(__FILE__) + "/coverage/html_formatter")
20 require File.expand_path(File.dirname(__FILE__) + "/coverage/html_formatter")
21 SimpleCov.formatter = Redmine::Coverage::HtmlFormatter
21 SimpleCov.formatter = Redmine::Coverage::HtmlFormatter
22 SimpleCov.start 'rails'
22 SimpleCov.start 'rails'
23 end
23 end
24
24
25 $redmine_test_ldap_server = ENV['REDMINE_TEST_LDAP_SERVER'] || '127.0.0.1'
25 $redmine_test_ldap_server = ENV['REDMINE_TEST_LDAP_SERVER'] || '127.0.0.1'
26
26
27 ENV["RAILS_ENV"] = "test"
27 ENV["RAILS_ENV"] = "test"
28 require File.expand_path(File.dirname(__FILE__) + "/../config/environment")
28 require File.expand_path(File.dirname(__FILE__) + "/../config/environment")
29 require 'rails/test_help'
29 require 'rails/test_help'
30 require Rails.root.join('test', 'mocks', 'open_id_authentication_mock.rb').to_s
30 require Rails.root.join('test', 'mocks', 'open_id_authentication_mock.rb').to_s
31
31
32 require File.expand_path(File.dirname(__FILE__) + '/object_helpers')
32 require File.expand_path(File.dirname(__FILE__) + '/object_helpers')
33 include ObjectHelpers
33 include ObjectHelpers
34
34
35 require 'net/ldap'
35 require 'net/ldap'
36 require 'mocha/setup'
36 require 'mocha/setup'
37
37
38 Redmine::SudoMode.disable!
38 Redmine::SudoMode.disable!
39
39
40 class ActionView::TestCase
40 class ActionView::TestCase
41 helper :application
41 helper :application
42 include ApplicationHelper
42 include ApplicationHelper
43 end
43 end
44
44
45 class ActiveSupport::TestCase
45 class ActiveSupport::TestCase
46 include ActionDispatch::TestProcess
46 include ActionDispatch::TestProcess
47
47
48 self.use_transactional_fixtures = true
48 self.use_transactional_fixtures = true
49 self.use_instantiated_fixtures = false
49 self.use_instantiated_fixtures = false
50
50
51 def uploaded_test_file(name, mime)
51 def uploaded_test_file(name, mime)
52 fixture_file_upload("files/#{name}", mime, true)
52 fixture_file_upload("files/#{name}", mime, true)
53 end
53 end
54
54
55 # Mock out a file
55 # Mock out a file
56 def self.mock_file
56 def self.mock_file
57 file = 'a_file.png'
57 file = 'a_file.png'
58 file.stubs(:size).returns(32)
58 file.stubs(:size).returns(32)
59 file.stubs(:original_filename).returns('a_file.png')
59 file.stubs(:original_filename).returns('a_file.png')
60 file.stubs(:content_type).returns('image/png')
60 file.stubs(:content_type).returns('image/png')
61 file.stubs(:read).returns(false)
61 file.stubs(:read).returns(false)
62 file
62 file
63 end
63 end
64
64
65 def mock_file
65 def mock_file
66 self.class.mock_file
66 self.class.mock_file
67 end
67 end
68
68
69 def mock_file_with_options(options={})
69 def mock_file_with_options(options={})
70 file = ''
70 file = ''
71 file.stubs(:size).returns(32)
71 file.stubs(:size).returns(32)
72 original_filename = options[:original_filename] || nil
72 original_filename = options[:original_filename] || nil
73 file.stubs(:original_filename).returns(original_filename)
73 file.stubs(:original_filename).returns(original_filename)
74 content_type = options[:content_type] || nil
74 content_type = options[:content_type] || nil
75 file.stubs(:content_type).returns(content_type)
75 file.stubs(:content_type).returns(content_type)
76 file.stubs(:read).returns(false)
76 file.stubs(:read).returns(false)
77 file
77 file
78 end
78 end
79
79
80 # Use a temporary directory for attachment related tests
80 # Use a temporary directory for attachment related tests
81 def set_tmp_attachments_directory
81 def set_tmp_attachments_directory
82 Dir.mkdir "#{Rails.root}/tmp/test" unless File.directory?("#{Rails.root}/tmp/test")
82 Dir.mkdir "#{Rails.root}/tmp/test" unless File.directory?("#{Rails.root}/tmp/test")
83 unless File.directory?("#{Rails.root}/tmp/test/attachments")
83 unless File.directory?("#{Rails.root}/tmp/test/attachments")
84 Dir.mkdir "#{Rails.root}/tmp/test/attachments"
84 Dir.mkdir "#{Rails.root}/tmp/test/attachments"
85 end
85 end
86 Attachment.storage_path = "#{Rails.root}/tmp/test/attachments"
86 Attachment.storage_path = "#{Rails.root}/tmp/test/attachments"
87 end
87 end
88
88
89 def set_fixtures_attachments_directory
89 def set_fixtures_attachments_directory
90 Attachment.storage_path = "#{Rails.root}/test/fixtures/files"
90 Attachment.storage_path = "#{Rails.root}/test/fixtures/files"
91 end
91 end
92
92
93 def with_settings(options, &block)
93 def with_settings(options, &block)
94 saved_settings = options.keys.inject({}) do |h, k|
94 saved_settings = options.keys.inject({}) do |h, k|
95 h[k] = case Setting[k]
95 h[k] = case Setting[k]
96 when Symbol, false, true, nil
96 when Symbol, false, true, nil
97 Setting[k]
97 Setting[k]
98 else
98 else
99 Setting[k].dup
99 Setting[k].dup
100 end
100 end
101 h
101 h
102 end
102 end
103 options.each {|k, v| Setting[k] = v}
103 options.each {|k, v| Setting[k] = v}
104 yield
104 yield
105 ensure
105 ensure
106 saved_settings.each {|k, v| Setting[k] = v} if saved_settings
106 saved_settings.each {|k, v| Setting[k] = v} if saved_settings
107 end
107 end
108
108
109 # Yields the block with user as the current user
109 # Yields the block with user as the current user
110 def with_current_user(user, &block)
110 def with_current_user(user, &block)
111 saved_user = User.current
111 saved_user = User.current
112 User.current = user
112 User.current = user
113 yield
113 yield
114 ensure
114 ensure
115 User.current = saved_user
115 User.current = saved_user
116 end
116 end
117
117
118 def with_locale(locale, &block)
118 def with_locale(locale, &block)
119 saved_localed = ::I18n.locale
119 saved_localed = ::I18n.locale
120 ::I18n.locale = locale
120 ::I18n.locale = locale
121 yield
121 yield
122 ensure
122 ensure
123 ::I18n.locale = saved_localed
123 ::I18n.locale = saved_localed
124 end
124 end
125
125
126 def self.ldap_configured?
126 def self.ldap_configured?
127 @test_ldap = Net::LDAP.new(:host => $redmine_test_ldap_server, :port => 389)
127 @test_ldap = Net::LDAP.new(:host => $redmine_test_ldap_server, :port => 389)
128 return @test_ldap.bind
128 return @test_ldap.bind
129 rescue Exception => e
129 rescue Exception => e
130 # LDAP is not listening
130 # LDAP is not listening
131 return nil
131 return nil
132 end
132 end
133
133
134 def self.convert_installed?
134 def self.convert_installed?
135 Redmine::Thumbnail.convert_available?
135 Redmine::Thumbnail.convert_available?
136 end
136 end
137
137
138 def convert_installed?
138 def convert_installed?
139 self.class.convert_installed?
139 self.class.convert_installed?
140 end
140 end
141
141
142 # Returns the path to the test +vendor+ repository
142 # Returns the path to the test +vendor+ repository
143 def self.repository_path(vendor)
143 def self.repository_path(vendor)
144 path = Rails.root.join("tmp/test/#{vendor.downcase}_repository").to_s
144 path = Rails.root.join("tmp/test/#{vendor.downcase}_repository").to_s
145 # Unlike ruby, JRuby returns Rails.root with backslashes under Windows
145 # Unlike ruby, JRuby returns Rails.root with backslashes under Windows
146 path.tr("\\", "/")
146 path.tr("\\", "/")
147 end
147 end
148
148
149 # Returns the url of the subversion test repository
149 # Returns the url of the subversion test repository
150 def self.subversion_repository_url
150 def self.subversion_repository_url
151 path = repository_path('subversion')
151 path = repository_path('subversion')
152 path = '/' + path unless path.starts_with?('/')
152 path = '/' + path unless path.starts_with?('/')
153 "file://#{path}"
153 "file://#{path}"
154 end
154 end
155
155
156 # Returns true if the +vendor+ test repository is configured
156 # Returns true if the +vendor+ test repository is configured
157 def self.repository_configured?(vendor)
157 def self.repository_configured?(vendor)
158 File.directory?(repository_path(vendor))
158 File.directory?(repository_path(vendor))
159 end
159 end
160
160
161 def repository_path_hash(arr)
161 def repository_path_hash(arr)
162 hs = {}
162 hs = {}
163 hs[:path] = arr.join("/")
163 hs[:path] = arr.join("/")
164 hs[:param] = arr.join("/")
164 hs[:param] = arr.join("/")
165 hs
165 hs
166 end
166 end
167
167
168 def sqlite?
168 def sqlite?
169 ActiveRecord::Base.connection.adapter_name =~ /sqlite/i
169 ActiveRecord::Base.connection.adapter_name =~ /sqlite/i
170 end
170 end
171
171
172 def mysql?
172 def mysql?
173 ActiveRecord::Base.connection.adapter_name =~ /mysql/i
173 ActiveRecord::Base.connection.adapter_name =~ /mysql/i
174 end
174 end
175
175
176 def postgresql?
176 def postgresql?
177 ActiveRecord::Base.connection.adapter_name =~ /postgresql/i
177 ActiveRecord::Base.connection.adapter_name =~ /postgresql/i
178 end
178 end
179
179
180 def quoted_date(date)
180 def quoted_date(date)
181 date = Date.parse(date) if date.is_a?(String)
181 date = Date.parse(date) if date.is_a?(String)
182 ActiveRecord::Base.connection.quoted_date(date)
182 ActiveRecord::Base.connection.quoted_date(date)
183 end
183 end
184
184
185 # Asserts that a new record for the given class is created
185 # Asserts that a new record for the given class is created
186 # and returns it
186 # and returns it
187 def new_record(klass, &block)
187 def new_record(klass, &block)
188 new_records(klass, 1, &block).first
188 new_records(klass, 1, &block).first
189 end
189 end
190
190
191 # Asserts that count new records for the given class are created
191 # Asserts that count new records for the given class are created
192 # and returns them as an array order by object id
192 # and returns them as an array order by object id
193 def new_records(klass, count, &block)
193 def new_records(klass, count, &block)
194 assert_difference "#{klass}.count", count do
194 assert_difference "#{klass}.count", count do
195 yield
195 yield
196 end
196 end
197 klass.order(:id => :desc).limit(count).to_a.reverse
197 klass.order(:id => :desc).limit(count).to_a.reverse
198 end
198 end
199
199
200 def assert_save(object)
200 def assert_save(object)
201 saved = object.save
201 saved = object.save
202 message = "#{object.class} could not be saved"
202 message = "#{object.class} could not be saved"
203 errors = object.errors.full_messages.map {|m| "- #{m}"}
203 errors = object.errors.full_messages.map {|m| "- #{m}"}
204 message << ":\n#{errors.join("\n")}" if errors.any?
204 message << ":\n#{errors.join("\n")}" if errors.any?
205 assert_equal true, saved, message
205 assert_equal true, saved, message
206 end
206 end
207
207
208 def assert_select_error(arg)
208 def assert_select_error(arg)
209 assert_select '#errorExplanation', :text => arg
209 assert_select '#errorExplanation', :text => arg
210 end
210 end
211
211
212 def assert_include(expected, s, message=nil)
212 def assert_include(expected, s, message=nil)
213 assert s.include?(expected), (message || "\"#{expected}\" not found in \"#{s}\"")
213 assert s.include?(expected), (message || "\"#{expected}\" not found in \"#{s}\"")
214 end
214 end
215
215
216 def assert_not_include(expected, s, message=nil)
216 def assert_not_include(expected, s, message=nil)
217 assert !s.include?(expected), (message || "\"#{expected}\" found in \"#{s}\"")
217 assert !s.include?(expected), (message || "\"#{expected}\" found in \"#{s}\"")
218 end
218 end
219
219
220 def assert_select_in(text, *args, &block)
220 def assert_select_in(text, *args, &block)
221 d = Nokogiri::HTML(CGI::unescapeHTML(String.new(text))).root
221 d = Nokogiri::HTML(CGI::unescapeHTML(String.new(text))).root
222 assert_select(d, *args, &block)
222 assert_select(d, *args, &block)
223 end
223 end
224
224
225 def assert_select_email(*args, &block)
225 def assert_select_email(*args, &block)
226 email = ActionMailer::Base.deliveries.last
226 email = ActionMailer::Base.deliveries.last
227 assert_not_nil email
227 assert_not_nil email
228 html_body = email.parts.detect {|part| part.content_type.include?('text/html')}.try(&:body)
228 html_body = email.parts.detect {|part| part.content_type.include?('text/html')}.try(&:body)
229 assert_not_nil html_body
229 assert_not_nil html_body
230 assert_select_in html_body.encoded, *args, &block
230 assert_select_in html_body.encoded, *args, &block
231 end
231 end
232
232
233 def assert_mail_body_match(expected, mail, message=nil)
233 def assert_mail_body_match(expected, mail, message=nil)
234 if expected.is_a?(String)
234 if expected.is_a?(String)
235 assert_include expected, mail_body(mail), message
235 assert_include expected, mail_body(mail), message
236 else
236 else
237 assert_match expected, mail_body(mail), message
237 assert_match expected, mail_body(mail), message
238 end
238 end
239 end
239 end
240
240
241 def assert_mail_body_no_match(expected, mail, message=nil)
241 def assert_mail_body_no_match(expected, mail, message=nil)
242 if expected.is_a?(String)
242 if expected.is_a?(String)
243 assert_not_include expected, mail_body(mail), message
243 assert_not_include expected, mail_body(mail), message
244 else
244 else
245 assert_no_match expected, mail_body(mail), message
245 assert_no_match expected, mail_body(mail), message
246 end
246 end
247 end
247 end
248
248
249 def mail_body(mail)
249 def mail_body(mail)
250 mail.parts.first.body.encoded
250 mail.parts.first.body.encoded
251 end
251 end
252
252
253 # Returns the lft value for a new root issue
253 # Returns the lft value for a new root issue
254 def new_issue_lft
254 def new_issue_lft
255 1
255 1
256 end
256 end
257 end
257 end
258
258
259 module Redmine
259 module Redmine
260 class RoutingTest < ActionDispatch::IntegrationTest
260 class RoutingTest < ActionDispatch::IntegrationTest
261 def should_route(arg)
261 def should_route(arg)
262 arg = arg.dup
262 arg = arg.dup
263 request = arg.keys.detect {|key| key.is_a?(String)}
263 request = arg.keys.detect {|key| key.is_a?(String)}
264 raise ArgumentError unless request
264 raise ArgumentError unless request
265 options = arg.slice!(request)
265 options = arg.slice!(request)
266
266
267 raise ArgumentError unless request =~ /\A(GET|POST|PUT|PATCH|DELETE)\s+(.+)\z/
267 raise ArgumentError unless request =~ /\A(GET|POST|PUT|PATCH|DELETE)\s+(.+)\z/
268 method, path = $1.downcase.to_sym, $2
268 method, path = $1.downcase.to_sym, $2
269
269
270 raise ArgumentError unless arg.values.first =~ /\A(.+)#(.+)\z/
270 raise ArgumentError unless arg.values.first =~ /\A(.+)#(.+)\z/
271 controller, action = $1, $2
271 controller, action = $1, $2
272
272
273 assert_routing(
273 assert_routing(
274 {:method => method, :path => path},
274 {:method => method, :path => path},
275 options.merge(:controller => controller, :action => action)
275 options.merge(:controller => controller, :action => action)
276 )
276 )
277 end
277 end
278 end
278 end
279
279
280 class ControllerTest < ActionController::TestCase
280 class ControllerTest < ActionController::TestCase
281 def process(method, path, parameters={}, options={}, flash={})
281 def process(method, path, parameters={}, session={}, flash={})
282 if parameters.key?(:params)
282 if parameters.key?(:params) || parameters.key?(:session)
283 raise ArgumentError if options.present?
283 raise ArgumentError if session.present?
284 super method, path, parameters[:params], parameters.except(:params)
284 super method, path, parameters[:params], parameters[:session], parameters.except(:params, :session)
285 else
285 else
286 super
286 super
287 end
287 end
288 end
288 end
289 end
289 end
290
290
291 class IntegrationTest < ActionDispatch::IntegrationTest
291 class IntegrationTest < ActionDispatch::IntegrationTest
292 def log_user(login, password)
292 def log_user(login, password)
293 User.anonymous
293 User.anonymous
294 get "/login"
294 get "/login"
295 assert_equal nil, session[:user_id]
295 assert_equal nil, session[:user_id]
296 assert_response :success
296 assert_response :success
297 assert_template "account/login"
297 assert_template "account/login"
298 post "/login", :username => login, :password => password
298 post "/login", :username => login, :password => password
299 assert_equal login, User.find(session[:user_id]).login
299 assert_equal login, User.find(session[:user_id]).login
300 end
300 end
301
301
302 def credentials(user, password=nil)
302 def credentials(user, password=nil)
303 {'HTTP_AUTHORIZATION' => ActionController::HttpAuthentication::Basic.encode_credentials(user, password || user)}
303 {'HTTP_AUTHORIZATION' => ActionController::HttpAuthentication::Basic.encode_credentials(user, password || user)}
304 end
304 end
305 end
305 end
306
306
307 module ApiTest
307 module ApiTest
308 API_FORMATS = %w(json xml).freeze
308 API_FORMATS = %w(json xml).freeze
309
309
310 # Base class for API tests
310 # Base class for API tests
311 class Base < Redmine::IntegrationTest
311 class Base < Redmine::IntegrationTest
312 def setup
312 def setup
313 Setting.rest_api_enabled = '1'
313 Setting.rest_api_enabled = '1'
314 end
314 end
315
315
316 def teardown
316 def teardown
317 Setting.rest_api_enabled = '0'
317 Setting.rest_api_enabled = '0'
318 end
318 end
319
319
320 # Uploads content using the XML API and returns the attachment token
320 # Uploads content using the XML API and returns the attachment token
321 def xml_upload(content, credentials)
321 def xml_upload(content, credentials)
322 upload('xml', content, credentials)
322 upload('xml', content, credentials)
323 end
323 end
324
324
325 # Uploads content using the JSON API and returns the attachment token
325 # Uploads content using the JSON API and returns the attachment token
326 def json_upload(content, credentials)
326 def json_upload(content, credentials)
327 upload('json', content, credentials)
327 upload('json', content, credentials)
328 end
328 end
329
329
330 def upload(format, content, credentials)
330 def upload(format, content, credentials)
331 set_tmp_attachments_directory
331 set_tmp_attachments_directory
332 assert_difference 'Attachment.count' do
332 assert_difference 'Attachment.count' do
333 post "/uploads.#{format}", content, {"CONTENT_TYPE" => 'application/octet-stream'}.merge(credentials)
333 post "/uploads.#{format}", content, {"CONTENT_TYPE" => 'application/octet-stream'}.merge(credentials)
334 assert_response :created
334 assert_response :created
335 end
335 end
336 data = response_data
336 data = response_data
337 assert_kind_of Hash, data['upload']
337 assert_kind_of Hash, data['upload']
338 token = data['upload']['token']
338 token = data['upload']['token']
339 assert_not_nil token
339 assert_not_nil token
340 token
340 token
341 end
341 end
342
342
343 # Parses the response body based on its content type
343 # Parses the response body based on its content type
344 def response_data
344 def response_data
345 unless response.content_type.to_s =~ /^application\/(.+)/
345 unless response.content_type.to_s =~ /^application\/(.+)/
346 raise "Unexpected response type: #{response.content_type}"
346 raise "Unexpected response type: #{response.content_type}"
347 end
347 end
348 format = $1
348 format = $1
349 case format
349 case format
350 when 'xml'
350 when 'xml'
351 Hash.from_xml(response.body)
351 Hash.from_xml(response.body)
352 when 'json'
352 when 'json'
353 ActiveSupport::JSON.decode(response.body)
353 ActiveSupport::JSON.decode(response.body)
354 else
354 else
355 raise "Unknown response format: #{format}"
355 raise "Unknown response format: #{format}"
356 end
356 end
357 end
357 end
358 end
358 end
359
359
360 class Routing < Redmine::RoutingTest
360 class Routing < Redmine::RoutingTest
361 def should_route(arg)
361 def should_route(arg)
362 arg = arg.dup
362 arg = arg.dup
363 request = arg.keys.detect {|key| key.is_a?(String)}
363 request = arg.keys.detect {|key| key.is_a?(String)}
364 raise ArgumentError unless request
364 raise ArgumentError unless request
365 options = arg.slice!(request)
365 options = arg.slice!(request)
366
366
367 API_FORMATS.each do |format|
367 API_FORMATS.each do |format|
368 format_request = request.sub /$/, ".#{format}"
368 format_request = request.sub /$/, ".#{format}"
369 super options.merge(format_request => arg[request], :format => format)
369 super options.merge(format_request => arg[request], :format => format)
370 end
370 end
371 end
371 end
372 end
372 end
373 end
373 end
374 end
374 end
General Comments 0
You need to be logged in to leave comments. Login now