11import React from 'react'
2- import { Button , Text } from 'react-native'
2+ import { AppState , Button , Text } from 'react-native'
3+ import type { AppStateStatus , NativeEventSubscription } from 'react-native'
34import {
45 act ,
56 fireEvent ,
@@ -9,7 +10,7 @@ import {
910 cleanup ,
1011 waitFor ,
1112} from '@testing-library/react-native'
12- import { createMMKV , useMMKVNumber , useMMKVString } from '..'
13+ import { createMMKV , useMMKVKeys , useMMKVNumber , useMMKVString } from '..'
1314
1415const mmkv = createMMKV ( )
1516
@@ -20,8 +21,37 @@ beforeEach(() => {
2021
2122afterEach ( ( ) => {
2223 cleanup ( )
24+ jest . restoreAllMocks ( )
2325} )
2426
27+ function mockAppStateChangeListener ( ) : {
28+ emit : ( state : AppStateStatus ) => void
29+ } {
30+ const listeners = new Set < ( state : AppStateStatus ) => void > ( )
31+
32+ jest
33+ . spyOn ( AppState , 'addEventListener' )
34+ . mockImplementation ( ( type , listener ) : NativeEventSubscription => {
35+ if ( type === 'change' ) {
36+ listeners . add ( listener as ( state : AppStateStatus ) => void )
37+ }
38+
39+ return {
40+ remove : ( ) => {
41+ listeners . delete ( listener as ( state : AppStateStatus ) => void )
42+ } ,
43+ } as NativeEventSubscription
44+ } )
45+
46+ return {
47+ emit : ( state ) => {
48+ act ( ( ) => {
49+ listeners . forEach ( ( listener ) => listener ( state ) )
50+ } )
51+ } ,
52+ }
53+ }
54+
2555test ( 'hooks update when the value is changed directly through the instance' , ( ) => {
2656 const { result } = renderHook ( ( ) => useMMKVString ( 'string-key' , mmkv ) )
2757
@@ -129,3 +159,40 @@ test('useMMKV hook stays consistent during rapid updates', async () => {
129159 expect ( result . current [ 0 ] ) . toBe ( 100 )
130160 } )
131161} )
162+
163+ test ( 'useMMKV hook checks for external content changes when app becomes active' , ( ) => {
164+ const appState = mockAppStateChangeListener ( )
165+ const key = 'app-state-key'
166+ let value = 'before'
167+
168+ const checkContentChanged = jest . spyOn ( mmkv , 'checkContentChanged' )
169+ jest . spyOn ( mmkv , 'getString' ) . mockImplementation ( ( requestedKey ) => {
170+ return requestedKey === key ? value : undefined
171+ } )
172+
173+ const { result } = renderHook ( ( ) => useMMKVString ( key , mmkv ) )
174+ expect ( result . current [ 0 ] ) . toStrictEqual ( 'before' )
175+
176+ value = 'after'
177+ appState . emit ( 'active' )
178+
179+ expect ( checkContentChanged ) . toHaveBeenCalledTimes ( 1 )
180+ expect ( result . current [ 0 ] ) . toStrictEqual ( 'after' )
181+ } )
182+
183+ test ( 'useMMKVKeys checks for external content changes when app becomes active' , ( ) => {
184+ const appState = mockAppStateChangeListener ( )
185+ let keys : string [ ] = [ ]
186+
187+ const checkContentChanged = jest . spyOn ( mmkv , 'checkContentChanged' )
188+ jest . spyOn ( mmkv , 'getAllKeys' ) . mockImplementation ( ( ) => keys )
189+
190+ const { result } = renderHook ( ( ) => useMMKVKeys ( mmkv ) )
191+ expect ( result . current ) . toStrictEqual ( [ ] )
192+
193+ keys = [ 'external-key' ]
194+ appState . emit ( 'active' )
195+
196+ expect ( checkContentChanged ) . toHaveBeenCalledTimes ( 1 )
197+ expect ( result . current ) . toStrictEqual ( [ 'external-key' ] )
198+ } )
0 commit comments