javascript - Typescript: Delvis typisering av en react-navigation spionhjelper
(Dette er noe relatert til dette tre år gamle innlegget. Jeg har prøvd å følge svarene, men de løste ikke problemet mitt.)
Jeg vil lage en generell mock (spion) navigator som jeg kan sende inn slik jeg gjør her med 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'),
})
})
})
Jeg vil gjerne abstrahere spyNavigation til en testhjelper og få TypeScript til å hjelpe meg med delvis typisering av den. Slik vil det fullføre metoder som 'replace', 'push' osv.
TypeScript-en til react-navigation er bare så kompleks for meg å forstå. Det hadde vært greit om spionen ikke vet om navnene Screens/Navigators - bare å være et generelt "navigasjons"-objekt.
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>
>
dette fungerer ikke
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)
Jeg har et gjetning på at det burde være noe som
export const mockNavigation: Record<keyof ???, () => ReturnType<typeof jest.fn>> = {
navigate: jest.fn(),
push: jest.fn(),
replace: jest.fn(),
pop: jest.fn(),
}
Svar #1
Her er en potensiell løsning på spørsmålet ditt etter kommentarene dine! Jeg håper dette fungerer for deg. Jeg utvider StackNavigationProp som har navnene på funksjonene du ønsker: navigate, push osv. Også ut fra spørsmålet ditt, erstatter jeg typene på egenskapene dens med returverdien til jest.fn.
De valgfrie generiske typene for MockStackNavigationProp bør også speile de for StackNavigationProp, og lar deg spesifisere om ParamList er tilgjengelig.
Hvis dette fungerer, lurer jeg på om det også kunne tas videre for å automatisk utlede argumenttypene til jest-funksjonsmockene fra de opprinnelige funksjonsdefinisjonene.
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-lenke.
