utils/tests/object.spec.ts
ztimson fec373ca4c
All checks were successful
Build / Build NPM Project (push) Successful in 1m16s
Build / Tag Version (push) Successful in 14s
Build / Publish Documentation (push) Successful in 53s
Added test suite
2025-05-14 16:30:42 -04:00

165 lines
4.8 KiB
TypeScript

import {
clean, deepCopy, deepMerge, dotNotation, encodeQuery, flattenObj, formData, includes, isEqual, mixin,
JSONAttemptParse, JSONSerialize, JSONSanitize
} from '../src';
describe('Object utilities', () => {
describe('clean', () => {
it('removes null values', () => {
const obj = { a: 1, b: null, c: undefined, d: 0 };
expect(clean({ ...obj })).toEqual({ a: 1, c: undefined, d: 0 });
});
it('throws on null input', () => {
expect(() => clean(null as any)).toThrow();
});
it('removes undefined only when specified', () => {
const obj = { a: 1, b: undefined, c: null };
expect(clean({ ...obj }, true)).toEqual({ a: 1, c: null });
});
it('works for arrays', () => {
expect(clean([1, null, 2, undefined, 3] as any)).toEqual([1, 2, 3]);
});
});
describe('deepCopy', () => {
it('creates a deep copy', () => {
const obj = { a: { b: 2 } };
const copy = deepCopy(obj);
expect(copy).toEqual(obj);
expect(copy).not.toBe(obj);
expect(copy.a).not.toBe(obj.a);
});
});
describe('deepMerge', () => {
it('merges deeply nested objects', () => {
const tgt = { a: { b: 1 }, d: 7 };
const src = { a: { c: 2 }, d: 8 };
expect(deepMerge({ ...tgt }, src)).toEqual({ a: { b: 1, c: 2 }, d: 8 });
});
it('merges multiple sources', () => {
const t = { a: 1 };
const s1 = { b: 2 };
const s2 = { c: 3 };
expect(deepMerge({ ...t }, s1, s2)).toEqual({ a: 1, b: 2, c: 3 });
});
});
describe('dotNotation', () => {
it('gets nested value', () => {
const obj = { a: { b: { c: 3 } } };
expect(dotNotation(obj, 'a.b.c')).toBe(3);
});
it('sets nested value', () => {
const obj = { a: { b: { c: 3 } } };
dotNotation(obj, 'a.b.c', 10);
expect(obj.a.b.c).toBe(10);
});
it('returns undefined for non-existent path', () => {
expect(dotNotation({ a: 1 }, 'a.b.c')).toBeUndefined();
});
it('creates nested object when setting', () => {
const obj: any = {};
dotNotation(obj, 'd.e.f', 5);
expect(obj.d.e.f).toBe(5);
});
});
describe('encodeQuery', () => {
it('encodes simple objects', () => {
expect(encodeQuery({ a: 1, b: 'test' })).toBe('a=1&b=test');
});
it('handles special characters', () => {
expect(encodeQuery({ a: 'hello world' })).toBe('a=hello%20world');
});
});
describe('flattenObj', () => {
it('flattens nested objects', () => {
const obj = { a: { b: 2 }, c: 3 };
expect(flattenObj(obj)).toEqual({ 'a.b': 2, c: 3 });
});
it('handles multiple nesting', () => {
const obj = { a: { b: { c: 4 } } };
expect(flattenObj(obj)).toEqual({ 'a.b.c': 4 });
});
});
describe('formData', () => {
it('converts object to FormData', () => {
const obj = { a: '1', b: 'foo' };
const fd = formData(obj);
expect(fd.get('a')).toBe('1');
expect(fd.get('b')).toBe('foo');
});
});
describe('includes', () => {
it('checks if all values included', () => {
expect(includes({ a: 2, b: 3 }, { a: 2 })).toBeTruthy();
expect(includes({ a: 2, b: 3 }, { c: 1 })).toBeFalsy();
});
it('handles arrays of values', () => {
expect(includes([{ a: 1 }], [{ a: 1 }])).toBeTruthy();
expect(includes([{ a: 1 }], [{ a: 2 }])).toBeFalsy();
});
it('allows missing when specified', () => {
expect(includes(undefined, { a: 2 }, true)).toBeTruthy();
});
});
describe('isEqual', () => {
it('returns true for deeply equal objects', () => {
expect(isEqual({ a: 1, b: { c: 3 } }, { a: 1, b: { c: 3 } })).toBe(true);
});
it('returns false for non-equal objects', () => {
expect(isEqual({ a: 1 }, { a: 2 })).toBe(false);
});
it('compares functions by string', () => {
expect(isEqual(() => 1, () => 1)).toBe(true);
});
});
describe('mixin', () => {
it('merges prototypes', () => {
class A { foo() { return 1; } }
class B { bar() { return 2; } }
class C {}
mixin(C, [A, B]);
const c = new (C as any)();
expect(c.foo()).toBe(1);
expect(c.bar()).toBe(2);
});
});
describe('JSONAttemptParse', () => {
it('parses valid JSON', () => {
expect(JSONAttemptParse('{"a":1}')).toEqual({ a: 1 });
});
it('returns original string on error', () => {
expect(JSONAttemptParse('not json')).toBe('not json');
});
});
describe('JSONSerialize', () => {
it('serializes objects', () => {
expect(JSONSerialize({ a: 1 })).toBe(JSON.stringify({ a: 1 }));
});
it('leaves primitives as is', () => {
expect(JSONSerialize('test')).toBe('test');
expect(JSONSerialize(123)).toBe(123);
});
});
describe('JSONSanitize', () => {
it('stringifies objects', () => {
expect(JSONSanitize({ a: 1 })).toBe(JSON.stringify({ a: 1 }));
});
it('does not throw on circular refs', () => {
const obj: any = {};
obj.self = obj;
expect(() => JSONSanitize(obj)).not.toThrow();
});
});
});