Expo + Detox + CircleCI - react-native

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...

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>

Related

Trying to Automate React Native builds with Firebase App Distribution using Gitlab CI/CID in windows

I'm having trouble automating react native release build apps using firebase app distribution with Gitlab CI/CD. I get this error Error: set the --app option to a valid Firebase app id and try again
Also see image:
I've setup ".gitlab-ci.yml" file as below
## install project deps with --frozen-lockfile to make sure we will have the same packages version ( very recommended on running yarn install on ci)
##run: yarn install --frozen-lockfile
before_script:
- yarn install --frozen-lockfile
- yarn global add firebase-tools
stages:
- buildApp
buildApp project:
stage: buildApp
image: reactnativecommunity/react-native-android
cache:
key:
files:
- yarn.lock
paths:
- node_modules
policy: pull #`pull` the jobs pull the cache at the beginning but do not push the changes again.
script:
- yarn build:apk
- yarn install --pure-lockfile --cache-folder .yarn
- ./bin/app_distribution.sh
# - firebase use kavyatara --token "$FIREBASE_TOKEN"
# - firebase deploy --token "$FIREBASE_TOKEN"
artifacts:
paths:
- android/app/build/outputs/apk/release/app-release.apk
Also
app_distribution.sh file
#!/bin/bash
RELEASE_NOTE="New update Android build"
firebase appdistribution:distribute android/app/build/outputs/apk/release/app-release.apk \
--token "$FIREBASE_TOKEN" \
--app "$FIREBASE_APP_ID" \
--release-notes "$RELEASE_NOTE" --testers-file testers.txt

get expo build url in Gitlab CI

I am using Gitlab CI to automate my expo project builds, for that I am using following commands to build and submit iOS app on TestFlight.
expo build:ios --non-interactive --skip-credentials-check
eas submit -p ios --latest --profile stage --non-interactive
The first command will return a build url, that url must be used in second command to submit build to TestFlight.
The issue is I am not able to get the url from expo build command, I tried using variable, but if I am using variable the command is not waiting for finish the command, so before the build finish next line is executed.
using variable
VER_BUILD_URL=$(expo build:ios --non-interactive
--skip-credentials-check)
Solution can be following:
I can get the url returned from expo build and can pass that url to eas submit
OR
expo must have a command to get the url directly from that command
We solved this by getting the build id from the output of the new eas build command and storing it in a variable. The variable can then be used in the next stage. Not sure if you can use the same solution with expo build:ios, as we just started building our first app with expo and directly used eas.
.template:
image: node:16-alpine
cache:
key: ${CI_COMMIT_REF_SLUG}
paths:
- .yarn
before_script:
- yarn install --cache-folder .yarn
- apk add --no-cache bash git
build:
extends: .template
stage: build
script:
- npx eas-cli build -p ios --non-interactive --profile production | tee $CI_PROJECT_DIR/.build-result-ios
- echo "IOS_BUILD_ID=$(sed -n "s/^Build details.*\/builds\/\([a-f0-9-]*\)$/\1/p" $CI_PROJECT_DIR/.build-result-ios)" >> build.env
artifacts:
reports:
dotenv: build.env
deploy:
image: node:16-alpine
stage: deploy
script:
- npx eas-cli submit -p ios --non-interactive --profile production --id=$IOS_BUILD_ID
dependencies:
- build-ios
needs:
- job: build-ios
artifacts: true
As a side note: With eas build you can also use the --auto-submit parameter.

gitlab-ci install specific yarn version

