@@ -676,5 +676,78 @@ describe('Onyx', () => {
676676 expect ( cache . hasCacheForKey ( 'key4' ) ) . toBe ( true ) ;
677677 } ) ;
678678 } ) ;
679+
680+ it ( 'Should NOT evict keys that are not in safeEvictionKeys list when cache limit is reached' , ( ) => {
681+ // Given Onyx keys configuration
682+ const testKeys = {
683+ ...ONYX_KEYS ,
684+ SAFE_FOR_EVICTION : 'evictable_' ,
685+ NOT_SAFE_FOR_EVICTION : 'critical_' ,
686+ } ;
687+
688+ // Create specific test key instances
689+ const criticalKey1 = `${ testKeys . NOT_SAFE_FOR_EVICTION } 1` ;
690+ const criticalKey2 = `${ testKeys . NOT_SAFE_FOR_EVICTION } 2` ;
691+ const criticalKey3 = `${ testKeys . NOT_SAFE_FOR_EVICTION } 3` ;
692+ const evictableKey1 = `${ testKeys . SAFE_FOR_EVICTION } 1` ;
693+ const evictableKey2 = `${ testKeys . SAFE_FOR_EVICTION } 2` ;
694+ const evictableKey3 = `${ testKeys . SAFE_FOR_EVICTION } 3` ;
695+
696+ // Given storage with some data
697+ StorageMock . getItem . mockResolvedValue ( '"mockValue"' ) ;
698+ const allKeys = [
699+ // Keys that should be evictable
700+ evictableKey1 ,
701+ evictableKey2 ,
702+ evictableKey3 ,
703+ // Keys that should NOT be evictable
704+ criticalKey1 ,
705+ criticalKey2 ,
706+ criticalKey3 ,
707+ ] ;
708+ StorageMock . getAllKeys . mockResolvedValue ( allKeys ) ;
709+
710+ // Given Onyx with a very small cache limit to force eviction
711+ return initOnyx ( {
712+ keys : testKeys ,
713+ maxCachedKeysCount : 3 , // Only allow 3 keys in cache
714+ safeEvictionKeys : [ testKeys . SAFE_FOR_EVICTION ] ,
715+ } )
716+ . then ( ( ) => {
717+ // Connect to non-evictable keys first (oldest in LRU queue)
718+ Onyx . connect ( { key : criticalKey1 , callback : jest . fn ( ) } ) ;
719+ Onyx . connect ( { key : criticalKey2 , callback : jest . fn ( ) } ) ;
720+ Onyx . connect ( { key : criticalKey3 , callback : jest . fn ( ) } ) ;
721+ } )
722+ . then ( waitForPromisesToResolve )
723+ . then ( ( ) => {
724+ // Then connect to evictable keys (more recent in LRU queue)
725+ Onyx . connect ( { key : evictableKey1 , callback : jest . fn ( ) } ) ;
726+ Onyx . connect ( { key : evictableKey2 , callback : jest . fn ( ) } ) ;
727+ Onyx . connect ( { key : evictableKey3 , callback : jest . fn ( ) } ) ;
728+ } )
729+ . then ( waitForPromisesToResolve )
730+ . then ( ( ) => {
731+ // Force an eviction by directly calling removeLeastRecentlyUsedKeys
732+ cache . removeLeastRecentlyUsedKeys ( ) ;
733+ } )
734+ . then ( waitForPromisesToResolve )
735+ . then ( ( ) => {
736+ // Get which keys were kept in cache
737+ const nonEvictableKeysInCache = [ cache . hasCacheForKey ( criticalKey1 ) , cache . hasCacheForKey ( criticalKey2 ) , cache . hasCacheForKey ( criticalKey3 ) ] ;
738+
739+ const evictableKeysInCache = [ cache . hasCacheForKey ( evictableKey1 ) , cache . hasCacheForKey ( evictableKey2 ) , cache . hasCacheForKey ( evictableKey3 ) ] ;
740+
741+ // Print results for debugging
742+ // eslint-disable-next-line no-console
743+ console . log ( 'Non-evictable keys in cache:' , nonEvictableKeysInCache ) ;
744+ // eslint-disable-next-line no-console
745+ console . log ( 'Evictable keys in cache:' , evictableKeysInCache ) ;
746+
747+ // Bug demonstration: This test should FAIL because critical keys are incorrectly evicted
748+ // The current implementation evicts based on LRU order, not respecting safeEvictionKeys
749+ expect ( nonEvictableKeysInCache . every ( ( inCache ) => inCache ) ) . toBe ( true ) ;
750+ } ) ;
751+ } ) ;
679752 } ) ;
680753} ) ;
0 commit comments