在 EAS Build 上运行 E2E 测试

了解如何使用 Detox 等流行库在 EAS Build 上设置和运行 E2E 测试。


已弃用:这是我们的 EAS Build E2E 测试指南的旧存档版本。在此处查看指南的最新版本

通过 EAS Build,你可以构建一个工作流程来为你的应用运行 E2E 测试。在本指南中,你将学习如何使用最流行的库之一 (排毒) 来做到这一点。

¥With EAS Build, you can build a workflow for running E2E tests for your application. In this guide, you will learn how to use one of the most popular libraries (Detox) to do that.

本指南解释了如何在裸工作流程项目中使用 Detox 运行 E2E 测试。你可以将 @config-plugins/detox 用于托管项目,但你可能需要调整本指南中的一些说明才能执行此操作。

¥This guide explains how to run E2E tests with Detox in a bare workflow project. You can use @config-plugins/detox for a managed project, but you may need to adjust some of the instructions in this guide to do so.

运行 iOS 测试

¥Running iOS tests

1

初始化一个新的裸工作流程项目

¥Initialize a new bare workflow project

让我们首先初始化一个新的 Expo 项目,安装和配置 @config-plugins/detox,然后运行 npx expo prebuild 来生成原生项目。

¥Let's start by initializing a new Expo project, installing and configuring @config-plugins/detox, and running npx expo prebuild to generate the native projects.

从以下命令开始:

¥Start with the following commands:

Terminal
# Initialize a new project
npx create-expo-app eas-tests-example
# cd into the project directory
cd eas-tests-example
# Install @config-plugins/detox
npm install --save-dev @config-plugins/detox

现在,打开 app.json 并将 @config-plugins/detox 插件添加到 plugins 列表中(这必须在预构建之前完成)。这将自动配置 Android 原生代码以支持 Detox。

¥Now, open app.json and add the @config-plugins/detox plugin to your plugins list (this must be done before prebuilding). This will automatically configure the Android native code to support Detox.

app.json
{
  "expo": {
    // ...
    "plugins": ["@config-plugins/detox"]
  }
}

运行 prebuild 以生成原生项目:

¥Run prebuild to generate the native projects:

Terminal
npx expo prebuild

2

使主屏幕具有交互性

¥Make home screen interactive

编写 E2E 测试的第一步是有一些东西要测试 - 有一个空的应用,所以让我们让我们的应用具有交互性。你可以添加一个按钮并在按下时显示一些新文本。稍后,你将编写一个测试来模拟点击按钮并验证文本是否按预期显示。

¥The first step to writing E2E tests is to have something to test — have an empty app, so let's make our app interactive. You can add a button and display some new text when it's pressed. Later, you will write a test that simulates tapping the button and verifies if the text is displayed as expected.

See the source code
App.js
import { StatusBar } from 'expo-status-bar';
import { useState } from 'react';
import { Pressable, StyleSheet, Text, View } from 'react-native';

export default function App() {
  const [clicked, setClicked] = useState(false);

  return (
    <View style={styles.container}>
      {!clicked && (
        <Pressable testID="click-me-button" style={styles.button} onPress={() => setClicked(true)}>
          <Text style={styles.text}>Click me</Text>
        </Pressable>
      )}
      {clicked && <Text style={styles.hi}>Hi!</Text>}
      <StatusBar style="auto" />
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    alignItems: 'center',
    justifyContent: 'center',
  },
  hi: {
    fontSize: 30,
    color: '#4630EB',
  },
  button: {
    alignItems: 'center',
    justifyContent: 'center',
    paddingVertical: 12,
    paddingHorizontal: 32,
    borderRadius: 4,
    elevation: 3,
    backgroundColor: '#4630EB',
  },
  text: {
    fontSize: 16,
    lineHeight: 21,
    fontWeight: 'bold',
    letterSpacing: 0.25,
    color: 'white',
  },
});

3

设置排毒

¥Set up Detox

安装依赖

¥Install dependencies

让我们在项目中添加两个开发依赖 - jestdetoxjest(或 mocha)是必需的,因为 detox 没有自己的测试运行程序。

¥Let's add two development dependencies to the project - jest and detox. jest (or mocha) is required because detox does not have its own test-runner.

Terminal
# Install jest and detox
npm install --save-dev jest detox
# Create Detox configuration files
npx detox init -r jest

请参阅官方 Detox 文档中的 入门项目设置 指南,了解此过程的任何潜在更新。

¥See the Getting started and Project setup guides in official Detox documentation to learn about any potential updates to this process.

