v5.page.test.ts 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756
  1. import { addSeconds } from 'date-fns';
  2. import mongoose from 'mongoose';
  3. import { PageActionStage, PageActionType } from '../../../src/interfaces/page-operation';
  4. import { getInstance } from '../setup-crowi';
  5. describe('Test page service methods', () => {
  6. let crowi;
  7. let Page;
  8. let Revision;
  9. let User;
  10. let UserGroup;
  11. let UserGroupRelation;
  12. let Tag;
  13. let PageTagRelation;
  14. let Bookmark;
  15. let Comment;
  16. let ShareLink;
  17. let PageRedirect;
  18. let PageOperation;
  19. let xssSpy;
  20. let rootPage;
  21. let dummyUser1;
  22. let dummyUser2;
  23. let globalGroupUser1;
  24. let globalGroupUser2;
  25. let globalGroupUser3;
  26. let globalGroupIsolate;
  27. let globalGroupA;
  28. let globalGroupB;
  29. let globalGroupC;
  30. let pageOpId1;
  31. let pageOpId2;
  32. let pageOpId3;
  33. let pageOpId4;
  34. let pageOpId5;
  35. let pageOpId6;
  36. beforeAll(async() => {
  37. crowi = await getInstance();
  38. await crowi.configManager.updateConfigsInTheSameNamespace('crowi', { 'app:isV5Compatible': true });
  39. User = mongoose.model('User');
  40. UserGroup = mongoose.model('UserGroup');
  41. UserGroupRelation = mongoose.model('UserGroupRelation');
  42. Page = mongoose.model('Page');
  43. Revision = mongoose.model('Revision');
  44. Tag = mongoose.model('Tag');
  45. PageTagRelation = mongoose.model('PageTagRelation');
  46. Bookmark = mongoose.model('Bookmark');
  47. Comment = mongoose.model('Comment');
  48. ShareLink = mongoose.model('ShareLink');
  49. PageRedirect = mongoose.model('PageRedirect');
  50. UserGroup = mongoose.model('UserGroup');
  51. UserGroupRelation = mongoose.model('UserGroupRelation');
  52. PageOperation = mongoose.model('PageOperation');
  53. /*
  54. * Common
  55. */
  56. xssSpy = jest.spyOn(crowi.xss, 'process').mockImplementation(path => path);
  57. // ***********************************************************************************************************
  58. // * Do NOT change properties of globally used documents. Otherwise, it might cause some errors in other tests
  59. // ***********************************************************************************************************
  60. // users
  61. dummyUser1 = await User.findOne({ username: 'v5DummyUser1' });
  62. dummyUser2 = await User.findOne({ username: 'v5DummyUser2' });
  63. globalGroupUser1 = await User.findOne({ username: 'gGroupUser1' });
  64. globalGroupUser2 = await User.findOne({ username: 'gGroupUser2' });
  65. globalGroupUser3 = await User.findOne({ username: 'gGroupUser3' });
  66. // groups
  67. globalGroupIsolate = await UserGroup.findOne({ name: 'globalGroupIsolate' });
  68. globalGroupA = await UserGroup.findOne({ name: 'globalGroupA' });
  69. globalGroupB = await UserGroup.findOne({ name: 'globalGroupB' });
  70. globalGroupC = await UserGroup.findOne({ name: 'globalGroupC' });
  71. // page
  72. rootPage = await Page.findOne({ path: '/' });
  73. /**
  74. * pages
  75. */
  76. const pageId0 = new mongoose.Types.ObjectId();
  77. const pageId1 = new mongoose.Types.ObjectId();
  78. const pageId2 = new mongoose.Types.ObjectId();
  79. const pageId3 = new mongoose.Types.ObjectId();
  80. const pageId4 = new mongoose.Types.ObjectId();
  81. const pageId5 = new mongoose.Types.ObjectId();
  82. const pageId6 = new mongoose.Types.ObjectId();
  83. const pageId7 = new mongoose.Types.ObjectId();
  84. const pageId8 = new mongoose.Types.ObjectId();
  85. const pageId9 = new mongoose.Types.ObjectId();
  86. const pageId10 = new mongoose.Types.ObjectId();
  87. const pageId11 = new mongoose.Types.ObjectId();
  88. const pageId12 = new mongoose.Types.ObjectId();
  89. const pageId13 = new mongoose.Types.ObjectId();
  90. const pageId14 = new mongoose.Types.ObjectId();
  91. const pageId15 = new mongoose.Types.ObjectId();
  92. const pageId16 = new mongoose.Types.ObjectId();
  93. const pageId17 = new mongoose.Types.ObjectId();
  94. const pageId18 = new mongoose.Types.ObjectId();
  95. const pageId19 = new mongoose.Types.ObjectId();
  96. const pageId20 = new mongoose.Types.ObjectId();
  97. await Page.insertMany([
  98. {
  99. _id: pageId0,
  100. path: '/resume_rename_0',
  101. parent: rootPage._id,
  102. grant: Page.GRANT_PUBLIC,
  103. creator: dummyUser1,
  104. lastUpdateUser: dummyUser1._id,
  105. descendantCount: 1,
  106. isEmpty: false,
  107. },
  108. {
  109. _id: pageId1,
  110. path: '/resume_rename_0/resume_rename_1',
  111. parent: pageId0,
  112. grant: Page.GRANT_PUBLIC,
  113. creator: dummyUser1,
  114. lastUpdateUser: dummyUser1._id,
  115. descendantCount: 2,
  116. isEmpty: false,
  117. },
  118. {
  119. _id: pageId2,
  120. path: '/resume_rename_1/resume_rename_2',
  121. parent: pageId1,
  122. grant: Page.GRANT_PUBLIC,
  123. creator: dummyUser1,
  124. lastUpdateUser: dummyUser1._id,
  125. descendantCount: 1,
  126. isEmpty: false,
  127. },
  128. {
  129. _id: pageId3,
  130. path: '/resume_rename_1/resume_rename_2/resume_rename_3',
  131. parent: pageId2,
  132. grant: Page.GRANT_PUBLIC,
  133. creator: dummyUser1,
  134. lastUpdateUser: dummyUser1._id,
  135. descendantCount: 0,
  136. isEmpty: false,
  137. },
  138. {
  139. _id: pageId4,
  140. path: '/resume_rename_4',
  141. parent: rootPage._id,
  142. grant: Page.GRANT_PUBLIC,
  143. creator: dummyUser1,
  144. lastUpdateUser: dummyUser1._id,
  145. descendantCount: 0,
  146. isEmpty: false,
  147. },
  148. {
  149. _id: pageId5,
  150. path: '/resume_rename_4/resume_rename_5',
  151. parent: pageId4,
  152. grant: Page.GRANT_PUBLIC,
  153. creator: dummyUser1,
  154. lastUpdateUser: dummyUser1._id,
  155. descendantCount: 1,
  156. isEmpty: false,
  157. },
  158. {
  159. _id: pageId6,
  160. path: '/resume_rename_5/resume_rename_6',
  161. parent: pageId5,
  162. grant: Page.GRANT_PUBLIC,
  163. creator: dummyUser1,
  164. lastUpdateUser: dummyUser1._id,
  165. descendantCount: 0,
  166. isEmpty: false,
  167. },
  168. {
  169. _id: pageId7,
  170. path: '/resume_rename_7',
  171. parent: rootPage._id,
  172. grant: Page.GRANT_PUBLIC,
  173. creator: dummyUser1,
  174. lastUpdateUser: dummyUser1._id,
  175. descendantCount: 0,
  176. isEmpty: false,
  177. },
  178. {
  179. _id: pageId8,
  180. path: '/resume_rename_8',
  181. parent: rootPage._id,
  182. grant: Page.GRANT_PUBLIC,
  183. creator: dummyUser1,
  184. lastUpdateUser: dummyUser1._id,
  185. descendantCount: 1,
  186. isEmpty: false,
  187. },
  188. {
  189. _id: pageId9,
  190. path: '/resume_rename_8/resume_rename_9',
  191. parent: pageId8,
  192. grant: Page.GRANT_PUBLIC,
  193. creator: dummyUser1,
  194. lastUpdateUser: dummyUser1._id,
  195. descendantCount: 1,
  196. isEmpty: false,
  197. },
  198. {
  199. path: '/resume_rename_9/resume_rename_10',
  200. parent: pageId9,
  201. grant: Page.GRANT_PUBLIC,
  202. creator: dummyUser1,
  203. lastUpdateUser: dummyUser1._id,
  204. descendantCount: 0,
  205. isEmpty: false,
  206. },
  207. {
  208. _id: pageId10,
  209. path: '/resume_rename_11',
  210. parent: rootPage._id,
  211. grant: Page.GRANT_PUBLIC,
  212. creator: dummyUser1,
  213. lastUpdateUser: dummyUser1._id,
  214. descendantCount: 3,
  215. isEmpty: false,
  216. },
  217. {
  218. _id: pageId11,
  219. path: '/resume_rename_11/resume_rename_12',
  220. parent: pageId10,
  221. grant: Page.GRANT_PUBLIC,
  222. creator: dummyUser1,
  223. lastUpdateUser: dummyUser1._id,
  224. descendantCount: 2,
  225. isEmpty: false,
  226. },
  227. {
  228. _id: pageId12,
  229. path: '/resume_rename_11/resume_rename_12/resume_rename_13',
  230. parent: pageId11,
  231. grant: Page.GRANT_PUBLIC,
  232. creator: dummyUser1,
  233. lastUpdateUser: dummyUser1._id,
  234. descendantCount: 1,
  235. isEmpty: false,
  236. },
  237. {
  238. path: '/resume_rename_11/resume_rename_12/resume_rename_13/resume_rename_14',
  239. parent: pageId12,
  240. grant: Page.GRANT_PUBLIC,
  241. creator: dummyUser1,
  242. lastUpdateUser: dummyUser1._id,
  243. descendantCount: 0,
  244. isEmpty: false,
  245. },
  246. {
  247. _id: pageId13,
  248. path: '/resume_rename_15',
  249. parent: rootPage._id,
  250. grant: Page.GRANT_PUBLIC,
  251. creator: dummyUser1,
  252. lastUpdateUser: dummyUser1._id,
  253. descendantCount: 2,
  254. isEmpty: false,
  255. },
  256. {
  257. _id: pageId14,
  258. path: '/resume_rename_15/resume_rename_16',
  259. parent: pageId13,
  260. grant: Page.GRANT_PUBLIC,
  261. creator: dummyUser1,
  262. lastUpdateUser: dummyUser1._id,
  263. descendantCount: 0,
  264. isEmpty: false,
  265. },
  266. {
  267. _id: pageId15,
  268. path: '/resume_rename_15/resume_rename_17',
  269. parent: pageId13,
  270. grant: Page.GRANT_PUBLIC,
  271. creator: dummyUser1,
  272. lastUpdateUser: dummyUser1._id,
  273. descendantCount: 1,
  274. isEmpty: false,
  275. },
  276. {
  277. _id: pageId16,
  278. path: '/resume_rename_15/resume_rename_17/resume_rename_18',
  279. parent: pageId15,
  280. grant: Page.GRANT_PUBLIC,
  281. creator: dummyUser1,
  282. lastUpdateUser: dummyUser1._id,
  283. descendantCount: 1,
  284. isEmpty: false,
  285. },
  286. {
  287. _id: pageId17,
  288. path: '/resume_rename_15/resume_rename_17/resume_rename_18/resume_rename_19',
  289. parent: pageId16,
  290. grant: Page.GRANT_PUBLIC,
  291. creator: dummyUser1,
  292. lastUpdateUser: dummyUser1._id,
  293. descendantCount: 0,
  294. isEmpty: false,
  295. },
  296. {
  297. _id: pageId18,
  298. path: '/fix_descendantCount_1',
  299. parent: rootPage._id,
  300. grant: Page.GRANT_PUBLIC,
  301. creator: dummyUser1,
  302. lastUpdateUser: dummyUser1._id,
  303. descendantCount: 100, // broken
  304. isEmpty: false,
  305. },
  306. {
  307. _id: pageId19,
  308. path: '/fix_descendantCount_1/fix_descendantCount_2',
  309. parent: pageId18,
  310. grant: Page.GRANT_PUBLIC,
  311. creator: dummyUser1,
  312. lastUpdateUser: dummyUser1._id,
  313. descendantCount: 100, // broken
  314. isEmpty: true,
  315. },
  316. {
  317. path: '/fix_descendantCount_1/fix_descendantCount_2/fix_descendantCount_3',
  318. parent: pageId19,
  319. grant: Page.GRANT_PUBLIC,
  320. creator: dummyUser1,
  321. lastUpdateUser: dummyUser1._id,
  322. descendantCount: 100, // broken
  323. isEmpty: false,
  324. },
  325. {
  326. _id: pageId20,
  327. path: '/fix_descendantCount_4',
  328. parent: rootPage._id,
  329. grant: Page.GRANT_PUBLIC,
  330. creator: dummyUser1,
  331. lastUpdateUser: dummyUser1._id,
  332. descendantCount: 100, // broken
  333. isEmpty: false,
  334. },
  335. {
  336. path: '/fix_descendantCount_4/fix_descendantCount_5',
  337. parent: pageId20,
  338. grant: Page.GRANT_PUBLIC,
  339. creator: dummyUser1,
  340. lastUpdateUser: dummyUser1._id,
  341. descendantCount: 100, // broken
  342. isEmpty: false,
  343. },
  344. ]);
  345. /**
  346. * PageOperation
  347. */
  348. pageOpId1 = new mongoose.Types.ObjectId();
  349. pageOpId2 = new mongoose.Types.ObjectId();
  350. pageOpId3 = new mongoose.Types.ObjectId();
  351. pageOpId4 = new mongoose.Types.ObjectId();
  352. const pageOpRevisionId1 = new mongoose.Types.ObjectId();
  353. const pageOpRevisionId2 = new mongoose.Types.ObjectId();
  354. const pageOpRevisionId3 = new mongoose.Types.ObjectId();
  355. const pageOpRevisionId4 = new mongoose.Types.ObjectId();
  356. await PageOperation.insertMany([
  357. {
  358. _id: pageOpId1,
  359. actionType: 'Rename',
  360. actionStage: 'Sub',
  361. fromPath: '/resume_rename_1',
  362. toPath: '/resume_rename_0/resume_rename_1',
  363. page: {
  364. _id: pageId1,
  365. parent: rootPage._id,
  366. descendantCount: 2,
  367. isEmpty: false,
  368. path: '/resume_rename_1',
  369. revision: pageOpRevisionId1,
  370. status: 'published',
  371. grant: 1,
  372. grantedUsers: [],
  373. grantedGroup: null,
  374. creator: dummyUser1._id,
  375. lastUpdateUser: dummyUser1._id,
  376. },
  377. user: {
  378. _id: dummyUser1._id,
  379. },
  380. options: {
  381. createRedirectPage: false,
  382. updateMetadata: true,
  383. },
  384. unprocessableExpiryDate: null,
  385. },
  386. {
  387. _id: pageOpId2,
  388. actionType: 'Rename',
  389. actionStage: 'Sub',
  390. fromPath: '/resume_rename_5',
  391. toPath: '/resume_rename_4/resume_rename_5',
  392. page: {
  393. _id: pageId5,
  394. parent: rootPage._id,
  395. descendantCount: 2,
  396. isEmpty: false,
  397. path: '/resume_rename_5',
  398. revision: pageOpRevisionId2,
  399. status: 'published',
  400. grant: 1,
  401. grantedUsers: [],
  402. grantedGroup: null,
  403. creator: dummyUser1._id,
  404. lastUpdateUser: dummyUser1._id,
  405. },
  406. user: {
  407. _id: dummyUser1._id,
  408. },
  409. options: {
  410. createRedirectPage: false,
  411. updateMetadata: true,
  412. },
  413. unprocessableExpiryDate: new Date(),
  414. },
  415. {
  416. _id: pageOpId3,
  417. actionType: 'Rename',
  418. actionStage: 'Sub',
  419. fromPath: '/resume_rename_7',
  420. // toPath NOT exist
  421. page: {
  422. _id: pageId7,
  423. parent: rootPage._id,
  424. descendantCount: 2,
  425. isEmpty: false,
  426. path: '/resume_rename_7',
  427. revision: pageOpRevisionId3,
  428. status: 'published',
  429. grant: 1,
  430. grantedUsers: [],
  431. grantedGroup: null,
  432. creator: dummyUser1._id,
  433. lastUpdateUser: dummyUser1._id,
  434. },
  435. user: {
  436. _id: dummyUser1._id,
  437. },
  438. options: {
  439. createRedirectPage: false,
  440. updateMetadata: true,
  441. },
  442. unprocessableExpiryDate: new Date(),
  443. },
  444. {
  445. _id: pageOpId4,
  446. actionType: 'Rename',
  447. actionStage: 'Sub',
  448. fromPath: '/resume_rename_9',
  449. toPath: '/resume_rename_8/resume_rename_9',
  450. page: {
  451. _id: pageId9,
  452. parent: rootPage._id,
  453. descendantCount: 1,
  454. isEmpty: false,
  455. path: '/resume_rename_9',
  456. revision: pageOpRevisionId4,
  457. status: 'published',
  458. grant: Page.GRANT_PUBLIC,
  459. grantedUsers: [],
  460. grantedGroup: null,
  461. creator: dummyUser1._id,
  462. lastUpdateUser: dummyUser1._id,
  463. },
  464. user: {
  465. _id: dummyUser1._id,
  466. },
  467. options: {
  468. createRedirectPage: false,
  469. updateMetadata: true,
  470. },
  471. unprocessableExpiryDate: null,
  472. },
  473. ]);
  474. });
  475. describe('restart renameOperation', () => {
  476. const resumeRenameSubOperation = async(renamePage, pageOp, activity?) => {
  477. const mockedPathsAndDescendantCountOfAncestors = jest.spyOn(crowi.pageService, 'fixPathsAndDescendantCountOfAncestors').mockReturnValue(null);
  478. await crowi.pageService.resumeRenameSubOperation(renamePage, pageOp, activity);
  479. const argsForRenameSubOperation = mockedPathsAndDescendantCountOfAncestors.mock.calls[0];
  480. mockedPathsAndDescendantCountOfAncestors.mockRestore();
  481. await crowi.pageService.fixPathsAndDescendantCountOfAncestors(...argsForRenameSubOperation);
  482. };
  483. test('it should successfully restart rename operation', async() => {
  484. // paths before renaming
  485. const _path0 = '/resume_rename_0'; // out of renaming scope
  486. const _path1 = '/resume_rename_0/resume_rename_1'; // renamed already
  487. const _path2 = '/resume_rename_1/resume_rename_2'; // not renamed yet
  488. const _path3 = '/resume_rename_1/resume_rename_2/resume_rename_3'; // not renamed yet
  489. // paths after renaming
  490. const path0 = '/resume_rename_0';
  491. const path1 = '/resume_rename_0/resume_rename_1';
  492. const path2 = '/resume_rename_0/resume_rename_1/resume_rename_2';
  493. const path3 = '/resume_rename_0/resume_rename_1/resume_rename_2/resume_rename_3';
  494. // activity options
  495. const activity = 'randomActivityId';
  496. // page
  497. const _page0 = await Page.findOne({ path: _path0 });
  498. const _page1 = await Page.findOne({ path: _path1 });
  499. const _page2 = await Page.findOne({ path: _path2 });
  500. const _page3 = await Page.findOne({ path: _path3 });
  501. expect(_page0).toBeTruthy();
  502. expect(_page1).toBeTruthy();
  503. expect(_page2).toBeTruthy();
  504. expect(_page3).toBeTruthy();
  505. expect(_page0.descendantCount).toBe(1);
  506. expect(_page1.descendantCount).toBe(2);
  507. expect(_page2.descendantCount).toBe(1);
  508. expect(_page3.descendantCount).toBe(0);
  509. // page operation
  510. const fromPath = '/resume_rename_1';
  511. const toPath = '/resume_rename_0/resume_rename_1';
  512. const _pageOperation = await PageOperation.findOne({
  513. _id: pageOpId1, fromPath, toPath, 'page._id': _page1._id, actionType: PageActionType.Rename, actionStage: PageActionStage.Sub,
  514. });
  515. expect(_pageOperation).toBeTruthy();
  516. // rename
  517. await resumeRenameSubOperation(_page1, _pageOperation, activity);
  518. // page
  519. const page0 = await Page.findById(_page0._id);
  520. const page1 = await Page.findById(_page1._id);
  521. const page2 = await Page.findById(_page2._id);
  522. const page3 = await Page.findById(_page3._id);
  523. expect(page0).toBeTruthy();
  524. expect(page1).toBeTruthy();
  525. expect(page2).toBeTruthy();
  526. expect(page3).toBeTruthy();
  527. // check paths after renaming
  528. expect(page0.path).toBe(path0);
  529. expect(page1.path).toBe(path1);
  530. expect(page2.path).toBe(path2);
  531. expect(page3.path).toBe(path3);
  532. // page operation
  533. const pageOperation = await PageOperation.findById(_pageOperation._id);
  534. expect(pageOperation).toBeNull(); // should not exist
  535. expect(page0.descendantCount).toBe(3);
  536. expect(page1.descendantCount).toBe(2);
  537. expect(page2.descendantCount).toBe(1);
  538. expect(page3.descendantCount).toBe(0);
  539. });
  540. test('it should successfully restart rename operation when unprocessableExpiryDate is null', async() => {
  541. // paths before renaming
  542. const _path0 = '/resume_rename_8'; // out of renaming scope
  543. const _path1 = '/resume_rename_8/resume_rename_9'; // renamed already
  544. const _path2 = '/resume_rename_9/resume_rename_10'; // not renamed yet
  545. // paths after renaming
  546. const path0 = '/resume_rename_8';
  547. const path1 = '/resume_rename_8/resume_rename_9';
  548. const path2 = '/resume_rename_8/resume_rename_9/resume_rename_10';
  549. // activity options
  550. const activityParameters = {
  551. ip: '::ffff:127.0.0.1',
  552. endpoint: '/_api/v3/pages/rename',
  553. activityId: '62e291bc10e0ab61bd691794',
  554. };
  555. // page
  556. const _page0 = await Page.findOne({ path: _path0 });
  557. const _page1 = await Page.findOne({ path: _path1 });
  558. const _page2 = await Page.findOne({ path: _path2 });
  559. expect(_page0).toBeTruthy();
  560. expect(_page1).toBeTruthy();
  561. expect(_page2).toBeTruthy();
  562. expect(_page0.descendantCount).toBe(1);
  563. expect(_page1.descendantCount).toBe(1);
  564. expect(_page2.descendantCount).toBe(0);
  565. // page operation
  566. const fromPath = '/resume_rename_9';
  567. const toPath = '/resume_rename_8/resume_rename_9';
  568. const _pageOperation = await PageOperation.findOne({
  569. _id: pageOpId4, fromPath, toPath, 'page._id': _page1._id, actionType: PageActionType.Rename, actionStage: PageActionStage.Sub,
  570. });
  571. expect(_pageOperation).toBeTruthy();
  572. // rename
  573. await resumeRenameSubOperation(_page1, _pageOperation, activityParameters);
  574. // page
  575. const page0 = await Page.findById(_page0._id);
  576. const page1 = await Page.findById(_page1._id);
  577. const page2 = await Page.findById(_page2._id);
  578. expect(page0).toBeTruthy();
  579. expect(page1).toBeTruthy();
  580. expect(page2).toBeTruthy();
  581. // check paths after renaming
  582. expect(page0.path).toBe(path0);
  583. expect(page1.path).toBe(path1);
  584. expect(page2.path).toBe(path2);
  585. // page operation
  586. const pageOperation = await PageOperation.findById(_pageOperation._id);
  587. expect(pageOperation).toBeNull(); // should not exist
  588. // others
  589. expect(page1.parent).toStrictEqual(page0._id);
  590. expect(page2.parent).toStrictEqual(page1._id);
  591. expect(page0.descendantCount).toBe(2);
  592. expect(page1.descendantCount).toBe(1);
  593. expect(page2.descendantCount).toBe(0);
  594. });
  595. test('it should fail and throw error if the current time is behind unprocessableExpiryDate', async() => {
  596. // path before renaming
  597. const _path0 = '/resume_rename_4'; // out of renaming scope
  598. const _path1 = '/resume_rename_4/resume_rename_5'; // renamed already
  599. const _path2 = '/resume_rename_5/resume_rename_6'; // not renamed yet
  600. // page
  601. const _page0 = await Page.findOne({ path: _path0 });
  602. const _page1 = await Page.findOne({ path: _path1 });
  603. const _page2 = await Page.findOne({ path: _path2 });
  604. expect(_page0).toBeTruthy();
  605. expect(_page1).toBeTruthy();
  606. expect(_page2).toBeTruthy();
  607. // page operation
  608. const fromPath = '/resume_rename_5';
  609. const toPath = '/resume_rename_4/resume_rename_5';
  610. const _pageOperation = await PageOperation.findOne({
  611. _id: pageOpId2, fromPath, toPath, 'page._id': _page1._id, actionType: PageActionType.Rename, actionStage: PageActionStage.Sub,
  612. });
  613. expect(_pageOperation).toBeTruthy();
  614. // Make `unprocessableExpiryDate` 15 seconds ahead of current time.
  615. // The number 15 seconds has no meaning other than placing time in the furue.
  616. const pageOperation = await PageOperation.findByIdAndUpdate(_pageOperation._id, { unprocessableExpiryDate: addSeconds(new Date(), 15) }, { new: true });
  617. expect(pageOperation).toBeTruthy();
  618. await expect(resumeRenameSubOperation(_page1, pageOperation)).rejects.toThrow(new Error('This page operation is currently being processed'));
  619. // cleanup
  620. await PageOperation.findByIdAndDelete(pageOperation._id);
  621. });
  622. test('Missing property(toPath) for PageOperation should throw error', async() => {
  623. // page
  624. const _path1 = '/resume_rename_7';
  625. const _page1 = await Page.findOne({ path: _path1 });
  626. expect(_page1).toBeTruthy();
  627. // page operation
  628. const pageOperation = await PageOperation.findOne({
  629. _id: pageOpId3, 'page._id': _page1._id, actionType: PageActionType.Rename, actionStage: PageActionStage.Sub,
  630. });
  631. expect(pageOperation).toBeTruthy();
  632. const promise = resumeRenameSubOperation(_page1, pageOperation);
  633. await expect(promise).rejects.toThrow(new Error(`Property toPath is missing which is needed to resume rename operation(${pageOperation._id})`));
  634. // cleanup
  635. await PageOperation.findByIdAndDelete(pageOperation._id);
  636. });
  637. });
  638. describe('updateDescendantCountOfPagesWithPaths', () => {
  639. test('should fix descendantCount of pages with one of the given paths', async() => {
  640. // path
  641. const _path1 = '/fix_descendantCount_1';
  642. const _path2 = '/fix_descendantCount_1/fix_descendantCount_2'; // empty
  643. const _path3 = '/fix_descendantCount_1/fix_descendantCount_2/fix_descendantCount_3';
  644. const _path4 = '/fix_descendantCount_4';
  645. const _path5 = '/fix_descendantCount_4/fix_descendantCount_5';
  646. // page
  647. const _page1 = await Page.findOne({ path: _path1 });
  648. const _page2 = await Page.findOne({ path: _path2 });
  649. const _page3 = await Page.findOne({ path: _path3 });
  650. const _page4 = await Page.findOne({ path: _path4 });
  651. const _page5 = await Page.findOne({ path: _path5 });
  652. // check existance
  653. expect(_page1).toBeTruthy();
  654. expect(_page2).toBeTruthy();
  655. expect(_page3).toBeTruthy();
  656. expect(_page4).toBeTruthy();
  657. expect(_page5).toBeTruthy();
  658. // check descendantCount (all broken)
  659. expect(_page1.descendantCount).toBe(100);
  660. expect(_page2.descendantCount).toBe(100);
  661. expect(_page3.descendantCount).toBe(100);
  662. expect(_page4.descendantCount).toBe(100);
  663. expect(_page5.descendantCount).toBe(100);
  664. // check isEmpty
  665. expect(_page1.isEmpty).toBe(false);
  666. expect(_page2.isEmpty).toBe(true);
  667. expect(_page3.isEmpty).toBe(false);
  668. expect(_page4.isEmpty).toBe(false);
  669. expect(_page5.isEmpty).toBe(false);
  670. // check parent
  671. expect(_page1.parent).toStrictEqual(rootPage._id);
  672. expect(_page2.parent).toStrictEqual(_page1._id);
  673. expect(_page3.parent).toStrictEqual(_page2._id);
  674. expect(_page4.parent).toStrictEqual(rootPage._id);
  675. expect(_page5.parent).toStrictEqual(_page4._id);
  676. await crowi.pageService.updateDescendantCountOfPagesWithPaths([_path1, _path2, _path3, _path4, _path5]);
  677. // page
  678. const page1 = await Page.findById(_page1._id);
  679. const page2 = await Page.findById(_page2._id);
  680. const page3 = await Page.findById(_page3._id);
  681. const page4 = await Page.findById(_page4._id);
  682. const page5 = await Page.findById(_page5._id);
  683. // check existance
  684. expect(page1).toBeTruthy();
  685. expect(page2).toBeTruthy();
  686. expect(page3).toBeTruthy();
  687. expect(page4).toBeTruthy();
  688. expect(page5).toBeTruthy();
  689. // check descendantCount (all fixed)
  690. expect(page1.descendantCount).toBe(1);
  691. expect(page2.descendantCount).toBe(1);
  692. expect(page3.descendantCount).toBe(0);
  693. expect(page4.descendantCount).toBe(1);
  694. expect(page5.descendantCount).toBe(0);
  695. // check isEmpty
  696. expect(page1.isEmpty).toBe(false);
  697. expect(page2.isEmpty).toBe(true);
  698. expect(page3.isEmpty).toBe(false);
  699. expect(page4.isEmpty).toBe(false);
  700. expect(page5.isEmpty).toBe(false);
  701. // check parent
  702. expect(page1.parent).toStrictEqual(rootPage._id);
  703. expect(page2.parent).toStrictEqual(page1._id);
  704. expect(page3.parent).toStrictEqual(page2._id);
  705. expect(page4.parent).toStrictEqual(rootPage._id);
  706. expect(page5.parent).toStrictEqual(page4._id);
  707. });
  708. });
  709. });