@@ -106,16 +106,31 @@ describe('mergeDeep()', () => {
106106 // https://github.com/vendurehq/vendure/issues/5083
107107 it ( 'should merge each object once rather than once per path' , ( ) => {
108108 // `depth + 2` distinct objects, 2 ^ (depth + 1) distinct paths to the leaf, no cycles.
109- let shared : any = { id : 'leaf' , value : 'x' } ;
110- for ( let i = 0 ; i < 22 ; i ++ ) {
111- shared = { id : `level-${ i } ` , left : shared , right : shared , value : 'x' } ;
112- }
109+ const layeredDiamond = ( leaf : object ) => {
110+ let shared : any = leaf ;
111+ for ( let i = 0 ; i < 22 ; i ++ ) {
112+ shared = { id : `level-${ i } ` , left : shared , right : shared , value : 'x' } ;
113+ }
114+ return { id : 'root' , a : shared , b : shared } ;
115+ } ;
116+ let leafMerges = 0 ;
117+ // mergeDeep() enumerates the source once per merge. Throwing rather than counting up stops
118+ // a regression here from working through the other 2 ^ 23 paths to the leaf first.
119+ const countedLeaf = new Proxy (
120+ { id : 'leaf' , value : 'x' } ,
121+ {
122+ ownKeys ( leaf ) {
123+ if ( ++ leafMerges > 1 ) {
124+ throw new Error ( 'the shared leaf was merged more than once' ) ;
125+ }
126+ return Reflect . ownKeys ( leaf ) ;
127+ } ,
128+ } ,
129+ ) ;
113130
114- const start = Date . now ( ) ;
115- mergeDeep ( { id : 'root' , a : shared , b : shared } , { id : 'root' , a : shared , b : shared } ) ;
131+ mergeDeep ( layeredDiamond ( { id : 'leaf' , value : 'x' } ) , layeredDiamond ( countedLeaf ) ) ;
116132
117- // Merging per object is sub-millisecond here; merging per path takes tens of seconds.
118- expect ( Date . now ( ) - start ) . toBeLessThan ( 2000 ) ;
133+ expect ( leafMerges ) . toBe ( 1 ) ;
119134 } ) ;
120135
121136 // Rules out memoising on the source alone, which is also linear but aliases the merged
0 commit comments