Appium Testing ReactNative for iOS Simulator in Github Actions, Sep 2020

Sandeep Dinesh
5 min readSep 28, 2020

--

iOS Test Bed in Github Actions

Continuing the good work of GitHub Actions trials from the time I tasted success with it for Android Emulators, My next short stop was the daunting iOS test bed setup in Github Actions. (For the uninitiated, please refer my post for Android Emulator, Appium on Github Actions here in medium)

Any one remembering the good old days of XCode Build of the project, package name update, Installation for XCUITestServer on Emulator, Apple Developer Certificates Signature and all that — Thanks God, Appium has eventually decided to spare us all from that drama from version 1.16 onwards with the XCUITestServer being packaged along with it.

As it turned out, it was way too easy this time. So, let’s jump to Coding

TLDR:
This is the route map of what we want to achieve..

1. Install iOS simulator runtime which you need
2. Create iOS simulator and start in the background
3. Start Metro Server in the background
4. Start Appium in the background
5. Use react-native run-ios
6. Copy the generated .app from the react-native run-ioscommand to the folder where you have set as the ‘app’ parameter in the desired capabilities
7. Run the tests

So Keep in Mind, Appium to be 1.16 or above and use of MacOS nodes in GitHub Actions.

Sample YAML:

# Pre-Commit E2E Tests in iOS
name: Pre-Commit E2E Tests in iOS
# Controls when the action will run.
on:
push:
branches: [ testbranch ]
pull_request:
branches: [ develop ]

# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
# This workflow contains a single job called "build"
build:
# The type of runner that the job will run on
runs-on: macOS-latest
# Steps represent a sequence of tasks that will be executed as part of the job
steps:
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
- uses: actions/checkout@v2
with:
ref: testbranch
# Setup Node JS - 10.17.0
- name: Set up Node JS 10.17.0
uses: actions/setup-node@v1
with:
node-version: '10.17.0'
# Clean Packages & Install Dependencies
- name: Clean Packages
run: |
rm -rf node_modules
npm cache clean --force
rm -rf package-lock.json
# Install React Native CLI
- name: Install React Native CLI
run: |
npm install react-native-cli
# List iOS Devices & Platforms
- name: List iOS Devices & Platforms
run: |
xcrun simctl list
# Install iOS 11.4 Runtime
- name: Install iOS 11.4 Runtime
run: |
gem install xcode-install
xcversion simulators --install='iOS 11.4'
# Create and Boot iOS Emulator - iPhoneX on iOS 11.4, Update default appium config for iOS
- name: Create and Run iOS Emulator - iPhoneX on iOS 11.4, Update default appium config for iOS
run: |
xcrun simctl create TestiPhoneX com.apple.CoreSimulator.SimDeviceType.iPhone-X com.apple.CoreSimulator.SimRuntime.iOS-11-4 > deviceid.txt
DEVICEUUID=`cat deviceid.txt`
echo $DEVICEUUID
sed -i -e "s/{IPHONE_UUID}/$DEVICEUUID/g" __tests__/e2e/template_appium_configs_ios.js
xcrun simctl boot $DEVICEUUID &
# Use HTTPS repos
- name: Use HTTPS repos
run: |
git config --global url."https://github".insteadOf ssh://git@github
# Install Repo and Dependencies
- name: Install Repo and Dependencies
run: |
npm install --save-dev
# Start the Appium Server
- name: Start the Appium Server
run: ./node_modules/.bin/appium --log-timestamp --log-no-colors --allow-insecure chromedriver_autodownload > appium.log &
# Poll for Appium Server to Start
- name: Poll for Appium Server to Start
run: |
until $(curl --output /dev/null --silent --head --fail http://127.0.0.1:4723/wd/hub/sessions); do
sleep 5
done
# Open Metro Bundler in Background
- name: Open Metro Bundler in Background
run: |
node_modules/react-native/scripts/launchPackager.command &
# Build iOS App and Run Tests
- name: Build iOS App and Run Tests
env:
E2E_TEST_PLATFORM: 'ios'
E2E_TEST_DEFAULTS: 'true'
E2E_TEST_TAGS: 'E2E'
run: |
react-native run-ios
BUILT_APP=`find ~/Library/Developer/Xcode/DerivedData -name <APP_NAME>.app | grep Build/Products/Debug-iphonesimulator/<APP_NAME>.app`
mkdir -p ios/build/<APP_NAME>/Build/Products/Debug-iphonesimulator
cp -R $BUILT_APP ios/build/<APP_NAME>/Build/Products/Debug-iphonesimulator
sleep 30
npm run e2e-test
# Upload Appium Logs
- name: Upload Appium logs
uses: actions/upload-artifact@v1
with:
name: appium.log
path: appium.log
# Upload Test Results
- name: Upload Test Results
uses: actions/upload-artifact@v1
with:
name: e2e-results
path: __tests__/e2e/output
Runtime installation of iOS 11.4

Few Hacks!
I am saving the Simulator’s UUID from the xcrun create command and replacing the desired capability which I have stored in __tests__/e2e/template_appium_configs_ios.js
Also ensure, you update the values of exact .app location and Apple developer’s certificate OrgId

Note that iOS appears to have a setting which will set the build location, but after much searching around for a command line way to do, I gave up on it. Instead I identified the generated build folder and copied to where I want to set as the ‘app’ param in appium config.

platform: 'iOS',
desiredCapabilities: {
deviceName: 'TestiPhoneX',
platformVersion: '11.4',
app: path.join(
__dirname,
'..',
'..',
'ios',
'build',
'<PRODUCT>',
'Build',
'Products',
'Debug-iphonesimulator',
'<APP>.app',
),
udid: '{IPHONE_UUID}',
xcodeOrgId: '<APPLE DEVELOPER CERT ORG>',
xcodeSigningId: 'iPhone Developer',
automationName: 'XCUITest',
}

Explanations
I have configured ‘e2e-test’ as a script in my package.json also the results will be available under ‘__tests__/e2e/output’.

  1. Appium is added as part of my dependencies, so it will be installed in ‘npm install — save-dev’
  2. I have few dependencies which don’t git clone in ssh mode, to overcome it I am forcing ‘Use HTTPS repos’ step, in your case it could be optional.
  3. Finally, if you are using Artifactory in your repo, you can add these steps before ‘Use HTTPS repos’ or ‘Install Repo and Dependencies’ step as explained in previous step
# Install Login CMD      
- name: Install npm-login-cmd
run: |
npm install -g npm-login-cmd
# Config Registry
- name: Config Registry
run: |
npm config set registry '${{ secrets.ARTIFACTORY_REGISTRY }}' # Login to NPM Repo
- name: npm login
env:
NPM_USER: ${{ secrets.ARTIFACTORY_USERNAME }}
NPM_PASS: ${{ secrets.ARTIFACTORY_PASSWORD }}
NPM_EMAIL: ${{ secrets.ARTIFACTORY_EMAIL }}
run: |
npm-login-cmd

Happy Test Automation!

--

--