import mongoose from 'mongoose'; import { PageActionType } from '../../../src/server/models/page-operation'; import { getInstance } from '../setup-crowi'; describe('Test page service methods', () => { let crowi; let Page; let Revision; let User; let UserGroup; let UserGroupRelation; let Tag; let PageTagRelation; let Bookmark; let Comment; let ShareLink; let PageRedirect; let PageOperation; let xssSpy; let rootPage; let dummyUser1; let dummyUser2; let globalGroupUser1; let globalGroupUser2; let globalGroupUser3; let globalGroupIsolate; let globalGroupA; let globalGroupB; let globalGroupC; beforeAll(async() => { crowi = await getInstance(); await crowi.configManager.updateConfigsInTheSameNamespace('crowi', { 'app:isV5Compatible': true }); User = mongoose.model('User'); UserGroup = mongoose.model('UserGroup'); UserGroupRelation = mongoose.model('UserGroupRelation'); Page = mongoose.model('Page'); Revision = mongoose.model('Revision'); Tag = mongoose.model('Tag'); PageTagRelation = mongoose.model('PageTagRelation'); Bookmark = mongoose.model('Bookmark'); Comment = mongoose.model('Comment'); ShareLink = mongoose.model('ShareLink'); PageRedirect = mongoose.model('PageRedirect'); UserGroup = mongoose.model('UserGroup'); UserGroupRelation = mongoose.model('UserGroupRelation'); PageOperation = mongoose.model('PageOperation'); /* * Common */ xssSpy = jest.spyOn(crowi.xss, 'process').mockImplementation(path => path); // *********************************************************************************************************** // * Do NOT change properties of globally used documents. Otherwise, it might cause some errors in other tests // *********************************************************************************************************** // users dummyUser1 = await User.findOne({ username: 'v5DummyUser1' }); dummyUser2 = await User.findOne({ username: 'v5DummyUser2' }); globalGroupUser1 = await User.findOne({ username: 'gGroupUser1' }); globalGroupUser2 = await User.findOne({ username: 'gGroupUser2' }); globalGroupUser3 = await User.findOne({ username: 'gGroupUser3' }); // groups globalGroupIsolate = await UserGroup.findOne({ name: 'globalGroupIsolate' }); globalGroupA = await UserGroup.findOne({ name: 'globalGroupA' }); globalGroupB = await UserGroup.findOne({ name: 'globalGroupB' }); globalGroupC = await UserGroup.findOne({ name: 'globalGroupC' }); // page rootPage = await Page.findOne({ path: '/' }); /** * pages */ const pageId0 = new mongoose.Types.ObjectId(); const pageId1 = new mongoose.Types.ObjectId(); const pageId2 = new mongoose.Types.ObjectId(); const pageId3 = new mongoose.Types.ObjectId(); const pageId4 = new mongoose.Types.ObjectId(); const pageId5 = new mongoose.Types.ObjectId(); const pageId6 = new mongoose.Types.ObjectId(); await Page.insertMany([ { _id: pageId0, path: '/POP0', parent: rootPage._id, grant: Page.GRANT_PUBLIC, creator: dummyUser1, lastUpdateUser: dummyUser1._id, descendantCount: 0, }, { _id: pageId1, path: '/POP0/renamePOP1', parent: pageId0._id, grant: Page.GRANT_PUBLIC, creator: dummyUser1, lastUpdateUser: dummyUser1._id, descendantCount: 2, }, { _id: pageId2, path: '/renamePOP1/renamePOP2', parent: pageId1, grant: Page.GRANT_PUBLIC, creator: dummyUser1, lastUpdateUser: dummyUser1._id, descendantCount: 1, }, { _id: pageId3, path: '/renamePOP1/renamePOP2/renamePOP3', parent: pageId2, grant: Page.GRANT_PUBLIC, creator: dummyUser1, lastUpdateUser: dummyUser1._id, descendantCount: 0, }, { _id: pageId4, path: '/POP1', parent: rootPage._id, grant: Page.GRANT_PUBLIC, creator: dummyUser1, lastUpdateUser: dummyUser1._id, descendantCount: 0, }, { _id: pageId5, path: '/POP1/renamePOP4', parent: pageId0._id, grant: Page.GRANT_PUBLIC, creator: dummyUser1, lastUpdateUser: dummyUser1._id, descendantCount: 1, }, { _id: pageId6, path: '/renamePOP4/renamePOP5', parent: pageId5, grant: Page.GRANT_PUBLIC, creator: dummyUser1, lastUpdateUser: dummyUser1._id, descendantCount: 0, }, ]); /** * PageOperation */ const pageOpId1 = new mongoose.Types.ObjectId(); const pageOpId2 = new mongoose.Types.ObjectId(); const pageOpRevisionId1 = new mongoose.Types.ObjectId(); const pageOpRevisionId2 = new mongoose.Types.ObjectId(); await PageOperation.insertMany([ { _id: pageOpId1, actionType: 'Rename', actionStage: 'Sub', fromPath: '/renamePOP1', toPath: '/POP0/renamePOP1', page: { _id: pageId1, parent: rootPage._id, descendantCount: 2, isEmpty: false, path: '/renamePOP1', revision: pageOpRevisionId1, status: 'published', grant: 1, grantedUsers: [], grantedGroup: null, creator: dummyUser1._id, lastUpdateUser: dummyUser1._id, }, user: { _id: dummyUser1._id, }, options: { createRedirectPage: false, updateMetadata: true, }, unprocessableExpiryDate: null, }, { _id: pageOpId2, actionType: 'Rename', actionStage: 'Sub', fromPath: '/renamePOP4', toPath: '/POP1/renamePOP4', page: { _id: pageId5, parent: rootPage._id, descendantCount: 2, isEmpty: false, path: '/renamePOP4', revision: pageOpRevisionId2, status: 'published', grant: 1, grantedUsers: [], grantedGroup: null, creator: dummyUser1._id, lastUpdateUser: dummyUser1._id, }, user: { _id: dummyUser1._id, }, options: { createRedirectPage: false, updateMetadata: true, }, unprocessableExpiryDate: new Date(5000, 0, 1), // year 5000 }, ]); }); describe('restart renameOperation', () => { const resumePageRenameOperation = async(pageId) => { const mockedRenameSubOperation = jest.spyOn(crowi.pageService, 'renameSubOperation').mockReturnValue(null); await crowi.pageService.resumePageRenameOperation(pageId); const argsForRenameSubOperation = mockedRenameSubOperation.mock.calls[0]; mockedRenameSubOperation.mockRestore(); await crowi.pageService.renameSubOperation(...argsForRenameSubOperation); }; test('it should successfully restart rename operation', async() => { const _path0 = '/POP0'; const _path1 = '/POP0/renamePOP1'; // renamed already const _path2 = '/renamePOP1/renamePOP2'; // not renamed yet const _path3 = '/renamePOP1/renamePOP2/renamePOP3'; // not renamed yet const _page0 = await Page.findOne({ path: _path0 }); const _page1 = await Page.findOne({ path: _path1 }); const _page2 = await Page.findOne({ path: _path2 }); const _page3 = await Page.findOne({ path: _path3 }); expect(_page0).toBeTruthy(); expect(_page1).toBeTruthy(); expect(_page2).toBeTruthy(); expect(_page3).toBeTruthy(); const _pageOperation = await PageOperation.findOne({ 'page._id': _page1._id, actionType: PageActionType.Rename }); expect(_pageOperation).toBeTruthy(); await resumePageRenameOperation(_pageOperation.page._id); const path0 = '/POP0'; const path1 = '/POP0/renamePOP1'; const path2 = '/POP0/renamePOP1/renamePOP2'; const path3 = '/POP0/renamePOP1/renamePOP2/renamePOP3'; const page0 = await Page.findOne({ path: path0 }); const page1 = await Page.findOne({ path: path1 }); const page2 = await Page.findOne({ path: path2 }); const page3 = await Page.findOne({ path: path3 }); const pageOperation = await PageOperation.findOne({ _id: _pageOperation._id }); expect(page0.descendantCount).toBe(3); expect(page0).toBeTruthy(); expect(page1).toBeTruthy(); expect(page2).toBeTruthy(); expect(page3).toBeTruthy(); expect(pageOperation).toBeNull(); // should not exist expect(page1.parent).toStrictEqual(page0._id); expect(page2.parent).toStrictEqual(page1._id); expect(page3.parent).toStrictEqual(page2._id); expect(page0.descendantCount).toBe(3); expect(page1.descendantCount).toBe(2); expect(page2.descendantCount).toBe(1); expect(page3.descendantCount).toBe(0); }); test('it should fail and throw error if PageOperation is not found', async() => { const pageId = new mongoose.Types.ObjectId(); // not exist in DB await expect(resumePageRenameOperation(pageId)) .rejects.toThrow(new Error('it did not restart rename operation because page operation to be processed was not found')); }); test('it should fail and throw error if the current time is behind unprocessableExpiryDate', async() => { const _path0 = '/POP1'; const _path1 = '/POP1/renamePOP4'; // renamed already const _path2 = '/renamePOP4/renamePOP5'; // not renamed yet const _page0 = await Page.findOne({ path: _path0 }); const _page1 = await Page.findOne({ path: _path1 }); const _page2 = await Page.findOne({ path: _path2 }); const _pageOperation = await PageOperation.findOne({ 'page._id': _page1._id, actionType: PageActionType.Rename }); expect(_page0).toBeTruthy(); expect(_page1).toBeTruthy(); expect(_page2).toBeTruthy(); expect(_pageOperation).toBeTruthy(); const promise = resumePageRenameOperation(_pageOperation.page._id); await expect(promise).rejects.toThrow(new Error('it did not restart rename operation because it is currently being processed')); }); }); });