Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Expo + Detox + CircleCI

For the last two days I’ve been looking for a good setup to use Expo + Detox + CircleCI so that the app can build during the CI process.

Locally, I can get Expo + Detox to work by downloading Exponent.app and placing in bin and running expo start (in a different terminal). However, expo start is blocking in Circle CI so is there an efficient way to achieve this.

I have looked at lots of examples and not found a single clear response with updated examples which is a shame considering how popular Expo is getting.

If anyone has an example CircleCI file that you could share that would be really great! Or indeed some help explaining what the flow might be to achieve this.

I appreciate that this is also a question for Detox and CircleCI too but I thought I would add it here as many might also want to know the answer?

My current Circle-CI code that I have been going backwards and forwards with trying to find a solution that works...

# Javascript Node CircleCI 2.0 configuration file
#
# Check https://circleci.com/docs/2.0/language-javascript/ for more details
#
version: 2

defaults: &defaults
  working_directory: ~/iynk-react-app

jobs:

  test:
    <<: *defaults

    docker:
      - image: circleci/node:10

    steps:
      - checkout

      - run:
          name: Update npm
          command: 'sudo npm install -g npm@latest'

      - run:
          name: Install Firebase Tools
          command: sudo npm install -g firebase-tools@latest

      - restore_cache:
          name: Restore Yarn Package Cache
          keys:
            - yarn-packages-{{ checksum "yarn.lock" }}

      - run:
          name: Install Dependencies
          command: yarn install --frozen-lockfile

      - save_cache:
          name: Save Yarn Package Cache
          key: yarn-packages-{{ checksum "yarn.lock" }}
          paths:
            - ~/.cache/yarn

      - run: yarn test

      - run:
          name: Install modules in functions
          command: yarn --cwd ./functions --ignore-engines

  e2e:
    <<: *defaults

    macos:
      xcode: "10.2.1"

    steps:
      - run:
          # Note: the [ character is necessary to uniquely identify the iPhone 8 simulator, as the phone + watch simulator is also present in the build image: 
          # Will show what looks like an error - Instruments Usage Error: Unknown device specified: "iPhone 8 (12.2) [") - but it launch
          name: Pre-start simulator first to ensure that it is open
          command: xcrun instruments -w "iPhone 8 (12.2) [" || true

      - checkout

      - restore_cache:
            key: yarn-v1-{{ checksum "yarn.lock" }}-{{ arch }}

      - restore_cache:
          key: node-v1-{{ checksum "package.json" }}-{{ arch }}

      - run: yarn install --ignore-engines

      - save_cache:
          key: yarn-v1-{{ checksum "yarn.lock" }}-{{ arch }}
          paths:
            - ~/.cache/yarn

      - save_cache:
          key: node-v1-{{ checksum "package.json" }}-{{ arch }}
          paths:
            - node_modules

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

      - run:
          name: Install react-native, detox CLI and expo CLI
          command: |
            npm install -g react-native-cli
            npm install -g detox-cli
            npm install -g expo-cli

      - run:
          name: Prepare detox environment
          command: |
            detox clean-framework-cache && 
            detox build-framework-cache

      - run: 
          name: Download Exponent.app into bin
          command: |
            brew install wget
            ./scripts/setup.sh

      # - run:
      #     name: Install the downloaded version of the expo iOS app on the Simulator
      #     command: |
      #       xcrun simctl install booted ./bin/Exponent.app

      # - run:
      #     name: Login into Expo and publish to staging
      #     command: |
      #       npx expo login -u $EXPO_USERNAME -p $EXPO_PASSWORD
      #       npx expo publish --non-interactive --max-workers 1 --release-channel staging

      - run: 
          name: Run expo locally using (&) Run detox tests
          # shell: /bin/sh
          command: |
            yarn test:e2e & 
            expo start -c    

workflows:
  version: 2

  build_and_test:
    jobs:
      - test
      - e2e

My packages:

"detox": "12.3.0",
"detox-expo-helpers": "^0.6.0",
"expo-detox-hook": "^1.0.10",

Local Works

My local setup runs and the tests pass. This is the process at the moment:

Ensure local environment is setup:

brew update
brew tap wix/brew
brew install --HEAD applesimutils
npm install -g detox-cli

Run the setup script:

./setup.sh

Then start expo.

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). You do not need to run i from expo though, just open the Simulator program.

open -a Simulator.app

Finally, run the detox tests from a different terminal with:

yarn test:e2e

Known issues

  • Detox + Expo + jest : timeout on opening the app https://github.com/wix/Detox/issues/1422

I do not think this is related as I can get my setup to run locally...

UPDATE 2 July 2019

I can get the tests to pass if I build in my circle ci with:

      - run:
          name: Login into Expo and publish to staging (could update with $CIRCLE_BRANCH)
          command: |
            npx expo login -u $EXPO_USERNAME -p $EXPO_PASSWORD --non-interactive
            npx expo publish --non-interactive --max-workers 1 --release-channel testing

And then in the e2e/init.js file load from that release channel:

beforeAll(async () => {
  await detox.init(config);

  // Run from the remote build if in CI
  if (__CI__) {
    const url = 'exp://exp.host/@alexpchin/iynk?release-channel=testing';
    await device.relaunchApp({ url, sourceApp: 'host.exp.exponent' });
    await expect(element(by.label('Got it'))).toBeVisible();
    await element(by.label('Got it')).tap();
  }
});

However, if I use this I must NOT use reloadApp from detox-expo-helpers (in e2e/init.js):

beforeEach(async () => {
  await adapter.beforeEach();
  // If not CI, use `reloadApp` from `detox-expo-helpers`
  if (!__CI__) {
    await reloadApp();
  }
});

This is obviously really slow because you have to create a new build every time you want to test the UI rather than running from the branch code...

like image 367
Alex Chin Avatar asked Nov 06 '22 16:11

Alex Chin


1 Answers

Still no answers or updates, so I'll try to provide mine. From what I understand the flow that you'd want to automate is the test on Simulator. Steps are listed in the attached link.

i.e. for iOS

expo build:ios -t simulator
expo build:status (or expo url:ipa)
tar -xvzf your-app.tar.gz
open /Applications/Xcode.app/Contents/Developer/Applications/Simulator.app --args -CurrentDeviceUDID `xcrun instruments -s | grep "iPhone 7 (12.2)" -m1 | cut -d "[" -f2 | cut -d "]" -f1`
xcrun simctl install booted <app path>
xcrun simctl launch booted <app identifier>
like image 82
Gianluca Esposito Avatar answered Nov 15 '22 11:11

Gianluca Esposito