/** * Copyright (c) Meta Platforms, Inc. and affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * * @format */ import { makeShallowSerializable, deserializeShallowObject, } from '../shallowSerialization'; import mockConsole from 'jest-mock-console'; class TestObject extends Object { constructor(title: Object, map?: Map, set?: Set) { super(); this.title = title; this.map = map; this.set = set; } title: Object; map?: Map; set?: Set; } test('test cyclic data structure', () => { const a: any = {x: 0, b: {c: []}}; a.b.c.push(a); expect(() => { makeShallowSerializable(a); }).toThrowErrorMatchingInlineSnapshot( `"Cycle detected: object at path '.b.c.0' is referring to itself: '[object Object]'"`, ); }); test('test shared data structure', () => { const restoreConsole = mockConsole(); try { const a = {hello: 'world'}; const b = {x: a, y: a}; const res = JSON.parse(JSON.stringify(makeShallowSerializable(b))); expect(res).toEqual({ x: {hello: 'world'}, y: {hello: 'world'}, }); expect(b.x).toBe(b.y); expect(res.x).not.toBe(res.y); // @ts-ignore expect(console.warn.mock.calls).toMatchInlineSnapshot(` Array [ Array [ "Duplicate value, object lives at path '.y', but also at path '.x': '[object Object]'. This might not behave correct after import and lead to unnecessary big exports.", ], ] `); } finally { restoreConsole(); } }); test('test makeObjectSerializable function for unnested object with no Set and Map', () => { const obj = {key1: 'value1', key2: 'value2'}; const output = makeShallowSerializable(obj); expect(output).toEqual(obj); // Testing numbers const obj2 = {key1: 1, key2: 2}; const output2 = makeShallowSerializable(obj2); expect(output2).toEqual(obj2); }); test('makeObjectSerializable function for unnested object with values which returns false when put in an if condition', () => { const obj2 = {key1: 0, key2: ''}; const output2 = makeShallowSerializable(obj2); return expect(output2).toEqual(obj2); }); test('test deserializeShallowObject function for unnested object with no Set and Map', () => { const obj = {key1: 'value1', key2: 'value2'}; const output = deserializeShallowObject(obj); expect(output).toEqual(obj); // Testing numbers const obj2 = {key1: 1, key2: 2}; const output2 = deserializeShallowObject(obj2); expect(output2).toEqual(obj2); }); test('test makeObjectSerializable and deserializeShallowObject function for nested object with no Set and Map', () => { const subObj = {key1: 'value1', key2: 'value2'}; const subObj2 = {key21: 'value21', key22: 'value22'}; const obj = {key1: subObj, key2: subObj2}; const output = makeShallowSerializable(obj); expect(output).toEqual(obj); expect(deserializeShallowObject(output)).toEqual(obj); const subObjNum = {key1: 1, key2: 2}; const subObjNum2 = {key21: 21, key22: 22}; const obj2 = {key1: subObjNum, key2: subObjNum2}; const output2 = makeShallowSerializable(obj2); expect(output2).toEqual(obj2); expect(deserializeShallowObject(output2)).toEqual(obj2); }); test('test makeObjectSerializable and deserializeShallowObject function for Map and Set with no nesting', () => { const map = new Map([ ['k1', 'v1'], ['k2', 'v2'], ]); const output = makeShallowSerializable(map); const expected = { __flipper_object_type__: 'Map', data: [ ['k1', 'v1'], ['k2', 'v2'], ], }; expect(output).toEqual(expected); expect(deserializeShallowObject(output)).toEqual(map); const set = new Set([1, 2, 3, 4, 5, 6, 5, 4, 3, 2, 1]); const outputSet = makeShallowSerializable(set); const expectedSet = { __flipper_object_type__: 'Set', data: [1, 2, 3, 4, 5, 6], }; expect(outputSet).toEqual(expectedSet); expect(deserializeShallowObject(outputSet)).toEqual(set); }); test('test makeObjectSerializable and deserializeShallowObject function for Map and Set with nesting', () => { const map = new Map([ [{title: 'k1'}, {title: 'v1'}], [{title: 'k2'}, {title: 'v2'}], ]); const output = makeShallowSerializable(map); const expected = { __flipper_object_type__: 'Map', data: [ [{title: 'k1'}, {title: 'v1'}], [{title: 'k2'}, {title: 'v2'}], ], }; expect(output).toEqual(expected); expect(deserializeShallowObject(output)).toEqual(map); const set = new Set([ {title: '1'}, {title: '2'}, {title: '3'}, {title: '4'}, {title: '5'}, {title: '6'}, ]); const outputSet = makeShallowSerializable(set); const expectedSet = { __flipper_object_type__: 'Set', data: [ {title: '1'}, {title: '2'}, {title: '3'}, {title: '4'}, {title: '5'}, {title: '6'}, ], }; expect(outputSet).toEqual(expectedSet); expect(deserializeShallowObject(outputSet)).toEqual(set); }); test('test makeObjectSerializable and deserializeShallowObject function for custom Object', () => { const obj = new TestObject('title'); expect(() => { makeShallowSerializable(obj); }).toThrowErrorMatchingInlineSnapshot( `"Unserializable object type (TestObject) at path '.': [object Object]."`, ); }); test('test makeObjectSerializable and deserializeShallowObject object with map', () => { const nestedObjWithMap = { map: new Map([ ['k1', 'v1'], ['k2', 'v2'], ]), }; expect(() => { makeShallowSerializable(nestedObjWithMap); }).toThrowErrorMatchingInlineSnapshot( `"Unserializable object type (Map) at path '.map': [object Map]."`, ); }); test('test makeObjectSerializable and deserializeShallowObject function for Array as input', () => { const arr = [1, 2, 4, 5]; const output = makeShallowSerializable(arr); expect(output).toEqual(arr); expect(deserializeShallowObject(output)).toEqual(arr); const arrMap = [ new Map([ ['a1', 'v1'], ['a2', 'v2'], ]), ]; expect(() => { makeShallowSerializable(arrMap); }).toThrowErrorMatchingInlineSnapshot( `"Unserializable object type (Map) at path '.0': [object Map]."`, ); }); test('test serialize and deserializeShallowObject function for non Object input', () => { expect(makeShallowSerializable('octopus')).toEqual('octopus'); expect(deserializeShallowObject(makeShallowSerializable('octopus'))).toEqual( 'octopus', ); expect(makeShallowSerializable(24567)).toEqual(24567); expect(deserializeShallowObject(makeShallowSerializable(24567))).toEqual( 24567, ); }); // dates on windows don't support changed timezones test.unix( 'test makeObjectSerializable and deserializeShallowObject function for Date input', () => { const date = new Date(2021, 1, 29, 10, 31, 7, 205); expect(makeShallowSerializable(date)).toMatchInlineSnapshot(` Object { "__flipper_object_type__": "Date", "data": 1614555067205, } `); expect(deserializeShallowObject(makeShallowSerializable(date))).toEqual( date, ); }, ); test('test makeObjectSerializable and deserializeShallowObject function for Map of Sets', () => { const map = new Map([ ['k1', new Set([1, 2, 3, 4, 5, 6])], [new Set([1, 2]), new Map([['k3', 'v3']])], ] as any); expect(() => { makeShallowSerializable(map); }).toThrowErrorMatchingInlineSnapshot( `"Unserializable object type (Set) at path '.01': [object Set]."`, ); });