@data-client/normalizr
Version:
Normalizes and denormalizes JSON according to schema for Redux and Flux applications
114 lines (99 loc) • 2.78 kB
text/typescript
// eslint-env jest
import { Entity, schema } from '@data-client/endpoint';
import { fromJS, Record, Map } from 'immutable';
import { normalize } from '..';
import { denormalize } from '../denormalize/denormalize.imm';
export function fromJSEntities(entities: {
[k: string]: { [k: string]: any };
}) {
return Map(entities).map(v => Map(v));
}
export function fromJSState(state: {
entities: {
[k: string]: { [k: string]: any };
};
indexes: {
[k: string]: { [k: string]: { [field: string]: string } };
};
}) {
return {
entities: fromJSEntities(state.entities),
indexes: fromJS(state.indexes),
};
}
class IDEntity extends Entity {
id = '';
pk(parent, key) {
return this.id || key;
}
}
class Tacos extends IDEntity {
type = '';
}
let dateSpy;
beforeAll(() => {
dateSpy = jest
.spyOn(global.Date, 'now')
.mockImplementation(() => new Date('2019-05-14T11:01:58.135Z').valueOf());
});
afterAll(() => {
dateSpy.mockRestore();
});
describe('immutableJS', () => {
class Food extends schema.EntityMixin(
class {
id = '';
},
) {}
class MenuData {
id = '';
food = Food.fromJS();
}
class Menu extends schema.EntityMixin(MenuData, {
schema: { food: Food },
}) {}
test('can normalize', () => {
const state = fromJS({
entities: { Food: {}, Menu: {} },
});
const v = normalize(Menu, {
id: '1',
food: { id: '1', extra: 'hi' },
});
// console.log(v);
const entities = state.mergeDeep(fromJS(v.entities));
// console.log(entities.getIn(['Menu', '1']));
// expect(denormalize(Menu, '1', entities)).toMatchSnapshot();
// expect(denormalize(Menu, '1', fromJS(entities))).toMatchSnapshot();
});
test('can denormalize already partially denormalized data', () => {
const entities = Map({
Menu: Map({
1: { id: '1', food: { id: '1' } },
}),
Food: Map({
// TODO: BREAKING CHANGE: Update this to use main entity and only return nested as 'fallback' in case main entity is not set
1: { id: '1', extra: 'hi' },
}),
});
expect(denormalize(Menu, '1', entities)).toMatchSnapshot();
});
test('denormalizes deep entities with records', () => {
const Food = Record<{ id: null | string }>({ id: null });
const MenuR = Record<{ id: null | string; food: null | string }>({
id: null,
food: null,
});
const entities = {
Menu: {
'1': new MenuR({ id: '1', food: '1' }),
'2': new MenuR({ id: '2' }),
},
Food: {
'1': new Food({ id: '1' }),
},
};
expect(denormalize(Menu, '1', fromJSEntities(entities))).toMatchSnapshot();
expect(denormalize(Menu, '2', fromJSEntities(entities))).toMatchSnapshot();
});
});