UNPKG

@data-client/endpoint

Version:

Declarative Network Interface Definitions

286 lines (263 loc) 8.64 kB
// eslint-env jest import { MemoCache } from '@data-client/normalizr'; import { useQuery, useSuspense } from '@data-client/react'; import { RestEndpoint } from '@data-client/rest'; import { IDEntity } from '__tests__/new'; import { fromJS } from 'immutable'; import { schema, DenormalizeNullable } from '../..'; let dateSpy: jest.SpyInstance<number, []>; beforeAll(() => { dateSpy = jest .spyOn(global.Date, 'now') .mockImplementation(() => new Date('2019-05-14T11:01:58.135Z').valueOf()); }); afterAll(() => { dateSpy.mockRestore(); }); class User extends IDEntity { name = ''; isAdmin = false; } describe.each([ ['direct', <T>(data: T) => data, <T>(data: T) => data], [ 'immutable', fromJS, (v: any) => (typeof v?.toJS === 'function' ? v.toJS() : v), ], ])(`input (%s)`, (_, createInput, createOutput) => { const SCHEMA_CASES = [ ['All', new schema.Object({ results: new schema.All(User) })], [ 'Collection', new schema.Object({ results: new schema.Collection([User]) }), ], ] as const; if (_ === 'immutable') { delete (SCHEMA_CASES as any)[1]; } describe.each(SCHEMA_CASES)( `${schema.Query.name} denormalization (%s schema)`, (_, usersSchema) => { const sortedUsers = new schema.Query( usersSchema, ({ results }, { asc } = { asc: false }) => { if (!results) return results; const sorted = [...results].sort((a, b) => a.name.localeCompare(b.name), ); if (asc) return sorted; return sorted.reverse(); }, ); test('denormalize sorts', () => { const entities = { User: { 1: { id: '1', name: 'Milo' }, 2: { id: '2', name: 'Jake' }, 3: { id: '3', name: 'Zeta' }, 4: { id: '4', name: 'Alpha' }, }, [new schema.Collection([User]).key]: { [new schema.Collection([User]).pk(undefined, undefined, '', [])]: [ 1, 2, 3, 4, ], }, }; const users: DenormalizeNullable<typeof sortedUsers> | symbol = new MemoCache().query(sortedUsers, [], createInput(entities), {}); expect(users).not.toEqual(expect.any(Symbol)); if (typeof users === 'symbol') return; expect(users && users[0].name).toBe('Zeta'); expect(users).toMatchSnapshot(); }); test('denormalize sorts with arg', () => { const entities = { User: { 1: { id: '1', name: 'Milo' }, 2: { id: '2', name: 'Jake' }, 3: { id: '3', name: 'Zeta' }, 4: { id: '4', name: 'Alpha' }, }, [new schema.Collection([User]).key]: { [new schema.Collection([User]).pk(undefined, undefined, '', [ { asc: true }, ])]: [1, 2, 3, 4], }, }; expect( new MemoCache().query( sortedUsers, [{ asc: true }], createInput(entities), {}, ), ).toMatchSnapshot(); }); test('denormalizes should not be found when no entities are present', () => { const entities = { DOG: { 1: { id: '1', name: 'Milo' }, 2: { id: '2', name: 'Jake' }, }, }; const data = new MemoCache().query(sortedUsers, [], entities, {}); expect(createOutput(data)).toEqual(undefined); }); test('denormalize aggregates', () => { const userCountByAdmin = new schema.Query( usersSchema, ({ results }, { isAdmin }: { isAdmin?: boolean } = {}) => { if (!results) return 0; if (isAdmin === undefined) return results.length; return results.filter(user => user.isAdmin === isAdmin).length; }, ); const entities = { User: { 1: { id: '1', name: 'Milo' }, 2: { id: '2', name: 'Jake', isAdmin: true }, 3: { id: '3', name: 'Zeta' }, 4: { id: '4', name: 'Alpha' }, }, [new schema.Collection([User]).key]: { [new schema.Collection([User]).pk(undefined, undefined, '', [])]: [ 1, 2, 3, 4, ], [new schema.Collection([User]).pk(undefined, undefined, '', [ { isAdmin: false }, ])]: [1, 3, 4], [new schema.Collection([User]).pk(undefined, undefined, '', [ { isAdmin: true }, ])]: [2], }, }; const totalCount: | DenormalizeNullable<typeof userCountByAdmin> | symbol = new MemoCache().query( userCountByAdmin, [], createInput(entities), {}, ); expect(totalCount).toBe(4); const nonAdminCount: | DenormalizeNullable<typeof userCountByAdmin> | symbol = new MemoCache().query( userCountByAdmin, [{ isAdmin: false }], createInput(entities), {}, ); expect(nonAdminCount).toBe(3); const adminCount: | DenormalizeNullable<typeof userCountByAdmin> | symbol = new MemoCache().query( userCountByAdmin, [{ isAdmin: true }], createInput(entities), {}, ); expect(adminCount).toBe(1); if (typeof totalCount === 'symbol') return; // typecheck totalCount !== undefined && totalCount + 5; // @ts-expect-error totalCount?.bob; }); }, ); }); describe('top level schema', () => { const sortedUsers = new schema.Query( new schema.Collection([User]), (results, { asc } = { asc: false }, ...args) => { const sorted = [...results].sort((a, b) => a.name.localeCompare(b.name)); if (asc) return sorted; return sorted.reverse(); }, ); test('denormalize sorts', () => { const entities = { User: { 1: { id: '1', name: 'Milo' }, 2: { id: '2', name: 'Jake' }, 3: { id: '3', name: 'Zeta' }, 4: { id: '4', name: 'Alpha' }, }, [new schema.Collection([User]).key]: { [new schema.Collection([User]).pk({}, undefined, '', [])]: [1, 2, 3, 4], }, }; const users = new MemoCache().query(sortedUsers, [], entities, {}); expect(users).not.toEqual(expect.any(Symbol)); if (typeof users === 'symbol') return; expect(users && users[0].name).toBe('Zeta'); expect(users).toMatchSnapshot(); }); test('works if base entity suspends', () => { const entities = { User: { 1: { id: '1', name: 'Milo' }, 2: { id: '2', name: 'Jake' }, 3: { id: '3', name: 'Zeta' }, 4: { id: '4', name: 'Alpha' }, }, }; const users = new MemoCache().query(sortedUsers, [], entities, {}); expect(users).toBeUndefined(); }); test('works if base entity suspends', () => { const allSortedUsers = new schema.Query( new schema.All(User), (results, { asc } = { asc: false }, ...args) => { const sorted = [...results].sort((a, b) => a.name.localeCompare(b.name), ); if (asc) return sorted; return sorted.reverse(); }, ); const users = new MemoCache().query(allSortedUsers, [], {}, {}); expect(users).toBeUndefined(); }); test('works with nested schemas', () => { const allSortedUsers = new schema.Query( new schema.All(User), (results, { asc } = { asc: false }, ...args) => { const sorted = [...results].sort((a, b) => a.name.localeCompare(b.name), ); if (asc) return sorted; return sorted.reverse(); }, ); const users = new MemoCache().query(allSortedUsers, [], {}, {}); expect(users).toBeUndefined(); }); test('denormalizes should not be found when no entities are present', () => { const entities = { DOG: { 1: { id: '1', name: 'Milo' }, 2: { id: '2', name: 'Jake' }, }, }; const value = new MemoCache().query(sortedUsers, [], entities, {}); expect(value).toEqual(undefined); }); test('', () => { const getUsers = new RestEndpoint({ path: '/users', searchParams: {} as { asc?: boolean }, schema: sortedUsers, }); () => { const users = useSuspense(getUsers, { asc: true }); users.map(user => user.name); const others = useQuery(getUsers.schema, { asc: true }); // @ts-expect-error others.map(user => user.name); others?.map(user => user.name); }; }); });