实际上是否可以通过在Expo上运行的React Native应用程序使Detox/Jest测试通过? [英] Is it actually possible to make Detox/Jest tests pass with a React Native app running with Expo?

查看:241
本文介绍了实际上是否可以通过在Expo上运行的React Native应用程序使Detox/Jest测试通过?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试为我的带有Expo的React Native应用程序创建一个自动化的UI测试套件.我到处都在寻找好的教程,但是当我进入实际的测试写作部分时,由于环境问题,例如import Icon from...上的意外标识符/令牌"或其他愚蠢的问题而我无法找到任何教程,因此我的测试甚至无法运行如何解决它们.我实际上花了一个星期的时间来尝试解决这些问题.

I'm attempting to create an automated UI test suite for my React Native app with Expo. I have looked everywhere for good tutorials but when I get to the actual test writing portion, my tests never even run because of environment issues such as "Unexpected Identifier/Token" on import Icon from... or other stupid issues that I cannot find any tutorials on how to fix them. I literally have spent a week trying to resolve these issues.

我是React Native的新手,还是Jest/Detox/Expo的新手

I am new to React Native and new to Jest/Detox/Expo

这是我的package.json

Here's my package.json

{
  "main": "node_modules/expo/AppEntry.js",
  "scripts": {
    "start": "expo start",
    "android": "expo start --android",
    "ios": "expo start --ios",
    "test": "node_modules/.bin/jest test/**/*.spec.js",
    "eject": "expo eject"
  },
  "jest": {
    "verbose": true,
    "preset": "jest-expo"
  },
  "dependencies": {
    "apsl-react-native-button": "^3.1.1",
    "react": "16.5.0",
    "react-native": "https://github.com/expo/react-native/archive/sdk-32.0.0.tar.gz",
    "react-native-camera": "git+https://git@github.com/react-native-community/react-native-camera.git",
    "react-native-camera-roll-picker": "^1.2.3",
    "react-native-elements": "^1.0.0",
    "react-native-fontawesome": "^6.0.1",
    "react-native-is-iphonex": "^1.0.1",
    "react-native-vector-icons": "^6.2.0",
    "react-navigation": "^3.1.5"
  },
  "devDependencies": {
    "babel-preset-expo": "^5.0.0",
    "bunyan-debug-stream": "^2.0.0",
    "detox": "^10.0.9",
    "detox-expo-helpers": "^0.6.0",
    "expo-detox-hook": "^1.0.10",
    "jest-expo": "^32.0.0",
    "react-native-testing-library": "^1.5.0",
    "react-test-renderer": "^16.8.2",
    "babel-jest": "^24.1.0",
    "enzyme": "^3.9.0",
    "@babel/core": "^7.3.3",
    "@expo/vector-icons": "^9.0.0",
    "expo": "^32.0.0",
    "jest": "^24.1.0"
  },
  "private": true,
  "detox": {
    "test-runner": "jest",
    "configurations": {
      "ios.sim": {
        "binaryPath": "bin/Exponent.app",
        "type": "ios.simulator",
        "name": "iPhone X"
      }
    }
  }
}

这是我遇到的错误

