redmine_rate 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/COPYRIGHT.txt +18 -0
- data/CREDITS.txt +5 -0
- data/GPL.txt +339 -0
- data/README.rdoc +93 -0
- data/Rakefile +37 -0
- data/VERSION +1 -0
- data/app/controllers/rate_caches_controller.rb +35 -0
- data/app/controllers/rates_controller.rb +154 -0
- data/app/models/rate.rb +161 -0
- data/app/views/rate_caches/index.html.erb +21 -0
- data/app/views/rates/_form.html.erb +36 -0
- data/app/views/rates/_list.html.erb +42 -0
- data/app/views/rates/create.js.rjs +2 -0
- data/app/views/rates/create_error.js.rjs +5 -0
- data/app/views/rates/edit.html.erb +3 -0
- data/app/views/rates/index.html.erb +5 -0
- data/app/views/rates/new.html.erb +3 -0
- data/app/views/rates/show.html.erb +23 -0
- data/app/views/users/_membership_rate.html.erb +23 -0
- data/app/views/users/_rates.html.erb +17 -0
- data/assets/images/database_refresh.png +0 -0
- data/config/locales/de.yml +18 -0
- data/config/locales/en.yml +18 -0
- data/config/locales/fr.yml +20 -0
- data/config/locales/ru.yml +9 -0
- data/config/routes.rb +4 -0
- data/init.rb +49 -0
- data/lang/de.yml +9 -0
- data/lang/en.yml +9 -0
- data/lang/fr.yml +8 -0
- data/lib/rate_conversion.rb +16 -0
- data/lib/rate_memberships_hook.rb +15 -0
- data/lib/rate_project_hook.rb +106 -0
- data/lib/rate_sort_helper_patch.rb +102 -0
- data/lib/rate_time_entry_patch.rb +66 -0
- data/lib/rate_users_helper_patch.rb +37 -0
- data/lib/redmine_rate/hooks/plugin_timesheet_view_timesheets_report_header_tags_hook.rb +11 -0
- data/lib/redmine_rate/hooks/plugin_timesheet_views_timesheet_group_header_hook.rb +9 -0
- data/lib/redmine_rate/hooks/plugin_timesheet_views_timesheet_time_entry_hook.rb +18 -0
- data/lib/redmine_rate/hooks/plugin_timesheet_views_timesheet_time_entry_sum_hook.rb +17 -0
- data/lib/redmine_rate/hooks/plugin_timesheet_views_timesheets_time_entry_row_class_hook.rb +21 -0
- data/lib/redmine_rate/hooks/timesheet_hook_helper.rb +14 -0
- data/lib/redmine_rate/hooks/view_layouts_base_html_head_hook.rb +9 -0
- data/lib/tasks/cache.rake +13 -0
- data/lib/tasks/data.rake +163 -0
- data/rails/init.rb +1 -0
- data/test/functional/rates_controller_test.rb +401 -0
- data/test/integration/admin_panel_test.rb +81 -0
- data/test/integration/routing_test.rb +16 -0
- data/test/test_helper.rb +43 -0
- data/test/unit/lib/rate_time_entry_patch_test.rb +77 -0
- data/test/unit/lib/rate_users_helper_patch_test.rb +37 -0
- data/test/unit/lib/redmine_rate/hooks/plugin_timesheet_view_timesheets_report_header_tags_hook_test.rb +26 -0
- data/test/unit/lib/redmine_rate/hooks/plugin_timesheet_views_timesheet_group_header_hook_test.rb +26 -0
- data/test/unit/lib/redmine_rate/hooks/plugin_timesheet_views_timesheet_time_entry_hook_test.rb +47 -0
- data/test/unit/lib/redmine_rate/hooks/plugin_timesheet_views_timesheet_time_entry_sum_hook_test.rb +48 -0
- data/test/unit/lib/redmine_rate/hooks/plugin_timesheet_views_timesheets_time_entry_row_class_hook_test.rb +60 -0
- data/test/unit/rate_for_test.rb +74 -0
- data/test/unit/rate_test.rb +333 -0
- metadata +137 -0
@@ -0,0 +1,401 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../test_helper'
|
2
|
+
|
3
|
+
class RatesControllerTest < ActionController::TestCase
|
4
|
+
|
5
|
+
def self.should_be_unauthorized(&block)
|
6
|
+
should 'should return a forbidden status code' do
|
7
|
+
instance_eval(&block)
|
8
|
+
assert_response :forbidden
|
9
|
+
end
|
10
|
+
|
11
|
+
should 'should display the standard unauthorized page' do
|
12
|
+
instance_eval(&block)
|
13
|
+
assert_template 'common/error'
|
14
|
+
end
|
15
|
+
|
16
|
+
context "with mime type of xml" do
|
17
|
+
|
18
|
+
should "should return an forbidden error" do
|
19
|
+
@request.env["HTTP_ACCEPT"] = "application/xml"
|
20
|
+
instance_eval(&block)
|
21
|
+
assert_response :forbidden
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
def mock_rate(stubs={})
|
28
|
+
@project = Project.generate!
|
29
|
+
stubs = {
|
30
|
+
:date_in_effect => Date.today,
|
31
|
+
:project => @project,
|
32
|
+
:amount => 100.0,
|
33
|
+
:user => @user
|
34
|
+
}.merge(stubs)
|
35
|
+
@mock_rate = Rate.generate(stubs)
|
36
|
+
end
|
37
|
+
|
38
|
+
def mock_locked_rate(stubs={})
|
39
|
+
@mock_rate = mock_rate
|
40
|
+
@mock_rate.time_entries << TimeEntry.generate!
|
41
|
+
@mock_rate
|
42
|
+
end
|
43
|
+
|
44
|
+
context "as regular user" do
|
45
|
+
setup do
|
46
|
+
@user = User.generate!
|
47
|
+
@request.session[:user_id] = @user.id
|
48
|
+
end
|
49
|
+
|
50
|
+
context "responding to GET index" do
|
51
|
+
should_be_unauthorized { get :index }
|
52
|
+
end
|
53
|
+
|
54
|
+
context "responding to GET show" do
|
55
|
+
should_be_unauthorized { get :show, :id => "37" }
|
56
|
+
end
|
57
|
+
|
58
|
+
context "responding to GET new" do
|
59
|
+
should_be_unauthorized { get :new }
|
60
|
+
end
|
61
|
+
|
62
|
+
context "responding to GET edit" do
|
63
|
+
should_be_unauthorized { get :edit, :id => "37" }
|
64
|
+
end
|
65
|
+
|
66
|
+
context "responding to POST create" do
|
67
|
+
should_be_unauthorized { post :create, :rate => {:these => 'params'} }
|
68
|
+
end
|
69
|
+
|
70
|
+
context "responding to PUT update" do
|
71
|
+
should_be_unauthorized { put :update, :id => "37", :rate => {:these => 'params'} }
|
72
|
+
end
|
73
|
+
|
74
|
+
context "responding to DELETE destroy" do
|
75
|
+
should_be_unauthorized { delete :destroy, :id => "37" }
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
|
80
|
+
context "as an administrator" do
|
81
|
+
|
82
|
+
setup do
|
83
|
+
@user = User.generate!(:admin => true)
|
84
|
+
@request.session[:user_id] = @user.id
|
85
|
+
end
|
86
|
+
|
87
|
+
context "responding to GET index" do
|
88
|
+
|
89
|
+
should "should redirect to the homepage" do
|
90
|
+
get :index
|
91
|
+
assert_redirected_to home_url
|
92
|
+
end
|
93
|
+
|
94
|
+
should "should display an error flash message" do
|
95
|
+
get :index
|
96
|
+
assert_match /not found/, flash[:error]
|
97
|
+
end
|
98
|
+
|
99
|
+
context "with mime type of xml" do
|
100
|
+
|
101
|
+
should "should return a 404 error" do
|
102
|
+
@request.env["HTTP_ACCEPT"] = "application/xml"
|
103
|
+
get :index
|
104
|
+
assert_response :not_found
|
105
|
+
end
|
106
|
+
|
107
|
+
end
|
108
|
+
|
109
|
+
end
|
110
|
+
|
111
|
+
context "responding to GET index with user" do
|
112
|
+
setup do
|
113
|
+
mock_rate
|
114
|
+
end
|
115
|
+
|
116
|
+
should "should expose all historic rates for the user as @rates" do
|
117
|
+
get :index, :user_id => @user.id
|
118
|
+
assert_equal assigns(:rates), [@mock_rate]
|
119
|
+
end
|
120
|
+
|
121
|
+
context "with mime type of xml" do
|
122
|
+
|
123
|
+
should "should render all rates as xml" do
|
124
|
+
@request.env["HTTP_ACCEPT"] = "application/xml"
|
125
|
+
get :index, :user_id => @user.id
|
126
|
+
|
127
|
+
assert_select 'rates' do
|
128
|
+
assert_select 'rate' do
|
129
|
+
assert_select 'id', :text => @mock_rate.id
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
end
|
134
|
+
|
135
|
+
end
|
136
|
+
|
137
|
+
end
|
138
|
+
|
139
|
+
context "responding to GET show" do
|
140
|
+
setup do
|
141
|
+
mock_rate
|
142
|
+
end
|
143
|
+
|
144
|
+
should "should expose the @requested rate as @rate" do
|
145
|
+
get :show, :id => @mock_rate.id
|
146
|
+
assert_equal assigns(:rate), @mock_rate
|
147
|
+
end
|
148
|
+
|
149
|
+
context "with mime type of xml" do
|
150
|
+
|
151
|
+
should "should render the requested rate as xml" do
|
152
|
+
@request.env["HTTP_ACCEPT"] = "application/xml"
|
153
|
+
get :show, :id => @mock_rate.id
|
154
|
+
|
155
|
+
assert_select 'rate' do
|
156
|
+
assert_select 'id', :text => @mock_rate.id
|
157
|
+
assert_select 'amount', :text => /100/
|
158
|
+
end
|
159
|
+
|
160
|
+
end
|
161
|
+
|
162
|
+
end
|
163
|
+
|
164
|
+
end
|
165
|
+
|
166
|
+
context "responding to GET new" do
|
167
|
+
|
168
|
+
should "should redirect to the homepage" do
|
169
|
+
get :new
|
170
|
+
assert_redirected_to home_url
|
171
|
+
end
|
172
|
+
|
173
|
+
should "should display an error flash message" do
|
174
|
+
get :new
|
175
|
+
assert_match /not found/, flash[:error]
|
176
|
+
end
|
177
|
+
|
178
|
+
context "with mime type of xml" do
|
179
|
+
|
180
|
+
should "should return a 404 error" do
|
181
|
+
@request.env["HTTP_ACCEPT"] = "application/xml"
|
182
|
+
get :new
|
183
|
+
assert_response :not_found
|
184
|
+
end
|
185
|
+
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
context "responding to GET new with user" do
|
190
|
+
should 'should be successful' do
|
191
|
+
get :new, :user_id => @user.id
|
192
|
+
assert_response :success
|
193
|
+
end
|
194
|
+
|
195
|
+
should "should expose a new rate as @rate" do
|
196
|
+
get :new, :user_id => @user.id
|
197
|
+
assert assigns(:rate)
|
198
|
+
assert assigns(:rate).new_record?
|
199
|
+
end
|
200
|
+
|
201
|
+
end
|
202
|
+
|
203
|
+
context "responding to GET edit" do
|
204
|
+
setup do
|
205
|
+
mock_rate
|
206
|
+
end
|
207
|
+
|
208
|
+
should "should expose the requested rate as @rate" do
|
209
|
+
get :edit, :id => @mock_rate.id
|
210
|
+
assert_equal assigns(:rate), @mock_rate
|
211
|
+
end
|
212
|
+
|
213
|
+
context "on a locked rate" do
|
214
|
+
setup do
|
215
|
+
mock_locked_rate
|
216
|
+
end
|
217
|
+
|
218
|
+
should 'should not have a Update button' do
|
219
|
+
get :edit, :id => @mock_rate.id
|
220
|
+
assert_select "input[type=submit]", :count => 0
|
221
|
+
end
|
222
|
+
|
223
|
+
should 'should show the locked icon' do
|
224
|
+
get :edit, :id => @mock_rate.id
|
225
|
+
assert_select "img[src*=locked.png]"
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
end
|
230
|
+
|
231
|
+
context "responding to POST create" do
|
232
|
+
|
233
|
+
context "with valid params" do
|
234
|
+
setup do
|
235
|
+
@project = Project.generate!
|
236
|
+
end
|
237
|
+
|
238
|
+
should "should expose a newly created rate as @rate" do
|
239
|
+
post :create, :rate => {:project_id => @project.id, :amount => '50', :date_in_effect => Date.today.to_s, :user_id => @user.id}
|
240
|
+
assert assigns(:rate)
|
241
|
+
end
|
242
|
+
|
243
|
+
should "should redirect to the rate list" do
|
244
|
+
post :create, :rate => {:project_id => @project.id, :amount => '50', :date_in_effect => Date.today.to_s, :user_id => @user.id}
|
245
|
+
|
246
|
+
assert_redirected_to rates_url(:user_id => @user.id)
|
247
|
+
end
|
248
|
+
|
249
|
+
should 'should redirect to the back_url if set' do
|
250
|
+
back_url = '/rates'
|
251
|
+
post :create, :rate => {:project_id => @project.id, :amount => '50', :date_in_effect => Date.today.to_s, :user_id => @user.id}, :back_url => back_url
|
252
|
+
|
253
|
+
assert_redirected_to back_url
|
254
|
+
end
|
255
|
+
|
256
|
+
end
|
257
|
+
|
258
|
+
context "with invalid params" do
|
259
|
+
should "should expose a newly created but unsaved rate as @rate" do
|
260
|
+
post :create, :rate => {}
|
261
|
+
assert assigns(:rate).new_record?
|
262
|
+
end
|
263
|
+
|
264
|
+
should "should re-render the 'new' template" do
|
265
|
+
post :create, :rate => {}
|
266
|
+
assert_template 'new'
|
267
|
+
end
|
268
|
+
|
269
|
+
end
|
270
|
+
|
271
|
+
end
|
272
|
+
|
273
|
+
context "responding to PUT udpate" do
|
274
|
+
|
275
|
+
context "with valid params" do
|
276
|
+
setup do
|
277
|
+
mock_rate
|
278
|
+
end
|
279
|
+
|
280
|
+
should "should update the requested rate" do
|
281
|
+
put :update, :id => @mock_rate.id, :rate => {:amount => '150'}
|
282
|
+
|
283
|
+
assert_equal 150.0, @mock_rate.reload.amount
|
284
|
+
end
|
285
|
+
|
286
|
+
should "should expose the requested rate as @rate" do
|
287
|
+
put :update, :id => @mock_rate.id
|
288
|
+
|
289
|
+
assert_equal assigns(:rate), @mock_rate
|
290
|
+
end
|
291
|
+
|
292
|
+
should "should redirect to the rate list" do
|
293
|
+
put :update, :id => "1"
|
294
|
+
|
295
|
+
assert_redirected_to rates_url(:user_id => @user.id)
|
296
|
+
end
|
297
|
+
|
298
|
+
should 'should redirect to the back_url if set' do
|
299
|
+
back_url = '/rates'
|
300
|
+
put :update, :id => "1", :back_url => back_url
|
301
|
+
|
302
|
+
assert_redirected_to back_url
|
303
|
+
end
|
304
|
+
|
305
|
+
end
|
306
|
+
|
307
|
+
context "with invalid params" do
|
308
|
+
setup do
|
309
|
+
mock_rate
|
310
|
+
end
|
311
|
+
|
312
|
+
should "should not update the requested rate" do
|
313
|
+
put :update, :id => @mock_rate.id, :rate => {:amount => 'asdf'}
|
314
|
+
|
315
|
+
assert_equal 100.0, @mock_rate.reload.amount
|
316
|
+
end
|
317
|
+
|
318
|
+
should "should expose the rate as @rate" do
|
319
|
+
put :update, :id => @mock_rate.id, :rate => {:amount => 'asdf'}
|
320
|
+
|
321
|
+
assert_equal assigns(:rate), @mock_rate
|
322
|
+
end
|
323
|
+
|
324
|
+
should "should re-render the 'edit' template" do
|
325
|
+
put :update, :id => @mock_rate.id, :rate => {:amount => 'asdf'}
|
326
|
+
|
327
|
+
assert_template 'edit'
|
328
|
+
end
|
329
|
+
|
330
|
+
end
|
331
|
+
|
332
|
+
context "on a locked rate" do
|
333
|
+
setup do
|
334
|
+
mock_locked_rate
|
335
|
+
end
|
336
|
+
|
337
|
+
should "should not save the rate" do
|
338
|
+
put :update, :id => @mock_rate.id, :rate => {:amount => '150'}
|
339
|
+
|
340
|
+
assert_equal 100, @mock_rate.reload.amount
|
341
|
+
end
|
342
|
+
|
343
|
+
should "should set the locked rate as @rate" do
|
344
|
+
put :update, :id => @mock_rate.id, :rate => { :amount => 200.0 }
|
345
|
+
|
346
|
+
assert_equal assigns(:rate), @mock_rate
|
347
|
+
end
|
348
|
+
|
349
|
+
should "should re-render the 'edit' template" do
|
350
|
+
put :update, :id => @mock_rate.id
|
351
|
+
|
352
|
+
assert_template 'edit'
|
353
|
+
end
|
354
|
+
|
355
|
+
should "should render an error message" do
|
356
|
+
put :update, :id => @mock_rate.id
|
357
|
+
|
358
|
+
assert_match /locked/, flash[:error]
|
359
|
+
end
|
360
|
+
end
|
361
|
+
|
362
|
+
end
|
363
|
+
|
364
|
+
context "responding to DELETE destroy" do
|
365
|
+
setup do
|
366
|
+
mock_rate
|
367
|
+
end
|
368
|
+
|
369
|
+
should "should destroy the requested rate" do
|
370
|
+
assert_difference('Rate.count', -1) do
|
371
|
+
delete :destroy, :id => @mock_rate.id
|
372
|
+
end
|
373
|
+
end
|
374
|
+
|
375
|
+
should "should redirect to the user's rates list" do
|
376
|
+
delete :destroy, :id => @mock_rate.id
|
377
|
+
assert_redirected_to rates_url(:user_id => @user.id)
|
378
|
+
end
|
379
|
+
|
380
|
+
should 'should redirect to the back_url if set' do
|
381
|
+
back_url = '/rates'
|
382
|
+
delete :destroy, :id => "1", :back_url => back_url
|
383
|
+
|
384
|
+
assert_redirected_to back_url
|
385
|
+
end
|
386
|
+
|
387
|
+
context "on a locked rate" do
|
388
|
+
setup do
|
389
|
+
mock_locked_rate
|
390
|
+
end
|
391
|
+
|
392
|
+
should "should display an error message" do
|
393
|
+
delete :destroy, :id => @mock_rate.id
|
394
|
+
assert_match /locked/, flash[:error]
|
395
|
+
end
|
396
|
+
end
|
397
|
+
|
398
|
+
end
|
399
|
+
|
400
|
+
end
|
401
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class AdminPanelTest < ActionController::IntegrationTest
|
4
|
+
include Redmine::I18n
|
5
|
+
|
6
|
+
def setup
|
7
|
+
@last_caching_run = 4.days.ago.to_s
|
8
|
+
@last_cache_clearing_run = 7.days.ago.to_s
|
9
|
+
|
10
|
+
Setting.plugin_redmine_rate = {
|
11
|
+
'last_caching_run' => @last_caching_run,
|
12
|
+
'last_cache_clearing_run' => @last_cache_clearing_run
|
13
|
+
}
|
14
|
+
|
15
|
+
@user = User.generate!(:admin => true, :password => 'rates', :password_confirmation => 'rates')
|
16
|
+
|
17
|
+
login_as(@user.login, 'rates')
|
18
|
+
end
|
19
|
+
|
20
|
+
context "Rate Caches admin panel" do
|
21
|
+
should "be listed in the main Admin section" do
|
22
|
+
click_link "Administration"
|
23
|
+
assert_response :success
|
24
|
+
|
25
|
+
assert_select "#admin-menu" do
|
26
|
+
assert_select "a.rate-caches"
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
should "show the last run timestamp for the last caching run" do
|
32
|
+
click_link "Administration"
|
33
|
+
click_link "Rate Caches"
|
34
|
+
|
35
|
+
assert_select '#caching-run' do
|
36
|
+
assert_select 'p', :text => /#{format_time(@last_caching_run)}/
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
should "show the last run timestamp for the last cache clearing run" do
|
42
|
+
click_link "Administration"
|
43
|
+
click_link "Rate Caches"
|
44
|
+
|
45
|
+
assert_select '#cache-clearing-run' do
|
46
|
+
assert_select 'p', :text => /#{format_time(@last_cache_clearing_run)}/
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
should "have a button to force a caching run" do
|
52
|
+
click_link "Administration"
|
53
|
+
click_link "Rate Caches"
|
54
|
+
click_button "Load Missing Caches"
|
55
|
+
|
56
|
+
assert_response :success
|
57
|
+
|
58
|
+
appx_clear_time = Date.today.strftime("%m/%d/%Y")
|
59
|
+
|
60
|
+
assert_select '#caching-run' do
|
61
|
+
assert_select 'p', :text => /#{appx_clear_time}/
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
|
66
|
+
should "have a button to force a cache clearing run" do
|
67
|
+
click_link "Administration"
|
68
|
+
click_link "Rate Caches"
|
69
|
+
click_button "Clear and Load All Caches"
|
70
|
+
|
71
|
+
assert_response :success
|
72
|
+
|
73
|
+
appx_clear_time = Date.today.strftime("%m/%d/%Y")
|
74
|
+
|
75
|
+
assert_select '#cache-clearing-run' do
|
76
|
+
assert_select 'p', :text => /#{appx_clear_time}/
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require "#{File.dirname(__FILE__)}/../test_helper"
|
2
|
+
|
3
|
+
class RoutingTest < ActionController::IntegrationTest
|
4
|
+
context "routing rates" do
|
5
|
+
should_route :get, "/rates", :controller => "rates", :action => "index"
|
6
|
+
should_route :get, "/rates/new", :controller => "rates", :action => "new"
|
7
|
+
should_route :get, "/rates/1", :controller => "rates", :action => "show", :id => "1"
|
8
|
+
should_route :get, "/rates/1/edit", :controller => "rates", :action => "edit", :id => "1"
|
9
|
+
|
10
|
+
should_route :post, "/rates", :controller => "rates", :action => "create"
|
11
|
+
|
12
|
+
should_route :put, "/rates/1", :controller => "rates", :action => "update", :id => "1"
|
13
|
+
|
14
|
+
should_route :delete, "/rates/1", :controller => "rates", :action => "destroy", :id => "1"
|
15
|
+
end
|
16
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
# Load the normal Rails helper
|
2
|
+
require File.expand_path(File.dirname(__FILE__) + '/../../../../test/test_helper')
|
3
|
+
|
4
|
+
# Ensure that we are using the temporary fixture path
|
5
|
+
Engines::Testing.set_fixture_path
|
6
|
+
|
7
|
+
require "webrat"
|
8
|
+
|
9
|
+
Webrat.configure do |config|
|
10
|
+
config.mode = :rails
|
11
|
+
end
|
12
|
+
|
13
|
+
module IntegrationTestHelper
|
14
|
+
def login_as(user="existing", password="existing")
|
15
|
+
visit "/login"
|
16
|
+
fill_in 'Login', :with => user
|
17
|
+
fill_in 'Password', :with => password
|
18
|
+
click_button 'login'
|
19
|
+
assert_response :success
|
20
|
+
assert User.current.logged?
|
21
|
+
end
|
22
|
+
|
23
|
+
def logout
|
24
|
+
visit '/logout'
|
25
|
+
assert_response :success
|
26
|
+
assert !User.current.logged?
|
27
|
+
end
|
28
|
+
|
29
|
+
def assert_forbidden
|
30
|
+
assert_response :forbidden
|
31
|
+
assert_template 'common/error'
|
32
|
+
end
|
33
|
+
|
34
|
+
def assert_requires_login
|
35
|
+
assert_response :success
|
36
|
+
assert_template 'account/login'
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
class ActionController::IntegrationTest
|
42
|
+
include IntegrationTestHelper
|
43
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../../test_helper'
|
2
|
+
|
3
|
+
class RateTimeEntryPatchTest < ActiveSupport::TestCase
|
4
|
+
def setup
|
5
|
+
@user = User.generate!
|
6
|
+
@project = Project.generate!
|
7
|
+
@date = Date.today.to_s
|
8
|
+
@time_entry = TimeEntry.new({:user => @user, :project => @project, :spent_on => @date, :hours => 10.0, :activity => TimeEntryActivity.generate!})
|
9
|
+
@rate = Rate.generate!(:user => @user, :project => @project, :date_in_effect => @date, :amount => 200.0)
|
10
|
+
end
|
11
|
+
|
12
|
+
should 'should return 0.0 if there are no rates for the user' do
|
13
|
+
@rate.destroy
|
14
|
+
assert_equal 0.0, @time_entry.cost
|
15
|
+
end
|
16
|
+
|
17
|
+
context 'should return the product of hours by' do
|
18
|
+
should 'the results of Rate.amount_for' do
|
19
|
+
assert_equal((200.0 * @time_entry.hours), @time_entry.cost)
|
20
|
+
end
|
21
|
+
|
22
|
+
should 'the assigned rate' do
|
23
|
+
rate = Rate.generate!(:user => @user, :project => @project, :date_in_effect => @date, :amount => 100.0)
|
24
|
+
@time_entry.rate = rate
|
25
|
+
assert_equal rate.amount * @time_entry.hours, @time_entry.cost
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
context "#cost" do
|
31
|
+
setup do
|
32
|
+
@time_entry.save!
|
33
|
+
end
|
34
|
+
|
35
|
+
context "without a cache" do
|
36
|
+
should "return the calculated cost" do
|
37
|
+
@time_entry.update_attribute(:cost, nil)
|
38
|
+
assert_equal 2000.0, @time_entry.cost
|
39
|
+
end
|
40
|
+
|
41
|
+
should "cache the cost to the field" do
|
42
|
+
@time_entry.update_attribute(:cost, nil)
|
43
|
+
@time_entry.cost
|
44
|
+
|
45
|
+
assert_equal 2000.0, @time_entry.read_attribute(:cost)
|
46
|
+
assert_equal 2000.0, @time_entry.reload.read_attribute(:cost)
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
context "with a cache" do
|
52
|
+
setup do
|
53
|
+
@time_entry.update_attribute(:cost, 2000.0)
|
54
|
+
@time_entry.reload
|
55
|
+
end
|
56
|
+
|
57
|
+
should "return the cached cost" do
|
58
|
+
assert_equal 2000.0, @time_entry.read_attribute(:cost)
|
59
|
+
assert_equal 2000.0, @time_entry.cost
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
|
66
|
+
context "before save" do
|
67
|
+
should "clear and recalculate the cache" do
|
68
|
+
assert_equal nil, @time_entry.read_attribute(:cost)
|
69
|
+
|
70
|
+
assert @time_entry.save
|
71
|
+
|
72
|
+
assert_equal 2000.0, @time_entry.read_attribute(:cost)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
|
77
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../../test_helper'
|
2
|
+
|
3
|
+
class UsersHelperWrapper
|
4
|
+
include UsersHelper
|
5
|
+
end
|
6
|
+
|
7
|
+
class RateUsersHelperPatchTest < ActiveSupport::TestCase
|
8
|
+
should 'should return 3 tabs' do
|
9
|
+
helper = UsersHelperWrapper.new
|
10
|
+
assert_equal 3, helper.user_settings_tabs.length
|
11
|
+
end
|
12
|
+
|
13
|
+
should 'should include a rate tab at the end' do
|
14
|
+
helper = UsersHelperWrapper.new
|
15
|
+
rate_tab = helper.user_settings_tabs[-1]
|
16
|
+
assert_not_nil rate_tab
|
17
|
+
end
|
18
|
+
|
19
|
+
context 'rate tab' do
|
20
|
+
setup do
|
21
|
+
helper = UsersHelperWrapper.new
|
22
|
+
@rate_tab = helper.user_settings_tabs[-1]
|
23
|
+
end
|
24
|
+
|
25
|
+
should 'should have the name of "rates"' do
|
26
|
+
assert_equal 'rates', @rate_tab[:name]
|
27
|
+
end
|
28
|
+
|
29
|
+
should 'should use the rates partial' do
|
30
|
+
assert_equal 'users/rates', @rate_tab[:partial]
|
31
|
+
end
|
32
|
+
|
33
|
+
should 'should use the i18n rates label' do
|
34
|
+
assert_equal :rate_label_rate_history, @rate_tab[:label]
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../../../../test_helper'
|
2
|
+
|
3
|
+
class RedmineRate::Hooks::PluginTimesheetViewTimesheetsReportHeaderTagsTest < ActionController::TestCase
|
4
|
+
include Redmine::Hook::Helper
|
5
|
+
|
6
|
+
def controller
|
7
|
+
@controller ||= ApplicationController.new
|
8
|
+
@controller.response ||= ActionController::TestResponse.new
|
9
|
+
@controller
|
10
|
+
end
|
11
|
+
|
12
|
+
def request
|
13
|
+
@request ||= ActionController::TestRequest.new
|
14
|
+
end
|
15
|
+
|
16
|
+
def hook(args={})
|
17
|
+
call_hook :plugin_timesheet_view_timesheets_report_header_tags, args
|
18
|
+
end
|
19
|
+
|
20
|
+
context "#plugin_timesheet_view_timesheets_report_header_tags" do
|
21
|
+
should "return a css string" do
|
22
|
+
@response.body = hook
|
23
|
+
assert_select "style", :text => /missing-rate/
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|