|
| 1 | +import { v4 } from 'uuid'; |
| 2 | + |
| 3 | +import Etherpad, { AuthorSession } from '@graasp/etherpad-api'; |
| 4 | +import { EtherpadItemFactory, FolderItemFactory, ItemType, PermissionLevel } from '@graasp/sdk'; |
| 5 | + |
| 6 | +import { MOCK_LOGGER } from '../../../../../test/app'; |
| 7 | +import { resolveDependency } from '../../../../di/utils'; |
| 8 | +import * as repositoriesUtils from '../../../../utils/repositories'; |
| 9 | +import { ItemMembership } from '../../../itemMembership/entities/ItemMembership'; |
| 10 | +import { ItemMembershipRepository } from '../../../itemMembership/repository'; |
| 11 | +import { Member } from '../../../member/entities/member'; |
| 12 | +import { ThumbnailService } from '../../../thumbnail/service'; |
| 13 | +import { EtherpadItem } from '../../entities/Item'; |
| 14 | +import { WrongItemTypeError } from '../../errors'; |
| 15 | +import { ItemRepository } from '../../repository'; |
| 16 | +import { ItemService } from '../../service'; |
| 17 | +import { ItemThumbnailService } from '../thumbnail/service'; |
| 18 | +import { EtherpadItemService } from './service'; |
| 19 | +import { EtherpadServiceConfig } from './serviceConfig'; |
| 20 | +import { PadNameFactory } from './types'; |
| 21 | + |
| 22 | +jest.mock('node-fetch'); |
| 23 | + |
| 24 | +const padNameFactory = {} as PadNameFactory; |
| 25 | +const etherPadConfig = resolveDependency(EtherpadServiceConfig); |
| 26 | +const itemService = new ItemService( |
| 27 | + {} as ThumbnailService, |
| 28 | + {} as ItemThumbnailService, |
| 29 | + MOCK_LOGGER, |
| 30 | +); |
| 31 | +const etherpad = { |
| 32 | + getReadOnlyID: () => {}, |
| 33 | + createAuthorIfNotExistsFor: () => {}, |
| 34 | + createSession: () => {}, |
| 35 | + deleteSession: () => {}, |
| 36 | + listSessionsOfAuthor: () => {}, |
| 37 | +} as unknown as Etherpad; |
| 38 | + |
| 39 | +const etherpadService = new EtherpadItemService( |
| 40 | + etherpad, |
| 41 | + padNameFactory, |
| 42 | + etherPadConfig, |
| 43 | + itemService, |
| 44 | + MOCK_LOGGER, |
| 45 | +); |
| 46 | +const id = v4(); |
| 47 | +const MOCK_ITEM = EtherpadItemFactory({ |
| 48 | + id, |
| 49 | + extra: { etherpad: { readerPermission: undefined, padID: v4(), groupID: v4() } }, |
| 50 | +}) as unknown as EtherpadItem; |
| 51 | + |
| 52 | +const MOCK_MEMBER = {} as Member; |
| 53 | +const repositories = { |
| 54 | + itemRepository: { |
| 55 | + getOneOrThrow: async () => { |
| 56 | + return MOCK_ITEM; |
| 57 | + }, |
| 58 | + } as unknown as ItemRepository, |
| 59 | + itemMembershipRepository: { |
| 60 | + getOneOrThrow: async () => { |
| 61 | + return MOCK_ITEM; |
| 62 | + }, |
| 63 | + getInherited: async () => { |
| 64 | + return {}; |
| 65 | + }, |
| 66 | + } as unknown as ItemMembershipRepository, |
| 67 | +} as repositoriesUtils.Repositories; |
| 68 | + |
| 69 | +describe('Etherpad Service', () => { |
| 70 | + afterEach(() => { |
| 71 | + jest.clearAllMocks(); |
| 72 | + }); |
| 73 | + |
| 74 | + describe('patchWithOptions', () => { |
| 75 | + it('throw if item is not an etherpad', async () => { |
| 76 | + const FOLDER_ITEM = FolderItemFactory(); |
| 77 | + await expect(() => |
| 78 | + etherpadService.patchWithOptions( |
| 79 | + MOCK_MEMBER, |
| 80 | + { |
| 81 | + itemRepository: { |
| 82 | + getOneOrThrow: async () => { |
| 83 | + return FOLDER_ITEM; |
| 84 | + }, |
| 85 | + } as unknown as ItemRepository, |
| 86 | + } as repositoriesUtils.Repositories, |
| 87 | + FOLDER_ITEM.id, |
| 88 | + { readerPermission: PermissionLevel.Write }, |
| 89 | + ), |
| 90 | + ).rejects.toBeInstanceOf(WrongItemTypeError); |
| 91 | + }); |
| 92 | + it('patch readerPermission', async () => { |
| 93 | + const itemServicePatchMock = jest |
| 94 | + .spyOn(ItemService.prototype, 'patch') |
| 95 | + .mockImplementation(async () => { |
| 96 | + return MOCK_ITEM; |
| 97 | + }); |
| 98 | + |
| 99 | + expect(MOCK_ITEM.extra.etherpad.readerPermission).toBeUndefined(); |
| 100 | + |
| 101 | + const readerPermission = PermissionLevel.Write; |
| 102 | + await etherpadService.patchWithOptions(MOCK_MEMBER, repositories, MOCK_ITEM.id, { |
| 103 | + readerPermission, |
| 104 | + }); |
| 105 | + |
| 106 | + // call to item service with initial item name |
| 107 | + expect(itemServicePatchMock).toHaveBeenCalledWith(MOCK_MEMBER, repositories, MOCK_ITEM.id, { |
| 108 | + extra: { |
| 109 | + [ItemType.ETHERPAD]: { |
| 110 | + readerPermission: PermissionLevel.Write, |
| 111 | + }, |
| 112 | + }, |
| 113 | + }); |
| 114 | + }); |
| 115 | + |
| 116 | + it('Cannot update not found item given id', async () => { |
| 117 | + jest.spyOn(repositories.itemRepository, 'getOneOrThrow').mockImplementation(() => { |
| 118 | + throw new Error(); |
| 119 | + }); |
| 120 | + |
| 121 | + await expect(() => |
| 122 | + etherpadService.patchWithOptions(MOCK_MEMBER, repositories, v4(), { |
| 123 | + readerPermission: PermissionLevel.Write, |
| 124 | + }), |
| 125 | + ).rejects.toThrow(); |
| 126 | + }); |
| 127 | + }); |
| 128 | + describe('getEtherpadFromItem', () => { |
| 129 | + beforeEach(() => { |
| 130 | + jest.spyOn(repositoriesUtils, 'buildRepositories').mockReturnValue(repositories); |
| 131 | + jest.spyOn(etherpad, 'createAuthorIfNotExistsFor').mockResolvedValue({ authorID: v4() }); |
| 132 | + jest.spyOn(etherpad, 'createSession').mockResolvedValue({ sessionID: v4() }); |
| 133 | + jest.spyOn(etherpad, 'deleteSession').mockResolvedValue(null); |
| 134 | + jest |
| 135 | + .spyOn(etherpad, 'listSessionsOfAuthor') |
| 136 | + .mockResolvedValue({ id: { validUntil: 1 } as AuthorSession }); |
| 137 | + }); |
| 138 | + |
| 139 | + it('return write for reader with write permission', async () => { |
| 140 | + // readerPermission is write |
| 141 | + jest.spyOn(itemService, 'get').mockResolvedValue( |
| 142 | + EtherpadItemFactory({ |
| 143 | + extra: { |
| 144 | + etherpad: { padID: v4(), groupID: v4(), readerPermission: PermissionLevel.Write }, |
| 145 | + }, |
| 146 | + }) as unknown as EtherpadItem, |
| 147 | + ); |
| 148 | + |
| 149 | + // actor has read permission |
| 150 | + jest |
| 151 | + .spyOn(repositories.itemMembershipRepository, 'getInherited') |
| 152 | + .mockResolvedValue({ permission: PermissionLevel.Read } as unknown as ItemMembership); |
| 153 | + const getReadOnlyIDMock = jest.spyOn(etherpad, 'getReadOnlyID'); |
| 154 | + |
| 155 | + // actor require write |
| 156 | + await etherpadService.getEtherpadFromItem(MOCK_MEMBER, MOCK_ITEM.id, 'write'); |
| 157 | + |
| 158 | + // this is called only if returned mode is read, which shouldn't be the case here |
| 159 | + expect(getReadOnlyIDMock).not.toHaveBeenCalled(); |
| 160 | + }); |
| 161 | + it('return read for reader with no permission even if asked for write', async () => { |
| 162 | + // readerPermission is read |
| 163 | + jest.spyOn(itemService, 'get').mockResolvedValue( |
| 164 | + EtherpadItemFactory({ |
| 165 | + extra: { |
| 166 | + etherpad: { padID: v4(), groupID: v4(), readerPermission: PermissionLevel.Read }, |
| 167 | + }, |
| 168 | + }) as unknown as EtherpadItem, |
| 169 | + ); |
| 170 | + |
| 171 | + // permission is read |
| 172 | + jest |
| 173 | + .spyOn(repositories.itemMembershipRepository, 'getInherited') |
| 174 | + .mockResolvedValue({ permission: PermissionLevel.Read } as unknown as ItemMembership); |
| 175 | + const getReadOnlyIDMock = jest |
| 176 | + .spyOn(etherpad, 'getReadOnlyID') |
| 177 | + .mockResolvedValue({ readOnlyID: v4() }); |
| 178 | + |
| 179 | + // request write |
| 180 | + await etherpadService.getEtherpadFromItem(MOCK_MEMBER, MOCK_ITEM.id, 'write'); |
| 181 | + |
| 182 | + // this is called only if returned mode is read, which is the case here |
| 183 | + expect(getReadOnlyIDMock).toHaveBeenCalled(); |
| 184 | + }); |
| 185 | + }); |
| 186 | +}); |
0 commit comments