ip-10-101-32-118:KitchenProject bob.dole$ detox test --loglevel trace
configuration="ios.sim" loglevel="trace" artifactsLocation="artifacts/ios.sim.2019-02-21 21-54-14Z" node_modules/.bin/jest "e2e" --config=e2e/config.json --maxWorkers=1 '--testNamePattern=^((?!:android:).)*$' 
● Deprecation Warning:

  Option "setupTestFrameworkScriptFile" was replaced by configuration "setupFilesAfterEnv", which supports multiple paths.

  Please update your configuration.

  Configuration Documentation:
  https://jestjs.io/docs/configuration.html

 FAIL  e2e/RoomLayout.spec.js
  ● Test suite failed to run

    /Users/bob.dole/KitchenDetail/KitchenProject/node_modules/@expo/vector-icons/FontAwesome.js:1
    ({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,global,jest){import glyphMap from './vendor/react-native-vector-icons/glyphmaps/FontAwesome.json';
                                                                                                    ^^^^^^^^

    SyntaxError: Unexpected identifier

    > 1 | import FontAwesomeI from 'react-native-vector-icons/FontAwesome'
        | ^
      2 | import React from 'react'
      3 | 
      4 | export const FontAwesome = props => (

      at ScriptTransformer._transformAndBuildScript (../node_modules/jest/node_modules/jest-runtime/build/ScriptTransformer.js:440:17)
      at Object.<anonymous> (../Components/icons.js:1:1)

 FAIL  e2e/tests/components/RoomLayoutDetox.spec.js
  ● Test suite failed to run

    /Users/bob.dole/KitchenDetail/KitchenProject/node_modules/@expo/vector-icons/FontAwesome.js:1
    ({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,global,jest){import glyphMap from './vendor/react-native-vector-icons/glyphmaps/FontAwesome.json';
                                                                                                    ^^^^^^^^

    SyntaxError: Unexpected identifier

    > 1 | import FontAwesomeI from 'react-native-vector-icons/FontAwesome'
        | ^
      2 | import React from 'react'
      3 | 
      4 | export const FontAwesome = props => (

      at ScriptTransformer._transformAndBuildScript (../node_modules/jest/node_modules/jest-runtime/build/ScriptTransformer.js:440:17)
      at Object.<anonymous> (../Components/icons.js:1:1)

Test Suites: 2 failed, 2 total
Tests:       0 total
Snapshots:   0 total
Time:        0.827s
Ran all test suites matching /e2e/i with tests matching "^((?!:android:).)*$".
child_process.js:677
    throw err;
    ^

Error: Command failed: node_modules/.bin/jest "e2e" --config=e2e/config.json --maxWorkers=1 '--testNamePattern=^((?!:android:).)*$' 
    at checkExecSyncError (child_process.js:637:11)
    at Object.execSync (child_process.js:674:13)
    at runJest (/Users/bob.dole/KitchenDetail/KitchenProject/node_modules/detox/local-cli/detox-test.js:166:6)
    at run (/Users/bob.dole/KitchenDetail/KitchenProject/node_modules/detox/local-cli/detox-test.js:86:7)
    at Object.<anonymous> (/Users/bob.dole/KitchenDetail/KitchenProject/node_modules/detox/local-cli/detox-test.js:229:1)
    at Module._compile (internal/modules/cjs/loader.js:738:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:749:10)
    at Module.load (internal/modules/cjs/loader.js:630:32)
    at tryModuleLoad (internal/modules/cjs/loader.js:570:12)
    at Function.Module._load (internal/modules/cjs/loader.js:562:3)

这是我的组件文件 RoomLayout.js

Here's my component file RoomLayout.js

import React, { Component } from 'react';
import { StyleSheet, View, Text, Button } from 'react-native';
import { LayoutButtons } from './LayoutButtons';
import { CameraLauncher } from './CameraLauncher';
import { CommentsLauncher } from './CommentsLauncher';


export class RoomLayout extends Component {
  render() {
    return (
      <View>
        <Text testID='roomLayoutText' style={styles.room}>
          Room Layout{"\n"}
        </Text>
        <Text testID='infoText' style={styles.infoText}>
          Take photos from opposite corners of the room{"\n"}
        </Text>
          <LayoutButtons />
      </View>
    );
  }
}

const styles = StyleSheet.create({
  view: {
      marginTop: 80, 
      textAlign: 'center',
      alignItems: 'center',
      justifyContent: 'center'
  },
  infoText: {
      marginTop: -10,
      fontWeight: 'normal',
      textAlign: 'center',
      fontSize: 12,
      justifyContent: 'center',
      alignSelf: 'center',
      color: 'grey'
  },
  room: {
      marginTop: 15,
      fontWeight: 'bold',
      textAlign: 'center',
      lineHeight: 14,
      fontSize: 15
  }
});

这是我的RoomLayout.spec.js文件

Here's my RoomLayout.spec.js file

import React from 'react';
// import { RoomLayout } from '../Components/RoomLayout';
import { render } from 'react-native-testing-library';

describe('RoomLayout', () => {
   // *** EDIT - I have removed this code ***
   // beforeEach(async () => {
   //   const tree = render(<RoomLayout />);
   //
   // });

  test('should have header and info text', async () => {
      await element(by.text('Room Layout'));
      await element(by.id('infoText'));
      await element(by.id('infoText').and(by.text(' Take photos from opposite corners of the room')));
      await expect(element(by.id('layoutButtonsReference'))).toBeVisible();
    });
  });

推荐答案

使用Expo应用程序设置排毒.您可能最适合从一个还没有做任何事情的干净应用程序开始.您需要确保已遵循基本设置(步骤1)使排毒在您的机器上工作

Setting up Detox with an Expo app. You're probably best placed to start with a clean app that you haven't done anything with yet. You’ll want to make sure you have followed the basic setup (step 1) for getting detox to work on your machine

npm i -D detox detox-expo-helpers expo-detox-hook jest

更新package.json

将以下内容添加到您的package.json文件中,这将配置排毒.您可以选择所需的iPhone类型.

Update the package.json

Add the following to your package.json file, this configures detox. You can choose the type of iPhone that you want.

"detox": {
  "configurations": {
    "ios.sim": {
      "binaryPath": "bin/Exponent.app",
      "type": "ios.simulator",
      "name": "iPhone X"
    }
  },
  "test-runner": "jest"
 }

在脚本部分中添加以下内容:

In the scripts section add the following:

"scripts": {
  "e2e": "detox test --configuration ios.sim"
}

这将允许我们运行排毒测试,但使用npm run e2e

This will allow us to run the detox test but using npm run e2e

运行以下命令设置您的第一个测试

Run the following to set up your first test

detox init -r jest

这将在您的项目中添加一个名为e2e的文件夹.您会在其中找到三个文件

This will add a folder called e2e in your project. You will find three files inside it

  • config.json
  • firstTest.spec.js
  • init.js
  • config.json
  • firstTest.spec.js
  • init.js

firstTest.spec.js是一个样本测试.您将需要对其进行以下更改.

firstTest.spec.js is a sample test. You will need to make the following changes to it.

const { reloadApp } = require('detox-expo-helpers');

您还需要更改以下行

await device.reloadReactNative();

await reloadApp();

将Expo Client添加到您的项目中

  • Expo.io/tools 下载Expo Client iOS应用.
  • 解压缩iOS IPA并将其重命名为Exponent.app.它会带有一个文件图标,但仍将是一个文件夹.
  • 创建bin文件夹并将Exponent.app放入其中,使其与上面设置的binaryPath相匹配.
  • Add the Expo Client to your project

    • Download the Expo Client iOS App from Expo.io/tools.
    • Unzip the iOS IPA and rename the folder to Exponent.app. It'll have a file icon but will still be a folder.
    • Create bin folder and put Exponent.app inside so it matches the binaryPath set above.
    • 或者,您也可以使用以下脚本,在项目根目录中创建一个文件并将其命名为setup.sh,复制内容然后运行它(您可能需要授予其运行权限,您可以通过首先运行chmod +x setup.sh,然后可以使用./setup.sh)运行它.

      Or alternatively you could use the following script, create a file and name it setup.sh in your project root directory, copy the contents and then run it (you will probably need to give it permission to run which you can do by running chmod +x setup.sh first, then you can run it using ./setup.sh).

      #!/bin/bash -e
      
      # query expo.io to find most recent ipaUrl
      IPA_URL=`curl https://expo.io/--/api/v2/versions |  python -c 'import sys, json; print json.load(sys.stdin)["iosUrl"]'`
      
      # download tar.gz
      TMP_PATH=/tmp/exponent.tar.gz
      wget -O $TMP_PATH $IPA_URL
      
      # recursively make app dir
      APP_PATH=bin/Exponent.app
      mkdir -p $APP_PATH
      
      # unzip tar.gz into APP_PATH
      tar -C $APP_PATH -xzf $TMP_PATH
      

      此脚本与上述步骤相同.

      This script does the same as the above steps.

      使用expo start -c

      启动计划用于测试的模拟器(因此,如果您选择了iPhone X,请启动iPhone X等).

      Launch the simulator that you plan to use for your test (so if you picked an iPhone X, launch the iPhone X etc).

      然后,如果添加了脚本,则可以在终端中运行npm run e2e,也可以运行detox test.

      Then in your terminal you can run npm run e2e if you added the script or you can run detox test.

      您将发现测试将失败.没关系,这是可以预期的.

      What you will find is that your test will fail. This is ok and to be expected.

      现在,如果要通过测试,则需要实现firstTest.spec.js中存在的所有测试用例,也可以将其删除并编写自己的测试用例.

      Now if you want to make your test pass you need to implement all of the test cases that exist in the firstTest.spec.js or you can scrap those and write your own.

      • Detox's own Expo Guide
      • Detox setup
      • Expo sample app with Detox

      如果您希望通过测试,则可以更新以下文件,并且应该获得3个通过测试.

      If you want to make your tests pass you can update the following files and you should get 3 passing tests.

      firstTest.spec.js

      const { reloadApp } = require('detox-expo-helpers');
      
      describe('Example', () => {
        beforeEach(async () => {
          await reloadApp();
        });
      
        it('should have welcome screen', async () => {
          await expect(element(by.id('welcome'))).toBeVisible();
        });
      
        it('should show hello screen after tap', async () => {
          await element(by.id('hello_button')).tap();
          await expect(element(by.label('Hello!!!'))).toBeVisible();
        });
      
        it('should show world screen after tap', async () => {
          await element(by.id('world_button')).tap();
          await expect(element(by.label('World!!!'))).toBeVisible();
        });
      });
      

      App.js

      import React, { Component } from 'react';
      import { StyleSheet, Text, TouchableOpacity, View } from 'react-native';
      
      export default class App extends Component {
        state = {
          greeting: undefined
        };
      
        render () {
          if (this.state.greeting) return this.renderAfterButton();
          return (
            <View
              testID="welcome"
              style={{
                flex: 1,
                paddingTop: 20,
                justifyContent: 'center',
                alignItems: 'center'
              }}>
              <Text style={{ fontSize: 25, marginBottom: 30 }}>Welcome</Text>
              <TouchableOpacity
                testID="hello_button"
                onPress={this.onButtonPress.bind(this, 'Hello')}>
                <Text style={{ color: 'blue', marginBottom: 20 }}>Say Hello</Text>
              </TouchableOpacity>
              <TouchableOpacity
                testID="world_button"
                onPress={this.onButtonPress.bind(this, 'World')}>
                <Text style={{ color: 'blue', marginBottom: 20 }}>Say World</Text>
              </TouchableOpacity>
            </View>
          );
        }
        renderAfterButton () {
          return (
            <View
              style={{
                flex: 1,
                paddingTop: 20,
                justifyContent: 'center',
                alignItems: 'center'
              }}>
              <Text style={{ fontSize: 25 }}>{this.state.greeting}!!!</Text>
            </View>
          );
        }
      
        onButtonPress (greeting) {
          this.setState({
            greeting: greeting
          });
        }
      }
      
      const styles = StyleSheet.create({
        container: {
          flex: 1,
          backgroundColor: '#fff',
          alignItems: 'center',
          justifyContent: 'center'
        }
      });
      

      这篇关于实际上是否可以通过在Expo上运行的React Native应用程序使Detox/Jest测试通过?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