Skip to content

fix(android): protect against headlessJS task multiple-invocation #668

fix(android): protect against headlessJS task multiple-invocation

fix(android): protect against headlessJS task multiple-invocation #668

name: Testing E2E Android
on:
workflow_dispatch:
pull_request:
paths-ignore:
- 'docs/**'
- '**/*.md'
push:
branches:
- main
paths-ignore:
- 'docs/**'
- '**/*.md'
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
android:
name: Android
runs-on: ubuntu-latest
timeout-minutes: 60
strategy:
fail-fast: false
matrix:
# Currently just API31 to mirror prior testing
# TODO: determine min we can test, and test max as well
api-level: [31]
arch: [x86_64]
target: [google_apis]
# This is useful for benchmarking, do 0, 1, 2, etc (up to 256 max job-per-matrix limit) for averages
iteration: [0]
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
steps:
- name: Liberate disk space
uses: jlumbroso/free-disk-space@main
with:
tool-cache: false
android: false
dotnet: true
haskell: true
large-packages: false
docker-images: true
swap-storage: false
- name: Enable KVM group perms
run: |
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
sudo udevadm control --reload-rules
sudo udevadm trigger --name-match=kvm
- uses: actions/checkout@v4
with:
fetch-depth: 50
- uses: actions/setup-node@v4
with:
node-version: 20
- name: Set workflow variables
id: workflow-variables
run: |
echo "yarn-cache=$(yarn cache dir)" >> $GITHUB_OUTPUT
echo "metro-cache=$HOME/.metro" >> $GITHUB_OUTPUT
- uses: actions/cache@v4
name: Yarn Cache
id: yarn-cache
with:
path: ${{ steps.workflow-variables.outputs.yarn-cache }}
key: ${{ runner.os }}-yarn-v1-${{ hashFiles('package.json', 'packages/react-native/package.json', 'tests_react_native/package.json') }}
restore-keys: ${{ runner.os }}-yarn-v1
- uses: actions/cache@v4
name: Gradle Cache
with:
path: ~/.gradle/caches
key: ${{ runner.os }}-gradle-v1--${{ hashFiles('package.json', 'packages/react-native/package.json', 'tests_react_native/package.json', 'packages/react-native/android/build.gradle', 'tests_react_native/android/build.gradle', 'tests_react_native/android/app/build.gradle') }}
restore-keys: ${{ runner.os }}-gradle-v1
- uses: actions/cache@v4
name: Cache Pods
with:
path: tests_react_native/ios/Pods
key: ${{ runner.os }}-pods-v2-${{ hashFiles('tests_react_native/ios/Podfile.lock') }}
restore-keys: ${{ runner.os }}-pods-v2
- name: Setup Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: 3
- name: Update Ruby build tools
uses: nick-fields/retry@v3
with:
timeout_minutes: 2
retry_wait_seconds: 60
max_attempts: 3
command: gem update cocoapods xcodeproj
- name: Yarn Install
uses: nick-fields/retry@v3
with:
timeout_minutes: 15
retry_wait_seconds: 60
max_attempts: 4
command: yarn --no-audit --prefer-offline && npm i -g cavy-cli
- name: Configure JDK
uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: '17'
- name: Build Android App
uses: nick-fields/retry@v3
with:
timeout_minutes: 10
retry_wait_seconds: 60
max_attempts: 3
command: yarn tests_rn:android:build
- name: Prepare test index file
# For some reason, in CI, the test file is never running. So let's make all index files the test file.
run: cp tests_react_native/index.test.js tests_react_native/index.js
- name: Metro Bundler Cache
uses: actions/cache@v4
with:
path: ${{ steps.workflow-variables.outputs.metro-cache }}
key: ${{ runner.os }}-metro-v1-${{ github.run_id }}
restore-keys: ${{ runner.os }}-metro-v1
- name: Pre-fetch Javascript bundle
# Prebuild the bundle so that's fast when the app starts.
run: |
nohup sh -c "yarn tests_rn:packager > packager.log 2>&1 &"
printf 'Waiting for packager to come online'
until curl --output /dev/null --silent --head --fail http://localhost:8081/status; do
printf '.'
sleep 2
done
echo "Packager is online! Preparing javascript bundle..."
curl --output /dev/null --silent --head --fail "http://localhost:8081/index.bundle?platform=android&dev=true&minify=false&inlineSourceMap=true"
echo "...javascript bundle ready."
- name: Emulator Tests
uses: reactivecircus/android-emulator-runner@v2
timeout-minutes: 60
with:
api-level: ${{ matrix.api-level }}
avd-name: TestingAVD
target: ${{ matrix.target }}
arch: ${{ matrix.arch }}
pre-emulator-launch-script: |
sudo mkdir /mnt/avd
sudo chown $USER:$USER /mnt/avd
mkdir -p $HOME/.android
ln -s /mnt/avd $HOME/.android/avd
script: |
$ANDROID_HOME/platform-tools/adb devices
nohup sh -c "$ANDROID_HOME/platform-tools/adb logcat '*:D' > adb-log.txt" &
nohup sh -c 'adb shell "screenrecord /data/local/tmp/emulator1.mp4; screenrecord /data/local/tmp/emulator2.mp4; screenrecord /data/local/tmp/emulator3.mp4; screenrecord /data/local/tmp/emulator4.mp4" &'
yarn tests_rn:android:test || touch tests-failed.out # even on failure do not exit yet...
adb pull /data/local/tmp/emulator1.mp4 || true # ...because we want to download our videos...
adb pull /data/local/tmp/emulator2.mp4 || true # ...and we need the emulator up to fetch them
adb pull /data/local/tmp/emulator3.mp4 || true
adb pull /data/local/tmp/emulator4.mp4 || true
if test -e tests-failed.out; then exit 1; fi # now exit with error code if tests failed
- uses: codecov/codecov-action@v4
with:
verbose: true
- name: Upload Emulator Log
uses: actions/upload-artifact@v4
if: always()
with:
name: adb_logs
path: adb-log.txt
- name: Upload Packager Log
uses: actions/upload-artifact@v4
if: always()
with:
name: packager_log
path: packager.log
- name: Upload App Video
uses: actions/upload-artifact@v4
if: always()
with:
name: emulator_video
path: emulator*.mp4