From 0d685216e30d93fe10a77f7b7b0b5e5b183f8ea8 Mon Sep 17 00:00:00 2001 From: Kevin Aleman Date: Mon, 16 Dec 2024 15:01:12 -0600 Subject: [PATCH] test: --- .../src/convertSubObjectsIntoPaths.spec.ts | 117 ++++++++++++++++++ .../tools/src/convertSubObjectsIntoPaths.ts | 2 +- packages/tools/src/objectMap.spec.ts | 93 ++++++++++++++ 3 files changed, 211 insertions(+), 1 deletion(-) create mode 100644 packages/tools/src/convertSubObjectsIntoPaths.spec.ts create mode 100644 packages/tools/src/objectMap.spec.ts diff --git a/packages/tools/src/convertSubObjectsIntoPaths.spec.ts b/packages/tools/src/convertSubObjectsIntoPaths.spec.ts new file mode 100644 index 000000000000..c595a17ae70e --- /dev/null +++ b/packages/tools/src/convertSubObjectsIntoPaths.spec.ts @@ -0,0 +1,117 @@ +import { expect } from 'chai'; + +import { convertSubObjectsIntoPaths } from './convertSubObjectsIntoPaths'; + +describe('convertSubObjectsIntoPaths', () => { + it('should flatten a simple object with no nested structure', () => { + const input = { a: 1, b: 2, c: 3 }; + const expected = { a: 1, b: 2, c: 3 }; + + expect(convertSubObjectsIntoPaths(input)).to.deep.equal(expected); + }); + + it('should flatten a nested object into paths', () => { + const input = { + a: 1, + b: { + c: 2, + d: { + e: 3, + }, + }, + }; + const expected = { + 'a': 1, + 'b.c': 2, + 'b.d.e': 3, + }; + + expect(convertSubObjectsIntoPaths(input)).to.deep.equal(expected); + }); + + it('should handle objects with array values', () => { + const input = { + a: [1, 2, 3], + b: { + c: [4, 5], + }, + }; + const expected = { + 'a': [1, 2, 3], + 'b.c': [4, 5], + }; + + expect(convertSubObjectsIntoPaths(input)).to.deep.equal(expected); + }); + + it('should handle deeply nested objects', () => { + const input = { + a: { + b: { + c: { + d: { + e: { + f: 6, + }, + }, + }, + }, + }, + }; + const expected = { + 'a.b.c.d.e.f': 6, + }; + + expect(convertSubObjectsIntoPaths(input)).to.deep.equal(expected); + }); + + it('should handle an empty object', () => { + const input = {}; + const expected = {}; + + expect(convertSubObjectsIntoPaths(input)).to.deep.equal(expected); + }); + + it('should handle objects with mixed types of values', () => { + const input = { + a: 1, + b: 'string', + c: true, + d: { + e: null, + f: undefined, + g: { + h: 2, + }, + }, + }; + const expected = { + 'a': 1, + + 'b': 'string', + + 'c': true, + 'd.e': null, + 'd.f': undefined, + 'd.g.h': 2, + }; + + expect(convertSubObjectsIntoPaths(input)).to.deep.equal(expected); + }); + + it('should respect the parentPath parameter', () => { + const input = { + a: 1, + b: { + c: 2, + }, + }; + const parentPath = 'root'; + const expected = { + 'root.a': 1, + 'root.b.c': 2, + }; + + expect(convertSubObjectsIntoPaths(input, parentPath)).to.deep.equal(expected); + }); +}); diff --git a/packages/tools/src/convertSubObjectsIntoPaths.ts b/packages/tools/src/convertSubObjectsIntoPaths.ts index 4fb3ae118f7d..8c128aa19f2c 100644 --- a/packages/tools/src/convertSubObjectsIntoPaths.ts +++ b/packages/tools/src/convertSubObjectsIntoPaths.ts @@ -4,7 +4,7 @@ export function convertSubObjectsIntoPaths(object: Record, parentPa const value = object[key]; const fullKey = parentPath ? `${parentPath}.${key}` : key; - if (typeof value === 'object') { + if (typeof value === 'object' && !Array.isArray(value) && value !== null) { const flattened = convertSubObjectsIntoPaths(value, fullKey); return Object.keys(flattened).map((newKey) => [newKey, flattened[newKey]]); diff --git a/packages/tools/src/objectMap.spec.ts b/packages/tools/src/objectMap.spec.ts new file mode 100644 index 000000000000..15299b9614a0 --- /dev/null +++ b/packages/tools/src/objectMap.spec.ts @@ -0,0 +1,93 @@ +import { expect } from 'chai'; + +import { objectMap } from './objectMap'; + +describe('objectMap', () => { + it('should map a simple object non-recursively', () => { + const input = { a: 1, b: 2, c: 3 }; + const callback = ({ key, value }) => ({ key: key.toUpperCase(), value: value * 2 }); + const expected = { A: 2, B: 4, C: 6 }; + expect(objectMap(input, callback)).to.deep.equal(expected); + }); + it('should filter out undefined results from callback', () => { + const input = { a: 1, b: 2, c: 3 }; + const callback = ({ key, value }) => (value > 1 ? { key, value } : undefined); + const expected = { b: 2, c: 3 }; + expect(objectMap(input, callback)).to.deep.equal(expected); + }); + it('should map a nested object recursively', () => { + const input = { + a: 1, + b: { + c: 2, + d: { + e: 3, + }, + }, + }; + const callback = ({ key, value }) => ({ key: `mapped_${key}`, value: typeof value === 'number' ? value * 10 : value }); + const expected = { + mapped_a: 10, + mapped_b: { + mapped_c: 20, + mapped_d: { + mapped_e: 30, + }, + }, + }; + expect(objectMap(input, callback, true)).to.deep.equal(expected); + }); + it('should handle an empty object', () => { + const input = {}; + const callback = ({ key, value }) => ({ key: `mapped_${key}`, value }); + const expected = {}; + expect(objectMap(input, callback)).to.deep.equal(expected); + }); + it('should handle mixed value types in non-recursive mode', () => { + const input = { + a: 1, + b: 'string', + c: true, + d: null, + }; + const callback = ({ key, value }) => ({ key: key.toUpperCase(), value: typeof value === 'number' ? value * 2 : value }); + const expected = { + A: 2, + B: 'string', + C: true, + D: null, + }; + expect(objectMap(input, callback)).to.deep.equal(expected); + }); + it('should handle nested objects with mixed types recursively', () => { + const input = { + a: 1, + b: { + c: 'string', + d: { + e: true, + f: null, + }, + }, + }; + const callback = ({ key, value }) => ({ key: key.toUpperCase(), value }); + const expected = { + A: 1, + B: { + C: 'string', + D: { + E: true, + F: null, + }, + }, + }; + expect(objectMap(input, callback, true)).to.deep.equal(expected); + }); + it('should not modify the original object', () => { + const input = { a: 1, b: 2 }; + const original = { ...input }; + const callback = ({ key, value }) => ({ key, value: value * 2 }); + objectMap(input, callback); + expect(input).to.deep.equal(original); + }); +});