As I understand it should be done so that useFocusEffect would work as useEffect for testing (mock). I use useFocusEffect for fetchData:
useFocusEffect(
useCallback(() => {
fetchData();
}, [fetchData]),
);
Error message: react-navigation hooks require a navigation context but it couldn't be found. Make sure you didn't forget to create and render the react-navigation app container. If you need to access an optional navigation object, you can useContext(NavigationContext), which may return
Package versions:
"jest": "^24.9.0",
"react-native": "0.61.2",
"react-navigation": "^4.0.10",
"react-navigation-hooks": "^1.1.0",
"@testing-library/react-native": "^4.0.14",
For TypeScript, it is also required to satisfy type requirements as well, so in my case, it was done by using jest.requireActual
:
const withProvider = (element, store = defaultStore) => {
// fake NavigationContext value data
const actualNav = jest.requireActual("@react-navigation/native");
const navContext = {
...actualNav.navigation,
navigate: () => {},
dangerouslyGetState: () => {},
setOptions: () => {},
addListener: () => () => {},
isFocused: () => true,
};
return (
<NavigationContext.Provider value={navContext}>
<MyComponent />
</NavigationContext.Provider>
);
};
it("renders correctly", () => {
render(withProvider(() => <SportsBooksScreen {...defaultProps} />));
});
Assuming you're rendering your component in your test, you need to wrap it in a fake <NavigationContext>
. Doing so lets useFocusEffect
look up the things it needs to determine if the component has been focused by your app's navigation.
This example uses render
from react-native-testing-library
. I think it's analogous to other rendering methods though.
import { NavigationContext } from "@react-navigation/native"
import { render } from "react-native-testing-library"
// fake NavigationContext value data
const navContext = {
isFocused: () => true,
// addListener returns an unscubscribe function.
addListener: jest.fn(() => jest.fn())
}
// MyComponent needs to be inside an NavigationContext, to allow useFocusEffect to function.
const { toJSON } = render(
<NavigationContext.Provider value={navContext}>
<MyComponent />
</NavigationContext.Provider>
)
This is just a fuller version of the above answer from @meshantz.
import { NavigationContext } from '@react-navigation/native';
import { render } from '@testing-library/react-native';
import React from 'react';
// This would probably be imported from elsewhere...
const ComponentUnderTest = () => {
useFocusEffect(
useCallback(() => {
fetchData();
}, [fetchData]),
);
return null;
};
const mockFetchData = jest.fn();
jest.mock('fetchData', () => mockFetchData);
describe('testing useFocusOnEffect in ComponentUnderTest', () => {
afterAll(() => {
jest.restoreAllMocks();
});
describe('when the view comes into focus', () => {
it('calls fetchData', () => {
const navContextValue = {
isFocused: () => false,
addListener: jest.fn(() => jest.fn()),
};
render(
<NavigationContext.Provider value={navContextValue}>
<ComponentUnderTest />
</NavigationContext.Provider>,
);
expect(mockFetchData).toBeCalledTimes(0);
render(
<NavigationContext.Provider
value={{
...navContextValue,
isFocused: () => true,
}}
>
<ComponentUnderTest />
</NavigationContext.Provider>,
);
expect(mockFetchData).toBeCalledTimes(1);
});
});
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With