v5.page.test.ts 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297
  1. import mongoose from 'mongoose';
  2. import { PageActionType } from '../../../src/server/models/page-operation';
  3. import { getInstance } from '../setup-crowi';
  4. describe('Test page service methods', () => {
  5. let crowi;
  6. let Page;
  7. let Revision;
  8. let User;
  9. let UserGroup;
  10. let UserGroupRelation;
  11. let Tag;
  12. let PageTagRelation;
  13. let Bookmark;
  14. let Comment;
  15. let ShareLink;
  16. let PageRedirect;
  17. let PageOperation;
  18. let xssSpy;
  19. let rootPage;
  20. let dummyUser1;
  21. let dummyUser2;
  22. let globalGroupUser1;
  23. let globalGroupUser2;
  24. let globalGroupUser3;
  25. let globalGroupIsolate;
  26. let globalGroupA;
  27. let globalGroupB;
  28. let globalGroupC;
  29. beforeAll(async() => {
  30. crowi = await getInstance();
  31. await crowi.configManager.updateConfigsInTheSameNamespace('crowi', { 'app:isV5Compatible': true });
  32. User = mongoose.model('User');
  33. UserGroup = mongoose.model('UserGroup');
  34. UserGroupRelation = mongoose.model('UserGroupRelation');
  35. Page = mongoose.model('Page');
  36. Revision = mongoose.model('Revision');
  37. Tag = mongoose.model('Tag');
  38. PageTagRelation = mongoose.model('PageTagRelation');
  39. Bookmark = mongoose.model('Bookmark');
  40. Comment = mongoose.model('Comment');
  41. ShareLink = mongoose.model('ShareLink');
  42. PageRedirect = mongoose.model('PageRedirect');
  43. UserGroup = mongoose.model('UserGroup');
  44. UserGroupRelation = mongoose.model('UserGroupRelation');
  45. PageOperation = mongoose.model('PageOperation');
  46. /*
  47. * Common
  48. */
  49. xssSpy = jest.spyOn(crowi.xss, 'process').mockImplementation(path => path);
  50. // ***********************************************************************************************************
  51. // * Do NOT change properties of globally used documents. Otherwise, it might cause some errors in other tests
  52. // ***********************************************************************************************************
  53. // users
  54. dummyUser1 = await User.findOne({ username: 'v5DummyUser1' });
  55. dummyUser2 = await User.findOne({ username: 'v5DummyUser2' });
  56. globalGroupUser1 = await User.findOne({ username: 'gGroupUser1' });
  57. globalGroupUser2 = await User.findOne({ username: 'gGroupUser2' });
  58. globalGroupUser3 = await User.findOne({ username: 'gGroupUser3' });
  59. // groups
  60. globalGroupIsolate = await UserGroup.findOne({ name: 'globalGroupIsolate' });
  61. globalGroupA = await UserGroup.findOne({ name: 'globalGroupA' });
  62. globalGroupB = await UserGroup.findOne({ name: 'globalGroupB' });
  63. globalGroupC = await UserGroup.findOne({ name: 'globalGroupC' });
  64. // page
  65. rootPage = await Page.findOne({ path: '/' });
  66. /**
  67. * pages
  68. */
  69. const pageId0 = new mongoose.Types.ObjectId();
  70. const pageId1 = new mongoose.Types.ObjectId();
  71. const pageId2 = new mongoose.Types.ObjectId();
  72. const pageId3 = new mongoose.Types.ObjectId();
  73. const pageId4 = new mongoose.Types.ObjectId();
  74. const pageId5 = new mongoose.Types.ObjectId();
  75. const pageId6 = new mongoose.Types.ObjectId();
  76. await Page.insertMany([
  77. {
  78. _id: pageId0,
  79. path: '/POP0',
  80. parent: rootPage._id,
  81. grant: Page.GRANT_PUBLIC,
  82. creator: dummyUser1,
  83. lastUpdateUser: dummyUser1._id,
  84. descendantCount: 0,
  85. },
  86. {
  87. _id: pageId1,
  88. path: '/POP0/renamePOP1',
  89. parent: pageId0._id,
  90. grant: Page.GRANT_PUBLIC,
  91. creator: dummyUser1,
  92. lastUpdateUser: dummyUser1._id,
  93. descendantCount: 2,
  94. },
  95. {
  96. _id: pageId2,
  97. path: '/renamePOP1/renamePOP2',
  98. parent: pageId1,
  99. grant: Page.GRANT_PUBLIC,
  100. creator: dummyUser1,
  101. lastUpdateUser: dummyUser1._id,
  102. descendantCount: 1,
  103. },
  104. {
  105. _id: pageId3,
  106. path: '/renamePOP1/renamePOP2/renamePOP3',
  107. parent: pageId2,
  108. grant: Page.GRANT_PUBLIC,
  109. creator: dummyUser1,
  110. lastUpdateUser: dummyUser1._id,
  111. descendantCount: 0,
  112. },
  113. {
  114. _id: pageId4,
  115. path: '/POP1',
  116. parent: rootPage._id,
  117. grant: Page.GRANT_PUBLIC,
  118. creator: dummyUser1,
  119. lastUpdateUser: dummyUser1._id,
  120. descendantCount: 0,
  121. },
  122. {
  123. _id: pageId5,
  124. path: '/POP1/renamePOP4',
  125. parent: pageId0._id,
  126. grant: Page.GRANT_PUBLIC,
  127. creator: dummyUser1,
  128. lastUpdateUser: dummyUser1._id,
  129. descendantCount: 1,
  130. },
  131. {
  132. _id: pageId6,
  133. path: '/renamePOP4/renamePOP5',
  134. parent: pageId5,
  135. grant: Page.GRANT_PUBLIC,
  136. creator: dummyUser1,
  137. lastUpdateUser: dummyUser1._id,
  138. descendantCount: 0,
  139. },
  140. ]);
  141. /**
  142. * PageOperation
  143. */
  144. const pageOpId1 = new mongoose.Types.ObjectId();
  145. const pageOpId2 = new mongoose.Types.ObjectId();
  146. const pageOpRevisionId1 = new mongoose.Types.ObjectId();
  147. const pageOpRevisionId2 = new mongoose.Types.ObjectId();
  148. await PageOperation.insertMany([
  149. {
  150. _id: pageOpId1,
  151. actionType: 'Rename',
  152. actionStage: 'Sub',
  153. fromPath: '/renamePOP1',
  154. toPath: '/POP0/renamePOP1',
  155. page: {
  156. _id: pageId1,
  157. parent: rootPage._id,
  158. descendantCount: 2,
  159. isEmpty: false,
  160. path: '/renamePOP1',
  161. revision: pageOpRevisionId1,
  162. status: 'published',
  163. grant: 1,
  164. grantedUsers: [],
  165. grantedGroup: null,
  166. creator: dummyUser1._id,
  167. lastUpdateUser: dummyUser1._id,
  168. },
  169. user: {
  170. _id: dummyUser1._id,
  171. },
  172. options: {
  173. createRedirectPage: false,
  174. updateMetadata: true,
  175. },
  176. unprocessableExpiryDate: null,
  177. },
  178. {
  179. _id: pageOpId2,
  180. actionType: 'Rename',
  181. actionStage: 'Sub',
  182. fromPath: '/renamePOP4',
  183. toPath: '/POP1/renamePOP4',
  184. page: {
  185. _id: pageId5,
  186. parent: rootPage._id,
  187. descendantCount: 2,
  188. isEmpty: false,
  189. path: '/renamePOP4',
  190. revision: pageOpRevisionId2,
  191. status: 'published',
  192. grant: 1,
  193. grantedUsers: [],
  194. grantedGroup: null,
  195. creator: dummyUser1._id,
  196. lastUpdateUser: dummyUser1._id,
  197. },
  198. user: {
  199. _id: dummyUser1._id,
  200. },
  201. options: {
  202. createRedirectPage: false,
  203. updateMetadata: true,
  204. },
  205. unprocessableExpiryDate: new Date(5000, 0, 1), // year 5000
  206. },
  207. ]);
  208. });
  209. describe('restart renameOperation', () => {
  210. const resumePageRenameOperation = async(pageId) => {
  211. const mockedRenameSubOperation = jest.spyOn(crowi.pageService, 'renameSubOperation').mockReturnValue(null);
  212. await crowi.pageService.resumePageRenameOperation(pageId);
  213. const argsForRenameSubOperation = mockedRenameSubOperation.mock.calls[0];
  214. mockedRenameSubOperation.mockRestore();
  215. await crowi.pageService.renameSubOperation(...argsForRenameSubOperation);
  216. };
  217. test('it should successfully restart rename operation', async() => {
  218. const _path0 = '/POP0';
  219. const _path1 = '/POP0/renamePOP1'; // renamed already
  220. const _path2 = '/renamePOP1/renamePOP2'; // not renamed yet
  221. const _path3 = '/renamePOP1/renamePOP2/renamePOP3'; // not renamed yet
  222. const _page0 = await Page.findOne({ path: _path0 });
  223. const _page1 = await Page.findOne({ path: _path1 });
  224. const _page2 = await Page.findOne({ path: _path2 });
  225. const _page3 = await Page.findOne({ path: _path3 });
  226. expect(_page0).toBeTruthy();
  227. expect(_page1).toBeTruthy();
  228. expect(_page2).toBeTruthy();
  229. expect(_page3).toBeTruthy();
  230. const _pageOperation = await PageOperation.findOne({ 'page._id': _page1._id, actionType: PageActionType.Rename });
  231. expect(_pageOperation).toBeTruthy();
  232. await resumePageRenameOperation(_pageOperation.page._id);
  233. const path0 = '/POP0';
  234. const path1 = '/POP0/renamePOP1';
  235. const path2 = '/POP0/renamePOP1/renamePOP2';
  236. const path3 = '/POP0/renamePOP1/renamePOP2/renamePOP3';
  237. const page0 = await Page.findOne({ path: path0 });
  238. const page1 = await Page.findOne({ path: path1 });
  239. const page2 = await Page.findOne({ path: path2 });
  240. const page3 = await Page.findOne({ path: path3 });
  241. const pageOperation = await PageOperation.findOne({ _id: _pageOperation._id });
  242. expect(page0.descendantCount).toBe(3);
  243. expect(page0).toBeTruthy();
  244. expect(page1).toBeTruthy();
  245. expect(page2).toBeTruthy();
  246. expect(page3).toBeTruthy();
  247. expect(pageOperation).toBeNull(); // should not exist
  248. expect(page1.parent).toStrictEqual(page0._id);
  249. expect(page2.parent).toStrictEqual(page1._id);
  250. expect(page3.parent).toStrictEqual(page2._id);
  251. expect(page0.descendantCount).toBe(3);
  252. expect(page1.descendantCount).toBe(2);
  253. expect(page2.descendantCount).toBe(1);
  254. expect(page3.descendantCount).toBe(0);
  255. });
  256. test('it should fail and throw error if PageOperation is not found', async() => {
  257. const pageId = new mongoose.Types.ObjectId(); // not exist in DB
  258. await expect(resumePageRenameOperation(pageId))
  259. .rejects.toThrow(new Error('it did not restart rename operation because page operation to be processed was not found'));
  260. });
  261. test('it should fail and throw error if the current time is behind unprocessableExpiryDate', async() => {
  262. const _path0 = '/POP1';
  263. const _path1 = '/POP1/renamePOP4'; // renamed already
  264. const _path2 = '/renamePOP4/renamePOP5'; // not renamed yet
  265. const _page0 = await Page.findOne({ path: _path0 });
  266. const _page1 = await Page.findOne({ path: _path1 });
  267. const _page2 = await Page.findOne({ path: _path2 });
  268. const _pageOperation = await PageOperation.findOne({ 'page._id': _page1._id, actionType: PageActionType.Rename });
  269. expect(_page0).toBeTruthy();
  270. expect(_page1).toBeTruthy();
  271. expect(_page2).toBeTruthy();
  272. expect(_pageOperation).toBeTruthy();
  273. const promise = resumePageRenameOperation(_pageOperation.page._id);
  274. await expect(promise).rejects.toThrow(new Error('it did not restart rename operation because it is currently being processed'));
  275. });
  276. });
  277. });