timelog_controller_test.rb
1018 lines
| 33.6 KiB
| text/x-ruby
|
RubyLexer
|
r2832 | # -*- coding: utf-8 -*- | ||
|
r6504 | # Redmine - project management software | ||
|
r14856 | # Copyright (C) 2006-2016 Jean-Philippe Lang | ||
|
r569 | # | ||
# This program is free software; you can redistribute it and/or | ||||
# modify it under the terms of the GNU General Public License | ||||
# as published by the Free Software Foundation; either version 2 | ||||
# of the License, or (at your option) any later version. | ||||
|
r6504 | # | ||
|
r569 | # This program is distributed in the hope that it will be useful, | ||
# but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||
# GNU General Public License for more details. | ||||
|
r6504 | # | ||
|
r569 | # You should have received a copy of the GNU General Public License | ||
# along with this program; if not, write to the Free Software | ||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||||
|
r4395 | require File.expand_path('../../test_helper', __FILE__) | ||
|
r569 | |||
|
r15279 | class TimelogControllerTest < Redmine::ControllerTest | ||
|
r7642 | fixtures :projects, :enabled_modules, :roles, :members, | ||
:member_roles, :issues, :time_entries, :users, | ||||
:trackers, :enumerations, :issue_statuses, | ||||
|
r11212 | :custom_fields, :custom_values, | ||
:projects_trackers, :custom_fields_trackers, | ||||
:custom_fields_projects | ||||
|
r569 | |||
|
r7824 | include Redmine::I18n | ||
|
r13058 | def test_new | ||
|
r1447 | @request.session[:user_id] = 3 | ||
|
r13058 | get :new | ||
|
r1447 | assert_response :success | ||
|
r15342 | |||
|
r13058 | assert_select 'input[name=?][type=hidden]', 'project_id', 0 | ||
assert_select 'input[name=?][type=hidden]', 'issue_id', 0 | ||||
assert_select 'select[name=?]', 'time_entry[project_id]' do | ||||
# blank option for project | ||||
|
r13237 | assert_select 'option[value=""]' | ||
|
r13058 | end | ||
|
r1447 | end | ||
|
r6504 | |||
|
r13058 | def test_new_with_project_id | ||
|
r4125 | @request.session[:user_id] = 3 | ||
|
r15284 | get :new, :params => {:project_id => 1} | ||
|
r4125 | assert_response :success | ||
|
r15342 | |||
|
r13058 | assert_select 'input[name=?][type=hidden]', 'project_id' | ||
assert_select 'input[name=?][type=hidden]', 'issue_id', 0 | ||||
|
r10000 | assert_select 'select[name=?]', 'time_entry[project_id]', 0 | ||
|
r8571 | end | ||
|
r13058 | def test_new_with_issue_id | ||
|
r8571 | @request.session[:user_id] = 3 | ||
|
r15284 | get :new, :params => {:issue_id => 2} | ||
|
r8571 | assert_response :success | ||
|
r15342 | |||
|
r13058 | assert_select 'input[name=?][type=hidden]', 'project_id', 0 | ||
assert_select 'input[name=?][type=hidden]', 'issue_id' | ||||
assert_select 'select[name=?]', 'time_entry[project_id]', 0 | ||||
|
r8571 | end | ||
|
r9558 | def test_new_without_project_should_prefill_the_form | ||
@request.session[:user_id] = 3 | ||||
|
r15284 | get :new, :params => {:time_entry => {:project_id => '1'}} | ||
|
r9558 | assert_response :success | ||
|
r15342 | |||
|
r9558 | assert_select 'select[name=?]', 'time_entry[project_id]' do | ||
|
r13237 | assert_select 'option[value="1"][selected=selected]' | ||
|
r9558 | end | ||
end | ||||
|
r8571 | def test_new_without_project_should_deny_without_permission | ||
Role.all.each {|role| role.remove_permission! :log_time} | ||||
@request.session[:user_id] = 3 | ||||
get :new | ||||
assert_response 403 | ||||
|
r4125 | end | ||
|
r10000 | def test_new_should_select_default_activity | ||
@request.session[:user_id] = 3 | ||||
|
r15284 | get :new, :params => {:project_id => 1} | ||
|
r10000 | assert_response :success | ||
assert_select 'select[name=?]', 'time_entry[activity_id]' do | ||||
assert_select 'option[selected=selected]', :text => 'Development' | ||||
end | ||||
end | ||||
def test_new_should_only_show_active_time_entry_activities | ||||
@request.session[:user_id] = 3 | ||||
|
r15284 | get :new, :params => {:project_id => 1} | ||
|
r10000 | assert_response :success | ||
|
r13242 | assert_select 'option', :text => 'Inactive Activity', :count => 0 | ||
|
r10000 | end | ||
|
r13905 | def test_post_new_as_js_should_update_activity_options | ||
@request.session[:user_id] = 3 | ||||
|
r15284 | post :new, :params => {:time_entry => {:project_id => 1}, :format => 'js'} | ||
|
r13905 | assert_response :success | ||
assert_include '#time_entry_activity_id', response.body | ||||
end | ||||
|
r2373 | def test_get_edit_existing_time | ||
@request.session[:user_id] = 2 | ||||
|
r15284 | get :edit, :params => {:id => 2, :project_id => nil} | ||
|
r2373 | assert_response :success | ||
|
r15342 | |||
|
r13242 | assert_select 'form[action=?]', '/time_entries/2' | ||
|
r2373 | end | ||
|
r6504 | |||
|
r2832 | def test_get_edit_with_an_existing_time_entry_with_inactive_activity | ||
te = TimeEntry.find(1) | ||||
te.activity = TimeEntryActivity.find_by_name("Inactive Activity") | ||||
|
r13909 | te.save!(:validate => false) | ||
|
r2832 | |||
@request.session[:user_id] = 1 | ||||
|
r15284 | get :edit, :params => {:project_id => 1, :id => 1} | ||
|
r2832 | assert_response :success | ||
|
r15342 | |||
|
r2832 | # Blank option since nothing is pre-selected | ||
|
r13242 | assert_select 'option', :text => '--- Please select ---' | ||
|
r2832 | end | ||
|
r6504 | |||
|
r4130 | def test_post_create | ||
|
r1235 | @request.session[:user_id] = 3 | ||
|
r13058 | assert_difference 'TimeEntry.count' do | ||
|
r15284 | post :create, :params => { | ||
:project_id => 1, | ||||
:time_entry => {:comments => 'Some work on TimelogControllerTest', | ||||
# Not the default activity | ||||
:activity_id => '11', | ||||
:spent_on => '2008-03-14', | ||||
:issue_id => '1', | ||||
:hours => '7.3' | ||||
} | ||||
} | ||||
|
r13058 | assert_redirected_to '/projects/ecookbook/time_entries' | ||
end | ||||
|
r6504 | |||
|
r13058 | t = TimeEntry.order('id DESC').first | ||
|
r1235 | assert_not_nil t | ||
|
r13058 | assert_equal 'Some work on TimelogControllerTest', t.comments | ||
assert_equal 1, t.project_id | ||||
assert_equal 1, t.issue_id | ||||
|
r1519 | assert_equal 11, t.activity_id | ||
|
r1235 | assert_equal 7.3, t.hours | ||
assert_equal 3, t.user_id | ||||
end | ||||
|
r4397 | |||
def test_post_create_with_blank_issue | ||||
@request.session[:user_id] = 3 | ||||
|
r13058 | assert_difference 'TimeEntry.count' do | ||
|
r15284 | post :create, :params => { | ||
:project_id => 1, | ||||
:time_entry => { | ||||
:comments => 'Some work on TimelogControllerTest', | ||||
# Not the default activity | ||||
:activity_id => '11', | ||||
:issue_id => '', | ||||
:spent_on => '2008-03-14', | ||||
:hours => '7.3' | ||||
} | ||||
} | ||||
|
r13058 | assert_redirected_to '/projects/ecookbook/time_entries' | ||
end | ||||
|
r6504 | |||
|
r13058 | t = TimeEntry.order('id DESC').first | ||
|
r4397 | assert_not_nil t | ||
|
r13058 | assert_equal 'Some work on TimelogControllerTest', t.comments | ||
assert_equal 1, t.project_id | ||||
assert_nil t.issue_id | ||||
|
r4397 | assert_equal 11, t.activity_id | ||
assert_equal 7.3, t.hours | ||||
assert_equal 3, t.user_id | ||||
end | ||||
|
r6504 | |||
|
r13780 | def test_create_on_project_with_time_tracking_disabled_should_fail | ||
Project.find(1).disable_module! :time_tracking | ||||
@request.session[:user_id] = 2 | ||||
assert_no_difference 'TimeEntry.count' do | ||||
|
r15284 | post :create, :params => { | ||
:time_entry => { | ||||
:project_id => '1', :issue_id => '', | ||||
:activity_id => '11', :spent_on => '2008-03-14', :hours => '7.3' | ||||
} | ||||
|
r13780 | } | ||
end | ||||
end | ||||
def test_create_on_project_without_permission_should_fail | ||||
Role.find(1).remove_permission! :log_time | ||||
@request.session[:user_id] = 2 | ||||
assert_no_difference 'TimeEntry.count' do | ||||
|
r15284 | post :create, :params => { | ||
:time_entry => { | ||||
:project_id => '1', :issue_id => '', | ||||
:activity_id => '11', :spent_on => '2008-03-14', :hours => '7.3' | ||||
} | ||||
|
r13780 | } | ||
end | ||||
end | ||||
def test_create_on_issue_in_project_with_time_tracking_disabled_should_fail | ||||
Project.find(1).disable_module! :time_tracking | ||||
@request.session[:user_id] = 2 | ||||
assert_no_difference 'TimeEntry.count' do | ||||
|
r15284 | post :create, :params => { | ||
:time_entry => { | ||||
:project_id => '', :issue_id => '1', | ||||
:activity_id => '11', :spent_on => '2008-03-14', :hours => '7.3' | ||||
} | ||||
|
r13780 | } | ||
assert_select_error /Issue is invalid/ | ||||
end | ||||
end | ||||
def test_create_on_issue_in_project_without_permission_should_fail | ||||
Role.find(1).remove_permission! :log_time | ||||
@request.session[:user_id] = 2 | ||||
assert_no_difference 'TimeEntry.count' do | ||||
|
r15284 | post :create, :params => { | ||
:time_entry => { | ||||
:project_id => '', :issue_id => '1', | ||||
:activity_id => '11', :spent_on => '2008-03-14', :hours => '7.3' | ||||
} | ||||
|
r13780 | } | ||
assert_select_error /Issue is invalid/ | ||||
end | ||||
end | ||||
|
r14414 | def test_create_on_issue_that_is_not_visible_should_not_disclose_subject | ||
issue = Issue.generate!(:subject => "issue_that_is_not_visible", :is_private => true) | ||||
assert !issue.visible?(User.find(3)) | ||||
@request.session[:user_id] = 3 | ||||
assert_no_difference 'TimeEntry.count' do | ||||
|
r15284 | post :create, :params => { | ||
:time_entry => { | ||||
:project_id => '', :issue_id => issue.id.to_s, | ||||
:activity_id => '11', :spent_on => '2008-03-14', :hours => '7.3' | ||||
} | ||||
|
r14414 | } | ||
end | ||||
assert_select_error /Issue is invalid/ | ||||
assert_select "input[name=?][value=?]", "time_entry[issue_id]", issue.id.to_s | ||||
assert_select "#time_entry_issue", 0 | ||||
assert !response.body.include?('issue_that_is_not_visible') | ||||
end | ||||
|
r13058 | def test_create_and_continue_at_project_level | ||
|
r8567 | @request.session[:user_id] = 2 | ||
|
r13058 | assert_difference 'TimeEntry.count' do | ||
|
r15284 | post :create, :params => { | ||
:time_entry => { | ||||
:project_id => '1', | ||||
:activity_id => '11', | ||||
:issue_id => '', | ||||
:spent_on => '2008-03-14', | ||||
:hours => '7.3' | ||||
}, | ||||
:continue => '1' | ||||
} | ||||
|
r13058 | assert_redirected_to '/time_entries/new?time_entry%5Bactivity_id%5D=11&time_entry%5Bissue_id%5D=&time_entry%5Bproject_id%5D=1' | ||
end | ||||
|
r8567 | end | ||
|
r13058 | def test_create_and_continue_at_issue_level | ||
|
r8567 | @request.session[:user_id] = 2 | ||
|
r13058 | assert_difference 'TimeEntry.count' do | ||
|
r15284 | post :create, :params => { | ||
:time_entry => { | ||||
:project_id => '', | ||||
:activity_id => '11', | ||||
:issue_id => '1', | ||||
:spent_on => '2008-03-14', | ||||
:hours => '7.3' | ||||
}, | ||||
:continue => '1' | ||||
} | ||||
|
r13058 | assert_redirected_to '/time_entries/new?time_entry%5Bactivity_id%5D=11&time_entry%5Bissue_id%5D=1&time_entry%5Bproject_id%5D=' | ||
end | ||||
|
r8567 | end | ||
|
r13058 | def test_create_and_continue_with_project_id | ||
|
r8571 | @request.session[:user_id] = 2 | ||
|
r13058 | assert_difference 'TimeEntry.count' do | ||
|
r15284 | post :create, :params => { | ||
:project_id => 1, | ||||
:time_entry => { | ||||
:activity_id => '11', | ||||
:issue_id => '', | ||||
:spent_on => '2008-03-14', | ||||
:hours => '7.3' | ||||
}, | ||||
:continue => '1' | ||||
} | ||||
|
r13058 | assert_redirected_to '/projects/ecookbook/time_entries/new?time_entry%5Bactivity_id%5D=11&time_entry%5Bissue_id%5D=&time_entry%5Bproject_id%5D=' | ||
end | ||||
end | ||||
|
r8571 | |||
|
r13058 | def test_create_and_continue_with_issue_id | ||
@request.session[:user_id] = 2 | ||||
assert_difference 'TimeEntry.count' do | ||||
|
r15284 | post :create, :params => { | ||
:issue_id => 1, | ||||
:time_entry => { | ||||
:activity_id => '11', | ||||
:issue_id => '1', | ||||
:spent_on => '2008-03-14', | ||||
:hours => '7.3' | ||||
}, | ||||
:continue => '1' | ||||
} | ||||
|
r13058 | 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=' | ||
end | ||||
|
r8571 | end | ||
|
r7801 | def test_create_without_log_time_permission_should_be_denied | ||
@request.session[:user_id] = 2 | ||||
Role.find_by_name('Manager').remove_permission! :log_time | ||||
|
r15284 | post :create, :params => { | ||
:project_id => 1, | ||||
:time_entry => { | ||||
:activity_id => '11', | ||||
:issue_id => '', | ||||
:spent_on => '2008-03-14', | ||||
:hours => '7.3' | ||||
} | ||||
} | ||||
|
r7801 | assert_response 403 | ||
end | ||||
|
r13058 | def test_create_without_project_and_issue_should_fail | ||
@request.session[:user_id] = 2 | ||||
|
r15284 | post :create, :params => {:time_entry => {:issue_id => ''}} | ||
|
r13058 | |||
assert_response :success | ||||
|
r15342 | assert_select_error /Project cannot be blank/ | ||
|
r13058 | end | ||
|
r8571 | def test_create_with_failure | ||
@request.session[:user_id] = 2 | ||||
|
r15284 | post :create, :params => { | ||
:project_id => 1, | ||||
:time_entry => { | ||||
:activity_id => '', | ||||
:issue_id => '', | ||||
:spent_on => '2008-03-14', | ||||
:hours => '7.3' | ||||
} | ||||
} | ||||
|
r8571 | assert_response :success | ||
end | ||||
def test_create_without_project | ||||
@request.session[:user_id] = 2 | ||||
assert_difference 'TimeEntry.count' do | ||||
|
r15284 | post :create, :params => { | ||
:time_entry => { | ||||
:project_id => '1', | ||||
:activity_id => '11', | ||||
:issue_id => '', | ||||
:spent_on => '2008-03-14', | ||||
:hours => '7.3' | ||||
} | ||||
} | ||||
|
r8571 | end | ||
assert_redirected_to '/projects/ecookbook/time_entries' | ||||
|
r12367 | time_entry = TimeEntry.order('id DESC').first | ||
|
r8571 | assert_equal 1, time_entry.project_id | ||
end | ||||
|
r8573 | def test_create_without_project_should_fail_with_issue_not_inside_project | ||
@request.session[:user_id] = 2 | ||||
assert_no_difference 'TimeEntry.count' do | ||||
|
r15284 | post :create, :params => { | ||
:time_entry => { | ||||
:project_id => '1', | ||||
:activity_id => '11', | ||||
:issue_id => '5', | ||||
:spent_on => '2008-03-14', | ||||
:hours => '7.3' | ||||
} | ||||
} | ||||
|
r8573 | end | ||
assert_response :success | ||||
|
r15342 | assert_select_error /Issue is invalid/ | ||
|
r8573 | end | ||
|
r8571 | def test_create_without_project_should_deny_without_permission | ||
@request.session[:user_id] = 2 | ||||
Project.find(3).disable_module!(:time_tracking) | ||||
assert_no_difference 'TimeEntry.count' do | ||||
|
r15284 | post :create, :params => { | ||
:time_entry => { | ||||
:project_id => '3', | ||||
:activity_id => '11', | ||||
:issue_id => '', | ||||
:spent_on => '2008-03-14', | ||||
:hours => '7.3' | ||||
} | ||||
} | ||||
|
r8571 | end | ||
assert_response 403 | ||||
end | ||||
def test_create_without_project_with_failure | ||||
@request.session[:user_id] = 2 | ||||
assert_no_difference 'TimeEntry.count' do | ||||
|
r15284 | post :create, :params => { | ||
:time_entry => { | ||||
:project_id => '1', | ||||
:activity_id => '11', | ||||
:issue_id => '', | ||||
:spent_on => '2008-03-14', | ||||
:hours => '' | ||||
} | ||||
} | ||||
|
r8571 | end | ||
assert_response :success | ||||
|
r13242 | assert_select 'select[name=?]', 'time_entry[project_id]' do | ||
assert_select 'option[value="1"][selected=selected]' | ||||
end | ||||
|
r8571 | end | ||
|
r1235 | def test_update | ||
entry = TimeEntry.find(1) | ||||
assert_equal 1, entry.issue_id | ||||
assert_equal 2, entry.user_id | ||||
|
r6504 | |||
|
r1235 | @request.session[:user_id] = 1 | ||
|
r15284 | put :update, :params => { | ||
:id => 1, | ||||
:time_entry => { | ||||
:issue_id => '2', | ||||
:hours => '8' | ||||
} | ||||
} | ||||
|
r4121 | assert_redirected_to :action => 'index', :project_id => 'ecookbook' | ||
|
r1235 | entry.reload | ||
|
r6504 | |||
|
r1235 | assert_equal 8, entry.hours | ||
assert_equal 2, entry.issue_id | ||||
assert_equal 2, entry.user_id | ||||
end | ||||
|
r5195 | |||
|
r12715 | def test_update_should_allow_to_change_issue_to_another_project | ||
entry = TimeEntry.generate!(:issue_id => 1) | ||||
@request.session[:user_id] = 1 | ||||
|
r15284 | put :update, :params => { | ||
:id => entry.id, | ||||
:time_entry => { | ||||
:issue_id => '5' | ||||
} | ||||
} | ||||
|
r12715 | assert_response 302 | ||
entry.reload | ||||
assert_equal 5, entry.issue_id | ||||
assert_equal 3, entry.project_id | ||||
end | ||||
def test_update_should_not_allow_to_change_issue_to_an_invalid_project | ||||
entry = TimeEntry.generate!(:issue_id => 1) | ||||
Project.find(3).disable_module!(:time_tracking) | ||||
@request.session[:user_id] = 1 | ||||
|
r15284 | put :update, :params => { | ||
:id => entry.id, | ||||
:time_entry => { | ||||
:issue_id => '5' | ||||
} | ||||
} | ||||
|
r15342 | assert_response :success | ||
assert_select_error /Issue is invalid/ | ||||
|
r12715 | end | ||
|
r5195 | def test_get_bulk_edit | ||
@request.session[:user_id] = 2 | ||||
|
r15284 | |||
get :bulk_edit, :params => {:ids => [1, 2]} | ||||
|
r5195 | assert_response :success | ||
|
r6504 | |||
|
r10841 | assert_select 'ul#bulk-selection' do | ||
assert_select 'li', 2 | ||||
assert_select 'li a', :text => '03/23/2007 - eCookbook: 4.25 hours' | ||||
end | ||||
|
r9460 | |||
|
r10841 | assert_select 'form#bulk_edit_form[action=?]', '/time_entries/bulk_update' do | ||
# System wide custom field | ||||
assert_select 'select[name=?]', 'time_entry[custom_field_values][10]' | ||||
# Activities | ||||
assert_select 'select[name=?]', 'time_entry[activity_id]' do | ||||
|
r13237 | assert_select 'option[value=""]', :text => '(No change)' | ||
assert_select 'option[value="9"]', :text => 'Design' | ||||
|
r10841 | end | ||
|
r9460 | end | ||
|
r5195 | end | ||
def test_get_bulk_edit_on_different_projects | ||||
@request.session[:user_id] = 2 | ||||
|
r15284 | |||
get :bulk_edit, :params => {:ids => [1, 2, 6]} | ||||
|
r5195 | assert_response :success | ||
end | ||||
|
r13860 | def test_bulk_edit_with_edit_own_time_entries_permission | ||
@request.session[:user_id] = 2 | ||||
Role.find_by_name('Manager').remove_permission! :edit_time_entries | ||||
Role.find_by_name('Manager').add_permission! :edit_own_time_entries | ||||
ids = (0..1).map {TimeEntry.generate!(:user => User.find(2)).id} | ||||
|
r15284 | get :bulk_edit, :params => {:ids => ids} | ||
|
r13860 | assert_response :success | ||
end | ||||
|
r5195 | def test_bulk_update | ||
@request.session[:user_id] = 2 | ||||
# update time entry activity | ||||
|
r15284 | post :bulk_update, :params => {:ids => [1, 2], :time_entry => { :activity_id => 9}} | ||
|
r6504 | |||
|
r5195 | assert_response 302 | ||
# check that the issues were updated | ||||
|
r12369 | assert_equal [9, 9], TimeEntry.where(:id => [1, 2]).collect {|i| i.activity_id} | ||
|
r5195 | end | ||
|
r8143 | def test_bulk_update_with_failure | ||
@request.session[:user_id] = 2 | ||||
|
r15284 | post :bulk_update, :params => {:ids => [1, 2], :time_entry => { :hours => 'A'}} | ||
|
r8143 | |||
assert_response 302 | ||||
assert_match /Failed to save 2 time entrie/, flash[:error] | ||||
end | ||||
|
r5195 | def test_bulk_update_on_different_projects | ||
@request.session[:user_id] = 2 | ||||
|
r7800 | # makes user a manager on the other project | ||
Member.create!(:user_id => 2, :project_id => 3, :role_ids => [1]) | ||||
|
r5195 | # update time entry activity | ||
|
r15284 | post :bulk_update, :params => {:ids => [1, 2, 4], :time_entry => { :activity_id => 9 }} | ||
|
r6504 | |||
|
r5195 | assert_response 302 | ||
# check that the issues were updated | ||||
|
r12376 | assert_equal [9, 9, 9], TimeEntry.where(:id => [1, 2, 4]).collect {|i| i.activity_id} | ||
|
r5195 | end | ||
def test_bulk_update_on_different_projects_without_rights | ||||
@request.session[:user_id] = 3 | ||||
user = User.find(3) | ||||
action = { :controller => "timelog", :action => "bulk_update" } | ||||
assert user.allowed_to?(action, TimeEntry.find(1).project) | ||||
assert ! user.allowed_to?(action, TimeEntry.find(5).project) | ||||
|
r15284 | |||
post :bulk_update, :params => {:ids => [1, 5], :time_entry => { :activity_id => 9 }} | ||||
|
r5195 | assert_response 403 | ||
end | ||||
|
r13860 | def test_bulk_update_with_edit_own_time_entries_permission | ||
@request.session[:user_id] = 2 | ||||
Role.find_by_name('Manager').remove_permission! :edit_time_entries | ||||
Role.find_by_name('Manager').add_permission! :edit_own_time_entries | ||||
ids = (0..1).map {TimeEntry.generate!(:user => User.find(2)).id} | ||||
|
r15284 | post :bulk_update, :params => {:ids => ids, :time_entry => { :activity_id => 9 }} | ||
|
r13860 | assert_response 302 | ||
end | ||||
def test_bulk_update_with_edit_own_time_entries_permissions_should_be_denied_for_time_entries_of_other_user | ||||
@request.session[:user_id] = 2 | ||||
Role.find_by_name('Manager').remove_permission! :edit_time_entries | ||||
Role.find_by_name('Manager').add_permission! :edit_own_time_entries | ||||
|
r15284 | post :bulk_update, :params => {:ids => [1, 2], :time_entry => { :activity_id => 9 }} | ||
|
r13860 | assert_response 403 | ||
end | ||||
|
r5195 | def test_bulk_update_custom_field | ||
@request.session[:user_id] = 2 | ||||
|
r15284 | post :bulk_update, :params => {:ids => [1, 2], :time_entry => { :custom_field_values => {'10' => '0'} }} | ||
|
r6504 | |||
|
r5195 | assert_response 302 | ||
|
r12376 | assert_equal ["0", "0"], TimeEntry.where(:id => [1, 2]).collect {|i| i.custom_value_for(10).value} | ||
|
r5195 | end | ||
|
r15151 | def test_bulk_update_clear_custom_field | ||
field = TimeEntryCustomField.generate!(:field_format => 'string') | ||||
@request.session[:user_id] = 2 | ||||
|
r15284 | post :bulk_update, :params => {:ids => [1, 2], :time_entry => { :custom_field_values => {field.id.to_s => '__none__'} }} | ||
|
r15151 | |||
assert_response 302 | ||||
assert_equal ["", ""], TimeEntry.where(:id => [1, 2]).collect {|i| i.custom_value_for(field).value} | ||||
end | ||||
|
r5195 | def test_post_bulk_update_should_redirect_back_using_the_back_url_parameter | ||
@request.session[:user_id] = 2 | ||||
|
r15284 | post :bulk_update, :params => {:ids => [1,2], :back_url => '/time_entries'} | ||
|
r5195 | |||
assert_response :redirect | ||||
assert_redirected_to '/time_entries' | ||||
end | ||||
def test_post_bulk_update_should_not_redirect_back_using_the_back_url_parameter_off_the_host | ||||
@request.session[:user_id] = 2 | ||||
|
r15284 | post :bulk_update, :params => {:ids => [1,2], :back_url => 'http://google.com'} | ||
|
r5195 | |||
assert_response :redirect | ||||
assert_redirected_to :controller => 'timelog', :action => 'index', :project_id => Project.find(1).identifier | ||||
end | ||||
|
r6504 | |||
|
r7800 | def test_post_bulk_update_without_edit_permission_should_be_denied | ||
@request.session[:user_id] = 2 | ||||
Role.find_by_name('Manager').remove_permission! :edit_time_entries | ||||
|
r15284 | post :bulk_update, :params => {:ids => [1,2]} | ||
|
r7800 | assert_response 403 | ||
end | ||||
|
r1777 | def test_destroy | ||
|
r1235 | @request.session[:user_id] = 2 | ||
|
r15284 | |||
delete :destroy, :params => {:id => 1} | ||||
|
r4121 | assert_redirected_to :action => 'index', :project_id => 'ecookbook' | ||
|
r3691 | assert_equal I18n.t(:notice_successful_delete), flash[:notice] | ||
|
r1235 | assert_nil TimeEntry.find_by_id(1) | ||
end | ||||
|
r6504 | |||
|
r3691 | def test_destroy_should_fail | ||
# simulate that this fails (e.g. due to a plugin), see #5700 | ||||
|
r5199 | TimeEntry.any_instance.expects(:destroy).returns(false) | ||
|
r3691 | @request.session[:user_id] = 2 | ||
|
r15284 | |||
delete :destroy, :params => {:id => 1} | ||||
|
r4121 | assert_redirected_to :action => 'index', :project_id => 'ecookbook' | ||
|
r3691 | assert_equal I18n.t(:notice_unable_delete_time_entry), flash[:error] | ||
assert_not_nil TimeEntry.find_by_id(1) | ||||
end | ||||
|
r6504 | |||
|
r4121 | def test_index_all_projects | ||
get :index | ||||
|
r1777 | assert_response :success | ||
|
r15267 | |||
assert_select '.total-for-hours', :text => 'Hours: 162.90' | ||||
|
r13242 | assert_select 'form#query_form[action=?]', '/time_entries' | ||
|
r1777 | end | ||
|
r6504 | |||
|
r8571 | def test_index_all_projects_should_show_log_time_link | ||
@request.session[:user_id] = 2 | ||||
get :index | ||||
assert_response :success | ||||
|
r15342 | |||
|
r13242 | assert_select 'a[href=?]', '/time_entries/new', :text => /Log time/ | ||
|
r8571 | end | ||
|
r11629 | def test_index_my_spent_time | ||
@request.session[:user_id] = 2 | ||||
|
r15342 | get :index, :params => {:user_id => 'me', :c => ['user']} | ||
|
r11629 | assert_response :success | ||
|
r15342 | |||
users = css_select('table.time-entries tbody td.user').map(&:text).uniq | ||||
assert_equal ["John Smith"], users | ||||
|
r11629 | end | ||
|
r4121 | def test_index_at_project_level | ||
|
r15342 | get :index, :params => {:project_id => 'ecookbook', :c => ['project']} | ||
|
r1159 | assert_response :success | ||
|
r15342 | |||
assert_select 'tr.time-entry', 4 | ||||
|
r1162 | # project and subproject | ||
|
r15342 | projects = css_select('table.time-entries tbody td.project').map(&:text).uniq.sort | ||
assert_equal ["eCookbook", "eCookbook Subproject 1"], projects | ||||
|
r15267 | |||
assert_select '.total-for-hours', :text => 'Hours: 162.90' | ||||
|
r13242 | assert_select 'form#query_form[action=?]', '/projects/ecookbook/time_entries' | ||
|
r1159 | end | ||
|
r6504 | |||
|
r11827 | def test_index_with_display_subprojects_issues_to_false_should_not_include_subproject_entries | ||
entry = TimeEntry.generate!(:project => Project.find(3)) | ||||
with_settings :display_subprojects_issues => '0' do | ||||
|
r15342 | get :index, :params => {:project_id => 'ecookbook', :c => ['project']} | ||
|
r11827 | assert_response :success | ||
|
r15342 | |||
projects = css_select('table.time-entries tbody td.project').map(&:text).uniq.sort | ||||
assert_equal ["eCookbook"], projects | ||||
|
r11827 | end | ||
end | ||||
def test_index_with_display_subprojects_issues_to_false_and_subproject_filter_should_include_subproject_entries | ||||
entry = TimeEntry.generate!(:project => Project.find(3)) | ||||
with_settings :display_subprojects_issues => '0' do | ||||
|
r15342 | get :index, :params => {:project_id => 'ecookbook', :c => ['project'], :subproject_id => 3} | ||
|
r11827 | assert_response :success | ||
|
r15342 | |||
projects = css_select('table.time-entries tbody td.project').map(&:text).uniq.sort | ||||
assert_equal ["eCookbook", "eCookbook Subproject 1"], projects | ||||
|
r11827 | end | ||
end | ||||
|
r15264 | def test_index_at_project_level_with_issue_id_short_filter | ||
issue = Issue.generate!(:project_id => 1) | ||||
TimeEntry.generate!(:issue => issue, :hours => 4) | ||||
TimeEntry.generate!(:issue => issue, :hours => 3) | ||||
@request.session[:user_id] = 2 | ||||
|
r15284 | get :index, :params => {:project_id => 'ecookbook', :issue_id => issue.id.to_s, :set_filter => 1} | ||
|
r15267 | assert_select '.total-for-hours', :text => 'Hours: 7.00' | ||
|
r15264 | end | ||
def test_index_at_project_level_with_issue_fixed_version_id_short_filter | ||||
version = Version.generate!(:project_id => 1) | ||||
issue = Issue.generate!(:project_id => 1, :fixed_version => version) | ||||
TimeEntry.generate!(:issue => issue, :hours => 2) | ||||
TimeEntry.generate!(:issue => issue, :hours => 3) | ||||
@request.session[:user_id] = 2 | ||||
|
r15284 | get :index, :params => {:project_id => 'ecookbook', :"issue.fixed_version_id" => version.id.to_s, :set_filter => 1} | ||
|
r15267 | assert_select '.total-for-hours', :text => 'Hours: 5.00' | ||
|
r15264 | end | ||
|
r4121 | def test_index_at_project_level_with_date_range | ||
|
r15284 | get :index, :params => { | ||
:project_id => 'ecookbook', | ||||
|
r10740 | :f => ['spent_on'], | ||
:op => {'spent_on' => '><'}, | ||||
:v => {'spent_on' => ['2007-03-20', '2007-04-30']} | ||||
|
r15284 | } | ||
|
r1159 | assert_response :success | ||
|
r15267 | |||
|
r15342 | assert_select 'tr.time-entry', 3 | ||
|
r15267 | assert_select '.total-for-hours', :text => 'Hours: 12.90' | ||
|
r13242 | assert_select 'form#query_form[action=?]', '/projects/ecookbook/time_entries' | ||
|
r1159 | end | ||
|
r10740 | def test_index_at_project_level_with_date_range_using_from_and_to_params | ||
|
r15284 | get :index, :params => { | ||
:project_id => 'ecookbook', | ||||
:from => '2007-03-20', | ||||
:to => '2007-04-30' | ||||
} | ||||
|
r1159 | assert_response :success | ||
|
r15267 | |||
|
r15342 | assert_select 'tr.time-entry', 3 | ||
|
r15267 | assert_select '.total-for-hours', :text => 'Hours: 12.90' | ||
|
r13242 | assert_select 'form#query_form[action=?]', '/projects/ecookbook/time_entries' | ||
|
r1159 | end | ||
|
r2895 | |||
|
r10740 | def test_index_at_project_level_with_period | ||
|
r15284 | get :index, :params => { | ||
:project_id => 'ecookbook', | ||||
|
r10740 | :f => ['spent_on'], | ||
:op => {'spent_on' => '>t-'}, | ||||
:v => {'spent_on' => ['7']} | ||||
|
r15284 | } | ||
|
r2895 | assert_response :success | ||
|
r15267 | |||
|
r13242 | assert_select 'form#query_form[action=?]', '/projects/ecookbook/time_entries' | ||
|
r2895 | end | ||
|
r6504 | |||
|
r9654 | def test_index_should_sort_by_spent_on_and_created_on | ||
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) | ||||
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) | ||||
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) | ||||
|
r15284 | get :index, :params => { | ||
:project_id => 1, | ||||
|
r10740 | :f => ['spent_on'], | ||
:op => {'spent_on' => '><'}, | ||||
:v => {'spent_on' => ['2012-06-15', '2012-06-16']} | ||||
|
r15284 | } | ||
|
r9654 | assert_response :success | ||
|
r15342 | assert_equal [t2, t1, t3].map(&:id).map(&:to_s), css_select('input[name="ids[]"]').map {|e| e.attr('value')} | ||
|
r9654 | |||
|
r15284 | get :index, :params => { | ||
:project_id => 1, | ||||
|
r10740 | :f => ['spent_on'], | ||
:op => {'spent_on' => '><'}, | ||||
:v => {'spent_on' => ['2012-06-15', '2012-06-16']}, | ||||
:sort => 'spent_on' | ||||
|
r15284 | } | ||
|
r9654 | assert_response :success | ||
|
r15342 | assert_equal [t3, t1, t2].map(&:id).map(&:to_s), css_select('input[name="ids[]"]').map {|e| e.attr('value')} | ||
|
r9654 | end | ||
|
r15356 | def test_index_with_issue_status_filter | ||
Issue.where(:status_id => 4).update_all(:status_id => 2) | ||||
issue = Issue.generate!(:project_id => 1, :tracker_id => 1, :status_id => 4) | ||||
entry = TimeEntry.generate!(:issue => issue, :hours => 4.5) | ||||
get :index, :params => { | ||||
:f => ['issue.status_id'], | ||||
:op => {'issue.status_id' => '='}, | ||||
:v => {'issue.status_id' => ['4']} | ||||
} | ||||
assert_response :success | ||||
assert_equal [entry].map(&:id).map(&:to_s), css_select('input[name="ids[]"]').map {|e| e.attr('value')} | ||||
end | ||||
def test_index_with_issue_status_column | ||||
issue = Issue.generate!(:project_id => 1, :tracker_id => 1, :status_id => 4) | ||||
entry = TimeEntry.generate!(:issue => issue) | ||||
get :index, :params => { | ||||
:c => %w(project spent_on issue comments hours issue.status) | ||||
} | ||||
assert_response :success | ||||
assert_select 'td.issue-status', :text => issue.status.name | ||||
end | ||||
def test_index_with_issue_status_sort | ||||
TimeEntry.delete_all | ||||
|
r15527 | TimeEntry.generate!(:issue => Issue.generate!(:project_id => 1, :tracker_id => 1, :status_id => 1)) | ||
TimeEntry.generate!(:issue => Issue.generate!(:project_id => 1, :tracker_id => 1, :status_id => 5)) | ||||
TimeEntry.generate!(:issue => Issue.generate!(:project_id => 1, :tracker_id => 1, :status_id => 3)) | ||||
|
r15356 | TimeEntry.generate!(:project_id => 1) | ||
get :index, :params => { | ||||
:c => ["hours", 'issue.status'], | ||||
:sort => 'issue.status' | ||||
} | ||||
assert_response :success | ||||
# Make sure that values are properly sorted | ||||
values = css_select("td.issue-status").map(&:text).reject(&:blank?) | ||||
assert_equal IssueStatus.where(:id => [1, 5, 3]).sorted.pluck(:name), values | ||||
end | ||||
def test_index_with_issue_tracker_filter | ||||
Issue.where(:tracker_id => 2).update_all(:tracker_id => 1) | ||||
issue = Issue.generate!(:project_id => 1, :tracker_id => 2) | ||||
entry = TimeEntry.generate!(:issue => issue, :hours => 4.5) | ||||
get :index, :params => { | ||||
:f => ['issue.tracker_id'], | ||||
:op => {'issue.tracker_id' => '='}, | ||||
:v => {'issue.tracker_id' => ['2']} | ||||
} | ||||
assert_response :success | ||||
assert_equal [entry].map(&:id).map(&:to_s), css_select('input[name="ids[]"]').map {|e| e.attr('value')} | ||||
end | ||||
def test_index_with_issue_tracker_column | ||||
issue = Issue.generate!(:project_id => 1, :tracker_id => 2) | ||||
entry = TimeEntry.generate!(:issue => issue) | ||||
get :index, :params => { | ||||
:c => %w(project spent_on issue comments hours issue.tracker) | ||||
} | ||||
assert_response :success | ||||
assert_select 'td.issue-tracker', :text => issue.tracker.name | ||||
end | ||||
def test_index_with_issue_tracker_sort | ||||
TimeEntry.delete_all | ||||
TimeEntry.generate!(:issue => Issue.generate!(:tracker_id => 1)) | ||||
TimeEntry.generate!(:issue => Issue.generate!(:tracker_id => 3)) | ||||
TimeEntry.generate!(:issue => Issue.generate!(:tracker_id => 2)) | ||||
TimeEntry.generate!(:project_id => 1) | ||||
get :index, :params => { | ||||
:c => ["hours", 'issue.tracker'], | ||||
:sort => 'issue.tracker' | ||||
} | ||||
assert_response :success | ||||
# Make sure that values are properly sorted | ||||
values = css_select("td.issue-tracker").map(&:text).reject(&:blank?) | ||||
assert_equal Tracker.where(:id => [1, 2, 3]).sorted.pluck(:name), values | ||||
end | ||||
|
r10941 | def test_index_with_filter_on_issue_custom_field | ||
issue = Issue.generate!(:project_id => 1, :tracker_id => 1, :custom_field_values => {2 => 'filter_on_issue_custom_field'}) | ||||
entry = TimeEntry.generate!(:issue => issue, :hours => 2.5) | ||||
|
r15284 | get :index, :params => { | ||
:f => ['issue.cf_2'], | ||||
:op => {'issue.cf_2' => '='}, | ||||
:v => {'issue.cf_2' => ['filter_on_issue_custom_field']} | ||||
} | ||||
|
r10941 | assert_response :success | ||
|
r15342 | assert_equal [entry].map(&:id).map(&:to_s), css_select('input[name="ids[]"]').map {|e| e.attr('value')} | ||
|
r10941 | end | ||
|
r10944 | def test_index_with_issue_custom_field_column | ||
issue = Issue.generate!(:project_id => 1, :tracker_id => 1, :custom_field_values => {2 => 'filter_on_issue_custom_field'}) | ||||
entry = TimeEntry.generate!(:issue => issue, :hours => 2.5) | ||||
|
r15284 | get :index, :params => { | ||
:c => %w(project spent_on issue comments hours issue.cf_2) | ||||
} | ||||
|
r10944 | assert_response :success | ||
assert_select 'td.issue_cf_2', :text => 'filter_on_issue_custom_field' | ||||
end | ||||
|
r11811 | def test_index_with_time_entry_custom_field_column | ||
field = TimeEntryCustomField.generate!(:field_format => 'string') | ||||
entry = TimeEntry.generate!(:hours => 2.5, :custom_field_values => {field.id => 'CF Value'}) | ||||
field_name = "cf_#{field.id}" | ||||
|
r15284 | get :index, :params => { | ||
:c => ["hours", field_name] | ||||
} | ||||
|
r11811 | assert_response :success | ||
assert_select "td.#{field_name}", :text => 'CF Value' | ||||
end | ||||
|
r11812 | def test_index_with_time_entry_custom_field_sorting | ||
field = TimeEntryCustomField.generate!(:field_format => 'string', :name => 'String Field') | ||||
TimeEntry.generate!(:hours => 2.5, :custom_field_values => {field.id => 'CF Value 1'}) | ||||
TimeEntry.generate!(:hours => 2.5, :custom_field_values => {field.id => 'CF Value 3'}) | ||||
TimeEntry.generate!(:hours => 2.5, :custom_field_values => {field.id => 'CF Value 2'}) | ||||
field_name = "cf_#{field.id}" | ||||
|
r15284 | get :index, :params => { | ||
:c => ["hours", field_name], | ||||
:sort => field_name | ||||
} | ||||
|
r11812 | assert_response :success | ||
assert_select "th a.sort", :text => 'String Field' | ||||
# Make sure that values are properly sorted | ||||
|
r15342 | values = css_select("td.#{field_name}").map(&:text).reject(&:blank?) | ||
|
r11812 | assert_equal values.sort, values | ||
|
r15342 | assert_equal 3, values.size | ||
|
r11812 | end | ||
|
r15257 | def test_index_with_query | ||
query = TimeEntryQuery.new(:project_id => 1, :name => 'Time Entry Query', :visibility => 2) | ||||
query.save! | ||||
@request.session[:user_id] = 2 | ||||
|
r15284 | get :index, :params => {:project_id => 'ecookbook', :query_id => query.id} | ||
|
r15257 | assert_response :success | ||
assert_select 'h2', :text => query.name | ||||
|
r15260 | assert_select '#sidebar a.selected', :text => query.name | ||
|
r15257 | end | ||
|
r4121 | def test_index_atom_feed | ||
|
r15284 | get :index, :params => {:project_id => 1, :format => 'atom'} | ||
|
r1546 | assert_response :success | ||
assert_equal 'application/atom+xml', @response.content_type | ||||
|
r15342 | assert_select 'entry > title', :text => /7\.65 hours/ | ||
|
r1546 | end | ||
|
r6504 | |||
|
r11466 | def test_index_at_project_level_should_include_csv_export_dialog | ||
|
r15284 | get :index, :params => { | ||
:project_id => 'ecookbook', | ||||
|
r11466 | :f => ['spent_on'], | ||
:op => {'spent_on' => '>='}, | ||||
:v => {'spent_on' => ['2007-04-01']}, | ||||
:c => ['spent_on', 'user'] | ||||
|
r15284 | } | ||
|
r11466 | assert_response :success | ||
assert_select '#csv-export-options' do | ||||
assert_select 'form[action=?][method=get]', '/projects/ecookbook/time_entries.csv' do | ||||
# filter | ||||
assert_select 'input[name=?][value=?]', 'f[]', 'spent_on' | ||||
|
r13510 | assert_select 'input[name=?][value=?]', 'op[spent_on]', '>=' | ||
|
r11466 | assert_select 'input[name=?][value=?]', 'v[spent_on][]', '2007-04-01' | ||
# columns | ||||
assert_select 'input[name=?][value=?]', 'c[]', 'spent_on' | ||||
assert_select 'input[name=?][value=?]', 'c[]', 'user' | ||||
assert_select 'input[name=?]', 'c[]', 2 | ||||
end | ||||
end | ||||
end | ||||
def test_index_cross_project_should_include_csv_export_dialog | ||||
get :index | ||||
assert_response :success | ||||
assert_select '#csv-export-options' do | ||||
assert_select 'form[action=?][method=get]', '/time_entries.csv' | ||||
end | ||||
end | ||||
|
r11212 | def test_index_csv_all_projects | ||
|
r13100 | with_settings :date_format => '%m/%d/%Y' do | ||
|
r15284 | get :index, :params => {:format => 'csv'} | ||
|
r13100 | assert_response :success | ||
assert_equal 'text/csv; header=present', response.content_type | ||||
end | ||||
|
r1777 | end | ||
|
r6504 | |||
|
r11212 | def test_index_csv | ||
|
r13100 | with_settings :date_format => '%m/%d/%Y' do | ||
|
r15284 | get :index, :params => {:project_id => 1, :format => 'csv'} | ||
|
r13100 | assert_response :success | ||
assert_equal 'text/csv; header=present', response.content_type | ||||
end | ||||
|
r7824 | end | ||
|
r13180 | |||
def test_index_csv_should_fill_issue_column_with_tracker_id_and_subject | ||||
issue = Issue.find(1) | ||||
entry = TimeEntry.generate!(:issue => issue, :comments => "Issue column content test") | ||||
|
r15284 | get :index, :params => {:format => 'csv'} | ||
|
r13180 | line = response.body.split("\n").detect {|l| l.include?(entry.comments)} | ||
assert_not_nil line | ||||
assert_include "#{issue.tracker} #1: #{issue.subject}", line | ||||
end | ||||
|
r569 | end | ||