(This is somewhat related to this three year-old post. I have tried to to follow the answers but they did not resolve my problem.)
I want to build a general mock (spy) navigator that I can pass in like I do here with spyNavigation:
it('shows an error if the request fails', async () => {
const spyNavigation = {
replace: jest.fn(),
push: jest.fn(),
}
mockServer.use(
rest.get('*/users/current-user', (req, res, ctx) => {
return res(ctx.status(200), ctx.json({ id: 1 }))
})
)
mockServer.use(
rest.get('*/some-data', (req, res, ctx) => {
return res(ctx.status(500))
})
)
// @ts-ignore
TestHelper.renderWithReactQueryClient(<OverviewScreen navigation={spyNavigation} />)
await TestHelper.waitForWithExtendedTimeOut(() => {
expect(spyNavigation.push).toHaveBeenCalledWith('Error', {
error: new Error('Request failed with status code 500'),
})
})
})
I would like to abstract the spyNavigation to a test helper and have TypeScript help me out to Partial typing it. So it will code-complete methods like 'replace', 'push' etc.
The TypeScript of react-navigation is just so complex for me to understand. It would be fine if the spy does not know about the names Screens/Navigators - just to be a general "navigation" object.
import { BottomTabScreenProps } from '@react-navigation/bottom-tabs'
import { CompositeScreenProps, NavigatorScreenParams } from '@react-navigation/native'
import { NativeStackScreenProps } from '@react-navigation/native-stack'
import { AxiosError } from 'axios'
declare global {
namespace ReactNavigation {
interface RootParamList extends RootStackParamList {}
}
}
export type RootStackParamList = {
SignInOrCreateUser: undefined
SignIn: undefined
Root: NavigatorScreenParams<RootTabParamList> | undefined
Modal: undefined
Error: { error: AxiosError | null } | undefined
}
export type RootTabParamList = {
Overview: undefined
Returns: undefined
Portfolio: undefined
More: undefined
}
export type RouteName = keyof RootStackParamList | keyof RootTabParamList
export const routeTypeGuard = (route: RouteName) => route
export type RootStackScreenProps<Screen extends keyof RootStackParamList> = NativeStackScreenProps<
RootStackParamList,
Screen
>
export type RootTabScreenProps<Screen extends keyof RootTabParamList> = CompositeScreenProps<
BottomTabScreenProps<RootTabParamList, Screen>,
NativeStackScreenProps<RootStackParamList>
>
this does not work
import { NativeStackNavigatorProps } from '@react-navigation/native-stack/lib/typescript/src/types'
export const mockNavigation: NativeStackNavigatorProps = {
navigate: jest.fn(),
push: jest.fn(),
replace: jest.fn(),
pop: jest.fn(),
}
Type '{ navigate: jest.Mock<any, any>; push: jest.Mock<any, any>; replace: jest.Mock<any, any>; pop: jest.Mock<any, any>; }' is not assignable to type 'NativeStackNavigatorProps'.
Object literal may only specify known properties, and 'navigate' does not exist in type 'NativeStackNavigatorProps'.ts(2322)
I have a guess that it should be something like
export const mockNavigation: Record<keyof ???, () => ReturnType<typeof jest.fn>> = {
navigate: jest.fn(),
push: jest.fn(),
replace: jest.fn(),
pop: jest.fn(),
}
Here is a potential solution to your question after your comments! I hope this works for you. I am extending the StackNavigationProp which has the names of the functions you want: navigate, push etc. Also from your question, I am replacing the types of its properties to be the return of jest.fn.
The optional generics for MockStackNavigationProp, should also mirror those of StackNavigationProp, allowing you to specify if ParamList if available.
If this works, I wonder if it could be taken further to also have the argument types of the jest function mocks, be automatically inferred from the original function definitions.
import { ParamListBase } from "@react-navigation/native";
import { StackNavigationProp } from "@react-navigation/stack";
type MockStackNavigationProp<
ParamList extends ParamListBase = any,
RouteName extends keyof ParamList = string
> = Record<
keyof StackNavigationProp<ParamList, RouteName>,
ReturnType<typeof jest.fn>
>;
const mockNavigation: MockStackNavigationProp = {
navigate: jest.fn(),
pop: jest.fn(),
push: jest.fn()
//.. and more, OR use Partial<MockStackNavigationProp>
};
CodeSandbox link.
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