v5.page.test.ts 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609
  1. /* eslint-disable no-unused-vars */
  2. import { advanceTo } from 'jest-date-mock';
  3. import mongoose from 'mongoose';
  4. import { getInstance } from '../setup-crowi';
  5. describe('PageService page operations with only public pages', () => {
  6. let dummyUser1;
  7. let dummyUser2;
  8. let crowi;
  9. let Page;
  10. let Revision;
  11. let User;
  12. let Tag;
  13. let PageTagRelation;
  14. let Bookmark;
  15. let Comment;
  16. let ShareLink;
  17. let PageRedirect;
  18. let xssSpy;
  19. let rootPage;
  20. // pass unless the data is one of [false, 0, '', null, undefined, NaN]
  21. const expectAllToBeTruthy = (dataList) => {
  22. dataList.forEach((data) => {
  23. expect(data).toBeTruthy();
  24. });
  25. };
  26. beforeAll(async() => {
  27. crowi = await getInstance();
  28. await crowi.configManager.updateConfigsInTheSameNamespace('crowi', { 'app:isV5Compatible': true });
  29. User = mongoose.model('User');
  30. Page = mongoose.model('Page');
  31. Revision = mongoose.model('Revision');
  32. Tag = mongoose.model('Tag');
  33. PageTagRelation = mongoose.model('PageTagRelation');
  34. Bookmark = mongoose.model('Bookmark');
  35. Comment = mongoose.model('Comment');
  36. ShareLink = mongoose.model('ShareLink');
  37. PageRedirect = mongoose.model('PageRedirect');
  38. /*
  39. * Common
  40. */
  41. await User.insertMany([
  42. { name: 'v5DummyUser1', username: 'v5DummyUser1', email: 'v5DummyUser1@example.com' },
  43. { name: 'v5DummyUser2', username: 'v5DummyUser2', email: 'v5DummyUser2@example.com' },
  44. ]);
  45. dummyUser1 = await User.findOne({ username: 'v5DummyUser1' });
  46. if (dummyUser1 == null) {
  47. dummyUser1 = await User.create({ name: 'v5DummyUser1', username: 'v5DummyUser1', email: 'v5DummyUser1@example.com' });
  48. }
  49. dummyUser2 = await User.findOne({ username: 'v5DummyUser2' });
  50. if (dummyUser2 == null) {
  51. dummyUser2 = await User.create({ name: 'v5DummyUser2', username: 'v5DummyUser2', email: 'v5DummyUser2@example.com' });
  52. }
  53. xssSpy = jest.spyOn(crowi.xss, 'process').mockImplementation(path => path);
  54. rootPage = await Page.findOne({ path: '/' });
  55. if (rootPage == null) {
  56. const pages = await Page.insertMany([{ path: '/', grant: Page.GRANT_PUBLIC }]);
  57. rootPage = pages[0];
  58. }
  59. /*
  60. * Rename
  61. */
  62. const pageIdForRename1 = new mongoose.Types.ObjectId();
  63. const pageIdForRename2 = new mongoose.Types.ObjectId();
  64. const pageIdForRename3 = new mongoose.Types.ObjectId();
  65. const pageIdForRename4 = new mongoose.Types.ObjectId();
  66. const pageIdForRename5 = new mongoose.Types.ObjectId();
  67. const pageIdForRename7 = new mongoose.Types.ObjectId();
  68. const pageIdForRename8 = new mongoose.Types.ObjectId();
  69. const pageIdForRename9 = new mongoose.Types.ObjectId();
  70. const pageIdForRename10 = new mongoose.Types.ObjectId();
  71. const pageIdForRename11 = new mongoose.Types.ObjectId();
  72. const pageIdForRename12 = new mongoose.Types.ObjectId();
  73. const pageIdForRename13 = new mongoose.Types.ObjectId();
  74. const pageIdForRename14 = new mongoose.Types.ObjectId();
  75. const pageIdForRename16 = new mongoose.Types.ObjectId();
  76. // Create Pages
  77. await Page.insertMany([
  78. // parents
  79. {
  80. _id: pageIdForRename1,
  81. path: '/v5_ParentForRename1',
  82. grant: Page.GRANT_PUBLIC,
  83. creator: dummyUser1,
  84. lastUpdateUser: dummyUser1._id,
  85. parent: rootPage._id,
  86. },
  87. {
  88. _id: pageIdForRename2,
  89. path: '/v5_ParentForRename2',
  90. grant: Page.GRANT_PUBLIC,
  91. parent: rootPage._id,
  92. isEmpty: true,
  93. },
  94. {
  95. // id not needed for this data
  96. path: '/v5_ParentForRename2/dummyChild1',
  97. grant: Page.GRANT_PUBLIC,
  98. creator: dummyUser1,
  99. lastUpdateUser: dummyUser1._id,
  100. parent: pageIdForRename2,
  101. },
  102. {
  103. _id: pageIdForRename3,
  104. path: '/v5_ParentForRename3',
  105. grant: Page.GRANT_PUBLIC,
  106. creator: dummyUser1,
  107. lastUpdateUser: dummyUser1._id,
  108. parent: rootPage._id,
  109. },
  110. {
  111. _id: pageIdForRename4,
  112. path: '/v5_ParentForRename4',
  113. grant: Page.GRANT_PUBLIC,
  114. creator: dummyUser1,
  115. lastUpdateUser: dummyUser1._id,
  116. parent: rootPage._id,
  117. },
  118. {
  119. _id: pageIdForRename5,
  120. path: '/v5_ParentForRename5',
  121. grant: Page.GRANT_PUBLIC,
  122. creator: dummyUser1,
  123. lastUpdateUser: dummyUser1._id,
  124. parent: rootPage._id,
  125. },
  126. {
  127. _id: pageIdForRename7,
  128. path: '/v5_ParentForRename7',
  129. grant: Page.GRANT_PUBLIC,
  130. creator: dummyUser1,
  131. lastUpdateUser: dummyUser1._id,
  132. parent: rootPage._id,
  133. },
  134. {
  135. _id: pageIdForRename8,
  136. path: '/v5_ParentForRename8',
  137. grant: Page.GRANT_PUBLIC,
  138. creator: dummyUser1,
  139. lastUpdateUser: dummyUser1._id,
  140. parent: rootPage._id,
  141. },
  142. {
  143. _id: pageIdForRename9,
  144. path: '/v5_ParentForRename9',
  145. grant: Page.GRANT_PUBLIC,
  146. creator: dummyUser1,
  147. lastUpdateUser: dummyUser1._id,
  148. parent: rootPage._id,
  149. },
  150. // children
  151. {
  152. _id: pageIdForRename10,
  153. path: '/v5_ChildForRename1',
  154. grant: Page.GRANT_PUBLIC,
  155. creator: dummyUser1,
  156. lastUpdateUser: dummyUser1._id,
  157. parent: rootPage._id,
  158. },
  159. {
  160. _id: pageIdForRename11,
  161. path: '/v5_ChildForRename2',
  162. grant: Page.GRANT_PUBLIC,
  163. creator: dummyUser1,
  164. lastUpdateUser: dummyUser1._id,
  165. parent: rootPage._id,
  166. },
  167. {
  168. _id: pageIdForRename12,
  169. path: '/v5_ChildForRename3',
  170. grant: Page.GRANT_PUBLIC,
  171. creator: dummyUser1,
  172. lastUpdateUser: dummyUser1._id,
  173. parent: rootPage._id,
  174. updatedAt: new Date('2021'),
  175. },
  176. {
  177. _id: pageIdForRename13,
  178. path: '/v5_ChildForRename4',
  179. grant: Page.GRANT_PUBLIC,
  180. creator: dummyUser1,
  181. lastUpdateUser: dummyUser1._id,
  182. parent: rootPage._id,
  183. },
  184. {
  185. _id: pageIdForRename14,
  186. path: '/v5_ChildForRename5',
  187. grant: Page.GRANT_PUBLIC,
  188. creator: dummyUser1,
  189. lastUpdateUser: dummyUser1._id,
  190. parent: rootPage._id,
  191. },
  192. {
  193. _id: pageIdForRename16,
  194. path: '/v5_ChildForRename7',
  195. grant: Page.GRANT_PUBLIC,
  196. parent: rootPage._id,
  197. isEmpty: true,
  198. },
  199. // Grandchild
  200. {
  201. path: '/v5_ChildForRename5/v5_GrandchildForRename5',
  202. grant: Page.GRANT_PUBLIC,
  203. creator: dummyUser1,
  204. lastUpdateUser: dummyUser1._id,
  205. parent: pageIdForRename14,
  206. updatedAt: new Date('2021'),
  207. },
  208. {
  209. path: '/v5_ChildForRename7/v5_GrandchildForRename7',
  210. grant: Page.GRANT_PUBLIC,
  211. creator: dummyUser1,
  212. lastUpdateUser: dummyUser1._id,
  213. parent: pageIdForRename16,
  214. },
  215. ]);
  216. /**
  217. * Delete
  218. */
  219. const pageIdForDelete1 = new mongoose.Types.ObjectId();
  220. const pageIdForDelete2 = new mongoose.Types.ObjectId();
  221. const pageIdForDelete3 = new mongoose.Types.ObjectId();
  222. const pageIdForDelete4 = new mongoose.Types.ObjectId();
  223. const pageIdForDelete5 = new mongoose.Types.ObjectId();
  224. await Page.insertMany([
  225. {
  226. path: '/trash/v5_PageForDelete1',
  227. grant: Page.GRANT_PUBLIC,
  228. creator: dummyUser1,
  229. lastUpdateUser: dummyUser1._id,
  230. status: Page.STATUS_DELETED,
  231. },
  232. {
  233. path: '/v5_PageForDelete2',
  234. grant: Page.GRANT_PUBLIC,
  235. creator: dummyUser1,
  236. lastUpdateUser: dummyUser1._id,
  237. parent: rootPage._id,
  238. status: Page.STATUS_PUBLISHED,
  239. },
  240. {
  241. _id: pageIdForDelete1,
  242. path: '/v5_PageForDelete3',
  243. grant: Page.GRANT_PUBLIC,
  244. creator: dummyUser1,
  245. lastUpdateUser: dummyUser1._id,
  246. parent: rootPage._id,
  247. status: Page.STATUS_PUBLISHED,
  248. },
  249. {
  250. _id: pageIdForDelete2,
  251. path: '/v5_PageForDelete3/v5_PageForDelete4',
  252. grant: Page.GRANT_PUBLIC,
  253. parent: pageIdForDelete1,
  254. status: Page.STATUS_PUBLISHED,
  255. isEmpty: true,
  256. },
  257. {
  258. path: '/v5_PageForDelete3/v5_PageForDelete4/v5_PageForDelete5',
  259. grant: Page.GRANT_PUBLIC,
  260. creator: dummyUser1,
  261. lastUpdateUser: dummyUser1._id,
  262. parent: pageIdForDelete2,
  263. status: Page.STATUS_PUBLISHED,
  264. },
  265. {
  266. _id: pageIdForDelete3,
  267. path: '/v5_PageForDelete6',
  268. grant: Page.GRANT_PUBLIC,
  269. creator: dummyUser1,
  270. lastUpdateUser: dummyUser1._id,
  271. parent: rootPage._id,
  272. status: Page.STATUS_PUBLISHED,
  273. },
  274. {
  275. _id: pageIdForDelete4,
  276. path: '/user',
  277. grant: Page.GRANT_PUBLIC,
  278. parent: rootPage._id,
  279. status: Page.STATUS_PUBLISHED,
  280. isEmpty: true,
  281. },
  282. {
  283. _id: pageIdForDelete5,
  284. path: '/user/v5DummyUser1',
  285. grant: Page.GRANT_PUBLIC,
  286. creator: dummyUser1,
  287. lastUpdateUser: dummyUser1._id,
  288. parent: pageIdForDelete4,
  289. status: Page.STATUS_PUBLISHED,
  290. },
  291. ]);
  292. const tagIdForDelete1 = new mongoose.Types.ObjectId();
  293. const tagIdForDelete2 = new mongoose.Types.ObjectId();
  294. await Tag.insertMany([
  295. { _id: tagIdForDelete1, name: 'TagForDelete1' },
  296. { _id: tagIdForDelete2, name: 'TagForDelete2' },
  297. ]);
  298. await PageTagRelation.insertMany([
  299. { relatedPage: pageIdForDelete3, relatedTag: tagIdForDelete1 },
  300. { relatedPage: pageIdForDelete3, relatedTag: tagIdForDelete2 },
  301. ]);
  302. });
  303. describe('Rename', () => {
  304. const renamePage = async(page, newPagePath, user, options) => {
  305. // mock return value
  306. const mockedResumableRenameDescendants = jest.spyOn(crowi.pageService, 'resumableRenameDescendants').mockReturnValue(null);
  307. const mockedCreateAndSendNotifications = jest.spyOn(crowi.pageService, 'createAndSendNotifications').mockReturnValue(null);
  308. const renamedPage = await crowi.pageService.renamePage(page, newPagePath, user, options);
  309. // retrieve the arguments passed when calling method resumableRenameDescendants inside renamePage method
  310. const argsForResumableRenameDescendants = mockedResumableRenameDescendants.mock.calls[0];
  311. // restores the original implementation
  312. mockedResumableRenameDescendants.mockRestore();
  313. mockedCreateAndSendNotifications.mockRestore();
  314. // rename descendants
  315. await crowi.pageService.resumableRenameDescendants(...argsForResumableRenameDescendants);
  316. return renamedPage;
  317. };
  318. test('Should NOT rename top page', async() => {
  319. expectAllToBeTruthy([rootPage]);
  320. let isThrown = false;
  321. try {
  322. await crowi.pageService.renamePage(rootPage, '/new_root', dummyUser1, {});
  323. }
  324. catch (err) {
  325. isThrown = true;
  326. }
  327. expect(isThrown).toBe(true);
  328. });
  329. test('Should rename/move to under non-empty page', async() => {
  330. const parentPage = await Page.findOne({ path: '/v5_ParentForRename1' });
  331. const childPage = await Page.findOne({ path: '/v5_ChildForRename1' });
  332. expectAllToBeTruthy([childPage, parentPage]);
  333. const newPath = '/v5_ParentForRename1/renamedChildForRename1';
  334. const renamedPage = await renamePage(childPage, newPath, dummyUser1, {});
  335. const childPageBeforeRename = await Page.findOne({ path: '/v5_ChildForRename1' });
  336. expect(xssSpy).toHaveBeenCalled();
  337. expect(renamedPage.path).toBe(newPath);
  338. expect(renamedPage.parent).toStrictEqual(parentPage._id);
  339. expect(childPageBeforeRename).toBeNull();
  340. });
  341. test('Should rename/move to under empty page', async() => {
  342. const parentPage = await Page.findOne({ path: '/v5_ParentForRename2' });
  343. const childPage = await Page.findOne({ path: '/v5_ChildForRename2' });
  344. expectAllToBeTruthy([childPage, parentPage]);
  345. expect(parentPage.isEmpty).toBe(true);
  346. const newPath = '/v5_ParentForRename2/renamedChildForRename2';
  347. const renamedPage = await renamePage(childPage, newPath, dummyUser1, {});
  348. const childPageBeforeRename = await Page.findOne({ path: '/v5_ChildForRename2' });
  349. expect(xssSpy).toHaveBeenCalled();
  350. expect(renamedPage.path).toBe(newPath);
  351. expect(parentPage.isEmpty).toBe(true);
  352. expect(renamedPage.parent).toStrictEqual(parentPage._id);
  353. expect(childPageBeforeRename).toBeNull();
  354. });
  355. test('Should rename/move with option updateMetadata: true', async() => {
  356. const parentPage = await Page.findOne({ path: '/v5_ParentForRename3' });
  357. const childPage = await Page.findOne({ path: '/v5_ChildForRename3' });
  358. expectAllToBeTruthy([childPage, parentPage]);
  359. expect(childPage.lastUpdateUser).toStrictEqual(dummyUser1._id);
  360. const newPath = '/v5_ParentForRename3/renamedChildForRename3';
  361. const oldUdpateAt = childPage.updatedAt;
  362. const renamedPage = await renamePage(childPage, newPath, dummyUser2, { updateMetadata: true });
  363. expect(xssSpy).toHaveBeenCalled();
  364. expect(renamedPage.path).toBe(newPath);
  365. expect(renamedPage.parent).toStrictEqual(parentPage._id);
  366. expect(renamedPage.lastUpdateUser).toStrictEqual(dummyUser2._id);
  367. expect(renamedPage.updatedAt.getFullYear()).toBeGreaterThan(oldUdpateAt.getFullYear());
  368. });
  369. // ****************** TODO ******************
  370. // uncomment the next test when working on 88097
  371. // ******************************************
  372. // test('Should move with option createRedirectPage: true', async() => {
  373. // const parentPage = await Page.findOne({ path: '/v5_ParentForRename4' });
  374. // const childPage = await Page.findOne({ path: '/v5_ChildForRename4' });
  375. // expectAllToBeTruthy([parentPage, childPage]);
  376. // // rename target page
  377. // const newPath = '/v5_ParentForRename4/renamedChildForRename4';
  378. // const renamedPage = await renamePage(childPage, newPath, dummyUser2, { createRedirectPage: true });
  379. // const pageRedirect = await PageRedirect.find({ fromPath: childPage.path, toPath: renamedPage.path });
  380. // expect(xssSpy).toHaveBeenCalled();
  381. // expect(renamedPage.path).toBe(newPath);
  382. // expect(renamedPage.parent).toStrictEqual(parentPage._id);
  383. // expect(pageRedirect.length).toBeGreaterThan(0);
  384. // });
  385. test('Should rename/move with descendants', async() => {
  386. const parentPage = await Page.findOne({ path: '/v5_ParentForRename5' });
  387. const childPage = await Page.findOne({ path: '/v5_ChildForRename5' });
  388. const grandchild = await Page.findOne({ parent: childPage._id, path: '/v5_ChildForRename5/v5_GrandchildForRename5' });
  389. expectAllToBeTruthy([parentPage, childPage, grandchild]);
  390. const newPath = '/v5_ParentForRename5/renamedChildForRename5';
  391. const renamedPage = await renamePage(childPage, newPath, dummyUser1, {});
  392. // find child of renamed page
  393. const renamedGrandchild = await Page.findOne({ parent: renamedPage._id });
  394. const childPageBeforeRename = await Page.findOne({ path: '/v5_ChildForRename5' });
  395. const grandchildBeforeRename = await Page.findOne({ path: grandchild.path });
  396. expect(xssSpy).toHaveBeenCalled();
  397. expect(renamedPage.path).toBe(newPath);
  398. expect(renamedPage.parent).toStrictEqual(parentPage._id);
  399. expect(childPageBeforeRename).toBeNull();
  400. expect(grandchildBeforeRename).toBeNull();
  401. // grandchild's parent should be the renamed page
  402. expect(renamedGrandchild.parent).toStrictEqual(renamedPage._id);
  403. expect(renamedGrandchild.path).toBe('/v5_ParentForRename5/renamedChildForRename5/v5_GrandchildForRename5');
  404. });
  405. test('Should rename/move empty page', async() => {
  406. const parentPage = await Page.findOne({ path: '/v5_ParentForRename7' });
  407. const childPage = await Page.findOne({ path: '/v5_ChildForRename7', isEmpty: true });
  408. const grandchild = await Page.findOne({ parent: childPage._id, path: '/v5_ChildForRename7/v5_GrandchildForRename7' });
  409. expectAllToBeTruthy([parentPage, childPage, grandchild]);
  410. const newPath = '/v5_ParentForRename7/renamedChildForRename7';
  411. const renamedPage = await renamePage(childPage, newPath, dummyUser1, {});
  412. const grandchildAfterRename = await Page.findOne({ parent: renamedPage._id });
  413. const grandchildBeforeRename = await Page.findOne({ path: '/v5_ChildForRename7/v5_GrandchildForRename7' });
  414. expect(xssSpy).toHaveBeenCalled();
  415. expect(renamedPage.path).toBe(newPath);
  416. expect(renamedPage.isEmpty).toBe(true);
  417. expect(renamedPage.parent).toStrictEqual(parentPage._id);
  418. expect(grandchildBeforeRename).toBeNull();
  419. // grandchild's parent should be renamed page
  420. expect(grandchildAfterRename.parent).toStrictEqual(renamedPage._id);
  421. expect(grandchildAfterRename.path).toBe('/v5_ParentForRename7/renamedChildForRename7/v5_GrandchildForRename7');
  422. });
  423. test('Should NOT rename/move with existing path', async() => {
  424. const page = await Page.findOne({ path: '/v5_ParentForRename8' });
  425. expectAllToBeTruthy([page]);
  426. const newPath = '/v5_ParentForRename9';
  427. let isThrown;
  428. try {
  429. await renamePage(page, newPath, dummyUser1, {});
  430. }
  431. catch (err) {
  432. isThrown = true;
  433. }
  434. expect(isThrown).toBe(true);
  435. });
  436. });
  437. describe('Delete', () => {
  438. const deletePage = async(page, user, options, isRecursively) => {
  439. const mockedResumableDeleteDescendants = jest.spyOn(crowi.pageService, 'resumableDeleteDescendants').mockReturnValue(null);
  440. const mockedCreateAndSendNotifications = jest.spyOn(crowi.pageService, 'createAndSendNotifications').mockReturnValue(null);
  441. const deletedPage = await crowi.pageService.deletePage(page, user, options, isRecursively);
  442. const argsForResumableDeleteDescendants = mockedResumableDeleteDescendants.mock.calls[0];
  443. mockedResumableDeleteDescendants.mockRestore();
  444. mockedCreateAndSendNotifications.mockRestore();
  445. if (isRecursively) {
  446. await crowi.pageService.resumableDeleteDescendants(...argsForResumableDeleteDescendants);
  447. }
  448. return deletedPage;
  449. };
  450. test('Should NOT delete root page', async() => {
  451. let isThrown;
  452. expectAllToBeTruthy([rootPage]);
  453. try { await deletePage(rootPage, dummyUser1, {}, false) }
  454. catch (err) { isThrown = true }
  455. const page = await Page.findOne({ path: '/' });
  456. expect(isThrown).toBe(true);
  457. expect(page).toBeTruthy();
  458. });
  459. test('Should NOT delete trashed page', async() => {
  460. const trashedPage = await Page.findOne({ path: '/trash/v5_PageForDelete1' });
  461. expectAllToBeTruthy([trashedPage]);
  462. let isThrown;
  463. try { await deletePage(trashedPage, dummyUser1, {}, false) }
  464. catch (err) { isThrown = true }
  465. const page = await Page.findOne({ path: '/trash/v5_PageForDelete1' });
  466. expect(page).toBeTruthy();
  467. expect(isThrown).toBe(true);
  468. });
  469. test('Should NOT delete /user/hoge page', async() => {
  470. const dummyUser1Page = await Page.findOne({ path: '/user/v5DummyUser1' });
  471. expectAllToBeTruthy([dummyUser1Page]);
  472. let isThrown;
  473. try { await deletePage(dummyUser1Page, dummyUser1, {}, false) }
  474. catch (err) { isThrown = true }
  475. const page = await Page.findOne({ path: '/user/v5DummyUser1' });
  476. expect(page).toBeTruthy();
  477. expect(isThrown).toBe(true);
  478. });
  479. test('Should delete single page', async() => {
  480. const pageToDelete = await Page.findOne({ path: '/v5_PageForDelete2' });
  481. expectAllToBeTruthy([pageToDelete]);
  482. const deletedPage = await deletePage(pageToDelete, dummyUser1, {}, false);
  483. const page = await Page.findOne({ path: '/v5_PageForDelete2' });
  484. expect(page).toBeNull();
  485. expect(deletedPage.path).toBe(`/trash${pageToDelete.path}`);
  486. expect(deletedPage.parent).toBeNull();
  487. expect(deletedPage.status).toBe(Page.STATUS_DELETED);
  488. });
  489. test('Should delete multiple pages including empty child', async() => {
  490. const parentPage = await Page.findOne({ path: '/v5_PageForDelete3' });
  491. const childPage = await Page.findOne({ path: '/v5_PageForDelete3/v5_PageForDelete4' });
  492. const grandchildPage = await Page.findOne({ path: '/v5_PageForDelete3/v5_PageForDelete4/v5_PageForDelete5' });
  493. expectAllToBeTruthy([parentPage, childPage, grandchildPage]);
  494. const deletedParentPage = await deletePage(parentPage, dummyUser1, {}, true);
  495. const deletedChildPage = await Page.findOne({ path: '/trash/v5_PageForDelete3/v5_PageForDelete4' });
  496. const deletedGrandchildPage = await Page.findOne({ path: '/trash/v5_PageForDelete3/v5_PageForDelete4/v5_PageForDelete5' });
  497. // originally NOT empty page should exist with status 'deleted' and parent set null
  498. expect(deletedParentPage._id).toStrictEqual(parentPage._id);
  499. expect(deletedParentPage.status).toBe(Page.STATUS_DELETED);
  500. expect(deletedParentPage.parent).toBeNull();
  501. // originally empty page should NOT exist
  502. expect(deletedChildPage).toBeNull();
  503. // originally NOT empty page should exist with status 'deleted' and parent set null
  504. expect(deletedGrandchildPage._id).toStrictEqual(grandchildPage._id);
  505. expect(deletedGrandchildPage.status).toBe(Page.STATUS_DELETED);
  506. expect(deletedGrandchildPage.parent).toBeNull();
  507. });
  508. test('Should delete page tag relation', async() => {
  509. const pageToDelete = await Page.findOne({ path: '/v5_PageForDelete6' });
  510. const tag1 = await Tag.findOne({ name: 'TagForDelete1' });
  511. const tag2 = await Tag.findOne({ name: 'TagForDelete2' });
  512. const pageRelation1 = await PageTagRelation.findOne({ relatedTag: tag1._id });
  513. const pageRelation2 = await PageTagRelation.findOne({ relatedTag: tag2._id });
  514. expectAllToBeTruthy([pageToDelete, tag1, tag2, pageRelation1, pageRelation2]);
  515. const deletedPage = await deletePage(pageToDelete, dummyUser1, {}, false);
  516. const page = await Page.findOne({ path: '/v5_PageForDelete6' });
  517. const deletedTagRelation1 = await PageTagRelation.findOne({ _id: pageRelation1._id });
  518. const deletedTagRelation2 = await PageTagRelation.findOne({ _id: pageRelation2._id });
  519. expect(page).toBe(null);
  520. expect(deletedPage.status).toBe(Page.STATUS_DELETED);
  521. expect(deletedTagRelation1.isPageTrashed).toBe(true);
  522. expect(deletedTagRelation2.isPageTrashed).toBe(true);
  523. });
  524. });
  525. });
  526. describe('PageService page operations with non-public pages', () => {
  527. // TODO: write test code
  528. });