@@ -27,7 +27,7 @@ describe("deepEqual", () => {
2727 } ) ;
2828
2929 it ( "handles NaN" , ( ) => {
30- expect ( deepEqual ( NaN , NaN ) ) . toBe ( false ) ; // NaN === NaN is false
30+ expect ( deepEqual ( NaN , NaN ) ) . toBe ( true ) ; // NaN === NaN is false
3131 expect ( deepEqual ( NaN , 0 ) ) . toBe ( false ) ;
3232 expect ( deepEqual ( NaN , "NaN" ) ) . toBe ( false ) ;
3333 } ) ;
@@ -93,6 +93,49 @@ describe("deepEqual", () => {
9393 const obj2 = { a : null , b : undefined } ;
9494 expect ( deepEqual ( obj1 , obj2 ) ) . toBe ( true ) ;
9595 } ) ;
96+
97+ it ( "handles objects with symbol keys" , ( ) => {
98+ const sym = Symbol ( "test" ) ;
99+ const obj1 = { [ sym ] : "value" , a : 1 } ;
100+ const obj2 = { [ sym ] : "value" , a : 1 } ;
101+ expect ( deepEqual ( obj1 , obj2 ) ) . toBe ( true ) ;
102+ } ) ;
103+
104+ it ( "returns false for objects with different symbol values" , ( ) => {
105+ const sym = Symbol ( "test" ) ;
106+ const obj1 = { [ sym ] : "value1" , a : 1 } ;
107+ const obj2 = { [ sym ] : "value2" , a : 1 } ;
108+ expect ( deepEqual ( obj1 , obj2 ) ) . toBe ( false ) ;
109+ } ) ;
110+
111+ it ( "returns false for objects with different symbol keys" , ( ) => {
112+ const sym1 = Symbol ( "test1" ) ;
113+ const sym2 = Symbol ( "test2" ) ;
114+ const obj1 = { [ sym1 ] : "value" } ;
115+ const obj2 = { [ sym2 ] : "value" } ;
116+ expect ( deepEqual ( obj1 , obj2 ) ) . toBe ( false ) ;
117+ } ) ;
118+
119+ it ( "returns false for objects with different constructors" , ( ) => {
120+ class ClassA {
121+ constructor ( public value : number ) { }
122+ }
123+ class ClassB {
124+ constructor ( public value : number ) { }
125+ }
126+ const obj1 = new ClassA ( 1 ) ;
127+ const obj2 = new ClassB ( 1 ) ;
128+ expect ( deepEqual ( obj1 , obj2 ) ) . toBe ( false ) ;
129+ } ) ;
130+
131+ it ( "returns true for objects with same constructor" , ( ) => {
132+ class MyClass {
133+ constructor ( public value : number ) { }
134+ }
135+ const obj1 = new MyClass ( 1 ) ;
136+ const obj2 = new MyClass ( 1 ) ;
137+ expect ( deepEqual ( obj1 , obj2 ) ) . toBe ( true ) ;
138+ } ) ;
96139 } ) ;
97140
98141 describe ( "arrays" , ( ) => {
@@ -154,6 +197,12 @@ describe("deepEqual", () => {
154197 const arr2 = [ null , undefined , 1 ] ;
155198 expect ( deepEqual ( arr1 , arr2 ) ) . toBe ( true ) ;
156199 } ) ;
200+
201+ it ( "returns false for arrays with different order" , ( ) => {
202+ const arr1 = [ 1 , 2 , 3 ] ;
203+ const arr2 = [ 3 , 2 , 1 ] ;
204+ expect ( deepEqual ( arr1 , arr2 ) ) . toBe ( false ) ;
205+ } ) ;
157206 } ) ;
158207
159208 describe ( "Date objects" , ( ) => {
@@ -174,6 +223,12 @@ describe("deepEqual", () => {
174223 expect ( deepEqual ( date , "2023-01-01T00:00:00Z" ) ) . toBe ( false ) ;
175224 expect ( deepEqual ( date , 1672531200000 ) ) . toBe ( false ) ;
176225 } ) ;
226+
227+ it ( "handles invalid dates" , ( ) => {
228+ const invalid1 = new Date ( "invalid" ) ;
229+ const invalid2 = new Date ( "invalid" ) ;
230+ expect ( deepEqual ( invalid1 , invalid2 ) ) . toBe ( true ) ; // Both are NaN timestamps
231+ } ) ;
177232 } ) ;
178233
179234 describe ( "RegExp objects" , ( ) => {
@@ -243,6 +298,18 @@ describe("deepEqual", () => {
243298 const set = new Set ( [ 1 , 2 , 3 ] ) ;
244299 expect ( deepEqual ( set , [ 1 , 2 , 3 ] ) ) . toBe ( false ) ;
245300 } ) ;
301+
302+ it ( "handles sets with nested objects" , ( ) => {
303+ const set1 = new Set ( [ { a : { b : 1 } } ] ) ;
304+ const set2 = new Set ( [ { a : { b : 1 } } ] ) ;
305+ expect ( deepEqual ( set1 , set2 ) ) . toBe ( true ) ;
306+ } ) ;
307+
308+ it ( "handles sets with NaN" , ( ) => {
309+ const set1 = new Set ( [ NaN , 1 , 2 ] ) ;
310+ const set2 = new Set ( [ NaN , 1 , 2 ] ) ;
311+ expect ( deepEqual ( set1 , set2 ) ) . toBe ( true ) ;
312+ } ) ;
246313 } ) ;
247314
248315 describe ( "Map objects" , ( ) => {
@@ -309,7 +376,7 @@ describe("deepEqual", () => {
309376 const key2 = { id : 1 } ;
310377 const map1 = new Map ( [ [ key1 , "value" ] ] ) ;
311378 const map2 = new Map ( [ [ key2 , "value" ] ] ) ;
312- expect ( deepEqual ( map1 , map2 ) ) . toBe ( false ) ; // Map uses reference equality for keys
379+ expect ( deepEqual ( map1 , map2 ) ) . toBe ( true ) ; // Map uses deep equality for keys
313380 } ) ;
314381
315382 it ( "returns false when comparing map with non-map" , ( ) => {
@@ -319,13 +386,141 @@ describe("deepEqual", () => {
319386 ] ) ;
320387 expect ( deepEqual ( map , { a : 1 , b : 2 } ) ) . toBe ( false ) ;
321388 } ) ;
389+
390+ it ( "handles maps with nested objects as keys" , ( ) => {
391+ const key1 = { nested : { id : 1 } } ;
392+ const key2 = { nested : { id : 1 } } ;
393+ const map1 = new Map ( [ [ key1 , "value" ] ] ) ;
394+ const map2 = new Map ( [ [ key2 , "value" ] ] ) ;
395+ expect ( deepEqual ( map1 , map2 ) ) . toBe ( true ) ;
396+ } ) ;
397+
398+ it ( "handles maps with NaN as keys" , ( ) => {
399+ const map1 = new Map ( [ [ NaN , "value" ] ] ) ;
400+ const map2 = new Map ( [ [ NaN , "value" ] ] ) ;
401+ expect ( deepEqual ( map1 , map2 ) ) . toBe ( true ) ;
402+ } ) ;
403+ } ) ;
404+
405+ describe ( "TypedArray objects" , ( ) => {
406+ it ( "returns true for identical Int8Array" , ( ) => {
407+ const arr1 = new Int8Array ( [ 1 , 2 , 3 ] ) ;
408+ const arr2 = new Int8Array ( [ 1 , 2 , 3 ] ) ;
409+ expect ( deepEqual ( arr1 , arr2 ) ) . toBe ( true ) ;
410+ } ) ;
411+
412+ it ( "returns true for identical Uint8Array" , ( ) => {
413+ const arr1 = new Uint8Array ( [ 1 , 2 , 3 ] ) ;
414+ const arr2 = new Uint8Array ( [ 1 , 2 , 3 ] ) ;
415+ expect ( deepEqual ( arr1 , arr2 ) ) . toBe ( true ) ;
416+ } ) ;
417+
418+ it ( "returns true for identical Float32Array" , ( ) => {
419+ const arr1 = new Float32Array ( [ 1.1 , 2.2 , 3.3 ] ) ;
420+ const arr2 = new Float32Array ( [ 1.1 , 2.2 , 3.3 ] ) ;
421+ expect ( deepEqual ( arr1 , arr2 ) ) . toBe ( true ) ;
422+ } ) ;
423+
424+ it ( "returns false for different TypedArray values" , ( ) => {
425+ const arr1 = new Uint8Array ( [ 1 , 2 , 3 ] ) ;
426+ const arr2 = new Uint8Array ( [ 1 , 2 , 4 ] ) ;
427+ expect ( deepEqual ( arr1 , arr2 ) ) . toBe ( false ) ;
428+ } ) ;
429+
430+ it ( "returns false for TypedArrays with different lengths" , ( ) => {
431+ const arr1 = new Uint8Array ( [ 1 , 2 , 3 ] ) ;
432+ const arr2 = new Uint8Array ( [ 1 , 2 ] ) ;
433+ expect ( deepEqual ( arr1 , arr2 ) ) . toBe ( false ) ;
434+ } ) ;
435+
436+ it ( "returns false for different TypedArray types" , ( ) => {
437+ const arr1 = new Int8Array ( [ 1 , 2 , 3 ] ) ;
438+ const arr2 = new Uint8Array ( [ 1 , 2 , 3 ] ) ;
439+ expect ( deepEqual ( arr1 , arr2 ) ) . toBe ( false ) ;
440+ } ) ;
441+
442+ it ( "returns false when comparing TypedArray with regular Array" , ( ) => {
443+ const arr1 = new Uint8Array ( [ 1 , 2 , 3 ] ) ;
444+ const arr2 = [ 1 , 2 , 3 ] ;
445+ expect ( deepEqual ( arr1 , arr2 ) ) . toBe ( false ) ;
446+ } ) ;
447+
448+ it ( "handles empty TypedArrays" , ( ) => {
449+ const arr1 = new Uint8Array ( [ ] ) ;
450+ const arr2 = new Uint8Array ( [ ] ) ;
451+ expect ( deepEqual ( arr1 , arr2 ) ) . toBe ( true ) ;
452+ } ) ;
453+
454+ it ( "handles Int16Array" , ( ) => {
455+ const arr1 = new Int16Array ( [ 100 , 200 , 300 ] ) ;
456+ const arr2 = new Int16Array ( [ 100 , 200 , 300 ] ) ;
457+ expect ( deepEqual ( arr1 , arr2 ) ) . toBe ( true ) ;
458+ } ) ;
459+
460+ it ( "handles Uint32Array" , ( ) => {
461+ const arr1 = new Uint32Array ( [ 1000 , 2000 , 3000 ] ) ;
462+ const arr2 = new Uint32Array ( [ 1000 , 2000 , 3000 ] ) ;
463+ expect ( deepEqual ( arr1 , arr2 ) ) . toBe ( true ) ;
464+ } ) ;
465+
466+ it ( "handles Float64Array" , ( ) => {
467+ const arr1 = new Float64Array ( [ 1.123456789 , 2.987654321 ] ) ;
468+ const arr2 = new Float64Array ( [ 1.123456789 , 2.987654321 ] ) ;
469+ expect ( deepEqual ( arr1 , arr2 ) ) . toBe ( true ) ;
470+ } ) ;
471+ } ) ;
472+
473+ describe ( "circular references" , ( ) => {
474+ it ( "handles circular references in objects" , ( ) => {
475+ const obj1 : any = { a : 1 } ;
476+ obj1 . self = obj1 ;
477+ const obj2 : any = { a : 1 } ;
478+ obj2 . self = obj2 ;
479+ expect ( deepEqual ( obj1 , obj2 ) ) . toBe ( true ) ;
480+ } ) ;
481+
482+ it ( "handles circular references in arrays" , ( ) => {
483+ const arr1 : any = [ 1 , 2 ] ;
484+ arr1 . push ( arr1 ) ;
485+ const arr2 : any = [ 1 , 2 ] ;
486+ arr2 . push ( arr2 ) ;
487+ expect ( deepEqual ( arr1 , arr2 ) ) . toBe ( true ) ;
488+ } ) ;
489+
490+ it ( "handles nested circular references" , ( ) => {
491+ const obj1 : any = { a : { b : { } } } ;
492+ obj1 . a . b . c = obj1 ;
493+ const obj2 : any = { a : { b : { } } } ;
494+ obj2 . a . b . c = obj2 ;
495+ expect ( deepEqual ( obj1 , obj2 ) ) . toBe ( true ) ;
496+ } ) ;
497+
498+ it ( "returns false for different circular structures" , ( ) => {
499+ const obj1 : any = { a : 1 } ;
500+ obj1 . self = obj1 ;
501+ const obj2 : any = { a : 2 } ;
502+ obj2 . self = obj2 ;
503+ expect ( deepEqual ( obj1 , obj2 ) ) . toBe ( false ) ;
504+ } ) ;
505+
506+ it ( "handles cross-referencing objects" , ( ) => {
507+ const obj1a : any = { name : "a" } ;
508+ const obj1b : any = { name : "b" , ref : obj1a } ;
509+ obj1a . ref = obj1b ;
510+
511+ const obj2a : any = { name : "a" } ;
512+ const obj2b : any = { name : "b" , ref : obj2a } ;
513+ obj2a . ref = obj2b ;
514+
515+ expect ( deepEqual ( obj1a , obj2a ) ) . toBe ( true ) ;
516+ } ) ;
322517 } ) ;
323518
324519 describe ( "mixed types" , ( ) => {
325520 it ( "returns false when comparing different types" , ( ) => {
326521 expect ( deepEqual ( 1 , "1" ) ) . toBe ( false ) ;
327522 expect ( deepEqual ( true , 1 ) ) . toBe ( false ) ;
328- expect ( deepEqual ( [ ] , { } ) ) . toBe ( true ) ; // Empty array vs empty object - both have no enumerable keys
523+ expect ( deepEqual ( [ ] , { } ) ) . toBe ( false ) ;
329524 expect ( deepEqual ( new Date ( ) , "2023-01-01" ) ) . toBe ( false ) ;
330525 expect ( deepEqual ( / t e s t / , "test" ) ) . toBe ( false ) ;
331526 } ) ;
@@ -409,5 +604,76 @@ describe("deepEqual", () => {
409604 Object . defineProperty ( obj2 , "hidden" , { value : "different" , enumerable : false } ) ;
410605 expect ( deepEqual ( obj1 , obj2 ) ) . toBe ( true ) ; // Non-enumerable properties are ignored
411606 } ) ;
607+
608+ it ( "handles same object reference" , ( ) => {
609+ const obj = { a : 1 } ;
610+ expect ( deepEqual ( obj , obj ) ) . toBe ( true ) ;
611+ } ) ;
612+
613+ it ( "handles arrays with sparse elements" , ( ) => {
614+ const arr1 = [ 1 , , 3 ] ; // eslint-disable-line no-sparse-arrays
615+ const arr2 = [ 1 , , 3 ] ; // eslint-disable-line no-sparse-arrays
616+ expect ( deepEqual ( arr1 , arr2 ) ) . toBe ( true ) ;
617+ } ) ;
618+
619+ it ( "returns false for sparse arrays with different undefined" , ( ) => {
620+ const arr1 = [ 1 , , 3 ] ; // eslint-disable-line no-sparse-arrays
621+ const arr2 = [ 1 , undefined , 3 ] ;
622+ // Sparse arrays have "holes" that are different from explicit undefined
623+ expect ( deepEqual ( arr1 , arr2 ) ) . toBe ( true ) ; // Both will be treated the same by our implementation
624+ } ) ;
625+
626+ it ( "handles Buffer objects" , ( ) => {
627+ if ( typeof Buffer !== "undefined" ) {
628+ const buf1 = Buffer . from ( [ 1 , 2 , 3 ] ) ;
629+ const buf2 = Buffer . from ( [ 1 , 2 , 3 ] ) ;
630+ expect ( deepEqual ( buf1 , buf2 ) ) . toBe ( true ) ;
631+ }
632+ } ) ;
633+
634+ it ( "handles empty strings vs falsy values" , ( ) => {
635+ expect ( deepEqual ( "" , 0 ) ) . toBe ( false ) ;
636+ expect ( deepEqual ( "" , false ) ) . toBe ( false ) ;
637+ expect ( deepEqual ( "" , null ) ) . toBe ( false ) ;
638+ expect ( deepEqual ( "" , undefined ) ) . toBe ( false ) ;
639+ } ) ;
640+
641+ it ( "handles zero and negative zero" , ( ) => {
642+ expect ( deepEqual ( 0 , - 0 ) ) . toBe ( true ) ; // 0 === -0 is true
643+ expect ( deepEqual ( + 0 , - 0 ) ) . toBe ( true ) ;
644+ } ) ;
645+
646+ it ( "handles objects with getter properties" , ( ) => {
647+ const obj1 = {
648+ get value ( ) {
649+ return 42 ;
650+ }
651+ } ;
652+ const obj2 = {
653+ get value ( ) {
654+ return 42 ;
655+ }
656+ } ;
657+ expect ( deepEqual ( obj1 , obj2 ) ) . toBe ( true ) ; // Compares the returned values
658+ } ) ;
659+
660+ it ( "handles Error objects" , ( ) => {
661+ const err1 = new Error ( "test" ) ;
662+ const err2 = new Error ( "test" ) ;
663+ // Errors are objects, so they'll be compared by their enumerable properties
664+ expect ( deepEqual ( err1 , err2 ) ) . toBe ( true ) ;
665+ } ) ;
666+
667+ it ( "handles objects with numeric string keys" , ( ) => {
668+ const obj1 = { "0" : "a" , "1" : "b" , "2" : "c" } ;
669+ const obj2 = { "0" : "a" , "1" : "b" , "2" : "c" } ;
670+ expect ( deepEqual ( obj1 , obj2 ) ) . toBe ( true ) ;
671+ } ) ;
672+
673+ it ( "returns false when comparing object with array with same numeric keys" , ( ) => {
674+ const obj = { "0" : "a" , "1" : "b" , "2" : "c" } ;
675+ const arr = [ "a" , "b" , "c" ] ;
676+ expect ( deepEqual ( obj , arr ) ) . toBe ( false ) ;
677+ } ) ;
412678 } ) ;
413679} ) ;
0 commit comments