配置排毒

¥Configure Detox

Detox 要求你指定构建命令及其生成的二进制文件的路径。从技术上讲,在 EAS Build 上运行测试时,构建命令不是必需的,但允许你在本地运行测试(例如,使用 npx detox build --configuration ios.release)。

¥Detox requires you to specify both the build command and the path to the binary produced by it. Technically, the build command is not necessary when running tests on EAS Build, but allows you to run tests locally (for example, using npx detox build --configuration ios.release).

使用以下配置更新 .detoxrc.js:

¥Update .detoxrc.js with the following configuration with:

.detoxrc.js
/** @type {Detox.DetoxConfig} */
module.exports = {
  logger: {
    level: process.env.CI ? 'debug' : undefined,
  },
  testRunner: {
    $0: 'jest',
    args: {
      config: 'e2e/jest.config.js',
      _: ['e2e'],
    },
  },
  artifacts: {
    plugins: {
      log: process.env.CI ? 'failing' : undefined,
      screenshot: 'failing',
    },
  },
  apps: {
    'ios.release': {
      type: 'ios.app',
      build:
        'xcodebuild -workspace ios/eastestsexample.xcworkspace -scheme eastestsexample -configuration Release -sdk iphonesimulator -arch x86_64 -derivedDataPath ios/build',
      binaryPath: 'ios/build/Build/Products/Release-iphonesimulator/eastestsexample.app',
    },
    'android.release': {
      type: 'android.apk',
      build:
        'cd android && ./gradlew :app:assembleRelease :app:assembleAndroidTest -DtestBuildType=release && cd ..',
      binaryPath: 'android/app/build/outputs/apk/release/app-release.apk',
    },
  },
  devices: {
    simulator: {
      type: 'ios.simulator',
      device: {
        type: 'iPhone 14',
      },
    },
    emulator: {
      type: 'android.emulator',
      device: {
        avdName: 'pixel_4',
      },
    },
  },
  configurations: {
    'ios.release': {
      device: 'simulator',
      app: 'ios.release',
    },
    'android.release': {
      device: 'emulator',
      app: 'android.release',
    },
  },
};

4

编写 E2E 测试

¥Write E2E tests

接下来,添加你的第一个 E2E 测试。删除自动生成的 e2e/starter.test.js 并使用以下代码片段创建我们自己的 e2e/homeScreen.test.js:

¥Next, add your first E2E tests. Delete the auto-generated e2e/starter.test.js and create our own e2e/homeScreen.test.js with the following snippet:

e2e/homeScreen.test.js
describe('Home screen', () => {
  beforeAll(async () => {
    await device.launchApp();
  });

  beforeEach(async () => {
    await device.reloadReactNative();
  });

  it('"Click me" button should be visible', async () => {
    await expect(element(by.id('click-me-button'))).toBeVisible();
  });

  it('shows "Hi!" after tapping "Click me"', async () => {
    await element(by.id('click-me-button')).tap();
    await expect(element(by.text('Hi!'))).toBeVisible();
  });
});

套件中有两个测试:

¥There are two tests in the suite:

  • 检查 "点我" 按钮在主屏幕上是否可见。

    ¥One that checks whether the "Click me" button is visible on the home screen.

  • 另一个验证点击按钮会触发显示 "你好!"。

    ¥Another that verifies that tapping the button triggers displaying "Hi!".

两个测试均假设按钮的 testID 设置为 click-me-button。详细信息请参见 源代码

¥Both tests assume the button has the testID set to click-me-button. See the source code for details.

5

配置 EAS 构建

¥Configure EAS Build

配置 Detox 并编写初始 E2E 测试后,下一步是配置 EAS Build 并在云中执行测试。

¥After configuring Detox and writing the initial E2E test, the next step is to configure EAS Build and execute the tests in the cloud.

创建 eas.json

¥Create eas.json

以下命令在项目根目录中创建 eas.json

¥The following command creates eas.json in the project's root directory:

Terminal
eas build:configure

配置 EAS 构建

¥Configure EAS Build

作为构建的一部分,还需要执行几个步骤来配置 EAS Build 以运行 E2E 测试:

¥There are a few more steps to configure EAS Build for running E2E tests as part of the build:

  • 安卓测试:

    ¥Android test:

    • 测试在 Android 模拟器中运行。你将定义一个构建配置文件,用于为模拟器构建应用(生成 .apk 文件)。

      ¥Tests are run in the Android Emulator. You will define a build profile that builds your app for the emulator (produces a .apk file).

    • 安装模拟器及其所有系统依赖。

      ¥Install the emulator and all its system dependencies.

  • iOS 测试:

    ¥iOS test:

  • 配置 EAS Build 以在成功构建应用后运行 Detox 测试。

    ¥Configure EAS Build to run Detox tests after successfully building the app.

