为 MockComponent 编写 JSX 语法并使用打字稿输入
Making a JSX syntax for a MockComponent and have it typed with typescript
想知道是否有人对如何破解此问题有一些好的建议。得到这个测试助手实用程序我已经添加了一些类型:
import { jest } from '@jest/globals'
import React from 'react'
// https://learn.reactnativeschool.com/courses/781007/lectures/14173979
export function mockComponent(moduleName: string, propOverrideFn = (props: Record<string, any>) => ({})) {
const RealComponent = jest.requireActual(moduleName) as React.ComponentType<any>
const CustomizedComponent = (props: Record<string, any>) => {
return React.createElement(
'CustomizedComponent',
{
...props,
...propOverrideFn(props),
},
props.children
)
}
CustomizedComponent.propTypes = RealComponent.propTypes
return CustomizedComponent
}
所以目前我可以这样称呼它
jest.mock('react-native/Libraries/Components/Touchable/TouchableOpacity', () => {
return mockComponent('react-native/Libraries/Components/Touchable/TouchableOpacity', (props) => {
return {
onPress: props.disabled ? () => {} : props.onPress
}
})
})
但我希望能够更像
jest.mock('react-native/Libraries/Components/Touchable/TouchableOpacity', () => {
return <MockComponent
module='TouchableOpacity'
onPress={props => props.disabled ? () => {} : props.onPress}
/>
})
或
jest.mock('react-native/Libraries/Components/Touchable/TouchableOpacity', () => {
return <MockComponent
module='TouchableOpacity'
propOverride={props => ({onPress: props.disabled ? () => {} : props.onPress, ...props})}
/>
})
如果您查看 React without JSX,您会发现 XML-inspired 语法 (<MockComponent />
) 只是 React.createElement('MockComponent')
.
的缩写
现在,如果您将 mockComponent
重命名为 MockComponent
并尝试使用尖括号语法,第一个 问题是您的函数接收两个参数. React 组件要么是 class 个接受一个构造函数参数(props)的组件,要么是接受一个参数(同样是 props)的函数式组件。 第二个 问题是你的函数 return 是一个 React 功能组件,当它需要 return 一个 渲染的 React 元素时.
解决此问题的一种方法是将 mockComponent
转换为 React 功能组件,并制作 FC 的 module
和 propOverride
道具。
// https://learn.reactnativeschool.com/courses/781007/lectures/14173979
export function MockComponent(props) {
const { moduleName, propOverrideFn, ...customComponentProps } = props;
const RealComponent = jest.requireActual(moduleName) as React.ComponentType<any>
const CustomizedComponent = (props: Record<string, any>) => {
return React.createElement(
'CustomizedComponent',
{
...props,
...propOverrideFn(props),
},
props.children
)
}
CustomizedComponent.propTypes = RealComponent.propTypes
return <CustomizedComponent {...customComponentProps} />
}
差异很小但很重要。这里我修改了 MockComponent
以接受一个单一的 prop
参数以与 React.createElement()
兼容。这导致了如何区分 CustomizedComponent
的 props 和 mockComponent()
的参数的问题。在这里,我使用 JavaScript 解构和扩展运算符将 module
和 propOverride
与 CustomizedComponent
.
的 props 分开
最后,我使用 JSX spread syntax 将用于 CustomizedComponent
的任意道具传递给 CustomizedComponent
,并使用尖括号来渲染它(而不是 return调用函数)。
我将作为练习留给您,让您为 MockComponent 的道具提出适当的 TypeScript 定义。您可以简单地将其定义为 Record 和 module
和 propOverride
的并集。但是,您可以想象并使用模板定义,因此 MockComponent<Toolbar>
是 module
和 propOverride
以及 Toolbar
的联合。
哦,我差点忘了。你的 Jest 电话看起来像
jest.mock('react-native/Libraries/Components/Touchable/TouchableOpacity', () => {
(props) => {
return <MockComponent
module='TouchableOpacity'
onPress={props => props.disabled ? () => {} : props.onPress}
{...props}
/>
}
})
想知道是否有人对如何破解此问题有一些好的建议。得到这个测试助手实用程序我已经添加了一些类型:
import { jest } from '@jest/globals'
import React from 'react'
// https://learn.reactnativeschool.com/courses/781007/lectures/14173979
export function mockComponent(moduleName: string, propOverrideFn = (props: Record<string, any>) => ({})) {
const RealComponent = jest.requireActual(moduleName) as React.ComponentType<any>
const CustomizedComponent = (props: Record<string, any>) => {
return React.createElement(
'CustomizedComponent',
{
...props,
...propOverrideFn(props),
},
props.children
)
}
CustomizedComponent.propTypes = RealComponent.propTypes
return CustomizedComponent
}
所以目前我可以这样称呼它
jest.mock('react-native/Libraries/Components/Touchable/TouchableOpacity', () => {
return mockComponent('react-native/Libraries/Components/Touchable/TouchableOpacity', (props) => {
return {
onPress: props.disabled ? () => {} : props.onPress
}
})
})
但我希望能够更像
jest.mock('react-native/Libraries/Components/Touchable/TouchableOpacity', () => {
return <MockComponent
module='TouchableOpacity'
onPress={props => props.disabled ? () => {} : props.onPress}
/>
})
或
jest.mock('react-native/Libraries/Components/Touchable/TouchableOpacity', () => {
return <MockComponent
module='TouchableOpacity'
propOverride={props => ({onPress: props.disabled ? () => {} : props.onPress, ...props})}
/>
})
如果您查看 React without JSX,您会发现 XML-inspired 语法 (<MockComponent />
) 只是 React.createElement('MockComponent')
.
现在,如果您将 mockComponent
重命名为 MockComponent
并尝试使用尖括号语法,第一个 问题是您的函数接收两个参数. React 组件要么是 class 个接受一个构造函数参数(props)的组件,要么是接受一个参数(同样是 props)的函数式组件。 第二个 问题是你的函数 return 是一个 React 功能组件,当它需要 return 一个 渲染的 React 元素时.
解决此问题的一种方法是将 mockComponent
转换为 React 功能组件,并制作 FC 的 module
和 propOverride
道具。
// https://learn.reactnativeschool.com/courses/781007/lectures/14173979
export function MockComponent(props) {
const { moduleName, propOverrideFn, ...customComponentProps } = props;
const RealComponent = jest.requireActual(moduleName) as React.ComponentType<any>
const CustomizedComponent = (props: Record<string, any>) => {
return React.createElement(
'CustomizedComponent',
{
...props,
...propOverrideFn(props),
},
props.children
)
}
CustomizedComponent.propTypes = RealComponent.propTypes
return <CustomizedComponent {...customComponentProps} />
}
差异很小但很重要。这里我修改了 MockComponent
以接受一个单一的 prop
参数以与 React.createElement()
兼容。这导致了如何区分 CustomizedComponent
的 props 和 mockComponent()
的参数的问题。在这里,我使用 JavaScript 解构和扩展运算符将 module
和 propOverride
与 CustomizedComponent
.
最后,我使用 JSX spread syntax 将用于 CustomizedComponent
的任意道具传递给 CustomizedComponent
,并使用尖括号来渲染它(而不是 return调用函数)。
我将作为练习留给您,让您为 MockComponent 的道具提出适当的 TypeScript 定义。您可以简单地将其定义为 Recordmodule
和 propOverride
的并集。但是,您可以想象并使用模板定义,因此 MockComponent<Toolbar>
是 module
和 propOverride
以及 Toolbar
的联合。
哦,我差点忘了。你的 Jest 电话看起来像
jest.mock('react-native/Libraries/Components/Touchable/TouchableOpacity', () => {
(props) => {
return <MockComponent
module='TouchableOpacity'
onPress={props => props.disabled ? () => {} : props.onPress}
{...props}
/>
}
})