AddUserToSharedVault.spec.ts 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. import { TimerInterface } from '@standardnotes/time'
  2. import { NotificationPayload, Result, SharedVaultUser } from '@standardnotes/domain-core'
  3. import { DomainEventInterface, DomainEventPublisherInterface } from '@standardnotes/domain-events'
  4. import { SharedVaultRepositoryInterface } from '../../../SharedVault/SharedVaultRepositoryInterface'
  5. import { SharedVaultUserRepositoryInterface } from '../../../SharedVault/User/SharedVaultUserRepositoryInterface'
  6. import { AddUserToSharedVault } from './AddUserToSharedVault'
  7. import { SharedVault } from '../../../SharedVault/SharedVault'
  8. import { DomainEventFactoryInterface } from '../../../Event/DomainEventFactoryInterface'
  9. import { AddNotificationsForUsers } from '../../Messaging/AddNotificationsForUsers/AddNotificationsForUsers'
  10. describe('AddUserToSharedVault', () => {
  11. let sharedVaultRepository: SharedVaultRepositoryInterface
  12. let sharedVaultUserRepository: SharedVaultUserRepositoryInterface
  13. let timer: TimerInterface
  14. let sharedVault: SharedVault
  15. let domainEventFactory: DomainEventFactoryInterface
  16. let domainEventPublisher: DomainEventPublisherInterface
  17. let addNotificationsForUsers: AddNotificationsForUsers
  18. const validUuid = '00000000-0000-0000-0000-000000000000'
  19. const createUseCase = () =>
  20. new AddUserToSharedVault(
  21. sharedVaultRepository,
  22. sharedVaultUserRepository,
  23. timer,
  24. domainEventFactory,
  25. domainEventPublisher,
  26. addNotificationsForUsers,
  27. )
  28. beforeEach(() => {
  29. sharedVault = {} as jest.Mocked<SharedVault>
  30. sharedVaultRepository = {} as jest.Mocked<SharedVaultRepositoryInterface>
  31. sharedVaultRepository.findByUuid = jest.fn().mockResolvedValue(sharedVault)
  32. sharedVaultUserRepository = {} as jest.Mocked<SharedVaultUserRepositoryInterface>
  33. sharedVaultUserRepository.save = jest.fn()
  34. timer = {} as jest.Mocked<TimerInterface>
  35. timer.getTimestampInMicroseconds = jest.fn().mockReturnValue(123456789)
  36. domainEventFactory = {} as jest.Mocked<DomainEventFactoryInterface>
  37. domainEventFactory.createUserAddedToSharedVaultEvent = jest
  38. .fn()
  39. .mockReturnValue({} as jest.Mocked<DomainEventInterface>)
  40. domainEventPublisher = {} as jest.Mocked<DomainEventPublisherInterface>
  41. domainEventPublisher.publish = jest.fn()
  42. addNotificationsForUsers = {} as jest.Mocked<AddNotificationsForUsers>
  43. addNotificationsForUsers.execute = jest.fn().mockReturnValue(Result.ok())
  44. })
  45. it('should return a failure result if the shared vault uuid is invalid', async () => {
  46. const useCase = createUseCase()
  47. const result = await useCase.execute({
  48. sharedVaultUuid: 'invalid-uuid',
  49. userUuid: validUuid,
  50. permission: 'read',
  51. })
  52. expect(result.isFailed()).toBe(true)
  53. expect(result.getError()).toBe('Given value is not a valid uuid: invalid-uuid')
  54. })
  55. it('should return a failure result if the user uuid is invalid', async () => {
  56. const useCase = createUseCase()
  57. const result = await useCase.execute({
  58. sharedVaultUuid: validUuid,
  59. userUuid: 'invalid-uuid',
  60. permission: 'read',
  61. })
  62. expect(result.isFailed()).toBe(true)
  63. expect(result.getError()).toBe('Given value is not a valid uuid: invalid-uuid')
  64. })
  65. it('should return a failure result if the permission is invalid', async () => {
  66. const useCase = createUseCase()
  67. const result = await useCase.execute({
  68. sharedVaultUuid: validUuid,
  69. userUuid: validUuid,
  70. permission: 'test',
  71. })
  72. expect(result.isFailed()).toBe(true)
  73. expect(result.getError()).toBe('Invalid shared vault user permission test')
  74. })
  75. it('should return a failure result if the shared vault does not exist', async () => {
  76. const useCase = createUseCase()
  77. sharedVaultRepository.findByUuid = jest.fn().mockResolvedValueOnce(null)
  78. const result = await useCase.execute({
  79. sharedVaultUuid: validUuid,
  80. userUuid: validUuid,
  81. permission: 'read',
  82. })
  83. expect(result.isFailed()).toBe(true)
  84. expect(result.getError()).toBe('Attempting to add a shared vault user to a non-existent shared vault')
  85. })
  86. it('should return a failure result if creating the shared vault user fails', async () => {
  87. const useCase = createUseCase()
  88. const mockSharedVaultUser = jest.spyOn(SharedVaultUser, 'create')
  89. mockSharedVaultUser.mockImplementation(() => {
  90. return Result.fail('Oops')
  91. })
  92. const result = await useCase.execute({
  93. sharedVaultUuid: validUuid,
  94. userUuid: validUuid,
  95. permission: 'read',
  96. })
  97. expect(result.isFailed()).toBe(true)
  98. expect(result.getError()).toBe('Oops')
  99. mockSharedVaultUser.mockRestore()
  100. })
  101. it('should return a failure if add notification for users fails', async () => {
  102. addNotificationsForUsers.execute = jest.fn().mockReturnValue(Result.fail('Oops'))
  103. const useCase = createUseCase()
  104. const result = await useCase.execute({
  105. sharedVaultUuid: validUuid,
  106. userUuid: validUuid,
  107. permission: 'read',
  108. })
  109. expect(result.isFailed()).toBe(true)
  110. expect(result.getError()).toBe('Oops')
  111. })
  112. it('should return error if notification payload could not be created', async () => {
  113. const mock = jest.spyOn(NotificationPayload, 'create')
  114. mock.mockReturnValue(Result.fail('Oops'))
  115. const useCase = createUseCase()
  116. const result = await useCase.execute({
  117. sharedVaultUuid: validUuid,
  118. userUuid: validUuid,
  119. permission: 'read',
  120. })
  121. expect(result.isFailed()).toBe(true)
  122. expect(result.getError()).toBe('Oops')
  123. mock.mockRestore()
  124. })
  125. it('should add a user to a shared vault', async () => {
  126. const useCase = createUseCase()
  127. const result = await useCase.execute({
  128. sharedVaultUuid: validUuid,
  129. userUuid: validUuid,
  130. permission: 'read',
  131. })
  132. expect(result.isFailed()).toBe(false)
  133. expect(sharedVaultUserRepository.save).toHaveBeenCalled()
  134. })
  135. it('should add a user to a shared vault and skip checking if shared vault exists to avoid race conditions', async () => {
  136. sharedVaultRepository.findByUuid = jest.fn().mockResolvedValueOnce(null)
  137. const useCase = createUseCase()
  138. const result = await useCase.execute({
  139. sharedVaultUuid: validUuid,
  140. userUuid: validUuid,
  141. permission: 'read',
  142. skipSharedVaultExistenceCheck: true,
  143. })
  144. expect(result.isFailed()).toBe(false)
  145. expect(sharedVaultUserRepository.save).toHaveBeenCalled()
  146. })
  147. })