UpdateExistingItem.spec.ts 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  1. import { DomainEventInterface, DomainEventPublisherInterface } from '@standardnotes/domain-events'
  2. import { Timer, TimerInterface } from '@standardnotes/time'
  3. import { DomainEventFactoryInterface } from '../../../Event/DomainEventFactoryInterface'
  4. import { Item } from '../../../Item/Item'
  5. import { ItemHash } from '../../../Item/ItemHash'
  6. import { ItemRepositoryInterface } from '../../../Item/ItemRepositoryInterface'
  7. import { UpdateExistingItem } from './UpdateExistingItem'
  8. import { Uuid, ContentType, Dates, Timestamps, UniqueEntityId, Result } from '@standardnotes/domain-core'
  9. describe('UpdateExistingItem', () => {
  10. let itemRepository: ItemRepositoryInterface
  11. let timer: TimerInterface
  12. let domainEventPublisher: DomainEventPublisherInterface
  13. let domainEventFactory: DomainEventFactoryInterface
  14. let itemHash1: ItemHash
  15. let item1: Item
  16. const createUseCase = () => new UpdateExistingItem(itemRepository, timer, domainEventPublisher, domainEventFactory, 5)
  17. beforeEach(() => {
  18. const timeHelper = new Timer()
  19. item1 = Item.create(
  20. {
  21. userUuid: Uuid.create('00000000-0000-0000-0000-000000000000').getValue(),
  22. updatedWithSession: null,
  23. content: 'foobar',
  24. contentType: ContentType.create(ContentType.TYPES.Note).getValue(),
  25. encItemKey: null,
  26. authHash: null,
  27. itemsKeyId: null,
  28. duplicateOf: null,
  29. deleted: false,
  30. dates: Dates.create(new Date(1616164633241311), new Date(1616164633241311)).getValue(),
  31. timestamps: Timestamps.create(1616164633241311, 1616164633241311).getValue(),
  32. },
  33. new UniqueEntityId('00000000-0000-0000-0000-000000000000'),
  34. ).getValue()
  35. itemHash1 = {
  36. uuid: '1-2-3',
  37. content: 'asdqwe1',
  38. content_type: ContentType.TYPES.Note,
  39. duplicate_of: null,
  40. enc_item_key: 'qweqwe1',
  41. auth_hash: 'auth_hash',
  42. items_key_id: 'asdasd1',
  43. created_at: timeHelper.formatDate(
  44. timeHelper.convertMicrosecondsToDate(item1.props.timestamps.createdAt),
  45. 'YYYY-MM-DDTHH:mm:ss.SSS[Z]',
  46. ),
  47. updated_at: timeHelper.formatDate(
  48. new Date(timeHelper.convertMicrosecondsToMilliseconds(item1.props.timestamps.updatedAt) + 1),
  49. 'YYYY-MM-DDTHH:mm:ss.SSS[Z]',
  50. ),
  51. } as jest.Mocked<ItemHash>
  52. itemRepository = {} as jest.Mocked<ItemRepositoryInterface>
  53. itemRepository.save = jest.fn()
  54. timer = {} as jest.Mocked<TimerInterface>
  55. timer.getTimestampInMicroseconds = jest.fn().mockReturnValue(123456789)
  56. timer.convertMicrosecondsToDate = jest.fn().mockReturnValue(new Date(123456789))
  57. timer.convertStringDateToMicroseconds = jest.fn().mockReturnValue(123456789)
  58. timer.convertMicrosecondsToSeconds = jest.fn().mockReturnValue(123456789)
  59. timer.convertStringDateToDate = jest.fn().mockReturnValue(new Date(123456789))
  60. domainEventPublisher = {} as jest.Mocked<DomainEventPublisherInterface>
  61. domainEventPublisher.publish = jest.fn()
  62. domainEventFactory = {} as jest.Mocked<DomainEventFactoryInterface>
  63. domainEventFactory.createDuplicateItemSyncedEvent = jest
  64. .fn()
  65. .mockReturnValue({} as jest.Mocked<DomainEventInterface>)
  66. domainEventFactory.createItemRevisionCreationRequested = jest
  67. .fn()
  68. .mockReturnValue({} as jest.Mocked<DomainEventInterface>)
  69. })
  70. it('should update item', async () => {
  71. const useCase = createUseCase()
  72. const result = await useCase.execute({
  73. existingItem: item1,
  74. itemHash: itemHash1,
  75. sessionUuid: '00000000-0000-0000-0000-000000000000',
  76. })
  77. expect(result.isFailed()).toBeFalsy()
  78. expect(itemRepository.save).toHaveBeenCalled()
  79. })
  80. it('should return error if session uuid is invalid', async () => {
  81. const useCase = createUseCase()
  82. const result = await useCase.execute({
  83. existingItem: item1,
  84. itemHash: itemHash1,
  85. sessionUuid: 'invalid-uuid',
  86. })
  87. expect(result.isFailed()).toBeTruthy()
  88. })
  89. it('should return error if content type is invalid', async () => {
  90. const useCase = createUseCase()
  91. const result = await useCase.execute({
  92. existingItem: item1,
  93. itemHash: {
  94. ...itemHash1,
  95. content_type: 'invalid',
  96. },
  97. sessionUuid: '00000000-0000-0000-0000-000000000000',
  98. })
  99. expect(result.isFailed()).toBeTruthy()
  100. })
  101. it('should mark item as deleted if item hash is deleted', async () => {
  102. const useCase = createUseCase()
  103. const result = await useCase.execute({
  104. existingItem: item1,
  105. itemHash: {
  106. ...itemHash1,
  107. deleted: true,
  108. },
  109. sessionUuid: '00000000-0000-0000-0000-000000000000',
  110. })
  111. expect(result.isFailed()).toBeFalsy()
  112. expect(itemRepository.save).toHaveBeenCalled()
  113. expect(item1.props.deleted).toBeTruthy()
  114. expect(item1.props.content).toBeNull()
  115. expect(item1.props.encItemKey).toBeNull()
  116. expect(item1.props.authHash).toBeNull()
  117. expect(item1.props.itemsKeyId).toBeNull()
  118. expect(item1.props.duplicateOf).toBeNull()
  119. })
  120. it('should mark item as duplicate if item hash has duplicate_of', async () => {
  121. const useCase = createUseCase()
  122. const result = await useCase.execute({
  123. existingItem: item1,
  124. itemHash: {
  125. ...itemHash1,
  126. duplicate_of: '00000000-0000-0000-0000-000000000001',
  127. },
  128. sessionUuid: '00000000-0000-0000-0000-000000000000',
  129. })
  130. expect(result.isFailed()).toBeFalsy()
  131. expect(itemRepository.save).toHaveBeenCalled()
  132. expect(item1.props.duplicateOf?.value).toBe('00000000-0000-0000-0000-000000000001')
  133. })
  134. it('shuld return error if duplicate uuid is invalid', async () => {
  135. const useCase = createUseCase()
  136. const result = await useCase.execute({
  137. existingItem: item1,
  138. itemHash: {
  139. ...itemHash1,
  140. duplicate_of: 'invalid-uuid',
  141. },
  142. sessionUuid: '00000000-0000-0000-0000-000000000000',
  143. })
  144. expect(result.isFailed()).toBeTruthy()
  145. })
  146. it('should update item with update timestamps', async () => {
  147. const useCase = createUseCase()
  148. const result = await useCase.execute({
  149. existingItem: item1,
  150. itemHash: {
  151. ...itemHash1,
  152. updated_at_timestamp: 123,
  153. created_at_timestamp: 123,
  154. },
  155. sessionUuid: '00000000-0000-0000-0000-000000000000',
  156. })
  157. expect(result.isFailed()).toBeFalsy()
  158. expect(itemRepository.save).toHaveBeenCalled()
  159. })
  160. it('should return error if created at time is not give in any form', async () => {
  161. const useCase = createUseCase()
  162. const result = await useCase.execute({
  163. existingItem: item1,
  164. itemHash: {
  165. ...itemHash1,
  166. created_at: undefined,
  167. created_at_timestamp: undefined,
  168. },
  169. sessionUuid: '00000000-0000-0000-0000-000000000000',
  170. })
  171. expect(result.isFailed()).toBeTruthy()
  172. })
  173. it('should return error if dates could not be created from timestamps', async () => {
  174. const mock = jest.spyOn(Dates, 'create')
  175. mock.mockImplementation(() => {
  176. return Result.fail('Oops')
  177. })
  178. const useCase = createUseCase()
  179. const result = await useCase.execute({
  180. existingItem: item1,
  181. itemHash: {
  182. ...itemHash1,
  183. created_at_timestamp: 123,
  184. updated_at_timestamp: 123,
  185. },
  186. sessionUuid: '00000000-0000-0000-0000-000000000000',
  187. })
  188. expect(result.isFailed()).toBeTruthy()
  189. mock.mockRestore()
  190. })
  191. it('should return error if timestamps could not be created from timestamps', async () => {
  192. const mock = jest.spyOn(Timestamps, 'create')
  193. mock.mockImplementation(() => {
  194. return Result.fail('Oops')
  195. })
  196. const useCase = createUseCase()
  197. const result = await useCase.execute({
  198. existingItem: item1,
  199. itemHash: {
  200. ...itemHash1,
  201. created_at_timestamp: 123,
  202. updated_at_timestamp: 123,
  203. },
  204. sessionUuid: '00000000-0000-0000-0000-000000000000',
  205. })
  206. expect(result.isFailed()).toBeTruthy()
  207. mock.mockRestore()
  208. })
  209. })