编辑 eas.json 并添加 test 构建配置文件:

¥Edit eas.json and add the test build profile:

eas.json
{
  "build": {
    "test": {
      "android": {
        "gradleCommand": ":app:assembleRelease :app:assembleAndroidTest -DtestBuildType=release",
        "withoutCredentials": true
      },
      "ios": {
        "simulator": true
      }
    }
  }
}

创建 eas-hooks/eas-build-pre-install.sh 来安装给定平台所需的工具和依赖:

¥Create eas-hooks/eas-build-pre-install.sh to install the necessary tools and dependencies for the given platform:

eas-hooks/eas-build-pre-install.sh
#!/usr/bin/env bash

set -eox pipefail

if [[ "$EAS_BUILD_RUNNER" == "eas-build" && "$EAS_BUILD_PROFILE" == "test"* ]]; then
  if [[ "$EAS_BUILD_PLATFORM" == "android" ]]; then
    sudo apt-get --quiet update --yes

    # Install emulator & video bridge dependencies
    # Source: https://github.com/react-native-community/docker-android/blob/master/Dockerfile
    sudo apt-get --quiet install --yes \
      libc6 \
      libdbus-1-3 \
      libfontconfig1 \
      libgcc1 \
      libpulse0 \
      libtinfo5 \
      libx11-6 \
      libxcb1 \
      libxdamage1 \
      libnss3 \
      libxcomposite1 \
      libxcursor1 \
      libxi6 \
      libxext6 \
      libxfixes3 \
      zlib1g \
      libgl1 \
      pulseaudio \
      socat

    # Emulator must be API 31 -- API 32 and 33 fail due to https://github.com/wix/Detox/issues/3762
    sdkmanager --install "system-images;android-31;google_apis;x86_64"
    avdmanager --verbose create avd --force --name "pixel_4" --device "pixel_4" --package "system-images;android-31;google_apis;x86_64"
  else
    brew tap wix/brew
    brew install applesimutils
  fi
fi

接下来,创建 eas-hooks/eas-build-on-success.sh 并添加代码片段,如下所示。该脚本针对 Android 和 iOS 运行不同的命令。

¥Next, create eas-hooks/eas-build-on-success.sh and add the code snippet as shown below. The script runs different commands for Android and iOS.

  • 对于 Android,你必须在运行测试之前手动启动模拟器,因为 detox 偶尔会遇到独立启动模拟器的问题,这可能会导致套件的第一次测试期间挂起。完成 detox test 后,有一个命令可以杀死之前启动的模拟器。

    ¥For Android, you have to manually start the emulator before running the tests as detox occasionally encounters issues initiating the emulator independently, which can cause a hang during the first test of your suite. After completing the detox test, there is a command that kills the previously started emulator.

  • 对于 iOS,唯一的命令是 detox test

    ¥For iOS, the only command is detox test.

eas-hooks/eas-build-on-success.sh
#!/usr/bin/env bash

function cleanup()
{
  echo 'Cleaning up...'
  if [[ "$EAS_BUILD_PLATFORM" == "android" ]]; then
    # Kill emulator
    adb emu kill &
  fi
}

if [[ "$EAS_BUILD_PROFILE" != "test" ]]; then
  exit
fi

# Fail if anything errors
set -eox pipefail
# If this script exits, trap it first and clean up the emulator
trap cleanup EXIT

ANDROID_EMULATOR=pixel_4

if [[ "$EAS_BUILD_PLATFORM" == "android" ]]; then
  # Start emulator
  $ANDROID_SDK_ROOT/emulator/emulator @$ANDROID_EMULATOR -no-audio -no-boot-anim -no-window -use-system-libs 2>&1 >/dev/null &

  # Wait for emulator
  max_retry=10
  counter=0
  until adb shell getprop sys.boot_completed; do
    sleep 10
    [[ counter -eq $max_retry ]] && echo "Failed to start the emulator!" && exit 1
    counter=$((counter + 1))
  done

  # Execute Android tests
  if [[ "$EAS_BUILD_PROFILE" == "test" ]]; then
    detox test --configuration android.release
  fi
