entityManager.test.ts 25 KB

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