entityManager.test.ts 26 KB

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