You need to enable JavaScript to run this app. react-native-testing-library测试无法获取styled-components组件props如何解决
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.11.05 16:54:03