|
| 1 | +import memoizedShallowEqual from '../../lib/memoizedShallowEqual'; |
| 2 | + |
| 3 | +describe('memoizedShallowEqual', () => { |
| 4 | + describe('shallowEqual semantics', () => { |
| 5 | + it('should return true for the same reference', () => { |
| 6 | + const obj = {a: 1}; |
| 7 | + expect(memoizedShallowEqual(obj, obj)).toBe(true); |
| 8 | + }); |
| 9 | + |
| 10 | + it('should return true for different references with shallowly-equal content', () => { |
| 11 | + const member = {name: 'John'}; |
| 12 | + expect(memoizedShallowEqual({a: 1, member}, {a: 1, member})).toBe(true); |
| 13 | + }); |
| 14 | + |
| 15 | + it('should return false when a top-level value differs', () => { |
| 16 | + expect(memoizedShallowEqual({a: 1}, {a: 2})).toBe(false); |
| 17 | + }); |
| 18 | + |
| 19 | + it('should return false when key counts differ', () => { |
| 20 | + expect(memoizedShallowEqual({a: 1}, {a: 1, b: 2})).toBe(false); |
| 21 | + }); |
| 22 | + |
| 23 | + it('should return false for equal deep content with different nested references', () => { |
| 24 | + // Shallow, not deep: nested objects are compared by reference. |
| 25 | + expect(memoizedShallowEqual({member: {name: 'John'}}, {member: {name: 'John'}})).toBe(false); |
| 26 | + }); |
| 27 | + |
| 28 | + it('should handle non-object inputs', () => { |
| 29 | + expect(memoizedShallowEqual(undefined, undefined)).toBe(true); |
| 30 | + expect(memoizedShallowEqual(undefined, {})).toBe(false); |
| 31 | + expect(memoizedShallowEqual('a', 'a')).toBe(true); |
| 32 | + expect(memoizedShallowEqual('a', 'b')).toBe(false); |
| 33 | + expect(memoizedShallowEqual(1, 1)).toBe(true); |
| 34 | + expect(memoizedShallowEqual(NaN, NaN)).toBe(true); |
| 35 | + }); |
| 36 | + |
| 37 | + it('should handle arrays', () => { |
| 38 | + expect(memoizedShallowEqual([1, 2], [1, 2])).toBe(true); |
| 39 | + expect(memoizedShallowEqual([1, 2], [1, 3])).toBe(false); |
| 40 | + }); |
| 41 | + }); |
| 42 | + |
| 43 | + describe('memoization', () => { |
| 44 | + it('should return the cached verdict for the same object pair without re-comparing', () => { |
| 45 | + const a = {name: 'John'}; |
| 46 | + const b = {name: 'Jane'}; |
| 47 | + expect(memoizedShallowEqual(a, b)).toBe(false); |
| 48 | + |
| 49 | + // Mutate `b` so the objects are now content-equal. Onyx values are immutable, |
| 50 | + // so the memo is expected to keep returning the verdict computed for this exact |
| 51 | + // (a, b) pair — proving the second call resolved from the cache, not a re-compare. |
| 52 | + b.name = 'John'; |
| 53 | + expect(memoizedShallowEqual(a, b)).toBe(false); |
| 54 | + }); |
| 55 | + |
| 56 | + it('should cache verdicts per pair, not per object', () => { |
| 57 | + const a = {x: 1}; |
| 58 | + const equalToA = {x: 1}; |
| 59 | + const differentFromA = {x: 2}; |
| 60 | + |
| 61 | + expect(memoizedShallowEqual(a, equalToA)).toBe(true); |
| 62 | + expect(memoizedShallowEqual(a, differentFromA)).toBe(false); |
| 63 | + |
| 64 | + // Both verdicts are retained independently for the same `a`. |
| 65 | + expect(memoizedShallowEqual(a, equalToA)).toBe(true); |
| 66 | + expect(memoizedShallowEqual(a, differentFromA)).toBe(false); |
| 67 | + }); |
| 68 | + |
| 69 | + it('should not memoize non-object inputs', () => { |
| 70 | + // Primitives cannot be WeakMap keys; these calls must not throw and must compare directly. |
| 71 | + expect(memoizedShallowEqual(1, {})).toBe(false); |
| 72 | + expect(memoizedShallowEqual({}, 1)).toBe(false); |
| 73 | + expect(memoizedShallowEqual(null, null)).toBe(true); |
| 74 | + }); |
| 75 | + }); |
| 76 | +}); |
0 commit comments