i have trouble with gitlab Continous integration. in localhost it yarn start work without problem even unit-test yarn berry version 2.4.2
my .yarnrc.yml
nodeLinker: node-modules
yarnPath: .yarn/releases/yarn-2.4.2.cjs
how to install a specific version of yarn in gitlab with gitlab-ci.yml please ?
I tryed with this different configuration and all failed
my gitlab-ci.yml
...
unit-tests:
stage: test
image: node:15.2.1-alpine3.11
cache:
key: ${CI_COMMIT_REF_SLUG}
paths:
- .yarn/
script:
- yarn set version 2.4.2
/* tested also with
yarn set version https://cdn.jsdelivr.net/npm/2.4.2#1.0.0/
yarn set version 2.4.2.cjs
yarn set version https://cdn.jsdelivr.net/npm/2.4.2
*/
- yarn install
- yarn build
- yarn test
the error
00:01
Using docker image sha256:7ddc154413f500a1ec545a38fe661bf0fd138e061495e5786ef017352b52c52d for node:15.2.1-alpine3.11 with digest node#sha256:7614f96f47ede63333a7ddbd31c71207956eb39b641e724f81c198c067bacf41 ...
$ yarn set version 2.4.2.cjs
Resolving 2.4.2.cjs to a url...
error An unexpected error occurred: "Release not found: 2.4.2.cjs".
this is a solution : using yarn set version 2.4.2alone don't work
.gitlab-ci.yml
stages:
- test
- release
unit-tests:
stage: test
image: node:15.2.1-alpine3.11
cache:
key: ${CI_COMMIT_REF_SLUG}
paths:
- .yarn/
script:
- yarn set version berry <--- get last version
- yarn set version 2.4.2 <--- then downgrade to a specific version
- yarn install
- yarn build
- yarn test
...
Dockerfile ( for build in CI)
...
ENV NODE_ENV production
RUN yarn set version berry
RUN yarn set version 2.4.2
RUN yarn install
...

environment variables in Expo when building with GitLab

I'm trying to build a React Native APK with Expo (without ejecting). I can manage to locally get my environment variables from .env file when I do expo build:android in my local machine with all the project files.
When I do a push to my GitLab repository, I have this .gitlab-ci.yml file
---
image: node:alpine
cache:
key: ${CI_COMMIT_REF_SLUG}
paths:
- ~/.npm
- .jest
stages:
- test
- deploy
before_script:
- npm ci
jest-tests:
stage: test
script:
- npx jest --ci --passWithNoTests
expo-deployments:
stage: deploy
script:
- apk add --no-cache bash
- npx expo login -u $EXPO_USERNAME -p $EXPO_PASSWORD
- npx expo build:android --EXPO_ANDROID_GOOGLE_API_KEY $EXPO_ANDROID_GOOGLE_API_KEY --EXPO_IOS_GOOGLE_API_KEY $EXPO_IOS_GOOGLE_API_KEY --release-channel staging --non-interactive
- EXPO_ANDROID_GOOGLE_API_KEY=$EXPO_ANDROID_GOOGLE_API_KEY; EXPO_IOS_GOOGLE_API_KEY=$EXPO_IOS_GOOGLE_API_KEY; expo build:android --release-channel staging --non-interactive
I don't have in the repo the .env file, because of security.
Where all this variables are stored within each environment in GitLab:
(working perfectly)
EXPO_USERNAME = the username of my development account to access Expo.
EXPO_PASSWORD = the password of the account to access Expo.
(not working at all when trying to build)
EXPO_IOS_GOOGLE_API_KEY = "abcdefghijklmnopqrstuvwxyz"
EXPO_ANDROID_GOOGLE_API_KEY = "abcdefghijklmnopqrstuvwxz"
I wonder how could I set the Google Maps environment variables into the app when running the expo build:android command via GitLab CI pipeline:
- npx expo build:android
Finally I could manage to make this work the following way:
---
image: node:alpine
cache:
key: ${CI_COMMIT_REF_SLUG}
paths:
- ~/.npm
- .jest
stages:
- test
- deploy
before_script:
- npm ci
- ANDROID_GOOGLE_MAPS_API_KEY=${CI_COMMIT_BRANCH}_EXPO_ANDROID_GOOGLE_API_KEY
- IOS_GOOGLE_MAPS_API_KEY=${CI_COMMIT_BRANCH}_EXPO_IOS_GOOGLE_API_KEY
- export android=$( eval echo \$$ANDROID_GOOGLE_MAPS_API_KEY )
- export ios=$( eval echo \$$IOS_GOOGLE_MAPS_API_KEY )
jest-tests:
stage: test
script:
- npx jest --ci --passWithNoTests
expo-deployments:
stage: deploy
script:
- echo "EXPO_ANDROID_GOOGLE_API_KEY=$android" >> .env
- echo "EXPO_IOS_GOOGLE_API_KEY=$ios" >> .env
- apk add --no-cache bash
- npx expo login -u $EXPO_USERNAME -p $EXPO_PASSWORD
- npx expo build:android --release-channel staging --non-interactive
Where...
...CI_COMMIT_BRANCH is development|staging|production depending which branch in gitlab I am using.
...development_EXPO_ANDROID_GOOGLE_API_KEY | staging_EXPO_ANDROID_GOOGLE_API_KEY | production_EXPO_ANDROID_GOOGLE_API_KEY are variables that are stored at the Gitlab project.
... I am generating the .env file every time I run the script and saving there my variables with the respective value with: echo "EXPO_ANDROID_GOOGLE_API_KEY=$android" >> .env.
This way I don't need to push my .env file into Gitlab. I only need to define my variables in the settings of the project at Gitlab.
Hope this help to someone!

