Files
trezor-suite/packages/utils/tests/mergeDeepObject.test.ts
Peter Sanderson 55d663ca2d chore: add recommanded checks from eslint-plugin-jest
chore: use jest/valid-describe-callback as it has only 2 places that fails, so I ignored them in-code
2024-11-06 14:18:07 +01:00

221 lines
6.3 KiB
TypeScript

import { mergeDeepObject } from '../src/mergeDeepObject';
interface INamedObject {
propertyA: string[];
propertyB: string;
}
describe('mergeDeepObject', () => {
const object1 = {
array: ['a'],
date: new Date('2020-01-01'),
functions: {
func1: () => 'Object 1',
func2: () => 'Object 1',
},
nest: {
nest: {
a: 1,
b: 2,
},
},
object: {
a: 1,
b: 2,
},
};
const object1Backup = { ...object1 };
const object2 = {
nest: {
nest: {
b: 3,
d: 5,
},
},
object: {
b: undefined,
c: 3,
d: 5,
},
};
const object2Backup = { ...object2 };
const object3 = {
array: ['b', 'c', 'a'],
date: new Date('2020-01-02'),
functions: {
func2: () => 'Object 3',
func3: () => 'Object 3',
},
nest: {
nest: {
c: 4,
},
},
object: {
d: null,
},
};
const object3Backup = { ...object3 };
const namedObject: INamedObject = {
propertyA: ['a', 'b'],
propertyB: 'propertyB',
};
describe('without options', () => {
const result = mergeDeepObject(object1, object2, object3);
it('merges arrays correctly', () => {
expect(result.array).toEqual(['a', 'b', 'c']);
});
it('merges objects with functions correctly', () => {
const { functions } = result;
expect(Object.keys(functions)).toEqual(['func1', 'func2', 'func3']);
expect(functions.func1()).toBe('Object 1');
expect(functions.func2()).toBe('Object 3');
expect(functions.func3()).toBe('Object 3');
});
it('merges nested objects correctly', () => {
const { nest } = result.nest;
expect(nest.a).toBe(1);
expect(nest.b).toBe(3);
expect(nest.c).toBe(4);
expect(nest.d).toBe(5);
expect(result.nest).toEqual({
nest: {
a: 1,
b: 3,
c: 4,
d: 5,
},
});
});
it('merges objects with undefined values correctly', () => {
const { object } = result;
expect(object.a).toBe(1);
expect(object.c).toBe(3);
expect(object.d).toBe(null);
expect(object).toEqual({
a: 1,
c: 3,
d: null,
});
});
it("doesn't mutate the arguments", () => {
expect(object1).toEqual(object1Backup);
expect(object2).toEqual(object2Backup);
expect(object3).toEqual(object3Backup);
});
it('overrides date correctly', () => {
expect(result.date).toEqual(object3.date);
});
it('retains Date instance', () => {
expect(result.date instanceof Date).toBe(true);
});
it('merges a named object', () => {
const obj = mergeDeepObject(namedObject, { propertyB: 'merged' });
expect(obj).toEqual({
propertyA: namedObject.propertyA,
propertyB: 'merged',
});
expect(obj.propertyA).toBe(namedObject.propertyA);
expect(obj.propertyB).toBe('merged');
});
});
describe('with options', () => {
const result = mergeDeepObject.withOptions(
{
mergeArrays: false,
},
object1,
object2,
object3,
);
it("doesn't mergeDeepObject arrays when mergeArrays is false", () => {
expect(result.array).toEqual(object3.array);
});
it('resets the options after calling it', () => {
expect(mergeDeepObject(object1, object2, object3).array).toEqual(['a', 'b', 'c']);
});
});
describe('reported issues', () => {
it('can mergeDeepObject objects with array-like properties', () => {
expect(mergeDeepObject({ length: 1 }, { length: 2 })).toEqual({ length: 2 });
});
it("can't mergeDeepObject arrays when provided directly as args", () => {
expect(() => mergeDeepObject([1], [2])).toThrow(
new TypeError('Arguments provided to ts-deepmerge must be objects, not arrays.'),
);
});
it('safeguards against prototype pollution', () => {
const merged: any = mergeDeepObject(
{},
JSON.parse('{ "__proto__": { "hasProto": true } }'),
);
expect(merged.__proto__.hasProto).toBe(undefined);
});
it('can mergeDeepObject objects that use `as const`', () => {
const a = { a: { b: 1, c: 'foo' } } as const;
const b = { a: { c: 'bar' } } as const;
const result = mergeDeepObject(a, b);
expect(result.a.c).toBe('bar');
});
it('can mergeDeepObject objects that have inconsistent property value types', () => {
const a = { a: { b: '1' } };
const b = { a: { b: 1 } };
const result = mergeDeepObject(a, b);
const value = result.a.b;
expect(value).toBe(1);
});
});
describe('dot notation', () => {
const fn = () => {};
const first = { a: { b: 1, c: 'foo' }, 'd.e': { f: null, 'g.h': 42 }, l: { m: [8] } };
const second = { 'a.b': 3, d: { 'e.f': fn, 'e.g': true }, 'i.j.k': undefined, 'l.m': [9] };
const third = { 'i.j': 'bar' };
it('dot notation off', () => {
const res = mergeDeepObject.withOptions({ mergeArrays: false }, first, second, third);
expect(res).toStrictEqual({ ...first, ...second, ...third });
});
it('dot notation on', () => {
const res = mergeDeepObject.withOptions({ dotNotation: true }, first, second, third);
expect(res).toStrictEqual({
a: { b: 3, c: 'foo' },
d: { e: { f: fn, g: true } },
i: { j: 'bar' },
l: { m: [8, 9] },
});
});
});
});