##// END OF EJS Templates
Merged r14795 and r14796 (#21150)....
Jean-Philippe Lang -
r14456:5bd5738750b0
parent child
Show More
@@ -1,131 +1,131
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2015 Jean-Philippe Lang
2 # Copyright (C) 2006-2015 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 class TimeEntry < ActiveRecord::Base
18 class TimeEntry < ActiveRecord::Base
19 include Redmine::SafeAttributes
19 include Redmine::SafeAttributes
20 # could have used polymorphic association
20 # could have used polymorphic association
21 # project association here allows easy loading of time entries at project level with one database trip
21 # project association here allows easy loading of time entries at project level with one database trip
22 belongs_to :project
22 belongs_to :project
23 belongs_to :issue
23 belongs_to :issue
24 belongs_to :user
24 belongs_to :user
25 belongs_to :activity, :class_name => 'TimeEntryActivity'
25 belongs_to :activity, :class_name => 'TimeEntryActivity'
26
26
27 attr_protected :user_id, :tyear, :tmonth, :tweek
27 attr_protected :user_id, :tyear, :tmonth, :tweek
28
28
29 acts_as_customizable
29 acts_as_customizable
30 acts_as_event :title => Proc.new {|o| "#{l_hours(o.hours)} (#{(o.issue || o.project).event_title})"},
30 acts_as_event :title => Proc.new {|o| "#{l_hours(o.hours)} (#{(o.issue || o.project).event_title})"},
31 :url => Proc.new {|o| {:controller => 'timelog', :action => 'index', :project_id => o.project, :issue_id => o.issue}},
31 :url => Proc.new {|o| {:controller => 'timelog', :action => 'index', :project_id => o.project, :issue_id => o.issue}},
32 :author => :user,
32 :author => :user,
33 :group => :issue,
33 :group => :issue,
34 :description => :comments
34 :description => :comments
35
35
36 acts_as_activity_provider :timestamp => "#{table_name}.created_on",
36 acts_as_activity_provider :timestamp => "#{table_name}.created_on",
37 :author_key => :user_id,
37 :author_key => :user_id,
38 :scope => joins(:project).preload(:project)
38 :scope => joins(:project).preload(:project)
39
39
40 validates_presence_of :user_id, :activity_id, :project_id, :hours, :spent_on
40 validates_presence_of :user_id, :activity_id, :project_id, :hours, :spent_on
41 validates_numericality_of :hours, :allow_nil => true, :message => :invalid
41 validates_numericality_of :hours, :allow_nil => true, :message => :invalid
42 validates_length_of :comments, :maximum => 255, :allow_nil => true
42 validates_length_of :comments, :maximum => 255, :allow_nil => true
43 validates :spent_on, :date => true
43 validates :spent_on, :date => true
44 before_validation :set_project_if_nil
44 before_validation :set_project_if_nil
45 validate :validate_time_entry
45 validate :validate_time_entry
46
46
47 scope :visible, lambda {|*args|
47 scope :visible, lambda {|*args|
48 joins(:project).
48 joins(:project).
49 where(Project.allowed_to_condition(args.shift || User.current, :view_time_entries, *args))
49 where(Project.allowed_to_condition(args.shift || User.current, :view_time_entries, *args))
50 }
50 }
51 scope :on_issue, lambda {|issue|
51 scope :on_issue, lambda {|issue|
52 joins(:issue).
52 joins(:issue).
53 where("#{Issue.table_name}.root_id = #{issue.root_id} AND #{Issue.table_name}.lft >= #{issue.lft} AND #{Issue.table_name}.rgt <= #{issue.rgt}")
53 where("#{Issue.table_name}.root_id = #{issue.root_id} AND #{Issue.table_name}.lft >= #{issue.lft} AND #{Issue.table_name}.rgt <= #{issue.rgt}")
54 }
54 }
55
55
56 safe_attributes 'hours', 'comments', 'project_id', 'issue_id', 'activity_id', 'spent_on', 'custom_field_values', 'custom_fields'
56 safe_attributes 'hours', 'comments', 'project_id', 'issue_id', 'activity_id', 'spent_on', 'custom_field_values', 'custom_fields'
57
57
58 def initialize(attributes=nil, *args)
58 def initialize(attributes=nil, *args)
59 super
59 super
60 if new_record? && self.activity.nil?
60 if new_record? && self.activity.nil?
61 if default_activity = TimeEntryActivity.default
61 if default_activity = TimeEntryActivity.default
62 self.activity_id = default_activity.id
62 self.activity_id = default_activity.id
63 end
63 end
64 self.hours = nil if hours == 0
64 self.hours = nil if hours == 0
65 end
65 end
66 end
66 end
67
67
68 def safe_attributes=(attrs, user=User.current)
68 def safe_attributes=(attrs, user=User.current)
69 if attrs
69 if attrs
70 attrs = super(attrs)
70 attrs = super(attrs)
71 if issue_id_changed? && issue
71 if issue_id_changed? && issue
72 if user.allowed_to?(:log_time, issue.project)
72 if issue.visible?(user) && user.allowed_to?(:log_time, issue.project)
73 if attrs[:project_id].blank? && issue.project_id != project_id
73 if attrs[:project_id].blank? && issue.project_id != project_id
74 self.project_id = issue.project_id
74 self.project_id = issue.project_id
75 end
75 end
76 @invalid_issue_id = nil
76 @invalid_issue_id = nil
77 else
77 else
78 @invalid_issue_id = issue_id
78 @invalid_issue_id = issue_id
79 end
79 end
80 end
80 end
81 end
81 end
82 attrs
82 attrs
83 end
83 end
84
84
85 def set_project_if_nil
85 def set_project_if_nil
86 self.project = issue.project if issue && project.nil?
86 self.project = issue.project if issue && project.nil?
87 end
87 end
88
88
89 def validate_time_entry
89 def validate_time_entry
90 errors.add :hours, :invalid if hours && (hours < 0 || hours >= 1000)
90 errors.add :hours, :invalid if hours && (hours < 0 || hours >= 1000)
91 errors.add :project_id, :invalid if project.nil?
91 errors.add :project_id, :invalid if project.nil?
92 errors.add :issue_id, :invalid if (issue_id && !issue) || (issue && project!=issue.project) || @invalid_issue_id
92 errors.add :issue_id, :invalid if (issue_id && !issue) || (issue && project!=issue.project) || @invalid_issue_id
93 end
93 end
94
94
95 def hours=(h)
95 def hours=(h)
96 write_attribute :hours, (h.is_a?(String) ? (h.to_hours || h) : h)
96 write_attribute :hours, (h.is_a?(String) ? (h.to_hours || h) : h)
97 end
97 end
98
98
99 def hours
99 def hours
100 h = read_attribute(:hours)
100 h = read_attribute(:hours)
101 if h.is_a?(Float)
101 if h.is_a?(Float)
102 h.round(2)
102 h.round(2)
103 else
103 else
104 h
104 h
105 end
105 end
106 end
106 end
107
107
108 # tyear, tmonth, tweek assigned where setting spent_on attributes
108 # tyear, tmonth, tweek assigned where setting spent_on attributes
109 # these attributes make time aggregations easier
109 # these attributes make time aggregations easier
110 def spent_on=(date)
110 def spent_on=(date)
111 super
111 super
112 self.tyear = spent_on ? spent_on.year : nil
112 self.tyear = spent_on ? spent_on.year : nil
113 self.tmonth = spent_on ? spent_on.month : nil
113 self.tmonth = spent_on ? spent_on.month : nil
114 self.tweek = spent_on ? Date.civil(spent_on.year, spent_on.month, spent_on.day).cweek : nil
114 self.tweek = spent_on ? Date.civil(spent_on.year, spent_on.month, spent_on.day).cweek : nil
115 end
115 end
116
116
117 # Returns true if the time entry can be edited by usr, otherwise false
117 # Returns true if the time entry can be edited by usr, otherwise false
118 def editable_by?(usr)
118 def editable_by?(usr)
119 (usr == user && usr.allowed_to?(:edit_own_time_entries, project)) || usr.allowed_to?(:edit_time_entries, project)
119 (usr == user && usr.allowed_to?(:edit_own_time_entries, project)) || usr.allowed_to?(:edit_time_entries, project)
120 end
120 end
121
121
122 # Returns the custom_field_values that can be edited by the given user
122 # Returns the custom_field_values that can be edited by the given user
123 def editable_custom_field_values(user=nil)
123 def editable_custom_field_values(user=nil)
124 visible_custom_field_values
124 visible_custom_field_values
125 end
125 end
126
126
127 # Returns the custom fields that can be edited by the given user
127 # Returns the custom fields that can be edited by the given user
128 def editable_custom_fields(user=nil)
128 def editable_custom_fields(user=nil)
129 editable_custom_field_values(user).map(&:custom_field).uniq
129 editable_custom_field_values(user).map(&:custom_field).uniq
130 end
130 end
131 end
131 end
@@ -1,34 +1,36
1 <%= error_messages_for 'time_entry' %>
1 <%= error_messages_for 'time_entry' %>
2 <%= back_url_hidden_field_tag %>
2 <%= back_url_hidden_field_tag %>
3
3
4 <div class="box tabular">
4 <div class="box tabular">
5 <% if @time_entry.new_record? %>
5 <% if @time_entry.new_record? %>
6 <% if params[:project_id] %>
6 <% if params[:project_id] %>
7 <%= hidden_field_tag 'project_id', params[:project_id] %>
7 <%= hidden_field_tag 'project_id', params[:project_id] %>
8 <% elsif params[:issue_id] %>
8 <% elsif params[:issue_id] %>
9 <%= hidden_field_tag 'issue_id', params[:issue_id] %>
9 <%= hidden_field_tag 'issue_id', params[:issue_id] %>
10 <% else %>
10 <% else %>
11 <p><%= f.select :project_id, project_tree_options_for_select(Project.allowed_to(:log_time).to_a, :selected => @time_entry.project, :include_blank => true) %></p>
11 <p><%= f.select :project_id, project_tree_options_for_select(Project.allowed_to(:log_time).to_a, :selected => @time_entry.project, :include_blank => true) %></p>
12 <% end %>
12 <% end %>
13 <% end %>
13 <% end %>
14 <p>
14 <p>
15 <%= f.text_field :issue_id, :size => 6 %>
15 <%= f.text_field :issue_id, :size => 6 %>
16 <span id="time_entry_issue"><%= h("#{@time_entry.issue.tracker.name} ##{@time_entry.issue.id}: #{@time_entry.issue.subject}") if @time_entry.issue %></span>
16 <% if @time_entry.issue.try(:visible?) %>
17 <span id="time_entry_issue"><%= "#{@time_entry.issue.tracker.name} ##{@time_entry.issue.id}: #{@time_entry.issue.subject}" %></span>
18 <% end %>
17 </p>
19 </p>
18 <p><%= f.text_field :spent_on, :size => 10, :required => true %><%= calendar_for('time_entry_spent_on') %></p>
20 <p><%= f.text_field :spent_on, :size => 10, :required => true %><%= calendar_for('time_entry_spent_on') %></p>
19 <p><%= f.text_field :hours, :size => 6, :required => true %></p>
21 <p><%= f.text_field :hours, :size => 6, :required => true %></p>
20 <p><%= f.text_field :comments, :size => 100, :maxlength => 255 %></p>
22 <p><%= f.text_field :comments, :size => 100, :maxlength => 255 %></p>
21 <p><%= f.select :activity_id, activity_collection_for_select_options(@time_entry), :required => true %></p>
23 <p><%= f.select :activity_id, activity_collection_for_select_options(@time_entry), :required => true %></p>
22 <% @time_entry.custom_field_values.each do |value| %>
24 <% @time_entry.custom_field_values.each do |value| %>
23 <p><%= custom_field_tag_with_label :time_entry, value %></p>
25 <p><%= custom_field_tag_with_label :time_entry, value %></p>
24 <% end %>
26 <% end %>
25 <%= call_hook(:view_timelog_edit_form_bottom, { :time_entry => @time_entry, :form => f }) %>
27 <%= call_hook(:view_timelog_edit_form_bottom, { :time_entry => @time_entry, :form => f }) %>
26 </div>
28 </div>
27
29
28 <%= javascript_tag do %>
30 <%= javascript_tag do %>
29 observeAutocompleteField('time_entry_issue_id', '<%= escape_javascript auto_complete_issues_path(:project_id => @project, :scope => (@project ? nil : 'all'))%>', {
31 observeAutocompleteField('time_entry_issue_id', '<%= escape_javascript auto_complete_issues_path(:project_id => @project, :scope => (@project ? nil : 'all'))%>', {
30 select: function(event, ui) {
32 select: function(event, ui) {
31 $('#time_entry_issue').text(ui.item.label);
33 $('#time_entry_issue').text(ui.item.label);
32 }
34 }
33 });
35 });
34 <% end %>
36 <% end %>
@@ -1,802 +1,819
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 # Redmine - project management software
2 # Redmine - project management software
3 # Copyright (C) 2006-2015 Jean-Philippe Lang
3 # Copyright (C) 2006-2015 Jean-Philippe Lang
4 #
4 #
5 # This program is free software; you can redistribute it and/or
5 # This program is free software; you can redistribute it and/or
6 # modify it under the terms of the GNU General Public License
6 # modify it under the terms of the GNU General Public License
7 # as published by the Free Software Foundation; either version 2
7 # as published by the Free Software Foundation; either version 2
8 # of the License, or (at your option) any later version.
8 # of the License, or (at your option) any later version.
9 #
9 #
10 # This program is distributed in the hope that it will be useful,
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
13 # GNU General Public License for more details.
14 #
14 #
15 # You should have received a copy of the GNU General Public License
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software
16 # along with this program; if not, write to the Free Software
17 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18
18
19 require File.expand_path('../../test_helper', __FILE__)
19 require File.expand_path('../../test_helper', __FILE__)
20
20
21 class TimelogControllerTest < ActionController::TestCase
21 class TimelogControllerTest < ActionController::TestCase
22 fixtures :projects, :enabled_modules, :roles, :members,
22 fixtures :projects, :enabled_modules, :roles, :members,
23 :member_roles, :issues, :time_entries, :users,
23 :member_roles, :issues, :time_entries, :users,
24 :trackers, :enumerations, :issue_statuses,
24 :trackers, :enumerations, :issue_statuses,
25 :custom_fields, :custom_values,
25 :custom_fields, :custom_values,
26 :projects_trackers, :custom_fields_trackers,
26 :projects_trackers, :custom_fields_trackers,
27 :custom_fields_projects
27 :custom_fields_projects
28
28
29 include Redmine::I18n
29 include Redmine::I18n
30
30
31 def test_new
31 def test_new
32 @request.session[:user_id] = 3
32 @request.session[:user_id] = 3
33 get :new
33 get :new
34 assert_response :success
34 assert_response :success
35 assert_template 'new'
35 assert_template 'new'
36 assert_select 'input[name=?][type=hidden]', 'project_id', 0
36 assert_select 'input[name=?][type=hidden]', 'project_id', 0
37 assert_select 'input[name=?][type=hidden]', 'issue_id', 0
37 assert_select 'input[name=?][type=hidden]', 'issue_id', 0
38 assert_select 'select[name=?]', 'time_entry[project_id]' do
38 assert_select 'select[name=?]', 'time_entry[project_id]' do
39 # blank option for project
39 # blank option for project
40 assert_select 'option[value=""]'
40 assert_select 'option[value=""]'
41 end
41 end
42 end
42 end
43
43
44 def test_new_with_project_id
44 def test_new_with_project_id
45 @request.session[:user_id] = 3
45 @request.session[:user_id] = 3
46 get :new, :project_id => 1
46 get :new, :project_id => 1
47 assert_response :success
47 assert_response :success
48 assert_template 'new'
48 assert_template 'new'
49 assert_select 'input[name=?][type=hidden]', 'project_id'
49 assert_select 'input[name=?][type=hidden]', 'project_id'
50 assert_select 'input[name=?][type=hidden]', 'issue_id', 0
50 assert_select 'input[name=?][type=hidden]', 'issue_id', 0
51 assert_select 'select[name=?]', 'time_entry[project_id]', 0
51 assert_select 'select[name=?]', 'time_entry[project_id]', 0
52 end
52 end
53
53
54 def test_new_with_issue_id
54 def test_new_with_issue_id
55 @request.session[:user_id] = 3
55 @request.session[:user_id] = 3
56 get :new, :issue_id => 2
56 get :new, :issue_id => 2
57 assert_response :success
57 assert_response :success
58 assert_template 'new'
58 assert_template 'new'
59 assert_select 'input[name=?][type=hidden]', 'project_id', 0
59 assert_select 'input[name=?][type=hidden]', 'project_id', 0
60 assert_select 'input[name=?][type=hidden]', 'issue_id'
60 assert_select 'input[name=?][type=hidden]', 'issue_id'
61 assert_select 'select[name=?]', 'time_entry[project_id]', 0
61 assert_select 'select[name=?]', 'time_entry[project_id]', 0
62 end
62 end
63
63
64 def test_new_without_project_should_prefill_the_form
64 def test_new_without_project_should_prefill_the_form
65 @request.session[:user_id] = 3
65 @request.session[:user_id] = 3
66 get :new, :time_entry => {:project_id => '1'}
66 get :new, :time_entry => {:project_id => '1'}
67 assert_response :success
67 assert_response :success
68 assert_template 'new'
68 assert_template 'new'
69 assert_select 'select[name=?]', 'time_entry[project_id]' do
69 assert_select 'select[name=?]', 'time_entry[project_id]' do
70 assert_select 'option[value="1"][selected=selected]'
70 assert_select 'option[value="1"][selected=selected]'
71 end
71 end
72 end
72 end
73
73
74 def test_new_without_project_should_deny_without_permission
74 def test_new_without_project_should_deny_without_permission
75 Role.all.each {|role| role.remove_permission! :log_time}
75 Role.all.each {|role| role.remove_permission! :log_time}
76 @request.session[:user_id] = 3
76 @request.session[:user_id] = 3
77
77
78 get :new
78 get :new
79 assert_response 403
79 assert_response 403
80 end
80 end
81
81
82 def test_new_should_select_default_activity
82 def test_new_should_select_default_activity
83 @request.session[:user_id] = 3
83 @request.session[:user_id] = 3
84 get :new, :project_id => 1
84 get :new, :project_id => 1
85 assert_response :success
85 assert_response :success
86 assert_select 'select[name=?]', 'time_entry[activity_id]' do
86 assert_select 'select[name=?]', 'time_entry[activity_id]' do
87 assert_select 'option[selected=selected]', :text => 'Development'
87 assert_select 'option[selected=selected]', :text => 'Development'
88 end
88 end
89 end
89 end
90
90
91 def test_new_should_only_show_active_time_entry_activities
91 def test_new_should_only_show_active_time_entry_activities
92 @request.session[:user_id] = 3
92 @request.session[:user_id] = 3
93 get :new, :project_id => 1
93 get :new, :project_id => 1
94 assert_response :success
94 assert_response :success
95 assert_select 'option', :text => 'Inactive Activity', :count => 0
95 assert_select 'option', :text => 'Inactive Activity', :count => 0
96 end
96 end
97
97
98 def test_get_edit_existing_time
98 def test_get_edit_existing_time
99 @request.session[:user_id] = 2
99 @request.session[:user_id] = 2
100 get :edit, :id => 2, :project_id => nil
100 get :edit, :id => 2, :project_id => nil
101 assert_response :success
101 assert_response :success
102 assert_template 'edit'
102 assert_template 'edit'
103 assert_select 'form[action=?]', '/time_entries/2'
103 assert_select 'form[action=?]', '/time_entries/2'
104 end
104 end
105
105
106 def test_get_edit_with_an_existing_time_entry_with_inactive_activity
106 def test_get_edit_with_an_existing_time_entry_with_inactive_activity
107 te = TimeEntry.find(1)
107 te = TimeEntry.find(1)
108 te.activity = TimeEntryActivity.find_by_name("Inactive Activity")
108 te.activity = TimeEntryActivity.find_by_name("Inactive Activity")
109 te.save!
109 te.save!
110
110
111 @request.session[:user_id] = 1
111 @request.session[:user_id] = 1
112 get :edit, :project_id => 1, :id => 1
112 get :edit, :project_id => 1, :id => 1
113 assert_response :success
113 assert_response :success
114 assert_template 'edit'
114 assert_template 'edit'
115 # Blank option since nothing is pre-selected
115 # Blank option since nothing is pre-selected
116 assert_select 'option', :text => '--- Please select ---'
116 assert_select 'option', :text => '--- Please select ---'
117 end
117 end
118
118
119 def test_post_create
119 def test_post_create
120 @request.session[:user_id] = 3
120 @request.session[:user_id] = 3
121 assert_difference 'TimeEntry.count' do
121 assert_difference 'TimeEntry.count' do
122 post :create, :project_id => 1,
122 post :create, :project_id => 1,
123 :time_entry => {:comments => 'Some work on TimelogControllerTest',
123 :time_entry => {:comments => 'Some work on TimelogControllerTest',
124 # Not the default activity
124 # Not the default activity
125 :activity_id => '11',
125 :activity_id => '11',
126 :spent_on => '2008-03-14',
126 :spent_on => '2008-03-14',
127 :issue_id => '1',
127 :issue_id => '1',
128 :hours => '7.3'}
128 :hours => '7.3'}
129 assert_redirected_to '/projects/ecookbook/time_entries'
129 assert_redirected_to '/projects/ecookbook/time_entries'
130 end
130 end
131
131
132 t = TimeEntry.order('id DESC').first
132 t = TimeEntry.order('id DESC').first
133 assert_not_nil t
133 assert_not_nil t
134 assert_equal 'Some work on TimelogControllerTest', t.comments
134 assert_equal 'Some work on TimelogControllerTest', t.comments
135 assert_equal 1, t.project_id
135 assert_equal 1, t.project_id
136 assert_equal 1, t.issue_id
136 assert_equal 1, t.issue_id
137 assert_equal 11, t.activity_id
137 assert_equal 11, t.activity_id
138 assert_equal 7.3, t.hours
138 assert_equal 7.3, t.hours
139 assert_equal 3, t.user_id
139 assert_equal 3, t.user_id
140 end
140 end
141
141
142 def test_post_create_with_blank_issue
142 def test_post_create_with_blank_issue
143 @request.session[:user_id] = 3
143 @request.session[:user_id] = 3
144 assert_difference 'TimeEntry.count' do
144 assert_difference 'TimeEntry.count' do
145 post :create, :project_id => 1,
145 post :create, :project_id => 1,
146 :time_entry => {:comments => 'Some work on TimelogControllerTest',
146 :time_entry => {:comments => 'Some work on TimelogControllerTest',
147 # Not the default activity
147 # Not the default activity
148 :activity_id => '11',
148 :activity_id => '11',
149 :issue_id => '',
149 :issue_id => '',
150 :spent_on => '2008-03-14',
150 :spent_on => '2008-03-14',
151 :hours => '7.3'}
151 :hours => '7.3'}
152 assert_redirected_to '/projects/ecookbook/time_entries'
152 assert_redirected_to '/projects/ecookbook/time_entries'
153 end
153 end
154
154
155 t = TimeEntry.order('id DESC').first
155 t = TimeEntry.order('id DESC').first
156 assert_not_nil t
156 assert_not_nil t
157 assert_equal 'Some work on TimelogControllerTest', t.comments
157 assert_equal 'Some work on TimelogControllerTest', t.comments
158 assert_equal 1, t.project_id
158 assert_equal 1, t.project_id
159 assert_nil t.issue_id
159 assert_nil t.issue_id
160 assert_equal 11, t.activity_id
160 assert_equal 11, t.activity_id
161 assert_equal 7.3, t.hours
161 assert_equal 7.3, t.hours
162 assert_equal 3, t.user_id
162 assert_equal 3, t.user_id
163 end
163 end
164
164
165 def test_create_on_project_with_time_tracking_disabled_should_fail
165 def test_create_on_project_with_time_tracking_disabled_should_fail
166 Project.find(1).disable_module! :time_tracking
166 Project.find(1).disable_module! :time_tracking
167
167
168 @request.session[:user_id] = 2
168 @request.session[:user_id] = 2
169 assert_no_difference 'TimeEntry.count' do
169 assert_no_difference 'TimeEntry.count' do
170 post :create, :time_entry => {
170 post :create, :time_entry => {
171 :project_id => '1', :issue_id => '',
171 :project_id => '1', :issue_id => '',
172 :activity_id => '11', :spent_on => '2008-03-14', :hours => '7.3'
172 :activity_id => '11', :spent_on => '2008-03-14', :hours => '7.3'
173 }
173 }
174 end
174 end
175 end
175 end
176
176
177 def test_create_on_project_without_permission_should_fail
177 def test_create_on_project_without_permission_should_fail
178 Role.find(1).remove_permission! :log_time
178 Role.find(1).remove_permission! :log_time
179
179
180 @request.session[:user_id] = 2
180 @request.session[:user_id] = 2
181 assert_no_difference 'TimeEntry.count' do
181 assert_no_difference 'TimeEntry.count' do
182 post :create, :time_entry => {
182 post :create, :time_entry => {
183 :project_id => '1', :issue_id => '',
183 :project_id => '1', :issue_id => '',
184 :activity_id => '11', :spent_on => '2008-03-14', :hours => '7.3'
184 :activity_id => '11', :spent_on => '2008-03-14', :hours => '7.3'
185 }
185 }
186 end
186 end
187 end
187 end
188
188
189 def test_create_on_issue_in_project_with_time_tracking_disabled_should_fail
189 def test_create_on_issue_in_project_with_time_tracking_disabled_should_fail
190 Project.find(1).disable_module! :time_tracking
190 Project.find(1).disable_module! :time_tracking
191
191
192 @request.session[:user_id] = 2
192 @request.session[:user_id] = 2
193 assert_no_difference 'TimeEntry.count' do
193 assert_no_difference 'TimeEntry.count' do
194 post :create, :time_entry => {
194 post :create, :time_entry => {
195 :project_id => '', :issue_id => '1',
195 :project_id => '', :issue_id => '1',
196 :activity_id => '11', :spent_on => '2008-03-14', :hours => '7.3'
196 :activity_id => '11', :spent_on => '2008-03-14', :hours => '7.3'
197 }
197 }
198 assert_select_error /Issue is invalid/
198 assert_select_error /Issue is invalid/
199 end
199 end
200 end
200 end
201
201
202 def test_create_on_issue_in_project_without_permission_should_fail
202 def test_create_on_issue_in_project_without_permission_should_fail
203 Role.find(1).remove_permission! :log_time
203 Role.find(1).remove_permission! :log_time
204
204
205 @request.session[:user_id] = 2
205 @request.session[:user_id] = 2
206 assert_no_difference 'TimeEntry.count' do
206 assert_no_difference 'TimeEntry.count' do
207 post :create, :time_entry => {
207 post :create, :time_entry => {
208 :project_id => '', :issue_id => '1',
208 :project_id => '', :issue_id => '1',
209 :activity_id => '11', :spent_on => '2008-03-14', :hours => '7.3'
209 :activity_id => '11', :spent_on => '2008-03-14', :hours => '7.3'
210 }
210 }
211 assert_select_error /Issue is invalid/
211 assert_select_error /Issue is invalid/
212 end
212 end
213 end
213 end
214
214
215 def test_create_on_issue_that_is_not_visible_should_not_disclose_subject
216 issue = Issue.generate!(:subject => "issue_that_is_not_visible", :is_private => true)
217 assert !issue.visible?(User.find(3))
218
219 @request.session[:user_id] = 3
220 assert_no_difference 'TimeEntry.count' do
221 post :create, :time_entry => {
222 :project_id => '', :issue_id => issue.id.to_s,
223 :activity_id => '11', :spent_on => '2008-03-14', :hours => '7.3'
224 }
225 end
226 assert_select_error /Issue is invalid/
227 assert_select "input[name=?][value=?]", "time_entry[issue_id]", issue.id.to_s
228 assert_select "#time_entry_issue", 0
229 assert !response.body.include?('issue_that_is_not_visible')
230 end
231
215 def test_create_and_continue_at_project_level
232 def test_create_and_continue_at_project_level
216 @request.session[:user_id] = 2
233 @request.session[:user_id] = 2
217 assert_difference 'TimeEntry.count' do
234 assert_difference 'TimeEntry.count' do
218 post :create, :time_entry => {:project_id => '1',
235 post :create, :time_entry => {:project_id => '1',
219 :activity_id => '11',
236 :activity_id => '11',
220 :issue_id => '',
237 :issue_id => '',
221 :spent_on => '2008-03-14',
238 :spent_on => '2008-03-14',
222 :hours => '7.3'},
239 :hours => '7.3'},
223 :continue => '1'
240 :continue => '1'
224 assert_redirected_to '/time_entries/new?time_entry%5Bactivity_id%5D=11&time_entry%5Bissue_id%5D=&time_entry%5Bproject_id%5D=1'
241 assert_redirected_to '/time_entries/new?time_entry%5Bactivity_id%5D=11&time_entry%5Bissue_id%5D=&time_entry%5Bproject_id%5D=1'
225 end
242 end
226 end
243 end
227
244
228 def test_create_and_continue_at_issue_level
245 def test_create_and_continue_at_issue_level
229 @request.session[:user_id] = 2
246 @request.session[:user_id] = 2
230 assert_difference 'TimeEntry.count' do
247 assert_difference 'TimeEntry.count' do
231 post :create, :time_entry => {:project_id => '',
248 post :create, :time_entry => {:project_id => '',
232 :activity_id => '11',
249 :activity_id => '11',
233 :issue_id => '1',
250 :issue_id => '1',
234 :spent_on => '2008-03-14',
251 :spent_on => '2008-03-14',
235 :hours => '7.3'},
252 :hours => '7.3'},
236 :continue => '1'
253 :continue => '1'
237 assert_redirected_to '/time_entries/new?time_entry%5Bactivity_id%5D=11&time_entry%5Bissue_id%5D=1&time_entry%5Bproject_id%5D='
254 assert_redirected_to '/time_entries/new?time_entry%5Bactivity_id%5D=11&time_entry%5Bissue_id%5D=1&time_entry%5Bproject_id%5D='
238 end
255 end
239 end
256 end
240
257
241 def test_create_and_continue_with_project_id
258 def test_create_and_continue_with_project_id
242 @request.session[:user_id] = 2
259 @request.session[:user_id] = 2
243 assert_difference 'TimeEntry.count' do
260 assert_difference 'TimeEntry.count' do
244 post :create, :project_id => 1,
261 post :create, :project_id => 1,
245 :time_entry => {:activity_id => '11',
262 :time_entry => {:activity_id => '11',
246 :issue_id => '',
263 :issue_id => '',
247 :spent_on => '2008-03-14',
264 :spent_on => '2008-03-14',
248 :hours => '7.3'},
265 :hours => '7.3'},
249 :continue => '1'
266 :continue => '1'
250 assert_redirected_to '/projects/ecookbook/time_entries/new?time_entry%5Bactivity_id%5D=11&time_entry%5Bissue_id%5D=&time_entry%5Bproject_id%5D='
267 assert_redirected_to '/projects/ecookbook/time_entries/new?time_entry%5Bactivity_id%5D=11&time_entry%5Bissue_id%5D=&time_entry%5Bproject_id%5D='
251 end
268 end
252 end
269 end
253
270
254 def test_create_and_continue_with_issue_id
271 def test_create_and_continue_with_issue_id
255 @request.session[:user_id] = 2
272 @request.session[:user_id] = 2
256 assert_difference 'TimeEntry.count' do
273 assert_difference 'TimeEntry.count' do
257 post :create, :issue_id => 1,
274 post :create, :issue_id => 1,
258 :time_entry => {:activity_id => '11',
275 :time_entry => {:activity_id => '11',
259 :issue_id => '1',
276 :issue_id => '1',
260 :spent_on => '2008-03-14',
277 :spent_on => '2008-03-14',
261 :hours => '7.3'},
278 :hours => '7.3'},
262 :continue => '1'
279 :continue => '1'
263 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='
280 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='
264 end
281 end
265 end
282 end
266
283
267 def test_create_without_log_time_permission_should_be_denied
284 def test_create_without_log_time_permission_should_be_denied
268 @request.session[:user_id] = 2
285 @request.session[:user_id] = 2
269 Role.find_by_name('Manager').remove_permission! :log_time
286 Role.find_by_name('Manager').remove_permission! :log_time
270 post :create, :project_id => 1,
287 post :create, :project_id => 1,
271 :time_entry => {:activity_id => '11',
288 :time_entry => {:activity_id => '11',
272 :issue_id => '',
289 :issue_id => '',
273 :spent_on => '2008-03-14',
290 :spent_on => '2008-03-14',
274 :hours => '7.3'}
291 :hours => '7.3'}
275
292
276 assert_response 403
293 assert_response 403
277 end
294 end
278
295
279 def test_create_without_project_and_issue_should_fail
296 def test_create_without_project_and_issue_should_fail
280 @request.session[:user_id] = 2
297 @request.session[:user_id] = 2
281 post :create, :time_entry => {:issue_id => ''}
298 post :create, :time_entry => {:issue_id => ''}
282
299
283 assert_response :success
300 assert_response :success
284 assert_template 'new'
301 assert_template 'new'
285 end
302 end
286
303
287 def test_create_with_failure
304 def test_create_with_failure
288 @request.session[:user_id] = 2
305 @request.session[:user_id] = 2
289 post :create, :project_id => 1,
306 post :create, :project_id => 1,
290 :time_entry => {:activity_id => '',
307 :time_entry => {:activity_id => '',
291 :issue_id => '',
308 :issue_id => '',
292 :spent_on => '2008-03-14',
309 :spent_on => '2008-03-14',
293 :hours => '7.3'}
310 :hours => '7.3'}
294
311
295 assert_response :success
312 assert_response :success
296 assert_template 'new'
313 assert_template 'new'
297 end
314 end
298
315
299 def test_create_without_project
316 def test_create_without_project
300 @request.session[:user_id] = 2
317 @request.session[:user_id] = 2
301 assert_difference 'TimeEntry.count' do
318 assert_difference 'TimeEntry.count' do
302 post :create, :time_entry => {:project_id => '1',
319 post :create, :time_entry => {:project_id => '1',
303 :activity_id => '11',
320 :activity_id => '11',
304 :issue_id => '',
321 :issue_id => '',
305 :spent_on => '2008-03-14',
322 :spent_on => '2008-03-14',
306 :hours => '7.3'}
323 :hours => '7.3'}
307 end
324 end
308
325
309 assert_redirected_to '/projects/ecookbook/time_entries'
326 assert_redirected_to '/projects/ecookbook/time_entries'
310 time_entry = TimeEntry.order('id DESC').first
327 time_entry = TimeEntry.order('id DESC').first
311 assert_equal 1, time_entry.project_id
328 assert_equal 1, time_entry.project_id
312 end
329 end
313
330
314 def test_create_without_project_should_fail_with_issue_not_inside_project
331 def test_create_without_project_should_fail_with_issue_not_inside_project
315 @request.session[:user_id] = 2
332 @request.session[:user_id] = 2
316 assert_no_difference 'TimeEntry.count' do
333 assert_no_difference 'TimeEntry.count' do
317 post :create, :time_entry => {:project_id => '1',
334 post :create, :time_entry => {:project_id => '1',
318 :activity_id => '11',
335 :activity_id => '11',
319 :issue_id => '5',
336 :issue_id => '5',
320 :spent_on => '2008-03-14',
337 :spent_on => '2008-03-14',
321 :hours => '7.3'}
338 :hours => '7.3'}
322 end
339 end
323
340
324 assert_response :success
341 assert_response :success
325 assert assigns(:time_entry).errors[:issue_id].present?
342 assert assigns(:time_entry).errors[:issue_id].present?
326 end
343 end
327
344
328 def test_create_without_project_should_deny_without_permission
345 def test_create_without_project_should_deny_without_permission
329 @request.session[:user_id] = 2
346 @request.session[:user_id] = 2
330 Project.find(3).disable_module!(:time_tracking)
347 Project.find(3).disable_module!(:time_tracking)
331
348
332 assert_no_difference 'TimeEntry.count' do
349 assert_no_difference 'TimeEntry.count' do
333 post :create, :time_entry => {:project_id => '3',
350 post :create, :time_entry => {:project_id => '3',
334 :activity_id => '11',
351 :activity_id => '11',
335 :issue_id => '',
352 :issue_id => '',
336 :spent_on => '2008-03-14',
353 :spent_on => '2008-03-14',
337 :hours => '7.3'}
354 :hours => '7.3'}
338 end
355 end
339
356
340 assert_response 403
357 assert_response 403
341 end
358 end
342
359
343 def test_create_without_project_with_failure
360 def test_create_without_project_with_failure
344 @request.session[:user_id] = 2
361 @request.session[:user_id] = 2
345 assert_no_difference 'TimeEntry.count' do
362 assert_no_difference 'TimeEntry.count' do
346 post :create, :time_entry => {:project_id => '1',
363 post :create, :time_entry => {:project_id => '1',
347 :activity_id => '11',
364 :activity_id => '11',
348 :issue_id => '',
365 :issue_id => '',
349 :spent_on => '2008-03-14',
366 :spent_on => '2008-03-14',
350 :hours => ''}
367 :hours => ''}
351 end
368 end
352
369
353 assert_response :success
370 assert_response :success
354 assert_select 'select[name=?]', 'time_entry[project_id]' do
371 assert_select 'select[name=?]', 'time_entry[project_id]' do
355 assert_select 'option[value="1"][selected=selected]'
372 assert_select 'option[value="1"][selected=selected]'
356 end
373 end
357 end
374 end
358
375
359 def test_update
376 def test_update
360 entry = TimeEntry.find(1)
377 entry = TimeEntry.find(1)
361 assert_equal 1, entry.issue_id
378 assert_equal 1, entry.issue_id
362 assert_equal 2, entry.user_id
379 assert_equal 2, entry.user_id
363
380
364 @request.session[:user_id] = 1
381 @request.session[:user_id] = 1
365 put :update, :id => 1,
382 put :update, :id => 1,
366 :time_entry => {:issue_id => '2',
383 :time_entry => {:issue_id => '2',
367 :hours => '8'}
384 :hours => '8'}
368 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
385 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
369 entry.reload
386 entry.reload
370
387
371 assert_equal 8, entry.hours
388 assert_equal 8, entry.hours
372 assert_equal 2, entry.issue_id
389 assert_equal 2, entry.issue_id
373 assert_equal 2, entry.user_id
390 assert_equal 2, entry.user_id
374 end
391 end
375
392
376 def test_update_should_allow_to_change_issue_to_another_project
393 def test_update_should_allow_to_change_issue_to_another_project
377 entry = TimeEntry.generate!(:issue_id => 1)
394 entry = TimeEntry.generate!(:issue_id => 1)
378
395
379 @request.session[:user_id] = 1
396 @request.session[:user_id] = 1
380 put :update, :id => entry.id, :time_entry => {:issue_id => '5'}
397 put :update, :id => entry.id, :time_entry => {:issue_id => '5'}
381 assert_response 302
398 assert_response 302
382 entry.reload
399 entry.reload
383
400
384 assert_equal 5, entry.issue_id
401 assert_equal 5, entry.issue_id
385 assert_equal 3, entry.project_id
402 assert_equal 3, entry.project_id
386 end
403 end
387
404
388 def test_update_should_not_allow_to_change_issue_to_an_invalid_project
405 def test_update_should_not_allow_to_change_issue_to_an_invalid_project
389 entry = TimeEntry.generate!(:issue_id => 1)
406 entry = TimeEntry.generate!(:issue_id => 1)
390 Project.find(3).disable_module!(:time_tracking)
407 Project.find(3).disable_module!(:time_tracking)
391
408
392 @request.session[:user_id] = 1
409 @request.session[:user_id] = 1
393 put :update, :id => entry.id, :time_entry => {:issue_id => '5'}
410 put :update, :id => entry.id, :time_entry => {:issue_id => '5'}
394 assert_response 200
411 assert_response 200
395 assert_include "Issue is invalid", assigns(:time_entry).errors.full_messages
412 assert_include "Issue is invalid", assigns(:time_entry).errors.full_messages
396 end
413 end
397
414
398 def test_get_bulk_edit
415 def test_get_bulk_edit
399 @request.session[:user_id] = 2
416 @request.session[:user_id] = 2
400 get :bulk_edit, :ids => [1, 2]
417 get :bulk_edit, :ids => [1, 2]
401 assert_response :success
418 assert_response :success
402 assert_template 'bulk_edit'
419 assert_template 'bulk_edit'
403
420
404 assert_select 'ul#bulk-selection' do
421 assert_select 'ul#bulk-selection' do
405 assert_select 'li', 2
422 assert_select 'li', 2
406 assert_select 'li a', :text => '03/23/2007 - eCookbook: 4.25 hours'
423 assert_select 'li a', :text => '03/23/2007 - eCookbook: 4.25 hours'
407 end
424 end
408
425
409 assert_select 'form#bulk_edit_form[action=?]', '/time_entries/bulk_update' do
426 assert_select 'form#bulk_edit_form[action=?]', '/time_entries/bulk_update' do
410 # System wide custom field
427 # System wide custom field
411 assert_select 'select[name=?]', 'time_entry[custom_field_values][10]'
428 assert_select 'select[name=?]', 'time_entry[custom_field_values][10]'
412
429
413 # Activities
430 # Activities
414 assert_select 'select[name=?]', 'time_entry[activity_id]' do
431 assert_select 'select[name=?]', 'time_entry[activity_id]' do
415 assert_select 'option[value=""]', :text => '(No change)'
432 assert_select 'option[value=""]', :text => '(No change)'
416 assert_select 'option[value="9"]', :text => 'Design'
433 assert_select 'option[value="9"]', :text => 'Design'
417 end
434 end
418 end
435 end
419 end
436 end
420
437
421 def test_get_bulk_edit_on_different_projects
438 def test_get_bulk_edit_on_different_projects
422 @request.session[:user_id] = 2
439 @request.session[:user_id] = 2
423 get :bulk_edit, :ids => [1, 2, 6]
440 get :bulk_edit, :ids => [1, 2, 6]
424 assert_response :success
441 assert_response :success
425 assert_template 'bulk_edit'
442 assert_template 'bulk_edit'
426 end
443 end
427
444
428 def test_bulk_edit_with_edit_own_time_entries_permission
445 def test_bulk_edit_with_edit_own_time_entries_permission
429 @request.session[:user_id] = 2
446 @request.session[:user_id] = 2
430 Role.find_by_name('Manager').remove_permission! :edit_time_entries
447 Role.find_by_name('Manager').remove_permission! :edit_time_entries
431 Role.find_by_name('Manager').add_permission! :edit_own_time_entries
448 Role.find_by_name('Manager').add_permission! :edit_own_time_entries
432 ids = (0..1).map {TimeEntry.generate!(:user => User.find(2)).id}
449 ids = (0..1).map {TimeEntry.generate!(:user => User.find(2)).id}
433
450
434 get :bulk_edit, :ids => ids
451 get :bulk_edit, :ids => ids
435 assert_response :success
452 assert_response :success
436 end
453 end
437
454
438 def test_bulk_update
455 def test_bulk_update
439 @request.session[:user_id] = 2
456 @request.session[:user_id] = 2
440 # update time entry activity
457 # update time entry activity
441 post :bulk_update, :ids => [1, 2], :time_entry => { :activity_id => 9}
458 post :bulk_update, :ids => [1, 2], :time_entry => { :activity_id => 9}
442
459
443 assert_response 302
460 assert_response 302
444 # check that the issues were updated
461 # check that the issues were updated
445 assert_equal [9, 9], TimeEntry.where(:id => [1, 2]).collect {|i| i.activity_id}
462 assert_equal [9, 9], TimeEntry.where(:id => [1, 2]).collect {|i| i.activity_id}
446 end
463 end
447
464
448 def test_bulk_update_with_failure
465 def test_bulk_update_with_failure
449 @request.session[:user_id] = 2
466 @request.session[:user_id] = 2
450 post :bulk_update, :ids => [1, 2], :time_entry => { :hours => 'A'}
467 post :bulk_update, :ids => [1, 2], :time_entry => { :hours => 'A'}
451
468
452 assert_response 302
469 assert_response 302
453 assert_match /Failed to save 2 time entrie/, flash[:error]
470 assert_match /Failed to save 2 time entrie/, flash[:error]
454 end
471 end
455
472
456 def test_bulk_update_on_different_projects
473 def test_bulk_update_on_different_projects
457 @request.session[:user_id] = 2
474 @request.session[:user_id] = 2
458 # makes user a manager on the other project
475 # makes user a manager on the other project
459 Member.create!(:user_id => 2, :project_id => 3, :role_ids => [1])
476 Member.create!(:user_id => 2, :project_id => 3, :role_ids => [1])
460
477
461 # update time entry activity
478 # update time entry activity
462 post :bulk_update, :ids => [1, 2, 4], :time_entry => { :activity_id => 9 }
479 post :bulk_update, :ids => [1, 2, 4], :time_entry => { :activity_id => 9 }
463
480
464 assert_response 302
481 assert_response 302
465 # check that the issues were updated
482 # check that the issues were updated
466 assert_equal [9, 9, 9], TimeEntry.where(:id => [1, 2, 4]).collect {|i| i.activity_id}
483 assert_equal [9, 9, 9], TimeEntry.where(:id => [1, 2, 4]).collect {|i| i.activity_id}
467 end
484 end
468
485
469 def test_bulk_update_on_different_projects_without_rights
486 def test_bulk_update_on_different_projects_without_rights
470 @request.session[:user_id] = 3
487 @request.session[:user_id] = 3
471 user = User.find(3)
488 user = User.find(3)
472 action = { :controller => "timelog", :action => "bulk_update" }
489 action = { :controller => "timelog", :action => "bulk_update" }
473 assert user.allowed_to?(action, TimeEntry.find(1).project)
490 assert user.allowed_to?(action, TimeEntry.find(1).project)
474 assert ! user.allowed_to?(action, TimeEntry.find(5).project)
491 assert ! user.allowed_to?(action, TimeEntry.find(5).project)
475 post :bulk_update, :ids => [1, 5], :time_entry => { :activity_id => 9 }
492 post :bulk_update, :ids => [1, 5], :time_entry => { :activity_id => 9 }
476 assert_response 403
493 assert_response 403
477 end
494 end
478
495
479 def test_bulk_update_with_edit_own_time_entries_permission
496 def test_bulk_update_with_edit_own_time_entries_permission
480 @request.session[:user_id] = 2
497 @request.session[:user_id] = 2
481 Role.find_by_name('Manager').remove_permission! :edit_time_entries
498 Role.find_by_name('Manager').remove_permission! :edit_time_entries
482 Role.find_by_name('Manager').add_permission! :edit_own_time_entries
499 Role.find_by_name('Manager').add_permission! :edit_own_time_entries
483 ids = (0..1).map {TimeEntry.generate!(:user => User.find(2)).id}
500 ids = (0..1).map {TimeEntry.generate!(:user => User.find(2)).id}
484
501
485 post :bulk_update, :ids => ids, :time_entry => { :activity_id => 9 }
502 post :bulk_update, :ids => ids, :time_entry => { :activity_id => 9 }
486 assert_response 302
503 assert_response 302
487 end
504 end
488
505
489 def test_bulk_update_with_edit_own_time_entries_permissions_should_be_denied_for_time_entries_of_other_user
506 def test_bulk_update_with_edit_own_time_entries_permissions_should_be_denied_for_time_entries_of_other_user
490 @request.session[:user_id] = 2
507 @request.session[:user_id] = 2
491 Role.find_by_name('Manager').remove_permission! :edit_time_entries
508 Role.find_by_name('Manager').remove_permission! :edit_time_entries
492 Role.find_by_name('Manager').add_permission! :edit_own_time_entries
509 Role.find_by_name('Manager').add_permission! :edit_own_time_entries
493
510
494 post :bulk_update, :ids => [1, 2], :time_entry => { :activity_id => 9 }
511 post :bulk_update, :ids => [1, 2], :time_entry => { :activity_id => 9 }
495 assert_response 403
512 assert_response 403
496 end
513 end
497
514
498 def test_bulk_update_custom_field
515 def test_bulk_update_custom_field
499 @request.session[:user_id] = 2
516 @request.session[:user_id] = 2
500 post :bulk_update, :ids => [1, 2], :time_entry => { :custom_field_values => {'10' => '0'} }
517 post :bulk_update, :ids => [1, 2], :time_entry => { :custom_field_values => {'10' => '0'} }
501
518
502 assert_response 302
519 assert_response 302
503 assert_equal ["0", "0"], TimeEntry.where(:id => [1, 2]).collect {|i| i.custom_value_for(10).value}
520 assert_equal ["0", "0"], TimeEntry.where(:id => [1, 2]).collect {|i| i.custom_value_for(10).value}
504 end
521 end
505
522
506 def test_post_bulk_update_should_redirect_back_using_the_back_url_parameter
523 def test_post_bulk_update_should_redirect_back_using_the_back_url_parameter
507 @request.session[:user_id] = 2
524 @request.session[:user_id] = 2
508 post :bulk_update, :ids => [1,2], :back_url => '/time_entries'
525 post :bulk_update, :ids => [1,2], :back_url => '/time_entries'
509
526
510 assert_response :redirect
527 assert_response :redirect
511 assert_redirected_to '/time_entries'
528 assert_redirected_to '/time_entries'
512 end
529 end
513
530
514 def test_post_bulk_update_should_not_redirect_back_using_the_back_url_parameter_off_the_host
531 def test_post_bulk_update_should_not_redirect_back_using_the_back_url_parameter_off_the_host
515 @request.session[:user_id] = 2
532 @request.session[:user_id] = 2
516 post :bulk_update, :ids => [1,2], :back_url => 'http://google.com'
533 post :bulk_update, :ids => [1,2], :back_url => 'http://google.com'
517
534
518 assert_response :redirect
535 assert_response :redirect
519 assert_redirected_to :controller => 'timelog', :action => 'index', :project_id => Project.find(1).identifier
536 assert_redirected_to :controller => 'timelog', :action => 'index', :project_id => Project.find(1).identifier
520 end
537 end
521
538
522 def test_post_bulk_update_without_edit_permission_should_be_denied
539 def test_post_bulk_update_without_edit_permission_should_be_denied
523 @request.session[:user_id] = 2
540 @request.session[:user_id] = 2
524 Role.find_by_name('Manager').remove_permission! :edit_time_entries
541 Role.find_by_name('Manager').remove_permission! :edit_time_entries
525 post :bulk_update, :ids => [1,2]
542 post :bulk_update, :ids => [1,2]
526
543
527 assert_response 403
544 assert_response 403
528 end
545 end
529
546
530 def test_destroy
547 def test_destroy
531 @request.session[:user_id] = 2
548 @request.session[:user_id] = 2
532 delete :destroy, :id => 1
549 delete :destroy, :id => 1
533 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
550 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
534 assert_equal I18n.t(:notice_successful_delete), flash[:notice]
551 assert_equal I18n.t(:notice_successful_delete), flash[:notice]
535 assert_nil TimeEntry.find_by_id(1)
552 assert_nil TimeEntry.find_by_id(1)
536 end
553 end
537
554
538 def test_destroy_should_fail
555 def test_destroy_should_fail
539 # simulate that this fails (e.g. due to a plugin), see #5700
556 # simulate that this fails (e.g. due to a plugin), see #5700
540 TimeEntry.any_instance.expects(:destroy).returns(false)
557 TimeEntry.any_instance.expects(:destroy).returns(false)
541
558
542 @request.session[:user_id] = 2
559 @request.session[:user_id] = 2
543 delete :destroy, :id => 1
560 delete :destroy, :id => 1
544 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
561 assert_redirected_to :action => 'index', :project_id => 'ecookbook'
545 assert_equal I18n.t(:notice_unable_delete_time_entry), flash[:error]
562 assert_equal I18n.t(:notice_unable_delete_time_entry), flash[:error]
546 assert_not_nil TimeEntry.find_by_id(1)
563 assert_not_nil TimeEntry.find_by_id(1)
547 end
564 end
548
565
549 def test_index_all_projects
566 def test_index_all_projects
550 get :index
567 get :index
551 assert_response :success
568 assert_response :success
552 assert_template 'index'
569 assert_template 'index'
553 assert_not_nil assigns(:total_hours)
570 assert_not_nil assigns(:total_hours)
554 assert_equal "162.90", "%.2f" % assigns(:total_hours)
571 assert_equal "162.90", "%.2f" % assigns(:total_hours)
555 assert_select 'form#query_form[action=?]', '/time_entries'
572 assert_select 'form#query_form[action=?]', '/time_entries'
556 end
573 end
557
574
558 def test_index_all_projects_should_show_log_time_link
575 def test_index_all_projects_should_show_log_time_link
559 @request.session[:user_id] = 2
576 @request.session[:user_id] = 2
560 get :index
577 get :index
561 assert_response :success
578 assert_response :success
562 assert_template 'index'
579 assert_template 'index'
563 assert_select 'a[href=?]', '/time_entries/new', :text => /Log time/
580 assert_select 'a[href=?]', '/time_entries/new', :text => /Log time/
564 end
581 end
565
582
566 def test_index_my_spent_time
583 def test_index_my_spent_time
567 @request.session[:user_id] = 2
584 @request.session[:user_id] = 2
568 get :index, :user_id => 'me'
585 get :index, :user_id => 'me'
569 assert_response :success
586 assert_response :success
570 assert_template 'index'
587 assert_template 'index'
571 assert assigns(:entries).all? {|entry| entry.user_id == 2}
588 assert assigns(:entries).all? {|entry| entry.user_id == 2}
572 end
589 end
573
590
574 def test_index_at_project_level
591 def test_index_at_project_level
575 get :index, :project_id => 'ecookbook'
592 get :index, :project_id => 'ecookbook'
576 assert_response :success
593 assert_response :success
577 assert_template 'index'
594 assert_template 'index'
578 assert_not_nil assigns(:entries)
595 assert_not_nil assigns(:entries)
579 assert_equal 4, assigns(:entries).size
596 assert_equal 4, assigns(:entries).size
580 # project and subproject
597 # project and subproject
581 assert_equal [1, 3], assigns(:entries).collect(&:project_id).uniq.sort
598 assert_equal [1, 3], assigns(:entries).collect(&:project_id).uniq.sort
582 assert_not_nil assigns(:total_hours)
599 assert_not_nil assigns(:total_hours)
583 assert_equal "162.90", "%.2f" % assigns(:total_hours)
600 assert_equal "162.90", "%.2f" % assigns(:total_hours)
584 assert_select 'form#query_form[action=?]', '/projects/ecookbook/time_entries'
601 assert_select 'form#query_form[action=?]', '/projects/ecookbook/time_entries'
585 end
602 end
586
603
587 def test_index_with_display_subprojects_issues_to_false_should_not_include_subproject_entries
604 def test_index_with_display_subprojects_issues_to_false_should_not_include_subproject_entries
588 entry = TimeEntry.generate!(:project => Project.find(3))
605 entry = TimeEntry.generate!(:project => Project.find(3))
589
606
590 with_settings :display_subprojects_issues => '0' do
607 with_settings :display_subprojects_issues => '0' do
591 get :index, :project_id => 'ecookbook'
608 get :index, :project_id => 'ecookbook'
592 assert_response :success
609 assert_response :success
593 assert_template 'index'
610 assert_template 'index'
594 assert_not_include entry, assigns(:entries)
611 assert_not_include entry, assigns(:entries)
595 end
612 end
596 end
613 end
597
614
598 def test_index_with_display_subprojects_issues_to_false_and_subproject_filter_should_include_subproject_entries
615 def test_index_with_display_subprojects_issues_to_false_and_subproject_filter_should_include_subproject_entries
599 entry = TimeEntry.generate!(:project => Project.find(3))
616 entry = TimeEntry.generate!(:project => Project.find(3))
600
617
601 with_settings :display_subprojects_issues => '0' do
618 with_settings :display_subprojects_issues => '0' do
602 get :index, :project_id => 'ecookbook', :subproject_id => 3
619 get :index, :project_id => 'ecookbook', :subproject_id => 3
603 assert_response :success
620 assert_response :success
604 assert_template 'index'
621 assert_template 'index'
605 assert_include entry, assigns(:entries)
622 assert_include entry, assigns(:entries)
606 end
623 end
607 end
624 end
608
625
609 def test_index_at_project_level_with_date_range
626 def test_index_at_project_level_with_date_range
610 get :index, :project_id => 'ecookbook',
627 get :index, :project_id => 'ecookbook',
611 :f => ['spent_on'],
628 :f => ['spent_on'],
612 :op => {'spent_on' => '><'},
629 :op => {'spent_on' => '><'},
613 :v => {'spent_on' => ['2007-03-20', '2007-04-30']}
630 :v => {'spent_on' => ['2007-03-20', '2007-04-30']}
614 assert_response :success
631 assert_response :success
615 assert_template 'index'
632 assert_template 'index'
616 assert_not_nil assigns(:entries)
633 assert_not_nil assigns(:entries)
617 assert_equal 3, assigns(:entries).size
634 assert_equal 3, assigns(:entries).size
618 assert_not_nil assigns(:total_hours)
635 assert_not_nil assigns(:total_hours)
619 assert_equal "12.90", "%.2f" % assigns(:total_hours)
636 assert_equal "12.90", "%.2f" % assigns(:total_hours)
620 assert_select 'form#query_form[action=?]', '/projects/ecookbook/time_entries'
637 assert_select 'form#query_form[action=?]', '/projects/ecookbook/time_entries'
621 end
638 end
622
639
623 def test_index_at_project_level_with_date_range_using_from_and_to_params
640 def test_index_at_project_level_with_date_range_using_from_and_to_params
624 get :index, :project_id => 'ecookbook', :from => '2007-03-20', :to => '2007-04-30'
641 get :index, :project_id => 'ecookbook', :from => '2007-03-20', :to => '2007-04-30'
625 assert_response :success
642 assert_response :success
626 assert_template 'index'
643 assert_template 'index'
627 assert_not_nil assigns(:entries)
644 assert_not_nil assigns(:entries)
628 assert_equal 3, assigns(:entries).size
645 assert_equal 3, assigns(:entries).size
629 assert_not_nil assigns(:total_hours)
646 assert_not_nil assigns(:total_hours)
630 assert_equal "12.90", "%.2f" % assigns(:total_hours)
647 assert_equal "12.90", "%.2f" % assigns(:total_hours)
631 assert_select 'form#query_form[action=?]', '/projects/ecookbook/time_entries'
648 assert_select 'form#query_form[action=?]', '/projects/ecookbook/time_entries'
632 end
649 end
633
650
634 def test_index_at_project_level_with_period
651 def test_index_at_project_level_with_period
635 get :index, :project_id => 'ecookbook',
652 get :index, :project_id => 'ecookbook',
636 :f => ['spent_on'],
653 :f => ['spent_on'],
637 :op => {'spent_on' => '>t-'},
654 :op => {'spent_on' => '>t-'},
638 :v => {'spent_on' => ['7']}
655 :v => {'spent_on' => ['7']}
639 assert_response :success
656 assert_response :success
640 assert_template 'index'
657 assert_template 'index'
641 assert_not_nil assigns(:entries)
658 assert_not_nil assigns(:entries)
642 assert_not_nil assigns(:total_hours)
659 assert_not_nil assigns(:total_hours)
643 assert_select 'form#query_form[action=?]', '/projects/ecookbook/time_entries'
660 assert_select 'form#query_form[action=?]', '/projects/ecookbook/time_entries'
644 end
661 end
645
662
646 def test_index_at_issue_level
663 def test_index_at_issue_level
647 get :index, :issue_id => 1
664 get :index, :issue_id => 1
648 assert_response :success
665 assert_response :success
649 assert_template 'index'
666 assert_template 'index'
650 assert_not_nil assigns(:entries)
667 assert_not_nil assigns(:entries)
651 assert_equal 2, assigns(:entries).size
668 assert_equal 2, assigns(:entries).size
652 assert_not_nil assigns(:total_hours)
669 assert_not_nil assigns(:total_hours)
653 assert_equal 154.25, assigns(:total_hours)
670 assert_equal 154.25, assigns(:total_hours)
654 # display all time
671 # display all time
655 assert_nil assigns(:from)
672 assert_nil assigns(:from)
656 assert_nil assigns(:to)
673 assert_nil assigns(:to)
657 assert_select 'form#query_form[action=?]', '/issues/1/time_entries'
674 assert_select 'form#query_form[action=?]', '/issues/1/time_entries'
658 end
675 end
659
676
660 def test_index_should_sort_by_spent_on_and_created_on
677 def test_index_should_sort_by_spent_on_and_created_on
661 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)
678 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)
662 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)
679 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)
663 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)
680 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)
664
681
665 get :index, :project_id => 1,
682 get :index, :project_id => 1,
666 :f => ['spent_on'],
683 :f => ['spent_on'],
667 :op => {'spent_on' => '><'},
684 :op => {'spent_on' => '><'},
668 :v => {'spent_on' => ['2012-06-15', '2012-06-16']}
685 :v => {'spent_on' => ['2012-06-15', '2012-06-16']}
669 assert_response :success
686 assert_response :success
670 assert_equal [t2, t1, t3], assigns(:entries)
687 assert_equal [t2, t1, t3], assigns(:entries)
671
688
672 get :index, :project_id => 1,
689 get :index, :project_id => 1,
673 :f => ['spent_on'],
690 :f => ['spent_on'],
674 :op => {'spent_on' => '><'},
691 :op => {'spent_on' => '><'},
675 :v => {'spent_on' => ['2012-06-15', '2012-06-16']},
692 :v => {'spent_on' => ['2012-06-15', '2012-06-16']},
676 :sort => 'spent_on'
693 :sort => 'spent_on'
677 assert_response :success
694 assert_response :success
678 assert_equal [t3, t1, t2], assigns(:entries)
695 assert_equal [t3, t1, t2], assigns(:entries)
679 end
696 end
680
697
681 def test_index_with_filter_on_issue_custom_field
698 def test_index_with_filter_on_issue_custom_field
682 issue = Issue.generate!(:project_id => 1, :tracker_id => 1, :custom_field_values => {2 => 'filter_on_issue_custom_field'})
699 issue = Issue.generate!(:project_id => 1, :tracker_id => 1, :custom_field_values => {2 => 'filter_on_issue_custom_field'})
683 entry = TimeEntry.generate!(:issue => issue, :hours => 2.5)
700 entry = TimeEntry.generate!(:issue => issue, :hours => 2.5)
684
701
685 get :index, :f => ['issue.cf_2'], :op => {'issue.cf_2' => '='}, :v => {'issue.cf_2' => ['filter_on_issue_custom_field']}
702 get :index, :f => ['issue.cf_2'], :op => {'issue.cf_2' => '='}, :v => {'issue.cf_2' => ['filter_on_issue_custom_field']}
686 assert_response :success
703 assert_response :success
687 assert_equal [entry], assigns(:entries)
704 assert_equal [entry], assigns(:entries)
688 end
705 end
689
706
690 def test_index_with_issue_custom_field_column
707 def test_index_with_issue_custom_field_column
691 issue = Issue.generate!(:project_id => 1, :tracker_id => 1, :custom_field_values => {2 => 'filter_on_issue_custom_field'})
708 issue = Issue.generate!(:project_id => 1, :tracker_id => 1, :custom_field_values => {2 => 'filter_on_issue_custom_field'})
692 entry = TimeEntry.generate!(:issue => issue, :hours => 2.5)
709 entry = TimeEntry.generate!(:issue => issue, :hours => 2.5)
693
710
694 get :index, :c => %w(project spent_on issue comments hours issue.cf_2)
711 get :index, :c => %w(project spent_on issue comments hours issue.cf_2)
695 assert_response :success
712 assert_response :success
696 assert_include :'issue.cf_2', assigns(:query).column_names
713 assert_include :'issue.cf_2', assigns(:query).column_names
697 assert_select 'td.issue_cf_2', :text => 'filter_on_issue_custom_field'
714 assert_select 'td.issue_cf_2', :text => 'filter_on_issue_custom_field'
698 end
715 end
699
716
700 def test_index_with_time_entry_custom_field_column
717 def test_index_with_time_entry_custom_field_column
701 field = TimeEntryCustomField.generate!(:field_format => 'string')
718 field = TimeEntryCustomField.generate!(:field_format => 'string')
702 entry = TimeEntry.generate!(:hours => 2.5, :custom_field_values => {field.id => 'CF Value'})
719 entry = TimeEntry.generate!(:hours => 2.5, :custom_field_values => {field.id => 'CF Value'})
703 field_name = "cf_#{field.id}"
720 field_name = "cf_#{field.id}"
704
721
705 get :index, :c => ["hours", field_name]
722 get :index, :c => ["hours", field_name]
706 assert_response :success
723 assert_response :success
707 assert_include field_name.to_sym, assigns(:query).column_names
724 assert_include field_name.to_sym, assigns(:query).column_names
708 assert_select "td.#{field_name}", :text => 'CF Value'
725 assert_select "td.#{field_name}", :text => 'CF Value'
709 end
726 end
710
727
711 def test_index_with_time_entry_custom_field_sorting
728 def test_index_with_time_entry_custom_field_sorting
712 field = TimeEntryCustomField.generate!(:field_format => 'string', :name => 'String Field')
729 field = TimeEntryCustomField.generate!(:field_format => 'string', :name => 'String Field')
713 TimeEntry.generate!(:hours => 2.5, :custom_field_values => {field.id => 'CF Value 1'})
730 TimeEntry.generate!(:hours => 2.5, :custom_field_values => {field.id => 'CF Value 1'})
714 TimeEntry.generate!(:hours => 2.5, :custom_field_values => {field.id => 'CF Value 3'})
731 TimeEntry.generate!(:hours => 2.5, :custom_field_values => {field.id => 'CF Value 3'})
715 TimeEntry.generate!(:hours => 2.5, :custom_field_values => {field.id => 'CF Value 2'})
732 TimeEntry.generate!(:hours => 2.5, :custom_field_values => {field.id => 'CF Value 2'})
716 field_name = "cf_#{field.id}"
733 field_name = "cf_#{field.id}"
717
734
718 get :index, :c => ["hours", field_name], :sort => field_name
735 get :index, :c => ["hours", field_name], :sort => field_name
719 assert_response :success
736 assert_response :success
720 assert_include field_name.to_sym, assigns(:query).column_names
737 assert_include field_name.to_sym, assigns(:query).column_names
721 assert_select "th a.sort", :text => 'String Field'
738 assert_select "th a.sort", :text => 'String Field'
722
739
723 # Make sure that values are properly sorted
740 # Make sure that values are properly sorted
724 values = assigns(:entries).map {|e| e.custom_field_value(field)}.compact
741 values = assigns(:entries).map {|e| e.custom_field_value(field)}.compact
725 assert_equal 3, values.size
742 assert_equal 3, values.size
726 assert_equal values.sort, values
743 assert_equal values.sort, values
727 end
744 end
728
745
729 def test_index_atom_feed
746 def test_index_atom_feed
730 get :index, :project_id => 1, :format => 'atom'
747 get :index, :project_id => 1, :format => 'atom'
731 assert_response :success
748 assert_response :success
732 assert_equal 'application/atom+xml', @response.content_type
749 assert_equal 'application/atom+xml', @response.content_type
733 assert_not_nil assigns(:items)
750 assert_not_nil assigns(:items)
734 assert assigns(:items).first.is_a?(TimeEntry)
751 assert assigns(:items).first.is_a?(TimeEntry)
735 end
752 end
736
753
737 def test_index_at_project_level_should_include_csv_export_dialog
754 def test_index_at_project_level_should_include_csv_export_dialog
738 get :index, :project_id => 'ecookbook',
755 get :index, :project_id => 'ecookbook',
739 :f => ['spent_on'],
756 :f => ['spent_on'],
740 :op => {'spent_on' => '>='},
757 :op => {'spent_on' => '>='},
741 :v => {'spent_on' => ['2007-04-01']},
758 :v => {'spent_on' => ['2007-04-01']},
742 :c => ['spent_on', 'user']
759 :c => ['spent_on', 'user']
743 assert_response :success
760 assert_response :success
744
761
745 assert_select '#csv-export-options' do
762 assert_select '#csv-export-options' do
746 assert_select 'form[action=?][method=get]', '/projects/ecookbook/time_entries.csv' do
763 assert_select 'form[action=?][method=get]', '/projects/ecookbook/time_entries.csv' do
747 # filter
764 # filter
748 assert_select 'input[name=?][value=?]', 'f[]', 'spent_on'
765 assert_select 'input[name=?][value=?]', 'f[]', 'spent_on'
749 assert_select 'input[name=?][value=?]', 'op[spent_on]', '>='
766 assert_select 'input[name=?][value=?]', 'op[spent_on]', '>='
750 assert_select 'input[name=?][value=?]', 'v[spent_on][]', '2007-04-01'
767 assert_select 'input[name=?][value=?]', 'v[spent_on][]', '2007-04-01'
751 # columns
768 # columns
752 assert_select 'input[name=?][value=?]', 'c[]', 'spent_on'
769 assert_select 'input[name=?][value=?]', 'c[]', 'spent_on'
753 assert_select 'input[name=?][value=?]', 'c[]', 'user'
770 assert_select 'input[name=?][value=?]', 'c[]', 'user'
754 assert_select 'input[name=?]', 'c[]', 2
771 assert_select 'input[name=?]', 'c[]', 2
755 end
772 end
756 end
773 end
757 end
774 end
758
775
759 def test_index_cross_project_should_include_csv_export_dialog
776 def test_index_cross_project_should_include_csv_export_dialog
760 get :index
777 get :index
761 assert_response :success
778 assert_response :success
762
779
763 assert_select '#csv-export-options' do
780 assert_select '#csv-export-options' do
764 assert_select 'form[action=?][method=get]', '/time_entries.csv'
781 assert_select 'form[action=?][method=get]', '/time_entries.csv'
765 end
782 end
766 end
783 end
767
784
768 def test_index_at_issue_level_should_include_csv_export_dialog
785 def test_index_at_issue_level_should_include_csv_export_dialog
769 get :index, :issue_id => 3
786 get :index, :issue_id => 3
770 assert_response :success
787 assert_response :success
771
788
772 assert_select '#csv-export-options' do
789 assert_select '#csv-export-options' do
773 assert_select 'form[action=?][method=get]', '/issues/3/time_entries.csv'
790 assert_select 'form[action=?][method=get]', '/issues/3/time_entries.csv'
774 end
791 end
775 end
792 end
776
793
777 def test_index_csv_all_projects
794 def test_index_csv_all_projects
778 with_settings :date_format => '%m/%d/%Y' do
795 with_settings :date_format => '%m/%d/%Y' do
779 get :index, :format => 'csv'
796 get :index, :format => 'csv'
780 assert_response :success
797 assert_response :success
781 assert_equal 'text/csv; header=present', response.content_type
798 assert_equal 'text/csv; header=present', response.content_type
782 end
799 end
783 end
800 end
784
801
785 def test_index_csv
802 def test_index_csv
786 with_settings :date_format => '%m/%d/%Y' do
803 with_settings :date_format => '%m/%d/%Y' do
787 get :index, :project_id => 1, :format => 'csv'
804 get :index, :project_id => 1, :format => 'csv'
788 assert_response :success
805 assert_response :success
789 assert_equal 'text/csv; header=present', response.content_type
806 assert_equal 'text/csv; header=present', response.content_type
790 end
807 end
791 end
808 end
792
809
793 def test_index_csv_should_fill_issue_column_with_tracker_id_and_subject
810 def test_index_csv_should_fill_issue_column_with_tracker_id_and_subject
794 issue = Issue.find(1)
811 issue = Issue.find(1)
795 entry = TimeEntry.generate!(:issue => issue, :comments => "Issue column content test")
812 entry = TimeEntry.generate!(:issue => issue, :comments => "Issue column content test")
796
813
797 get :index, :format => 'csv'
814 get :index, :format => 'csv'
798 line = response.body.split("\n").detect {|l| l.include?(entry.comments)}
815 line = response.body.split("\n").detect {|l| l.include?(entry.comments)}
799 assert_not_nil line
816 assert_not_nil line
800 assert_include "#{issue.tracker} #1: #{issue.subject}", line
817 assert_include "#{issue.tracker} #1: #{issue.subject}", line
801 end
818 end
802 end
819 end
General Comments 0
You need to be logged in to leave comments. Login now