import { Serializer } from "./serializer"; class TestSerializerObj1 { a: number; constructor(a = 0) { this.a = a; } } class TestSerializerObj2 { a = () => 1 b = [(obj: any) => 2] } class TestSerializerObj3 { a = [1, 2]; postUnserialize() { this.a.push(3); } } class TestSerializerObj4 extends TestSerializerObj1 { } const TEST_NS = { TestSerializerObj1, TestSerializerObj2, TestSerializerObj3, }; const TEST_NS_FLAT = [ TestSerializerObj1, TestSerializerObj2, TestSerializerObj3, ]; const TEST_NS_RENAME = { ob1: TestSerializerObj1, ob2: TestSerializerObj2, ob3: TestSerializerObj3, } describe("Serializer", () => { function checkReversability(obj: any, namespace: any = TEST_NS): any { var serializer = new Serializer(namespace); var data = serializer.serialize(obj); serializer = new Serializer(namespace); var loaded = serializer.unserialize(data); expect(loaded).toEqual(obj); return loaded; } it("serializes simple objects", () => { var obj = { "a": 5, "b": null, "c": [{ "a": 2 }, "test"] }; checkReversability(obj); }); it("restores objects constructed from class", () => { let loaded = checkReversability(new TestSerializerObj1(5)); expect(loaded.a).toBe(5); expect(loaded).toBeInstanceOf(TestSerializerObj1); loaded = checkReversability(new TestSerializerObj1(5), TEST_NS_FLAT); expect(loaded.a).toBe(5); expect(loaded).toBeInstanceOf(TestSerializerObj1); loaded = checkReversability(new TestSerializerObj1(5), TEST_NS_RENAME); expect(loaded.a).toBe(5); expect(loaded).toBeInstanceOf(TestSerializerObj1); }); it("stores one version of the same object", () => { var a = new TestSerializerObj1(8); var b = new TestSerializerObj1(8); var c = { 'r': a, 's': ["test", a], 't': a, 'u': b }; var loaded = checkReversability(c); expect(loaded.t).toBe(loaded.r); expect(loaded.s[1]).toBe(loaded.r); expect(loaded.u).not.toBe(loaded.r); }); it("handles circular references", () => { var a: any = { b: {} }; a.b.c = a; checkReversability(a); }); it("ignores some classes", () => { let serializer = new Serializer(TEST_NS); serializer.addIgnoredClass("TestSerializerObj1"); let data = serializer.serialize({ a: 5, b: new TestSerializerObj1() }); let loaded = serializer.unserialize(data); expect(loaded).toEqual({ a: 5, b: undefined }); serializer = new Serializer(TEST_NS); serializer.addIgnoredClass(TestSerializerObj1); data = serializer.serialize({ a: 5, b: new TestSerializerObj1() }); loaded = serializer.unserialize(data); expect(loaded).toEqual({ a: 5, b: undefined }); serializer = new Serializer(TEST_NS_RENAME); serializer.addIgnoredClass(TestSerializerObj1); data = serializer.serialize({ a: 5, b: new TestSerializerObj1() }); loaded = serializer.unserialize(data); expect(loaded).toEqual({ a: 5, b: undefined }); }); it("ignores functions", () => { let serializer = new Serializer(TEST_NS); let data = serializer.serialize({ obj: new TestSerializerObj2() }); let loaded = serializer.unserialize(data); let expected = new TestSerializerObj2(); expected.a = undefined; expected.b[0] = undefined; expect(loaded).toEqual({ obj: expected }); }); it("calls specific postUnserialize", () => { let serializer = new Serializer(TEST_NS); let data = serializer.serialize({ obj: new TestSerializerObj3() }); let loaded = serializer.unserialize(data); let expected = new TestSerializerObj3(); expected.a = [1, 2, 3]; expect(loaded).toEqual({ obj: expected }); }); it("handles missing classes", () => { jest.spyOn(console, "error").mockImplementation(); let serializer = new Serializer(TEST_NS); let data = serializer.serialize({ obj: new TestSerializerObj4() }); let loaded = serializer.unserialize(data); expect(loaded).toEqual({ obj: { a: 0 } }); expect(console.error).toHaveBeenCalledWith("Can't find class", "TestSerializerObj4"); }); it("uses namespace alias to protect from property mangling", () => { const data = { a: new TestSerializerObj1(1), b: new TestSerializerObj1(2), c: [new TestSerializerObj1(3)], }; const serializer1 = new Serializer(TEST_NS); const serializer2 = new Serializer(TEST_NS_RENAME); const dumped1 = serializer1.serialize(data); const dumped2 = serializer2.serialize(data); expect(dumped1.length).toBeGreaterThan(dumped2.length); expect(serializer1.unserialize(dumped1)).toEqual(data); expect(serializer2.unserialize(dumped2)).toEqual(data); }); });