react-native expo in circleci fails to login: This command requires Expo CLI

I'm setting up a ci/cd pipeline for my expo react-native application using circleci.
I have followed this tutorial. And this is my config.yml:
version: 2
publish: &publish
working_directory: ~/loplop-native
docker:
- image: circleci/node:12.14.0
steps:
- checkout
- restore_cache:
name: Restore yarn package cache
key: v1-cache-dependencies-{{ checksum "yarn.lock" }}-{{ checksum "package.json" }}-{{ arch }}
- run:
name: Install dependencies
command: yarn install --frozen-lockfile
- save_cache:
name: Save yarn package cache
paths:
- ~/.cache/yarn
key: v1-cache-dependencies-{{ checksum "yarn.lock" }}-{{ checksum "package.json" }}-{{ arch }}
- run:
name: Login into Expo
command: npx expo login -u $EXPO_USERNAME -p $EXPO_PASSWORD
# command: npx expo login --non-interactive -u $EXPO_USERNAME
- run:
name: Save current branch name to an env variable
command: |
if [ "${CIRCLE_BRANCH}" == "master" ]; then
echo 'export EXPO_RELEASE_CHANNEL="default"' >> $BASH_ENV
else
echo 'export EXPO_RELEASE_CHANNEL=$CIRCLE_BRANCH' >> $BASH_ENV
fi
- run:
name: Publish to Expo
command: npx expo publish --non-interactive --max-workers 1 --release-channel $EXPO_RELEASE_CHANNEL
jobs:
build_and_test:
docker:
- image: circleci/node:12.14.0
steps:
- checkout
- restore_cache:
name: Restore yarn package cache
key: v1-cache-dependencies-{{ checksum "yarn.lock" }}-{{ checksum "package.json" }}-{{ arch }}
- run:
name: Install Expo-cli
command: yarn global add expo-cli
- run:
name: Install dependencies
command: yarn install --frozen-lockfile
- save_cache:
name: Save yarn package cache
paths:
- ~/.cache/yarn
key: v1-cache-dependencies-{{ checksum "yarn.lock" }}-{{ checksum "package.json" }}-{{ arch }}
- run:
name: Run linting
command: yarn lint
publish_to_expo:
<<: *publish
workflows:
version: 2
workflow:
jobs:
- build_and_test
- publish_to_expo:
filters:
branches:
ignore: gh-pages
The script is failing on the login step with this error:
I have also tried with the --no-interactive flag but I'm still getting the same error.
Any suggestion would be greatly appreciated.
You need to install the Expo CLI first. Run yarn global add expo-cli or npm install -g expo-cli, then run the Expo commands directly, without npx (e.g. expo login ...)
It is due to you don't have the dependencies of expo-cli in package.json. You need to add "expo-cli": "1.1.0-beta.4" in package.json under devdependencies.
Reference : https://bitbucket.org/byCedric/expo-guide-ci/src/master/package.json