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

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

问题描述

我正在尝试使用 Expo 为我的 React Native 应用程序创建一个自动化的 UI 测试套件.我到处寻找好的教程,但是当我进入实际的测试编写部分时,我的测试甚至从未运行,因为环境问题,例如 import Icon from... 上的意外标识符/令牌"或其他愚蠢的问题,我找不到任何关于如何修复它们的教程.我真的花了一周的时间试图解决这些问题.

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

这是我的 package.json

<代码>{"main": "node_modules/expo/AppEntry.js",脚本":{"start": "展会开始","android": "expo start --android","ios": "expo start --ios","test": "node_modules/.bin/jest test/**/*.spec.js","eject": "博览会弹出"},开玩笑":{详细":真实,预设":笑话博览会"},依赖关系":{"apsl-react-native-button": "^3.1.1",反应":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",反应原生元素":^ 1.0.0","react-native-fontawesome": "^6.0.1","react-native-is-iphonex": "^1.0.1","react-native-vector-icons": "^6.2.0",反应导航":^3.1.5"},开发依赖":{"babel-preset-expo": "^5.0.0","bunyan-debug-stream": "^2.0.0","排毒": "^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",反应测试渲染器":^ 16.8.2","babel-jest": "^24.1.0","酶": "^3.9.0","@babel/core": "^7.3.3","@expo/vector-icons": "^9.0.0","博览会": "^32.0.0",开玩笑":^24.1.0"},私人":真的,排毒":{"test-runner": "jest",配置":{ios.sim":{"binaryPath": "bin/Exponent.app","type": "ios.simulator",名称":iPhone X"}}}}

这是我遇到的错误

ip-10-101-32-118:KitchenProject bob.dole$ detox test --loglevel traceconfiguration="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:).)*$'● 弃用警告:选项setupTestFrameworkScriptFile"被配置setupFilesAfterEnv"替换,支持多路径.请更新您的配置.配置文档:https://jestjs.io/docs/configuration.html失败 e2e/RoomLayout.spec.js● 测试套件运行失败/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';^^^^^^^^^语法错误:意外的标识符>1 |从'react-native-vector-icons/FontAwesome' 导入 FontAwesomeI|^2 |从反应"导入反应3 |4 |导出 const FontAwesome = 道具 =>(在 ScriptTransformer._transformAndBuildScript (../node_modules/jest/node_modules/jest-runtime/build/ScriptTransformer.js:440:17)在对象<匿名>(../Components/icons.js:1:1)失败 e2e/tests/components/RoomLayoutDetox.spec.js● 测试套件运行失败/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';^^^^^^^^^语法错误:意外的标识符>1 |从'react-native-vector-icons/FontAwesome' 导入 FontAwesomeI|^2 |从反应"导入反应3 |4 |导出 const FontAwesome = 道具 =>(在 ScriptTransformer._transformAndBuildScript (../node_modules/jest/node_modules/jest-runtime/build/ScriptTransformer.js:440:17)在对象<匿名>(../Components/icons.js:1:1)测试套件:2 个失败,总共 2 个测试: 0 总快照:共 0 个时间:0.827s运行所有匹配/e2e/i 的测试套件,测试匹配^((?!:android:).)*$".child_process.js:677抛出错误;^错误:命令失败:node_modules/.bin/jest "e2e" --config=e2e/config.json --maxWorkers=1 '--testNamePattern=^((?!:android:).)*$'在 checkExecSyncError (child_process.js:637:11)在 Object.execSync (child_process.js:674:13)在 runJest (/Users/bob.dole/KitchenDetail/KitchenProject/node_modules/detox/local-cli/detox-test.js:166:6)运行时 (/Users/bob.dole/KitchenDetail/KitchenProject/node_modules/detox/local-cli/detox-test.js:86:7)在对象<匿名>(/Users/bob.dole/KitchenDetail/KitchenProject/node_modules/detox/local-cli/detox-test.js:229:1)在 Module._compile (internal/modules/cjs/loader.js:738:30)在 Object.Module._extensions..js (internal/modules/cjs/loader.js:749:10)在 Module.load (internal/modules/cjs/loader.js:630:32)在 tryModuleLoad (internal/modules/cjs/loader.js:570:12)在 Function.Module._load (internal/modules/cjs/loader.js:562:3)

这是我的组件文件房间布局.js

import React, { Component } from 'react';import { StyleSheet, View, Text, Button } from 'react-native';从 './LayoutButtons' 导入 { LayoutButtons };从'./CameraLauncher'导入{CameraLauncher};从 './CommentsLauncher' 导入 { CommentsLauncher };导出类 RoomLayout 扩展组件 {使成为() {返回 (<查看><Text testID='roomLayoutText' style={styles.room}>房间布局{"
"}</文本><Text testID='infoText' style={styles.infoText}>从房间的对角拍照{"
"}</文本><布局按钮/></查看>);}}const 样式 = StyleSheet.create({看法: {边距顶部:80,文本对齐:'居中',alignItems: '中心',justifyContent: '中心'},信息文本:{边距顶部:-10,fontWeight: '正常',文本对齐:'居中',字体大小:12,justifyContent: '中心',alignSelf: '居中',颜色:'灰色'},房间: {边距顶部:15,fontWeight: '粗体',文本对齐:'居中',行高:14,字体大小:15}});

这是我的 RoomLayout.spec.js 文件

从'react'导入React;//import { RoomLayout } from '../Components/RoomLayout';从'react-native-testing-library'导入{渲染};描述('房间布局',()=> {//*** 编辑 - 我已删除此代码 ***//beforeEach(async () => {//const tree = render(<RoomLayout/>);////});test('应该有标题和信息文本', async () => {等待元素(by.text('房间布局'));等待元素(by.id('infoText'));await element(by.id('infoText').and(by.text('从房间的对角拍照')));await expect(element(by.id('layoutButtonsReference'))).toBeVisible();});});

解决方案

使用 Expo 应用设置 Detox.您可能最适合从尚未使用过的干净应用程序开始.您需要确保已遵循基本设置

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.

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

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"
      }
    }
  }
}

Here are the errors I'm getting

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)

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{"
"}
        </Text>
        <Text testID='infoText' style={styles.infoText}>
          Take photos from opposite corners of the room{"
"}
        </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
  }
});

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();
    });
  });

解决方案

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

#Install the following devDependencies

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

#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"
}

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

#Setup your first test

Run the following to set up your first test

detox init -r jest

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

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

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

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

You also need to change the following line

await device.reloadReactNative();

to

await reloadApp();

#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.

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.

#Run your first test

Start the packager with expo start -c

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

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.

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 scrape those and write your own.

#Links

#Make your tests pass

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天全站免登陆