排毒无法找到已赋予testId

时间:2020-04-10 13:16:51

标签: javascript react-native jestjs enzyme detox

我正在尝试在我的React Native应用上实施e2e测试。

Detox构建在Android和iOS上均成功,并且我设法按预期运行了模拟程序,但是Detox似乎无法在我要测试的页面上找到任何组件。我要查找的所有组件都具有一个testId,并且当我尝试在Android和iOS上进行测试时,ID都存在于视图层次结构中。

这是我在android上收到的错误:

androidx.test.espresso.base.DefaultFailureHandler$AssertionFailedWithCauseError: 'at least 75 percent of the view's area is displayed to the user.' doesn't match the selected view.
    Expected: at least 75 percent of the view's area is displayed to the user.
         Got: null

        at dalvik.system.VMStack.getThreadStackTrace(Native Method)
        at java.lang.Thread.getStackTrace(Thread.java:1538)
        at androidx.test.espresso.base.DefaultFailureHandler.getUserFriendlyError(DefaultFailureHandler.java:96)
        at androidx.test.espresso.base.DefaultFailureHandler.handle(DefaultFailureHandler.java:59)
        at androidx.test.espresso.ViewInteraction.waitForAndHandleInteractionResults(ViewInteraction.java:324)
        at androidx.test.espresso.ViewInteraction.check(ViewInteraction.java:306)
        at com.wix.detox.espresso.DetoxAssertion.assertMatcher(DetoxAssertion.java:32)
        at java.lang.reflect.Method.invoke(Native Method)
        at org.apache.commons.lang3.reflect.MethodUtils.invokeStaticMethod(MethodUtils.java:443)
        at org.apache.commons.lang3.reflect.MethodUtils.invokeStaticMethod(MethodUtils.java:405)
        at com.wix.invoke.types.ClassTarget.execute(ClassTarget.java:23)
        at com.wix.invoke.types.Target.invoke(Target.java:59)
        at com.wix.invoke.MethodInvocation.invoke(MethodInvocation.java:35)
        at com.wix.invoke.MethodInvocation.invoke(MethodInvocation.java:26)
        at com.wix.invoke.MethodInvocation.invoke(MethodInvocation.java:20)
        at com.wix.detox.InvokeActionHandler.handle(DetoxActionHandlers.kt:52)
        at com.wix.detox.DetoxManager$4.run(DetoxManager.java:121)
        at android.os.Handler.handleCallback(Handler.java:790)
        at android.os.Handler.dispatchMessage(Handler.java:99)
        at android.os.Looper.loop(Looper.java:164)
        at com.wix.detox.Detox$1.run(Detox.java:135)
        at java.lang.Thread.run(Thread.java:764)
    Caused by: junit.framework.AssertionFailedError: 'at least 75 percent of the view's area is displayed to the user.' doesn't match the selected view.
    Expected: at least 75 percent of the view's area is displayed to the user.
         Got: null

        at androidx.test.espresso.matcher.ViewMatchers.assertThat(ViewMatchers.java:540)
        at com.wix.detox.espresso.assertion.ViewAssertions$MatchesViewAssertion.check(ViewAssertions.java:52)
        at androidx.test.espresso.ViewInteraction$SingleExecutionViewAssertion.check(ViewInteraction.java:425)
        at androidx.test.espresso.ViewInteraction$2.call(ViewInteraction.java:288)
        at androidx.test.espresso.ViewInteraction$2.call(ViewInteraction.java:272)
        at java.util.concurrent.FutureTask.run(FutureTask.java:266)
        at android.os.Handler.handleCallback(Handler.java:790)
        at android.os.Handler.dispatchMessage(Handler.java:99)
        at android.os.Looper.loop(Looper.java:164)
        at android.app.ActivityThread.main(ActivityThread.java:6494)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)

    Check device logs for full details!

       9 | 
      10 |   it('should have physiotherapy button', async () => {
    > 11 |     await expect(element(by.id('Physiotherapy button'))).toBeVisible();
         |                                                             ^
      12 |   });
      13 | 
      14 |   it('should have reminders button', async () => {

      at Client.execute (../node_modules/detox/src/client/Client.js:92:28)
      at InvocationManager.execute (../node_modules/detox/src/invoke.js:11:39)
      at MatcherAssertionInteraction.execute (../node_modules/detox/src/android/expect.js:128:35)
      at ExpectElement.toBeVisible (../node_modules/detox/src/android/expect.js:275:112)
      at _callee3$ (dashboard.spec.js:11:61)
      at tryCatch (../node_modules/regenerator-runtime/runtime.js:45:40)
      at Generator.invoke [as _invoke] (../node_modules/regenerator-runtime/runtime.js:271:22)
      at Generator.prototype.<computed> [as next] (../node_modules/regenerator-runtime/runtime.js:97:21)
      at tryCatch (../node_modules/regenerator-runtime/runtime.js:45:40)
      at invoke (../node_modules/regenerator-runtime/runtime.js:135:20)
      at ../node_modules/regenerator-runtime/runtime.js:170:11
      at callInvokeWithMethodAndArg (../node_modules/regenerator-runtime/runtime.js:169:16)
      at AsyncIterator.enqueue (../node_modules/regenerator-runtime/runtime.js:192:13)
      at AsyncIterator.prototype.<computed> [as next] (../node_modules/regenerator-runtime/runtime.js:97:21)
      at Object.exports.async (../node_modules/regenerator-runtime/runtime.js:216:14)

这是测试:

describe('Dashboard', () => {
  beforeEach(async () => {
    await device.reloadReactNative();
  });

  it('should have physiotherapy button', async () => {
    await expect(element(by.id('Physiotherapy button'))).toBeVisible();
  });

这是我要测试的组件:

/* Dashboard with custom buttons to navigate between pages */
import React, {Component} from 'react';
import {View, StyleSheet} from 'react-native';
import SplashScreen from 'react-native-splash-screen';
import DashboardButton from '../layout/DashboardButton';
import {connect} from 'react-redux';
import * as actions from '../../actions/index';
import {NavigationEvents} from 'react-navigation';

export class Dashboard extends Component {
  constructor(props) {
    super(props);

    // present log in page if user is not logged in
    if (props.loggedIn !== true) {
      this.login();
    }

    // show dashboard
    SplashScreen.hide();
  }

  login() {
    this.props.addDevice('testId', 'testToken');
    this.props.loginUser('testId', 'testToken');
    this.props.loadInitialReminders();
    this.props.loadInitialDiaryEntries();
  }

  render() {
    return (
      <View testId={'Dashboard'} accessible={true} style={styles.mainContainer}>
        <NavigationEvents
          onDidFocus={() => {
            if (this.props.loggedIn !== true) {
              this.login();
            }
          }}
        />

        <DashboardButton
          testId={'Physiotherapy button'}
          accessibilityLabel={'Physiotherapy button'}
          accessibilityHint={
            'Navigates to the Physiotherapy exercise categories screen'
          }
          disabled={!this.props.loggedIn}
          title="PHYSIOTHERAPY"
          customClick={() =>
            this.props.navigation.navigate('PhysiotherapyExerciseCategories')
          }
        />
        <DashboardButton
          testId={'Reminders button'}
          accessibilityLabel={'Reminders button'}
          accessibilityHint={'Navigates to the Reminders screen'}
          disabled={!this.props.loggedIn}
          title="REMINDERS"
          customClick={() => this.props.navigation.navigate('Reminders')}
        />
        <DashboardButton
          testId={'Diary button'}
          accessibilityLabel={'Diary button'}
          accessibilityHint={'Navigates to the Diary screen'}
          disabled={!this.props.loggedIn}
          title="DIARY"
          customClick={() => this.props.navigation.navigate('Diary')}
        />
      </View>
    );
  }
}

const mapStateToProps = state => {
  return {
    loggedIn: state.authorisationReducer.loggedIn,
    reminders: state.remindersReducer.reminders,
    notificationsSet: state.remindersReducer.notificationsSet,
  };
};

export default connect(
  mapStateToProps,
  actions,
)(Dashboard);

const styles = StyleSheet.create({
  mainContainer: {
    flex: 1,
    backgroundColor: 'white',
    flexDirection: 'column',
  },
});

如您所见,我正在寻找一个自定义组件,但该组件只是包裹在一个具有proptestId = {props.testId}的TouchableOpacity周围。我还尝试过为Dashboard组件中的主视图提供ID并进行搜索,但仍然没有运气。

我尝试按标签和ID搜索。

我还读到这可能是一个本机反应,因为它们嵌套了组件,因此排毒将无法找到该组件。是这样吗这是我的package.json文件,向您显示我正在使用的版本:

{
  "name": "XXX",
  "version": "1.0.0",
  "private": true,
  "description": "XXX",
  "author": "XXX",
  "scripts": {
    "android": "react-native run-android",
    "ios": "react-native run-ios",
    "start": "react-native start",
    "test": "jest",
    "lint": "eslint ."
  },
  "dependencies": {
    "@bam.tech/react-native-make": "^1.0.3",
    "@fortawesome/fontawesome-svg-core": "^1.2.25",
    "@fortawesome/free-solid-svg-icons": "^5.11.2",
    "@fortawesome/react-native-fontawesome": "^0.1.0",
    "@react-native-community/async-storage": "^1.8.1",
    "@react-native-community/cli": "^4.0.0",
    "@react-native-community/cli-platform-android": "^4.6.3",
    "@react-native-community/datetimepicker": "^2.2.1",
    "@react-native-community/netinfo": "^5.5.1",
    "axios": "^0.18.1",
    "bcryptjs": "^2.4.3",
    "body-parser": "^1.19.0",
    "classnames": "^2.2.6",
    "concurrently": "^4.1.2",
    "enzyme-adapter-react-16": "^1.15.2",
    "express": "^4.17.1",
    "is-empty": "^1.2.0",
    "jetifier": "^1.6.5",
    "jsonwebtoken": "^8.5.1",
    "jwt-decode": "^2.2.0",
    "lodash.uniqueid": "^4.0.1",
    "moment": "^2.24.0",
    "mongoose": "^5.7.12",
    "node-schedule": "^1.3.2",
    "passport": "^0.4.0",
    "passport-jwt": "^4.0.0",
    "react": "16.9.0",
    "react-dom": "^16.12.0",
    "react-native": "0.61.5",
    "react-native-auth0": "^2.3.0",
    "react-native-base64": "0.0.2",
    "react-native-elements": "^1.2.7",
    "react-native-firebase": "^5.6.0",
    "react-native-gesture-handler": "^1.5.0",
    "react-native-modal": "^11.5.4",
    "react-native-modal-selector": "^1.1.5",
    "react-native-paper": "^3.2.1",
    "react-native-render-html": "^4.2.0",
    "react-native-screens": "^2.0.0-beta.2",
    "react-native-splash-screen": "^3.0.6",
    "react-native-svg": "^11.0.1",
    "react-native-uuid-generator": "^6.1.1",
    "react-native-vector-icons": "^6.6.0",
    "react-native-webview": "^8.1.2",
    "react-navigation": "^4.0.10",
    "react-navigation-stack": "^1.10.3",
    "react-redux": "^5.1.2",
    "react-router-dom": "^4.3.1",
    "react-scripts": "^3.3.0",
    "redux": "^4.0.4",
    "redux-thunk": "^2.3.0",
    "serialize-javascript": "^2.1.2",
    "typescript": "^3.7.2",
    "validator": "^10.11.0",
    "xss": "^1.0.6"
  },
  "devDependencies": {
    "@babel/core": "^7.6.2",
    "@babel/preset-env": "^7.1.0",
    "@babel/preset-flow": "^7.8.3",
    "@babel/preset-react": "^7.0.0",
    "@babel/runtime": "^7.6.2",
    "@bam.tech/react-native-make": "^1.0.3",
    "@react-native-community/eslint-config": "^0.0.5",
    "babel-jest": "^24.9.0",
    "detox": "^16.1.1",
    "dotenv-webpack": "^1.7.0",
    "enzyme": "^3.11.0",
    "eslint": "^6.5.1",
    "jest": "^25.3.0",
    "metro-react-native-babel-preset": "^0.56.0",
    "nodemon": "^2.0.0",
    "react-test-renderer": "16.9.0",
    "redux-mock-store": "^1.5.4"
  },
  "jest": {
    "preset": "react-native",
    "setupFiles": [
      "./node_modules/react-native-gesture-handler/jestSetup.js",
      "./node_modules/react-test-renderer/cjs/react-test-renderer.development.js"
    ],
    "setupFilesAfterEnv": [
      "./__mocks__/async-storage.js",
      "./__mocks__/auth0.js",
      "./__mocks__/firebase.js",
      "./__mocks__/net-info.js",
      "./__mocks__/react-native-navigation.js",
      "./__mocks__/react-native-splash-screen.js"
    ],
    "transformIgnorePatterns": [
      "./node_modules/?!(react-navigation|react-native-gesture-handler)"
    ]
  },
  "detox": {
    "configurations": {
      "ios.sim.debug": {
        "binaryPath": "ios/build/Build/Products/Debug-iphonesimulator/Tulip.app",
        "build": "RN_SRC_EXT=e2e.js xcodebuild -workspace ios/clean.xcworkspace -scheme Tulip -configuration Debug -sdk iphonesimulator -derivedDataPath ios/build",
        "type": "ios.simulator",
        "device": {
          "type": "iPhone 11 Pro"
        }
      },
      "android.emu.debug": {
        "binaryPath": "android/app/build/outputs/apk/debug/app-debug.apk",
        "build": "RN_SRC_EXT=e2e.js cd android && ./gradlew assembleDebug assembleAndroidTest -DtestBuildType=debug && cd ..",
        "type": "android.emulator",
        "device": {
          "avdName": "Pixel_2_XL_API_27"
        }
      },
      "android.emu.release": {
        "binaryPath": "android/app/build/outputs/apk/release/app-release.apk",
        "build": "RN_SRC_EXT=e2e.js cd android && ./gradlew assembleRelease assembleAndroidTest -DtestBuildType=release && cd ..",
        "type": "android.emulator",
        "device": {
          "avdName": "Pixel_2_XL_API_27"
        }
      }
    },
    "test-runner": "jest"
  }
}

如果您知道解决此问题的方法或另一种e2e测试方法,请告诉我。预先感谢您的帮助。

1 个答案:

答案 0 :(得分:0)

我很傻。错字。

测试ID应该写为:testID =“ Dashboard”