validated-changeset
Version:
Changesets for your local state
438 lines (363 loc) • 11.2 kB
text/typescript
import setDeep from '../../src/utils/set-deep';
import Change from '../../src/-private/change';
describe('Unit | Utility | set deep', () => {
it('it sets value', () => {
const objA = { other: 'Ivan' };
const value = setDeep(objA, 'foo', 'bar');
expect(value).toEqual({ other: 'Ivan', foo: 'bar' });
});
it('it sets deeper', () => {
const objA = { other: 'Ivan' };
const value = setDeep(objA, 'other.nick', 'bar');
expect(value).toEqual({ other: { nick: 'bar' } });
});
it('it overrides leaf key', () => {
const objA = { name: { other: 'Ivan' } };
const value = setDeep(objA, 'name', 'foo');
expect(value).toEqual({ name: 'foo' });
});
it('handles null case', () => {
const objA = { name: { other: 'Ivan', nick: null } };
const value = setDeep(objA, 'name.other', null);
expect(value).toEqual({ name: { other: null, nick: null } });
});
it('handles booleans', () => {
const objA = { name: [{ nick: false }] };
const value = setDeep(objA, 'name.0.nick', true);
expect(value).toEqual({ name: [{ nick: true }] });
const value2 = setDeep(value, 'name.0.nick', false);
expect(value2).toEqual({ name: [{ nick: false }] });
});
it('handles function case', () => {
const objA = { name: { other: 'Ivan' } };
const anon = () => {};
const value = setDeep(objA, 'name.other', anon);
expect(value).toEqual({ name: { other: anon } });
});
it('it handles nested key', () => {
const objA = { name: { other: 'Ivan' } };
const value = setDeep(objA, 'name.other', 'foo');
expect(value).toEqual({ name: { other: 'foo' } });
});
it('handles existing arrays', () => {
const objA = { entries: [{ prop: 'foo' }] };
const value = setDeep(objA, 'entries.0.prop', 'bar');
expect(value).toEqual({ entries: [{ prop: 'bar' }] });
});
it('inserts data into existing arrays', () => {
const objA = { entries: [{ prop: 'foo' }] };
const value = setDeep(objA, 'entries.1.prop', 'bar');
expect(value).toEqual({ entries: [{ prop: 'foo' }, { prop: 'bar' }] });
});
it('inserts data into empty arrays', () => {
const objA = { entries: [] };
const value = setDeep(objA, 'entries.0.prop', 'bar');
expect(value).toEqual({ entries: [{ prop: 'bar' }] });
});
it('does not allow inserting into arrays at negative values', () => {
const objA = { entries: [] };
expect(() => {
setDeep(objA, 'entries.-1.prop', 'bar');
}).toThrow(
'Negative indices are not allowed as arrays do not serialize values at negative indices'
);
});
it('inserts primitive types into existing arrays', () => {
const objA = { entries: ['foo'] };
const value = setDeep(objA, 'entries.1', 'bar');
expect(value).toEqual({ entries: ['foo', 'bar'] });
});
it('inserts primitive types into empty arrays', () => {
const objA = { entries: [] };
const value = setDeep(objA, 'entries.0', 'bar');
expect(value).toEqual({ entries: ['bar'] });
});
it('it does not lose sibling keys', () => {
const objA = {
name: {
other: 'Ivan',
koala: 'bear',
location: {
state: 'MN',
zip: '45554'
}
},
star: 'wars'
};
let value = setDeep(objA, 'name.other', 'foo');
value = setDeep(objA, 'name.location.state', 'CO');
const expected = {
name: {
other: 'foo',
koala: 'bear',
location: {
state: 'CO',
zip: '45554'
}
},
star: 'wars'
};
expect(value).toEqual(expected);
});
it('it works with multiple values', () => {
const objA = { name: { other: 'Ivan' }, foo: { other: 'bar' } };
const value = setDeep(objA, 'name', 'zoo');
expect(value).toEqual({ foo: { other: 'bar' }, name: 'zoo' });
});
it('it works with nested multiple values', () => {
const objA = { top: { name: 'jimmy', foo: { other: 'bar' } } };
const value = setDeep(objA, 'top.name', 'zoo');
expect(value).toEqual({ top: { foo: { other: 'bar' }, name: 'zoo' } });
});
it('it works with nested multiple values with Changes', () => {
const objA = {
top: new Change({ name: 'jimmy', foo: { other: 'bar' } })
};
const value = setDeep(objA, 'top.name', 'zoo');
expect(value).toEqual({
top: new Change({
foo: { other: 'bar' },
name: 'zoo'
})
});
});
it('it works with nested Changes', () => {
const objA = {
top: new Change({ name: 'jimmy', foo: { other: 'bar' } })
};
const value = setDeep(objA, 'top.name', new Change('zoo'));
expect(value).toEqual({
top: new Change({
foo: { other: 'bar' },
name: 'zoo' // value is not a Change instance
})
});
});
it('it works with nested Changes null', () => {
const objA = {
top: new Change({ name: 'jimmy', foo: { other: null } })
};
let value = setDeep(objA, 'top.name', new Change(null));
value = setDeep(objA, 'top.foo', new Change(null));
expect(value).toEqual({
top: new Change({
foo: null,
name: null
})
});
});
it('sets changes to undefined values', () => {
const objA = {
contacts: {
0: new Change({ emails: { primary: 'sanholo@email.com' } }),
1: { emails: { primary: 'fred@email.com' } }
}
};
let value = setDeep(objA, 'contacts.0', new Change(null));
expect(value).toEqual({
contacts: {
0: new Change(null),
1: {
emails: { primary: 'fred@email.com' }
}
}
});
});
it('it works with nested Changes with different order', () => {
const objA = {
top: new Change({ foo: { other: 'bar' }, name: 'jimmy' })
};
const value = setDeep(objA, 'top.name', new Change('zoo'));
expect(value).toEqual({
top: new Change({
foo: { other: 'bar' },
name: 'zoo' // value is not a Change instance
})
});
});
it('it works with nested Changes with different order', () => {
const objA = {
top: new Change({ foo: { other: 'bar' }, name: 'jimmy' })
};
const value = setDeep(objA, 'top.name', new Change('zoo'));
expect(value).toEqual({
top: new Change({
foo: { other: 'bar' },
name: 'zoo' // value is not a Change instance
})
});
});
it('set on nested Changes', () => {
const objA = {
top: new Change({ foo: { other: 'bar' }, name: 'jimmy' })
};
let value = setDeep(objA, 'top.name', new Change('zoo'));
expect(value).toEqual({
top: new Change({
foo: { other: 'bar' },
name: 'zoo' // value is not a Change instance
})
});
value = setDeep(value, 'top.foo.other', new Change('baz'));
expect(value).toEqual({
top: new Change({
foo: { other: 'baz' },
name: 'zoo'
})
});
});
it('set on nested properties within an empty object', () => {
const objA = {
top: {}
};
let value = setDeep(objA, 'top.name', new Change('zoo'));
expect(value).toEqual({
top: {
name: new Change('zoo')
}
});
value = setDeep(value, 'top.foo.other', new Change('baz'));
expect(value).toEqual({
top: {
name: new Change('zoo'),
foo: {
other: new Change('baz')
}
}
});
});
describe('arrays at various nestings within an object', () => {
describe('array nested one level deep', () => {
it('sets when teh array is initially empty', () => {
const objA = {
top: []
};
let value = setDeep(objA, 'top.0.name', new Change('zoo'));
expect(value).toEqual({
top: [{ name: new Change('zoo') }]
});
value = setDeep(value, 'top.0.foo.other', new Change('baz'));
expect(value).toEqual({
top: [
{
name: new Change('zoo'),
foo: {
other: new Change('baz')
}
}
]
});
});
it('sets with existing changes', () => {
const objA = {
top: [new Change({ foo: { other: 'bar' }, name: 'jimmy' })]
};
let value = setDeep(objA, 'top.0.name', new Change('zoo'));
expect(value).toEqual({
top: [
new Change({
foo: { other: 'bar' },
name: 'zoo' // value is not a Change instance
})
]
});
value = setDeep(value, 'top.0.foo.other', new Change('baz'));
expect(value).toEqual({
top: [
new Change({
foo: { other: 'baz' },
name: 'zoo'
})
]
});
});
});
});
describe('faux arrays at various nestings within an object', () => {
describe('faux array deeply nested', () => {
it('works with existing changes', () => {
const objA = {
contact: {
emails: {
1: new Change({ funEmail: 'fun@email.com', primary: 'primary@email.com' })
}
}
};
let value = setDeep(objA, 'contact.emails.1.primary', new Change('primary2@email.com'));
expect(value).toEqual({
contact: {
emails: {
1: new Change({
funEmail: 'fun@email.com',
primary: 'primary2@email.com'
})
}
}
});
});
});
});
it('set with class instances', () => {
class Person {
name = 'baz';
}
const objA = {
top: new Change({ foo: { other: 'bar' }, name: 'jimmy' })
};
let value = setDeep(objA, 'top.name', new Change(new Person()));
expect(value).toEqual({
top: new Change({
foo: { other: 'bar' },
name: new Person()
})
});
class Foo {
other = 'baz';
}
value = setDeep(value, 'top.foo', new Change(new Foo()));
expect(value).toEqual({
top: new Change({
foo: new Foo(),
name: new Person()
})
});
});
it('super deep set does not lose siblings', () => {
const resource = {
styles: {
colors: {
main: {
sync: true,
color: '#3D3D3D',
contrastColor: '#FFFFFF',
syncedColor: '#575757',
syncedContrastColor: '#FFFFFF'
},
accent: {
sync: true,
color: '#967E6E',
contrastColor: '#ffffff',
syncedColor: '#967E6E',
syncedContrastColor: '#ffffff'
},
ambient: {
sync: true,
color: '#FFFFFF',
contrastColor: '#3D3D3D',
syncedColor: '#FFFFFF',
syncedContrastColor: '#575757'
}
}
}
};
setDeep(resource, 'styles.colors.main.sync', false);
const value = resource.styles.colors.main;
expect(value).toEqual({
sync: false,
color: '#3D3D3D',
contrastColor: '#FFFFFF',
syncedColor: '#575757',
syncedContrastColor: '#FFFFFF'
});
});
});