react-native-testing-library测试无法获取styled-components组件props如何解决
React Native Testing Library 读取封装按钮组件props异常问题
问题背景
项目中基于 styled-components 封装了通用的Button组件,在使用 react-native-testing-library 编写单元测试时,通过testID拿到的元素props缺失了外部传入的disabled、onPress字段,无法直接对这些属性做断言验证。
现有代码实现
封装的Button组件
export const StyledButton = styled.TouchableOpacity<IButtonProps>` height: 46px; width: 100%; display: flex; flex-direction: row; justify-content: center; align-items: center; border-radius: 8px; background: ${EAppColors.BLACK}; opacity: ${props => (props.disabled ? 0.6 : 1)}; `; interface IButtonProps { readonly children: React.ReactNode; readonly onPress: () => any; readonly style?: StyleProp<ViewStyle>; readonly testID?: string; readonly disabled?: boolean; } const Button: React.FC<IButtonProps> = ({ children, style, onPress, disabled = false, }) => { return ( <StyledButton testID={'button.simple'} onPress={onPress} style={style} disabled={disabled}> {children} </StyledButton> ); };
现有测试用例
const { getByTestId } = render( <Button disabled={false} onPress={onPressMock}> <Text>Title</Text> </Button>, ); // 打印获取到的元素props console.log(getByTestId('button.simple').props);
实际输出表现
执行测试后,终端打印的props仅包含以下字段,缺失了disabled、onPress等传入的属性:
{ accessible: true, style: { height: 46, width: '100%', display: 'flex', flexDirection: 'row', justifyContent: 'center', alignItems: 'center', borderRadius: 8, backgroundColor: '#000000', opacity: 1 }, testID: 'button.simple' }
问题根因
出现这类现象的核心原因有两点:
react-native-testing-library通过testID查询定位时,找到的是styled-components最终渲染出的原生底层组件节点,styled-components作为高阶组件会对传入的属性做转发和处理,部分自定义属性不会被原样保留到最终渲染节点的props上- React Native 原生TouchableOpacity组件的
disabled、onPress属于组件内部消费的交互属性,不会被默认暴露到节点对外可读取的props对象中,因此哪怕正确传入了参数,打印节点props时也看不到对应字段
解决方案
1. 优先通过交互行为做断言(推荐)
单元测试的核心是验证组件的实际表现,而非校验内部属性值,因此不需要直接读取disabled的props值,而是通过测试库提供的交互API验证实际行为:
- 当
disabled为true时,触发按钮的press事件,验证绑定的onPress回调不会被执行
示例代码:
// 验证disabled状态下,按钮点击不会触发回调 const onPressMock = jest.fn() render( <Button disabled={true} onPress={onPressMock}> <Text>Title</Text> </Button> ) fireEvent.press(getByTestId('button.simple')) expect(onPressMock).not.toHaveBeenCalled() // 验证非disabled状态下,按钮点击可以正常触发回调 render( <Button disabled={false} onPress={onPressMock}> <Text>Title</Text> </Button> ) fireEvent.press(getByTestId('button.simple')) expect(onPressMock).toHaveBeenCalledTimes(1)
2. 通过标准可访问性属性暴露需要测试的值
如果确实需要直接读取属性值做断言,可以将disabled值通过RN规范的accessibilityState属性透传到节点上,这个属性会被正常保留在节点可读取的props中:
修改组件内StyledButton的传参:
<StyledButton testID={'button.simple'} onPress={onPress} style={style} disabled={disabled} // 新增accessibilityState透传disabled状态 accessibilityState={{ disabled }} > {children} </StyledButton>
测试时就可以直接读取对应值做断言:
const buttonElement = getByTestId('button.simple') expect(buttonElement.props.accessibilityState.disabled).toBe(true)
3. 直接查询封装的Button组件实例获取原始props
如果一定要拿到Button组件本身接收到的所有原始传入属性,可以借助react-test-renderer的API直接找到对应封装组件的实例:
import TestRenderer from 'react-test-renderer' // 渲染组件 const testRenderer = TestRenderer.create( <Button disabled={false} onPress={onPressMock}> <Text>Title</Text> </Button> ) // 找到Button组件的实例 const buttonInstance = testRenderer.root.findByType(Button) // 读取组件接收的原始props console.log(buttonInstance.props.disabled) // 输出 false expect(buttonInstance.props.disabled).toBe(false)
内容的提问来源于stack exchange,提问作者E.D
相关产品推荐
相关产品推荐

