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