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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260
  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, :issue_categories
  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 ['Project', '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), 'totalable_names' => []} do
  634. get :index
  635. assert_response :success
  636. end
  637. assert_select 'table.time-entries thead' do
  638. assert_select 'th.project'
  639. assert_select 'th.spent_on'
  640. assert_select 'th.issue'
  641. assert_select 'th.user'
  642. assert_select 'th.hours'
  643. end
  644. assert_select 'table.time-entries tbody' do
  645. assert_select 'td.project'
  646. assert_select 'td.spent_on'
  647. assert_select 'td.issue'
  648. assert_select 'td.user'
  649. assert_select 'td.hours'
  650. end
  651. assert_equal ['Project', 'Date', 'Issue', 'User', 'Hours'], columns_in_list
  652. end
  653. def test_index_with_default_query_setting_using_custom_field
  654. field = TimeEntryCustomField.create!(:name => 'Foo', :field_format => 'int')
  655. with_settings :time_entry_list_defaults => {
  656. 'column_names' => ["spent_on", "user", "hours", "cf_#{field.id}"],
  657. 'totalable_names' => ["hours", "cf_#{field.id}"]
  658. } do
  659. get :index
  660. assert_response :success
  661. end
  662. assert_equal ['Project', 'Date', 'User', 'Hours', 'Foo'], columns_in_list
  663. assert_select '.total-for-hours'
  664. assert_select ".total-for-cf-#{field.id}"
  665. assert_select '.query-totals>span', 2
  666. end
  667. def test_index_all_projects_should_show_log_time_link
  668. @request.session[:user_id] = 2
  669. get :index
  670. assert_response :success
  671. assert_select 'a[href=?]', '/time_entries/new', :text => /Log time/
  672. end
  673. def test_index_my_spent_time
  674. @request.session[:user_id] = 2
  675. get :index, :params => {:user_id => 'me', :c => ['user']}
  676. assert_response :success
  677. users = css_select('table.time-entries tbody td.user').map(&:text).uniq
  678. assert_equal ["John Smith"], users
  679. end
  680. def test_index_at_project_level
  681. @request.session[:user_id] = 2
  682. get :index, :params => {:project_id => 'ecookbook', :c => ['project']}
  683. assert_response :success
  684. assert_select 'tr.time-entry', 4
  685. # project and subproject
  686. projects = css_select('table.time-entries tbody td.project').map(&:text).uniq.sort
  687. assert_equal ["eCookbook", "eCookbook Subproject 1"], projects
  688. assert_select '.total-for-hours', :text => 'Hours: 162.90'
  689. assert_select 'form#query_form[action=?]', '/projects/ecookbook/time_entries'
  690. # 'Log time' shoudl link to log time on the filtered issue
  691. assert_select 'a[href=?]', "/projects/ecookbook/time_entries/new"
  692. end
  693. def test_index_with_display_subprojects_issues_to_false_should_not_include_subproject_entries
  694. entry = TimeEntry.generate!(:project => Project.find(3))
  695. with_settings :display_subprojects_issues => '0' do
  696. get :index, :params => {:project_id => 'ecookbook', :c => ['project']}
  697. assert_response :success
  698. projects = css_select('table.time-entries tbody td.project').map(&:text).uniq.sort
  699. assert_equal ["eCookbook"], projects
  700. end
  701. end
  702. def test_index_with_display_subprojects_issues_to_false_and_subproject_filter_should_include_subproject_entries
  703. entry = TimeEntry.generate!(:project => Project.find(3))
  704. with_settings :display_subprojects_issues => '0' do
  705. get :index, :params => {:project_id => 'ecookbook', :c => ['project'], :subproject_id => 3}
  706. assert_response :success
  707. projects = css_select('table.time-entries tbody td.project').map(&:text).uniq.sort
  708. assert_equal ["eCookbook", "eCookbook Subproject 1"], projects
  709. end
  710. end
  711. def test_index_at_project_level_with_issue_id_short_filter
  712. issue = Issue.generate!(:project_id => 1)
  713. TimeEntry.generate!(:issue => issue, :hours => 4)
  714. TimeEntry.generate!(:issue => issue, :hours => 3)
  715. @request.session[:user_id] = 2
  716. get :index, :params => {:project_id => 'ecookbook', :issue_id => issue.id.to_s, :set_filter => 1}
  717. assert_select '.total-for-hours', :text => 'Hours: 7.00'
  718. # 'Log time' shoudl link to log time on the filtered issue
  719. assert_select 'a[href=?]', "/issues/#{issue.id}/time_entries/new"
  720. end
  721. def test_index_at_project_level_with_issue_fixed_version_id_short_filter
  722. version = Version.generate!(:project_id => 1)
  723. issue = Issue.generate!(:project_id => 1, :fixed_version => version)
  724. TimeEntry.generate!(:issue => issue, :hours => 2)
  725. TimeEntry.generate!(:issue => issue, :hours => 3)
  726. @request.session[:user_id] = 2
  727. get :index, :params => {:project_id => 'ecookbook', :"issue.fixed_version_id" => version.id.to_s, :set_filter => 1}
  728. assert_select '.total-for-hours', :text => 'Hours: 5.00'
  729. end
  730. def test_index_at_project_level_with_multiple_issue_fixed_version_ids
  731. version = Version.generate!(:project_id => 1)
  732. version2 = Version.generate!(:project_id => 1)
  733. issue = Issue.generate!(:project_id => 1, :fixed_version => version)
  734. issue2 = Issue.generate!(:project_id => 1, :fixed_version => version2)
  735. TimeEntry.generate!(:issue => issue, :hours => 2)
  736. TimeEntry.generate!(:issue => issue2, :hours => 3)
  737. @request.session[:user_id] = 2
  738. get :index, :params => {
  739. :project_id => 'ecookbook',
  740. :f => ['issue.fixed_version_id'],
  741. :op => {'issue.fixed_version_id' => '='},
  742. :v => {'issue.fixed_version_id' => [version.id.to_s,version2.id.to_s]}
  743. }
  744. assert_response :success
  745. assert_select 'tr.time-entry', 2
  746. assert_select '.total-for-hours', :text => 'Hours: 5.00'
  747. end
  748. def test_index_at_project_level_with_date_range
  749. get :index, :params => {
  750. :project_id => 'ecookbook',
  751. :f => ['spent_on'],
  752. :op => {'spent_on' => '><'},
  753. :v => {'spent_on' => ['2007-03-20', '2007-04-30']}
  754. }
  755. assert_response :success
  756. assert_select 'tr.time-entry', 3
  757. assert_select '.total-for-hours', :text => 'Hours: 12.90'
  758. assert_select 'form#query_form[action=?]', '/projects/ecookbook/time_entries'
  759. end
  760. def test_index_at_project_level_with_date_range_using_from_and_to_params
  761. get :index, :params => {
  762. :project_id => 'ecookbook',
  763. :from => '2007-03-20',
  764. :to => '2007-04-30'
  765. }
  766. assert_response :success
  767. assert_select 'tr.time-entry', 3
  768. assert_select '.total-for-hours', :text => 'Hours: 12.90'
  769. assert_select 'form#query_form[action=?]', '/projects/ecookbook/time_entries'
  770. end
  771. def test_index_at_project_level_with_period
  772. get :index, :params => {
  773. :project_id => 'ecookbook',
  774. :f => ['spent_on'],
  775. :op => {'spent_on' => '>t-'},
  776. :v => {'spent_on' => ['7']}
  777. }
  778. assert_response :success
  779. assert_select 'form#query_form[action=?]', '/projects/ecookbook/time_entries'
  780. end
  781. def test_index_should_sort_by_spent_on_and_created_on
  782. 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)
  783. 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)
  784. 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)
  785. get :index, :params => {
  786. :project_id => 1,
  787. :f => ['spent_on'],
  788. :op => {'spent_on' => '><'},
  789. :v => {'spent_on' => ['2012-06-15', '2012-06-16']}
  790. }
  791. assert_response :success
  792. assert_equal [t2, t1, t3].map(&:id).map(&:to_s), css_select('input[name="ids[]"]').map {|e| e.attr('value')}
  793. get :index, :params => {
  794. :project_id => 1,
  795. :f => ['spent_on'],
  796. :op => {'spent_on' => '><'},
  797. :v => {'spent_on' => ['2012-06-15', '2012-06-16']},
  798. :sort => 'spent_on'
  799. }
  800. assert_response :success
  801. assert_equal [t3, t1, t2].map(&:id).map(&:to_s), css_select('input[name="ids[]"]').map {|e| e.attr('value')}
  802. end
  803. def test_index_with_activity_filter
  804. activity = TimeEntryActivity.create!(:name => 'Activity')
  805. entry = TimeEntry.generate!(:issue_id => 1, :hours => 4.5, :activity => activity)
  806. get :index, :params => {
  807. :f => ['activity_id'],
  808. :op => {'activity_id' => '='},
  809. :v => {'activity_id' => [activity.id.to_s]}
  810. }
  811. assert_response :success
  812. assert_select "tr#time-entry-#{entry.id}"
  813. assert_select "table.time-entries tbody tr", 1
  814. end
  815. def test_index_with_issue_status_filter
  816. Issue.where(:status_id => 4).update_all(:status_id => 2)
  817. issue = Issue.generate!(:project_id => 1, :tracker_id => 1, :status_id => 4)
  818. entry = TimeEntry.generate!(:issue => issue, :hours => 4.5)
  819. get :index, :params => {
  820. :f => ['issue.status_id'],
  821. :op => {'issue.status_id' => '='},
  822. :v => {'issue.status_id' => ['4']}
  823. }
  824. assert_response :success
  825. assert_equal [entry].map(&:id).map(&:to_s), css_select('input[name="ids[]"]').map {|e| e.attr('value')}
  826. end
  827. def test_index_with_project_status_filter
  828. project = Project.find(3)
  829. project.close
  830. project.save
  831. get :index, :params => {
  832. :set_filter => 1,
  833. :f => ['project.status'],
  834. :op => {'project.status' => '='},
  835. :v => {'project.status' => ['1']}
  836. }
  837. assert_response :success
  838. time_entries = css_select('input[name="ids[]"]').map {|e| e.attr('value')}
  839. assert_include '1', time_entries
  840. assert_not_include '4', time_entries
  841. end
  842. def test_index_with_issue_status_column
  843. issue = Issue.generate!(:project_id => 1, :tracker_id => 1, :status_id => 4)
  844. entry = TimeEntry.generate!(:issue => issue)
  845. get :index, :params => {
  846. :c => %w(project spent_on issue comments hours issue.status)
  847. }
  848. assert_response :success
  849. assert_select 'th.issue-status'
  850. assert_select 'td.issue-status', :text => issue.status.name
  851. end
  852. def test_index_with_issue_status_sort
  853. TimeEntry.delete_all
  854. TimeEntry.generate!(:issue => Issue.generate!(:project_id => 1, :tracker_id => 1, :status_id => 1))
  855. TimeEntry.generate!(:issue => Issue.generate!(:project_id => 1, :tracker_id => 1, :status_id => 5))
  856. TimeEntry.generate!(:issue => Issue.generate!(:project_id => 1, :tracker_id => 1, :status_id => 3))
  857. TimeEntry.generate!(:project_id => 1)
  858. get :index, :params => {
  859. :c => ["hours", 'issue.status'],
  860. :sort => 'issue.status'
  861. }
  862. assert_response :success
  863. # Make sure that values are properly sorted
  864. values = css_select("td.issue-status").map(&:text).reject(&:blank?)
  865. assert_equal IssueStatus.where(:id => [1, 5, 3]).sorted.pluck(:name), values
  866. end
  867. def test_index_with_issue_tracker_filter
  868. Issue.where(:tracker_id => 2).update_all(:tracker_id => 1)
  869. issue = Issue.generate!(:project_id => 1, :tracker_id => 2)
  870. entry = TimeEntry.generate!(:issue => issue, :hours => 4.5)
  871. get :index, :params => {
  872. :f => ['issue.tracker_id'],
  873. :op => {'issue.tracker_id' => '='},
  874. :v => {'issue.tracker_id' => ['2']}
  875. }
  876. assert_response :success
  877. assert_equal [entry].map(&:id).map(&:to_s), css_select('input[name="ids[]"]').map {|e| e.attr('value')}
  878. end
  879. def test_index_with_issue_tracker_column
  880. issue = Issue.generate!(:project_id => 1, :tracker_id => 2)
  881. entry = TimeEntry.generate!(:issue => issue)
  882. get :index, :params => {
  883. :c => %w(project spent_on issue comments hours issue.tracker)
  884. }
  885. assert_response :success
  886. assert_select 'td.issue-tracker', :text => issue.tracker.name
  887. end
  888. def test_index_with_issue_tracker_sort
  889. TimeEntry.delete_all
  890. TimeEntry.generate!(:issue => Issue.generate!(:tracker_id => 1))
  891. TimeEntry.generate!(:issue => Issue.generate!(:tracker_id => 3))
  892. TimeEntry.generate!(:issue => Issue.generate!(:tracker_id => 2))
  893. TimeEntry.generate!(:project_id => 1)
  894. get :index, :params => {
  895. :c => ["hours", 'issue.tracker'],
  896. :sort => 'issue.tracker'
  897. }
  898. assert_response :success
  899. # Make sure that values are properly sorted
  900. values = css_select("td.issue-tracker").map(&:text).reject(&:blank?)
  901. assert_equal Tracker.where(:id => [1, 2, 3]).sorted.pluck(:name), values
  902. end
  903. def test_index_with_issue_category_filter
  904. get :index, :params => {
  905. :project_id => 'ecookbook',
  906. :f => ['issue.category_id'],
  907. :op => {'issue.category_id' => '='},
  908. :v => {'issue.category_id' => ['1']}
  909. }
  910. assert_response :success
  911. assert_equal ['1', '2'], css_select('input[name="ids[]"]').map {|e| e.attr('value')}
  912. end
  913. def test_index_with_issue_category_column
  914. get :index, :params => {
  915. :project_id => 'ecookbook',
  916. :c => %w(project spent_on issue comments hours issue.category)
  917. }
  918. assert_response :success
  919. assert_select 'td.issue-category', :text => 'Printing'
  920. end
  921. def test_index_with_issue_category_sort
  922. issue = Issue.find(3)
  923. issue.category_id = 2
  924. issue.save!
  925. get :index, :params => {
  926. :c => ["hours", 'issue.category'],
  927. :sort => 'issue.category'
  928. }
  929. assert_response :success
  930. # Make sure that values are properly sorted
  931. values = css_select("td.issue-category").map(&:text).reject(&:blank?)
  932. assert_equal ['Printing', 'Printing', 'Recipes'], values
  933. end
  934. def test_index_with_filter_on_issue_custom_field
  935. issue = Issue.generate!(:project_id => 1, :tracker_id => 1, :custom_field_values => {2 => 'filter_on_issue_custom_field'})
  936. entry = TimeEntry.generate!(:issue => issue, :hours => 2.5)
  937. get :index, :params => {
  938. :f => ['issue.cf_2'],
  939. :op => {'issue.cf_2' => '='},
  940. :v => {'issue.cf_2' => ['filter_on_issue_custom_field']}
  941. }
  942. assert_response :success
  943. assert_equal [entry].map(&:id).map(&:to_s), css_select('input[name="ids[]"]').map {|e| e.attr('value')}
  944. end
  945. def test_index_with_issue_custom_field_column
  946. issue = Issue.generate!(:project_id => 1, :tracker_id => 1, :custom_field_values => {2 => 'filter_on_issue_custom_field'})
  947. entry = TimeEntry.generate!(:issue => issue, :hours => 2.5)
  948. get :index, :params => {
  949. :c => %w(project spent_on issue comments hours issue.cf_2)
  950. }
  951. assert_response :success
  952. assert_select 'td.issue_cf_2', :text => 'filter_on_issue_custom_field'
  953. end
  954. def test_index_with_time_entry_custom_field_column
  955. field = TimeEntryCustomField.generate!(:field_format => 'string')
  956. entry = TimeEntry.generate!(:hours => 2.5, :custom_field_values => {field.id => 'CF Value'})
  957. field_name = "cf_#{field.id}"
  958. get :index, :params => {
  959. :c => ["hours", field_name]
  960. }
  961. assert_response :success
  962. assert_select "td.#{field_name}", :text => 'CF Value'
  963. end
  964. def test_index_with_time_entry_custom_field_sorting
  965. field = TimeEntryCustomField.generate!(:field_format => 'string', :name => 'String Field')
  966. TimeEntry.generate!(:hours => 2.5, :custom_field_values => {field.id => 'CF Value 1'})
  967. TimeEntry.generate!(:hours => 2.5, :custom_field_values => {field.id => 'CF Value 3'})
  968. TimeEntry.generate!(:hours => 2.5, :custom_field_values => {field.id => 'CF Value 2'})
  969. field_name = "cf_#{field.id}"
  970. get :index, :params => {
  971. :c => ["hours", field_name],
  972. :sort => field_name
  973. }
  974. assert_response :success
  975. assert_select "th.cf_#{field.id} a.sort", :text => 'String Field'
  976. # Make sure that values are properly sorted
  977. values = css_select("td.#{field_name}").map(&:text).reject(&:blank?)
  978. assert_equal values.sort, values
  979. assert_equal 3, values.size
  980. end
  981. def test_index_with_invalid_date_filter_should_not_validate
  982. @request.session[:user_id] = 2
  983. get :index, :params => {:set_filter => '1', :f => ['spent_on'], :op => {'spent_on' => '='}, :v => {'spent_on' => ['2016-09-010']}}
  984. assert_select_error 'Date is invalid'
  985. assert_select 'table.time-entries', 0
  986. end
  987. def test_index_with_query
  988. query = TimeEntryQuery.new(:project_id => 1, :name => 'Time Entry Query', :visibility => 2)
  989. query.save!
  990. @request.session[:user_id] = 2
  991. get :index, :params => {:project_id => 'ecookbook', :query_id => query.id}
  992. assert_response :success
  993. assert_select 'h2', :text => query.name
  994. assert_select '#sidebar a.selected', :text => query.name
  995. end
  996. def test_index_atom_feed
  997. get :index, :params => {:project_id => 1, :format => 'atom'}
  998. assert_response :success
  999. assert_equal 'application/atom+xml', @response.content_type
  1000. assert_select 'entry > title', :text => /7\.65 hours/
  1001. end
  1002. def test_index_at_project_level_should_include_csv_export_dialog
  1003. get :index, :params => {
  1004. :project_id => 'ecookbook',
  1005. :f => ['spent_on'],
  1006. :op => {'spent_on' => '>='},
  1007. :v => {'spent_on' => ['2007-04-01']},
  1008. :c => ['spent_on', 'user']
  1009. }
  1010. assert_response :success
  1011. assert_select '#csv-export-options' do
  1012. assert_select 'form[action=?][method=get]', '/projects/ecookbook/time_entries.csv' do
  1013. # filter
  1014. assert_select 'input[name=?][value=?]', 'f[]', 'spent_on'
  1015. assert_select 'input[name=?][value=?]', 'op[spent_on]', '>='
  1016. assert_select 'input[name=?][value=?]', 'v[spent_on][]', '2007-04-01'
  1017. # columns
  1018. assert_select 'input[name=?][type=hidden][value=?]', 'c[]', 'spent_on'
  1019. assert_select 'input[name=?][type=hidden][value=?]', 'c[]', 'user'
  1020. assert_select 'input[name=?][type=hidden]', 'c[]', 2
  1021. assert_select 'input[name=?][value=?]', 'c[]', 'all_inline'
  1022. end
  1023. end
  1024. end
  1025. def test_index_cross_project_should_include_csv_export_dialog
  1026. get :index
  1027. assert_response :success
  1028. assert_select '#csv-export-options' do
  1029. assert_select 'form[action=?][method=get]', '/time_entries.csv'
  1030. end
  1031. end
  1032. def test_index_csv_all_projects
  1033. with_settings :date_format => '%m/%d/%Y' do
  1034. get :index, :params => {:format => 'csv'}
  1035. assert_response :success
  1036. assert_equal 'text/csv; header=present', response.content_type
  1037. end
  1038. end
  1039. def test_index_csv
  1040. with_settings :date_format => '%m/%d/%Y' do
  1041. get :index, :params => {:project_id => 1, :format => 'csv'}
  1042. assert_response :success
  1043. assert_equal 'text/csv; header=present', response.content_type
  1044. end
  1045. end
  1046. def test_index_csv_should_fill_issue_column_with_tracker_id_and_subject
  1047. issue = Issue.find(1)
  1048. entry = TimeEntry.generate!(:issue => issue, :comments => "Issue column content test")
  1049. get :index, :params => {:format => 'csv'}
  1050. line = response.body.split("\n").detect {|l| l.include?(entry.comments)}
  1051. assert_not_nil line
  1052. assert_include "#{issue.tracker} #1: #{issue.subject}", line
  1053. end
  1054. end