Appium React Native 尚未准备好进行文本输入

Appium React Native Not Ready for Text Input

我最近切换到 Appium + webdriverIO 进行 E2E 测试。除了一个与文本输入相关的测试用例外,一切都运行良好。

基本上,被测组件是一个使用redux-form进行表单管理的登录界面。我不断收到错误 "'"login-field" Other' is not ready for a text input. Neither the accessibility element itself nor its accessible descendants have the input focus"。组成部分如下:

SignInScreen.tsx

export class SignInScreen extends React.Component<any> {
  render() {
    const { handleSubmit, submitting, style } = this.props;
    return (
      <View style={style}>
        <View>
          <View>
            <Field
              name="login"
              component={Input}
              accessibilityLabel="login-field"
              testID="login-field"
            />
            <Field
              secureTextEntry
              name="password"
              component={Input}
              accessibilityLabel="password-field"
              testID="password-field"
            />
          </View>
        </View>
      </View>
    );
  }
}

Input.tsx

export class Input extends React.Component {
  render() {
    const {
      input,
      meta: { error, active, focused },
      accessibilityLabel,
      testID
    } = this.props;

    const showError = !active && !!error && !focused;
    const errorText = "ERROR!"

    return (
      <View style={[style, styles.container]}>
        <TextInput
          autoCapitalize="none"
          value={input.value}
          onChangeText={input.onChange}
          onFocus={input.onFocus}
          onBlur={input.onBlur}
          accessibilityLabel={accessibilityLabel},
          testID={testID}
        />

        <View style={{height: 30}}>
          {showError && (
            <Text>{errorText}</Text>
          )}
        </View>
      </View>
    );
  }
}

SignInScreen.test.ts

describe('Sign In Screen Test', () => {
  let client;

  beforeAll(async () => {
    // set up code
  });

  afterAll(async () => {
    // tear down code
  });

  it('Can login', async () => {
    const loginField = await client.$('~login-field');
    await loginField.setValue('test@gmail.com'); // error here

    const passwordField = await client.$('~password-field');
    await passwordField.set('password' + '\n');
  });
});

我确实意识到,当我在 Input.tsx 组件中的现有 <TextInput /> 组件之上添加一个额外的 <TextInput /> 时,测试用例会起作用,如下所示:

Input.tsx

export class Input extends React.Component {
  render() {
    const {
      input,
      meta: { error, active, focused },
      accessibilityLabel,
      testID
    } = this.props;

    const showError = !active && !!error && !focused;
    const errorText = "ERROR!"

    return (
      <View style={[style, styles.container]}>
        <TextInput />
        <TextInput
          autoCapitalize="none"
          value={input.value}
          onChangeText={input.onChange}
          onFocus={input.onFocus}
          onBlur={input.onBlur}
          accessibilityLabel={accessibilityLabel},
          testID={testID}
        />

        <View style={{height: 30}}>
          {showError && (
            <Text>{errorText}</Text>
          )}
        </View>
      </View>
    );
  }
}

或者我把嵌套错误信息的View组件中的固定高度去掉如下:

Input.tsx

export class Input extends React.Component {
  render() {
    const {
      input,
      meta: { error, active, focused },
      accessibilityLabel,
      testID
    } = this.props;

    const showError = !active && !!error && !focused;
    const errorText = "ERROR!"

    return (
      <View style={[style, styles.container]}>
        <TextInput
          autoCapitalize="none"
          value={input.value}
          onChangeText={input.onChange}
          onFocus={input.onFocus}
          onBlur={input.onBlur}
          accessibilityLabel={accessibilityLabel},
          testID={testID}
        />

        <View>
          {showError && (
            <Text>{errorText}</Text>
          )}
        </View>
      </View>
    );
  }
}

那么是什么原因呢?我真的不知道是什么导致 Appium 在不进行上述调整的情况下无法获取输入焦点。

我相信这是 Appium 最近的一个错误 - https://github.com/appium/java-client/issues/1386

您不应该为 ios 指定 accessibilityLabel 单独的道具 ios 和 android 尝试下一个解决方法:

export default function testID(id) {
    return Platform.OS === 'android'
        ? {
            accessible        : true,
            accessibilityLabel: id,
        }
        : {
            testID: id,
        };
}

然后

<TextInput
    {...otherProps}
    {...testID('some-testID')}
/>