InversifyExpressItemsController.spec.ts 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. import 'reflect-metadata'
  2. import * as express from 'express'
  3. import { ContentType } from '@standardnotes/common'
  4. import { InversifyExpressItemsController } from './InversifyExpressItemsController'
  5. import { results } from 'inversify-express-utils'
  6. import { Item } from '../../Domain/Item/Item'
  7. import { ItemProjection } from '../../Projection/ItemProjection'
  8. import { ProjectorInterface } from '../../Projection/ProjectorInterface'
  9. import { ApiVersion } from '../../Domain/Api/ApiVersion'
  10. import { SyncResponse20200115 } from '../../Domain/Item/SyncResponse/SyncResponse20200115'
  11. import { SyncResponseFactoryInterface } from '../../Domain/Item/SyncResponse/SyncResponseFactoryInterface'
  12. import { SyncResponseFactoryResolverInterface } from '../../Domain/Item/SyncResponse/SyncResponseFactoryResolverInterface'
  13. import { CheckIntegrity } from '../../Domain/UseCase/Syncing/CheckIntegrity/CheckIntegrity'
  14. import { GetItem } from '../../Domain/UseCase/Syncing/GetItem/GetItem'
  15. import { SyncItems } from '../../Domain/UseCase/Syncing/SyncItems/SyncItems'
  16. describe('InversifyExpressItemsController', () => {
  17. let syncItems: SyncItems
  18. let checkIntegrity: CheckIntegrity
  19. let getItem: GetItem
  20. let itemProjector: ProjectorInterface<Item, ItemProjection>
  21. let request: express.Request
  22. let response: express.Response
  23. let syncResponceFactoryResolver: SyncResponseFactoryResolverInterface
  24. let syncResponseFactory: SyncResponseFactoryInterface
  25. let syncResponse: SyncResponse20200115
  26. const createController = () =>
  27. new InversifyExpressItemsController(syncItems, checkIntegrity, getItem, itemProjector, syncResponceFactoryResolver)
  28. beforeEach(() => {
  29. itemProjector = {} as jest.Mocked<ProjectorInterface<Item, ItemProjection>>
  30. itemProjector.projectFull = jest.fn().mockReturnValue({ foo: 'bar' })
  31. syncItems = {} as jest.Mocked<SyncItems>
  32. syncItems.execute = jest.fn().mockReturnValue({ foo: 'bar' })
  33. checkIntegrity = {} as jest.Mocked<CheckIntegrity>
  34. checkIntegrity.execute = jest.fn().mockReturnValue({ mismatches: [{ uuid: '1-2-3', updated_at_timestamp: 2 }] })
  35. getItem = {} as jest.Mocked<GetItem>
  36. getItem.execute = jest.fn().mockReturnValue({ success: true, item: {} as jest.Mocked<Item> })
  37. request = {
  38. headers: {},
  39. body: {},
  40. params: {},
  41. } as jest.Mocked<express.Request>
  42. request.body.api = ApiVersion.v20200115
  43. request.body.sync_token = 'MjoxNjE3MTk1MzQyLjc1ODEyMTc='
  44. request.body.limit = 150
  45. request.body.compute_integrity = false
  46. request.headers['user-agent'] = 'Google Chrome'
  47. request.body.items = [
  48. {
  49. content: 'test',
  50. content_type: ContentType.Note,
  51. created_at: '2021-02-19T11:35:45.655Z',
  52. deleted: false,
  53. duplicate_of: null,
  54. enc_item_key: 'test',
  55. items_key_id: 'test',
  56. updated_at: '2021-02-19T11:35:45.655Z',
  57. uuid: '1-2-3',
  58. },
  59. ]
  60. response = {
  61. locals: {},
  62. } as jest.Mocked<express.Response>
  63. response.locals.user = {
  64. uuid: '123',
  65. }
  66. response.locals.freeUser = false
  67. syncResponse = {} as jest.Mocked<SyncResponse20200115>
  68. syncResponseFactory = {} as jest.Mocked<SyncResponseFactoryInterface>
  69. syncResponseFactory.createResponse = jest.fn().mockReturnValue(syncResponse)
  70. syncResponceFactoryResolver = {} as jest.Mocked<SyncResponseFactoryResolverInterface>
  71. syncResponceFactoryResolver.resolveSyncResponseFactoryVersion = jest.fn().mockReturnValue(syncResponseFactory)
  72. })
  73. it('should get a single item', async () => {
  74. request.params.uuid = '1-2-3'
  75. const httpResponse = <results.JsonResult>await createController().getSingleItem(request, response)
  76. const result = await httpResponse.executeAsync()
  77. expect(getItem.execute).toHaveBeenCalledWith({
  78. itemUuid: '1-2-3',
  79. userUuid: '123',
  80. })
  81. expect(result.statusCode).toEqual(200)
  82. })
  83. it('should return 404 on a missing single item', async () => {
  84. request.params.uuid = '1-2-3'
  85. getItem.execute = jest.fn().mockReturnValue({ success: false })
  86. const httpResponse = <results.NotFoundResult>await createController().getSingleItem(request, response)
  87. const result = await httpResponse.executeAsync()
  88. expect(getItem.execute).toHaveBeenCalledWith({
  89. itemUuid: '1-2-3',
  90. userUuid: '123',
  91. })
  92. expect(result.statusCode).toEqual(404)
  93. })
  94. it('should check items integrity', async () => {
  95. request.body.integrityPayloads = [
  96. {
  97. uuid: '1-2-3',
  98. updated_at_timestamp: 1,
  99. },
  100. ]
  101. const httpResponse = <results.JsonResult>await createController().checkItemsIntegrity(request, response)
  102. const result = await httpResponse.executeAsync()
  103. expect(checkIntegrity.execute).toHaveBeenCalledWith({
  104. integrityPayloads: [
  105. {
  106. updated_at_timestamp: 1,
  107. uuid: '1-2-3',
  108. },
  109. ],
  110. userUuid: '123',
  111. freeUser: false,
  112. })
  113. expect(result.statusCode).toEqual(200)
  114. expect(await result.content.readAsStringAsync()).toEqual(
  115. '{"mismatches":[{"uuid":"1-2-3","updated_at_timestamp":2}]}',
  116. )
  117. })
  118. it('should check items integrity with missing request parameter', async () => {
  119. const httpResponse = <results.JsonResult>await createController().checkItemsIntegrity(request, response)
  120. const result = await httpResponse.executeAsync()
  121. expect(checkIntegrity.execute).toHaveBeenCalledWith({
  122. integrityPayloads: [],
  123. userUuid: '123',
  124. freeUser: false,
  125. })
  126. expect(result.statusCode).toEqual(200)
  127. expect(await result.content.readAsStringAsync()).toEqual(
  128. '{"mismatches":[{"uuid":"1-2-3","updated_at_timestamp":2}]}',
  129. )
  130. })
  131. it('should sync items', async () => {
  132. const httpResponse = <results.JsonResult>await createController().sync(request, response)
  133. const result = await httpResponse.executeAsync()
  134. expect(syncItems.execute).toHaveBeenCalledWith({
  135. apiVersion: '20200115',
  136. computeIntegrityHash: false,
  137. itemHashes: [
  138. {
  139. content: 'test',
  140. content_type: 'Note',
  141. created_at: '2021-02-19T11:35:45.655Z',
  142. deleted: false,
  143. duplicate_of: null,
  144. enc_item_key: 'test',
  145. items_key_id: 'test',
  146. updated_at: '2021-02-19T11:35:45.655Z',
  147. uuid: '1-2-3',
  148. },
  149. ],
  150. limit: 150,
  151. syncToken: 'MjoxNjE3MTk1MzQyLjc1ODEyMTc=',
  152. userUuid: '123',
  153. sessionUuid: null,
  154. })
  155. expect(result.statusCode).toEqual(200)
  156. })
  157. it('should sync items with defaulting API version if none specified', async () => {
  158. delete request.body.api
  159. const httpResponse = <results.JsonResult>await createController().sync(request, response)
  160. const result = await httpResponse.executeAsync()
  161. expect(syncItems.execute).toHaveBeenCalledWith({
  162. apiVersion: '20161215',
  163. computeIntegrityHash: false,
  164. itemHashes: [
  165. {
  166. content: 'test',
  167. content_type: 'Note',
  168. created_at: '2021-02-19T11:35:45.655Z',
  169. deleted: false,
  170. duplicate_of: null,
  171. enc_item_key: 'test',
  172. items_key_id: 'test',
  173. updated_at: '2021-02-19T11:35:45.655Z',
  174. uuid: '1-2-3',
  175. },
  176. ],
  177. limit: 150,
  178. syncToken: 'MjoxNjE3MTk1MzQyLjc1ODEyMTc=',
  179. userUuid: '123',
  180. sessionUuid: null,
  181. })
  182. expect(result.statusCode).toEqual(200)
  183. })
  184. it('should sync items with no incoming items in request', async () => {
  185. response.locals.session = { uuid: '2-3-4' }
  186. delete request.body.items
  187. const httpResponse = <results.JsonResult>await createController().sync(request, response)
  188. const result = await httpResponse.executeAsync()
  189. expect(syncItems.execute).toHaveBeenCalledWith({
  190. apiVersion: '20200115',
  191. computeIntegrityHash: false,
  192. itemHashes: [],
  193. limit: 150,
  194. syncToken: 'MjoxNjE3MTk1MzQyLjc1ODEyMTc=',
  195. userUuid: '123',
  196. sessionUuid: '2-3-4',
  197. })
  198. expect(result.statusCode).toEqual(200)
  199. })
  200. })