pagev5.test.ts 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473
  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. // parents
  21. let parentForRename1;
  22. let parentForRename2;
  23. let parentForRename3;
  24. let parentForRename4;
  25. let parentForRename5;
  26. let parentForRename6;
  27. let parentForRename7;
  28. // children
  29. let childForRename1;
  30. let childForRename2;
  31. let childForRename3;
  32. let childForRename4;
  33. let childForRename5;
  34. let childForRename6;
  35. let childForRename7;
  36. // rename
  37. // parents
  38. let parentForDuplicate1;
  39. let parentForDuplicate3;
  40. let childForDuplicate3;
  41. beforeAll(async() => {
  42. crowi = await getInstance();
  43. await crowi.configManager.updateConfigsInTheSameNamespace('crowi', { 'app:isV5Compatible': true });
  44. User = mongoose.model('User');
  45. Page = mongoose.model('Page');
  46. Revision = mongoose.model('Revision');
  47. Tag = mongoose.model('Tag');
  48. PageTagRelation = mongoose.model('PageTagRelation');
  49. Bookmark = mongoose.model('Bookmark');
  50. Comment = mongoose.model('Comment');
  51. ShareLink = mongoose.model('ShareLink');
  52. PageRedirect = mongoose.model('PageRedirect');
  53. /*
  54. * Common
  55. */
  56. await User.insertMany([
  57. { name: 'dummyUser1', username: 'dummyUser1', email: 'dummyUser1@example.com' },
  58. { name: 'dummyUser2', username: 'dummyUser2', email: 'dummyUser2@example.com' },
  59. ]);
  60. dummyUser1 = await User.findOne({ username: 'dummyUser1' });
  61. dummyUser2 = await User.findOne({ username: 'dummyUser2' });
  62. xssSpy = jest.spyOn(crowi.xss, 'process').mockImplementation(path => path);
  63. /*
  64. * Rename
  65. */
  66. // delete root page if any created by other test file
  67. const pages = await Page.find({ path: '/' });
  68. if (pages.length > 0) {
  69. await Page.deleteOne({ path: '/' });
  70. }
  71. // then create new root page
  72. rootPage = await Page.create('/', 'body', dummyUser1._id, {});
  73. // Create Pages
  74. await Page.insertMany([
  75. // parents
  76. {
  77. path: '/v5_ParentForRename1',
  78. grant: Page.GRANT_PUBLIC,
  79. creator: dummyUser1,
  80. lastUpdateUser: dummyUser1._id,
  81. parent: rootPage._id,
  82. },
  83. {
  84. path: '/v5_ParentForRename2',
  85. grant: Page.GRANT_PUBLIC,
  86. creator: dummyUser1,
  87. lastUpdateUser: dummyUser1._id,
  88. parent: rootPage._id,
  89. isEmpty: true,
  90. },
  91. {
  92. path: '/v5_ParentForRename3',
  93. grant: Page.GRANT_PUBLIC,
  94. creator: dummyUser1,
  95. lastUpdateUser: dummyUser1._id,
  96. parent: rootPage._id,
  97. },
  98. {
  99. path: '/v5_ParentForRename4',
  100. grant: Page.GRANT_PUBLIC,
  101. creator: dummyUser1,
  102. lastUpdateUser: dummyUser1._id,
  103. parent: rootPage._id,
  104. },
  105. {
  106. path: '/v5_ParentForRename5',
  107. grant: Page.GRANT_PUBLIC,
  108. creator: dummyUser1,
  109. lastUpdateUser: dummyUser1._id,
  110. parent: rootPage._id,
  111. },
  112. {
  113. path: '/v5_ParentForRename6',
  114. grant: Page.GRANT_PUBLIC,
  115. creator: dummyUser1,
  116. lastUpdateUser: dummyUser1._id,
  117. parent: rootPage._id,
  118. },
  119. {
  120. path: '/v5_ParentForRename7',
  121. grant: Page.GRANT_PUBLIC,
  122. creator: dummyUser1,
  123. lastUpdateUser: dummyUser1._id,
  124. parent: rootPage._id,
  125. },
  126. // children
  127. {
  128. path: '/v5_ChildForRename1',
  129. grant: Page.GRANT_PUBLIC,
  130. creator: dummyUser1,
  131. lastUpdateUser: dummyUser1._id,
  132. parent: rootPage._id,
  133. },
  134. {
  135. path: '/v5_ChildForRename2',
  136. grant: Page.GRANT_PUBLIC,
  137. creator: dummyUser1,
  138. lastUpdateUser: dummyUser1._id,
  139. parent: rootPage._id,
  140. },
  141. {
  142. path: '/v5_ChildForRename3',
  143. grant: Page.GRANT_PUBLIC,
  144. creator: dummyUser1,
  145. lastUpdateUser: dummyUser1._id,
  146. parent: rootPage._id,
  147. updatedAt: new Date('2021'),
  148. },
  149. {
  150. path: '/v5_ChildForRename4',
  151. grant: Page.GRANT_PUBLIC,
  152. creator: dummyUser1,
  153. lastUpdateUser: dummyUser1._id,
  154. parent: rootPage._id,
  155. },
  156. {
  157. path: '/v5_ChildForRename5',
  158. grant: Page.GRANT_PUBLIC,
  159. creator: dummyUser1,
  160. lastUpdateUser: dummyUser1._id,
  161. parent: rootPage._id,
  162. },
  163. {
  164. path: '/v5_ChildForRename6',
  165. grant: Page.GRANT_RESTRICTED,
  166. creator: dummyUser1,
  167. lastUpdateUser: dummyUser1._id,
  168. parent: rootPage._id,
  169. },
  170. {
  171. path: '/v5_ChildForRename7',
  172. grant: Page.GRANT_PUBLIC,
  173. parent: rootPage._id,
  174. isEmpty: true,
  175. },
  176. ]);
  177. // Find pages as Parent
  178. parentForRename1 = await Page.findOne({ path: '/v5_ParentForRename1' });
  179. parentForRename2 = await Page.findOne({ path: '/v5_ParentForRename2' });
  180. parentForRename3 = await Page.findOne({ path: '/v5_ParentForRename3' });
  181. parentForRename4 = await Page.findOne({ path: '/v5_ParentForRename4' });
  182. parentForRename5 = await Page.findOne({ path: '/v5_ParentForRename5' });
  183. parentForRename6 = await Page.findOne({ path: '/v5_ParentForRename6' });
  184. parentForRename7 = await Page.findOne({ path: '/v5_ParentForRename7' });
  185. // Find pages as Child
  186. childForRename1 = await Page.findOne({ path: '/v5_ChildForRename1' });
  187. childForRename2 = await Page.findOne({ path: '/v5_ChildForRename2' });
  188. childForRename3 = await Page.findOne({ path: '/v5_ChildForRename3' });
  189. childForRename4 = await Page.findOne({ path: '/v5_ChildForRename4' });
  190. childForRename5 = await Page.findOne({ path: '/v5_ChildForRename5' });
  191. childForRename6 = await Page.findOne({ path: '/v5_ChildForRename6' });
  192. childForRename7 = await Page.findOne({ path: '/v5_ChildForRename7' });
  193. // create grandchild
  194. await Page.insertMany([
  195. // Grandchild
  196. {
  197. path: '/v5_ChildForRename5/v5_GrandchildForRename5',
  198. grant: Page.GRANT_PUBLIC,
  199. creator: dummyUser1,
  200. lastUpdateUser: dummyUser1._id,
  201. parent: childForRename5._id,
  202. updatedAt: new Date('2021'),
  203. },
  204. {
  205. path: '/v5_ChildForRename7/v5_GrandchildForRename7',
  206. grant: Page.GRANT_PUBLIC,
  207. creator: dummyUser1,
  208. lastUpdateUser: dummyUser1._id,
  209. parent: childForRename7._id,
  210. },
  211. ]);
  212. /*
  213. * Duplicate
  214. */
  215. // page ids
  216. const pageIdForParent1 = new mongoose.Types.ObjectId();
  217. const pageIdForParent3 = new mongoose.Types.ObjectId();
  218. const pageIdForChild3 = new mongoose.Types.ObjectId();
  219. // revision ids
  220. const revisionIdForParent1 = new mongoose.Types.ObjectId();
  221. const revisionIdForChild3 = new mongoose.Types.ObjectId();
  222. await Page.insertMany([
  223. {
  224. _id: pageIdForParent1,
  225. path: '/v5_ParentForDuplicate1',
  226. grant: Page.GRANT_PUBLIC,
  227. creator: dummyUser1,
  228. lastUpdateUser: dummyUser1._id,
  229. parent: rootPage._id,
  230. revision: revisionIdForParent1,
  231. },
  232. {
  233. _id: pageIdForParent3,
  234. path: '/v5_ParentForDuplicate3',
  235. grant: Page.GRANT_PUBLIC,
  236. parent: rootPage._id,
  237. },
  238. // children
  239. {
  240. _id: pageIdForChild3,
  241. path: '/v5_ChildForDuplicate3',
  242. grant: Page.GRANT_PUBLIC,
  243. creator: dummyUser1,
  244. lastUpdateUser: dummyUser1._id,
  245. parent: pageIdForParent3,
  246. revision: revisionIdForChild3,
  247. },
  248. ]);
  249. // Revision
  250. await Revision.insertMany([
  251. {
  252. _id: revisionIdForParent1,
  253. body: 'body1',
  254. format: 'markdown',
  255. pageId: pageIdForParent1,
  256. author: dummyUser1,
  257. },
  258. {
  259. _id: revisionIdForChild3,
  260. body: 'body3',
  261. format: 'markdown',
  262. pageId: pageIdForChild3,
  263. author: dummyUser1,
  264. },
  265. ]);
  266. parentForDuplicate1 = await Page.findOne({ path: '/v5_ParentForDuplicate1' });
  267. parentForDuplicate3 = await Page.findOne({ path: '/v5_ParentForDuplicate3' });
  268. });
  269. describe('Rename', () => {
  270. const renamePage = async(page, newPagePath, user, options) => {
  271. // mock return value
  272. const mockedResumableRenameDescendants = jest.spyOn(crowi.pageService, 'resumableRenameDescendants').mockReturnValue(null);
  273. jest.spyOn(crowi.pageService, 'createAndSendNotifications').mockReturnValue(null);
  274. const renamedPage = await crowi.pageService.renamePage(page, newPagePath, user, options);
  275. // retrieve the arguments passed when calling method resumableRenameDescendants inside renamePage method
  276. const argsForResumableRenameDescendants = mockedResumableRenameDescendants.mock.calls[0];
  277. // restores the original implementation
  278. jest.restoreAllMocks();
  279. // rename descendants
  280. await crowi.pageService.resumableRenameDescendants(...argsForResumableRenameDescendants);
  281. return renamedPage;
  282. };
  283. test('Should NOT rename top page', async() => {
  284. let isThrown = false;
  285. try {
  286. await crowi.pageService.renamePage(rootPage, '/new_root', dummyUser1, {});
  287. }
  288. catch (err) {
  289. isThrown = true;
  290. }
  291. expect(isThrown).toBe(true);
  292. });
  293. test('Should move to under non-empty page', async() => {
  294. // rename target page
  295. const newPath = '/v5_ParentForRename1/renamedChildForRename1';
  296. const renamedPage = await renamePage(childForRename1, newPath, dummyUser1, {});
  297. expect(renamedPage.path).toBe(newPath);
  298. expect(renamedPage.parent).toStrictEqual(parentForRename1._id);
  299. });
  300. test('Should move to under empty page', async() => {
  301. // rename target page
  302. const newPath = '/v5_ParentForRename2/renamedChildForRename2';
  303. const renamedPage = await renamePage(childForRename2, newPath, dummyUser1, {});
  304. expect(renamedPage.path).toBe(newPath);
  305. expect(parentForRename2.isEmpty).toBe(true);
  306. expect(renamedPage.parent).toStrictEqual(parentForRename2._id);
  307. });
  308. test('Should move with option updateMetadata: true', async() => {
  309. // rename target page
  310. const newPath = '/v5_ParentForRename3/renamedChildForRename3';
  311. const oldUdpateAt = childForRename3.updatedAt;
  312. const renamedPage = await renamePage(childForRename3, newPath, dummyUser2, { updateMetadata: true });
  313. expect(renamedPage.path).toBe(newPath);
  314. expect(renamedPage.parent).toStrictEqual(parentForRename3._id);
  315. expect(renamedPage.lastUpdateUser).toStrictEqual(dummyUser2._id);
  316. expect(renamedPage.updatedAt.getFullYear()).toBeGreaterThan(oldUdpateAt.getFullYear());
  317. });
  318. // ****************** TODO ******************
  319. // uncomment the next test when working on 88097
  320. // ******************************************
  321. // test('Should move with option createRedirectPage: true', async() => {
  322. // // rename target page
  323. // const newPath = '/v5_ParentForRename4/renamedChildForRename4';
  324. // const renamedPage = await renamePage(childForRename4, newPath, dummyUser2, { createRedirectPage: true });
  325. // const pageRedirect = await PageRedirect.find({ fromPath: childForRename4.path, toPath: renamedPage.path });
  326. // expect(renamedPage.path).toBe(newPath);
  327. // expect(renamedPage.parent).toStrictEqual(parentForRename4._id);
  328. // expect(pageRedirect.length).toBeGreaterThan(0);
  329. // });
  330. test('Should move with descendants', async() => {
  331. // rename target page
  332. const newPath = '/v5_ParentForRename5/renamedChildForRename5';
  333. const renamedPage = await renamePage(childForRename5, newPath, dummyUser1, {});
  334. // find child of renamed page
  335. const grandchildren = await Page.find({ parent: renamedPage._id });
  336. const grandchild = grandchildren[0];
  337. expect(renamedPage.path).toBe(newPath);
  338. expect(renamedPage.parent).toStrictEqual(parentForRename5._id);
  339. // grandchild's parent should be renamed page
  340. expect(grandchild.parent).toStrictEqual(renamedPage._id);
  341. expect(grandchild.path).toBe('/v5_ParentForRename5/renamedChildForRename5/v5_GrandchildForRename5');
  342. });
  343. test('Should move with same grant', async() => {
  344. // rename target page
  345. const newPath = '/v5_ParentForRename6/renamedChildForRename6';
  346. expect(childForRename6.grant).toBe(Page.GRANT_RESTRICTED);
  347. const renamedPage = await renamePage(childForRename6, newPath, dummyUser1, {});
  348. expect(renamedPage.path).toBe(newPath);
  349. expect(renamedPage.parent).toStrictEqual(parentForRename6._id);
  350. expect(renamedPage.grant).toBe(Page.GRANT_RESTRICTED);
  351. });
  352. test('Should move empty page', async() => {
  353. // rename target page
  354. const newPath = '/v5_ParentForRename7/renamedChildForRename7';
  355. const renamedPage = await renamePage(childForRename7, newPath, dummyUser1, {});
  356. // find child of renamed page
  357. const grandchildren = await Page.find({ parent: renamedPage._id });
  358. const grandchild = grandchildren[0];
  359. expect(renamedPage.path).toBe(newPath);
  360. expect(renamedPage.isEmpty).toBe(true);
  361. expect(renamedPage.parent).toStrictEqual(parentForRename7._id);
  362. // grandchild's parent should be renamed page
  363. expect(grandchild.parent).toStrictEqual(renamedPage._id);
  364. expect(grandchild.path).toBe('/v5_ParentForRename7/renamedChildForRename7/v5_GrandchildForRename7');
  365. });
  366. });
  367. describe('Duplicate', () => {
  368. const duplicate = async(page, newPagePath, user, isRecursively) => {
  369. // mock return value
  370. const mockedResumableDuplicateDescendants = jest.spyOn(crowi.pageService, 'resumableDuplicateDescendants').mockRejectedValue(null);
  371. jest.spyOn(crowi.pageService, 'createAndSendNotifications').mockReturnValue(null);
  372. const duplicatedPage = await crowi.pageService.duplicate(page, newPagePath, user, isRecursively);
  373. // retrieve the arguments passed when calling method resumableDuplicateDescendants inside duplicate method
  374. const argsForResumableDuplicateDescendants = mockedResumableDuplicateDescendants.mock.calls[0];
  375. // restores the original implementation
  376. jest.restoreAllMocks();
  377. // duplicate descendants
  378. if (isRecursively) {
  379. await crowi.pageService.resumableDuplicateDescendants(...argsForResumableDuplicateDescendants);
  380. }
  381. return duplicatedPage;
  382. };
  383. test('Should duplicate single page', async() => {
  384. const newPagePath = '/duplicatedParentForDuplicate1';
  385. const duplicatedPage = await duplicate(parentForDuplicate1, newPagePath, dummyUser1, false);
  386. const duplicatedRevision = await Revision.findOne({ pageId: duplicatedPage._id });
  387. const baseRevision = await Revision.findOne({ pageId: parentForDuplicate1._id });
  388. // new path
  389. expect(duplicatedPage.path).toBe(newPagePath);
  390. expect(duplicatedPage._id).not.toStrictEqual(parentForDuplicate1._id);
  391. expect(duplicatedPage.revision).toStrictEqual(duplicatedRevision._id);
  392. expect(duplicatedRevision.body).toEqual(baseRevision.body);
  393. });
  394. test('Should NOT duplicate empty page', async() => {
  395. const newPagePath = '/duplicatedParentForDuplicate3';
  396. let isThrown;
  397. let duplicatedPage;
  398. try {
  399. duplicatedPage = await duplicate(parentForDuplicate3, newPagePath, dummyUser1, false);
  400. }
  401. catch (err) {
  402. isThrown = true;
  403. }
  404. expect(duplicatedPage).toBeFalsy();
  405. expect(isThrown).toBe(true);
  406. });
  407. test('Should duplicate multiple pages', async() => {
  408. // a
  409. });
  410. test('Should keep grant', async() => {
  411. // a
  412. });
  413. });
  414. afterAll(async() => {
  415. // await Page.remove({});
  416. // await User.remove({});
  417. // await Revision.remove({});
  418. });
  419. });
  420. describe('PageService page operations with non-public pages', () => {
  421. // TODO: write test code
  422. });