entityManager.test.ts 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842
  1. import { describe, test, it, expect } from 'vitest'
  2. import EntityManager from "~/services/data/entityManager";
  3. import ApiResource from "~/models/ApiResource";
  4. import ApiModel from "~/models/ApiModel";
  5. import ApiRequestService from "~/services/data/apiRequestService";
  6. import {Element, Repository} from "pinia-orm";
  7. import {ApiResponse} from "~/types/data";
  8. import HydraDenormalizer from "~/services/data/normalizer/hydraDenormalizer";
  9. class TestableEntityManager extends EntityManager {
  10. public cast(model: typeof ApiResource, entity: ApiResource): ApiResource { return super.cast(model, entity) }
  11. public async saveResponseAsEntity(model: typeof ApiModel, response: Response) { return super.saveResponseAsEntity(model, response) }
  12. public saveInitialState(model: typeof ApiResource, entity: ApiResource) { return super.saveInitialState(model, entity) }
  13. public getInitialStateOf(model: typeof ApiResource, id: string | number): ApiResource | null { return super.getInitialStateOf(model, id) }
  14. public removeTempAfterPersist(model: typeof ApiResource, tempEntityId: number | string) { return super.removeTempAfterPersist(model, tempEntityId) }
  15. }
  16. class DummyApiResource extends ApiResource {
  17. static entity = 'dummyResource'
  18. }
  19. class DummyApiModel extends ApiModel {
  20. static entity = 'dummyModel'
  21. }
  22. let apiRequestService: ApiRequestService
  23. let entityManager: TestableEntityManager
  24. beforeEach(() => {
  25. // @ts-ignore
  26. apiRequestService = vi.fn() as ApiRequestService
  27. entityManager = new TestableEntityManager(apiRequestService)
  28. // TODO: s'assurer que les mocks globaux sont bien réinitialisés après les tests, en particulier les fonctions de console
  29. })
  30. describe('getRepository', () => {
  31. // TODO: à revoir
  32. })
  33. describe('cast', () => {
  34. test('simple cast', () => {
  35. // @ts-ignore
  36. const result = entityManager.cast(DummyApiResource, { id: 1 })
  37. expect(result instanceof DummyApiResource).toEqual(true)
  38. })
  39. })
  40. describe('getModelFor', () => {
  41. // TODO: à revoir
  42. })
  43. describe('getModelFromIri', () => {
  44. test('simple call', () => {
  45. // @ts-ignore
  46. entityManager.getModelFor = vi.fn((entityName: string) => entityName === 'dummy' ? DummyApiResource : null)
  47. // @ts-ignore
  48. const result = entityManager.getModelFromIri('/api/dummy/123')
  49. expect(result).toEqual(DummyApiResource)
  50. })
  51. test('invalide Iri', () => {
  52. expect(() => entityManager.getModelFromIri('/invalid')).toThrowError('cannot parse the IRI')
  53. })
  54. })
  55. describe('newInstance', () => {
  56. test('simple call', () => {
  57. const properties = { 'id': 1 }
  58. // @ts-ignore
  59. const repo = vi.fn() as Repository<ApiResource>
  60. // @ts-ignore
  61. entityManager.getRepository = vi.fn((model: typeof ApiResource) => {
  62. return model === DummyApiResource ? repo : null
  63. })
  64. entityManager.saveInitialState = vi.fn((model: typeof ApiResource, entity: ApiResource) => null)
  65. // @ts-ignore
  66. const entity = new DummyApiResource(properties)
  67. entity.setModel = vi.fn((model: typeof ApiResource) => null)
  68. // @ts-ignore
  69. repo.make = vi.fn((properties: object) => {
  70. // @ts-ignore
  71. entity.id = properties.id
  72. return entity
  73. })
  74. // @ts-ignore
  75. repo.save = vi.fn((record: Element) => entity)
  76. const result = entityManager.newInstance(DummyApiResource, properties)
  77. expect(repo.make).toHaveBeenCalledWith(properties)
  78. expect(entity.setModel).toHaveBeenCalledWith(DummyApiResource)
  79. expect(repo.save).toHaveBeenCalledWith(entity)
  80. expect(entityManager.saveInitialState).toHaveBeenCalledWith(DummyApiResource, entity)
  81. expect(result.id).toEqual(properties.id)
  82. })
  83. test('with no id provided', () => {
  84. const properties = { 'name': 'bob' }
  85. // @ts-ignore
  86. const repo = vi.fn() as Repository<ApiResource>
  87. // @ts-ignore
  88. entityManager.getRepository = vi.fn((model: typeof ApiResource) => {
  89. return model === DummyApiResource ? repo : null
  90. })
  91. entityManager.saveInitialState = vi.fn((model: typeof ApiResource, entity: ApiResource) => null)
  92. // @ts-ignore
  93. const entity = new DummyApiResource(properties)
  94. entity.setModel = vi.fn((model: typeof ApiResource) => null)
  95. // @ts-ignore
  96. repo.make = vi.fn((properties: object) => {
  97. // @ts-ignore
  98. entity.name = properties.name
  99. return entity
  100. })
  101. // @ts-ignore
  102. repo.save = vi.fn((record: Element) => entity)
  103. const result = entityManager.newInstance(DummyApiResource, properties)
  104. expect(
  105. result.id,
  106. 'id is \'tmp\' followed by a valid uuid-V4'
  107. ).toMatch(/tmp[0-9a-f]{8}-[0-9a-f]{4}-[0-5][0-9a-f]{3}-[089ab][0-9a-f]{3}-[0-9a-f]{12}/)
  108. expect(result.name).toEqual(properties.name)
  109. })
  110. })
  111. describe('save', () => {
  112. test('simple call', () => {
  113. // @ts-ignore
  114. const repo = vi.fn() as Repository<ApiResource>
  115. // @ts-ignore
  116. entityManager.getRepository = vi.fn((model: typeof ApiResource) => {
  117. return model === DummyApiResource ? repo : null
  118. })
  119. // @ts-ignore
  120. repo.save = vi.fn((record: Element) => entity)
  121. const entity = new DummyApiResource()
  122. entityManager.save(DummyApiResource, entity)
  123. expect(repo.save).toHaveBeenCalledWith(entity)
  124. })
  125. })
  126. describe('find', () => {
  127. test('simple call', () => {
  128. // @ts-ignore
  129. const repo = vi.fn() as Repository<ApiResource>
  130. // @ts-ignore
  131. entityManager.getRepository = vi.fn((model: typeof ApiResource) => {
  132. return model === DummyApiResource ? repo : null
  133. })
  134. const entity = new DummyApiResource({ id: 1 })
  135. // @ts-ignore
  136. repo.find = vi.fn((id: string | number) => entity)
  137. entityManager.find(DummyApiResource, 1)
  138. expect(entityManager.getRepository).toHaveBeenCalledWith(DummyApiResource)
  139. expect(repo.find).toHaveBeenCalledWith(1)
  140. })
  141. })
  142. describe('fetch', () => {
  143. test('not in store, no force refresh', async () => {
  144. const properties = { id: 1 }
  145. const entity = new DummyApiResource({ id: 1 })
  146. // @ts-ignore
  147. entityManager.find = vi.fn((model: typeof ApiResource, id: number) => undefined)
  148. // @ts-ignore
  149. apiRequestService.get = vi.fn(async (url: string) => properties)
  150. // @ts-ignore
  151. entityManager.newInstance = vi.fn((model: typeof ApiResource, props: object) => entity)
  152. const result = await entityManager.fetch(DummyApiResource, 1)
  153. expect(entityManager.find).toHaveBeenCalledWith(DummyApiResource, 1)
  154. expect(apiRequestService.get).toHaveBeenCalledWith('api/dummyResource/1')
  155. expect(entityManager.newInstance).toHaveBeenCalledWith(DummyApiResource, properties)
  156. expect(result).toEqual(entity)
  157. })
  158. test('in store, no force refresh', async () => {
  159. const properties = { id: 1 }
  160. const entity = new DummyApiResource({ id: 1 })
  161. // @ts-ignore
  162. entityManager.find = vi.fn((model: typeof ApiResource, id: number) => entity)
  163. const result = await entityManager.fetch(DummyApiResource, 1)
  164. expect(entityManager.find).toHaveBeenCalledWith(DummyApiResource, 1)
  165. expect(result).toEqual(entity)
  166. })
  167. test('in store, but with force refresh', async () => {
  168. const properties = { id: 1 }
  169. const entity = new DummyApiResource({ id: 1 })
  170. // @ts-ignore
  171. entityManager.find = vi.fn((model: typeof ApiResource, id: number) => undefined)
  172. // @ts-ignore
  173. apiRequestService.get = vi.fn(async (url: string) => properties)
  174. // @ts-ignore
  175. entityManager.newInstance = vi.fn((model: typeof ApiResource, props: object) => entity)
  176. const result = await entityManager.fetch(DummyApiResource, 1, true)
  177. expect(entityManager.find).toHaveBeenCalledTimes(0)
  178. expect(apiRequestService.get).toHaveBeenCalledWith('api/dummyResource/1')
  179. expect(entityManager.newInstance).toHaveBeenCalledWith(DummyApiResource, properties)
  180. expect(result).toEqual(entity)
  181. })
  182. })
  183. describe('fetchCollection', () => {
  184. test('simple call', async () => {
  185. const collection = {
  186. '@type': 'hydra:Collection',
  187. 'hydra:totalItems': 3,
  188. 'hydra:member': [
  189. {id: 1},
  190. {id: 2},
  191. {id: 3},
  192. ]
  193. }
  194. // @ts-ignore
  195. apiRequestService.get = vi.fn(async (url: string) => collection)
  196. // @ts-ignore
  197. entityManager.newInstance = vi.fn((model: typeof ApiResource, props: object) => {
  198. return new DummyApiResource(props)
  199. })
  200. const result = await entityManager.fetchCollection(DummyApiResource, null)
  201. expect(apiRequestService.get).toHaveBeenCalledWith('api/dummyResource', [])
  202. expect(entityManager.newInstance).toHaveBeenCalledTimes(3)
  203. expect(entityManager.newInstance).toHaveBeenCalledWith(DummyApiResource, {id: 1})
  204. expect(entityManager.newInstance).toHaveBeenCalledWith(DummyApiResource, {id: 2})
  205. expect(entityManager.newInstance).toHaveBeenCalledWith(DummyApiResource, {id: 3})
  206. expect(result.items).toEqual([
  207. new DummyApiResource({id: 1}),
  208. new DummyApiResource({id: 2}),
  209. new DummyApiResource({id: 3})
  210. ])
  211. expect(result.pagination, 'default pagination').toEqual({
  212. first: 1,
  213. last: 1,
  214. next: undefined,
  215. previous: undefined
  216. })
  217. })
  218. test('with a parent', async () => {
  219. const collection = {
  220. '@type': 'hydra:Collection',
  221. 'hydra:totalItems': 3,
  222. 'hydra:member': [
  223. {id: 1},
  224. {id: 2},
  225. {id: 3},
  226. ]
  227. }
  228. // @ts-ignore
  229. apiRequestService.get = vi.fn(async (url: string) => collection)
  230. // @ts-ignore
  231. entityManager.newInstance = vi.fn((model: typeof ApiResource, props: object) => {
  232. return new DummyApiResource(props)
  233. })
  234. const parent = new DummyApiModel()
  235. parent.id = 100
  236. parent.entity = 'dummyModel' // TODO: je ne comprend pas pqoi cette ligne est nécessaire...
  237. await entityManager.fetchCollection(DummyApiResource, parent)
  238. expect(apiRequestService.get).toHaveBeenCalledWith('api/dummyModel/100/dummyResource', [])
  239. })
  240. test('with a query', async () => {
  241. const collection = {
  242. '@type': 'hydra:Collection',
  243. 'hydra:totalItems': 3,
  244. 'hydra:member': [
  245. {id: 1},
  246. {id: 2},
  247. {id: 3},
  248. ]
  249. }
  250. // @ts-ignore
  251. apiRequestService.get = vi.fn(async (url: string) => collection)
  252. // @ts-ignore
  253. entityManager.newInstance = vi.fn((model: typeof ApiResource, props: object) => {
  254. return new DummyApiResource(props)
  255. })
  256. await entityManager.fetchCollection(DummyApiResource, null, { page: 10 })
  257. expect(apiRequestService.get).toHaveBeenCalledWith('api/dummyResource', { page: 10 })
  258. })
  259. test('with pagination', async () => {
  260. const collection = {
  261. '@type': 'hydra:Collection',
  262. 'hydra:totalItems': 1000,
  263. 'hydra:member': [],
  264. 'hydra:view': {
  265. "@id": "/api/subdomains?organization=498&page=50",
  266. 'hydra:first': '/api/subdomains?organization=498&page=1',
  267. 'hydra:last': '/api/subdomains?organization=498&page=100',
  268. 'hydra:next': '/api/subdomains?organization=498&page=51',
  269. 'hydra:previous': '/api/subdomains?organization=498&page=49'
  270. }
  271. }
  272. // @ts-ignore
  273. apiRequestService.get = vi.fn(async (url: string) => collection)
  274. const result = await entityManager.fetchCollection(DummyApiResource, null)
  275. expect(result.totalItems).toEqual(1000)
  276. expect(result.pagination.first).toEqual(1)
  277. expect(result.pagination.last).toEqual(100)
  278. expect(result.pagination.previous).toEqual(49)
  279. expect(result.pagination.next).toEqual(51)
  280. })
  281. })
  282. describe('saveResponseAsEntity', () => {
  283. test('simple call', async () => {
  284. const entity = new DummyApiModel({id: 1})
  285. // @ts-ignore
  286. const repo = vi.fn() as Repository<ApiResource>
  287. // @ts-ignore
  288. entityManager.getRepository = vi.fn((model: typeof ApiResource) => {
  289. return model === DummyApiModel ? repo : null
  290. })
  291. // @ts-ignore
  292. const response = {id: 1} as Response
  293. entityManager.newInstance = vi.fn((model: typeof ApiResource, properties: object) => {
  294. return entity
  295. })
  296. entityManager.saveInitialState = vi.fn((model: typeof ApiResource, entity: ApiResource) => null)
  297. // @ts-ignore
  298. repo.save = vi.fn((data: any) => null)
  299. const result = await entityManager.saveResponseAsEntity(DummyApiModel, response)
  300. expect(entityManager.getRepository).toHaveBeenCalledWith(DummyApiModel)
  301. expect(entityManager.newInstance).toHaveBeenCalledWith(DummyApiModel, {id: 1})
  302. expect(entityManager.saveInitialState).toHaveBeenCalledWith(DummyApiModel, entity)
  303. expect(repo.save).toHaveBeenCalledWith(entity)
  304. expect(result).toEqual(entity)
  305. })
  306. })
  307. describe('persist', () => {
  308. test('new entity (POST)', async () => {
  309. const entity = new DummyApiModel({id: 'tmp1', name: 'bob'})
  310. entity.isNew = vi.fn(() => true)
  311. // @ts-ignore
  312. entity.$toJson = vi.fn(() => {
  313. return {id: 'tmp1', name: 'bob'}
  314. })
  315. entityManager.cast = vi.fn((model: typeof ApiResource, entity: ApiResource): ApiResource => entity)
  316. const response = { id: 1, name: 'bob' }
  317. // @ts-ignore
  318. apiRequestService.post = vi.fn((url, data) => response)
  319. // @ts-ignore
  320. entityManager.saveResponseAsEntity = vi.fn((model, response) => {
  321. const newEntity = new DummyApiModel(response)
  322. // @ts-ignore
  323. newEntity.id = response.id
  324. // @ts-ignore
  325. newEntity.name = response.name
  326. return newEntity
  327. })
  328. entityManager.removeTempAfterPersist = vi.fn()
  329. const result = await entityManager.persist(DummyApiModel, entity)
  330. // temp id should have been purged from the posted data
  331. expect(apiRequestService.post).toHaveBeenCalledWith('api/dummyModel', {name: 'bob'})
  332. expect(entityManager.saveResponseAsEntity).toHaveBeenCalledWith(DummyApiModel, response)
  333. expect(entityManager.removeTempAfterPersist).toHaveBeenCalledWith(DummyApiModel, entity.id)
  334. expect(result.id).toEqual(1)
  335. expect(result.name).toEqual('bob')
  336. })
  337. test('existing entity (PUT)', async () => {
  338. const props = {id: 1, name: 'bob'}
  339. const entity = new DummyApiModel(props)
  340. entity.id = 1
  341. entity.isNew = vi.fn(() => false)
  342. // @ts-ignore
  343. entity.$toJson = vi.fn(() => props)
  344. entityManager.cast = vi.fn((model: typeof ApiResource, entity: ApiResource): ApiResource => entity)
  345. // @ts-ignore
  346. apiRequestService.put = vi.fn((url, data) => props)
  347. // @ts-ignore
  348. entityManager.saveResponseAsEntity = vi.fn((model, response) => {
  349. const newEntity = new DummyApiModel(response)
  350. // @ts-ignore
  351. newEntity.id = response.id
  352. // @ts-ignore
  353. newEntity.name = response.name
  354. return newEntity
  355. })
  356. entityManager.removeTempAfterPersist = vi.fn()
  357. const result = await entityManager.persist(DummyApiModel, entity)
  358. expect(apiRequestService.put).toHaveBeenCalledWith('api/dummyModel/1', {id: 1, name: 'bob'})
  359. expect(entityManager.saveResponseAsEntity).toHaveBeenCalledWith(DummyApiModel, props)
  360. expect(entityManager.removeTempAfterPersist).toHaveBeenCalledTimes(0)
  361. expect(result.id).toEqual(1)
  362. expect(result.name).toEqual('bob')
  363. })
  364. })
  365. describe('patch', () => {
  366. test('simple call', async () => {
  367. const props = {id: 1, name: 'bobby'}
  368. // @ts-ignore
  369. apiRequestService.put = vi.fn((url, data) => props)
  370. // @ts-ignore
  371. entityManager.saveResponseAsEntity = vi.fn((model, response) => {
  372. const newEntity = new DummyApiModel(response)
  373. // @ts-ignore
  374. newEntity.id = response.id
  375. // @ts-ignore
  376. newEntity.name = response.name
  377. return newEntity
  378. })
  379. const result = await entityManager.patch(DummyApiModel, 1, {name: 'bobby'})
  380. expect(apiRequestService.put).toHaveBeenCalledWith('api/dummyModel/1', '{"name":"bobby"}')
  381. expect(entityManager.saveResponseAsEntity).toHaveBeenCalledWith(DummyApiModel, {id: 1, name: 'bobby'})
  382. expect(result.id).toEqual(1)
  383. expect(result.name).toEqual('bobby')
  384. })
  385. })
  386. describe('delete', () => {
  387. test('delete non persisted entity', () => {
  388. const entity = new DummyApiModel()
  389. entity.isNew = vi.fn(() => true)
  390. entity.id = 'tmp123'
  391. // @ts-ignore
  392. const repo = vi.fn() as Repository<ApiResource>
  393. // @ts-ignore
  394. entityManager.getRepository = vi.fn((model: typeof ApiResource) => {
  395. return model === DummyApiModel ? repo : null
  396. })
  397. apiRequestService.delete = vi.fn()
  398. // @ts-ignore
  399. repo.destroy = vi.fn((id: number) => null)
  400. entityManager.delete(DummyApiModel, entity)
  401. expect(entityManager.getRepository).toHaveBeenCalledWith(DummyApiModel)
  402. expect(apiRequestService.delete).toHaveBeenCalledTimes(0)
  403. expect(repo.destroy).toHaveBeenCalledWith('tmp123')
  404. })
  405. test('delete persisted entity', async () => {
  406. const entity = new DummyApiModel()
  407. entity.isNew = vi.fn(() => false)
  408. entity.id = 1
  409. // @ts-ignore
  410. const repo = vi.fn() as Repository<ApiResource>
  411. // @ts-ignore
  412. entityManager.getRepository = vi.fn((model: typeof ApiResource) => {
  413. return model === DummyApiModel ? repo : null
  414. })
  415. // @ts-ignore
  416. apiRequestService.delete = vi.fn((id: number) => null)
  417. // @ts-ignore
  418. repo.destroy = vi.fn((id: number) => null)
  419. await entityManager.delete(DummyApiModel, entity)
  420. expect(entityManager.getRepository).toHaveBeenCalledWith(DummyApiModel)
  421. expect(apiRequestService.delete).toHaveBeenCalledWith('api/dummyModel/1')
  422. expect(repo.destroy).toHaveBeenCalledWith(1)
  423. })
  424. })
  425. describe('reset', () => {
  426. test('simple call', () => {
  427. const entity = new DummyApiModel()
  428. entity.id = 1
  429. entity.name = 'paul'
  430. const initialEntity = new DummyApiModel()
  431. initialEntity.id = 1
  432. initialEntity.name = 'serges'
  433. entityManager.getInitialStateOf = vi.fn((model: typeof ApiResource, id: string | number) => initialEntity)
  434. // @ts-ignore
  435. const repo = vi.fn() as Repository<ApiResource>
  436. // @ts-ignore
  437. entityManager.getRepository = vi.fn((model: typeof ApiResource) => {
  438. return model === DummyApiModel ? repo : null
  439. })
  440. // @ts-ignore
  441. repo.save = vi.fn((data: any) => null)
  442. const result = entityManager.reset(DummyApiModel, entity)
  443. expect(entityManager.getInitialStateOf).toHaveBeenCalledWith(DummyApiModel, 1)
  444. expect(repo.save).toHaveBeenCalledWith(initialEntity)
  445. expect(result).toEqual(initialEntity)
  446. })
  447. test('no initial state stored', () => {
  448. const entity = new DummyApiModel()
  449. entity.id = 1
  450. entityManager.getInitialStateOf = vi.fn((model: typeof ApiResource, id: string | number) => null)
  451. expect(() => entityManager.reset(DummyApiModel, entity)).toThrowError(
  452. 'no initial state recorded for this object - abort [dummyModel/1]'
  453. )
  454. })
  455. })
  456. describe('flush', () => {
  457. test('simple call', () => {
  458. // @ts-ignore
  459. const repo = vi.fn() as Repository<ApiResource>
  460. // @ts-ignore
  461. entityManager.getRepository = vi.fn((model: typeof ApiResource) => {
  462. return model === DummyApiModel ? repo : null
  463. })
  464. repo.flush = vi.fn()
  465. entityManager.flush(DummyApiModel)
  466. expect(repo.flush).toHaveBeenCalled()
  467. })
  468. })
  469. describe('isNewEntity', () => {
  470. test('with new entity', () => {
  471. const entity = new DummyApiModel()
  472. entity.isNew = vi.fn(() => true)
  473. // @ts-ignore
  474. const repo = vi.fn() as Repository<ApiResource>
  475. // @ts-ignore
  476. entityManager.getRepository = vi.fn((model: typeof ApiResource) => {
  477. return model === DummyApiModel ? repo : null
  478. })
  479. // @ts-ignore
  480. repo.find = vi.fn((id: number) => entity)
  481. const result = entityManager.isNewEntity(DummyApiModel, 1)
  482. expect(result).toBeTruthy()
  483. })
  484. test('with existing entity', () => {
  485. const entity = new DummyApiModel()
  486. entity.isNew = vi.fn(() => false)
  487. // @ts-ignore
  488. const repo = vi.fn() as Repository<ApiResource>
  489. // @ts-ignore
  490. entityManager.getRepository = vi.fn((model: typeof ApiResource) => {
  491. return model === DummyApiModel ? repo : null
  492. })
  493. // @ts-ignore
  494. repo.find = vi.fn((id: number) => entity)
  495. const result = entityManager.isNewEntity(DummyApiModel, 1)
  496. expect(result).toBeFalsy()
  497. })
  498. test('non-existing entity', () => {
  499. // @ts-ignore
  500. const repo = vi.fn() as Repository<ApiResource>
  501. // @ts-ignore
  502. entityManager.getRepository = vi.fn((model: typeof ApiResource) => {
  503. return model === DummyApiModel ? repo : null
  504. })
  505. // @ts-ignore
  506. repo.find = vi.fn((id: number) => null)
  507. console.error = vi.fn()
  508. const result = entityManager.isNewEntity(DummyApiModel, 1)
  509. expect(result).toBeFalsy()
  510. expect(console.error).toHaveBeenCalledWith('dummyModel/1 does not exist!')
  511. })
  512. })
  513. describe('saveInitialState', () => {
  514. test('simple call', () => {
  515. // @ts-ignore
  516. const entity = { id: 1, name: 'bob' } as DummyApiResource
  517. // @ts-ignore
  518. const repo = vi.fn() as Repository<ApiResource>
  519. // @ts-ignore
  520. entityManager.getRepository = vi.fn((model: typeof ApiResource) => {
  521. return model === DummyApiResource ? repo : null
  522. })
  523. // @ts-ignore
  524. repo.save = vi.fn((record: Element) => null)
  525. entityManager.saveInitialState(DummyApiResource, entity)
  526. expect(repo.save).toHaveBeenCalledWith({ id: '_clone_1', name: 'bob' })
  527. expect(entity.id).toEqual(1)
  528. })
  529. })
  530. describe('getInitialStateOf', () => {
  531. test('with initial state', () => {
  532. // @ts-ignore
  533. const entity = { id: 1, name: 'bob' } as DummyApiResource
  534. // @ts-ignore
  535. const repo = vi.fn() as Repository<ApiResource>
  536. // @ts-ignore
  537. entityManager.getRepository = vi.fn((model: typeof ApiResource) => {
  538. return model === DummyApiResource ? repo : null
  539. })
  540. // @ts-ignore
  541. repo.find = vi.fn((id: number | string) => {
  542. // @ts-ignore
  543. return { id: 1, name: 'robert' } as DummyApiResource
  544. })
  545. const result = entityManager.getInitialStateOf(DummyApiResource, 1) as DummyApiResource
  546. expect(repo.find).toHaveBeenCalledWith('_clone_1')
  547. expect(result.id).toEqual(1)
  548. expect(result.name).toEqual('robert')
  549. })
  550. test('without initial state', () => {
  551. // @ts-ignore
  552. const repo = vi.fn() as Repository<ApiResource>
  553. // @ts-ignore
  554. entityManager.getRepository = vi.fn((model: typeof ApiResource) => {
  555. return model === DummyApiResource ? repo : null
  556. })
  557. // @ts-ignore
  558. repo.find = vi.fn((id: number | string) => null)
  559. const result = entityManager.getInitialStateOf(DummyApiResource, 1) as DummyApiResource
  560. expect(repo.find).toHaveBeenCalledWith('_clone_1')
  561. expect(result).toEqual(null)
  562. })
  563. })
  564. describe('removeTempAfterPersist', () => {
  565. test('simple call', () => {
  566. // @ts-ignore
  567. const entity = new DummyApiResource()
  568. entity.id = 'tmp123'
  569. entity.isNew = vi.fn(() => true)
  570. // @ts-ignore
  571. const repo = vi.fn() as Repository<ApiResource>
  572. // @ts-ignore
  573. entityManager.getRepository = vi.fn((model: typeof ApiResource) => {
  574. return model === DummyApiResource ? repo : null
  575. })
  576. // @ts-ignore
  577. repo.find = vi.fn((id: number | string) => entity)
  578. // @ts-ignore
  579. repo.destroy = vi.fn()
  580. entityManager.removeTempAfterPersist(DummyApiResource, 'tmp123')
  581. expect(repo.destroy).toHaveBeenCalledWith('tmp123')
  582. expect(repo.destroy).toHaveBeenCalledWith('_clone_tmp123')
  583. })
  584. test('entity is not temporary', () => {
  585. // @ts-ignore
  586. const entity = new DummyApiResource()
  587. entity.id = 1
  588. entity.isNew = vi.fn(() => false)
  589. // @ts-ignore
  590. const repo = vi.fn() as Repository<ApiResource>
  591. // @ts-ignore
  592. entityManager.getRepository = vi.fn((model: typeof ApiResource) => {
  593. return model === DummyApiResource ? repo : null
  594. })
  595. // @ts-ignore
  596. repo.find = vi.fn((id: number | string) => entity)
  597. // @ts-ignore
  598. repo.destroy = vi.fn()
  599. expect(() => entityManager.removeTempAfterPersist(DummyApiResource, 'tmp123')).toThrowError(
  600. 'Error: Can not remove a non-temporary entity'
  601. )
  602. expect(repo.destroy).toHaveBeenCalledTimes(0)
  603. })
  604. test('entity does not exist', () => {
  605. // @ts-ignore
  606. const repo = vi.fn() as Repository<ApiResource>
  607. // @ts-ignore
  608. entityManager.getRepository = vi.fn((model: typeof ApiResource) => {
  609. return model === DummyApiResource ? repo : null
  610. })
  611. // @ts-ignore
  612. repo.find = vi.fn((id: number | string) => null)
  613. // @ts-ignore
  614. repo.destroy = vi.fn()
  615. console.error = vi.fn()
  616. entityManager.removeTempAfterPersist(DummyApiResource, 'tmp123')
  617. expect(repo.destroy).toHaveBeenCalledTimes(0)
  618. expect(console.error).toHaveBeenCalledWith('dummyResource/tmp123 does not exist!')
  619. })
  620. })