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.

wiki_controller_test.rb 41KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198
  1. # encoding: utf-8
  2. #
  3. # Redmine - project management software
  4. # Copyright (C) 2006-2017 Jean-Philippe Lang
  5. #
  6. # This program is free software; you can redistribute it and/or
  7. # modify it under the terms of the GNU General Public License
  8. # as published by the Free Software Foundation; either version 2
  9. # of the License, or (at your option) any later version.
  10. #
  11. # This program is distributed in the hope that it will be useful,
  12. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. # GNU General Public License for more details.
  15. #
  16. # You should have received a copy of the GNU General Public License
  17. # along with this program; if not, write to the Free Software
  18. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  19. require File.expand_path('../../test_helper', __FILE__)
  20. class WikiControllerTest < Redmine::ControllerTest
  21. fixtures :projects, :users, :email_addresses, :roles, :members, :member_roles,
  22. :enabled_modules, :wikis, :wiki_pages, :wiki_contents,
  23. :wiki_content_versions, :attachments,
  24. :issues, :issue_statuses, :trackers
  25. def setup
  26. User.current = nil
  27. end
  28. def test_show_start_page
  29. get :show, :params => {:project_id => 'ecookbook'}
  30. assert_response :success
  31. assert_select 'h1', :text => /CookBook documentation/
  32. # child_pages macro
  33. assert_select 'ul.pages-hierarchy>li>a[href=?]', '/projects/ecookbook/wiki/Page_with_an_inline_image',
  34. :text => 'Page with an inline image'
  35. end
  36. def test_export_link
  37. Role.anonymous.add_permission! :export_wiki_pages
  38. get :show, :params => {:project_id => 'ecookbook'}
  39. assert_response :success
  40. assert_select 'a[href=?]', '/projects/ecookbook/wiki/CookBook_documentation.txt'
  41. end
  42. def test_show_page_with_name
  43. get :show, :params => {:project_id => 1, :id => 'Another_page'}
  44. assert_response :success
  45. assert_select 'h1', :text => /Another page/
  46. # Included page with an inline image
  47. assert_select 'p', :text => /This is an inline image/
  48. assert_select 'img[src=?][alt=?]', '/attachments/download/3/logo.gif', 'This is a logo'
  49. end
  50. def test_show_old_version
  51. with_settings :default_language => 'en' do
  52. get :show, :params => {:project_id => 'ecookbook', :id => 'CookBook_documentation', :version => '2'}
  53. end
  54. assert_response :success
  55. assert_select 'a[href=?]', '/projects/ecookbook/wiki/CookBook_documentation/1', :text => /Previous/
  56. assert_select 'a[href=?]', '/projects/ecookbook/wiki/CookBook_documentation/2/diff', :text => /diff/
  57. assert_select 'a[href=?]', '/projects/ecookbook/wiki/CookBook_documentation/3', :text => /Next/
  58. end
  59. def test_show_old_version_with_attachments
  60. page = WikiPage.find(4)
  61. assert page.attachments.any?
  62. content = page.content
  63. content.text = "update"
  64. content.save!
  65. get :show, :params => {:project_id => 'ecookbook', :id => page.title, :version => '1'}
  66. assert_response :success
  67. end
  68. def test_show_old_version_without_permission_should_be_denied
  69. Role.anonymous.remove_permission! :view_wiki_edits
  70. get :show, :params => {:project_id => 'ecookbook', :id => 'CookBook_documentation', :version => '2'}
  71. assert_redirected_to '/login?back_url=http%3A%2F%2Ftest.host%2Fprojects%2Fecookbook%2Fwiki%2FCookBook_documentation%2F2'
  72. end
  73. def test_show_first_version
  74. with_settings :default_language => 'en' do
  75. get :show, :params => {:project_id => 'ecookbook', :id => 'CookBook_documentation', :version => '1'}
  76. end
  77. assert_response :success
  78. assert_select 'a', :text => /Previous/, :count => 0
  79. assert_select 'a', :text => /diff/, :count => 0
  80. assert_select 'a[href=?]', '/projects/ecookbook/wiki/CookBook_documentation/2', :text => /Next/
  81. end
  82. def test_show_redirected_page
  83. WikiRedirect.create!(:wiki_id => 1, :title => 'Old_title', :redirects_to => 'Another_page')
  84. get :show, :params => {:project_id => 'ecookbook', :id => 'Old_title'}
  85. assert_redirected_to '/projects/ecookbook/wiki/Another_page'
  86. end
  87. def test_show_with_sidebar
  88. page = Project.find(1).wiki.pages.new(:title => 'Sidebar')
  89. page.content = WikiContent.new(:text => 'Side bar content for test_show_with_sidebar')
  90. page.save!
  91. get :show, :params => {:project_id => 1, :id => 'Another_page'}
  92. assert_response :success
  93. assert_select 'div#sidebar', :text => /Side bar content for test_show_with_sidebar/
  94. end
  95. def test_show_should_display_section_edit_links
  96. @request.session[:user_id] = 2
  97. get :show, :params => {:project_id => 1, :id => 'Page with sections'}
  98. assert_select 'a[href=?]', '/projects/ecookbook/wiki/Page_with_sections/edit?section=1', 0
  99. assert_select 'a[href=?]', '/projects/ecookbook/wiki/Page_with_sections/edit?section=2'
  100. assert_select 'a[href=?]', '/projects/ecookbook/wiki/Page_with_sections/edit?section=3'
  101. end
  102. def test_show_current_version_should_display_section_edit_links
  103. @request.session[:user_id] = 2
  104. get :show, :params => {:project_id => 1, :id => 'Page with sections', :version => 3}
  105. assert_select 'a[href=?]', '/projects/ecookbook/wiki/Page_with_sections/edit?section=2'
  106. end
  107. def test_show_old_version_should_not_display_section_edit_links
  108. @request.session[:user_id] = 2
  109. get :show, :params => {:project_id => 1, :id => 'Page with sections', :version => 2}
  110. assert_select 'a[href=?]', '/projects/ecookbook/wiki/Page_with_sections/edit?section=2', 0
  111. end
  112. def test_show_unexistent_page_without_edit_right
  113. get :show, :params => {:project_id => 1, :id => 'Unexistent page'}
  114. assert_response 404
  115. end
  116. def test_show_unexistent_page_with_edit_right
  117. @request.session[:user_id] = 2
  118. get :show, :params => {:project_id => 1, :id => 'Unexistent page'}
  119. assert_response :success
  120. assert_select 'textarea[name=?]', 'content[text]'
  121. end
  122. def test_show_specific_version_of_an_unexistent_page_without_edit_right
  123. get :show, :params => {:project_id => 1, :id => 'Unexistent page', :version => 1}
  124. assert_response 404
  125. end
  126. def test_show_unexistent_page_with_parent_should_preselect_parent
  127. @request.session[:user_id] = 2
  128. get :show, :params => {:project_id => 1, :id => 'Unexistent page', :parent => 'Another_page'}
  129. assert_response :success
  130. assert_select 'select[name=?] option[value="2"][selected=selected]', 'wiki_page[parent_id]'
  131. end
  132. def test_show_should_not_show_history_without_permission
  133. Role.anonymous.remove_permission! :view_wiki_edits
  134. get :show, :params => {:project_id => 1, :id => 'Page with sections', :version => 2}
  135. assert_response 302
  136. end
  137. def test_show_page_without_content_should_display_the_edit_form
  138. @request.session[:user_id] = 2
  139. WikiPage.create!(:title => 'NoContent', :wiki => Project.find(1).wiki)
  140. get :show, :params => {:project_id => 1, :id => 'NoContent'}
  141. assert_response :success
  142. assert_select 'textarea[name=?]', 'content[text]'
  143. end
  144. def test_get_new
  145. @request.session[:user_id] = 2
  146. get :new, :params => {:project_id => 'ecookbook'}
  147. assert_response :success
  148. assert_select 'input[name=?]', 'title'
  149. end
  150. def test_get_new_xhr
  151. @request.session[:user_id] = 2
  152. get :new, :params => {:project_id => 'ecookbook'}, :xhr => true
  153. assert_response :success
  154. assert_include 'Unallowed characters', response.body
  155. end
  156. def test_post_new_with_valid_title_should_redirect_to_edit
  157. @request.session[:user_id] = 2
  158. post :new, :params => {:project_id => 'ecookbook', :title => 'New Page'}
  159. assert_redirected_to '/projects/ecookbook/wiki/New_Page'
  160. end
  161. def test_post_new_xhr_with_valid_title_should_redirect_to_edit
  162. @request.session[:user_id] = 2
  163. post :new, :params => {:project_id => 'ecookbook', :title => 'New Page'}, :xhr => true
  164. assert_response :success
  165. assert_equal 'window.location = "/projects/ecookbook/wiki/New_Page"', response.body
  166. end
  167. def test_post_new_should_redirect_to_edit_with_parent
  168. @request.session[:user_id] = 2
  169. post :new, :params => {:project_id => 'ecookbook', :title => 'New_Page', :parent => 'Child_1'}
  170. assert_redirected_to '/projects/ecookbook/wiki/New_Page?parent=Child_1'
  171. end
  172. def test_post_new_with_invalid_title_should_display_errors
  173. @request.session[:user_id] = 2
  174. post :new, :params => {:project_id => 'ecookbook', :title => 'Another page'}
  175. assert_response :success
  176. assert_select_error 'Title has already been taken'
  177. end
  178. def test_post_new_with_protected_title_should_display_errors
  179. Role.find(1).remove_permission!(:protect_wiki_pages)
  180. @request.session[:user_id] = 2
  181. post :new, :params => {:project_id => 'ecookbook', :title => 'Sidebar'}
  182. assert_response :success
  183. assert_select_error /Title/
  184. end
  185. def test_post_new_xhr_with_invalid_title_should_display_errors
  186. @request.session[:user_id] = 2
  187. post :new, :params => {:project_id => 'ecookbook', :title => 'Another page'}, :xhr => true
  188. assert_response :success
  189. assert_include 'Title has already been taken', response.body
  190. end
  191. def test_create_page
  192. @request.session[:user_id] = 2
  193. assert_difference 'WikiPage.count' do
  194. assert_difference 'WikiContent.count' do
  195. put :update, :params => {
  196. :project_id => 1,
  197. :id => 'New page',
  198. :content => {
  199. :comments => 'Created the page',
  200. :text => "h1. New page\n\nThis is a new page",
  201. :version => 0
  202. }
  203. }
  204. end
  205. end
  206. assert_redirected_to :action => 'show', :project_id => 'ecookbook', :id => 'New_page'
  207. page = Project.find(1).wiki.find_page('New page')
  208. assert !page.new_record?
  209. assert_not_nil page.content
  210. assert_nil page.parent
  211. assert_equal 'Created the page', page.content.comments
  212. end
  213. def test_create_page_with_attachments
  214. @request.session[:user_id] = 2
  215. assert_difference 'WikiPage.count' do
  216. assert_difference 'Attachment.count' do
  217. put :update, :params => {
  218. :project_id => 1,
  219. :id => 'New page',
  220. :content => {
  221. :comments => 'Created the page',
  222. :text => "h1. New page\n\nThis is a new page",
  223. :version => 0
  224. },
  225. :attachments => {'1' => {'file' => uploaded_test_file('testfile.txt', 'text/plain')}}
  226. }
  227. end
  228. end
  229. page = Project.find(1).wiki.find_page('New page')
  230. assert_equal 1, page.attachments.count
  231. assert_equal 'testfile.txt', page.attachments.first.filename
  232. end
  233. def test_create_page_with_parent
  234. @request.session[:user_id] = 2
  235. assert_difference 'WikiPage.count' do
  236. put :update, :params => {
  237. :project_id => 1,
  238. :id => 'New page',
  239. :content => {
  240. :text => "h1. New page\n\nThis is a new page",
  241. :version => 0
  242. },
  243. :wiki_page => {:parent_id => 2}
  244. }
  245. end
  246. page = Project.find(1).wiki.find_page('New page')
  247. assert_equal WikiPage.find(2), page.parent
  248. end
  249. def test_edit_page
  250. @request.session[:user_id] = 2
  251. get :edit, :params => {:project_id => 'ecookbook', :id => 'Another_page'}
  252. assert_response :success
  253. assert_select 'textarea[name=?]', 'content[text]',
  254. :text => WikiPage.find_by_title('Another_page').content.text
  255. end
  256. def test_edit_section
  257. @request.session[:user_id] = 2
  258. get :edit, :params => {:project_id => 'ecookbook', :id => 'Page_with_sections', :section => 2}
  259. assert_response :success
  260. page = WikiPage.find_by_title('Page_with_sections')
  261. section, hash = Redmine::WikiFormatting::Textile::Formatter.new(page.content.text).get_section(2)
  262. assert_select 'textarea[name=?]', 'content[text]', :text => section
  263. assert_select 'input[name=section][type=hidden][value="2"]'
  264. assert_select 'input[name=section_hash][type=hidden][value=?]', hash
  265. end
  266. def test_edit_invalid_section_should_respond_with_404
  267. @request.session[:user_id] = 2
  268. get :edit, :params => {:project_id => 'ecookbook', :id => 'Page_with_sections', :section => 10}
  269. assert_response 404
  270. end
  271. def test_update_page
  272. @request.session[:user_id] = 2
  273. assert_no_difference 'WikiPage.count' do
  274. assert_no_difference 'WikiContent.count' do
  275. assert_difference 'WikiContentVersion.count' do
  276. put :update, :params => {
  277. :project_id => 1,
  278. :id => 'Another_page',
  279. :content => {
  280. :comments => "my comments",
  281. :text => "edited",
  282. :version => 1
  283. }
  284. }
  285. end
  286. end
  287. end
  288. assert_redirected_to '/projects/ecookbook/wiki/Another_page'
  289. page = Wiki.find(1).pages.find_by_title('Another_page')
  290. assert_equal "edited", page.content.text
  291. assert_equal 2, page.content.version
  292. assert_equal "my comments", page.content.comments
  293. end
  294. def test_update_page_with_parent
  295. @request.session[:user_id] = 2
  296. assert_no_difference 'WikiPage.count' do
  297. assert_no_difference 'WikiContent.count' do
  298. assert_difference 'WikiContentVersion.count' do
  299. put :update, :params => {
  300. :project_id => 1,
  301. :id => 'Another_page',
  302. :content => {
  303. :comments => "my comments",
  304. :text => "edited",
  305. :version => 1
  306. },
  307. :wiki_page => {:parent_id => '1'}
  308. }
  309. end
  310. end
  311. end
  312. assert_redirected_to '/projects/ecookbook/wiki/Another_page'
  313. page = Wiki.find(1).pages.find_by_title('Another_page')
  314. assert_equal "edited", page.content.text
  315. assert_equal 2, page.content.version
  316. assert_equal "my comments", page.content.comments
  317. assert_equal WikiPage.find(1), page.parent
  318. end
  319. def test_update_page_with_failure
  320. @request.session[:user_id] = 2
  321. assert_no_difference 'WikiPage.count' do
  322. assert_no_difference 'WikiContent.count' do
  323. assert_no_difference 'WikiContentVersion.count' do
  324. put :update, :params => {
  325. :project_id => 1,
  326. :id => 'Another_page',
  327. :content => {
  328. :comments => 'a' * 1300, # failure here, comment is too long
  329. :text => 'edited'
  330. },
  331. :wiki_page => {
  332. :parent_id => ""
  333. }
  334. }
  335. end
  336. end
  337. end
  338. assert_response :success
  339. assert_select_error /Comment is too long/
  340. assert_select 'textarea#content_text', :text => "edited"
  341. assert_select 'input#content_version[value="1"]'
  342. end
  343. def test_update_page_with_parent_change_only_should_not_create_content_version
  344. @request.session[:user_id] = 2
  345. assert_no_difference 'WikiPage.count' do
  346. assert_no_difference 'WikiContent.count' do
  347. assert_no_difference 'WikiContentVersion.count' do
  348. put :update, :params => {
  349. :project_id => 1,
  350. :id => 'Another_page',
  351. :content => {
  352. :comments => '',
  353. :text => Wiki.find(1).find_page('Another_page').content.text,
  354. :version => 1
  355. },
  356. :wiki_page => {:parent_id => '1'}
  357. }
  358. end
  359. end
  360. end
  361. page = Wiki.find(1).pages.find_by_title('Another_page')
  362. assert_equal 1, page.content.version
  363. assert_equal WikiPage.find(1), page.parent
  364. end
  365. def test_update_page_with_attachments_only_should_not_create_content_version
  366. @request.session[:user_id] = 2
  367. assert_no_difference 'WikiPage.count' do
  368. assert_no_difference 'WikiContent.count' do
  369. assert_no_difference 'WikiContentVersion.count' do
  370. assert_difference 'Attachment.count' do
  371. put :update, :params => {
  372. :project_id => 1,
  373. :id => 'Another_page',
  374. :content => {
  375. :comments => '',
  376. :text => Wiki.find(1).find_page('Another_page').content.text,
  377. :version => 1
  378. },
  379. :attachments => {'1' => {'file' => uploaded_test_file('testfile.txt', 'text/plain'), 'description' => 'test file'}}
  380. }
  381. end
  382. end
  383. end
  384. end
  385. page = Wiki.find(1).pages.find_by_title('Another_page')
  386. assert_equal 1, page.content.version
  387. end
  388. def test_update_with_deleted_attachment_ids
  389. @request.session[:user_id] = 2
  390. page = WikiPage.find(4)
  391. attachment = page.attachments.first
  392. assert_difference 'Attachment.count', -1 do
  393. put :update, :params => {
  394. :project_id => page.wiki.project.id,
  395. :id => page.title,
  396. :content => {
  397. :comments => 'delete file',
  398. :text => 'edited'
  399. },
  400. :wiki_page => {:deleted_attachment_ids => [attachment.id]}
  401. }
  402. end
  403. page.reload
  404. refute_includes page.attachments, attachment
  405. end
  406. def test_update_with_deleted_attachment_ids_and_failure_should_preserve_selected_attachments
  407. @request.session[:user_id] = 2
  408. page = WikiPage.find(4)
  409. attachment = page.attachments.first
  410. assert_no_difference 'Attachment.count' do
  411. put :update, :params => {
  412. :project_id => page.wiki.project.id,
  413. :id => page.title,
  414. :content => {
  415. :comments => 'a' * 1300, # failure here, comment is too long
  416. :text => 'edited'
  417. },
  418. :wiki_page => {:deleted_attachment_ids => [attachment.id]}
  419. }
  420. end
  421. page.reload
  422. assert_includes page.attachments, attachment
  423. end
  424. def test_update_stale_page_should_not_raise_an_error
  425. @request.session[:user_id] = 2
  426. c = Wiki.find(1).find_page('Another_page').content
  427. c.text = 'Previous text'
  428. c.save!
  429. assert_equal 2, c.version
  430. assert_no_difference 'WikiPage.count' do
  431. assert_no_difference 'WikiContent.count' do
  432. assert_no_difference 'WikiContentVersion.count' do
  433. put :update, :params => {
  434. :project_id => 1,
  435. :id => 'Another_page',
  436. :content => {
  437. :comments => 'My comments',
  438. :text => 'Text should not be lost',
  439. :version => 1
  440. }
  441. }
  442. end
  443. end
  444. end
  445. assert_response :success
  446. assert_select 'div.error', :text => /Data has been updated by another user/
  447. assert_select 'textarea[name=?]', 'content[text]', :text => /Text should not be lost/
  448. assert_select 'input[name=?][value=?]', 'content[comments]', 'My comments'
  449. c.reload
  450. assert_equal 'Previous text', c.text
  451. assert_equal 2, c.version
  452. end
  453. def test_update_page_without_content_should_create_content
  454. @request.session[:user_id] = 2
  455. page = WikiPage.create!(:title => 'NoContent', :wiki => Project.find(1).wiki)
  456. assert_no_difference 'WikiPage.count' do
  457. assert_difference 'WikiContent.count' do
  458. put :update, :params => {
  459. :project_id => 1,
  460. :id => 'NoContent',
  461. :content => {:text => 'Some content'}
  462. }
  463. assert_response 302
  464. end
  465. end
  466. assert_equal 'Some content', page.reload.content.text
  467. end
  468. def test_update_section
  469. @request.session[:user_id] = 2
  470. page = WikiPage.find_by_title('Page_with_sections')
  471. section, hash = Redmine::WikiFormatting::Textile::Formatter.new(page.content.text).get_section(2)
  472. text = page.content.text
  473. assert_no_difference 'WikiPage.count' do
  474. assert_no_difference 'WikiContent.count' do
  475. assert_difference 'WikiContentVersion.count' do
  476. put :update, :params => {
  477. :project_id => 1,
  478. :id => 'Page_with_sections',
  479. :content => {
  480. :text => "New section content",
  481. :version => 3
  482. },
  483. :section => 2,
  484. :section_hash => hash
  485. }
  486. end
  487. end
  488. end
  489. assert_redirected_to '/projects/ecookbook/wiki/Page_with_sections#section-2'
  490. assert_equal Redmine::WikiFormatting::Textile::Formatter.new(text).update_section(2, "New section content"), page.reload.content.text
  491. end
  492. def test_update_section_should_allow_stale_page_update
  493. @request.session[:user_id] = 2
  494. page = WikiPage.find_by_title('Page_with_sections')
  495. section, hash = Redmine::WikiFormatting::Textile::Formatter.new(page.content.text).get_section(2)
  496. text = page.content.text
  497. assert_no_difference 'WikiPage.count' do
  498. assert_no_difference 'WikiContent.count' do
  499. assert_difference 'WikiContentVersion.count' do
  500. put :update, :params => {
  501. :project_id => 1,
  502. :id => 'Page_with_sections',
  503. :content => {
  504. :text => "New section content",
  505. :version => 2 # Current version is 3
  506. },
  507. :section => 2,
  508. :section_hash => hash
  509. }
  510. end
  511. end
  512. end
  513. assert_redirected_to '/projects/ecookbook/wiki/Page_with_sections#section-2'
  514. page.reload
  515. assert_equal Redmine::WikiFormatting::Textile::Formatter.new(text).update_section(2, "New section content"), page.content.text
  516. assert_equal 4, page.content.version
  517. end
  518. def test_update_section_should_not_allow_stale_section_update
  519. @request.session[:user_id] = 2
  520. assert_no_difference 'WikiPage.count' do
  521. assert_no_difference 'WikiContent.count' do
  522. assert_no_difference 'WikiContentVersion.count' do
  523. put :update, :params => {
  524. :project_id => 1,
  525. :id => 'Page_with_sections',
  526. :content => {
  527. :comments => 'My comments',
  528. :text => "Text should not be lost",
  529. :version => 3
  530. },
  531. :section => 2,
  532. :section_hash => Digest::MD5.hexdigest("wrong hash")
  533. }
  534. end
  535. end
  536. end
  537. assert_response :success
  538. assert_select 'div.error', :text => /Data has been updated by another user/
  539. assert_select 'textarea[name=?]', 'content[text]', :text => /Text should not be lost/
  540. assert_select 'input[name=?][value=?]', 'content[comments]', 'My comments'
  541. end
  542. def test_preview
  543. @request.session[:user_id] = 2
  544. post :preview, :params => {
  545. :project_id => 1,
  546. :id => 'CookBook_documentation',
  547. :content => {
  548. :comments => '',
  549. :text => 'this is a *previewed text*',
  550. :version => 3
  551. }
  552. }, :xhr => true
  553. assert_response :success
  554. assert_select 'strong', :text => /previewed text/
  555. end
  556. def test_preview_new_page
  557. @request.session[:user_id] = 2
  558. post :preview, :params => {
  559. :project_id => 1,
  560. :id => 'New page',
  561. :content => {
  562. :text => 'h1. New page',
  563. :comments => '',
  564. :version => 0
  565. }
  566. }, :xhr => true
  567. assert_response :success
  568. assert_select 'h1', :text => /New page/
  569. end
  570. def test_history
  571. @request.session[:user_id] = 2
  572. get :history, :params => {:project_id => 'ecookbook', :id => 'CookBook_documentation'}
  573. assert_response :success
  574. assert_select 'table.wiki-page-versions tbody' do
  575. assert_select 'tr', 3
  576. end
  577. assert_select "input[type=submit][name=commit]"
  578. assert_select 'td' do
  579. assert_select 'a[href=?]', '/projects/ecookbook/wiki/CookBook_documentation/2', :text => '2'
  580. assert_select 'a[href=?]', '/projects/ecookbook/wiki/CookBook_documentation/2/annotate', :text => 'Annotate'
  581. assert_select 'a[href=?]', '/projects/ecookbook/wiki/CookBook_documentation/2', :text => 'Delete'
  582. end
  583. end
  584. def test_history_with_one_version
  585. @request.session[:user_id] = 2
  586. get :history, :params => {:project_id => 'ecookbook', :id => 'Another_page'}
  587. assert_response :success
  588. assert_select 'table.wiki-page-versions tbody' do
  589. assert_select 'tr', 1
  590. end
  591. assert_select "input[type=submit][name=commit]", false
  592. assert_select 'td' do
  593. assert_select 'a[href=?]', '/projects/ecookbook/wiki/Another_page/1', :text => '1'
  594. assert_select 'a[href=?]', '/projects/ecookbook/wiki/Another_page/1/annotate', :text => 'Annotate'
  595. assert_select 'a[href=?]', '/projects/ecookbook/wiki/Another_page/1', :text => 'Delete', :count => 0
  596. end
  597. end
  598. def test_diff
  599. content = WikiPage.find(1).content
  600. assert_difference 'WikiContentVersion.count', 2 do
  601. content.text = "Line removed\nThis is a sample text for testing diffs"
  602. content.save!
  603. content.text = "This is a sample text for testing diffs\nLine added"
  604. content.save!
  605. end
  606. get :diff, :params => {
  607. :project_id => 1, :id => 'CookBook_documentation',
  608. :version => content.version,
  609. :version_from => (content.version - 1)
  610. }
  611. assert_response :success
  612. assert_select 'span.diff_out', :text => 'Line removed'
  613. assert_select 'span.diff_in', :text => 'Line added'
  614. end
  615. def test_diff_with_invalid_version_should_respond_with_404
  616. get :diff, :params => {
  617. :project_id => 1, :id => 'CookBook_documentation',
  618. :version => '99'
  619. }
  620. assert_response 404
  621. end
  622. def test_diff_with_invalid_version_from_should_respond_with_404
  623. get :diff, :params => {
  624. :project_id => 1, :id => 'CookBook_documentation',
  625. :version => '99',
  626. :version_from => '98'
  627. }
  628. assert_response 404
  629. end
  630. def test_annotate
  631. get :annotate, :params => {
  632. :project_id => 1, :id => 'CookBook_documentation',
  633. :version => 2
  634. }
  635. assert_response :success
  636. # Line 1
  637. assert_select 'table.annotate tr:nth-child(1)' do
  638. assert_select 'th.line-num', :text => '1'
  639. assert_select 'td.author', :text => /Redmine Admin/
  640. assert_select 'td', :text => /h1\. CookBook documentation v2/
  641. end
  642. # Line 2
  643. assert_select 'table.annotate tr:nth-child(2)' do
  644. assert_select 'th.line-num', :text => '2'
  645. assert_select 'td.author', :text => /John Smith/
  646. end
  647. # Line 5
  648. assert_select 'table.annotate tr:nth-child(5)' do
  649. assert_select 'th.line-num', :text => '5'
  650. assert_select 'td.author', :text => /Redmine Admin/
  651. assert_select 'td', :text => /Some updated \[\[documentation\]\] here/
  652. end
  653. end
  654. def test_annotate_with_invalid_version_should_respond_with_404
  655. get :annotate, :params => {
  656. :project_id => 1, :id => 'CookBook_documentation',
  657. :version => '99'
  658. }
  659. assert_response 404
  660. end
  661. def test_get_rename
  662. @request.session[:user_id] = 2
  663. get :rename, :params => {:project_id => 1, :id => 'Another_page'}
  664. assert_response :success
  665. assert_select 'select[name=?]', 'wiki_page[parent_id]' do
  666. assert_select 'option[value=""]', :text => ''
  667. assert_select 'option[selected=selected]', 0
  668. end
  669. end
  670. def test_get_rename_child_page
  671. @request.session[:user_id] = 2
  672. get :rename, :params => {:project_id => 1, :id => 'Child_1'}
  673. assert_response :success
  674. assert_select 'select[name=?]', 'wiki_page[parent_id]' do
  675. assert_select 'option[value=""]', :text => ''
  676. assert_select 'option[value="2"][selected=selected]', :text => /Another page/
  677. end
  678. end
  679. def test_rename_with_redirect
  680. @request.session[:user_id] = 2
  681. post :rename, :params => {
  682. :project_id => 1,
  683. :id => 'Another_page',
  684. :wiki_page => {
  685. :title => 'Another renamed page',
  686. :redirect_existing_links => 1
  687. }
  688. }
  689. assert_redirected_to :action => 'show', :project_id => 'ecookbook', :id => 'Another_renamed_page'
  690. wiki = Project.find(1).wiki
  691. # Check redirects
  692. assert_not_nil wiki.find_page('Another page')
  693. assert_nil wiki.find_page('Another page', :with_redirect => false)
  694. end
  695. def test_rename_without_redirect
  696. @request.session[:user_id] = 2
  697. post :rename, :params => {
  698. :project_id => 1,
  699. :id => 'Another_page',
  700. :wiki_page => {
  701. :title => 'Another renamed page',
  702. :redirect_existing_links => "0"
  703. }
  704. }
  705. assert_redirected_to :action => 'show', :project_id => 'ecookbook', :id => 'Another_renamed_page'
  706. wiki = Project.find(1).wiki
  707. # Check that there's no redirects
  708. assert_nil wiki.find_page('Another page')
  709. end
  710. def test_rename_with_parent_assignment
  711. @request.session[:user_id] = 2
  712. post :rename, :params => {
  713. :project_id => 1,
  714. :id => 'Another_page',
  715. :wiki_page => {
  716. :title => 'Another page',
  717. :redirect_existing_links => "0",
  718. :parent_id => '4'
  719. }
  720. }
  721. assert_redirected_to :action => 'show', :project_id => 'ecookbook', :id => 'Another_page'
  722. assert_equal WikiPage.find(4), WikiPage.find_by_title('Another_page').parent
  723. end
  724. def test_rename_with_parent_unassignment
  725. @request.session[:user_id] = 2
  726. post :rename, :params => {
  727. :project_id => 1,
  728. :id => 'Child_1',
  729. :wiki_page => {
  730. :title => 'Child 1',
  731. :redirect_existing_links => "0",
  732. :parent_id => ''
  733. }
  734. }
  735. assert_redirected_to :action => 'show', :project_id => 'ecookbook', :id => 'Child_1'
  736. assert_nil WikiPage.find_by_title('Child_1').parent
  737. end
  738. def test_get_rename_should_show_target_projects_list
  739. @request.session[:user_id] = 2
  740. project = Project.find(5)
  741. project.enable_module! :wiki
  742. get :rename, :params => {:project_id => 1, :id => 'Another_page'}
  743. assert_response :success
  744. assert_select 'select[name=?]', 'wiki_page[wiki_id]' do
  745. assert_select 'option', 2
  746. assert_select 'option[value=?][selected=selected]', '1', :text => /eCookbook/
  747. assert_select 'option[value=?]', project.wiki.id.to_s, :text => /#{project.name}/
  748. end
  749. end
  750. def test_rename_with_move
  751. @request.session[:user_id] = 2
  752. project = Project.find(5)
  753. project.enable_module! :wiki
  754. post :rename, :params => {
  755. :project_id => 1,
  756. :id => 'Another_page',
  757. :wiki_page => {
  758. :wiki_id => project.wiki.id.to_s,
  759. :title => 'Another renamed page',
  760. :redirect_existing_links => 1
  761. }
  762. }
  763. assert_redirected_to '/projects/private-child/wiki/Another_renamed_page'
  764. page = WikiPage.find(2)
  765. assert_equal project.wiki.id, page.wiki_id
  766. end
  767. def test_rename_as_start_page
  768. @request.session[:user_id] = 2
  769. post :rename, :params => {
  770. :project_id => 'ecookbook',
  771. :id => 'Another_page',
  772. :wiki_page => {
  773. :wiki_id => '1',
  774. :title => 'Another_page',
  775. :redirect_existing_links => '1',
  776. :is_start_page => '1'
  777. }
  778. }
  779. assert_redirected_to '/projects/ecookbook/wiki/Another_page'
  780. wiki = Wiki.find(1)
  781. assert_equal 'Another_page', wiki.start_page
  782. end
  783. def test_destroy_a_page_without_children_should_not_ask_confirmation
  784. @request.session[:user_id] = 2
  785. delete :destroy, :params => {:project_id => 1, :id => 'Child_2'}
  786. assert_redirected_to :action => 'index', :project_id => 'ecookbook'
  787. end
  788. def test_destroy_parent_should_ask_confirmation
  789. @request.session[:user_id] = 2
  790. assert_no_difference('WikiPage.count') do
  791. delete :destroy, :params => {:project_id => 1, :id => 'Another_page'}
  792. end
  793. assert_response :success
  794. assert_select 'form' do
  795. assert_select 'input[name=todo][value=nullify]'
  796. assert_select 'input[name=todo][value=destroy]'
  797. assert_select 'input[name=todo][value=reassign]'
  798. end
  799. end
  800. def test_destroy_parent_with_nullify_should_delete_parent_only
  801. @request.session[:user_id] = 2
  802. assert_difference('WikiPage.count', -1) do
  803. delete :destroy, :params => {:project_id => 1, :id => 'Another_page', :todo => 'nullify'}
  804. end
  805. assert_redirected_to :action => 'index', :project_id => 'ecookbook'
  806. assert_nil WikiPage.find_by_id(2)
  807. end
  808. def test_destroy_parent_with_cascade_should_delete_descendants
  809. @request.session[:user_id] = 2
  810. assert_difference('WikiPage.count', -4) do
  811. delete :destroy, :params => {:project_id => 1, :id => 'Another_page', :todo => 'destroy'}
  812. end
  813. assert_redirected_to :action => 'index', :project_id => 'ecookbook'
  814. assert_nil WikiPage.find_by_id(2)
  815. assert_nil WikiPage.find_by_id(5)
  816. end
  817. def test_destroy_parent_with_reassign
  818. @request.session[:user_id] = 2
  819. assert_difference('WikiPage.count', -1) do
  820. delete :destroy, :params => {:project_id => 1, :id => 'Another_page', :todo => 'reassign', :reassign_to_id => 1}
  821. end
  822. assert_redirected_to :action => 'index', :project_id => 'ecookbook'
  823. assert_nil WikiPage.find_by_id(2)
  824. assert_equal WikiPage.find(1), WikiPage.find_by_id(5).parent
  825. end
  826. def test_destroy_version
  827. @request.session[:user_id] = 2
  828. assert_difference 'WikiContentVersion.count', -1 do
  829. assert_no_difference 'WikiContent.count' do
  830. assert_no_difference 'WikiPage.count' do
  831. delete :destroy_version, :params => {:project_id => 'ecookbook', :id => 'CookBook_documentation', :version => 2}
  832. assert_redirected_to '/projects/ecookbook/wiki/CookBook_documentation/history'
  833. end
  834. end
  835. end
  836. end
  837. def test_destroy_invalid_version_should_respond_with_404
  838. @request.session[:user_id] = 2
  839. assert_no_difference 'WikiContentVersion.count' do
  840. assert_no_difference 'WikiContent.count' do
  841. assert_no_difference 'WikiPage.count' do
  842. delete :destroy_version, :params => {:project_id => 'ecookbook', :id => 'CookBook_documentation', :version => 99}
  843. end
  844. end
  845. end
  846. assert_response 404
  847. end
  848. def test_index
  849. get :index, :params => {:project_id => 'ecookbook'}
  850. assert_response :success
  851. assert_select 'ul.pages-hierarchy' do
  852. assert_select 'li', Project.find(1).wiki.pages.count
  853. end
  854. assert_select 'ul.pages-hierarchy' do
  855. assert_select 'li' do
  856. assert_select 'a[href=?]', '/projects/ecookbook/wiki/CookBook_documentation', :text => 'CookBook documentation'
  857. assert_select 'ul li a[href=?]', '/projects/ecookbook/wiki/Page_with_an_inline_image', :text => 'Page with an inline image'
  858. end
  859. assert_select 'li a[href=?]', '/projects/ecookbook/wiki/Another_page', :text => 'Another page'
  860. end
  861. end
  862. def test_index_should_include_atom_link
  863. get :index, :params => {:project_id => 'ecookbook'}
  864. assert_select 'a[href=?]', '/projects/ecookbook/activity.atom?show_wiki_edits=1'
  865. end
  866. def test_export_to_html
  867. @request.session[:user_id] = 2
  868. get :export, :params => {:project_id => 'ecookbook'}
  869. assert_response :success
  870. assert_equal "text/html", @response.content_type
  871. assert_select "a[name=?]", "CookBook_documentation"
  872. assert_select "a[name=?]", "Another_page"
  873. assert_select "a[name=?]", "Page_with_an_inline_image"
  874. end
  875. def test_export_to_pdf
  876. @request.session[:user_id] = 2
  877. get :export, :params => {:project_id => 'ecookbook', :format => 'pdf'}
  878. assert_response :success
  879. assert_equal 'application/pdf', @response.content_type
  880. assert_equal 'attachment; filename="ecookbook.pdf"', @response.headers['Content-Disposition']
  881. assert @response.body.starts_with?('%PDF')
  882. end
  883. def test_export_without_permission_should_be_denied
  884. @request.session[:user_id] = 2
  885. Role.find_by_name('Manager').remove_permission! :export_wiki_pages
  886. get :export, :params => {:project_id => 'ecookbook'}
  887. assert_response 403
  888. end
  889. def test_date_index
  890. get :date_index, :params => {:project_id => 'ecookbook'}
  891. assert_response :success
  892. assert_select 'a[href=?]', '/projects/ecookbook/activity.atom?show_wiki_edits=1'
  893. end
  894. def test_not_found
  895. get :show, :params => {:project_id => 999}
  896. assert_response 404
  897. end
  898. def test_protect_page
  899. page = WikiPage.find_by_wiki_id_and_title(1, 'Another_page')
  900. assert !page.protected?
  901. @request.session[:user_id] = 2
  902. post :protect, :params => {:project_id => 1, :id => page.title, :protected => '1'}
  903. assert_redirected_to :action => 'show', :project_id => 'ecookbook', :id => 'Another_page'
  904. assert page.reload.protected?
  905. end
  906. def test_unprotect_page
  907. page = WikiPage.find_by_wiki_id_and_title(1, 'CookBook_documentation')
  908. assert page.protected?
  909. @request.session[:user_id] = 2
  910. post :protect, :params => {:project_id => 1, :id => page.title, :protected => '0'}
  911. assert_redirected_to :action => 'show', :project_id => 'ecookbook', :id => 'CookBook_documentation'
  912. assert !page.reload.protected?
  913. end
  914. def test_show_page_with_edit_link
  915. @request.session[:user_id] = 2
  916. get :show, :params => {:project_id => 1}
  917. assert_response :success
  918. assert_select 'a[href=?]', '/projects/1/wiki/CookBook_documentation/edit'
  919. end
  920. def test_show_page_without_edit_link
  921. @request.session[:user_id] = 4
  922. get :show, :params => {:project_id => 1}
  923. assert_response :success
  924. assert_select 'a[href=?]', '/projects/1/wiki/CookBook_documentation/edit', 0
  925. end
  926. def test_show_pdf
  927. @request.session[:user_id] = 2
  928. get :show, :params => {:project_id => 1, :format => 'pdf'}
  929. assert_response :success
  930. assert_equal 'application/pdf', @response.content_type
  931. assert_equal 'attachment; filename="CookBook_documentation.pdf"',
  932. @response.headers['Content-Disposition']
  933. end
  934. def test_show_html
  935. @request.session[:user_id] = 2
  936. get :show, :params => {:project_id => 1, :format => 'html'}
  937. assert_response :success
  938. assert_equal 'text/html', @response.content_type
  939. assert_equal 'attachment; filename="CookBook_documentation.html"',
  940. @response.headers['Content-Disposition']
  941. assert_select 'h1', :text => /CookBook documentation/
  942. end
  943. def test_show_versioned_html
  944. @request.session[:user_id] = 2
  945. get :show, :params => {:project_id => 1, :format => 'html', :version => 2}
  946. assert_response :success
  947. assert_equal 'text/html', @response.content_type
  948. assert_equal 'attachment; filename="CookBook_documentation.html"',
  949. @response.headers['Content-Disposition']
  950. assert_select 'h1', :text => /CookBook documentation v2/
  951. end
  952. def test_show_txt
  953. @request.session[:user_id] = 2
  954. get :show, :params => {:project_id => 1, :format => 'txt'}
  955. assert_response :success
  956. assert_equal 'text/plain', @response.content_type
  957. assert_equal 'attachment; filename="CookBook_documentation.txt"',
  958. @response.headers['Content-Disposition']
  959. assert_include 'h1. CookBook documentation', @response.body
  960. end
  961. def test_show_versioned_txt
  962. @request.session[:user_id] = 2
  963. get :show, :params => {:project_id => 1, :format => 'txt', :version => 2}
  964. assert_response :success
  965. assert_equal 'text/plain', @response.content_type
  966. assert_equal 'attachment; filename="CookBook_documentation.txt"',
  967. @response.headers['Content-Disposition']
  968. assert_include 'h1. CookBook documentation v2', @response.body
  969. end
  970. def test_show_filename_should_be_uri_encoded_for_ms_browsers
  971. @request.session[:user_id] = 2
  972. title = 'Этика_менеджмента'
  973. %w|pdf html txt|.each do |format|
  974. # Non-MS browsers
  975. @request.user_agent = ""
  976. get :show, :params => {:project_id => 1, :id => title, :format => format}
  977. assert_response :success
  978. assert_equal "attachment; filename=\"#{title}.#{format}\"",
  979. @response.headers['Content-Disposition']
  980. # Microsoft's browsers: filename should be URI encoded
  981. @request.user_agent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36 Edge/15.15063'
  982. get :show, :params => {:project_id => 1, :id => title, :format => format}
  983. assert_response :success
  984. filename = URI.encode("#{title}.#{format}")
  985. assert_equal "attachment; filename=\"#{filename}\"",
  986. @response.headers['Content-Disposition']
  987. end
  988. end
  989. def test_edit_unprotected_page
  990. # Non members can edit unprotected wiki pages
  991. @request.session[:user_id] = 4
  992. get :edit, :params => {:project_id => 1, :id => 'Another_page'}
  993. assert_response :success
  994. end
  995. def test_edit_protected_page_by_nonmember
  996. # Non members cannot edit protected wiki pages
  997. @request.session[:user_id] = 4
  998. get :edit, :params => {:project_id => 1, :id => 'CookBook_documentation'}
  999. assert_response 403
  1000. end
  1001. def test_edit_protected_page_by_member
  1002. @request.session[:user_id] = 2
  1003. get :edit, :params => {:project_id => 1, :id => 'CookBook_documentation'}
  1004. assert_response :success
  1005. end
  1006. def test_history_of_non_existing_page_should_return_404
  1007. get :history, :params => {:project_id => 1, :id => 'Unknown_page'}
  1008. assert_response 404
  1009. end
  1010. def test_add_attachment
  1011. @request.session[:user_id] = 2
  1012. assert_difference 'Attachment.count' do
  1013. post :add_attachment, :params => {
  1014. :project_id => 1,
  1015. :id => 'CookBook_documentation',
  1016. :attachments => {
  1017. '1' => {'file' => uploaded_test_file('testfile.txt', 'text/plain'), 'description' => 'test file'}
  1018. }
  1019. }
  1020. end
  1021. attachment = Attachment.order('id DESC').first
  1022. assert_equal Wiki.find(1).find_page('CookBook_documentation'), attachment.container
  1023. end
  1024. def test_old_version_should_have_robot_exclusion_tag
  1025. @request.session[:user_id] = 2
  1026. # Discourage search engines from indexing old versions
  1027. get :show, :params => {:project_id => 'ecookbook', :id => 'CookBook_documentation', :version => '2'}
  1028. assert_response :success
  1029. assert_select 'head>meta[name="robots"][content=?]', 'noindex,follow,noarchive'
  1030. # No robots meta tag in the current version
  1031. get :show, :params => {:project_id => 'ecookbook', :id => 'CookBook_documentation'}
  1032. assert_response :success
  1033. assert_select 'head>meta[name="robots"]', false
  1034. end
  1035. end