entityManager.test.ts 24 KB

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