@@ -1566,13 +1566,66 @@ describe('OnyxUtils', () => {
15661566
15671567 await LocalOnyx . multiSet ( { [ memberKey ] : { value : 'updated' } } ) ;
15681568
1569- // The in-flight key was evicted then restored by the retry's cache.set. Subscriber's
1570- // last value must be the new value, never a transient undefined from the eviction .
1569+ // The in-flight key is excluded from eviction, so its cache value ( the merge base) is
1570+ // never dropped. Subscriber's last value is the new value, never a transient undefined.
15711571 expect ( LocalOnyxCache . get ( memberKey ) ) . toEqual ( { value : 'updated' } ) ;
15721572 expect ( subscriberCalls . at ( - 1 ) ) . toEqual ( { value : 'updated' } ) ;
15731573 // Subscriber should never have seen undefined in the middle of the eviction-retry cycle.
15741574 expect ( subscriberCalls ) . not . toContain ( undefined ) ;
15751575 } ) ;
1576+
1577+ it ( 'mergeCollection — evicts an unrelated key, not the in-flight key, so its fields survive' , async ( ) => {
1578+ const collectionKey = ONYXKEYS . COLLECTION . TEST_KEY ;
1579+ const memberKey = `${ collectionKey } 1` ;
1580+ const unrelatedKey = `${ collectionKey } 2` ;
1581+
1582+ // Seed the in-flight member with extra fields, plus a separate evictable key. The merge
1583+ // only touches memberKey; the unrelated key is the genuine eviction target.
1584+ await LocalOnyx . set ( memberKey , { id : 1 , value : 'orig' } ) ;
1585+ await LocalOnyx . set ( unrelatedKey , { value : 'evict-me' } ) ;
1586+
1587+ const memberCalls : unknown [ ] = [ ] ;
1588+ LocalOnyx . connect ( { key : memberKey , callback : ( value ) => memberCalls . push ( value ) } ) ;
1589+ await waitForPromisesToResolve ( ) ;
1590+ memberCalls . length = 0 ;
1591+
1592+ // Storage.multiMerge rejects once with disk-full, then succeeds on retry.
1593+ LocalStorageMock . multiMerge = jest . fn ( LocalStorageMock . multiMerge ) . mockRejectedValueOnce ( diskFullError ) . mockImplementation ( LocalStorageMock . multiMerge ) ;
1594+
1595+ await LocalOnyx . mergeCollection ( collectionKey , { [ memberKey ] : { value : 'merged' } } as GenericCollection ) ;
1596+
1597+ // The old code evicted the in-flight key and re-ran the merge against an empty cache,
1598+ // collapsing {id: 1, value: 'orig'} + {value: 'merged'} to just {value: 'merged'}. Now
1599+ // the in-flight key is protected, so its pre-existing {id: 1} survives.
1600+ expect ( LocalOnyxCache . get ( memberKey ) ) . toEqual ( { id : 1 , value : 'merged' } ) ;
1601+ expect ( memberCalls . at ( - 1 ) ) . toEqual ( { id : 1 , value : 'merged' } ) ;
1602+ expect ( memberCalls ) . not . toContain ( undefined ) ;
1603+ // The unrelated key was the genuine eviction target.
1604+ expect ( LocalOnyxCache . hasCacheForKey ( unrelatedKey ) ) . toBe ( false ) ;
1605+ } ) ;
1606+
1607+ it ( 'mergeCollection — does not truncate the in-flight key when it is the only evictable key' , async ( ) => {
1608+ const collectionKey = ONYXKEYS . COLLECTION . TEST_KEY ;
1609+ const memberKey = `${ collectionKey } 1` ;
1610+
1611+ await LocalOnyx . set ( memberKey , { id : 1 , value : 'orig' } ) ;
1612+ expect ( LocalOnyxCache . getKeyForEviction ( ) ) . toBe ( memberKey ) ;
1613+
1614+ const memberCalls : unknown [ ] = [ ] ;
1615+ LocalOnyx . connect ( { key : memberKey , callback : ( value ) => memberCalls . push ( value ) } ) ;
1616+ await waitForPromisesToResolve ( ) ;
1617+ memberCalls . length = 0 ;
1618+
1619+ // The only evictable key is the in-flight one, which is now excluded — so retryOperation
1620+ // finds no acceptable key and reports the quota instead of dropping (and truncating) it.
1621+ LocalStorageMock . multiMerge = jest . fn ( LocalStorageMock . multiMerge ) . mockRejectedValue ( diskFullError ) ;
1622+
1623+ await LocalOnyx . mergeCollection ( collectionKey , { [ memberKey ] : { value : 'merged' } } as GenericCollection ) ;
1624+
1625+ expect ( LocalOnyxCache . get ( memberKey ) ) . toEqual ( { id : 1 , value : 'merged' } ) ;
1626+ expect ( memberCalls . at ( - 1 ) ) . toEqual ( { id : 1 , value : 'merged' } ) ;
1627+ expect ( memberCalls ) . not . toContain ( undefined ) ;
1628+ } ) ;
15761629 } ) ;
15771630
15781631 describe ( 'afterInit' , ( ) => {
0 commit comments