-
Notifications
You must be signed in to change notification settings - Fork 40
[MOB-12159] add-tests-for-useappstatelistener #707
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
lposen
merged 4 commits into
master
from
feature/MOB-12159-add-tests-for-useappstatelistener
Oct 8, 2025
+184
−0
Merged
Changes from all commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
39824e0
test: add unit tests for useAppStateListener hook to verify state man…
lposen a28c572
chore: remove unused index.ts hook file
lposen b34dc9b
Merge branch 'feature/MOB-12158-improve-iterable-ts-test-coverage' in…
lposen 9249cea
Merge branch 'master' into feature/MOB-12159-add-tests-for-useappstat…
lposen File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,184 @@ | ||||||
| import { renderHook, act } from '@testing-library/react-native'; | ||||||
| import { AppState } from 'react-native'; | ||||||
|
|
||||||
| import { useAppStateListener } from './useAppStateListener'; | ||||||
|
|
||||||
| describe('useAppStateListener', () => { | ||||||
| let mockListener: { remove: jest.Mock }; | ||||||
| let addEventListenerSpy: jest.SpyInstance; | ||||||
| let currentStateGetter: jest.SpyInstance; | ||||||
|
|
||||||
| beforeEach(() => { | ||||||
| jest.clearAllMocks(); | ||||||
| mockListener = { remove: jest.fn() }; | ||||||
|
|
||||||
| // Spy on AppState methods | ||||||
| addEventListenerSpy = jest.spyOn(AppState, 'addEventListener').mockReturnValue(mockListener); | ||||||
|
|
||||||
| // Mock the currentState property | ||||||
| Object.defineProperty(AppState, 'currentState', { | ||||||
| get: jest.fn(() => 'active'), | ||||||
| configurable: true, | ||||||
| }); | ||||||
| currentStateGetter = jest.spyOn(AppState, 'currentState', 'get'); | ||||||
| }); | ||||||
|
|
||||||
| afterEach(() => { | ||||||
| addEventListenerSpy.mockRestore(); | ||||||
| currentStateGetter.mockRestore(); | ||||||
| }); | ||||||
|
|
||||||
| it('should return initial app state', () => { | ||||||
| // GIVEN the hook is rendered | ||||||
| const { result } = renderHook(() => useAppStateListener()); | ||||||
|
|
||||||
| // THEN it should return the current app state | ||||||
| expect(result.current).toBe('active'); | ||||||
| }); | ||||||
|
|
||||||
| it('should set up AppState listener on mount', () => { | ||||||
| // WHEN the hook is rendered | ||||||
| renderHook(() => useAppStateListener()); | ||||||
|
|
||||||
| // THEN AppState.addEventListener should be called with correct parameters | ||||||
| expect(addEventListenerSpy).toHaveBeenCalledWith( | ||||||
| 'change', | ||||||
| expect.any(Function) | ||||||
| ); | ||||||
| }); | ||||||
|
|
||||||
| it('should update state when app state changes to background', () => { | ||||||
| // GIVEN the hook is rendered | ||||||
| const { result } = renderHook(() => useAppStateListener()); | ||||||
|
|
||||||
| // Get the listener callback | ||||||
| const listenerCallback = addEventListenerSpy.mock.calls[0][1]; | ||||||
|
|
||||||
| // WHEN app state changes to background | ||||||
| act(() => { | ||||||
| listenerCallback('background'); | ||||||
| }); | ||||||
|
|
||||||
| // THEN the hook should return the new state | ||||||
| expect(result.current).toBe('background'); | ||||||
| }); | ||||||
|
|
||||||
| it('should update state when app state changes to inactive', () => { | ||||||
| // GIVEN the hook is rendered | ||||||
| const { result } = renderHook(() => useAppStateListener()); | ||||||
|
|
||||||
| // Get the listener callback | ||||||
| const listenerCallback = addEventListenerSpy.mock.calls[0][1]; | ||||||
|
|
||||||
| // WHEN app state changes to inactive | ||||||
| act(() => { | ||||||
| listenerCallback('inactive'); | ||||||
| }); | ||||||
|
|
||||||
| // THEN the hook should return the new state | ||||||
| expect(result.current).toBe('inactive'); | ||||||
| }); | ||||||
|
|
||||||
| it('should update state when app state changes back to active', () => { | ||||||
| // GIVEN the hook is rendered and state is initially background | ||||||
| const { result } = renderHook(() => useAppStateListener()); | ||||||
| const listenerCallback = addEventListenerSpy.mock.calls[0][1]; | ||||||
|
|
||||||
| act(() => { | ||||||
| listenerCallback('background'); | ||||||
| }); | ||||||
| expect(result.current).toBe('background'); | ||||||
|
|
||||||
| // WHEN app state changes back to active | ||||||
| act(() => { | ||||||
| listenerCallback('active'); | ||||||
| }); | ||||||
|
|
||||||
| // THEN the hook should return active | ||||||
| expect(result.current).toBe('active'); | ||||||
| }); | ||||||
|
|
||||||
| it('should handle multiple state changes', () => { | ||||||
| // GIVEN the hook is rendered | ||||||
| const { result } = renderHook(() => useAppStateListener()); | ||||||
| const listenerCallback = addEventListenerSpy.mock.calls[0][1]; | ||||||
|
|
||||||
| // WHEN multiple state changes occur | ||||||
| act(() => { | ||||||
| listenerCallback('background'); | ||||||
| }); | ||||||
| expect(result.current).toBe('background'); | ||||||
|
|
||||||
| act(() => { | ||||||
| listenerCallback('inactive'); | ||||||
| }); | ||||||
| expect(result.current).toBe('inactive'); | ||||||
|
|
||||||
| act(() => { | ||||||
| listenerCallback('active'); | ||||||
| }); | ||||||
| expect(result.current).toBe('active'); | ||||||
| }); | ||||||
|
|
||||||
| it('should clean up listener on unmount', () => { | ||||||
| // GIVEN the hook is rendered | ||||||
| const { unmount } = renderHook(() => useAppStateListener()); | ||||||
|
|
||||||
| // WHEN the component unmounts | ||||||
| unmount(); | ||||||
|
|
||||||
| // THEN the listener should be removed | ||||||
| expect(mockListener.remove).toHaveBeenCalledTimes(1); | ||||||
| }); | ||||||
|
|
||||||
| it('should handle initial state with different AppState.currentState', () => { | ||||||
| // GIVEN AppState.currentState is set to background | ||||||
| currentStateGetter.mockReturnValue('background'); | ||||||
|
|
||||||
| // WHEN the hook is rendered | ||||||
| const { result } = renderHook(() => useAppStateListener()); | ||||||
|
|
||||||
| // THEN it should return the background state | ||||||
| expect(result.current).toBe('background'); | ||||||
| }); | ||||||
|
|
||||||
| it('should handle initial state with inactive AppState.currentState', () => { | ||||||
| // GIVEN AppState.currentState is set to inactive | ||||||
| currentStateGetter.mockReturnValue('inactive'); | ||||||
|
|
||||||
| // WHEN the hook is rendered | ||||||
| const { result } = renderHook(() => useAppStateListener()); | ||||||
|
|
||||||
| // THEN it should return the inactive state | ||||||
| expect(result.current).toBe('inactive'); | ||||||
| }); | ||||||
|
|
||||||
| it('should not call addEventListener multiple times on re-renders', () => { | ||||||
| // GIVEN the hook is rendered | ||||||
| const { rerender } = renderHook(() => useAppStateListener()); | ||||||
|
|
||||||
| // WHEN the component re-renders | ||||||
| rerender(() => useAppStateListener()); | ||||||
| rerender(() => useAppStateListener()); | ||||||
|
|
||||||
| // THEN addEventListener should only be called once | ||||||
| expect(addEventListenerSpy).toHaveBeenCalledTimes(1); | ||||||
| }); | ||||||
|
|
||||||
| it('should maintain state consistency across re-renders', () => { | ||||||
| // GIVEN the hook is rendered and state changes | ||||||
| const { result, rerender } = renderHook(() => useAppStateListener()); | ||||||
| const listenerCallback = addEventListenerSpy.mock.calls[0][1]; | ||||||
|
|
||||||
| act(() => { | ||||||
| listenerCallback('background'); | ||||||
| }); | ||||||
| expect(result.current).toBe('background'); | ||||||
|
|
||||||
| // WHEN the component re-renders | ||||||
| rerender(() => useAppStateListener()); | ||||||
|
||||||
| rerender(() => useAppStateListener()); | |
| rerender(); |
Empty file.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The
rerenderfunction expects no parameters, but arrow functions are being passed. This should bererender()to trigger re-renders of the same hook.