@@ -146,6 +146,28 @@ describe('Function: deepMerge', () => {
146146 } ) ;
147147 } ) ;
148148
149+ describe ( 'Multi-source merging' , ( ) => {
150+ it ( 'merges three sources with arrays of objects' , ( ) => {
151+ // Prepare
152+ const names = { characters : [ { name : 'barney' } , { name : 'fred' } ] } ;
153+ const ages = { characters : [ { age : 36 } , { age : 40 } ] } ;
154+ const heights = {
155+ characters : [ { height : '5\'4"' } , { height : '5\'5"' } ] ,
156+ } ;
157+
158+ // Act
159+ const result = deepMerge ( { } , names , ages , heights ) ;
160+
161+ // Assess
162+ expect ( result ) . toEqual ( {
163+ characters : [
164+ { name : 'barney' , age : 36 , height : '5\'4"' } ,
165+ { name : 'fred' , age : 40 , height : '5\'5"' } ,
166+ ] ,
167+ } ) ;
168+ } ) ;
169+ } ) ;
170+
149171 describe ( 'Array merging (index-based)' , ( ) => {
150172 it ( 'merges arrays by index' , ( ) => {
151173 // Prepare
@@ -238,6 +260,16 @@ describe('Function: deepMerge', () => {
238260 expect ( result . constructor ) . toBe ( Object ) ;
239261 } ) ;
240262
263+ it ( 'does not indirectly pollute via toString.constructor.prototype' , ( ) => {
264+ // Prepare & Act
265+ deepMerge ( { } , {
266+ toString : { constructor : { prototype : { polluted : true } } } ,
267+ } as Record < string , unknown > ) ;
268+
269+ // Assess
270+ expect ( 'polluted' in Function . prototype ) . toBe ( false ) ;
271+ } ) ;
272+
241273 it ( 'handles nested __proto__ keys' , ( ) => {
242274 // Prepare
243275 const target = { nested : { a : 1 } } ;
@@ -692,5 +724,31 @@ describe('Function: deepMerge', () => {
692724 expect ( result . fn ) . toBe ( fn ) ;
693725 expect ( ( result . fn as ( ) => number ) ( ) ) . toBe ( 42 ) ;
694726 } ) ;
727+
728+ it ( 'replaces function target value with object from later source' , ( ) => {
729+ // Prepare
730+ const fn = ( ) => 42 ;
731+ const source1 = { a : fn } as Record < string , unknown > ;
732+ const source2 = { a : { b : 2 } } ;
733+
734+ // Act
735+ const result = deepMerge ( { } , source1 , source2 ) ;
736+
737+ // Assess - object source overwrites function, not merged into it
738+ expect ( result ) . toEqual ( { a : { b : 2 } } ) ;
739+ expect ( 'b' in ( source1 . a as object ) ) . toBe ( false ) ;
740+ } ) ;
741+
742+ it ( 'handles self-merge without infinite loop' , ( ) => {
743+ // Prepare
744+ const object : Record < string , unknown > = { a : 1 , b : { c : 2 } } ;
745+
746+ // Act
747+ const result = deepMerge ( object , object ) ;
748+
749+ // Assess - should be a no-op
750+ expect ( result ) . toBe ( object ) ;
751+ expect ( result ) . toEqual ( { a : 1 , b : { c : 2 } } ) ;
752+ } ) ;
695753 } ) ;
696754} ) ;
0 commit comments