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 **detox.config.js** and replace the configuration with: 139 140```js detox.config.js 141/** @type {Detox.DetoxConfig} */ 142module.exports = { 143 logger: { 144 level: process.env.CI ? 'debug' : undefined, 145 }, 146 testRunner: { 147 $0: 'jest', 148 args: { 149 config: 'e2e/jest.config.js', 150 _: ['e2e'], 151 }, 152 }, 153 artifacts: { 154 plugins: { 155 log: process.env.CI ? 'failing' : undefined, 156 /* @info In Detox 20, this plugin setting will take screenshots if tests fail */ 157 screenshot: 'failing', 158 /* @end */ 159 }, 160 }, 161 apps: { 162 'ios.release': { 163 type: 'ios.app', 164 /* @info This is project-specific, replace eastestsexample with correct value */ 165 build: 166 'xcodebuild -workspace ios/eastestsexample.xcworkspace -scheme eastestsexample -configuration Release -sdk iphonesimulator -arch x86_64 -derivedDataPath ios/build', 167 binaryPath: 168 'ios/build/Build/Products/Release-iphonesimulator/eastestsexample.app', 169 /* @end */ 170 }, 171 'android.release': { 172 type: 'android.apk', 173 build: 174 'cd android && ./gradlew :app:assembleRelease :app:assembleAndroidTest -DtestBuildType=release && cd ..', 175 binaryPath: 'android/app/build/outputs/apk/release/app-release.apk', 176 }, 177 }, 178 devices: { 179 simulator: { 180 type: 'ios.simulator', 181 device: { 182 type: 'iPhone 14', 183 }, 184 }, 185 emulator: { 186 type: 'android.emulator', 187 device: { 188 avdName: 'pixel_4', 189 }, 190 }, 191 }, 192 configurations: { 193 'ios.release': { 194 device: 'simulator', 195 app: 'ios.release', 196 }, 197 'android.release': { 198 device: 'emulator', 199 app: 'android.release', 200 }, 201 }, 202}; 203``` 204 205### 4. Write E2E tests 206 207Next, 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: 208 209```js e2e/homeScreen.e2e.js 210describe('Home screen', () => { 211 beforeAll(async () => { 212 await device.launchApp(); 213 }); 214 215 beforeEach(async () => { 216 await device.reloadReactNative(); 217 }); 218 219 it('"Click me" button should be visible', async () => { 220 await expect(element(by.id('click-me-button'))).toBeVisible(); 221 }); 222 223 it('shows "Hi!" after tapping "Click me"', async () => { 224 await element(by.id('click-me-button')).tap(); 225 await expect(element(by.text('Hi!'))).toBeVisible(); 226 }); 227}); 228``` 229 230There are two tests in the suite: 231 232- One that checks whether the "Click me" button is visible on the home screen. 233- Another that verifies that tapping the button triggers displaying "Hi!". 234 235Both tests assume the button has the `testID` set to `click-me-button`. See [the source code](#2-make-home-screen-interactive) for details. 236 237### 5. Configure EAS Build 238 239Now that we have configured Detox and written our first E2E test, let's configure EAS Build and run the tests in the cloud. 240 241#### Create eas.json 242 243The following command creates [eas.json](/build/eas-json.mdx) in the project's root directory: 244 245<Terminal cmd={['$ eas build:configure']} /> 246 247#### Configure EAS Build 248 249There are a few more steps to configure EAS Build for running E2E tests as part of the build: 250 251- Android tests: 252 - Tests are run in the Android Emulator. You will define a build profile that builds your app for the emulator (produces an `apk` file). 253 - Install the emulator and all its system dependencies. 254- iOS test: 255 - Tests are run in the iOS Simulator. You will define a build profile that builds your app for the simulator. 256 - Install the [`applesimutils`](https://github.com/wix/AppleSimulatorUtils) command line util. 257- Configure EAS Build to run Detox tests after successfully building the app. 258 259Edit **eas.json** and add the `test` build profile: 260 261```json eas.json 262{ 263 "build": { 264 "test": { 265 "android": { 266 "gradleCommand": ":app:assembleRelease :app:assembleAndroidTest -DtestBuildType=release", 267 "withoutCredentials": true 268 }, 269 "ios": { 270 "simulator": true 271 } 272 } 273 } 274} 275``` 276 277Create **eas-hooks/eas-build-pre-install.sh** that installs the necessary tools and dependencies for the given platform: 278 279```sh eas-hooks/eas-build-pre-install.sh 280#!/usr/bin/env bash 281 282set -eox pipefail 283 284if [[ "$EAS_BUILD_RUNNER" == "eas-build" && "$EAS_BUILD_PROFILE" == "test"* ]]; then 285 if [[ "$EAS_BUILD_PLATFORM" == "android" ]]; then 286 sudo apt-get --quiet update --yes 287 288 # Install emulator & video bridge dependencies 289 # Source: https://github.com/react-native-community/docker-android/blob/master/Dockerfile 290 sudo apt-get --quiet install --yes \ 291 libc6 \ 292 libdbus-1-3 \ 293 libfontconfig1 \ 294 libgcc1 \ 295 libpulse0 \ 296 libtinfo5 \ 297 libx11-6 \ 298 libxcb1 \ 299 libxdamage1 \ 300 libnss3 \ 301 libxcomposite1 \ 302 libxcursor1 \ 303 libxi6 \ 304 libxext6 \ 305 libxfixes3 \ 306 zlib1g \ 307 libgl1 \ 308 pulseaudio \ 309 socat 310 311 # Emulator must be API 31 -- API 32 and 33 fail due to https://github.com/wix/Detox/issues/3762 312 sdkmanager --install "system-images;android-31;google_apis;x86_64" 313 avdmanager --verbose create avd --force --name "pixel_4" --device "pixel_4" --package "system-images;android-31;google_apis;x86_64" 314 else 315 brew tap wix/brew 316 brew install applesimutils 317 fi 318fi 319 320``` 321 322Next, 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. 323 324```sh eas-hooks/eas-build-on-success.sh 325#!/usr/bin/env bash 326 327function cleanup() 328{ 329 echo 'Cleaning up...' 330 if [[ "$EAS_BUILD_PLATFORM" == "android" ]]; then 331 # Kill emulator 332 adb emu kill & 333 fi 334} 335 336if [[ "$EAS_BUILD_PROFILE" != "test" ]]; then 337 exit 338fi 339 340# Fail if anything errors 341set -eox pipefail 342# If this script exits, trap it first and clean up the emulator 343trap cleanup EXIT 344 345ANDROID_EMULATOR=pixel_4 346 347if [[ "$EAS_BUILD_PLATFORM" == "android" ]]; then 348 # Start emulator 349 $ANDROID_SDK_ROOT/emulator/emulator @$ANDROID_EMULATOR -no-audio -no-boot-anim -no-window -use-system-libs 2>&1 >/dev/null & 350 351 # Wait for emulator 352 max_retry=10 353 counter=0 354 until adb shell getprop sys.boot_completed; do 355 sleep 10 356 [[ counter -eq $max_retry ]] && echo "Failed to start the emulator!" && exit 1 357 counter=$((counter + 1)) 358 done 359 360 # Execute Android tests 361 if [[ "$EAS_BUILD_PROFILE" == "test" ]]; then 362 detox test --configuration android.release 363 fi 364else 365 # Execute iOS tests 366 if [[ "$EAS_BUILD_PROFILE" == "test" ]]; then 367 detox test --configuration ios.release 368 fi 369fi 370``` 371 372Edit **package.json** to use [EAS Build hooks](/build-reference/npm-hooks.mdx) to run the above scripts on EAS Build: 373 374```json package.json 375{ 376 "scripts": { 377 "eas-build-pre-install": "./eas-hooks/eas-build-pre-install.sh", 378 "eas-build-on-success": "./eas-hooks/eas-build-on-success.sh" 379 } 380} 381``` 382 383> 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`. 384 385### 6. Run tests on EAS Build 386 387Running the tests on EAS Build is like running a regular build: 388 389<Terminal cmd={['$ eas build -p all -e test']} /> 390 391If you have set up everything correctly you should see the successful test result in the build logs: 392 393<ImageSpotlight src="/static/images/eas-build/tests/03-logs.png" style={{ maxWidth: '90%' }} /> 394 395### 7. Upload screenshots of failed test cases 396 397> This step is optional but highly recommended. 398 399When 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**. 400 401#### Take screenshots for failed tests 402 403Detox supports taking in-test screenshots of the device. The [**detox.config.js** sample](/build-reference/e2e-tests/#configure-detox) above includes a line to configure Detox to take screenshots of failed tests. 404 405#### Configure EAS Build for screenshots upload 406 407Edit **eas.json** and add `buildArtifactPaths` to the `test` build profile: 408 409```json eas.json 410{ 411 "build": { 412 "test": { 413 "android": { 414 "gradleCommand": ":app:assembleRelease :app:assembleAndroidTest -DtestBuildType=release", 415 "withoutCredentials": true 416 }, 417 "ios": { 418 "simulator": true 419 }, 420 /* @info */ 421 "buildArtifactPaths": ["artifacts/**/*.png"] 422 /* @end */ 423 } 424 } 425} 426``` 427 428In 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. 429 430If you run E2E tests locally, remember to add `artifacts` to `.gitignore`: 431 432```stylus .gitignore 433artifacts/ 434``` 435 436#### Break a test and run a build 437 438To test the new configuration, let's break a test and see that EAS Build uploads the screenshots. 439 440Edit **e2e/homeScreen.e2e.js** and make the following change: 441 442<DiffBlock source="/static/diffs/e2e-tests-homescreen.diff" /> 443 444Run an iOS build with the following command and wait for it to finish: 445 446<Terminal cmd={['$ eas build -p ios -e test']} /> 447 448After going to the build details page you should see that the build failed. Use the **"Download artifacts"** button to download and examine the screenshot: 449 450<ImageSpotlight src="/static/images/eas-build/tests/04-artifacts.png" style={{ maxWidth: '90%' }} /> 451 452## Repository 453 454The full example from this guide is available at https://github.com/expo/eas-tests-example. 455 456## Alternative Approaches 457 458### Using development builds to speed up test run time 459 460The 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. 461 462Instead, 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). 463 464Development 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). 465 466An 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. 467 468<Collapsible summary="e2e/homeScreen.e2e.js"> 469 470```js 471/* @info New line */ 472const { openApp } = require('./utils/openApp'); 473/* @end */ 474 475describe('Home screen', () => { 476 beforeEach(async () => { 477 /* @info New line */ await openApp(); /* @end */ 478 }); 479 480 it('"Click me" button should be visible', async () => { 481 await expect(element(by.id('click-me-button'))).toBeVisible(); 482 }); 483 484 it('shows "Hi!" after tapping "Click me"', async () => { 485 await element(by.id('click-me-button')).tap(); 486 await expect(element(by.text('Hi!'))).toBeVisible(); 487 }); 488}); 489``` 490 491</Collapsible> 492 493<Collapsible summary="e2e/utils/openApp.js (new file)"> 494 495```js 496const appConfig = require('../../../app.json'); 497const { resolveConfig } = require('detox/internals'); 498 499const platform = device.getPlatform(); 500 501module.exports.openApp = async function openApp() { 502 const config = await resolveConfig(); 503 if (config.configurationName.split('.')[1] === 'debug') { 504 return await openAppForDebugBuild(platform); 505 } else { 506 return await device.launchApp({ 507 newInstance: true, 508 }); 509 } 510}; 511 512async function openAppForDebugBuild(platform) { 513 const deepLinkUrl = process.env.EXPO_USE_UPDATES 514 ? // Testing latest published EAS update for the test_debug channel 515 getDeepLinkUrl(getLatestUpdateUrl()) 516 : // Local testing with packager 517 getDeepLinkUrl(getDevLauncherPackagerUrl(platform)); 518 519 if (platform === 'ios') { 520 await device.launchApp({ 521 newInstance: true, 522 }); 523 sleep(3000); 524 await device.openURL({ 525 url: deepLinkUrl, 526 }); 527 } else { 528 await device.launchApp({ 529 newInstance: true, 530 url: deepLinkUrl, 531 }); 532 } 533 534 await sleep(3000); 535} 536 537const getDeepLinkUrl = (url) => 538 `eastestsexample://expo-development-client/?url=${encodeURIComponent(url)}`; 539 540const getDevLauncherPackagerUrl = (platform) => 541 `http://localhost:8081/index.bundle?platform=${platform}&dev=true&minify=false&disableOnboarding=1`; 542 543const getLatestUpdateUrl = () => 544 `https://u.expo.dev/${getAppId()}?channel-name=test_debug&disableOnboarding=1`; 545 546const getAppId = () => appConfig?.expo?.extra?.eas?.projectId ?? ''; 547 548const sleep = (t) => new Promise((res) => setTimeout(res, t)); 549``` 550 551</Collapsible> 552 553<Collapsible summary="detox.config.js"> 554 555```js 556/** @type {Detox.DetoxConfig} */ 557module.exports = { 558 logger: { 559 level: process.env.CI ? 'debug' : undefined, 560 }, 561 testRunner: { 562 $0: 'jest', 563 args: { 564 config: 'e2e/jest.config.js', 565 _: ['e2e'], 566 }, 567 }, 568 artifacts: { 569 plugins: { 570 log: process.env.CI ? 'failing' : undefined, 571 screenshot: 'failing', 572 }, 573 }, 574 apps: { 575 'ios.debug': { 576 type: 'ios.app', 577 build: 578 'xcodebuild -workspace ios/eastestsexample.xcworkspace -scheme eastestsexample -configuration Debug -sdk iphonesimulator -arch x86_64 -derivedDataPath ios/build', 579 binaryPath: 580 'ios/build/Build/Products/Debug-iphonesimulator/eastestsexample.app', 581 }, 582 'ios.release': { 583 type: 'ios.app', 584 build: 585 'xcodebuild -workspace ios/eastestsexample.xcworkspace -scheme eastestsexample -configuration Release -sdk iphonesimulator -arch x86_64 -derivedDataPath ios/build', 586 binaryPath: 587 'ios/build/Build/Products/Release-iphonesimulator/eastestsexample.app', 588 }, 589 'android.debug': { 590 type: 'android.apk', 591 build: 592 'cd android && ./gradlew :app:assembleDebug :app:assembleAndroidTest -DtestBuildType=debug && cd ..', 593 binaryPath: 'android/app/build/outputs/apk/debug/app-debug.apk', 594 }, 595 'android.release': { 596 type: 'android.apk', 597 build: 598 'cd android && ./gradlew :app:assembleRelease :app:assembleAndroidTest -DtestBuildType=release && cd ..', 599 binaryPath: 'android/app/build/outputs/apk/release/app-release.apk', 600 }, 601 }, 602 devices: { 603 simulator: { 604 type: 'ios.simulator', 605 device: { 606 type: 'iPhone 14', 607 }, 608 }, 609 emulator: { 610 type: 'android.emulator', 611 device: { 612 avdName: 'pixel_4', 613 }, 614 }, 615 }, 616 configurations: { 617 'ios.debug': { 618 device: 'simulator', 619 app: 'ios.debug', 620 }, 621 'ios.release': { 622 device: 'simulator', 623 app: 'ios.release', 624 }, 625 'android.debug': { 626 device: 'emulator', 627 app: 'android.debug', 628 }, 629 'android.release': { 630 device: 'emulator', 631 app: 'android.release', 632 }, 633 }, 634}; 635 636``` 637 638</Collapsible> 639 640<Collapsible summary="eas-hooks/eas-build-on-success.sh"> 641 642```sh 643#!/usr/bin/env bash 644 645function cleanup() 646{ 647 echo 'Cleaning up...' 648 if [[ "$EAS_BUILD_PLATFORM" == "android" ]]; then 649 # Kill emulator 650 adb emu kill & 651 fi 652} 653 654if [[ "$EAS_BUILD_PROFILE" != "test"* ]]; then 655 exit 656fi 657 658# Fail if anything errors 659set -eox pipefail 660# If this script exits, trap it first and clean up the emulator 661trap cleanup EXIT 662 663ANDROID_EMULATOR=pixel_4 664 665if [[ "$EAS_BUILD_PLATFORM" == "android" ]]; then 666 # Start emulator 667 $ANDROID_SDK_ROOT/emulator/emulator @$ANDROID_EMULATOR -no-audio -no-boot-anim -no-window -use-system-libs 2>&1 >/dev/null & 668 669 # Wait for emulator 670 max_retry=10 671 counter=0 672 until adb shell getprop sys.boot_completed; do 673 sleep 10 674 [[ counter -eq $max_retry ]] && echo "Failed to start the emulator!" && exit 1 675 counter=$((counter + 1)) 676 done 677 678 679 # Execute Android tests 680 if [[ "$EAS_BUILD_PROFILE" == "test" ]]; then 681 detox test --configuration android.release 682 fi 683 if [[ "$EAS_BUILD_PROFILE" == "test_debug" ]]; then 684 detox test --configuration android.debug 685 fi 686else 687 # Execute iOS tests 688 if [[ "$EAS_BUILD_PROFILE" == "test" ]]; then 689 detox test --configuration ios.release 690 fi 691 if [[ "$EAS_BUILD_PROFILE" == "test_debug" ]]; then 692 detox test --configuration ios.debug 693 fi 694fi 695``` 696 697</Collapsible> 698 699<Collapsible summary="eas.json"> 700 701```json 702{ 703 "build": { 704 "test": { 705 "android": { 706 "gradleCommand": ":app:assembleRelease :app:assembleAndroidTest -DtestBuildType=release", 707 "withoutCredentials": true 708 }, 709 "ios": { 710 "simulator": true 711 } 712 }, 713 /* @info New section */ "test_debug": { 714 "android": { 715 "gradleCommand": ":app:assembleDebug :app:assembleAndroidTest -DtestBuildType=debug", 716 "withoutCredentials": true 717 }, 718 "ios": { 719 "buildConfiguration": "Debug", 720 "simulator": true 721 }, 722 "env": { 723 "EXPO_USE_UPDATES": "1" 724 }, 725 "channel": "test_debug" 726 } /* @end */ 727 } 728} 729``` 730 731</Collapsible> 732