How to run Detox tests on GitHub Actions


This post goes over how to set up and run React Native Detox tests on GitHub Actions:

Prerequisites

You have a React Native project with Detox set up.

iOS

Create a GitHub Actions workflow named e2e-ios.yml:

mkdir -p .github/workflows && touch .github/workflows/e2e-ios.yml

Name your workflow, set up the event that triggers the workflow, and create a job that runs on macOS:

name: e2e-ios
on: push
jobs:
  e2e-ios:
    runs-on: macos-latest
    steps:
      # ...

iOS Steps

Check out the repository:

- name: Checkout repository
  uses: actions/checkout@v3

Set up Node.js:

- name: Setup Node.js
  uses: actions/setup-node@v3
  with:
    cache: yarn
    node-version-file: .node-version

If you’re using NVM, replace .node-version with .nvmrc.

Install node_modules with Yarn:

- name: Install Yarn dependencies
  run: yarn --frozen-lockfile --prefer-offline

Install applesimutils with Homebrew:

- name: Install macOS dependencies
  run: |
    brew tap wix/brew
    brew install applesimutils

If you want to speed up the step, you can disable Homebrew’s auto update and install cleanup:

env:
  HOMEBREW_NO_AUTO_UPDATE: 1
  HOMEBREW_NO_INSTALL_CLEANUP: 1

Set up Ruby, run bundle install, and cache gems:

- name: Setup Ruby
  uses: ruby/setup-ruby@v1
  with:
    bundler-cache: true

ruby/setup-ruby will get the Ruby version from .ruby-version.

Install and cache CocoaPods:

- name: Cache CocoaPods
  id: cache-cocoapods
  uses: actions/cache@v3
  with:
    path: ios/Pods
    key: ${{ runner.os }}-pods-${{ hashFiles('ios/Podfile.lock') }}
    restore-keys: |
      ${{ runner.os }}-pods-

- name: Install CocoaPods
  if: steps.cache-cocoapods.outputs.cache-hit != 'true'
  run: cd ios ; pod install ; cd -

Optionally, you can clean and build Detox framework cache:

- name: Detox rebuild framework cache
  run: yarn detox rebuild-framework-cache

Build and cache Detox iOS (release) build:

- name: Cache Detox build
  id: cache-detox-build
  uses: actions/cache@v3
  with:
    path: ios/build
    key: ${{ runner.os }}-detox-build
    restore-keys: |
      ${{ runner.os }}-detox-build

- name: Detox build
  run: yarn detox build --configuration ios.sim.release

This builds the iOS app using the ios.sim.release configuration in .detoxrc.js.

Run Detox tests:

- name: Detox test
  run: yarn detox test --configuration ios.sim.release --cleanup --headless --record-logs all

If you get the error Exceeded timeout of 120000ms while setting up Detox environment, then increase the testRunner.jest.setupTimeout in .detoxrc.js.

If there’s a failure, upload the Detox artifacts so you can download them after the workflow ends:

- name: Upload artifacts
  if: failure()
  uses: actions/upload-artifact@v3
  with:
    name: detox-artifacts
    path: artifacts

iOS Workflow

Here’s the full E2E workflow for iOS (see code):

# .github/workflows/e2e-ios.yml
name: e2e-ios
on: push

jobs:
  e2e-ios:
    runs-on: macos-latest
    steps:
      - name: Checkout repository
        uses: actions/checkout@v3

      - name: Setup Node.js
        uses: actions/setup-node@v3
        with:
          cache: yarn
          node-version-file: .node-version

      - name: Install Yarn dependencies
        run: yarn --frozen-lockfile --prefer-offline

      - name: Install macOS dependencies
        run: |
          brew tap wix/brew
          brew install applesimutils
        env:
          HOMEBREW_NO_AUTO_UPDATE: 1
          HOMEBREW_NO_INSTALL_CLEANUP: 1

      - name: Setup Ruby
        uses: ruby/setup-ruby@v1
        with:
          bundler-cache: true

      - name: Cache CocoaPods
        id: cache-cocoapods
        uses: actions/cache@v3
        with:
          path: ios/Pods
          key: ${{ runner.os }}-pods-${{ hashFiles('ios/Podfile.lock') }}
          restore-keys: |
            ${{ runner.os }}-pods-

      - name: Install CocoaPods
        if: steps.cache-cocoapods.outputs.cache-hit != 'true'
        run: cd ios ; pod install ; cd -

      - name: Detox rebuild framework cache
        run: yarn detox rebuild-framework-cache

      - name: Cache Detox build
        id: cache-detox-build
        uses: actions/cache@v3
        with:
          path: ios/build
          key: ${{ runner.os }}-detox-build
          restore-keys: |
            ${{ runner.os }}-detox-build

      - name: Detox build
        run: yarn detox build --configuration ios.sim.release

      - name: Detox test
        run: yarn detox test --configuration ios.sim.release --cleanup --headless --record-logs all

      - name: Upload artifacts
        if: failure()
        uses: actions/upload-artifact@v3
        with:
          name: detox-artifacts
          path: artifacts

