| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537 |
- import { vi, describe, test, it, expect, afterEach } from 'vitest'
- import type {AnyJson} from "~/types/data";
- import HydraNormalizer from "~/services/data/normalizer/hydraNormalizer";
- import {METADATA_TYPE} from "~/types/enum/data";
- import ApiModel from "~/models/ApiModel";
- import {Str, Uid, Attr} from "pinia-orm/dist/decorators";
- import {IriEncoded} from "~/models/decorators";
- import UrlUtils from "~/services/utils/urlUtils";
- import ApiResource from "~/models/ApiResource";
- class DummyApiChild extends ApiModel {
- static entity = 'dummyChild'
- @Uid()
- declare id: number | string
- }
- class DummyApiModel extends ApiModel {
- static entity = 'dummyModel'
- @Uid()
- declare id: number | string
- @Attr(null)
- @IriEncoded(DummyApiChild)
- declare oneToOneRelation: number | null
- @Attr([])
- @IriEncoded(DummyApiChild)
- declare oneToManyRelation: []
- @Str(null)
- declare name: null
- }
- afterEach(() => {
- vi.clearAllMocks();
- vi.resetAllMocks();
- });
- describe('normalize', () => {
- const initialMakeUriMethod = UrlUtils.makeIRI
- afterEach(() => {
- UrlUtils.makeIRI = initialMakeUriMethod
- })
- test('should normalize an entity into a JSON Object', () => {
- const entity: DummyApiModel = new DummyApiModel({
- id: 7351,
- oneToOneRelation: 99,
- oneToManyRelation: [123, 124, 125]
- })
- //@ts-ignore
- UrlUtils.makeIRI = vi.fn(
- (targetEntity, id) => {
- return {
- 99: '/api/dummyChild/99',
- 123: '/api/dummyChild/123',
- 124: '/api/dummyChild/124',
- 125: '/api/dummyChild/125',
- }[id]
- }
- )
- const result = HydraNormalizer.normalizeEntity(entity)
- const expected = {
- id: 7351,
- name: null,
- oneToOneRelation: '/api/dummyChild/99',
- oneToManyRelation: ['/api/dummyChild/123', '/api/dummyChild/124', '/api/dummyChild/125']
- }
- expect(result).toStrictEqual(expected)
- })
- })
- describe('denormalize', () => {
- //@ts-ignore
- const initialGetDataMethod = HydraNormalizer.getData
- //@ts-ignore
- const initialGetMetadataMethod = HydraNormalizer.getMetadata
- afterEach(() => {
- //@ts-ignore
- HydraNormalizer.getData = initialGetDataMethod
- //@ts-ignore
- HydraNormalizer.getMetadata = initialGetMetadataMethod
- })
- test('should parse a API Item response and return a JSON Object', () => {
- const data: AnyJson = { id: 1, name: 'foo' };
- //@ts-ignore
- HydraNormalizer.getData = vi.fn((data, model) => {
- return data
- })
- //@ts-ignore
- HydraNormalizer.getMetadata = vi.fn((data, model) => {
- return { "type": METADATA_TYPE.ITEM }
- })
- const result = HydraNormalizer.denormalize(data, DummyApiModel)
- const expected = {
- "data": {
- id: 1,
- name: 'foo',
- },
- "metadata": {
- "type": METADATA_TYPE.ITEM
- }
- }
- expect(result).toEqual(expected)
- })
- })
- describe('getData', () => {
- test('With collection', () => {
- const data = {
- "@context": "/api/contexts/Foo",
- "@id": "/api/foo",
- "@type": "hydra:Collection",
- "hydra:member": [ 'foo' ],
- }
- // @ts-ignore
- expect(HydraNormalizer.getData(data)).toEqual([ 'foo' ])
- })
- test('With item', () => {
- const data = {
- "@context": "/api/contexts/Foo",
- "@id": "/api/foo",
- "@type": "Foo",
- "param1": 'a',
- }
- // @ts-ignore
- expect(HydraNormalizer.getData(data)).toEqual(data)
- })
- })
- describe('getMetadata', () => {
- test('With valid collection metadata', () => {
- const data = {
- "@context": "/api/contexts/Foo",
- "@id": "/api/foo",
- "@type": "hydra:Collection",
- "hydra:member": [ 'foo' ],
- "hydra:totalItems": 10,
- "hydra:view": {
- "@id": "/api/foo?page=3",
- "@type": "hydra:PartialCollectionView",
- "hydra:first": "/api/foo?page=1",
- "hydra:last": "/api/foo?page=5",
- "hydra:next": "/api/foo?page=4",
- "hydra:previous": "/api/foo?page=2"
- }
- }
- // @ts-ignore
- const metadata = HydraNormalizer.getMetadata(data)
- expect(metadata.totalItems).toEqual(10)
- expect(metadata.firstPage).toEqual(1)
- expect(metadata.lastPage).toEqual(5)
- expect(metadata.nextPage).toEqual(4)
- expect(metadata.previousPage).toEqual(2)
- expect(metadata.type).toEqual(METADATA_TYPE.COLLECTION)
- })
- test('With partial collection metadata', () => {
- const data = {
- "@context": "/api/contexts/Foo",
- "@id": "/api/foo",
- "@type": "hydra:Collection",
- "hydra:member": [ 'foo' ],
- "hydra:totalItems": 10,
- "hydra:view": {
- "@id": "/api/foo?page=3",
- "@type": "hydra:PartialCollectionView",
- "hydra:first": "/api/foo?page=1",
- }
- }
- // @ts-ignore
- const metadata = HydraNormalizer.getMetadata(data)
- expect(metadata.totalItems).toEqual(10)
- expect(metadata.firstPage).toEqual(1)
- expect(metadata.lastPage).toEqual(1)
- expect(metadata.nextPage).toEqual(undefined)
- expect(metadata.previousPage).toEqual(undefined)
- })
- test('With item metadata', () => {
- // @ts-ignore
- const metadata = HydraNormalizer.getMetadata({})
- expect(metadata.type).toEqual(METADATA_TYPE.ITEM)
- })
- })
- describe('denormalizeItem', () => {
- //@ts-ignore
- const initialDenormalizeEntity = HydraNormalizer.denormalizeEntity
- //@ts-ignore
- const initialDenormalizeEnum = HydraNormalizer.denormalizeEnum
- //@ts-ignore
- const initialParseEntityIRI = HydraNormalizer.parseEntityIRI
- const initialConsoleError = console.error
- afterEach(() => {
- //@ts-ignore
- HydraNormalizer.denormalizeEntity = initialDenormalizeEntity
- //@ts-ignore
- HydraNormalizer.denormalizeEnum = initialDenormalizeEnum
- //@ts-ignore
- HydraNormalizer.parseEntityIRI = initialParseEntityIRI
- console.error = initialConsoleError
- })
- test('With provided model', () => {
- const item = {
- '@id': '/api/dummyModel/1',
- id: 1,
- name: 'foo'
- }
- const model = DummyApiModel
- const expected = new DummyApiModel(item)
- //@ts-ignore
- HydraNormalizer.denormalizeEntity = vi.fn((model, item) => {
- return expected
- })
- //@ts-ignore
- const result = HydraNormalizer.denormalizeItem(item, model)
- expect(result).toEqual(expected)
- //@ts-ignore
- expect(HydraNormalizer.denormalizeEntity).toHaveBeenCalledWith(model, item)
- })
- test('with no @id prop', () => {
- const item = {
- id: 1,
- name: 'foo'
- }
- console.error = vi.fn((msg) => {})
- //@ts-ignore
- const result = HydraNormalizer.denormalizeItem(item)
- expect(result).toEqual(item)
- expect(console.error).toHaveBeenCalledWith(
- 'De-normalization error : the item is not hydra formatted',
- item
- )
- })
- test('with enum', () => {
- const item = {
- '@id': '/api/enum/abc',
- A: 1,
- B: 2,
- C: 3
- }
- //@ts-ignore
- HydraNormalizer.denormalizeEnum = vi.fn((item) => {
- return item
- })
- //@ts-ignore
- const result = HydraNormalizer.denormalizeItem(item)
- expect(result).toEqual(item)
- //@ts-ignore
- expect(HydraNormalizer.denormalizeEnum).toHaveBeenCalledWith(item)
- })
- test('with unparsable iri', () => {
- const item = {
- '@id': 'some_invalid_iri',
- id: 1,
- name: 'foo'
- }
- //@ts-ignore
- HydraNormalizer.parseEntityIRI = vi.fn((iri) => {
- throw('parsing error')
- })
- console.error = vi.fn((msg) => {})
- //@ts-ignore
- const result = HydraNormalizer.denormalizeItem(item)
- expect(result).toEqual(item)
- //@ts-ignore
- expect(console.error).toHaveBeenCalledWith(
- 'De-normalization error : could not parse the IRI',
- item
- )
- })
- test('With valid iri and existing model', () => {
- HydraNormalizer.models = {
- 'dummyModel': DummyApiModel
- }
- const item = {
- '@id': '/api/dummyModel/1',
- id: 1,
- name: 'foo'
- }
- //@ts-ignore
- HydraNormalizer.parseEntityIRI = vi.fn((iri) => {
- return { entity: 'dummyModel' }
- })
- const expected = new DummyApiModel(item)
- //@ts-ignore
- HydraNormalizer.denormalizeEntity = vi.fn((model, item) => {
- return expected
- })
- //@ts-ignore
- const result = HydraNormalizer.denormalizeItem(item)
- expect(result).toEqual(expected)
- //@ts-ignore
- expect(HydraNormalizer.denormalizeEntity).toHaveBeenCalledWith(DummyApiModel, item)
- })
- test('With valid iri and un-existing model', () => {
- HydraNormalizer.models = {
- 'dummyModel': DummyApiModel
- }
- const item = {
- '@id': '/api/unknownModel/1',
- id: 1,
- name: 'foo'
- }
- //@ts-ignore
- HydraNormalizer.parseEntityIRI = vi.fn((iri) => {
- return 'unknownModel'
- })
- expect(
- //@ts-ignore
- () => HydraNormalizer.denormalizeItem(item)
- ).toThrowError()
- })
- })
- describe('denormalizeEntity', () => {
- //@ts-ignore
- const initialGetIdFromEntityIriMethod = HydraNormalizer.getIdFromEntityIri
- afterEach(() => {
- //@ts-ignore
- HydraNormalizer.getIdFromEntityIri = initialGetIdFromEntityIriMethod
- })
- test('should denormalize a Json object into an entity', () => {
- const data = {
- id: 7351,
- name: null,
- oneToOneRelation: '/api/dummyChild/99',
- oneToManyRelation: ['/api/dummyChild/123', '/api/dummyChild/124', '/api/dummyChild/125']
- }
- //@ts-ignore
- HydraNormalizer.getIdFromEntityIri = vi.fn((iri) => {
- return {
- '/api/dummyChild/99': 99,
- '/api/dummyChild/123': 123,
- '/api/dummyChild/124': 124,
- '/api/dummyChild/125': 125
- }[iri]
- })
- //@ts-ignore
- const result = HydraNormalizer.denormalizeEntity(DummyApiModel, data)
- expect(result).toStrictEqual(new DummyApiModel({
- id: 7351,
- name: null,
- oneToOneRelation: 99,
- oneToManyRelation: [123, 124, 125]
- }))
- })
- test('should ignore relations fields when missing in the incoming data', () => {
- const data = {
- id: 7351,
- name: 'Bob',
- oneToManyRelation: ['/api/dummyChild/123', '/api/dummyChild/124', '/api/dummyChild/125']
- }
- //@ts-ignore
- HydraNormalizer.getIdFromEntityIri = vi.fn((iri) => {
- return {
- '/api/dummyChild/123': 123,
- '/api/dummyChild/124': 124,
- '/api/dummyChild/125': 125
- }[iri]
- })
- //@ts-ignore
- const result = HydraNormalizer.denormalizeEntity(DummyApiModel, data)
- expect(result).toStrictEqual(new DummyApiModel({
- id: 7351,
- name: "Bob",
- oneToOneRelation: null,
- oneToManyRelation: [123, 124, 125]
- }))
- })
- test('should handle relations with empty values', () => {
- const data = {
- id: 7351,
- name: null,
- oneToOneRelation: null,
- oneToManyRelation: []
- }
- //@ts-ignore
- HydraNormalizer.getIriEncodedFields = vi.fn(
- (entity) => {
- return {
- oneToOneRelation: DummyApiChild,
- oneToManyRelation: DummyApiChild
- }
- }
- )
- //@ts-ignore
- const result = HydraNormalizer.denormalizeEntity(DummyApiModel, data)
- expect(result).toStrictEqual(new DummyApiModel({
- id: 7351,
- name: null,
- oneToOneRelation: null,
- oneToManyRelation: []
- }))
- })
- })
- describe('denormalizeEnum', () => {
- test('does nothing', () => {
- const item = {
- '@id': '/api/enum/abc',
- A: 1,
- B: 2,
- C: 3
- }
- //@ts-ignore
- expect(HydraNormalizer.denormalizeEnum(item)).toStrictEqual(item)
- })
- })
- describe('parseEntityIRI', () => {
- test('valid iri', () => {
- const iri = '/api/someEntity/456'
- const expected = {
- entity: 'someEntity',
- id: 456
- }
- //@ts-ignore
- expect(HydraNormalizer.parseEntityIRI(iri)).toStrictEqual(expected)
- })
- test('invalid iri', () => {
- const iri = 'some_invalid_iri'
- //@ts-ignore
- expect(() => HydraNormalizer.parseEntityIRI(iri)).toThrowError('could not parse the IRI : "some_invalid_iri"')
- })
- })
- describe('getIdFromEntityIri', () => {
- //@ts-ignore
- const initialParseEntityIRI = HydraNormalizer.parseEntityIRI
- afterEach(() => {
- //@ts-ignore
- HydraNormalizer.parseEntityIRI = initialParseEntityIRI
- })
- test('valid iri', () => {
- const iri = '/api/someEntity/456'
- //@ts-ignore
- const result = HydraNormalizer.getIdFromEntityIri(iri, 'someEntity')
- expect(result).toEqual(456)
- })
- test('entity not matching', () => {
- const iri = '/api/someEntity/456'
- //@ts-ignore
- expect(
- //@ts-ignore
- () => HydraNormalizer.getIdFromEntityIri(iri, 'otherEntity')
- ).toThrowError("IRI entity does not match the field's target entity (someEntity != otherEntity)")
- })
- })
|