else
  # Execute iOS tests
  if [[  "$EAS_BUILD_PROFILE" == "test" ]]; then
    detox test --configuration ios.release
  fi
fi

更新 package.json 以使用 EAS 构建钩子 在 EAS Build 上运行上述脚本:

¥Update package.json to use EAS Build hooks to run the above scripts on EAS Build:

package.json
{
  "scripts": {
    "eas-build-pre-install": "./eas-hooks/eas-build-pre-install.sh",
    "eas-build-on-success": "./eas-hooks/eas-build-on-success.sh"
  }
}

不要忘记为 eas-build-pre-install.sh 和 eas-build-on-success.sh 添加可执行权限。运行 chmod +x eas-hooks/*.sh

¥Don't forget to add executable permissions to eas-build-pre-install.sh and eas-build-on-success.sh. Run chmod +x eas-hooks/*.sh.

6

在 EAS Build 上运行测试

¥Run tests on EAS Build

在 EAS Build 上运行测试就像运行常规构建一样:

¥Running the tests on EAS Build is like running a regular build:

Terminal
eas build -p all -e test

如果你已正确设置所有内容,你应该在构建日志中看到成功的测试结果:

¥If you have set up everything correctly you should see the successful test result in the build logs:

7

上传失败测试用例的截图

¥Upload screenshots of failed test cases

此步骤是可选的,但强烈推荐。

¥This step is optional but highly recommended.

当 E2E 测试用例失败时,查看应用状态的屏幕截图会很有帮助。EAS Build 可以轻松地使用 eas.json 中的 buildArtifactPaths 上传任意构建工件。

¥When an E2E test case fails, it can be helpful to see the screenshot of the application state. EAS Build makes it easy to upload any arbitrary build artifacts using buildArtifactPaths in eas.json.

对失败的测试进行屏幕截图

¥Take screenshots for failed tests

Detox 支持在测试中截取设备的屏幕截图。上面的 .detoxrc.js 示例 包括 Detox 的配置,用于拍摄失败测试的屏幕截图。

¥Detox supports taking in-test screenshots of the device. The .detoxrc.js sample above includes a configuration for Detox to take screenshots of failed tests.

配置 EAS Build 以进行屏幕截图上传

¥Configure EAS Build for screenshots upload

编辑 eas.json 并将 buildArtifactPaths 添加到 test 构建配置文件中:

¥Edit eas.json and add buildArtifactPaths to the test build profile:

eas.json
{
  "build": {
    "test": {
      "android": {
        "gradleCommand": ":app:assembleRelease :app:assembleAndroidTest -DtestBuildType=release",
        "withoutCredentials": true
      },
      "ios": {
        "simulator": true
      },
      "buildArtifactPaths": ["artifacts/**/*.png"]
    }
  }
}

applicationArchivePath 相比,即使构建失败,也会上传 buildArtifactPaths 中定义的构建工件。工件目录中的所有 .png 文件都将打包到 tarball 中并上传到 AWS S3。你可以稍后从构建详细信息页面下载它们。

¥In contrast to applicationArchivePath, the build artifacts defined at buildArtifactPaths will be uploaded even if the build fails. All .png files from the artifacts directory will be packed into a tarball and uploaded to AWS S3. You can download them later from the build details page.

如果你在本地运行 E2E 测试,请记住将工件添加到 .gitignore:

¥If you run E2E tests locally, remember to add artifacts to .gitignore:

.gitignore
artifacts/

中断测试并运行构建

¥Break a test and run a build

为了测试新配置,让我们进行测试并查看 EAS Build 上传屏幕截图。

¥To test the new configuration, let's break a test and see that EAS Build uploads the screenshots.

编辑 e2e/homeScreen.test.js 并进行以下更改:

¥Edit e2e/homeScreen.test.js and make the following change:

使用以下命令运行 iOS 构建并等待其完成:

¥Run an iOS build with the following command and wait for it to finish:

Terminal
eas build -p ios -e test

进入构建详细信息页面后,你应该会看到构建失败。使用 "下载工件" 按钮下载并检查屏幕截图:

¥After going to the build details page you should see that the build failed. Use the "Download artifacts" button to download and examine the screenshot:

存储库

¥Repository

示例存储库

GitHub 上提供了本指南的完整示例。

替代方法

¥Alternative approaches

使用开发构建来加快测试运行时间

¥Using development builds to speed up test run time

上述指南解释了如何针对项目的发布版本运行 E2E 测试,这需要在每次测试运行之前执行完全原生构建。如果仅项目 JavaScript 或资源发生了更改,则每次运行 E2E 测试时重新构建原生应用可能并不理想。但是,这对于发布版本是必需的,因为应用 JavaScript 包已嵌入到二进制文件中。