Android

Before you start, make sure you first patch your project with the additional Android configuration.

Create a GitHub Actions workflow named e2e-android.yml:

mkdir -p .github/workflows && touch .github/workflows/e2e-android.yml

Name your workflow, set up the event that triggers the workflow, and create a job that runs on macOS:

name: e2e-android
on: push
jobs:
  e2e-android:
    runs-on: macos-latest
    steps:
      # ...

Android Steps

Check out the repository:

- name: Checkout repository
  uses: actions/checkout@v3

Set up Node.js:

- name: Setup Node.js
  uses: actions/setup-node@v3
  with:
    cache: yarn
    node-version-file: .node-version # .nvmrc

Install node_modules with Yarn:

- name: Install Yarn dependencies
  run: yarn --frozen-lockfile --prefer-offline

Set up Java:

- name: Setup Java
  uses: actions/setup-java@v3
  with:
    cache: gradle
    distribution: temurin
    java-version: 17

Build and cache Detox Android (release) build:

- name: Cache Detox build
  id: cache-detox-build
  uses: actions/cache@v3
  with:
    path: ios/build
    key: ${{ runner.os }}-detox-build
    restore-keys: |
      ${{ runner.os }}-detox-build

- name: Detox build
  run: yarn detox build --configuration android.emu.release

This builds the Android app using the android.emu.release configuration in .detoxrc.js.

Get the Android Virtual Device (AVD) name from .detoxrc.js:

- name: Get device name
  id: device
  run: node -e "console.log('AVD_NAME=' + require('./.detoxrc').devices.emulator.device.avdName)" >> $GITHUB_OUTPUT

Run Detox tests using reactivecircus/android-emulator-runner:

- name: Detox test
  uses: reactivecircus/android-emulator-runner@v2
  with:
    api-level: 31
    arch: x86_64
    avd-name: ${{ steps.device.outputs.AVD_NAME }}
    script: yarn detox test --configuration android.emu.release --headless --record-logs all

Make sure not to pass the --cleanup option in the script or else it will throw an error:

detox[27246] i adb: error: device 'emulator-5554' not found

If there’s a failure, upload the Detox artifacts so you can download them after the workflow ends:

- name: Upload artifacts
  if: failure()
  uses: actions/upload-artifact@v3
  with:
    name: detox-artifacts
    path: artifacts

Android Workflow

Here’s the full E2E workflow for Android (see code):

# .github/workflows/e2e-android.yml
name: e2e-android
on: push

jobs:
  e2e-android:
    runs-on: macos-latest

    steps:
      - name: Checkout repository
        uses: actions/checkout@v3

      - name: Setup Node.js
        uses: actions/setup-node@v3
        with:
          cache: yarn
          node-version-file: .node-version

      - name: Install Yarn dependencies
        run: yarn --frozen-lockfile --prefer-offline

      - name: Setup Java
        uses: actions/setup-java@v3
        with:
          cache: gradle
          distribution: temurin
          java-version: 17

      - name: Cache Detox build
        id: cache-detox-build
        uses: actions/cache@v3
        with:
          path: android/app/build
          key: ${{ runner.os }}-detox-build
          restore-keys: |
            ${{ runner.os }}-detox-build

      - name: Detox build
        run: yarn detox build --configuration android.emu.release

      - name: Get device name
        id: device
        run: node -e "console.log('AVD_NAME=' + require('./.detoxrc').devices.emulator.device.avdName)" >> $GITHUB_OUTPUT

      - name: Detox test
        uses: reactivecircus/android-emulator-runner@v2
        with:
          api-level: 31
          arch: x86_64
          avd-name: ${{ steps.device.outputs.AVD_NAME }}
          script: yarn detox test --configuration android.emu.release --headless --record-logs all

      - name: Upload artifacts
        if: failure()
        uses: actions/upload-artifact@v3
        with:
          name: detox-artifacts
          path: artifacts

Resources



Please support this site and join our Discord!