1--- 2title: Running E2E tests on EAS Build 3sidebar_title: Running E2E tests 4description: Learn how to set up and run E2E tests on EAS Build with popular libraries such as Detox. 5--- 6 7import { Collapsible } from '~/ui/components/Collapsible'; 8import { Terminal, DiffBlock } from '~/ui/components/Snippet'; 9import ImageSpotlight from '~/components/plugins/ImageSpotlight'; 10 11> **Warning** EAS Build support for E2E testing is in a _very early_ state. The intention of this guide is to explain how you can run E2E tests on the service today, 12> without all of the affordances that we plan to build in the future. This guide will evolve over time as support for testing workflows in EAS Build improves. 13 14With 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](https://wix.github.io/Detox)) to do that. 15 16This guide explains how to run E2E tests with Detox in a bare workflow project. You can use [`@config-plugins/detox`](https://github.com/expo/config-plugins/tree/main/packages/detox) for a managed project, but you may need to adjust some of the instructions in this guide in order to do so. 17 18## Running iOS tests 19 20### 1. Initialize a new Bare Workflow project 21 22Let's start by initializing a new Expo project, installing and configuring `@config-plugins/detox`, and running `npx expo prebuild` to generate the native projects. 23 24Start with the following commands: 25 26<Terminal 27 cmd={[ 28 '# Initialize a new project', 29 '$ npx create-expo-app eas-tests-example', 30 '# cd into the project directory', 31 '$ cd eas-tests-example', 32 '# Install @config-plugins/detox', 33 '$ npm install --save-dev @config-plugins/detox', 34 ]} 35/> 36 37Now, 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. 38 39```json app.json 40{ 41 "expo": { 42 // ... 43 "plugins": ["@config-plugins/detox"] 44 } 45} 46``` 47 48Run prebuild to generate the native projects: 49 50<Terminal cmd={['$ npx expo prebuild']} /> 51 52### 2. Make home screen interactive 53 54The first step to writing E2E tests is to have something to test - we have an empty app, so let's make our app interactive. We can add a button and display some new text when it's pressed. 55Later, we're going to write a test that's going to tap the button and check whether the text has been displayed. 56 57<div style={{ display: 'flex', justifyContent: 'center' }}> 58 <img src="/static/images/eas-build/tests/01-click-me.png" style={{ maxWidth: '45%' }} /> 59 <img src="/static/images/eas-build/tests/02-hi.png" style={{ maxWidth: '45%' }} /> 60</div> 61 62<Collapsible summary=" See the source code"> 63 64```js App.js 65import { StatusBar } from 'expo-status-bar'; 66import { useState } from 'react'; 67import { Pressable, StyleSheet, Text, View } from 'react-native'; 68 69export default function App() { 70 const [clicked, setClicked] = useState(false); 71 72 return ( 73 <View style={styles.container}> 74 {!clicked && ( 75 <Pressable testID="click-me-button" style={styles.button} onPress={() => setClicked(true)}> 76 <Text style={styles.text}>Click me</Text> 77 </Pressable> 78 )} 79 {clicked && <Text style={styles.hi}>Hi!</Text>} 80 <StatusBar style="auto" /> 81 </View> 82 ); 83} 84 85const styles = StyleSheet.create({ 86 container: { 87 flex: 1, 88 backgroundColor: '#fff', 89 alignItems: 'center', 90 justifyContent: 'center', 91 }, 92 hi: { 93 fontSize: 30, 94 color: '#4630EB', 95 }, 96 button: { 97 alignItems: 'center', 98 justifyContent: 'center', 99 paddingVertical: 12, 100 paddingHorizontal: 32, 101 borderRadius: 4, 102 elevation: 3, 103 backgroundColor: '#4630EB', 104 }, 105 text: { 106 fontSize: 16, 107 lineHeight: 21, 108 fontWeight: 'bold', 109 letterSpacing: 0.25, 110 color: 'white', 111 }, 112}); 113``` 114 115</Collapsible> 116 117### 3. Set up Detox 118 119#### Install dependencies 120 121Let'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. 122 123<Terminal 124 cmd={[ 125 '# Install jest & detox', 126 '$ npm install --save-dev jest detox', 127 '# Create Detox configuration files', 128 '$ npx detox init -r jest', 129 ]} 130/> 131 132> See the official Detox docs at https://wix.github.io/Detox/docs/introduction/getting-started/ and https://wix.github.io/Detox/docs/guide/jest to learn about any potential updates to this process. 133 134#### Configure Detox 135 136Detox requires you to specify both the build command and 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`). 137 138Edit **.detoxrc.json** and replace the configuration with: 139 140```json .detoxrc.json 141{ 142 "testRunner": "jest", 143 "runnerConfig": "e2e/config.json", 144 "skipLegacyWorkersInjection": true, 145 "apps": { 146 "ios.release": { 147 "type": "ios.app", 148 /* @info This is project-specific, replace eastestsexample with correct value */ 149 "build": "xcodebuild -workspace ios/eastestsexample.xcworkspace -scheme eastestsexample -configuration Release -sdk iphonesimulator -arch x86_64 -derivedDataPath ios/build", 150 "binaryPath": "ios/build/Build/Products/Release-iphonesimulator/eastestsexample.app" 151 /* @end */ 152 }, 153 "android.release": { 154 "type": "android.apk", 155 /* @info This is project-specific, replace eastestsexample with correct value */ 156 "build": "cd android && ./gradlew :app:assembleRelease :app:assembleAndroidTest -DtestBuildType=release && cd ..", 157 "binaryPath": "android/app/build/outputs/apk/release/app-release.apk" 158 /* @end */ 159 } 160 }, 161 "devices": { 162 "simulator": { 163 "type": "ios.simulator", 164 "device": { 165 "type": "iPhone 14" 166 } 167 }, 168 "emulator": { 169 "type": "android.emulator", 170 "device": { 171 "avdName": "pixel_4" 172 } 173 } 174 }, 175 "configurations": { 176 "ios.release": { 177 "device": "simulator", 178 "app": "ios.release" 179 }, 180 "android.release": { 181 "device": "emulator", 182 "app": "android.release" 183 } 184 } 185} 186``` 187 188### 4. Write E2E tests 189 190Next, we'll add our first E2E tests. Delete the auto-generated **e2e/firstTest.e2e.js** and create our own **e2e/homeScreen.e2e.js** with the following contents: 191 192```js e2e/homeScreen.e2e.js 193describe('Home screen', () => { 194 beforeAll(async () => { 195 await device.launchApp(); 196 }); 197 198 beforeEach(async () => { 199 await device.reloadReactNative(); 200 }); 201 202 it('"Click me" button should be visible', async () => { 203 await expect(element(by.id('click-me-button'))).toBeVisible(); 204 }); 205 206 it('shows "Hi!" after tapping "Click me"', async () => { 207 await element(by.id('click-me-button')).tap(); 208 await expect(element(by.text('Hi!'))).toBeVisible(); 209 }); 210}); 211``` 212 213There are two tests in the suite: 214 215- One that checks whether the "Click me" button is visible on the home screen. 216- Another that verifies that tapping the button triggers displaying "Hi!". 217 218Both tests assume the button has the `testID` set to `click-me-button`. See [the source code](#2-make-home-screen-interactive) for details. 219 220### 5. Configure EAS Build 221 222Now that we have configured Detox and written our first E2E test, let's configure EAS Build and run the tests in the cloud. 223 224#### Create eas.json 225 226The following command creates [eas.json](/build/eas-json.mdx) in the project's root directory: 227 228<Terminal cmd={['$ eas build:configure']} /> 229 230#### Configure EAS Build 231 232There are a few more steps to configure EAS Build for running E2E tests as part of the build: 233 234- Android tests: 235 - Tests are run in the Android Emulator. You will define a build profile that builds your app for the emulator (produces an `apk` file). 236 - Install the emulator and all its system dependencies. 237- iOS test: 238 - Tests are run in the iOS Simulator. You will define a build profile that builds your app for the simulator. 239 - Install the [`applesimutils`](https://github.com/wix/AppleSimulatorUtils) command line util. 240- Configure EAS Build to run Detox tests after successfully building the app. 241 242Edit **eas.json** and add the `test` build profile: 243 244```json eas.json 245{ 246 "build": { 247 "test": { 248 "android": { 249 "gradleCommand": ":app:assembleRelease :app:assembleAndroidTest -DtestBuildType=release", 250 "withoutCredentials": true 251 }, 252 "ios": { 253 "simulator": true 254 } 255 } 256 } 257} 258``` 259 260Create **eas-hooks/eas-build-pre-install.sh** that installs the necessary tools and dependencies for the given platform: 261 262```sh eas-hooks/eas-build-pre-install.sh 263#!/usr/bin/env bash 264 265set -eox pipefail 266 267if [[ "$EAS_BUILD_RUNNER" == "eas-build" && "$EAS_BUILD_PROFILE" == "test"* ]]; then 268 if [[ "$EAS_BUILD_PLATFORM" == "android" ]]; then 269 sudo apt-get --quiet update --yes 270 271 # Install emulator & video bridge dependencies 272 # Source: https://github.com/react-native-community/docker-android/blob/master/Dockerfile 273 sudo apt-get --quiet install --yes \ 274 libc6 \ 275 libdbus-1-3 \ 276 libfontconfig1 \ 277 libgcc1 \ 278 libpulse0 \ 279 libtinfo5 \ 280 libx11-6 \ 281 libxcb1 \ 282 libxdamage1 \ 283 libnss3 \ 284 libxcomposite1 \ 285 libxcursor1 \ 286 libxi6 \ 287 libxext6 \ 288 libxfixes3 \ 289 zlib1g \ 290 libgl1 \ 291 pulseaudio \ 292 socat 293 294 sdkmanager --install "system-images;android-32;google_apis;x86_64" 295 avdmanager --verbose create avd --force --name "pixel_4" --device "pixel_4" --package "system-images;android-32;google_apis;x86_64" 296 else 297 brew tap wix/brew 298 brew install applesimutils 299 fi 300fi 301 302``` 303 304Next, create **eas-hooks/eas-build-on-success.sh** with the following contents. The script runs different commands for Android and iOS. For iOS, the only command is `detox test`. For Android, it's a bit more complicated. You'll have to start the emulator prior to running the tests as `detox` sometimes seems to be having problems with starting the emulator on its own and it can get stuck on running the first test from your test suite. After the `detox test` run, there is a command that kills the previously started emulator. 305 306```sh eas-hooks/eas-build-on-success.sh 307#!/usr/bin/env bash 308 309set -eox pipefail 310 311ANDROID_EMULATOR=pixel_4 312 313if [[ "$EAS_BUILD_PLATFORM" == "android" ]]; then 314 # Start emulator 315 $ANDROID_SDK_ROOT/emulator/emulator @$ANDROID_EMULATOR -no-audio -no-boot-anim -no-window -use-system-libs 2>&1 >/dev/null & 316 317 # Wait for emulator 318 max_retry=10 319 counter=0 320 until adb shell getprop sys.boot_completed; do 321 sleep 10 322 [[ counter -eq $max_retry ]] && echo "Failed to start the emulator!" && exit 1 323 counter=$((counter + 1)) 324 done 325 326 if [[ "$EAS_BUILD_PROFILE" == "test" ]]; then 327 detox test --configuration android.release --headless 328 fi 329 if [[ "$EAS_BUILD_PROFILE" == "test_debug" ]]; then 330 detox test --configuration android.debug --headless 331 fi 332 333 # Kill emulator 334 adb emu kill 335else 336 if [[ "$EAS_BUILD_PROFILE" == "test" ]]; then 337 detox test --configuration ios.release --headless 338 fi 339 if [[ "$EAS_BUILD_PROFILE" == "test_debug" ]]; then 340 detox test --configuration ios.debug --headless 341 fi 342fi 343``` 344 345Edit **package.json** to use [EAS Build hooks](/build-reference/npm-hooks.mdx) to run the above scripts on EAS Build: 346 347```json package.json 348{ 349 "scripts": { 350 "eas-build-pre-install": "./eas-hooks/eas-build-pre-install.sh", 351 "eas-build-on-success": "./eas-hooks/eas-build-on-success.sh" 352 } 353} 354``` 355 356> 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`. 357 358### 5.1. Patch **build.gradle** 359 360> This step will be redundant in the future. 361 362The Android build command that you use to produce the test build is `./gradlew :app:assembleRelease :app:assembleAndroidTest -DtestBuildType=release`. Notice that it consists of two Gradle tasks. Unfortunately, when building the `*AndroidTest` task, some versions of the `expo-modules-core` module change what native libraries are included in the app binary. Those settings don't work with settings for `assembleRelease`. 363 364To fix the problem, add the `pickFirsts` list under `android.packagingOptions` in your **android/app/build.gradle**. The `pickFirsts` property overrides the setting for your project. 365 366<DiffBlock source="/static/diffs/e2e-tests-pickfirsts.diff" /> 367 368### 6. Run tests on EAS Build 369 370Running the tests on EAS Build is like running a regular build: 371 372<Terminal cmd={['$ eas build -p all -e test']} /> 373 374If you have set up everything correctly you should see the successful test result in the build logs: 375 376<ImageSpotlight src="/static/images/eas-build/tests/03-logs.png" style={{ maxWidth: '90%' }} /> 377 378### 7. Upload screenshots of failed test cases 379 380> This step is optional but highly recommended. 381 382When 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 the [`buildArtifactPaths`](/build-reference/eas-json.mdx#buildartifactpaths) field in **eas.json**. 383 384#### Take screenshots for failed tests 385 386[Detox supports taking in-test screenshots of the device](https://wix.github.io/Detox/docs/api/screenshots). It exposes the `device.takeScreenshot()` function that can be called from any test case. 387 388Neither `jest` nor `detox` offers a simple way to detect when a particular test case has failed and take a screenshot for only failed test cases. You will have to implement your own mechanism for that. 389 390Edit **e2e/environment.js** and add the `handleTestEvent` method to the `CustomDetoxEnvironment` class. The function handles test events and sets a global `testFailed` variable for test case failure. See the snippet below: 391 392```ts e2e/environment.js 393class CustomDetoxEnvironment extends DetoxCircusEnvironment { 394 // ... 395 396 async handleTestEvent(event, state) { 397 const { name } = event; 398 399 if (['test_start', 'test_fn_start'].includes(name)) { 400 this.global.testFailed = false; 401 } 402 403 if (name === 'test_fn_failure') { 404 this.global.testFailed = true; 405 } 406 407 await super.handleTestEvent(event, state); 408 } 409} 410``` 411 412After modifying the environment class, define an `afterEach` hook that calls `device.takeScreenshot()` for failed tests. Create the **e2e/setup.js** file with the following snippet: 413 414```ts e2e/setup.js 415afterEach(async () => { 416 if (testFailed) { 417 await device.takeScreenshot('screenshot'); 418 } 419}); 420``` 421 422The last step is to configure `jest` to load `e2e/setup.js` before running tests. This way, you don't need to include the `afterEach` hook in every test suite: 423 424```json e2e/config.json 425{ 426 /// ... 427 "setupFilesAfterEnv": ["./setup.js"] 428} 429``` 430 431After making those changes, screenshots for failed tests will be saved in the `artifacts` directory. 432 433#### Configure EAS Build for screenshots upload 434 435Edit **eas.json** and add `buildArtifactPaths` to the `test` build profile: 436 437```json eas.json 438{ 439 "build": { 440 "test": { 441 "android": { 442 "gradleCommand": ":app:assembleRelease :app:assembleAndroidTest -DtestBuildType=release", 443 "withoutCredentials": true 444 }, 445 "ios": { 446 "simulator": true 447 }, 448 /* @info */ 449 "buildArtifactPaths": ["artifacts/**/*.png"] 450 /* @end */ 451 } 452 } 453} 454``` 455 456In 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. 457 458If you run E2E tests locally, remember to add `artifacts` to `.gitignore`: 459 460```stylus .gitignore 461artifacts/ 462``` 463 464#### Break a test and run a build 465 466To test the new configuration, let's break a test and see that EAS Build uploads the screenshots. 467 468Edit **e2e/homeScreen.e2e.js** and make the following change: 469 470<DiffBlock source="/static/diffs/e2e-tests-homescreen.diff" /> 471 472Run an iOS build with the following command and wait for it to finish: 473 474<Terminal cmd={['$ eas build -p ios -e test']} /> 475 476After going to the build details page you should see that the build failed. Use the **"Download artifacts"** button to download and examine the screenshot: 477 478<ImageSpotlight src="/static/images/eas-build/tests/04-artifacts.png" style={{ maxWidth: '90%' }} /> 479 480## Repository 481 482The full example from this guide is available at https://github.com/expo/eas-tests-example. 483 484## Alternative Approaches 485 486### Using development builds to speed up test run time 487 488The above guide explains how to run E2E tests against a release build of your project, which requires executing a full 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. 489 490Instead, we can use [development builds](/development/introduction/) to load from a local development server or from [published updates](/eas-update/introduction/) 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](/development/development-workflows/#deep-linking-urls). 491 492Development 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). 493 494An example of such a Detox test is shown below. Full example code is available on the [eas-tests-example](https://github.com/expo/eas-tests-example) repository. 495 496<Collapsible summary="e2e/homeScreen.e2e.js"> 497 498```js 499/* @info New line */ 500const { openApp } = require('./utils/openApp'); 501/* @end */ 502 503describe('Home screen', () => { 504 beforeEach(async () => { 505 /* @info New line */ await openApp(); /* @end */ 506 }); 507 508 it('"Click me" button should be visible', async () => { 509 await expect(element(by.id('click-me-button'))).toBeVisible(); 510 }); 511 512 it('shows "Hi!" after tapping "Click me"', async () => { 513 await element(by.id('click-me-button')).tap(); 514 await expect(element(by.text('Hi!'))).toBeVisible(); 515 }); 516}); 517``` 518 519</Collapsible> 520 521<Collapsible summary="e2e/utils/openApp.js (new file)"> 522 523```js 524const appConfig = require('../../../app.json'); 525 526module.exports.openApp = async function openApp() { 527 const [platform, target] = process.env.DETOX_CONFIGURATION.split('.'); 528 if (target === 'debug') { 529 return await openAppForDebugBuild(platform); 530 } else { 531 return await device.launchApp({ 532 newInstance: true, 533 }); 534 } 535}; 536 537async function openAppForDebugBuild(platform) { 538 const deepLinkUrl = process.env.EXPO_USE_UPDATES 539 ? // Testing latest published EAS update for the test_debug channel 540 getDeepLinkUrl(getLatestUpdateUrl()) 541 : // Local testing with packager 542 getDeepLinkUrl(getDevLauncherPackagerUrl(platform)); 543 544 if (platform === 'ios') { 545 // For iOS, the app must be launched, then the deep link URL invoked 546 await device.launchApp({ 547 newInstance: true, 548 }); 549 sleep(3000); 550 await device.openURL({ 551 url: deepLinkUrl, 552 }); 553 } else { 554 // For Android, the app must be launched directly with the deep link URL 555 await device.launchApp({ 556 newInstance: true, 557 url: deepLinkUrl, 558 }); 559 } 560 561 await sleep(3000); 562} 563 564const getDeepLinkUrl = url => 565 /* @info This is project-specific, replace eastestsexample with correct value */ 566 `eastestsexample://expo-development-client/?url=${encodeURIComponent(url)}`; 567/* @end */ 568 569const getDevLauncherPackagerUrl = platform => 570 `http://localhost:8081/index.bundle?platform=${platform}&dev=true&minify=false&disableOnboarding=1`; 571 572const getLatestUpdateUrl = () => 573 `https://u.expo.dev/${getAppId()}?channel-name=test_debug&disableOnboarding=1`; 574 575const getAppId = () => appConfig?.expo?.extra?.eas?.projectId ?? ''; 576 577const sleep = t => new Promise(res => setTimeout(res, t)); 578``` 579 580</Collapsible> 581 582<Collapsible summary=".detoxrc.json"> 583 584```json 585{ 586 "testRunner": "jest", 587 "runnerConfig": "e2e/config.json", 588 "skipLegacyWorkersInjection": true, 589 "apps": { 590 /* @info New section */ "ios.debug": { 591 "type": "ios.app", 592 "build": "xcodebuild -workspace ios/eastestsexample.xcworkspace -scheme eastestsexample -configuration Debug -sdk iphonesimulator -arch x86_64 -derivedDataPath ios/build", 593 "binaryPath": "ios/build/Build/Products/Debug-iphonesimulator/eastestsexample.app" 594 } /* @end */, 595 "ios.release": { 596 "type": "ios.app", 597 "build": "xcodebuild -workspace ios/eastestsexample.xcworkspace -scheme eastestsexample -configuration Release -sdk iphonesimulator -arch x86_64 -derivedDataPath ios/build", 598 "binaryPath": "ios/build/Build/Products/Release-iphonesimulator/eastestsexample.app" 599 }, 600 /* @info New section */ "android.debug": { 601 "type": "android.apk", 602 "build": "cd android && ./gradlew :app:assembleDebug :app:assembleAndroidTest -DtestBuildType=debug && cd ..", 603 "binaryPath": "android/app/build/outputs/apk/debug/app-debug.apk" 604 } /* @end */, 605 "android.release": { 606 "type": "android.apk", 607 "build": "cd android && ./gradlew :app:assembleRelease :app:assembleAndroidTest -DtestBuildType=release && cd ..", 608 "binaryPath": "android/app/build/outputs/apk/release/app-release.apk" 609 } 610 }, 611 "devices": { 612 "simulator": { 613 "type": "ios.simulator", 614 "device": { 615 "type": "iPhone 14" 616 } 617 }, 618 "emulator": { 619 "type": "android.emulator", 620 "device": { 621 "avdName": "pixel_4" 622 } 623 } 624 }, 625 "configurations": { 626 /* @info New section */ "ios.debug": { 627 "device": "simulator", 628 "app": "ios.debug" 629 } /* @end */, 630 "ios.release": { 631 "device": "simulator", 632 "app": "ios.release" 633 }, 634 /* @info New section */ "android.debug": { 635 "device": "emulator", 636 "app": "android.debug" 637 } /* @end */, 638 "android.release": { 639 "device": "emulator", 640 "app": "android.release" 641 } 642 } 643} 644``` 645 646</Collapsible> 647 648<Collapsible summary="eas-hooks/eas-build-on-success.sh"> 649 650```sh 651#!/usr/bin/env bash 652 653set -eox pipefail 654 655ANDROID_EMULATOR=pixel_4 656 657if [[ "$EAS_BUILD_PLATFORM" == "android" ]]; then 658 # Start emulator 659 $ANDROID_SDK_ROOT/emulator/emulator @$ANDROID_EMULATOR -no-audio -no-boot-anim -no-window -use-system-libs 2>&1 >/dev/null & 660 661 # Wait for emulator 662 max_retry=10 663 counter=0 664 until adb shell getprop sys.boot_completed; do 665 sleep 10 666 [[ counter -eq $max_retry ]] && echo "Failed to start the emulator!" && exit 1 667 counter=$((counter + 1)) 668 done 669 670 if [[ "$EAS_BUILD_PROFILE" == "test" ]]; then 671 detox test --configuration android.release --headless 672 fi 673 # @info New section # 674 if [[ "$EAS_BUILD_PROFILE" == "test_debug" ]]; then 675 detox test --configuration android.debug --headless 676 fi 677 # @end # 678 # Kill emulator 679 adb emu kill 680else 681 if [[ "$EAS_BUILD_PROFILE" == "test" ]]; then 682 detox test --configuration ios.release --headless 683 fi 684 # @info New section # 685 if [[ "$EAS_BUILD_PROFILE" == "test_debug" ]]; then 686 detox test --configuration ios.debug --headless 687 fi 688 # @end # 689fi 690``` 691 692</Collapsible> 693 694<Collapsible summary="eas.json"> 695 696```json 697{ 698 "build": { 699 "test": { 700 "android": { 701 "gradleCommand": ":app:assembleRelease :app:assembleAndroidTest -DtestBuildType=release", 702 "withoutCredentials": true 703 }, 704 "ios": { 705 "simulator": true 706 } 707 }, 708 /* @info New section */ "test_debug": { 709 "android": { 710 "gradleCommand": ":app:assembleDebug :app:assembleAndroidTest -DtestBuildType=debug", 711 "withoutCredentials": true 712 }, 713 "ios": { 714 "buildConfiguration": "Debug", 715 "simulator": true 716 }, 717 "env": { 718 "EXPO_USE_UPDATES": "1" 719 }, 720 "channel": "test_debug" 721 } /* @end */ 722 } 723} 724``` 725 726</Collapsible> 727