deno.land / std@0.224.0 / collections / deep_merge_test.ts
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.import { assertEquals, assertStrictEquals } from "../assert/mod.ts";import { deepMerge } from "./deep_merge.ts";
Deno.test("deepMerge() handles simple merge", () => { assertEquals( deepMerge({ foo: true, }, { bar: true, }), { foo: true, bar: true, }, );});
Deno.test("deepMerge() handles symbol merge", () => { assertEquals( deepMerge({}, { [Symbol.for("deepmerge.test")]: true, }), { [Symbol.for("deepmerge.test")]: true, }, );});
Deno.test("deepMerge() ignores non enumerable", () => { assertEquals( deepMerge( {}, Object.defineProperties({}, { foo: { enumerable: false, value: true }, bar: { enumerable: true, value: true }, }), ), { bar: true, }, );});
Deno.test("deepMerge() handles nested merge", () => { assertEquals( deepMerge({ foo: { bar: true, }, }, { foo: { baz: true, quux: {}, }, qux: true, }), { foo: { bar: true, baz: true, quux: {}, }, qux: true, }, );});
Deno.test("deepMerge() prevents prototype merge", () => { assertEquals( deepMerge({ constructor: undefined, }, { foo: true, }), { constructor: undefined, foo: true, }, );});
Deno.test("deepMerge() prevents calling Object.prototype.__proto__ accessor property", () => { Object.defineProperty(Object.prototype, "__proto__", { get() { throw new Error( "Unexpected Object.prototype.__proto__ getter property call", ); }, set() { throw new Error( "Unexpected Object.prototype.__proto__ setter property call", ); }, configurable: true, }); try { assertEquals<unknown>( deepMerge({ foo: true, }, { bar: true, ["__proto__"]: {}, }), { foo: true, bar: true, }, ); } finally { // deno-lint-ignore no-explicit-any delete (Object.prototype as any).__proto__; }});
Deno.test("deepMerge() overrides target (non-mergeable source)", () => { assertEquals( deepMerge({ foo: { bar: true, }, }, { foo: true, }), { foo: true, }, );});
Deno.test("deepMerge() overrides target (non-mergeable destination, object like)", () => { const CustomClass = class {}; assertEquals( deepMerge({ foo: new CustomClass(), }, { foo: true, }), { foo: true, }, );});
Deno.test("deepMerge() overrides target (non-mergeable destination, array like)", () => { assertEquals( deepMerge({ foo: [], }, { foo: true, }), { foo: true, }, );});
Deno.test("deepMerge() overrides target (different object like source and destination)", () => { assertEquals( deepMerge({ foo: {}, }, { foo: [1, 2], }), { foo: [1, 2], }, ); assertEquals( deepMerge({ foo: [], }, { foo: { bar: true }, }), { foo: { bar: true }, }, );});
Deno.test("deepMerge() handles primitive types handling", () => { const CustomClass = class {}; const expected = { boolean: true, null: null, undefined: undefined, number: 1, bigint: 1n, string: "string", symbol: Symbol.for("deepmerge.test"), object: { foo: true }, regexp: /regex/, date: new Date(), function() {}, async async() {}, arrow: () => {}, class: new CustomClass(), get get() { return true; }, }; assertEquals( deepMerge({ boolean: false, null: undefined, undefined: null, number: -1, bigint: -1n, string: "foo", symbol: Symbol(), object: null, regexp: /foo/, date: new Date(0), function: function () {}, async: async function () {}, arrow: () => {}, class: null, get: false, }, expected), expected, );});
Deno.test("deepMerge() handles array merge (replace)", () => { assertEquals( deepMerge({ foo: [1, 2, 3], }, { foo: [4, 5, 6], }, { arrays: "replace" }), { foo: [4, 5, 6], }, );});
Deno.test("deepMerge() handles array merge (merge)", () => { assertEquals( deepMerge({ foo: [1, 2, 3], }, { foo: [4, 5, 6], }, { arrays: "merge" }), { foo: [1, 2, 3, 4, 5, 6], }, );});
Deno.test("deepMerge() handles maps merge (replace)", () => { assertEquals( deepMerge({ map: new Map([["foo", true]]), }, { map: new Map([["bar", true]]), }, { maps: "replace" }), { map: new Map([["bar", true]]), }, );});
Deno.test("deepMerge() handles maps merge (merge)", () => { assertEquals( deepMerge({ map: new Map([["foo", true]]), }, { map: new Map([["bar", true]]), }, { maps: "merge" }), { map: new Map([["foo", true], ["bar", true]]), }, );});
Deno.test("deepMerge() handles sets merge (replace)", () => { assertEquals( deepMerge({ set: new Set(["foo"]), }, { set: new Set(["bar"]), }, { sets: "replace" }), { set: new Set(["bar"]), }, );});
Deno.test("deepMerge() handles sets merge (merge)", () => { assertEquals( deepMerge({ set: new Set(["foo"]), }, { set: new Set(["bar"]), }, { sets: "merge" }), { set: new Set(["foo", "bar"]), }, );});
Deno.test("deepMerge() handles nested replace", () => { assertEquals( deepMerge( { a: "A1", b: ["B11", "B12"], c: { d: "D1", e: ["E11"], }, }, { b: [], c: { d: "D2", e: [], }, }, { arrays: "replace", }, ), { a: "A1", b: [], c: { d: "D2", e: [], }, }, );});
Deno.test("deepMerge() handles complex test", () => { assertEquals( deepMerge({ foo: { bar: { quux: new Set(["foo"]), grault: {}, }, }, }, { foo: { bar: { baz: true, qux: [1, 2], grault: { garply: false, }, }, corge: "deno", [Symbol.for("deepmerge.test")]: true, }, }), { foo: { bar: { quux: new Set(["foo"]), baz: true, qux: [1, 2], grault: { garply: false, }, }, corge: "deno", [Symbol.for("deepmerge.test")]: true, }, }, );});
Deno.test("deepMerge() handles circular references", () => { const expected = { foo: true } as { foo: boolean; bar: unknown }; expected.bar = expected; assertEquals(deepMerge({}, expected), expected); assertEquals(deepMerge(expected, {}), expected); assertEquals(deepMerge(expected, expected), expected);
const source = { foo: { b: { c: { d: {} } } }, bar: {}, }; const object = { foo: { a: 1 }, bar: { a: 2 }, };
source.foo.b.c.d = source; // deno-lint-ignore no-explicit-any (source.bar as any).b = source.foo.b; // deno-lint-ignore no-explicit-any const result: any = deepMerge(source, object); assertStrictEquals(result.foo.b.c.d, result.foo.b.c.d.foo.b.c.d);});
Deno.test("deepMerge() handles target object is not modified", () => { const record = { foo: { bar: true, }, baz: [1, 2, 3], quux: new Set([1, 2, 3]), }; assertEquals( deepMerge(record, { foo: { qux: false, }, baz: [4, 5, 6], quux: new Set([4, 5, 6]), }, { arrays: "merge", sets: "merge" }), { foo: { bar: true, qux: false, }, baz: [1, 2, 3, 4, 5, 6], quux: new Set([1, 2, 3, 4, 5, 6]), }, ); assertEquals(record, { foo: { bar: true, }, baz: [1, 2, 3], quux: new Set([1, 2, 3]), });});
Version Info