js-object-util
Version:
A simple utility to access nested JSON object properties, including arrays. Inspired by Immutable API methods like hasIn and getIn.
364 lines (304 loc) • 12.5 kB
JavaScript
;
var ObjectUtil = require('../object_util');
jest.unmock('../object_util');
const book = {
publisher: {
name: "dpunkt",
address: {
city: "Heidelberg",
plz: 69123
}
},
title : "React",
year: 2015,
properties: {
includes_ebook: false,
whatever: null,
dunno: undefined
},
readers: [
{
type: "user",
name: "Johnny",
age: 32,
nickname: null
},
{
type: "user",
name: "Brad",
age: 13,
nickname: "Bratze"
}
]
};
const empty_book = {};
const almost_empty_book = {
is_cc_licensed: true
};
describe('Check for existence of keys in objects', function () {
it('properly detects existing keys', function () {
expect(ObjectUtil.hasIn(book, ['publisher', 'address', 'city'])).toBe(true);
expect(ObjectUtil.hasIn(book, ['title'])).toBe(true);
expect(ObjectUtil.hasIn(book, ['properties', 'includes_ebook'])).toBe(true);
expect(ObjectUtil.hasIn(book, ['properties', 'whatever'])).toBe(true);
expect(ObjectUtil.hasIn(book, ['properties', 'dunno'])).toBe(true);
});
it('properly detects absence of keys', function () {
expect(ObjectUtil.hasIn(book, ['publisher', 'address', 'notthere'])).toBe(false);
});
});
describe('Check for existence of keys in arrays nested in the objects', function () {
it('properly detects array elements', function () {
expect(ObjectUtil.hasIn(book, ['readers', '0'])).toBe(true);
expect(ObjectUtil.hasIn(book, ['readers', '1'])).toBe(true);
expect(ObjectUtil.hasIn(book, ['readers', '2'])).toBe(false);
expect(ObjectUtil.hasIn(book, ['readers', '0', 'name'])).toBe(true);
expect(ObjectUtil.hasIn(book, ['readers', '0', 'age'])).toBe(true);
expect(ObjectUtil.hasIn(book, ['readers', '0', 'nickname'])).toBe(true);
expect(ObjectUtil.hasIn(book, ['readers', '0', 'notthere'])).toBe(false);
});
it('properly detects array elements based on integers instead of strings as keys', function () {
expect(ObjectUtil.hasIn(book, ['readers', 0])).toBe(true);
expect(ObjectUtil.hasIn(book, ['readers', 1])).toBe(true);
});
it('properly detects absence of keys', function () {
expect(ObjectUtil.hasIn(book, ['publisher', 'address', 'notthere'])).toBe(false);
expect(ObjectUtil.hasIn(book, ['readers', 3])).toBe(false);
});
it('properly handles broken array keys', function () {
expect(ObjectUtil.hasIn(book, ['readers', 1])).toBe(true);
expect(ObjectUtil.hasIn(book, ['readers', 'nonumber'])).toBe(false);
expect(ObjectUtil.hasIn(book, ['readers', '1,1'])).toBe(false);
});
});
describe('Check for existence of non-null and defined keys in objects', function () {
it('properly detects existing non-null and defined keys', function () {
expect(ObjectUtil.hasDefinedAndNonNullIn(book, ['publisher', 'address', 'city'])).toBe(true);
expect(ObjectUtil.hasDefinedAndNonNullIn(book, ['title'])).toBe(true);
expect(ObjectUtil.hasDefinedAndNonNullIn(book, ['properties', 'includes_ebook'])).toBe(true);
expect(ObjectUtil.hasDefinedAndNonNullIn(book, ['properties', 'whatever'])).toBe(false);
expect(ObjectUtil.hasDefinedAndNonNullIn(book, ['properties', 'dunno'])).toBe(false);
});
it('properly detects absence of non-null and undefined keys', function () {
expect(ObjectUtil.hasDefinedAndNonNullIn(book, ['publisher', 'address', 'notthere'])).toBe(false);
});
});
describe('Check retrieval of nested keys in objects', function () {
it('properly retrieves keys', function () {
expect(ObjectUtil.getIn(book, ['title'])).toBe("React");
expect(ObjectUtil.getIn(book, ['year'])).toBe(2015);
expect(ObjectUtil.getIn(book, ['publisher', 'address', 'city'])).toBe("Heidelberg");
expect(ObjectUtil.getIn(book, ['properties', 'includes_ebook'])).toBe(false);
expect(ObjectUtil.getIn(book, ['properties', 'whatever'])).toBeNull();
expect(ObjectUtil.getIn(book, ['properties', 'dunno'])).toBeUndefined();
});
});
describe('Check retrieval of whole arrays', function () {
it('properly retrieves whole arrays', function () {
expect(Object.prototype.toString.call( ObjectUtil.getIn(book, ['readers']) ) === '[object Array]').toBe(true);
});
});
describe('Check string representation of integer test function', function () {
it('properly accepts simple numbers', function () {
expect(ObjectUtil._stringRepresentsPositiveIntegerIncludingZero('0')).toBe(true);
expect(ObjectUtil._stringRepresentsPositiveIntegerIncludingZero('1')).toBe(true);
expect(ObjectUtil._stringRepresentsPositiveIntegerIncludingZero('13453256236')).toBe(true);
});
it('properly rejects negative numbers', function () {
expect(ObjectUtil._stringRepresentsPositiveIntegerIncludingZero('-1')).toBe(false);
expect(ObjectUtil._stringRepresentsPositiveIntegerIncludingZero('-13243443.56')).toBe(false);
});
it('properly rejects strings which do not represent numbers', function () {
expect(ObjectUtil._stringRepresentsPositiveIntegerIncludingZero('1,1')).toBe(false);
expect(ObjectUtil._stringRepresentsPositiveIntegerIncludingZero('wohlkaum')).toBe(false);
});
it('properly rejects strings representing floats', function () {
expect(ObjectUtil._stringRepresentsPositiveIntegerIncludingZero('1.1')).toBe(false);
expect(ObjectUtil._stringRepresentsPositiveIntegerIncludingZero('1.324324')).toBe(false);
});
});
describe('Check retrieval of values inside arrays', function () {
it('properly retrieves values inside arrays', function () {
expect(ObjectUtil.getIn(book, ['readers', '1', 'name'])).toBe('Brad');
expect(ObjectUtil.getIn(book, ['readers', '0', 'age'])).toBe(32);
});
it('properly retrieves values inside arrays using integers instead of strings as keys', function () {
expect(ObjectUtil.getIn(book, ['readers', 1, 'name'])).toBe('Brad');
expect(ObjectUtil.getIn(book, ['readers', 0, 'age'])).toBe(32);
});
});
describe('Check fine with null values', function () {
it('properly handles null input', function () {
expect(ObjectUtil.hasIn(null, ['readers', 1, 'name'])).toBe(false);
expect(ObjectUtil.hasIn(undefined, ['readers', 0, 'age'])).toBe(false);
});
});
describe('Check alternate return value of getIn', function () {
it('properly returns the alternate value if the path does not exist in the object', function () {
expect(ObjectUtil.hasIn(book, ['readers', 1, 'nonexistant'])).toBe(false);
expect(ObjectUtil.getIn(book, ['readers', 1, 'nonexistant'], null)).toBe(null);
expect(ObjectUtil.getIn(book, ['readers', 1, 'nonexistant'], 53)).toBe(53);
expect(ObjectUtil.getIn(book, ['readers', 1, 'nonexistant'], 'sorry')).toBe('sorry');
expect(ObjectUtil.getIn(book, ['readers', 1, 'nonexistant'])).toBe(undefined);
});
});
describe('Check setIn functionality', function () {
it('properly creates a path in an object', function () {
expect(ObjectUtil.hasIn(empty_book, ['publisher', 'address', 'city'])).toBe(false);
var new_book = ObjectUtil.setIn(empty_book, ['publisher', 'address', 'city'], {});
var expected_book = {
publisher: {
address: {
city: {
}
}
}
};
expect(ObjectUtil.hasIn(new_book, ['publisher', 'address', 'city'])).toBe(true);
expect(new_book).toEqual(expected_book);
});
it('properly creates a path in an object and does not mess with existing paths', function () {
expect(ObjectUtil.hasIn(almost_empty_book, ['publisher', 'address', 'city'])).toBe(false);
var new_book = ObjectUtil.setIn(almost_empty_book, ['publisher', 'address', 'city'], {});
var expected_book = {
publisher: {
address: {
city: {
}
}
},
is_cc_licensed: true
};
expect(ObjectUtil.hasIn(new_book, ['publisher', 'address', 'city'])).toBe(true);
expect(new_book).toEqual(expected_book);
});
it('properly handles null input objects', function () {
var new_book = ObjectUtil.setIn(null, ['publisher', 'address', 'city'], {});
var expected_book = {
publisher: {
address: {
city: {
}
}
}
};
expect(ObjectUtil.hasIn(new_book, ['publisher', 'address', 'city'])).toBe(true);
expect(new_book).toEqual(expected_book);
});
it('properly handles undefined input objects', function () {
var new_book = ObjectUtil.setIn(undefined, ['publisher', 'address', 'city'], {});
var expected_book = {
publisher: {
address: {
city: {
}
}
}
};
expect(ObjectUtil.hasIn(new_book, ['publisher', 'address', 'city'])).toBe(true);
expect(new_book).toEqual(expected_book);
});
it('properly handles arrays which do not exist in the input objects', function () {
var new_book = ObjectUtil.setIn(almost_empty_book, ['readers', 3, 'address'], {});
var expected_book = {
readers: [
undefined,
undefined,
undefined,
{
address: {
}
}
],
is_cc_licensed: true
};
expect(ObjectUtil.hasIn(new_book, ['readers', 3, 'address'])).toBe(true);
expect(new_book).toEqual(expected_book);
});
it('properly handles arrays which do not exist in the input objects and uses the given value for missing elements', function () {
var new_book = ObjectUtil.setIn(almost_empty_book, ['readers', 3, 'address'], {}, null);
var expected_book = {
readers: [
null,
null,
null,
{
address: {
}
}
],
is_cc_licensed: true
};
expect(ObjectUtil.hasIn(new_book, ['readers', 3, 'address'])).toBe(true);
expect(new_book).toEqual(expected_book);
});
it('properly handles paths which already exist', function () {
var new_book = ObjectUtil.setIn(almost_empty_book, ['is_cc_licensed'], true);
expect(ObjectUtil.hasIn(new_book, ['is_cc_licensed'])).toBe(true);
expect(new_book).toEqual(almost_empty_book);
});
it('can cope with arrays at the root', function () {
var new_book = ObjectUtil.setIn(empty_book, [1, 'is_cc_licensed'], {});
expect(ObjectUtil.hasIn(new_book, [1, 'is_cc_licensed'])).toBe(true);
var expected_book = [
undefined,
{
is_cc_licensed: {
}
}
];
expect(new_book).toEqual(expected_book);
});
it('overwrites other values with arrays if required by the new path', function () {
var new_book = ObjectUtil.setIn(almost_empty_book, ['is_cc_licensed', 1, 'age'], {});
expect(ObjectUtil.hasIn(new_book, ['is_cc_licensed', 1, 'age'])).toBe(true);
var expected_book = {
is_cc_licensed: [
undefined,
{
age: {
}
}
]
};
expect(new_book).toEqual(expected_book);
});
it('does not erase existing array data', function () {
var new_book = ObjectUtil.setIn(book, ['readers', 2, 'age'], 14);
var new_book = ObjectUtil.setIn(book, ['readers', 2, 'sex'], 'somethinginbetween');
expect(ObjectUtil.getIn(new_book, ['readers', 1, 'name'])).toBe('Brad');
expect(ObjectUtil.getIn(new_book, ['readers', 2, 'sex'])).toBe('somethinginbetween');
});
it('sets different data types correctly in an object', function () {
var new_book;
new_book = ObjectUtil.setIn(empty_book, ['readers', 0, 'age'], 14);
new_book = ObjectUtil.setIn(new_book, ['readers', 0, 'name'], 'Dan');
new_book = ObjectUtil.setIn(new_book, ['readers', 0, 'is_illiterate'], false);
new_book = ObjectUtil.setIn(new_book, ['readers', 0, 'nickname'], null);
new_book = ObjectUtil.setIn(new_book, ['readers', 0, 'type'], 'user');
new_book = ObjectUtil.setIn(new_book, ['title'], 'React to what?');
new_book = ObjectUtil.setIn(new_book, ['year'], 2017);
new_book = ObjectUtil.setIn(new_book, ['publisher', 'name'], 'cpunkt');
new_book = ObjectUtil.setIn(new_book, ['publisher', 'address', 'city'], 'Frankfurt am Main');
const expected_book = {
publisher: {
name: "cpunkt",
address: {
city: "Frankfurt am Main"
}
},
title : "React to what?",
year: 2017,
readers: [
{
type: "user",
name: "Dan",
age: 14,
nickname: null,
is_illiterate: false
}
]
};
expect(new_book).toEqual(expected_book);
});
});