¥The above guide explains how to run E2E tests against a release build of your project, which requires executing a fully native build before each test run. Re-building the native app each time you run E2E tests may not be desirable if only the project JavaScript or assets have changed. However, this is necessary for release builds because the app JavaScript bundle is embedded into the binary.

相反,使用 开发构建 从本地开发服务器或从 已发布的更新 加载,以节省时间和 CI 资源。这可以通过让 E2E 测试运行程序使用指向特定更新包 URL 的 URL 调用应用来完成,如 开发构建深度链接 URL 指南.1 中所述。

¥Instead, use development builds to load from a local development server or from published updates to save time and CI resources. This can be done by having your E2E test runner invoke the app with a URL that points to a specific update bundle URL, as described in the development builds deep linking URLs guide.

首次启动应用时,开发版本通常会显示入门欢迎屏幕,旨在为开发者提供有关 expo-dev-client UI 的上下文。但是,它可能会干扰你的 E2E 测试(期望与你的应用交互,而不是与入门屏幕交互)。要在测试环境中跳过入门屏幕,可以将查询参数 disableOnboarding=1 附加到项目 URL(EAS 更新 URL 或本地开发服务器 URL)。

¥Development builds typically display an onboarding welcome screen when an app is launched for the first time, which intends to provide context about the expo-dev-client UI for developers. However, it can interfere with your E2E tests (which expect to interact with your app and not an onboarding screen). To skip the onboarding screen in a test environment, the query parameter disableOnboarding=1 can be appended to the project URL (an EAS Update URL or a local development server URL).

此类排毒测试的示例如下所示。完整的示例代码可在 eas-tests-example 存储库中找到。

¥An example of such a Detox test is shown below. Full example code is available on the eas-tests-example repository.

e2e/homeScreen.test.js
e2e/homeScreen.test.js
const { openApp } = require('./utils/openApp');

describe('Home screen', () => {
  beforeEach(async () => {
    await openApp();
  });

  it('"Click me" button should be visible', async () => {
    await expect(element(by.id('click-me-button'))).toBeVisible();
  });

  it('shows "Hi!" after tapping "Click me"', async () => {
    await element(by.id('click-me-button')).tap();
    await expect(element(by.text('Hi!'))).toBeVisible();
  });
});
e2e/utils/openApp.js (new file)
e2e/utils/openApp.js
const appConfig = require('../../app.json');
const { resolveConfig } = require('detox/internals');

const platform = device.getPlatform();

module.exports.openApp = async function openApp() {
  const config = await resolveConfig();
  if (config.configurationName.split('.')[1] === 'debug') {
    return await openAppForDebugBuild(platform);
  } else {
    return await device.launchApp({
      newInstance: true,
    });
  }
};

async function openAppForDebugBuild(platform) {
  const deepLinkUrl = process.env.EXPO_USE_UPDATES
    ? // Testing latest published EAS update for the test_debug channel
      getDeepLinkUrl(getLatestUpdateUrl())
    : // Local testing with packager
      getDeepLinkUrl(getDevLauncherPackagerUrl(platform));

  if (platform === 'ios') {
    await device.launchApp({
      newInstance: true,
    });
    sleep(3000);
    await device.openURL({
      url: deepLinkUrl,
    });
  } else {
    await device.launchApp({
      newInstance: true,
      url: deepLinkUrl,
    });
  }

  await sleep(3000);
}

const getDeepLinkUrl = url =>
  `eastestsexample://expo-development-client/?url=${encodeURIComponent(url)}`;

const getDevLauncherPackagerUrl = platform =>
  `http://localhost:8081/index.bundle?platform=${platform}&dev=true&minify=false&disableOnboarding=1`;

const getLatestUpdateUrl = () =>
  `https://u.expo.dev/${getAppId()}?channel-name=test_debug&disableOnboarding=1`;

const getAppId = () => appConfig?.expo?.extra?.eas?.projectId ?? '';

