"Fossies" - the Fresh Open Source Software Archive

Member "redmine-4.1.1/test/functional/timelog_controller_test.rb" (6 Apr 2020, 50777 Bytes) of package /linux/www/redmine-4.1.1.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Ruby source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. See also the latest Fossies "Diffs" side-by-side code changes report for "timelog_controller_test.rb": 4.1.0_vs_4.1.1.

    1 # frozen_string_literal: true
    2 
    3 # Redmine - project management software
    4 # Copyright (C) 2006-2019  Jean-Philippe Lang
    5 #
    6 # This program is free software; you can redistribute it and/or
    7 # modify it under the terms of the GNU General Public License
    8 # as published by the Free Software Foundation; either version 2
    9 # of the License, or (at your option) any later version.
   10 #
   11 # This program is distributed in the hope that it will be useful,
   12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
   13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   14 # GNU General Public License for more details.
   15 #
   16 # You should have received a copy of the GNU General Public License
   17 # along with this program; if not, write to the Free Software
   18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
   19 
   20 require File.expand_path('../../test_helper', __FILE__)
   21 
   22 class TimelogControllerTest < Redmine::ControllerTest
   23   fixtures :projects, :enabled_modules, :roles, :members,
   24            :member_roles, :issues, :time_entries, :users,
   25            :trackers, :enumerations, :issue_statuses,
   26            :custom_fields, :custom_values,
   27            :projects_trackers, :custom_fields_trackers,
   28            :custom_fields_projects, :issue_categories, :versions
   29 
   30   include Redmine::I18n
   31 
   32   def setup
   33     super
   34     Setting.default_language = 'en'
   35   end
   36 
   37   def test_new
   38     @request.session[:user_id] = 3
   39     get :new
   40     assert_response :success
   41 
   42     assert_select 'input[name=?][type=hidden]', 'project_id', 0
   43     assert_select 'input[name=?][type=hidden]', 'issue_id', 0
   44     assert_select 'span[id=?]', 'time_entry_issue'
   45     assert_select 'select[name=?]', 'time_entry[project_id]' do
   46       # blank option for project
   47       assert_select 'option[value=""]'
   48     end
   49     assert_select 'label[for=?]', 'time_entry_user_id', 0
   50     assert_select 'select[name=?]', 'time_entry[user_id]', 0
   51   end
   52 
   53   def test_new_with_project_id
   54     @request.session[:user_id] = 3
   55     get :new, :params => {:project_id => 1}
   56     assert_response :success
   57 
   58     assert_select 'input[name=?][type=hidden]', 'project_id'
   59     assert_select 'input[name=?][type=hidden]', 'issue_id', 0
   60     assert_select 'select[name=?]', 'time_entry[project_id]', 0
   61   end
   62 
   63   def test_new_with_issue_id
   64     @request.session[:user_id] = 3
   65     get :new, :params => {:issue_id => 2}
   66     assert_response :success
   67 
   68     assert_select 'input[name=?][type=hidden]', 'project_id', 0
   69     assert_select 'input[name=?][type=hidden]', 'issue_id'
   70     assert_select 'a[href=?]', '/issues/2', :text => /Feature request #2/
   71     assert_select 'select[name=?]', 'time_entry[project_id]', 0
   72   end
   73 
   74   def test_new_without_project_should_prefill_the_form
   75     @request.session[:user_id] = 3
   76     get :new, :params => {:time_entry => {:project_id => '1'}}
   77     assert_response :success
   78 
   79     assert_select 'select[name=?]', 'time_entry[project_id]' do
   80       assert_select 'option[value="1"][selected=selected]'
   81     end
   82   end
   83 
   84   def test_new_without_project_should_deny_without_permission
   85     Role.all.each {|role| role.remove_permission! :log_time}
   86     @request.session[:user_id] = 3
   87 
   88     get :new
   89     assert_response 403
   90   end
   91 
   92   def test_new_should_select_default_activity
   93     @request.session[:user_id] = 3
   94     get :new, :params => {:project_id => 1}
   95     assert_response :success
   96     assert_select 'select[name=?]', 'time_entry[activity_id]' do
   97       assert_select 'option[selected=selected]', :text => 'Development'
   98     end
   99   end
  100 
  101   def test_new_should_only_show_active_time_entry_activities
  102     @request.session[:user_id] = 3
  103     get :new, :params => {:project_id => 1}
  104     assert_response :success
  105     assert_select 'option', :text => 'Inactive Activity', :count => 0
  106   end
  107 
  108   def test_new_should_show_user_select_if_user_has_permission
  109     Role.find_by_name('Manager').add_permission! :log_time_for_other_users
  110     @request.session[:user_id] = 2
  111 
  112     get :new, :params => {:project_id => 1}
  113     assert_response :success
  114     assert_select 'select[name=?]', 'time_entry[user_id]' do
  115       assert_select 'option', 3
  116       assert_select 'option[value=?]', '2', 2
  117       assert_select 'option[value=?]', '3', 1
  118       # locked members should not be available
  119       assert_select 'option[value=?]', '4', 0
  120     end
  121   end
  122 
  123   def test_new_user_select_should_include_current_user_if_is_logged
  124     @request.session[:user_id] = 1
  125 
  126     get :new, :params => {:project_id => 1}
  127     assert_response :success
  128     assert_select 'select[name=?]', 'time_entry[user_id]' do
  129       assert_select 'option[value=?]', '1', :text => '<< me >>'
  130       assert_select 'option[value=?]', '1', :text => 'Redmine Admin'
  131     end
  132   end
  133 
  134   def test_new_should_not_show_user_select_if_user_does_not_have_permission
  135     @request.session[:user_id] = 2
  136 
  137     get :new, :params => {:project_id => 1}
  138     assert_response :success
  139     assert_select 'select[name=?]', 'time_entry[user_id]', 0
  140   end
  141 
  142   def test_post_new_as_js_should_update_activity_options
  143     @request.session[:user_id] = 3
  144     post :new, :params => {:time_entry => {:project_id => 1}, :format => 'js'}
  145     assert_response :success
  146     assert_include '#time_entry_activity_id', response.body
  147   end
  148 
  149   def test_get_edit_existing_time
  150     @request.session[:user_id] = 2
  151     get :edit, :params => {:id => 2, :project_id => nil}
  152     assert_response :success
  153 
  154     assert_select 'form[action=?]', '/time_entries/2'
  155 
  156     # Time entry user should be shown as text
  157     # for user without permission to log time for other users
  158     assert_select 'label[for=?]', 'time_entry_user_id', 1
  159     assert_select 'a.user.active', :text => 'Redmine Admin'
  160   end
  161 
  162   def test_get_edit_with_an_existing_time_entry_with_inactive_activity
  163     te = TimeEntry.find(1)
  164     te.activity = TimeEntryActivity.find_by_name("Inactive Activity")
  165     te.save!(:validate => false)
  166 
  167     @request.session[:user_id] = 1
  168     get :edit, :params => {:project_id => 1, :id => 1}
  169     assert_response :success
  170 
  171     # Blank option since nothing is pre-selected
  172     assert_select 'option', :text => '--- Please select ---'
  173   end
  174 
  175   def test_get_edit_should_show_projects_select
  176     @request.session[:user_id] = 2
  177     get :edit, :params => {:id => 2, :project_id => nil}
  178     assert_response :success
  179 
  180     assert_select 'select[name=?]', 'time_entry[project_id]'
  181   end
  182 
  183   def test_get_edit_should_validate_back_url
  184     @request.session[:user_id] = 2
  185 
  186     get :edit, :params => {:id => 2, :project_id => nil, :back_url => '/valid'}
  187     assert_response :success
  188     assert_select 'a[href=?]', '/valid', {:text => 'Cancel'}
  189 
  190     get :edit, :params => {:id => 2, :project_id => nil, :back_url => 'invalid'}
  191     assert_response :success
  192     assert_select 'a[href=?]', 'invalid', {:text => 'Cancel', :count => 0}
  193     assert_select 'a[href=?]', '/projects/ecookbook/time_entries', {:text => 'Cancel'}
  194   end
  195 
  196   def test_get_edit_with_an_existing_time_entry_with_locked_user
  197     user = User.find(3)
  198     entry = TimeEntry.generate!(:user_id => user.id, :comments => "Time entry on a future locked user")
  199     entry.save!
  200 
  201     user.status = User::STATUS_LOCKED
  202     user.save!
  203     Role.find_by_name('Manager').add_permission! :log_time_for_other_users
  204     @request.session[:user_id] = 2
  205 
  206     get :edit, :params => {
  207       :id => entry.id
  208     }
  209 
  210     assert_response :success
  211 
  212     assert_select 'select[name=?]', 'time_entry[user_id]' do
  213       # User with id 3 should be selected even if it's locked
  214       assert_select 'option[value="3"][selected=selected]'
  215     end
  216   end
  217 
  218   def test_get_edit_for_other_user
  219     Role.find_by_name('Manager').add_permission! :log_time_for_other_users
  220     @request.session[:user_id] = 2
  221 
  222     get :edit, :params => {
  223       :id => 1
  224     }
  225 
  226     assert_response :success
  227 
  228     assert_select 'select[name=?]', 'time_entry[user_id]' do
  229       assert_select 'option[value="2"][selected=selected]'
  230     end
  231   end
  232 
  233   def test_post_create
  234     @request.session[:user_id] = 3
  235     assert_difference 'TimeEntry.count' do
  236       post :create, :params => {
  237         :project_id => 1,
  238         :time_entry => {:comments => 'Some work on TimelogControllerTest',
  239           # Not the default activity
  240           :activity_id => '11',
  241           :spent_on => '2008-03-14',
  242           :issue_id => '1',
  243           :hours => '7.3'
  244         }
  245       }
  246       assert_redirected_to '/projects/ecookbook/time_entries'
  247     end
  248 
  249     t = TimeEntry.order('id DESC').first
  250     assert_not_nil t
  251     assert_equal 'Some work on TimelogControllerTest', t.comments
  252     assert_equal 1, t.project_id
  253     assert_equal 1, t.issue_id
  254     assert_equal 11, t.activity_id
  255     assert_equal 7.3, t.hours
  256     assert_equal 3, t.user_id
  257   end
  258 
  259   def test_post_create_with_blank_issue
  260     @request.session[:user_id] = 3
  261     assert_difference 'TimeEntry.count' do
  262       post :create, :params => {
  263         :project_id => 1,
  264         :time_entry => {
  265           :comments => 'Some work on TimelogControllerTest',
  266           # Not the default activity
  267           :activity_id => '11',
  268           :issue_id => '',
  269           :spent_on => '2008-03-14',
  270           :hours => '7.3'
  271         }
  272       }
  273       assert_redirected_to '/projects/ecookbook/time_entries'
  274     end
  275 
  276     t = TimeEntry.order('id DESC').first
  277     assert_not_nil t
  278     assert_equal 'Some work on TimelogControllerTest', t.comments
  279     assert_equal 1, t.project_id
  280     assert_nil t.issue_id
  281     assert_equal 11, t.activity_id
  282     assert_equal 7.3, t.hours
  283     assert_equal 3, t.user_id
  284   end
  285 
  286   def test_create_on_project_with_time_tracking_disabled_should_fail
  287     Project.find(1).disable_module! :time_tracking
  288 
  289     @request.session[:user_id] = 2
  290     assert_no_difference 'TimeEntry.count' do
  291       post :create, :params => {
  292         :time_entry => {
  293           :project_id => '1', :issue_id => '',
  294           :activity_id => '11', :spent_on => '2008-03-14', :hours => '7.3'
  295         }
  296       }
  297     end
  298   end
  299 
  300   def test_create_on_project_without_permission_should_fail
  301     Role.find(1).remove_permission! :log_time
  302 
  303     @request.session[:user_id] = 2
  304     assert_no_difference 'TimeEntry.count' do
  305       post :create, :params => {
  306         :time_entry => {
  307           :project_id => '1', :issue_id => '',
  308           :activity_id => '11', :spent_on => '2008-03-14', :hours => '7.3'
  309         }
  310       }
  311     end
  312   end
  313 
  314   def test_create_on_issue_in_project_with_time_tracking_disabled_should_fail
  315     Project.find(1).disable_module! :time_tracking
  316 
  317     @request.session[:user_id] = 2
  318     assert_no_difference 'TimeEntry.count' do
  319       post :create, :params => {
  320         :time_entry => {
  321           :project_id => '', :issue_id => '1',
  322           :activity_id => '11', :spent_on => '2008-03-14', :hours => '7.3'
  323         }
  324       }
  325       assert_select_error /Issue is invalid/
  326     end
  327   end
  328 
  329   def test_create_on_issue_in_project_without_permission_should_fail
  330     Role.find(1).remove_permission! :log_time
  331 
  332     @request.session[:user_id] = 2
  333     assert_no_difference 'TimeEntry.count' do
  334       post :create, :params => {
  335         :time_entry => {
  336           :project_id => '', :issue_id => '1',
  337           :activity_id => '11', :spent_on => '2008-03-14', :hours => '7.3'
  338         }
  339       }
  340       assert_select_error /Issue is invalid/
  341     end
  342   end
  343 
  344   def test_create_on_issue_that_is_not_visible_should_not_disclose_subject
  345     issue = Issue.generate!(:subject => "issue_that_is_not_visible", :is_private => true)
  346     assert !issue.visible?(User.find(3))
  347 
  348     @request.session[:user_id] = 3
  349     assert_no_difference 'TimeEntry.count' do
  350       post :create, :params => {
  351         :time_entry => {
  352           :project_id => '', :issue_id => issue.id.to_s,
  353           :activity_id => '11', :spent_on => '2008-03-14', :hours => '7.3'
  354         }
  355       }
  356     end
  357     assert_select_error /Issue is invalid/
  358     assert_select "input[name=?][value=?]", "time_entry[issue_id]", issue.id.to_s
  359     assert_select "#time_entry_issue a", 0
  360     assert !response.body.include?('issue_that_is_not_visible')
  361   end
  362 
  363   def test_create_for_other_user
  364     Role.find_by_name('Manager').add_permission! :log_time_for_other_users
  365     @request.session[:user_id] = 2
  366 
  367     post :create, :params => {
  368       :project_id => 1,
  369       :time_entry => {:comments => 'Some work on TimelogControllerTest',
  370         # Not the default activity
  371         :activity_id => '11',
  372         :spent_on => '2008-03-14',
  373         :issue_id => '1',
  374         :hours => '7.3',
  375         :user_id => '3'
  376       }
  377     }
  378 
  379     assert_redirected_to '/projects/ecookbook/time_entries'
  380 
  381     t = TimeEntry.last
  382     assert_equal 3, t.user_id
  383     assert_equal 2, t.author_id
  384   end
  385 
  386   def test_create_for_other_user_should_fail_without_permission
  387     Role.find_by_name('Manager').remove_permission! :log_time_for_other_users
  388     @request.session[:user_id] = 2
  389 
  390     post :create, :params => {
  391       :project_id => 1,
  392       :time_entry => {:comments => 'Some work on TimelogControllerTest',
  393         # Not the default activity
  394         :activity_id => '11',
  395         :spent_on => '2008-03-14',
  396         :issue_id => '1',
  397         :hours => '7.3',
  398         :user_id => '3'
  399       }
  400     }
  401 
  402     assert_response :success
  403     assert_select_error /User is invalid/
  404   end
  405 
  406   def test_create_and_continue_at_project_level
  407     @request.session[:user_id] = 2
  408     assert_difference 'TimeEntry.count' do
  409       post :create, :params => {
  410         :time_entry => {
  411           :project_id => '1',
  412           :activity_id => '11',
  413           :issue_id => '',
  414           :spent_on => '2008-03-14',
  415           :hours => '7.3'
  416         },
  417         :continue => '1'
  418       }
  419       assert_redirected_to '/time_entries/new?time_entry%5Bactivity_id%5D=11&time_entry%5Bissue_id%5D=&time_entry%5Bproject_id%5D=1&time_entry%5Bspent_on%5D=2008-03-14'
  420     end
  421   end
  422 
  423   def test_create_and_continue_at_issue_level
  424     @request.session[:user_id] = 2
  425     assert_difference 'TimeEntry.count' do
  426       post :create, :params => {
  427         :time_entry => {
  428           :project_id => '',
  429           :activity_id => '11',
  430           :issue_id => '1',
  431           :spent_on => '2008-03-14',
  432           :hours => '7.3'
  433         },
  434         :continue => '1'
  435       }
  436       assert_redirected_to '/time_entries/new?time_entry%5Bactivity_id%5D=11&time_entry%5Bissue_id%5D=1&time_entry%5Bproject_id%5D=&time_entry%5Bspent_on%5D=2008-03-14'
  437     end
  438   end
  439 
  440   def test_create_and_continue_with_project_id
  441     @request.session[:user_id] = 2
  442     assert_difference 'TimeEntry.count' do
  443       post :create, :params => {
  444         :project_id => 1,
  445         :time_entry => {
  446           :activity_id => '11',
  447           :issue_id => '',
  448           :spent_on => '2008-03-14',
  449           :hours => '7.3'
  450         },
  451         :continue => '1'
  452       }
  453       assert_redirected_to '/projects/ecookbook/time_entries/new?time_entry%5Bactivity_id%5D=11&time_entry%5Bissue_id%5D=&time_entry%5Bproject_id%5D=&time_entry%5Bspent_on%5D=2008-03-14'
  454     end
  455   end
  456 
  457   def test_create_and_continue_with_issue_id
  458     @request.session[:user_id] = 2
  459     assert_difference 'TimeEntry.count' do
  460       post :create, :params => {
  461         :issue_id => 1,
  462         :time_entry => {
  463           :activity_id => '11',
  464           :issue_id => '1',
  465           :spent_on => '2008-03-14',
  466           :hours => '7.3'
  467         },
  468         :continue => '1'
  469       }
  470       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=&time_entry%5Bspent_on%5D=2008-03-14'
  471     end
  472   end
  473 
  474   def test_create_without_log_time_permission_should_be_denied
  475     @request.session[:user_id] = 2
  476     Role.find_by_name('Manager').remove_permission! :log_time
  477     post :create, :params => {
  478       :project_id => 1,
  479       :time_entry => {
  480         :activity_id => '11',
  481         :issue_id => '',
  482         :spent_on => '2008-03-14',
  483         :hours => '7.3'
  484       }
  485     }
  486     assert_response 403
  487   end
  488 
  489   def test_create_without_project_and_issue_should_fail
  490     @request.session[:user_id] = 2
  491     post :create, :params => {:time_entry => {:issue_id => ''}}
  492 
  493     assert_response :success
  494     assert_select_error /Project cannot be blank/
  495   end
  496 
  497   def test_create_with_failure
  498     @request.session[:user_id] = 2
  499     post :create, :params => {
  500       :project_id => 1,
  501       :time_entry => {
  502         :activity_id => '',
  503         :issue_id => '',
  504         :spent_on => '2008-03-14',
  505         :hours => '7.3'
  506       }
  507     }
  508     assert_response :success
  509   end
  510 
  511   def test_create_without_project
  512     @request.session[:user_id] = 2
  513     assert_difference 'TimeEntry.count' do
  514       post :create, :params => {
  515         :time_entry => {
  516           :project_id => '1',
  517           :activity_id => '11',
  518           :issue_id => '',
  519           :spent_on => '2008-03-14',
  520           :hours => '7.3'
  521         }
  522       }
  523     end
  524 
  525     assert_redirected_to '/projects/ecookbook/time_entries'
  526     time_entry = TimeEntry.order('id DESC').first
  527     assert_equal 1, time_entry.project_id
  528   end
  529 
  530   def test_create_without_project_should_fail_with_issue_not_inside_project
  531     @request.session[:user_id] = 2
  532     assert_no_difference 'TimeEntry.count' do
  533       post :create, :params => {
  534         :time_entry => {
  535           :project_id => '1',
  536           :activity_id => '11',
  537           :issue_id => '5',
  538           :spent_on => '2008-03-14',
  539           :hours => '7.3'
  540         }
  541       }
  542     end
  543 
  544     assert_response :success
  545     assert_select_error /Issue is invalid/
  546   end
  547 
  548   def test_create_without_project_should_deny_without_permission
  549     @request.session[:user_id] = 2
  550     Project.find(3).disable_module!(:time_tracking)
  551 
  552     assert_no_difference 'TimeEntry.count' do
  553       post :create, :params => {
  554         :time_entry => {
  555           :project_id => '3',
  556           :activity_id => '11',
  557           :issue_id => '',
  558           :spent_on => '2008-03-14',
  559           :hours => '7.3'
  560         }
  561       }
  562     end
  563 
  564     assert_response 403
  565   end
  566 
  567   def test_create_without_project_with_failure
  568     @request.session[:user_id] = 2
  569     assert_no_difference 'TimeEntry.count' do
  570       post :create, :params => {
  571         :time_entry => {
  572           :project_id => '1',
  573           :activity_id => '11',
  574           :issue_id => '',
  575           :spent_on => '2008-03-14',
  576           :hours => ''
  577         }
  578       }
  579     end
  580 
  581     assert_response :success
  582     assert_select 'select[name=?]', 'time_entry[project_id]' do
  583       assert_select 'option[value="1"][selected=selected]'
  584     end
  585   end
  586 
  587   def test_update
  588     entry = TimeEntry.find(1)
  589     assert_equal 1, entry.issue_id
  590     assert_equal 2, entry.user_id
  591 
  592     @request.session[:user_id] = 1
  593     put :update, :params => {
  594       :id => 1,
  595       :time_entry => {
  596         :issue_id => '2',
  597         :hours => '8'
  598       }
  599     }
  600     assert_redirected_to :action => 'index', :project_id => 'ecookbook'
  601     entry.reload
  602 
  603     assert_equal 8, entry.hours
  604     assert_equal 2, entry.issue_id
  605     assert_equal 2, entry.user_id
  606   end
  607 
  608   def test_update_should_allow_to_change_issue_to_another_project
  609     entry = TimeEntry.generate!(:issue_id => 1)
  610 
  611     @request.session[:user_id] = 1
  612     put :update, :params => {
  613       :id => entry.id,
  614       :time_entry => {
  615         :issue_id => '5'
  616       }
  617     }
  618     assert_response 302
  619     entry.reload
  620 
  621     assert_equal 5, entry.issue_id
  622     assert_equal 3, entry.project_id
  623   end
  624 
  625   def test_update_should_not_allow_to_change_issue_to_an_invalid_project
  626     entry = TimeEntry.generate!(:issue_id => 1)
  627     Project.find(3).disable_module!(:time_tracking)
  628 
  629     @request.session[:user_id] = 1
  630     put :update, :params => {
  631       :id => entry.id,
  632       :time_entry => {
  633         :issue_id => '5'
  634       }
  635     }
  636     assert_response :success
  637     assert_select_error /Issue is invalid/
  638   end
  639 
  640   def test_update_should_allow_to_change_project
  641     entry = TimeEntry.generate!(:project_id => 1)
  642 
  643     @request.session[:user_id] = 1
  644     put :update, :params => {
  645       :id => entry.id,
  646       :time_entry => {
  647         :project_id => '2'
  648       }
  649     }
  650     assert_response 302
  651     entry.reload
  652 
  653     assert_equal 2, entry.project_id
  654   end
  655 
  656   def test_update_should_fail_with_issue_from_another_project
  657     entry = TimeEntry.generate!(:project_id => 1, :issue_id => 1)
  658 
  659     @request.session[:user_id] = 1
  660     put :update, :params => {
  661       :id => entry.id,
  662       :time_entry => {
  663         :project_id => '2'
  664       }
  665     }
  666 
  667     assert_response :success
  668     assert_select_error /Issue is invalid/
  669   end
  670 
  671   def test_update_should_fail_when_changing_user_without_permission
  672     Role.find_by_name('Manager').remove_permission! :log_time_for_other_users
  673     @request.session[:user_id] = 2
  674 
  675     put :update, :params => {
  676       :id => 3,
  677       :time_entry => {
  678         :user_id => '3'
  679       }
  680     }
  681 
  682     assert_response :success
  683     assert_select_error /User is invalid/
  684   end
  685 
  686   def test_update_should_allow_updating_existing_entry_logged_on_a_locked_user
  687     entry = TimeEntry.generate!(:user_id => 2, :hours => 4, :comments => "Time entry on a future locked user")
  688     Role.find_by_name('Manager').add_permission! :log_time_for_other_users
  689     @request.session[:user_id] = 2
  690 
  691     put :update, :params => {
  692       :id => entry.id,
  693       :time_entry => {
  694         :hours => '6'
  695       }
  696     }
  697 
  698     assert_response :redirect
  699 
  700     entry.reload
  701     # Ensure user didn't change
  702     assert_equal 2, entry.user_id
  703     assert_equal 6.0, entry.hours
  704   end
  705 
  706   def test_get_bulk_edit
  707     @request.session[:user_id] = 2
  708 
  709     get :bulk_edit, :params => {:ids => [1, 2]}
  710     assert_response :success
  711 
  712     assert_select 'ul#bulk-selection' do
  713       assert_select 'li', 2
  714       assert_select 'li a', :text => '03/23/2007 - eCookbook: 4.25 hours (John Smith)'
  715     end
  716 
  717     assert_select 'form#bulk_edit_form[action=?]', '/time_entries/bulk_update' do
  718       assert_select 'select[name=?]', 'time_entry[project_id]'
  719 
  720       # Clear issue checkbox
  721       assert_select 'input[name=?][value=?]', 'time_entry[issue_id]', 'none'
  722 
  723       # System wide custom field
  724       assert_select 'select[name=?]', 'time_entry[custom_field_values][10]'
  725 
  726       # Activities
  727       assert_select 'select[name=?]', 'time_entry[activity_id]' do
  728         assert_select 'option[value=""]', :text => '(No change)'
  729         assert_select 'option[value="9"]', :text => 'Design'
  730       end
  731     end
  732   end
  733 
  734   def test_get_bulk_edit_on_different_projects
  735     @request.session[:user_id] = 2
  736 
  737     get :bulk_edit, :params => {:ids => [1, 2, 6]}
  738     assert_response :success
  739   end
  740 
  741   def test_get_bulk_edit_on_different_projects_should_propose_only_common_activites
  742     project = Project.find(3)
  743     TimeEntryActivity.create!(:name => 'QA', :project => project, :parent => TimeEntryActivity.find_by_name('QA'), :active => false)
  744     @request.session[:user_id] = 1
  745 
  746     get :bulk_edit, :params => {:ids => [1, 2, 4]}
  747     assert_response :success
  748     assert_select 'select[id=?]', 'time_entry_activity_id' do
  749       assert_select 'option', 3
  750       assert_select 'option[value=?]', '11', 0, :text => 'QA'
  751     end
  752   end
  753 
  754   def test_get_bulk_edit_on_same_project_should_propose_project_activities
  755     project = Project.find(1)
  756     override_activity = TimeEntryActivity.create!({:name => "QA override", :parent => TimeEntryActivity.find_by_name("QA"), :project => project})
  757 
  758     @request.session[:user_id] = 1
  759 
  760     get :bulk_edit, :params => {:ids => [1, 2]}
  761     assert_response :success
  762 
  763     assert_select 'select[id=?]', 'time_entry_activity_id' do
  764       assert_select 'option', 4
  765       assert_select 'option[value=?]', override_activity.id.to_s, :text => 'QA override'
  766     end
  767   end
  768 
  769   def test_bulk_edit_with_edit_own_time_entries_permission
  770     @request.session[:user_id] = 2
  771     Role.find_by_name('Manager').remove_permission! :edit_time_entries
  772     Role.find_by_name('Manager').add_permission! :edit_own_time_entries
  773     ids = (0..1).map {TimeEntry.generate!(:user => User.find(2)).id}
  774 
  775     get :bulk_edit, :params => {:ids => ids}
  776     assert_response :success
  777   end
  778 
  779   def test_bulk_update
  780     @request.session[:user_id] = 2
  781     # update time entry activity
  782     post :bulk_update, :params => {:ids => [1, 2], :time_entry => { :activity_id => 9}}
  783 
  784     assert_response 302
  785     # check that the issues were updated
  786     assert_equal [9, 9], TimeEntry.where(:id => [1, 2]).collect {|i| i.activity_id}
  787   end
  788 
  789   def test_bulk_update_with_failure
  790     @request.session[:user_id] = 2
  791     post :bulk_update, :params => {:ids => [1, 2], :time_entry => { :hours => 'A'}}
  792 
  793     assert_response :success
  794     assert_select_error /Failed to save 2 time entrie/
  795   end
  796 
  797   def test_bulk_update_on_different_projects
  798     @request.session[:user_id] = 2
  799     # makes user a manager on the other project
  800     Member.create!(:user_id => 2, :project_id => 3, :role_ids => [1])
  801 
  802     # update time entry activity
  803     post :bulk_update, :params => {:ids => [1, 2, 4], :time_entry => { :activity_id => 9 }}
  804 
  805     assert_response 302
  806     # check that the issues were updated
  807     assert_equal [9, 9, 9], TimeEntry.where(:id => [1, 2, 4]).collect {|i| i.activity_id}
  808   end
  809 
  810   def test_bulk_update_on_different_projects_without_rights
  811     @request.session[:user_id] = 3
  812     user = User.find(3)
  813     action = { :controller => "timelog", :action => "bulk_update" }
  814     assert user.allowed_to?(action, TimeEntry.find(1).project)
  815     assert ! user.allowed_to?(action, TimeEntry.find(5).project)
  816 
  817     post :bulk_update, :params => {:ids => [1, 5], :time_entry => { :activity_id => 9 }}
  818     assert_response 403
  819   end
  820 
  821   def test_bulk_update_with_edit_own_time_entries_permission
  822     @request.session[:user_id] = 2
  823     Role.find_by_name('Manager').remove_permission! :edit_time_entries
  824     Role.find_by_name('Manager').add_permission! :edit_own_time_entries
  825     ids = (0..1).map {TimeEntry.generate!(:user => User.find(2)).id}
  826 
  827     post :bulk_update, :params => {:ids => ids, :time_entry => { :activity_id => 9 }}
  828     assert_response 302
  829   end
  830 
  831   def test_bulk_update_with_edit_own_time_entries_permissions_should_be_denied_for_time_entries_of_other_user
  832     @request.session[:user_id] = 2
  833     Role.find_by_name('Manager').remove_permission! :edit_time_entries
  834     Role.find_by_name('Manager').add_permission! :edit_own_time_entries
  835 
  836     post :bulk_update, :params => {:ids => [1, 2], :time_entry => { :activity_id => 9 }}
  837     assert_response 403
  838   end
  839 
  840   def test_bulk_update_custom_field
  841     @request.session[:user_id] = 2
  842     post :bulk_update, :params => {:ids => [1, 2], :time_entry => { :custom_field_values => {'10' => '0'} }}
  843 
  844     assert_response 302
  845     assert_equal ["0", "0"], TimeEntry.where(:id => [1, 2]).collect {|i| i.custom_value_for(10).value}
  846   end
  847 
  848   def test_bulk_update_clear_custom_field
  849     field = TimeEntryCustomField.generate!(:field_format => 'string')
  850     @request.session[:user_id] = 2
  851     post :bulk_update, :params => {:ids => [1, 2], :time_entry => { :custom_field_values => {field.id.to_s => '__none__'} }}
  852 
  853     assert_response 302
  854     assert_equal ["", ""], TimeEntry.where(:id => [1, 2]).collect {|i| i.custom_value_for(field).value}
  855   end
  856 
  857   def test_post_bulk_update_should_redirect_back_using_the_back_url_parameter
  858     @request.session[:user_id] = 2
  859     post :bulk_update, :params => {:ids => [1,2], :back_url => '/time_entries'}
  860 
  861     assert_response :redirect
  862     assert_redirected_to '/time_entries'
  863   end
  864 
  865   def test_post_bulk_update_should_not_redirect_back_using_the_back_url_parameter_off_the_host
  866     @request.session[:user_id] = 2
  867     post :bulk_update, :params => {:ids => [1,2], :back_url => 'http://google.com'}
  868 
  869     assert_response :redirect
  870     assert_redirected_to :controller => 'timelog', :action => 'index', :project_id => Project.find(1).identifier
  871   end
  872 
  873   def test_post_bulk_update_without_edit_permission_should_be_denied
  874     @request.session[:user_id] = 2
  875     Role.find_by_name('Manager').remove_permission! :edit_time_entries
  876 
  877     post :bulk_update, :params => {:ids => [1,2]}
  878     assert_response 403
  879   end
  880 
  881   def test_destroy
  882     @request.session[:user_id] = 2
  883 
  884     delete :destroy, :params => {:id => 1}
  885     assert_redirected_to :action => 'index', :project_id => 'ecookbook'
  886     assert_equal I18n.t(:notice_successful_delete), flash[:notice]
  887     assert_nil TimeEntry.find_by_id(1)
  888   end
  889 
  890   def test_destroy_should_fail
  891     # simulate that this fails (e.g. due to a plugin), see #5700
  892     TimeEntry.any_instance.expects(:destroy).returns(false)
  893     @request.session[:user_id] = 2
  894 
  895     delete :destroy, :params => {:id => 1}
  896     assert_redirected_to :action => 'index', :project_id => 'ecookbook'
  897     assert_equal I18n.t(:notice_unable_delete_time_entry), flash[:error]
  898     assert_not_nil TimeEntry.find_by_id(1)
  899   end
  900 
  901   def test_destroy_should_redirect_to_referer
  902     referer = 'http://test.host/time_entries?utf8=✓&set_filter=1&&f%5B%5D=user_id&op%5Buser_id%5D=%3D&v%5Buser_id%5D%5B%5D=me'
  903     @request.env["HTTP_REFERER"] = referer
  904     @request.session[:user_id] = 2
  905 
  906     delete :destroy, :params => {:id => 1}
  907     assert_redirected_to referer
  908   end
  909 
  910   def test_index_all_projects
  911     get :index
  912     assert_response :success
  913 
  914     assert_select '.total-for-hours', :text => 'Hours: 162.90'
  915     assert_select 'form#query_form[action=?]', '/time_entries'
  916 
  917     assert_equal ['Project', 'Date', 'User', 'Activity', 'Issue', 'Comment', 'Hours'], columns_in_list
  918     assert_select '.query-totals>span', 1
  919   end
  920 
  921   def test_index_with_default_query_setting
  922     with_settings :time_entry_list_defaults => {'column_names' => %w(spent_on issue user hours), 'totalable_names' => []} do
  923       get :index
  924       assert_response :success
  925     end
  926 
  927     assert_select 'table.time-entries thead' do
  928       assert_select 'th.project'
  929       assert_select 'th.spent_on'
  930       assert_select 'th.issue'
  931       assert_select 'th.user'
  932       assert_select 'th.hours'
  933     end
  934     assert_select 'table.time-entries tbody' do
  935       assert_select 'td.project'
  936       assert_select 'td.spent_on'
  937       assert_select 'td.issue'
  938       assert_select 'td.user'
  939       assert_select 'td.hours'
  940     end
  941     assert_equal ['Project', 'Date', 'Issue', 'User', 'Hours'], columns_in_list
  942   end
  943 
  944   def test_index_with_default_query_setting_using_custom_field
  945     field = TimeEntryCustomField.create!(:name => 'Foo', :field_format => 'int')
  946 
  947     with_settings :time_entry_list_defaults => {
  948         'column_names' => ["spent_on", "user", "hours", "cf_#{field.id}"],
  949         'totalable_names' => ["hours", "cf_#{field.id}"]
  950       } do
  951       get :index
  952       assert_response :success
  953     end
  954 
  955     assert_equal ['Project', 'Date', 'User', 'Hours', 'Foo'], columns_in_list
  956 
  957     assert_select '.total-for-hours'
  958     assert_select ".total-for-cf-#{field.id}"
  959     assert_select '.query-totals>span', 2
  960   end
  961 
  962   def test_index_all_projects_should_show_log_time_link
  963     @request.session[:user_id] = 2
  964     get :index
  965     assert_response :success
  966 
  967     assert_select 'a[href=?]', '/time_entries/new', :text => /Log time/
  968   end
  969 
  970   def test_index_my_spent_time
  971     @request.session[:user_id] = 2
  972     get :index, :params => {:user_id => 'me', :c => ['user']}
  973     assert_response :success
  974 
  975     users = css_select('table.time-entries tbody td.user').map(&:text).uniq
  976     assert_equal ["John Smith"], users
  977   end
  978 
  979   def test_index_at_project_level
  980     @request.session[:user_id] = 2
  981 
  982     get :index, :params => {:project_id => 'ecookbook', :c => ['project']}
  983     assert_response :success
  984 
  985     assert_select 'tr.time-entry', 4
  986 
  987     # project and subproject
  988     projects = css_select('table.time-entries tbody td.project').map(&:text).uniq.sort
  989     assert_equal ["eCookbook", "eCookbook Subproject 1"], projects
  990 
  991     assert_select '.total-for-hours', :text => 'Hours: 162.90'
  992     assert_select 'form#query_form[action=?]', '/projects/ecookbook/time_entries'
  993 
  994     # 'Log time' shoudl link to log time on the filtered issue
  995     assert_select 'a[href=?]', "/projects/ecookbook/time_entries/new"
  996   end
  997 
  998   def test_index_with_display_subprojects_issues_to_false_should_not_include_subproject_entries
  999     entry = TimeEntry.generate!(:project => Project.find(3))
 1000 
 1001     with_settings :display_subprojects_issues => '0' do
 1002       get :index, :params => {:project_id => 'ecookbook', :c => ['project']}
 1003       assert_response :success
 1004 
 1005       projects = css_select('table.time-entries tbody td.project').map(&:text).uniq.sort
 1006       assert_equal ["eCookbook"], projects
 1007     end
 1008   end
 1009 
 1010   def test_index_with_display_subprojects_issues_to_false_and_subproject_filter_should_include_subproject_entries
 1011     entry = TimeEntry.generate!(:project => Project.find(3))
 1012 
 1013     with_settings :display_subprojects_issues => '0' do
 1014       get :index, :params => {:project_id => 'ecookbook', :c => ['project'], :subproject_id => 3}
 1015       assert_response :success
 1016 
 1017       projects = css_select('table.time-entries tbody td.project').map(&:text).uniq.sort
 1018       assert_equal ["eCookbook", "eCookbook Subproject 1"], projects
 1019     end
 1020   end
 1021 
 1022   def test_index_at_project_level_with_issue_id_short_filter
 1023     issue = Issue.generate!(:project_id => 1)
 1024     TimeEntry.generate!(:issue => issue, :hours => 4)
 1025     TimeEntry.generate!(:issue => issue, :hours => 3)
 1026     @request.session[:user_id] = 2
 1027 
 1028     get :index, :params => {:project_id => 'ecookbook', :issue_id => issue.id.to_s, :set_filter => 1}
 1029     assert_select '.total-for-hours', :text => 'Hours: 7.00'
 1030 
 1031     # 'Log time' shoudl link to log time on the filtered issue
 1032     assert_select 'a[href=?]', "/issues/#{issue.id}/time_entries/new"
 1033   end
 1034 
 1035   def test_index_at_project_level_with_issue_fixed_version_id_short_filter
 1036     version = Version.generate!(:project_id => 1)
 1037     issue = Issue.generate!(:project_id => 1, :fixed_version => version)
 1038     TimeEntry.generate!(:issue => issue, :hours => 2)
 1039     TimeEntry.generate!(:issue => issue, :hours => 3)
 1040     @request.session[:user_id] = 2
 1041 
 1042     get :index, :params => {:project_id => 'ecookbook', :"issue.fixed_version_id" => version.id.to_s, :set_filter => 1}
 1043     assert_select '.total-for-hours', :text => 'Hours: 5.00'
 1044   end
 1045 
 1046   def test_index_at_project_level_with_multiple_issue_fixed_version_ids
 1047     version = Version.generate!(:project_id => 1)
 1048     version2 = Version.generate!(:project_id => 1)
 1049     issue = Issue.generate!(:project_id => 1, :fixed_version => version)
 1050     issue2 = Issue.generate!(:project_id => 1, :fixed_version => version2)
 1051     TimeEntry.generate!(:issue => issue, :hours => 2)
 1052     TimeEntry.generate!(:issue => issue2, :hours => 3)
 1053     @request.session[:user_id] = 2
 1054 
 1055     get :index, :params => {
 1056       :project_id => 'ecookbook',
 1057       :f => ['issue.fixed_version_id'],
 1058       :op => {'issue.fixed_version_id' => '='},
 1059       :v => {'issue.fixed_version_id' => [version.id.to_s,version2.id.to_s]}
 1060     }
 1061     assert_response :success
 1062 
 1063     assert_select 'tr.time-entry', 2
 1064     assert_select '.total-for-hours', :text => 'Hours: 5.00'
 1065   end
 1066 
 1067   def test_index_at_project_level_with_date_range
 1068     get :index, :params => {
 1069       :project_id => 'ecookbook',
 1070       :f => ['spent_on'],
 1071       :op => {'spent_on' => '><'},
 1072       :v => {'spent_on' => ['2007-03-20', '2007-04-30']}
 1073     }
 1074     assert_response :success
 1075 
 1076     assert_select 'tr.time-entry', 3
 1077     assert_select '.total-for-hours', :text => 'Hours: 12.90'
 1078     assert_select 'form#query_form[action=?]', '/projects/ecookbook/time_entries'
 1079   end
 1080 
 1081   def test_index_at_project_level_with_date_range_using_from_and_to_params
 1082     get :index, :params => {
 1083       :project_id => 'ecookbook',
 1084       :from => '2007-03-20',
 1085       :to => '2007-04-30'
 1086     }
 1087     assert_response :success
 1088 
 1089     assert_select 'tr.time-entry', 3
 1090     assert_select '.total-for-hours', :text => 'Hours: 12.90'
 1091     assert_select 'form#query_form[action=?]', '/projects/ecookbook/time_entries'
 1092   end
 1093 
 1094   def test_index_at_project_level_with_period
 1095     get :index, :params => {
 1096       :project_id => 'ecookbook',
 1097       :f => ['spent_on'],
 1098       :op => {'spent_on' => '>t-'},
 1099       :v => {'spent_on' => ['7']}
 1100     }
 1101     assert_response :success
 1102 
 1103     assert_select 'form#query_form[action=?]', '/projects/ecookbook/time_entries'
 1104   end
 1105 
 1106   def test_index_should_sort_by_spent_on_and_created_on
 1107     t1 = TimeEntry.create!(:author => User.find(1), :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)
 1108     t2 = TimeEntry.create!(:author => User.find(1), :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)
 1109     t3 = TimeEntry.create!(:author => User.find(1), :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)
 1110 
 1111     get :index, :params => {
 1112       :project_id => 1,
 1113       :f => ['spent_on'],
 1114       :op => {'spent_on' => '><'},
 1115       :v => {'spent_on' => ['2012-06-15', '2012-06-16']}
 1116     }
 1117     assert_response :success
 1118     assert_equal [t2, t1, t3].map(&:id).map(&:to_s), css_select('input[name="ids[]"]').map {|e| e.attr('value')}
 1119 
 1120     get :index, :params => {
 1121       :project_id => 1,
 1122       :f => ['spent_on'],
 1123       :op => {'spent_on' => '><'},
 1124       :v => {'spent_on' => ['2012-06-15', '2012-06-16']},
 1125       :sort => 'spent_on'
 1126     }
 1127     assert_response :success
 1128     assert_equal [t3, t1, t2].map(&:id).map(&:to_s), css_select('input[name="ids[]"]').map {|e| e.attr('value')}
 1129   end
 1130 
 1131   def test_index_with_activity_filter
 1132     activity = TimeEntryActivity.create!(:name => 'Activity')
 1133     entry = TimeEntry.generate!(:issue_id => 1, :hours => 4.5, :activity => activity)
 1134 
 1135     get :index, :params => {
 1136       :f => ['activity_id'],
 1137       :op => {'activity_id' => '='},
 1138       :v => {'activity_id' => [activity.id.to_s]}
 1139     }
 1140     assert_response :success
 1141     assert_select "tr#time-entry-#{entry.id}"
 1142     assert_select "table.time-entries tbody tr", 1
 1143   end
 1144 
 1145   def test_index_with_issue_status_filter
 1146     Issue.where(:status_id => 4).update_all(:status_id => 2)
 1147     issue = Issue.generate!(:project_id => 1, :tracker_id => 1, :status_id => 4)
 1148     entry = TimeEntry.generate!(:issue => issue, :hours => 4.5)
 1149 
 1150     get :index, :params => {
 1151       :f => ['issue.status_id'],
 1152       :op => {'issue.status_id' => '='},
 1153       :v => {'issue.status_id' => ['4']}
 1154     }
 1155     assert_response :success
 1156     assert_equal [entry].map(&:id).map(&:to_s), css_select('input[name="ids[]"]').map {|e| e.attr('value')}
 1157   end
 1158 
 1159   def test_index_with_project_status_filter
 1160     project = Project.find(3)
 1161     project.close
 1162     project.save
 1163 
 1164     get :index, :params => {
 1165         :set_filter => 1,
 1166         :f => ['project.status'],
 1167         :op => {'project.status' => '='},
 1168         :v => {'project.status' => ['1']}
 1169     }
 1170 
 1171     assert_response :success
 1172 
 1173     time_entries = css_select('input[name="ids[]"]').map {|e| e.attr('value')}
 1174     assert_include '1', time_entries
 1175     assert_not_include '4', time_entries
 1176   end
 1177 
 1178   def test_index_with_issue_status_column
 1179     issue = Issue.generate!(:project_id => 1, :tracker_id => 1, :status_id => 4)
 1180     entry = TimeEntry.generate!(:issue => issue)
 1181 
 1182     get :index, :params => {
 1183       :c => %w(project spent_on issue comments hours issue.status)
 1184     }
 1185     assert_response :success
 1186 
 1187     assert_select 'th.issue-status'
 1188     assert_select 'td.issue-status', :text => issue.status.name
 1189   end
 1190 
 1191   def test_index_with_issue_status_sort
 1192     TimeEntry.delete_all
 1193     TimeEntry.generate!(:issue => Issue.generate!(:project_id => 1, :tracker_id => 1, :status_id => 1))
 1194     TimeEntry.generate!(:issue => Issue.generate!(:project_id => 1, :tracker_id => 1, :status_id => 5))
 1195     TimeEntry.generate!(:issue => Issue.generate!(:project_id => 1, :tracker_id => 1, :status_id => 3))
 1196     TimeEntry.generate!(:project_id => 1)
 1197 
 1198     get :index, :params => {
 1199       :c => ["hours", 'issue.status'],
 1200       :sort => 'issue.status'
 1201     }
 1202     assert_response :success
 1203 
 1204     # Make sure that values are properly sorted
 1205     values = css_select("td.issue-status").map(&:text).reject(&:blank?)
 1206     assert_equal IssueStatus.where(:id => [1, 5, 3]).sorted.pluck(:name), values
 1207   end
 1208 
 1209   def test_index_with_issue_tracker_filter
 1210     Issue.where(:tracker_id => 2).update_all(:tracker_id => 1)
 1211     issue = Issue.generate!(:project_id => 1, :tracker_id => 2)
 1212     entry = TimeEntry.generate!(:issue => issue, :hours => 4.5)
 1213 
 1214     get :index, :params => {
 1215       :f => ['issue.tracker_id'],
 1216       :op => {'issue.tracker_id' => '='},
 1217       :v => {'issue.tracker_id' => ['2']}
 1218     }
 1219     assert_response :success
 1220     assert_equal [entry].map(&:id).map(&:to_s), css_select('input[name="ids[]"]').map {|e| e.attr('value')}
 1221   end
 1222 
 1223   def test_index_with_issue_tracker_column
 1224     issue = Issue.generate!(:project_id => 1, :tracker_id => 2)
 1225     entry = TimeEntry.generate!(:issue => issue)
 1226 
 1227     get :index, :params => {
 1228       :c => %w(project spent_on issue comments hours issue.tracker)
 1229     }
 1230     assert_response :success
 1231     assert_select 'td.issue-tracker', :text => issue.tracker.name
 1232   end
 1233 
 1234   def test_index_with_issue_tracker_sort
 1235     TimeEntry.delete_all
 1236     TimeEntry.generate!(:issue => Issue.generate!(:tracker_id => 1))
 1237     TimeEntry.generate!(:issue => Issue.generate!(:tracker_id => 3))
 1238     TimeEntry.generate!(:issue => Issue.generate!(:tracker_id => 2))
 1239     TimeEntry.generate!(:project_id => 1)
 1240 
 1241     get :index, :params => {
 1242       :c => ["hours", 'issue.tracker'],
 1243       :sort => 'issue.tracker'
 1244     }
 1245     assert_response :success
 1246 
 1247     # Make sure that values are properly sorted
 1248     values = css_select("td.issue-tracker").map(&:text).reject(&:blank?)
 1249     assert_equal Tracker.where(:id => [1, 2, 3]).sorted.pluck(:name), values
 1250   end
 1251 
 1252   def test_index_with_issue_category_filter
 1253     get :index, :params => {
 1254       :project_id => 'ecookbook',
 1255       :f => ['issue.category_id'],
 1256       :op => {'issue.category_id' => '='},
 1257       :v => {'issue.category_id' => ['1']}
 1258     }
 1259     assert_response :success
 1260     assert_equal ['1', '2'], css_select('input[name="ids[]"]').map {|e| e.attr('value')}
 1261   end
 1262 
 1263   def test_index_with_issue_category_column
 1264     get :index, :params => {
 1265       :project_id => 'ecookbook',
 1266       :c => %w(project spent_on issue comments hours issue.category)
 1267     }
 1268 
 1269     assert_response :success
 1270     assert_select 'td.issue-category', :text => 'Printing'
 1271   end
 1272 
 1273   def test_index_with_issue_fixed_version_column
 1274     issue = Issue.find(1)
 1275     issue.fixed_version = Version.find(3)
 1276     issue.save!
 1277 
 1278     get :index, :params => {
 1279       :project_id => 'ecookbook',
 1280       :c => %w(project spent_on issue comments hours issue.fixed_version)
 1281     }
 1282 
 1283     assert_response :success
 1284     assert_select 'td.issue-fixed_version', :text => '2.0'
 1285   end
 1286 
 1287   def test_index_with_author_filter
 1288     get :index, :params => {
 1289       :project_id => 'ecookbook',
 1290       :f => ['author_id'],
 1291       :op => {'author_id' => '='},
 1292       :v => {'author_id' => ['2']}
 1293     }
 1294     assert_response :success
 1295     assert_equal ['1'], css_select('input[name="ids[]"]').map {|e| e.attr('value')}
 1296   end
 1297 
 1298   def test_index_with_author_column
 1299     get :index, :params => {
 1300       :project_id => 'ecookbook',
 1301       :c => %w(project spent_on issue comments hours author)
 1302     }
 1303 
 1304     assert_response :success
 1305     assert_select 'td.author', :text => 'Redmine Admin'
 1306   end
 1307 
 1308   def test_index_with_issue_category_sort
 1309     issue = Issue.find(3)
 1310     issue.category_id = 2
 1311     issue.save!
 1312 
 1313     get :index, :params => {
 1314       :c => ["hours", 'issue.category'],
 1315       :sort => 'issue.category'
 1316     }
 1317     assert_response :success
 1318 
 1319     # Make sure that values are properly sorted
 1320     values = css_select("td.issue-category").map(&:text).reject(&:blank?)
 1321     assert_equal ['Printing', 'Printing', 'Recipes'], values
 1322   end
 1323 
 1324   def test_index_with_issue_fixed_version_sort
 1325     issue = Issue.find(1)
 1326     issue.fixed_version = Version.find(3)
 1327     issue.save!
 1328 
 1329     TimeEntry.generate!(:issue => Issue.find(12))
 1330 
 1331     get :index, :params => {
 1332       :project_id => 'ecookbook',
 1333       :c => ["hours", 'issue.fixed_version'],
 1334       :sort => 'issue.fixed_version'
 1335     }
 1336 
 1337     assert_response :success
 1338     # Make sure that values are properly sorted
 1339     values = css_select("td.issue-fixed_version").map(&:text).reject(&:blank?)
 1340     assert_equal ['1.0', '2.0', '2.0'], values
 1341   end
 1342 
 1343   def test_index_with_filter_on_issue_custom_field
 1344     issue = Issue.generate!(:project_id => 1, :tracker_id => 1, :custom_field_values => {2 => 'filter_on_issue_custom_field'})
 1345     entry = TimeEntry.generate!(:issue => issue, :hours => 2.5)
 1346 
 1347     get :index, :params => {
 1348       :f => ['issue.cf_2'],
 1349       :op => {'issue.cf_2' => '='},
 1350       :v => {'issue.cf_2' => ['filter_on_issue_custom_field']}
 1351     }
 1352     assert_response :success
 1353     assert_equal [entry].map(&:id).map(&:to_s), css_select('input[name="ids[]"]').map {|e| e.attr('value')}
 1354   end
 1355 
 1356   def test_index_with_issue_custom_field_column
 1357     issue = Issue.generate!(:project_id => 1, :tracker_id => 1, :custom_field_values => {2 => 'filter_on_issue_custom_field'})
 1358     entry = TimeEntry.generate!(:issue => issue, :hours => 2.5)
 1359 
 1360     get :index, :params => {
 1361       :c => %w(project spent_on issue comments hours issue.cf_2)
 1362     }
 1363     assert_response :success
 1364     assert_select 'td.issue_cf_2', :text => 'filter_on_issue_custom_field'
 1365   end
 1366 
 1367   def test_index_with_time_entry_custom_field_column
 1368     field = TimeEntryCustomField.generate!(:field_format => 'string')
 1369     entry = TimeEntry.generate!(:hours => 2.5, :custom_field_values => {field.id => 'CF Value'})
 1370     field_name = "cf_#{field.id}"
 1371 
 1372     get :index, :params => {
 1373       :c => ["hours", field_name]
 1374     }
 1375     assert_response :success
 1376     assert_select "td.#{field_name}", :text => 'CF Value'
 1377   end
 1378 
 1379   def test_index_with_time_entry_custom_field_sorting
 1380     field = TimeEntryCustomField.generate!(:field_format => 'string', :name => 'String Field')
 1381     TimeEntry.generate!(:hours => 2.5, :custom_field_values => {field.id => 'CF Value 1'})
 1382     TimeEntry.generate!(:hours => 2.5, :custom_field_values => {field.id => 'CF Value 3'})
 1383     TimeEntry.generate!(:hours => 2.5, :custom_field_values => {field.id => 'CF Value 2'})
 1384     field_name = "cf_#{field.id}"
 1385 
 1386     get :index, :params => {
 1387       :c => ["hours", field_name],
 1388       :sort => field_name
 1389     }
 1390     assert_response :success
 1391     assert_select "th.cf_#{field.id} a.sort", :text => 'String Field'
 1392 
 1393     # Make sure that values are properly sorted
 1394     values = css_select("td.#{field_name}").map(&:text).reject(&:blank?)
 1395     assert_equal values.sort, values
 1396     assert_equal 3, values.size
 1397   end
 1398 
 1399   def test_index_with_invalid_date_filter_should_not_validate
 1400     @request.session[:user_id] = 2
 1401 
 1402     get :index, :params => {:set_filter => '1', :f => ['spent_on'], :op => {'spent_on' => '='}, :v => {'spent_on' => ['2016-09-010']}}
 1403     assert_select_error 'Date is invalid'
 1404     assert_select 'table.time-entries', 0
 1405   end
 1406 
 1407   def test_index_with_query
 1408     query = TimeEntryQuery.new(:project_id => 1, :name => 'Time Entry Query', :visibility => 2)
 1409     query.save!
 1410     @request.session[:user_id] = 2
 1411 
 1412     get :index, :params => {:project_id => 'ecookbook', :query_id => query.id}
 1413     assert_response :success
 1414     assert_select 'h2', :text => query.name
 1415     assert_select '#sidebar a.selected', :text => query.name
 1416   end
 1417 
 1418   def test_index_atom_feed
 1419     get :index, :params => {:project_id => 1, :format => 'atom'}
 1420     assert_response :success
 1421     assert_equal 'application/atom+xml', @response.content_type
 1422     assert_select 'entry > title', :text => /7\.65 hours/
 1423   end
 1424 
 1425   def test_index_at_project_level_should_include_csv_export_dialog
 1426     get :index, :params => {
 1427       :project_id => 'ecookbook',
 1428       :f => ['spent_on'],
 1429       :op => {'spent_on' => '>='},
 1430       :v => {'spent_on' => ['2007-04-01']},
 1431       :c => ['spent_on', 'user']
 1432     }
 1433     assert_response :success
 1434 
 1435     assert_select '#csv-export-options' do
 1436       assert_select 'form[action=?][method=get]', '/projects/ecookbook/time_entries.csv' do
 1437         # filter
 1438         assert_select 'input[name=?][value=?]', 'f[]', 'spent_on'
 1439         assert_select 'input[name=?][value=?]', 'op[spent_on]', '>='
 1440         assert_select 'input[name=?][value=?]', 'v[spent_on][]', '2007-04-01'
 1441         # columns
 1442         assert_select 'input[name=?][type=hidden][value=?]', 'c[]', 'spent_on'
 1443         assert_select 'input[name=?][type=hidden][value=?]', 'c[]', 'user'
 1444         assert_select 'input[name=?][type=hidden]', 'c[]', 2
 1445         assert_select 'input[name=?][value=?]', 'c[]', 'all_inline'
 1446       end
 1447     end
 1448   end
 1449 
 1450   def test_index_cross_project_should_include_csv_export_dialog
 1451     get :index
 1452     assert_response :success
 1453 
 1454     assert_select '#csv-export-options' do
 1455       assert_select 'form[action=?][method=get]', '/time_entries.csv'
 1456     end
 1457   end
 1458 
 1459   def test_index_csv_all_projects
 1460     with_settings :date_format => '%m/%d/%Y' do
 1461       get :index, :params => {:format => 'csv'}
 1462       assert_response :success
 1463       assert_equal 'text/csv', response.media_type
 1464     end
 1465   end
 1466 
 1467   def test_index_csv
 1468     with_settings :date_format => '%m/%d/%Y' do
 1469       get :index, :params => {:project_id => 1, :format => 'csv'}
 1470       assert_response :success
 1471       assert_equal 'text/csv', response.media_type
 1472     end
 1473   end
 1474 
 1475   def test_index_csv_should_fill_issue_column_with_tracker_id_and_subject
 1476     issue = Issue.find(1)
 1477     entry = TimeEntry.generate!(:issue => issue, :comments => "Issue column content test")
 1478 
 1479     get :index, :params => {:format => 'csv'}
 1480     line = response.body.split("\n").detect {|l| l.include?(entry.comments)}
 1481     assert_not_nil line
 1482     assert_include "#{issue.tracker} #1: #{issue.subject}", line
 1483   end
 1484 
 1485   def test_index_csv_should_fill_issue_column_with_issue_id_if_issue_that_is_not_visible
 1486     @request.session[:user_id] = 3
 1487     issue = Issue.generate!(:author_id => 1, :is_private => true)
 1488     entry = TimeEntry.generate!(:issue => issue, :comments => "Issue column content test")
 1489 
 1490     get :index, :params => {:format => 'csv'}
 1491     assert_not issue.visible?
 1492     line = response.body.split("\n").detect {|l| l.include?(entry.comments)}
 1493     assert_not_nil line
 1494     assert_not_include "#{issue.tracker} ##{issue.id}: #{issue.subject}", line
 1495     assert_include "##{issue.id}", line
 1496   end
 1497 
 1498   def test_index_grouped_by_created_on
 1499     skip unless TimeEntryQuery.new.groupable_columns.detect {|c| c.name == :created_on}
 1500 
 1501     get :index, :params => {
 1502         :set_filter => 1,
 1503         :group_by => 'created_on'
 1504       }
 1505     assert_response :success
 1506 
 1507     assert_select 'tr.group span.name', :text => '03/23/2007' do
 1508       assert_select '+ span.count', :text => '2'
 1509     end
 1510   end
 1511 
 1512   def test_index_with_inline_issue_long_text_custom_field_column
 1513     field = IssueCustomField.create!(:name => 'Long text', :field_format => 'text', :full_width_layout => '1',
 1514       :tracker_ids => [1], :is_for_all => true)
 1515     issue = Issue.find(1)
 1516     issue.custom_field_values = {field.id => 'This is a long text'}
 1517     issue.save!
 1518 
 1519     get :index, :params => {
 1520         :set_filter => 1,
 1521         :c => ['subject', 'description', "issue.cf_#{field.id}"]
 1522       }
 1523     assert_response :success
 1524     assert_select "td.issue_cf_#{field.id}", :text => 'This is a long text'
 1525   end
 1526 end