entityManager.test.ts 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926
  1. import { describe, test, vi, expect, beforeEach, afterEach } from 'vitest'
  2. import { Repository } from 'pinia-orm'
  3. import type { Element } from 'pinia-orm'
  4. import { Str, Uid } from 'pinia-orm/dist/decorators'
  5. import EntityManager from '~/services/data/entityManager'
  6. import ApiResource from '~/models/ApiResource'
  7. import ApiModel from '~/models/ApiModel'
  8. import ApiRequestService from '~/services/data/apiRequestService'
  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. const _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) =>
  77. entityName === 'dummy' ? DummyApiResource : null,
  78. )
  79. // @ts-ignore
  80. const result = entityManager.getModelFromIri('/api/dummy/123')
  81. expect(result).toEqual(DummyApiResource)
  82. })
  83. test('invalide Iri', () => {
  84. expect(() => entityManager.getModelFromIri('/invalid')).toThrowError(
  85. 'cannot parse the IRI',
  86. )
  87. })
  88. })
  89. describe('newInstance', () => {
  90. test('simple call', () => {
  91. const properties = { id: 1 }
  92. // @ts-ignore
  93. entityManager.getRepository = vi.fn((model: typeof ApiResource) => {
  94. return model === DummyApiResource ? repo : null
  95. })
  96. // @ts-ignore
  97. const entity = new DummyApiResource(properties)
  98. // @ts-ignore
  99. repo.make = vi.fn((properties: object) => {
  100. // @ts-ignore
  101. entity.id = properties.id
  102. return entity
  103. })
  104. // @ts-ignore
  105. entityManager.save = vi.fn(
  106. (model: typeof ApiResource, entity: ApiResource, permanent: boolean) =>
  107. entity,
  108. )
  109. const result = entityManager.newInstance(DummyApiResource, properties)
  110. expect(repo.make).toHaveBeenCalledWith(properties)
  111. expect(entityManager.save).toHaveBeenCalledWith(
  112. DummyApiResource,
  113. entity,
  114. true,
  115. )
  116. expect(result.id).toEqual(properties.id)
  117. })
  118. test('with no id provided', () => {
  119. const properties = { name: 'bob' }
  120. // @ts-ignore
  121. const repo = vi.fn() as Repository<ApiResource>
  122. // @ts-ignore
  123. entityManager.getRepository = vi.fn((model: typeof ApiResource) => {
  124. return model === DummyApiResource ? repo : null
  125. })
  126. // @ts-ignore
  127. entityManager.saveInitialState = vi.fn(
  128. (model: typeof ApiResource, entity: ApiResource) => null,
  129. )
  130. // @ts-ignore
  131. const entity = new DummyApiResource(properties)
  132. // @ts-ignore
  133. repo.make = vi.fn((properties: object) => {
  134. // @ts-ignore
  135. entity.name = properties.name
  136. return entity
  137. })
  138. // @ts-ignore
  139. repo.save = vi.fn((record: Element) => entity)
  140. const result = entityManager.newInstance(DummyApiResource, properties)
  141. expect(result.id, "id is 'tmp' followed by a valid uuid-V4").toMatch(
  142. /tmp[0-9a-f]{8}-[0-9a-f]{4}-[0-5][0-9a-f]{3}-[089ab][0-9a-f]{3}-[0-9a-f]{12}/,
  143. )
  144. expect(result.name).toEqual(properties.name)
  145. })
  146. })
  147. describe('save', () => {
  148. test('simple call', () => {
  149. // @ts-ignore
  150. const repo = vi.fn() as Repository<ApiResource>
  151. // @ts-ignore
  152. entityManager.getRepository = vi.fn((model: typeof ApiResource) => {
  153. return model === DummyApiResource ? repo : null
  154. })
  155. // @ts-ignore
  156. repo.save = vi.fn((record: Element) => entity)
  157. const entity = new DummyApiResource()
  158. entityManager.save(DummyApiResource, entity)
  159. expect(repo.save).toHaveBeenCalledWith(entity)
  160. })
  161. })
  162. describe('find', () => {
  163. test('simple call', () => {
  164. // @ts-ignore
  165. const repo = vi.fn() as Repository<ApiResource>
  166. // @ts-ignore
  167. entityManager.getRepository = vi.fn((model: typeof ApiResource) => {
  168. return model === DummyApiResource ? repo : null
  169. })
  170. const entity = new DummyApiResource({ id: 1 })
  171. // @ts-ignore
  172. repo.find = vi.fn((id: string | number) => entity)
  173. entityManager.find(DummyApiResource, 1)
  174. expect(entityManager.getRepository).toHaveBeenCalledWith(DummyApiResource)
  175. expect(repo.find).toHaveBeenCalledWith(1)
  176. })
  177. })
  178. describe('fetch', () => {
  179. test('not in store, no force refresh', async () => {
  180. const properties = { id: 1 }
  181. const entity = new DummyApiResource({ id: 1 })
  182. // @ts-ignore
  183. entityManager.find = vi.fn(
  184. (model: typeof ApiResource, id: number) => undefined,
  185. )
  186. // @ts-ignore
  187. apiRequestService.get = vi.fn(async (url: string) => properties)
  188. // @ts-ignore
  189. entityManager.newInstance = vi.fn(
  190. (model: typeof ApiResource, props: object) => entity,
  191. )
  192. const result = await entityManager.fetch(DummyApiResource, 1)
  193. expect(entityManager.find).toHaveBeenCalledWith(DummyApiResource, 1)
  194. expect(apiRequestService.get).toHaveBeenCalledWith('api/dummyResource/1')
  195. expect(entityManager.newInstance).toHaveBeenCalledWith(DummyApiResource, {
  196. id: 1,
  197. name: null,
  198. _model: undefined,
  199. })
  200. expect(result).toEqual(entity)
  201. })
  202. test('in store, no force refresh', async () => {
  203. const properties = { id: 1 }
  204. const entity = new DummyApiResource({ id: 1 })
  205. // @ts-ignore
  206. entityManager.find = vi.fn(
  207. (model: typeof ApiResource, id: number) => entity,
  208. )
  209. const result = await entityManager.fetch(DummyApiResource, 1)
  210. expect(entityManager.find).toHaveBeenCalledWith(DummyApiResource, 1)
  211. expect(result).toEqual(entity)
  212. })
  213. test('in store, but with force refresh', async () => {
  214. const properties = { id: 1 }
  215. const entity = new DummyApiResource({ id: 1 })
  216. // @ts-ignore
  217. entityManager.find = vi.fn(
  218. (model: typeof ApiResource, id: number) => undefined,
  219. )
  220. // @ts-ignore
  221. apiRequestService.get = vi.fn(async (url: string) => properties)
  222. // @ts-ignore
  223. entityManager.newInstance = vi.fn(
  224. (model: typeof ApiResource, props: object) => entity,
  225. )
  226. const result = await entityManager.fetch(DummyApiResource, 1, true)
  227. expect(entityManager.find).toHaveBeenCalledTimes(0)
  228. expect(apiRequestService.get).toHaveBeenCalledWith('api/dummyResource/1')
  229. expect(entityManager.newInstance).toHaveBeenCalledWith(DummyApiResource, {
  230. id: 1,
  231. name: null,
  232. _model: undefined,
  233. })
  234. expect(result).toEqual(entity)
  235. })
  236. })
  237. describe('fetchCollection', () => {
  238. test('simple call', async () => {
  239. const collection = {
  240. '@type': 'hydra:Collection',
  241. 'hydra:totalItems': 3,
  242. 'hydra:member': [{ id: 1 }, { id: 2 }, { id: 3 }],
  243. }
  244. // @ts-ignore
  245. apiRequestService.get = vi.fn(async (url: string) => collection)
  246. // @ts-ignore
  247. entityManager.newInstance = vi.fn(
  248. (model: typeof ApiResource, props: object) => {
  249. return new DummyApiResource(props)
  250. },
  251. )
  252. const piniaOrmQuery = vi.fn()
  253. // @ts-ignore
  254. entityManager.getQuery = vi.fn((model: typeof ApiResource) => piniaOrmQuery)
  255. const result = await entityManager.fetchCollection(DummyApiResource, null)
  256. expect(apiRequestService.get).toHaveBeenCalledWith('api/dummyResource')
  257. expect(entityManager.newInstance).toHaveBeenCalledTimes(3)
  258. expect(entityManager.newInstance).toHaveBeenCalledWith(DummyApiResource, {
  259. id: 1,
  260. name: null,
  261. _model: undefined,
  262. })
  263. expect(entityManager.newInstance).toHaveBeenCalledWith(DummyApiResource, {
  264. id: 2,
  265. name: null,
  266. _model: undefined,
  267. })
  268. expect(entityManager.newInstance).toHaveBeenCalledWith(DummyApiResource, {
  269. id: 3,
  270. name: null,
  271. _model: undefined,
  272. })
  273. // @ts-ignore
  274. piniaOrmQuery.get = vi.fn(() => [
  275. new DummyApiResource({ id: 1 }),
  276. new DummyApiResource({ id: 2 }),
  277. new DummyApiResource({ id: 3 }),
  278. ])
  279. expect(result.value.items).toEqual([
  280. new DummyApiResource({ id: 1 }),
  281. new DummyApiResource({ id: 2 }),
  282. new DummyApiResource({ id: 3 }),
  283. ])
  284. expect(result.value.pagination, 'default pagination').toEqual({
  285. first: 1,
  286. last: 1,
  287. next: undefined,
  288. previous: undefined,
  289. })
  290. })
  291. test('with a parent', async () => {
  292. const collection = {
  293. '@type': 'hydra:Collection',
  294. 'hydra:totalItems': 3,
  295. 'hydra:member': [{ id: 1 }, { id: 2 }, { id: 3 }],
  296. }
  297. // @ts-ignore
  298. apiRequestService.get = vi.fn(async (url: string) => collection)
  299. const piniaOrmQuery = vi.fn()
  300. // @ts-ignore
  301. entityManager.getQuery = vi.fn((model: typeof ApiResource) => piniaOrmQuery)
  302. // @ts-ignore
  303. entityManager.newInstance = vi.fn(
  304. (model: typeof ApiResource, props: object) => {
  305. return new DummyApiResource(props)
  306. },
  307. )
  308. const parent = new DummyApiModel()
  309. parent.id = 100
  310. parent.entity = 'dummyModel' // TODO: je ne comprend pas pqoi cette ligne est nécessaire...
  311. await entityManager.fetchCollection(DummyApiResource, parent)
  312. expect(apiRequestService.get).toHaveBeenCalledWith(
  313. 'api/dummyModel/100/dummyResource',
  314. )
  315. })
  316. test('with a query', async () => {
  317. const collection = {
  318. '@type': 'hydra:Collection',
  319. 'hydra:totalItems': 3,
  320. 'hydra:member': [{ id: 1 }, { id: 2 }, { id: 3 }],
  321. }
  322. const query = vi.fn()
  323. // @ts-ignore
  324. query.getUrlQuery = vi.fn(() => 'foo=bar')
  325. // @ts-ignore
  326. query.applyToPiniaOrmQuery = vi.fn((q) => q)
  327. const piniaOrmQuery = vi.fn()
  328. // @ts-ignore
  329. entityManager.getQuery = vi.fn((model: typeof ApiResource) => piniaOrmQuery)
  330. // @ts-ignore
  331. apiRequestService.get = vi.fn(async (url: string) => collection)
  332. // @ts-ignore
  333. entityManager.newInstance = vi.fn(
  334. (model: typeof ApiResource, props: object) => {
  335. return new DummyApiResource(props)
  336. },
  337. )
  338. // @ts-ignore
  339. await entityManager.fetchCollection(DummyApiResource, null, query)
  340. expect(apiRequestService.get).toHaveBeenCalledWith(
  341. 'api/dummyResource?foo=bar',
  342. )
  343. // @ts-ignore
  344. expect(query.getUrlQuery).toHaveBeenCalledWith()
  345. // @ts-ignore
  346. expect(query.applyToPiniaOrmQuery).toHaveBeenCalledWith(piniaOrmQuery)
  347. })
  348. })
  349. describe('persist', () => {
  350. test('new entity (POST)', async () => {
  351. const instance = new DummyApiModel({ id: 'tmp1', name: 'bob' })
  352. instance.isNew = vi.fn(() => true)
  353. // @ts-ignore
  354. instance.$toJson = vi.fn(() => {
  355. return { id: 'tmp1', name: 'bob' }
  356. })
  357. // @ts-ignore
  358. entityManager.cast = vi.fn(
  359. (model: typeof ApiResource, entity: ApiResource): ApiResource => entity,
  360. )
  361. const response = { id: 1, name: 'bob' }
  362. // @ts-ignore
  363. apiRequestService.post = vi.fn((url, data) => response)
  364. // @ts-ignore
  365. entityManager.newInstance = vi.fn((model, response) => {
  366. const newEntity = new DummyApiModel(response)
  367. // @ts-ignore
  368. newEntity.id = response.id
  369. // @ts-ignore
  370. newEntity.name = response.name
  371. return newEntity
  372. })
  373. // @ts-ignore
  374. entityManager.removeTempAfterPersist = vi.fn()
  375. const result = await entityManager.persist(DummyApiModel, instance)
  376. // temp id should have been purged from the posted data
  377. expect(apiRequestService.post).toHaveBeenCalledWith('api/dummyModel', {
  378. name: 'bob',
  379. })
  380. expect(entityManager.newInstance).toHaveBeenCalledWith(
  381. DummyApiModel,
  382. response,
  383. )
  384. // @ts-ignore
  385. expect(entityManager.removeTempAfterPersist).toHaveBeenCalledWith(
  386. DummyApiModel,
  387. instance.id,
  388. )
  389. expect(result.id).toEqual(1)
  390. expect(result.name).toEqual('bob')
  391. })
  392. test('existing entity (PUT)', async () => {
  393. const props = { id: 1, name: 'bob' }
  394. const entity = new DummyApiModel(props)
  395. entity.id = 1
  396. entity.isNew = vi.fn(() => false)
  397. // @ts-ignore
  398. entity.$toJson = vi.fn(() => props)
  399. // TODO: attendre de voir si cet appel est nécessaire dans l'entity manager
  400. // entityManager.cast = vi.fn((model: typeof ApiResource, entity: ApiResource): ApiResource => entity)
  401. // @ts-ignore
  402. apiRequestService.put = vi.fn((url, data) => props)
  403. // @ts-ignore
  404. entityManager.newInstance = vi.fn((model, response) => {
  405. const newEntity = new DummyApiModel(response)
  406. // @ts-ignore
  407. newEntity.id = response.id
  408. // @ts-ignore
  409. newEntity.name = response.name
  410. return newEntity
  411. })
  412. // @ts-ignore
  413. entityManager.removeTempAfterPersist = vi.fn()
  414. const result = await entityManager.persist(DummyApiModel, entity)
  415. expect(apiRequestService.put).toHaveBeenCalledWith('api/dummyModel/1', {
  416. id: 1,
  417. name: 'bob',
  418. })
  419. expect(entityManager.newInstance).toHaveBeenCalledWith(DummyApiModel, props)
  420. // @ts-ignore
  421. expect(entityManager.removeTempAfterPersist).toHaveBeenCalledTimes(0)
  422. expect(result.id).toEqual(1)
  423. expect(result.name).toEqual('bob')
  424. })
  425. })
  426. describe('patch', () => {
  427. test('simple call', async () => {
  428. const props = { id: 1, name: 'bobby' }
  429. // @ts-ignore
  430. apiRequestService.put = vi.fn((url, data) => props)
  431. // @ts-ignore
  432. entityManager.newInstance = vi.fn((model, response) => {
  433. const newEntity = new DummyApiModel(response)
  434. // @ts-ignore
  435. newEntity.id = response.id
  436. // @ts-ignore
  437. newEntity.name = response.name
  438. return newEntity
  439. })
  440. const result = await entityManager.patch(DummyApiModel, 1, {
  441. name: 'bobby',
  442. })
  443. expect(apiRequestService.put).toHaveBeenCalledWith(
  444. 'api/dummyModel/1',
  445. '{"name":"bobby"}',
  446. )
  447. expect(entityManager.newInstance).toHaveBeenCalledWith(DummyApiModel, {
  448. id: 1,
  449. name: 'bobby',
  450. })
  451. expect(result.id).toEqual(1)
  452. expect(result.name).toEqual('bobby')
  453. })
  454. })
  455. describe('delete', () => {
  456. test('delete non persisted entity', () => {
  457. const entity = new DummyApiModel()
  458. entity.isNew = vi.fn(() => true)
  459. entity.id = 'tmp123'
  460. // @ts-ignore
  461. const repo = vi.fn() as Repository<ApiResource>
  462. // @ts-ignore
  463. entityManager.getRepository = vi.fn((model: typeof ApiResource) => {
  464. return model === DummyApiModel ? repo : null
  465. })
  466. apiRequestService.delete = vi.fn()
  467. // @ts-ignore
  468. repo.destroy = vi.fn((id: number) => null)
  469. entityManager.delete(DummyApiModel, entity)
  470. expect(entityManager.getRepository).toHaveBeenCalledWith(DummyApiModel)
  471. expect(apiRequestService.delete).toHaveBeenCalledTimes(0)
  472. expect(repo.destroy).toHaveBeenCalledWith('tmp123')
  473. })
  474. test('delete persisted entity', async () => {
  475. const entity = new DummyApiModel()
  476. entity.isNew = vi.fn(() => false)
  477. entity.id = 1
  478. // @ts-ignore
  479. const repo = vi.fn() as Repository<ApiResource>
  480. // @ts-ignore
  481. entityManager.getRepository = vi.fn((model: typeof ApiResource) => {
  482. return model === DummyApiModel ? repo : null
  483. })
  484. // @ts-ignore
  485. apiRequestService.delete = vi.fn((id: number) => null)
  486. // @ts-ignore
  487. repo.destroy = vi.fn((id: number) => null)
  488. await entityManager.delete(DummyApiModel, entity)
  489. expect(entityManager.getRepository).toHaveBeenCalledWith(DummyApiModel)
  490. expect(apiRequestService.delete).toHaveBeenCalledWith('api/dummyModel/1')
  491. expect(repo.destroy).toHaveBeenCalledWith(1)
  492. })
  493. })
  494. describe('reset', () => {
  495. test('simple call', () => {
  496. const entity = new DummyApiModel()
  497. entity.id = 1
  498. entity.name = 'paul'
  499. const initialEntity = new DummyApiModel()
  500. initialEntity.id = 1
  501. initialEntity.name = 'serges'
  502. // @ts-ignore
  503. entityManager.getInitialStateOf = vi.fn(
  504. (model: typeof ApiResource, id: string | number) => initialEntity,
  505. )
  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.save = vi.fn((data: any) => null)
  514. const result = entityManager.reset(DummyApiModel, entity)
  515. // @ts-ignore
  516. expect(entityManager.getInitialStateOf).toHaveBeenCalledWith(
  517. DummyApiModel,
  518. 1,
  519. )
  520. expect(repo.save).toHaveBeenCalledWith(initialEntity)
  521. expect(result).toEqual(initialEntity)
  522. })
  523. test('no initial state stored', () => {
  524. const entity = new DummyApiModel()
  525. entity.id = 1
  526. // @ts-ignore
  527. entityManager.getInitialStateOf = vi.fn(
  528. (model: typeof ApiResource, id: string | number) => null,
  529. )
  530. expect(() => entityManager.reset(DummyApiModel, entity)).toThrowError(
  531. 'no initial state recorded for this object - abort [dummyModel/1]',
  532. )
  533. })
  534. })
  535. describe('flush', () => {
  536. test('simple call', () => {
  537. // @ts-ignore
  538. const repo = vi.fn() as Repository<ApiResource>
  539. // @ts-ignore
  540. entityManager.getRepository = vi.fn((model: typeof ApiResource) => {
  541. return model === DummyApiModel ? repo : null
  542. })
  543. repo.flush = vi.fn()
  544. entityManager.flush(DummyApiModel)
  545. expect(repo.flush).toHaveBeenCalled()
  546. })
  547. })
  548. describe('isNewEntity', () => {
  549. test('with new entity', () => {
  550. const entity = new DummyApiModel()
  551. entity.isNew = vi.fn(() => true)
  552. // @ts-ignore
  553. const repo = vi.fn() as Repository<ApiResource>
  554. // @ts-ignore
  555. entityManager.getRepository = vi.fn((model: typeof ApiResource) => {
  556. return model === DummyApiModel ? repo : null
  557. })
  558. // @ts-ignore
  559. repo.find = vi.fn((id: number) => entity)
  560. const result = entityManager.isNewInstance(DummyApiModel, 1)
  561. expect(result).toBeTruthy()
  562. })
  563. test('with existing entity', () => {
  564. const entity = new DummyApiModel()
  565. entity.isNew = vi.fn(() => false)
  566. // @ts-ignore
  567. const repo = vi.fn() as Repository<ApiResource>
  568. // @ts-ignore
  569. entityManager.getRepository = vi.fn((model: typeof ApiResource) => {
  570. return model === DummyApiModel ? repo : null
  571. })
  572. // @ts-ignore
  573. repo.find = vi.fn((id: number) => entity)
  574. const result = entityManager.isNewInstance(DummyApiModel, 1)
  575. expect(result).toBeFalsy()
  576. })
  577. test('non-existing entity', () => {
  578. // @ts-ignore
  579. const repo = vi.fn() as Repository<ApiResource>
  580. // @ts-ignore
  581. entityManager.getRepository = vi.fn((model: typeof ApiResource) => {
  582. return model === DummyApiModel ? repo : null
  583. })
  584. // @ts-ignore
  585. repo.find = vi.fn((id: number) => null)
  586. console.error = vi.fn()
  587. const result = entityManager.isNewInstance(DummyApiModel, 1)
  588. expect(result).toBeFalsy()
  589. expect(console.error).toHaveBeenCalledWith('dummyModel/1 does not exist!')
  590. })
  591. })
  592. describe('saveInitialState', () => {
  593. test('simple call', () => {
  594. // @ts-ignore
  595. const entity = { id: 1, name: 'bob' } as DummyApiResource
  596. // @ts-ignore
  597. const repo = vi.fn() as Repository<ApiResource>
  598. // @ts-ignore
  599. entityManager.getRepository = vi.fn((model: typeof ApiResource) => {
  600. return model === DummyApiResource ? repo : null
  601. })
  602. // @ts-ignore
  603. repo.save = vi.fn((record: Element) => null)
  604. // @ts-ignore
  605. entityManager.saveInitialState(DummyApiResource, entity)
  606. expect(repo.save).toHaveBeenCalledWith({ id: '_clone_1', name: 'bob' })
  607. expect(entity.id).toEqual(1)
  608. })
  609. })
  610. describe('getInitialStateOf', () => {
  611. test('with initial state', () => {
  612. // @ts-ignore
  613. const entity = { id: 1, name: 'bob' } as DummyApiResource
  614. // @ts-ignore
  615. const repo = vi.fn() as Repository<ApiResource>
  616. // @ts-ignore
  617. entityManager.getRepository = vi.fn((model: typeof ApiResource) => {
  618. return model === DummyApiResource ? repo : null
  619. })
  620. // @ts-ignore
  621. repo.find = vi.fn((id: number | string) => {
  622. // @ts-ignore
  623. return { id: 1, name: 'robert' } as DummyApiResource
  624. })
  625. // @ts-ignore
  626. const result = entityManager.getInitialStateOf(
  627. DummyApiResource,
  628. 1,
  629. ) as DummyApiResource
  630. expect(repo.find).toHaveBeenCalledWith('_clone_1')
  631. expect(result.id).toEqual(1)
  632. expect(result.name).toEqual('robert')
  633. })
  634. test('without initial state', () => {
  635. // @ts-ignore
  636. const repo = vi.fn() as Repository<ApiResource>
  637. // @ts-ignore
  638. entityManager.getRepository = vi.fn((model: typeof ApiResource) => {
  639. return model === DummyApiResource ? repo : null
  640. })
  641. // @ts-ignore
  642. repo.find = vi.fn((id: number | string) => null)
  643. // @ts-ignore
  644. const result = entityManager.getInitialStateOf(
  645. DummyApiResource,
  646. 1,
  647. ) as DummyApiResource
  648. expect(repo.find).toHaveBeenCalledWith('_clone_1')
  649. expect(result).toEqual(null)
  650. })
  651. })
  652. describe('removeTempAfterPersist', () => {
  653. test('simple call', () => {
  654. // @ts-ignore
  655. const entity = new DummyApiResource()
  656. entity.id = 'tmp123'
  657. entity.isNew = vi.fn(() => true)
  658. // @ts-ignore
  659. const repo = vi.fn() as Repository<ApiResource>
  660. // @ts-ignore
  661. entityManager.getRepository = vi.fn((model: typeof ApiResource) => {
  662. return model === DummyApiResource ? repo : null
  663. })
  664. // @ts-ignore
  665. repo.find = vi.fn((id: number | string) => entity)
  666. // @ts-ignore
  667. repo.destroy = vi.fn()
  668. // @ts-ignore
  669. entityManager.removeTempAfterPersist(DummyApiResource, 'tmp123')
  670. expect(repo.destroy).toHaveBeenCalledWith('tmp123')
  671. expect(repo.destroy).toHaveBeenCalledWith('_clone_tmp123')
  672. })
  673. test('entity is not temporary', () => {
  674. // @ts-ignore
  675. const entity = new DummyApiResource()
  676. entity.id = 1
  677. entity.isNew = vi.fn(() => false)
  678. // @ts-ignore
  679. const repo = vi.fn() as Repository<ApiResource>
  680. // @ts-ignore
  681. entityManager.getRepository = vi.fn((model: typeof ApiResource) => {
  682. return model === DummyApiResource ? repo : null
  683. })
  684. // @ts-ignore
  685. repo.find = vi.fn((id: number | string) => entity)
  686. // @ts-ignore
  687. repo.destroy = vi.fn()
  688. // @ts-ignore
  689. expect(() =>
  690. entityManager.removeTempAfterPersist(DummyApiResource, 'tmp123'),
  691. ).toThrowError('Error: Can not remove a non-temporary model instance')
  692. expect(repo.destroy).toHaveBeenCalledTimes(0)
  693. })
  694. test('entity does not exist', () => {
  695. // @ts-ignore
  696. const repo = vi.fn() as Repository<ApiResource>
  697. // @ts-ignore
  698. entityManager.getRepository = vi.fn((model: typeof ApiResource) => {
  699. return model === DummyApiResource ? repo : null
  700. })
  701. // @ts-ignore
  702. repo.find = vi.fn((id: number | string) => null)
  703. // @ts-ignore
  704. repo.destroy = vi.fn()
  705. console.error = vi.fn()
  706. // @ts-ignore
  707. entityManager.removeTempAfterPersist(DummyApiResource, 'tmp123')
  708. expect(repo.destroy).toHaveBeenCalledTimes(0)
  709. expect(console.error).toHaveBeenCalledWith(
  710. 'dummyResource/tmp123 does not exist!',
  711. )
  712. })
  713. })