自定义禁用按钮getAttributes()返回enabled属性错误问题排查
Detox getAttributes()返回enabled属性错误问题排查
问题现象
在Android和iOS平台使用Detox的getAttributes()方法时,遇到元素enabled属性返回错误的情况。通过Appium Inspector和Layout Inspector确认,对应testID的元素处于禁用状态,但Detox无法验证这一点,返回的enabled值为true。Appium inspector显示:enabled: false
预期行为
在此场景下,预期getAttributes()返回的enabled属性值为false。
复现代码
自定义按钮BaseButton代码
import React from 'react'; import {Animated, Platform, Pressable} from 'react-native'; import {rippleColors} from './types'; const Wrapper = ({containerStyle, children, testID}) => { if (!containerStyle) { return <>{children}</>; } return <Animated.View testID={testID} style={containerStyle}>{children}</Animated.View>; }; const BaseButton = ({ variant = 'outline', onPress, disable, testID, containerStyle, buttonStyle, children, borderless = false, radius, foreground, ...rest }) => { return ( <Wrapper containerStyle={containerStyle} testID={testID + '.wrapper'}> <Pressable testID={testID} rippleColor={rippleColors[variant]} android_ripple={{ color: rippleColors[variant], borderless, radius, foreground, }} onPress={onPress} disabled={disable} enabled={!disable} style={({pressed}) => [ buttonStyle, Platform.OS === 'ios' && { backgroundColor: pressed ? rippleColors[variant] : 'transparent', }, ]} {...rest}> {children} </Pressable> </Wrapper> ); }; export default BaseButton;
按钮在汉堡菜单Header组件中的使用代码
import React, {useCallback} from 'react'; import {StyleSheet, View} from 'react-native'; import useTheme from '@/theme'; import {BaseButton, Body, Icon} from '@/components'; import {Navigation} from 'react-native-navigation'; import {useNavigation} from 'react-native-navigation-hooks'; const styles = theme => StyleSheet.create({ button: { flexDirection: 'row', padding: theme.spacing.sizes.l, alignItems: 'center', justifyContent: 'space-between', }, }); const Header = ({ title, action, root, setSection, disable = false, selected = false, }) => { const {theme} = useTheme(); const style = styles(theme); const {mergeOptions} = useNavigation(); const onPress = useCallback(async () => { if (root) { await Navigation.setRoot(root); return; } if (action) { mergeOptions({sideMenu: {left: {visible: false}}}); action(); return; } setSection && setSection(title); }, [action, mergeOptions, root, setSection, title]); return ( <BaseButton disable={disable} onPress={onPress} testID={`common.hamburger.section.${title}`}> <View style={style.button}> <Body testID={`hamburger.menu.header.${title}`} variant="m" numberOfLines={1} tx={`hamburger-menu.header.${title}`} color={disable ? theme.colors.basic.t48 : undefined} /> {!action && !root && ( <> {selected && ( <Icon name="up" size="m" color={theme.colors.darkGrey.base} /> )} {!selected && ( <Icon name="down" size="m" color={ disable ? theme.colors.basic.t24 : theme.colors.darkGrey.base } /> )} </> )} </View> </BaseButton> ); }; export default Header;
运行环境
- Detox版本:20.28.0
- React Native版本:0.72.5
- 未启用Fabric渲染系统
- Node版本:18.20.4
- 设备型号:Pixel 7a
- Android版本:Android 15.0 arm64-v8a
- 测试框架:jest
Detox日志信息
执行console.log(JSON.stringify(await element(by.id(ElementIds.HamburgerMenu.operationSection)).getAttributes(), null, 2))后,日志显示返回的enabled值为true,导致验证元素禁用状态失败,报错信息如下:
12:25:29.755 detox[9681] [90mi[39m 验证元素状态为"disabled"失败,元素匹配规则为'[{"type":"Invocation","value":{"target":{"type":"Class","value":"com.wix.detox.espresso.DetoxMatcher"},"method":"matcherForAnd","args":[{"type":"Invocation","value":{"target":{"type":"Class","value":"com.wix.detox.espresso.DetoxMatcher"},"method":"matcherForClass","args":["android.view.ViewGroup"]}},{"type":"Invocation","value":{"target":{"type":"Class","value":"com.wix.detox.espresso.DetoxMatcher"},"method":"matcherForTestId","args":["common.hamburger.section.operation",{"type":"boolean","value":false}]}}]}},{"type":"Invocation","value":{"target":{"type":"Class","value":"com.wix.detox.espresso.DetoxMatcher"},"method":"matcherForText","args":["TAŞIMA FAALİYETLERİM",{"type":"boolean","value":false}]}}]': 错误:元素未禁用: [{"type":"Invocation","value":{"target":{"type":"Class","value":"com.wix.detox.espresso.DetoxMatcher"},"method":"matcherForAnd","args":[{"type":"Invocation","value":{"target":{"type":"Class","value":"com.wix.detox.espresso.DetoxMatcher"},"method":"matcherForClass","args":["android.view.ViewGroup"]}},{"type":"Invocation","value":{"target":{"type":"Class","value":"com.wix.detox.espresso.DetoxMatcher"},"method":"matcherForTestId","args":["common.hamburger.section.operation",{"type":"boolean","value":false}]}}]}},{"type":"Invocation","value":{"target":{"type":"Class","value":"com.wix.detox.espresso.DetoxMatcher"},"method":"matcherForText","args":["TAŞIMA FAALİYETLERİM",{"type":"boolean","value":false}]}}] 在 HamburgerMenu.<anonymous> (/Users/erdem.kilic/Desktop/lastmile-courier-app/e2e/base/BasePage.ts:60:19) 在 Generator.next (<anonymous>) 在 asyncGeneratorStep (/Users/erdem.kilic/Desktop/lastmile-courier-app/node_modules/@babel/runtime/helpers/asyncToGenerator.js:3:17) 在 _next (/Users/erdem.kilic/Desktop/lastmile-courier-app/node_modules/@babel/runtime/helpers/asyncToGenerator.js:17:9) 在 processTicksAndRejections (node:internal/process/task_queues:95:5)
内容的提问来源于stack exchange,提问作者erdemkiiliic
相关产品推荐
相关产品推荐