const sleep = t => new Promise(res => setTimeout(res, t));
.detoxrc.js
.detoxrc.js
/** @type {Detox.DetoxConfig} */
module.exports = {
  logger: {
    level: process.env.CI ? 'debug' : undefined,
  },
  testRunner: {
    $0: 'jest',
    args: {
      config: 'e2e/jest.config.js',
      _: ['e2e'],
    },
  },
  artifacts: {
    plugins: {
      log: process.env.CI ? 'failing' : undefined,
      screenshot: 'failing',
    },
  },
  apps: {
    'ios.debug': {
      type: 'ios.app',
      build:
        'xcodebuild -workspace ios/eastestsexample.xcworkspace -scheme eastestsexample -configuration Debug -sdk iphonesimulator -arch x86_64 -derivedDataPath ios/build',
      binaryPath: 'ios/build/Build/Products/Debug-iphonesimulator/eastestsexample.app',
    },
    'ios.release': {
      type: 'ios.app',
      build:
        'xcodebuild -workspace ios/eastestsexample.xcworkspace -scheme eastestsexample -configuration Release -sdk iphonesimulator -arch x86_64 -derivedDataPath ios/build',
      binaryPath: 'ios/build/Build/Products/Release-iphonesimulator/eastestsexample.app',
    },
    'android.debug': {
      type: 'android.apk',
      build:
        'cd android && ./gradlew :app:assembleDebug :app:assembleAndroidTest -DtestBuildType=debug && cd ..',
      binaryPath: 'android/app/build/outputs/apk/debug/app-debug.apk',
    },
    'android.release': {
      type: 'android.apk',
      build:
        'cd android && ./gradlew :app:assembleRelease :app:assembleAndroidTest -DtestBuildType=release && cd ..',
      binaryPath: 'android/app/build/outputs/apk/release/app-release.apk',
    },
  },
  devices: {
    simulator: {
      type: 'ios.simulator',
      device: {
        type: 'iPhone 14',
      },
    },
    emulator: {
      type: 'android.emulator',
      device: {
        avdName: 'pixel_4',
      },
    },
  },
  configurations: {
    'ios.debug': {
      device: 'simulator',
      app: 'ios.debug',
    },
    'ios.release': {
      device: 'simulator',
      app: 'ios.release',
    },
    'android.debug': {
      device: 'emulator',
      app: 'android.debug',
    },
    'android.release': {
      device: 'emulator',
      app: 'android.release',
    },
  },
};
eas-hooks/eas-build-on-success.sh
eas-hooks/eas-build-on-success.sh
#!/usr/bin/env bash

function cleanup()
{
  echo 'Cleaning up...'
  if [[ "$EAS_BUILD_PLATFORM" == "android" ]]; then
    # Kill emulator
    adb emu kill &
  fi
}

if [[ "$EAS_BUILD_PROFILE" != "test"* ]]; then
  exit
fi

# Fail if anything errors
set -eox pipefail
# If this script exits, trap it first and clean up the emulator
trap cleanup EXIT

ANDROID_EMULATOR=pixel_4

if [[ "$EAS_BUILD_PLATFORM" == "android" ]]; then
  # Start emulator
  $ANDROID_SDK_ROOT/emulator/emulator @$ANDROID_EMULATOR -no-audio -no-boot-anim -no-window -use-system-libs 2>&1 >/dev/null &

  # Wait for emulator
  max_retry=10
  counter=0
  until adb shell getprop sys.boot_completed; do
    sleep 10
    [[ counter -eq $max_retry ]] && echo "Failed to start the emulator!" && exit 1
    counter=$((counter + 1))
  done


  # Execute Android tests
  if [[ "$EAS_BUILD_PROFILE" == "test" ]]; then
    detox test --configuration android.release
  fi
  if [[ "$EAS_BUILD_PROFILE" == "test_debug" ]]; then
    detox test --configuration android.debug
  fi
else
  # Execute iOS tests
  if [[  "$EAS_BUILD_PROFILE" == "test" ]]; then
    detox test --configuration ios.release
  fi
  if [[ "$EAS_BUILD_PROFILE" == "test_debug" ]]; then
    detox test --configuration ios.debug
  fi
fi
eas.json
eas.json
{
  "build": {
    "test": {
      "android": {
        "gradleCommand": ":app:assembleRelease :app:assembleAndroidTest -DtestBuildType=release",
        "withoutCredentials": true
      },
      "ios": {
        "simulator": true
      }
    },
    "test_debug": {
      "android": {
        "gradleCommand": ":app:assembleDebug :app:assembleAndroidTest -DtestBuildType=debug",
        "withoutCredentials": true
      },
      "ios": {
        "buildConfiguration": "Debug",
        "simulator": true
      },
      "env": {
        "EXPO_USE_UPDATES": "1"
      },
      "channel": "test_debug"
    }
  }
}
Expo 中文网 - 粤ICP备13048890号