You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

timelog_controller_test.rb 41KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239
  1. # -*- coding: utf-8 -*-
  2. # Redmine - project management software
  3. # Copyright (C) 2006-2017 Jean-Philippe Lang
  4. #
  5. # This program is free software; you can redistribute it and/or
  6. # modify it under the terms of the GNU General Public License
  7. # as published by the Free Software Foundation; either version 2
  8. # of the License, or (at your option) any later version.
  9. #
  10. # This program is distributed in the hope that it will be useful,
  11. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. # GNU General Public License for more details.
  14. #
  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
  17. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  18. require File.expand_path('../../test_helper', __FILE__)
  19. class TimelogControllerTest < Redmine::ControllerTest
  20. fixtures :projects, :enabled_modules, :roles, :members,
  21. :member_roles, :issues, :time_entries, :users,
  22. :trackers, :enumerations, :issue_statuses,
  23. :custom_fields, :custom_values,
  24. :projects_trackers, :custom_fields_trackers,
  25. :custom_fields_projects
  26. include Redmine::I18n
  27. def setup
  28. super
  29. Setting.default_language = 'en'
  30. end
  31. def test_new
  32. @request.session[:user_id] = 3
  33. get :new
  34. assert_response :success
  35. assert_select 'input[name=?][type=hidden]', 'project_id', 0
  36. assert_select 'input[name=?][type=hidden]', 'issue_id', 0
  37. assert_select 'span[id=?]', 'time_entry_issue'
  38. assert_select 'select[name=?]', 'time_entry[project_id]' do
  39. # blank option for project
  40. assert_select 'option[value=""]'
  41. end
  42. end
  43. def test_new_with_project_id
  44. @request.session[:user_id] = 3
  45. get :new, :params => {:project_id => 1}
  46. assert_response :success
  47. assert_select 'input[name=?][type=hidden]', 'project_id'
  48. assert_select 'input[name=?][type=hidden]', 'issue_id', 0
  49. assert_select 'select[name=?]', 'time_entry[project_id]', 0
  50. end
  51. def test_new_with_issue_id
  52. @request.session[:user_id] = 3
  53. get :new, :params => {:issue_id => 2}
  54. assert_response :success
  55. assert_select 'input[name=?][type=hidden]', 'project_id', 0
  56. assert_select 'input[name=?][type=hidden]', 'issue_id'
  57. assert_select 'a[href=?]', '/issues/2', :text => /Feature request #2/
  58. assert_select 'select[name=?]', 'time_entry[project_id]', 0
  59. end
  60. def test_new_without_project_should_prefill_the_form
  61. @request.session[:user_id] = 3
  62. get :new, :params => {:time_entry => {:project_id => '1'}}
  63. assert_response :success
  64. assert_select 'select[name=?]', 'time_entry[project_id]' do
  65. assert_select 'option[value="1"][selected=selected]'
  66. end
  67. end
  68. def test_new_without_project_should_deny_without_permission
  69. Role.all.each {|role| role.remove_permission! :log_time}
  70. @request.session[:user_id] = 3
  71. get :new
  72. assert_response 403
  73. end
  74. def test_new_should_select_default_activity
  75. @request.session[:user_id] = 3
  76. get :new, :params => {:project_id => 1}
  77. assert_response :success
  78. assert_select 'select[name=?]', 'time_entry[activity_id]' do
  79. assert_select 'option[selected=selected]', :text => 'Development'
  80. end
  81. end
  82. def test_new_should_only_show_active_time_entry_activities
  83. @request.session[:user_id] = 3
  84. get :new, :params => {:project_id => 1}
  85. assert_response :success
  86. assert_select 'option', :text => 'Inactive Activity', :count => 0
  87. end
  88. def test_post_new_as_js_should_update_activity_options
  89. @request.session[:user_id] = 3
  90. post :new, :params => {:time_entry => {:project_id => 1}, :format => 'js'}
  91. assert_response :success
  92. assert_include '#time_entry_activity_id', response.body
  93. end
  94. def test_get_edit_existing_time
  95. @request.session[:user_id] = 2
  96. get :edit, :params => {:id => 2, :project_id => nil}
  97. assert_response :success
  98. assert_select 'form[action=?]', '/time_entries/2'
  99. end
  100. def test_get_edit_with_an_existing_time_entry_with_inactive_activity
  101. te = TimeEntry.find(1)
  102. te.activity = TimeEntryActivity.find_by_name("Inactive Activity")
  103. te.save!(:validate => false)
  104. @request.session[:user_id] = 1
  105. get :edit, :params => {:project_id => 1, :id => 1}
  106. assert_response :success
  107. # Blank option since nothing is pre-selected
  108. assert_select 'option', :text => '--- Please select ---'
  109. end
  110. def test_get_edit_should_show_projects_select
  111. @request.session[:user_id] = 2
  112. get :edit, :params => {:id => 2, :project_id => nil}
  113. assert_response :success
  114. assert_select 'select[name=?]', 'time_entry[project_id]'
  115. end
  116. def test_post_create
  117. @request.session[:user_id] = 3
  118. assert_difference 'TimeEntry.count' do
  119. post :create, :params => {
  120. :project_id => 1,
  121. :time_entry => {:comments => 'Some work on TimelogControllerTest',
  122. # Not the default activity
  123. :activity_id => '11',
  124. :spent_on => '2008-03-14',
  125. :issue_id => '1',
  126. :hours => '7.3'
  127. }
  128. }
  129. assert_redirected_to '/projects/ecookbook/time_entries'
  130. end
  131. t = TimeEntry.order('id DESC').first
  132. assert_not_nil t
  133. assert_equal 'Some work on TimelogControllerTest', t.comments
  134. assert_equal 1, t.project_id
  135. assert_equal 1, t.issue_id
  136. assert_equal 11, t.activity_id
  137. assert_equal 7.3, t.hours
  138. assert_equal 3, t.user_id
  139. end
  140. def test_post_create_with_blank_issue
  141. @request.session[:user_id] = 3
  142. assert_difference 'TimeEntry.count' do
  143. post :create, :params => {
  144. :project_id => 1,
  145. :time_entry => {
  146. :comments => 'Some work on TimelogControllerTest',
  147. # Not the default activity
  148. :activity_id => '11',
  149. :issue_id => '',
  150. :spent_on => '2008-03-14',
  151. :hours => '7.3'
  152. }
  153. }
  154. assert_redirected_to '/projects/ecookbook/time_entries'
  155. end
  156. t = TimeEntry.order('id DESC').first
  157. assert_not_nil t
  158. assert_equal 'Some work on TimelogControllerTest', t.comments
  159. assert_equal 1, t.project_id
  160. assert_nil t.issue_id
  161. assert_equal 11, t.activity_id
  162. assert_equal 7.3, t.hours
  163. assert_equal 3, t.user_id
  164. end
  165. def test_create_on_project_with_time_tracking_disabled_should_fail
  166. Project.find(1).disable_module! :time_tracking
  167. @request.session[:user_id] = 2
  168. assert_no_difference 'TimeEntry.count' do
  169. post :create, :params => {
  170. :time_entry => {
  171. :project_id => '1', :issue_id => '',
  172. :activity_id => '11', :spent_on => '2008-03-14', :hours => '7.3'
  173. }
  174. }
  175. end
  176. end
  177. def test_create_on_project_without_permission_should_fail
  178. Role.find(1).remove_permission! :log_time
  179. @request.session[:user_id] = 2
  180. assert_no_difference 'TimeEntry.count' do
  181. post :create, :params => {
  182. :time_entry => {
  183. :project_id => '1', :issue_id => '',
  184. :activity_id => '11', :spent_on => '2008-03-14', :hours => '7.3'
  185. }
  186. }
  187. end
  188. end
  189. def test_create_on_issue_in_project_with_time_tracking_disabled_should_fail
  190. Project.find(1).disable_module! :time_tracking
  191. @request.session[:user_id] = 2
  192. assert_no_difference 'TimeEntry.count' do
  193. post :create, :params => {
  194. :time_entry => {
  195. :project_id => '', :issue_id => '1',
  196. :activity_id => '11', :spent_on => '2008-03-14', :hours => '7.3'
  197. }
  198. }
  199. assert_select_error /Issue is invalid/
  200. end
  201. end
  202. def test_create_on_issue_in_project_without_permission_should_fail
  203. Role.find(1).remove_permission! :log_time
  204. @request.session[:user_id] = 2
  205. assert_no_difference 'TimeEntry.count' do
  206. post :create, :params => {
  207. :time_entry => {
  208. :project_id => '', :issue_id => '1',
  209. :activity_id => '11', :spent_on => '2008-03-14', :hours => '7.3'
  210. }
  211. }
  212. assert_select_error /Issue is invalid/
  213. end
  214. end
  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. @request.session[:user_id] = 3
  219. assert_no_difference 'TimeEntry.count' do
  220. post :create, :params => {
  221. :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. }
  226. end
  227. assert_select_error /Issue is invalid/
  228. assert_select "input[name=?][value=?]", "time_entry[issue_id]", issue.id.to_s
  229. assert_select "#time_entry_issue a", 0
  230. assert !response.body.include?('issue_that_is_not_visible')
  231. end
  232. def test_create_and_continue_at_project_level
  233. @request.session[:user_id] = 2
  234. assert_difference 'TimeEntry.count' do
  235. post :create, :params => {
  236. :time_entry => {
  237. :project_id => '1',
  238. :activity_id => '11',
  239. :issue_id => '',
  240. :spent_on => '2008-03-14',
  241. :hours => '7.3'
  242. },
  243. :continue => '1'
  244. }
  245. 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'
  246. end
  247. end
  248. def test_create_and_continue_at_issue_level
  249. @request.session[:user_id] = 2
  250. assert_difference 'TimeEntry.count' do
  251. post :create, :params => {
  252. :time_entry => {
  253. :project_id => '',
  254. :activity_id => '11',
  255. :issue_id => '1',
  256. :spent_on => '2008-03-14',
  257. :hours => '7.3'
  258. },
  259. :continue => '1'
  260. }
  261. 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'
  262. end
  263. end
  264. def test_create_and_continue_with_project_id
  265. @request.session[:user_id] = 2
  266. assert_difference 'TimeEntry.count' do
  267. post :create, :params => {
  268. :project_id => 1,
  269. :time_entry => {
  270. :activity_id => '11',
  271. :issue_id => '',
  272. :spent_on => '2008-03-14',
  273. :hours => '7.3'
  274. },
  275. :continue => '1'
  276. }
  277. 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'
  278. end
  279. end
  280. def test_create_and_continue_with_issue_id
  281. @request.session[:user_id] = 2
  282. assert_difference 'TimeEntry.count' do
  283. post :create, :params => {
  284. :issue_id => 1,
  285. :time_entry => {
  286. :activity_id => '11',
  287. :issue_id => '1',
  288. :spent_on => '2008-03-14',
  289. :hours => '7.3'
  290. },
  291. :continue => '1'
  292. }
  293. 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'
  294. end
  295. end
  296. def test_create_without_log_time_permission_should_be_denied
  297. @request.session[:user_id] = 2
  298. Role.find_by_name('Manager').remove_permission! :log_time
  299. post :create, :params => {
  300. :project_id => 1,
  301. :time_entry => {
  302. :activity_id => '11',
  303. :issue_id => '',
  304. :spent_on => '2008-03-14',
  305. :hours => '7.3'
  306. }
  307. }
  308. assert_response 403
  309. end
  310. def test_create_without_project_and_issue_should_fail
  311. @request.session[:user_id] = 2
  312. post :create, :params => {:time_entry => {:issue_id => ''}}
  313. assert_response :success
  314. assert_select_error /Project cannot be blank/
  315. end
  316. def test_create_with_failure
  317. @request.session[:user_id] = 2
  318. post :create, :params => {
  319. :project_id => 1,
  320. :time_entry => {
  321. :activity_id => '',
  322. :issue_id => '',
  323. :spent_on => '2008-03-14',
  324. :hours => '7.3'
  325. }
  326. }
  327. assert_response :success
  328. end
  329. def test_create_without_project
  330. @request.session[:user_id] = 2
  331. assert_difference 'TimeEntry.count' do
  332. post :create, :params => {
  333. :time_entry => {
  334. :project_id => '1',
  335. :activity_id => '11',
  336. :issue_id => '',
  337. :spent_on => '2008-03-14',
  338. :hours => '7.3'
  339. }
  340. }
  341. end
  342. assert_redirected_to '/projects/ecookbook/time_entries'
  343. time_entry = TimeEntry.order('id DESC').first
  344. assert_equal 1, time_entry.project_id
  345. end
  346. def test_create_without_project_should_fail_with_issue_not_inside_project
  347. @request.session[:user_id] = 2
  348. assert_no_difference 'TimeEntry.count' do
  349. post :create, :params => {
  350. :time_entry => {
  351. :project_id => '1',
  352. :activity_id => '11',
  353. :issue_id => '5',
  354. :spent_on => '2008-03-14',
  355. :hours => '7.3'
  356. }
  357. }
  358. end
  359. assert_response :success
  360. assert_select_error /Issue is invalid/
  361. end
  362. def test_create_without_project_should_deny_without_permission
  363. @request.session[:user_id] = 2
  364. Project.find(3).disable_module!(:time_tracking)
  365. assert_no_difference 'TimeEntry.count' do
  366. post :create, :params => {
  367. :time_entry => {
  368. :project_id => '3',
  369. :activity_id => '11',
  370. :issue_id => '',
  371. :spent_on => '2008-03-14',
  372. :hours => '7.3'
  373. }
  374. }
  375. end
  376. assert_response 403
  377. end
  378. def test_create_without_project_with_failure
  379. @request.session[:user_id] = 2
  380. assert_no_difference 'TimeEntry.count' do
  381. post :create, :params => {
  382. :time_entry => {
  383. :project_id => '1',
  384. :activity_id => '11',
  385. :issue_id => '',
  386. :spent_on => '2008-03-14',
  387. :hours => ''
  388. }
  389. }
  390. end
  391. assert_response :success
  392. assert_select 'select[name=?]', 'time_entry[project_id]' do
  393. assert_select 'option[value="1"][selected=selected]'
  394. end
  395. end
  396. def test_update
  397. entry = TimeEntry.find(1)
  398. assert_equal 1, entry.issue_id
  399. assert_equal 2, entry.user_id
  400. @request.session[:user_id] = 1
  401. put :update, :params => {
  402. :id => 1,
  403. :time_entry => {
  404. :issue_id => '2',
  405. :hours => '8'
  406. }
  407. }
  408. assert_redirected_to :action => 'index', :project_id => 'ecookbook'
  409. entry.reload
  410. assert_equal 8, entry.hours
  411. assert_equal 2, entry.issue_id
  412. assert_equal 2, entry.user_id
  413. end
  414. def test_update_should_allow_to_change_issue_to_another_project
  415. entry = TimeEntry.generate!(:issue_id => 1)
  416. @request.session[:user_id] = 1
  417. put :update, :params => {
  418. :id => entry.id,
  419. :time_entry => {
  420. :issue_id => '5'
  421. }
  422. }
  423. assert_response 302
  424. entry.reload
  425. assert_equal 5, entry.issue_id
  426. assert_equal 3, entry.project_id
  427. end
  428. def test_update_should_not_allow_to_change_issue_to_an_invalid_project
  429. entry = TimeEntry.generate!(:issue_id => 1)
  430. Project.find(3).disable_module!(:time_tracking)
  431. @request.session[:user_id] = 1
  432. put :update, :params => {
  433. :id => entry.id,
  434. :time_entry => {
  435. :issue_id => '5'
  436. }
  437. }
  438. assert_response :success
  439. assert_select_error /Issue is invalid/
  440. end
  441. def test_update_should_allow_to_change_project
  442. entry = TimeEntry.generate!(:project_id => 1)
  443. @request.session[:user_id] = 1
  444. put :update, :params => {
  445. :id => entry.id,
  446. :time_entry => {
  447. :project_id => '2'
  448. }
  449. }
  450. assert_response 302
  451. entry.reload
  452. assert_equal 2, entry.project_id
  453. end
  454. def test_update_should_fail_with_issue_from_another_project
  455. entry = TimeEntry.generate!(:project_id => 1, :issue_id => 1)
  456. @request.session[:user_id] = 1
  457. put :update, :params => {
  458. :id => entry.id,
  459. :time_entry => {
  460. :project_id => '2'
  461. }
  462. }
  463. assert_response :success
  464. assert_select_error /Issue is invalid/
  465. end
  466. def test_get_bulk_edit
  467. @request.session[:user_id] = 2
  468. get :bulk_edit, :params => {:ids => [1, 2]}
  469. assert_response :success
  470. assert_select 'ul#bulk-selection' do
  471. assert_select 'li', 2
  472. assert_select 'li a', :text => '03/23/2007 - eCookbook: 4.25 hours'
  473. end
  474. assert_select 'form#bulk_edit_form[action=?]', '/time_entries/bulk_update' do
  475. assert_select 'select[name=?]', 'time_entry[project_id]'
  476. # Clear issue checkbox
  477. assert_select 'input[name=?][value=?]', 'time_entry[issue_id]', 'none'
  478. # System wide custom field
  479. assert_select 'select[name=?]', 'time_entry[custom_field_values][10]'
  480. # Activities
  481. assert_select 'select[name=?]', 'time_entry[activity_id]' do
  482. assert_select 'option[value=""]', :text => '(No change)'
  483. assert_select 'option[value="9"]', :text => 'Design'
  484. end
  485. end
  486. end
  487. def test_get_bulk_edit_on_different_projects
  488. @request.session[:user_id] = 2
  489. get :bulk_edit, :params => {:ids => [1, 2, 6]}
  490. assert_response :success
  491. end
  492. def test_get_bulk_edit_on_different_projects_should_propose_only_common_activites
  493. project = Project.find(3)
  494. TimeEntryActivity.create!(:name => 'QA', :project => project, :parent => TimeEntryActivity.find_by_name('QA'), :active => false)
  495. @request.session[:user_id] = 1
  496. get :bulk_edit, :params => {:ids => [1, 2, 4]}
  497. assert_response :success
  498. assert_select 'select[id=?]', 'time_entry_activity_id' do
  499. assert_select 'option', 3
  500. assert_select 'option[value=?]', '11', 0, :text => 'QA'
  501. end
  502. end
  503. def test_get_bulk_edit_on_same_project_should_propose_project_activities
  504. project = Project.find(1)
  505. override_activity = TimeEntryActivity.create!({:name => "QA override", :parent => TimeEntryActivity.find_by_name("QA"), :project => project})
  506. @request.session[:user_id] = 1
  507. get :bulk_edit, :params => {:ids => [1, 2]}
  508. assert_response :success
  509. assert_select 'select[id=?]', 'time_entry_activity_id' do
  510. assert_select 'option', 4
  511. assert_select 'option[value=?]', override_activity.id.to_s, :text => 'QA override'
  512. end
  513. end
  514. def test_bulk_edit_with_edit_own_time_entries_permission
  515. @request.session[:user_id] = 2
  516. Role.find_by_name('Manager').remove_permission! :edit_time_entries
  517. Role.find_by_name('Manager').add_permission! :edit_own_time_entries
  518. ids = (0..1).map {TimeEntry.generate!(:user => User.find(2)).id}
  519. get :bulk_edit, :params => {:ids => ids}
  520. assert_response :success
  521. end
  522. def test_bulk_update
  523. @request.session[:user_id] = 2
  524. # update time entry activity
  525. post :bulk_update, :params => {:ids => [1, 2], :time_entry => { :activity_id => 9}}
  526. assert_response 302
  527. # check that the issues were updated
  528. assert_equal [9, 9], TimeEntry.where(:id => [1, 2]).collect {|i| i.activity_id}
  529. end
  530. def test_bulk_update_with_failure
  531. @request.session[:user_id] = 2
  532. post :bulk_update, :params => {:ids => [1, 2], :time_entry => { :hours => 'A'}}
  533. assert_response :success
  534. assert_select_error /Failed to save 2 time entrie/
  535. end
  536. def test_bulk_update_on_different_projects
  537. @request.session[:user_id] = 2
  538. # makes user a manager on the other project
  539. Member.create!(:user_id => 2, :project_id => 3, :role_ids => [1])
  540. # update time entry activity
  541. post :bulk_update, :params => {:ids => [1, 2, 4], :time_entry => { :activity_id => 9 }}
  542. assert_response 302
  543. # check that the issues were updated
  544. assert_equal [9, 9, 9], TimeEntry.where(:id => [1, 2, 4]).collect {|i| i.activity_id}
  545. end
  546. def test_bulk_update_on_different_projects_without_rights
  547. @request.session[:user_id] = 3
  548. user = User.find(3)
  549. action = { :controller => "timelog", :action => "bulk_update" }
  550. assert user.allowed_to?(action, TimeEntry.find(1).project)
  551. assert ! user.allowed_to?(action, TimeEntry.find(5).project)
  552. post :bulk_update, :params => {:ids => [1, 5], :time_entry => { :activity_id => 9 }}
  553. assert_response 403
  554. end
  555. def test_bulk_update_with_edit_own_time_entries_permission
  556. @request.session[:user_id] = 2
  557. Role.find_by_name('Manager').remove_permission! :edit_time_entries
  558. Role.find_by_name('Manager').add_permission! :edit_own_time_entries
  559. ids = (0..1).map {TimeEntry.generate!(:user => User.find(2)).id}
  560. post :bulk_update, :params => {:ids => ids, :time_entry => { :activity_id => 9 }}
  561. assert_response 302
  562. end
  563. def test_bulk_update_with_edit_own_time_entries_permissions_should_be_denied_for_time_entries_of_other_user
  564. @request.session[:user_id] = 2
  565. Role.find_by_name('Manager').remove_permission! :edit_time_entries
  566. Role.find_by_name('Manager').add_permission! :edit_own_time_entries
  567. post :bulk_update, :params => {:ids => [1, 2], :time_entry => { :activity_id => 9 }}
  568. assert_response 403
  569. end
  570. def test_bulk_update_custom_field
  571. @request.session[:user_id] = 2
  572. post :bulk_update, :params => {:ids => [1, 2], :time_entry => { :custom_field_values => {'10' => '0'} }}
  573. assert_response 302
  574. assert_equal ["0", "0"], TimeEntry.where(:id => [1, 2]).collect {|i| i.custom_value_for(10).value}
  575. end
  576. def test_bulk_update_clear_custom_field
  577. field = TimeEntryCustomField.generate!(:field_format => 'string')
  578. @request.session[:user_id] = 2
  579. post :bulk_update, :params => {:ids => [1, 2], :time_entry => { :custom_field_values => {field.id.to_s => '__none__'} }}
  580. assert_response 302
  581. assert_equal ["", ""], TimeEntry.where(:id => [1, 2]).collect {|i| i.custom_value_for(field).value}
  582. end
  583. def test_post_bulk_update_should_redirect_back_using_the_back_url_parameter
  584. @request.session[:user_id] = 2
  585. post :bulk_update, :params => {:ids => [1,2], :back_url => '/time_entries'}
  586. assert_response :redirect
  587. assert_redirected_to '/time_entries'
  588. end
  589. def test_post_bulk_update_should_not_redirect_back_using_the_back_url_parameter_off_the_host
  590. @request.session[:user_id] = 2
  591. post :bulk_update, :params => {:ids => [1,2], :back_url => 'http://google.com'}
  592. assert_response :redirect
  593. assert_redirected_to :controller => 'timelog', :action => 'index', :project_id => Project.find(1).identifier
  594. end
  595. def test_post_bulk_update_without_edit_permission_should_be_denied
  596. @request.session[:user_id] = 2
  597. Role.find_by_name('Manager').remove_permission! :edit_time_entries
  598. post :bulk_update, :params => {:ids => [1,2]}
  599. assert_response 403
  600. end
  601. def test_destroy
  602. @request.session[:user_id] = 2
  603. delete :destroy, :params => {:id => 1}
  604. assert_redirected_to :action => 'index', :project_id => 'ecookbook'
  605. assert_equal I18n.t(:notice_successful_delete), flash[:notice]
  606. assert_nil TimeEntry.find_by_id(1)
  607. end
  608. def test_destroy_should_fail
  609. # simulate that this fails (e.g. due to a plugin), see #5700
  610. TimeEntry.any_instance.expects(:destroy).returns(false)
  611. @request.session[:user_id] = 2
  612. delete :destroy, :params => {:id => 1}
  613. assert_redirected_to :action => 'index', :project_id => 'ecookbook'
  614. assert_equal I18n.t(:notice_unable_delete_time_entry), flash[:error]
  615. assert_not_nil TimeEntry.find_by_id(1)
  616. end
  617. def test_destroy_should_redirect_to_referer
  618. 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'
  619. @request.env["HTTP_REFERER"] = referer
  620. @request.session[:user_id] = 2
  621. delete :destroy, :params => {:id => 1}
  622. assert_redirected_to referer
  623. end
  624. def test_index_all_projects
  625. get :index
  626. assert_response :success
  627. assert_select '.total-for-hours', :text => 'Hours: 162.90'
  628. assert_select 'form#query_form[action=?]', '/time_entries'
  629. assert_equal ['Date', 'User', 'Activity', 'Issue', 'Comment', 'Hours'], columns_in_list
  630. assert_select '.query-totals>span', 1
  631. end
  632. def test_index_with_default_query_setting
  633. with_settings :time_entry_list_defaults => {'column_names' => %w(spent_on issue user hours)} do
  634. get :index
  635. assert_response :success
  636. end
  637. assert_select 'table.time-entries thead' do
  638. assert_select 'th.spent_on'
  639. assert_select 'th.issue'
  640. assert_select 'th.user'
  641. assert_select 'th.hours'
  642. end
  643. assert_select 'table.time-entries tbody' do
  644. assert_select 'td.spent_on'
  645. assert_select 'td.issue'
  646. assert_select 'td.user'
  647. assert_select 'td.hours'
  648. end
  649. assert_equal ['Date', 'Issue', 'User', 'Hours'], columns_in_list
  650. end
  651. def test_index_with_default_query_setting_using_custom_field
  652. field = TimeEntryCustomField.create!(:name => 'Foo', :field_format => 'int')
  653. with_settings :time_entry_list_defaults => {
  654. 'column_names' => ["spent_on", "user", "hours", "cf_#{field.id}"],
  655. 'totalable_names' => ["hours", "cf_#{field.id}"]
  656. } do
  657. get :index
  658. assert_response :success
  659. end
  660. assert_equal ['Date', 'User', 'Hours', 'Foo'], columns_in_list
  661. assert_select '.total-for-hours'
  662. assert_select ".total-for-cf-#{field.id}"
  663. assert_select '.query-totals>span', 2
  664. end
  665. def test_index_all_projects_should_show_log_time_link
  666. @request.session[:user_id] = 2
  667. get :index
  668. assert_response :success
  669. assert_select 'a[href=?]', '/time_entries/new', :text => /Log time/
  670. end
  671. def test_index_my_spent_time
  672. @request.session[:user_id] = 2
  673. get :index, :params => {:user_id => 'me', :c => ['user']}
  674. assert_response :success
  675. users = css_select('table.time-entries tbody td.user').map(&:text).uniq
  676. assert_equal ["John Smith"], users
  677. end
  678. def test_index_at_project_level
  679. @request.session[:user_id] = 2
  680. get :index, :params => {:project_id => 'ecookbook', :c => ['project']}
  681. assert_response :success
  682. assert_select 'tr.time-entry', 4
  683. # project and subproject
  684. projects = css_select('table.time-entries tbody td.project').map(&:text).uniq.sort
  685. assert_equal ["eCookbook", "eCookbook Subproject 1"], projects
  686. assert_select '.total-for-hours', :text => 'Hours: 162.90'
  687. assert_select 'form#query_form[action=?]', '/projects/ecookbook/time_entries'
  688. # 'Log time' shoudl link to log time on the filtered issue
  689. assert_select 'a[href=?]', "/projects/ecookbook/time_entries/new"
  690. end
  691. def test_index_with_display_subprojects_issues_to_false_should_not_include_subproject_entries
  692. entry = TimeEntry.generate!(:project => Project.find(3))
  693. with_settings :display_subprojects_issues => '0' do
  694. get :index, :params => {:project_id => 'ecookbook', :c => ['project']}
  695. assert_response :success
  696. projects = css_select('table.time-entries tbody td.project').map(&:text).uniq.sort
  697. assert_equal ["eCookbook"], projects
  698. end
  699. end
  700. def test_index_with_display_subprojects_issues_to_false_and_subproject_filter_should_include_subproject_entries
  701. entry = TimeEntry.generate!(:project => Project.find(3))
  702. with_settings :display_subprojects_issues => '0' do
  703. get :index, :params => {:project_id => 'ecookbook', :c => ['project'], :subproject_id => 3}
  704. assert_response :success
  705. projects = css_select('table.time-entries tbody td.project').map(&:text).uniq.sort
  706. assert_equal ["eCookbook", "eCookbook Subproject 1"], projects
  707. end
  708. end
  709. def test_index_at_project_level_with_issue_id_short_filter
  710. issue = Issue.generate!(:project_id => 1)
  711. TimeEntry.generate!(:issue => issue, :hours => 4)
  712. TimeEntry.generate!(:issue => issue, :hours => 3)
  713. @request.session[:user_id] = 2
  714. get :index, :params => {:project_id => 'ecookbook', :issue_id => issue.id.to_s, :set_filter => 1}
  715. assert_select '.total-for-hours', :text => 'Hours: 7.00'
  716. # 'Log time' shoudl link to log time on the filtered issue
  717. assert_select 'a[href=?]', "/issues/#{issue.id}/time_entries/new"
  718. end
  719. def test_index_at_project_level_with_issue_fixed_version_id_short_filter
  720. version = Version.generate!(:project_id => 1)
  721. issue = Issue.generate!(:project_id => 1, :fixed_version => version)
  722. TimeEntry.generate!(:issue => issue, :hours => 2)
  723. TimeEntry.generate!(:issue => issue, :hours => 3)
  724. @request.session[:user_id] = 2
  725. get :index, :params => {:project_id => 'ecookbook', :"issue.fixed_version_id" => version.id.to_s, :set_filter => 1}
  726. assert_select '.total-for-hours', :text => 'Hours: 5.00'
  727. end
  728. def test_index_at_project_level_with_multiple_issue_fixed_version_ids
  729. version = Version.generate!(:project_id => 1)
  730. version2 = Version.generate!(:project_id => 1)
  731. issue = Issue.generate!(:project_id => 1, :fixed_version => version)
  732. issue2 = Issue.generate!(:project_id => 1, :fixed_version => version2)
  733. TimeEntry.generate!(:issue => issue, :hours => 2)
  734. TimeEntry.generate!(:issue => issue2, :hours => 3)
  735. @request.session[:user_id] = 2
  736. get :index, :params => {
  737. :project_id => 'ecookbook',
  738. :f => ['issue.fixed_version_id'],
  739. :op => {'issue.fixed_version_id' => '='},
  740. :v => {'issue.fixed_version_id' => [version.id.to_s,version2.id.to_s]}
  741. }
  742. assert_response :success
  743. assert_select 'tr.time-entry', 2
  744. assert_select '.total-for-hours', :text => 'Hours: 5.00'
  745. end
  746. def test_index_at_project_level_with_date_range
  747. get :index, :params => {
  748. :project_id => 'ecookbook',
  749. :f => ['spent_on'],
  750. :op => {'spent_on' => '><'},
  751. :v => {'spent_on' => ['2007-03-20', '2007-04-30']}
  752. }
  753. assert_response :success
  754. assert_select 'tr.time-entry', 3
  755. assert_select '.total-for-hours', :text => 'Hours: 12.90'
  756. assert_select 'form#query_form[action=?]', '/projects/ecookbook/time_entries'
  757. end
  758. def test_index_at_project_level_with_date_range_using_from_and_to_params
  759. get :index, :params => {
  760. :project_id => 'ecookbook',
  761. :from => '2007-03-20',
  762. :to => '2007-04-30'
  763. }
  764. assert_response :success
  765. assert_select 'tr.time-entry', 3
  766. assert_select '.total-for-hours', :text => 'Hours: 12.90'
  767. assert_select 'form#query_form[action=?]', '/projects/ecookbook/time_entries'
  768. end
  769. def test_index_at_project_level_with_period
  770. get :index, :params => {
  771. :project_id => 'ecookbook',
  772. :f => ['spent_on'],
  773. :op => {'spent_on' => '>t-'},
  774. :v => {'spent_on' => ['7']}
  775. }
  776. assert_response :success
  777. assert_select 'form#query_form[action=?]', '/projects/ecookbook/time_entries'
  778. end
  779. def test_index_should_sort_by_spent_on_and_created_on
  780. 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)
  781. 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)
  782. 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)
  783. get :index, :params => {
  784. :project_id => 1,
  785. :f => ['spent_on'],
  786. :op => {'spent_on' => '><'},
  787. :v => {'spent_on' => ['2012-06-15', '2012-06-16']}
  788. }
  789. assert_response :success
  790. assert_equal [t2, t1, t3].map(&:id).map(&:to_s), css_select('input[name="ids[]"]').map {|e| e.attr('value')}
  791. get :index, :params => {
  792. :project_id => 1,
  793. :f => ['spent_on'],
  794. :op => {'spent_on' => '><'},
  795. :v => {'spent_on' => ['2012-06-15', '2012-06-16']},
  796. :sort => 'spent_on'
  797. }
  798. assert_response :success
  799. assert_equal [t3, t1, t2].map(&:id).map(&:to_s), css_select('input[name="ids[]"]').map {|e| e.attr('value')}
  800. end
  801. def test_index_with_activity_filter
  802. activity = TimeEntryActivity.create!(:name => 'Activity')
  803. entry = TimeEntry.generate!(:issue_id => 1, :hours => 4.5, :activity => activity)
  804. get :index, :params => {
  805. :f => ['activity_id'],
  806. :op => {'activity_id' => '='},
  807. :v => {'activity_id' => [activity.id.to_s]}
  808. }
  809. assert_response :success
  810. assert_select "tr#time-entry-#{entry.id}"
  811. assert_select "table.time-entries tbody tr", 1
  812. end
  813. def test_index_with_issue_status_filter
  814. Issue.where(:status_id => 4).update_all(:status_id => 2)
  815. issue = Issue.generate!(:project_id => 1, :tracker_id => 1, :status_id => 4)
  816. entry = TimeEntry.generate!(:issue => issue, :hours => 4.5)
  817. get :index, :params => {
  818. :f => ['issue.status_id'],
  819. :op => {'issue.status_id' => '='},
  820. :v => {'issue.status_id' => ['4']}
  821. }
  822. assert_response :success
  823. assert_equal [entry].map(&:id).map(&:to_s), css_select('input[name="ids[]"]').map {|e| e.attr('value')}
  824. end
  825. def test_index_with_issue_status_column
  826. issue = Issue.generate!(:project_id => 1, :tracker_id => 1, :status_id => 4)
  827. entry = TimeEntry.generate!(:issue => issue)
  828. get :index, :params => {
  829. :c => %w(project spent_on issue comments hours issue.status)
  830. }
  831. assert_response :success
  832. assert_select 'th.issue-status'
  833. assert_select 'td.issue-status', :text => issue.status.name
  834. end
  835. def test_index_with_issue_status_sort
  836. TimeEntry.delete_all
  837. TimeEntry.generate!(:issue => Issue.generate!(:project_id => 1, :tracker_id => 1, :status_id => 1))
  838. TimeEntry.generate!(:issue => Issue.generate!(:project_id => 1, :tracker_id => 1, :status_id => 5))
  839. TimeEntry.generate!(:issue => Issue.generate!(:project_id => 1, :tracker_id => 1, :status_id => 3))
  840. TimeEntry.generate!(:project_id => 1)
  841. get :index, :params => {
  842. :c => ["hours", 'issue.status'],
  843. :sort => 'issue.status'
  844. }
  845. assert_response :success
  846. # Make sure that values are properly sorted
  847. values = css_select("td.issue-status").map(&:text).reject(&:blank?)
  848. assert_equal IssueStatus.where(:id => [1, 5, 3]).sorted.pluck(:name), values
  849. end
  850. def test_index_with_issue_tracker_filter
  851. Issue.where(:tracker_id => 2).update_all(:tracker_id => 1)
  852. issue = Issue.generate!(:project_id => 1, :tracker_id => 2)
  853. entry = TimeEntry.generate!(:issue => issue, :hours => 4.5)
  854. get :index, :params => {
  855. :f => ['issue.tracker_id'],
  856. :op => {'issue.tracker_id' => '='},
  857. :v => {'issue.tracker_id' => ['2']}
  858. }
  859. assert_response :success
  860. assert_equal [entry].map(&:id).map(&:to_s), css_select('input[name="ids[]"]').map {|e| e.attr('value')}
  861. end
  862. def test_index_with_issue_tracker_column
  863. issue = Issue.generate!(:project_id => 1, :tracker_id => 2)
  864. entry = TimeEntry.generate!(:issue => issue)
  865. get :index, :params => {
  866. :c => %w(project spent_on issue comments hours issue.tracker)
  867. }
  868. assert_response :success
  869. assert_select 'td.issue-tracker', :text => issue.tracker.name
  870. end
  871. def test_index_with_issue_tracker_sort
  872. TimeEntry.delete_all
  873. TimeEntry.generate!(:issue => Issue.generate!(:tracker_id => 1))
  874. TimeEntry.generate!(:issue => Issue.generate!(:tracker_id => 3))
  875. TimeEntry.generate!(:issue => Issue.generate!(:tracker_id => 2))
  876. TimeEntry.generate!(:project_id => 1)
  877. get :index, :params => {
  878. :c => ["hours", 'issue.tracker'],
  879. :sort => 'issue.tracker'
  880. }
  881. assert_response :success
  882. # Make sure that values are properly sorted
  883. values = css_select("td.issue-tracker").map(&:text).reject(&:blank?)
  884. assert_equal Tracker.where(:id => [1, 2, 3]).sorted.pluck(:name), values
  885. end
  886. def test_index_with_issue_category_filter
  887. get :index, :params => {
  888. :project_id => 'ecookbook',
  889. :f => ['issue.category_id'],
  890. :op => {'issue.category_id' => '='},
  891. :v => {'issue.category_id' => ['1']}
  892. }
  893. assert_response :success
  894. assert_equal ['1', '2'], css_select('input[name="ids[]"]').map {|e| e.attr('value')}
  895. end
  896. def test_index_with_issue_category_column
  897. get :index, :params => {
  898. :project_id => 'ecookbook',
  899. :c => %w(project spent_on issue comments hours issue.category)
  900. }
  901. assert_response :success
  902. assert_select 'td.issue-category', :text => 'Printing'
  903. end
  904. def test_index_with_issue_category_sort
  905. issue = Issue.find(3)
  906. issue.category_id = 2
  907. issue.save!
  908. get :index, :params => {
  909. :c => ["hours", 'issue.category'],
  910. :sort => 'issue.category'
  911. }
  912. assert_response :success
  913. # Make sure that values are properly sorted
  914. values = css_select("td.issue-category").map(&:text).reject(&:blank?)
  915. assert_equal ['Printing', 'Printing', 'Recipes'], values
  916. end
  917. def test_index_with_filter_on_issue_custom_field
  918. issue = Issue.generate!(:project_id => 1, :tracker_id => 1, :custom_field_values => {2 => 'filter_on_issue_custom_field'})
  919. entry = TimeEntry.generate!(:issue => issue, :hours => 2.5)
  920. get :index, :params => {
  921. :f => ['issue.cf_2'],
  922. :op => {'issue.cf_2' => '='},
  923. :v => {'issue.cf_2' => ['filter_on_issue_custom_field']}
  924. }
  925. assert_response :success
  926. assert_equal [entry].map(&:id).map(&:to_s), css_select('input[name="ids[]"]').map {|e| e.attr('value')}
  927. end
  928. def test_index_with_issue_custom_field_column
  929. issue = Issue.generate!(:project_id => 1, :tracker_id => 1, :custom_field_values => {2 => 'filter_on_issue_custom_field'})
  930. entry = TimeEntry.generate!(:issue => issue, :hours => 2.5)
  931. get :index, :params => {
  932. :c => %w(project spent_on issue comments hours issue.cf_2)
  933. }
  934. assert_response :success
  935. assert_select 'td.issue_cf_2', :text => 'filter_on_issue_custom_field'
  936. end
  937. def test_index_with_time_entry_custom_field_column
  938. field = TimeEntryCustomField.generate!(:field_format => 'string')
  939. entry = TimeEntry.generate!(:hours => 2.5, :custom_field_values => {field.id => 'CF Value'})
  940. field_name = "cf_#{field.id}"
  941. get :index, :params => {
  942. :c => ["hours", field_name]
  943. }
  944. assert_response :success
  945. assert_select "td.#{field_name}", :text => 'CF Value'
  946. end
  947. def test_index_with_time_entry_custom_field_sorting
  948. field = TimeEntryCustomField.generate!(:field_format => 'string', :name => 'String Field')
  949. TimeEntry.generate!(:hours => 2.5, :custom_field_values => {field.id => 'CF Value 1'})
  950. TimeEntry.generate!(:hours => 2.5, :custom_field_values => {field.id => 'CF Value 3'})
  951. TimeEntry.generate!(:hours => 2.5, :custom_field_values => {field.id => 'CF Value 2'})
  952. field_name = "cf_#{field.id}"
  953. get :index, :params => {
  954. :c => ["hours", field_name],
  955. :sort => field_name
  956. }
  957. assert_response :success
  958. assert_select "th.cf_#{field.id} a.sort", :text => 'String Field'
  959. # Make sure that values are properly sorted
  960. values = css_select("td.#{field_name}").map(&:text).reject(&:blank?)
  961. assert_equal values.sort, values
  962. assert_equal 3, values.size
  963. end
  964. def test_index_with_invalid_date_filter_should_not_validate
  965. @request.session[:user_id] = 2
  966. get :index, :params => {:set_filter => '1', :f => ['spent_on'], :op => {'spent_on' => '='}, :v => {'spent_on' => ['2016-09-010']}}
  967. assert_select_error 'Date is invalid'
  968. assert_select 'table.time-entries', 0
  969. end
  970. def test_index_with_query
  971. query = TimeEntryQuery.new(:project_id => 1, :name => 'Time Entry Query', :visibility => 2)
  972. query.save!
  973. @request.session[:user_id] = 2
  974. get :index, :params => {:project_id => 'ecookbook', :query_id => query.id}
  975. assert_response :success
  976. assert_select 'h2', :text => query.name
  977. assert_select '#sidebar a.selected', :text => query.name
  978. end
  979. def test_index_atom_feed
  980. get :index, :params => {:project_id => 1, :format => 'atom'}
  981. assert_response :success
  982. assert_equal 'application/atom+xml', @response.content_type
  983. assert_select 'entry > title', :text => /7\.65 hours/
  984. end
  985. def test_index_at_project_level_should_include_csv_export_dialog
  986. get :index, :params => {
  987. :project_id => 'ecookbook',
  988. :f => ['spent_on'],
  989. :op => {'spent_on' => '>='},
  990. :v => {'spent_on' => ['2007-04-01']},
  991. :c => ['spent_on', 'user']
  992. }
  993. assert_response :success
  994. assert_select '#csv-export-options' do
  995. assert_select 'form[action=?][method=get]', '/projects/ecookbook/time_entries.csv' do
  996. # filter
  997. assert_select 'input[name=?][value=?]', 'f[]', 'spent_on'
  998. assert_select 'input[name=?][value=?]', 'op[spent_on]', '>='
  999. assert_select 'input[name=?][value=?]', 'v[spent_on][]', '2007-04-01'
  1000. # columns
  1001. assert_select 'input[name=?][type=hidden][value=?]', 'c[]', 'spent_on'
  1002. assert_select 'input[name=?][type=hidden][value=?]', 'c[]', 'user'
  1003. assert_select 'input[name=?][type=hidden]', 'c[]', 2
  1004. assert_select 'input[name=?][value=?]', 'c[]', 'all_inline'
  1005. end
  1006. end
  1007. end
  1008. def test_index_cross_project_should_include_csv_export_dialog
  1009. get :index
  1010. assert_response :success
  1011. assert_select '#csv-export-options' do
  1012. assert_select 'form[action=?][method=get]', '/time_entries.csv'
  1013. end
  1014. end
  1015. def test_index_csv_all_projects
  1016. with_settings :date_format => '%m/%d/%Y' do
  1017. get :index, :params => {:format => 'csv'}
  1018. assert_response :success
  1019. assert_equal 'text/csv; header=present', response.content_type
  1020. end
  1021. end
  1022. def test_index_csv
  1023. with_settings :date_format => '%m/%d/%Y' do
  1024. get :index, :params => {:project_id => 1, :format => 'csv'}
  1025. assert_response :success
  1026. assert_equal 'text/csv; header=present', response.content_type
  1027. end
  1028. end
  1029. def test_index_csv_should_fill_issue_column_with_tracker_id_and_subject
  1030. issue = Issue.find(1)
  1031. entry = TimeEntry.generate!(:issue => issue, :comments => "Issue column content test")
  1032. get :index, :params => {:format => 'csv'}
  1033. line = response.body.split("\n").detect {|l| l.include?(entry.comments)}
  1034. assert_not_nil line
  1035. assert_include "#{issue.tracker} #1: #{issue.subject}", line
  1036. end
  1037. end