Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/actions/build-android/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ runs:
run: |
if [[ "${{ inputs.release-type }}" == "dry-run" ]]; then
# dry-run: we only build ARM64 to save time/resources. For release/nightlies the default is to build all archs.
export ORG_GRADLE_PROJECT_reactNativeArchitectures="arm64-v8a"
export ORG_GRADLE_PROJECT_reactNativeArchitectures="arm64-v8a,x86" # x86 is required for E2E testing
TASKS="publishAllToMavenTempLocal build"
elif [[ "${{ inputs.release-type }}" == "nightly" ]]; then
# nightly: we set isSnapshot to true so artifacts are sent to the right repository on Maven Central.
Expand Down
70 changes: 70 additions & 0 deletions .github/actions/maestro-android/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
name: Maestro E2E Android
description: Runs E2E Tests on iOS using Maestro
inputs:
app-path:
required: true
description: The path to the .apk file
app-id:
required: true
description: The id of the app to test
jsengine:
required: true
description: The js engine we are using
maestro-flow:
required: true
description: the folder that contains the maestro tests
install-java:
required: false
default: 'true'
description: whether this action has to install java 17 or not
runs:
using: composite
steps:
- name: Installing Maestro
shell: bash
run: curl -Ls "https://get.maestro.mobile.dev" | bash
- name: Set up JDK 17
if: ${{ inputs.install-java == 'true' }}
uses: actions/setup-java@v2
with:
java-version: '17'
distribution: 'zulu'
- name: Enable KVM group perms
shell: bash
run: |
# ubuntu machines have hardware acceleration available and when we try to create an emulator, the script pauses asking for user input
# These lines set the rules to reply automatically to that question and unblock the creation of the emulator.
# source: https://github.com/ReactiveCircus/android-emulator-runner?tab=readme-ov-file#running-hardware-accelerated-emulators-on-linux-runners
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
- name: Run e2e tests
uses: reactivecircus/android-emulator-runner@v2
with:
api-level: 24
arch: x86
script: |
echo "Install APK from ${{ inputs.app-path }}"
adb install "${{ inputs.app-path }}"

echo "Start recording to /sdcard/screen.mp4"
adb shell screenrecord /sdcard/screen.mp4

echo "Start testing ${{ inputs.maestro-flow }}"
$HOME/.maestro/bin/maestro test ${{ inputs.maestro-flow }} --format junit -e APP_ID=${{ inputs.app-id }} --debug-output /tmp/MaestroLogs

echo "Stop recording. Saving to screen.mp4"
adb pull /sdcard/screen.mp4
- name: Store tests result
uses: actions/upload-artifact@v3
with:
name: e2e_android_${{ inputs.app-id }}_report_${{ inputs.jsengine }}
path: |
report.xml
screen.mp4
- name: Store Logs
if: failure() && steps.run-tests.outcome == 'failure'
uses: actions/upload-artifact@v4
with:
name: maestro-logs-android-${{ inputs.app-id }}-${{ inputs.jsengine }}
path: /tmp/MaestroLogs
96 changes: 96 additions & 0 deletions .github/actions/maestro-ios/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
name: Maestro E2E iOS
description: Runs E2E Tests on iOS using Maestro
inputs:
app-path:
required: true
description: The path to the .app file
app-id:
required: true
description: The id of the app to test
jsengine:
required: true
description: The js engine we are using
maestro-flow:
required: true
description: the folder that contains the maestro tests
runs:
using: composite
steps:
- name: Installing Maestro
shell: bash
run: curl -Ls "https://get.maestro.mobile.dev" | bash
- name: Installing Maestro dependencies
shell: bash
run: |
brew tap facebook/fb
brew install facebook/fb/idb-companion jq
- name: Set up JDK 11
uses: actions/setup-java@v2
with:
java-version: '17'
distribution: 'zulu'
- name: Run tests
id: run-tests
shell: bash
run: |
# Avoid exit from the job if one of the command returns an error.
# Maestro can fail in case of flakyness, we have some retry logic.
set +e

echo "Launching iOS Simulator: iPhone 15 Pro"
xcrun simctl boot "iPhone 15 Pro"

echo "Installing app on Simulator"
xcrun simctl install booted "${{ inputs.app-path }}"

echo "Retrieving device UDID"
UDID=$(xcrun simctl list devices booted -j | jq -r '[.devices[]] | add | first | .udid')
echo "UDID is $UDID"

echo "Bring simulator in foreground"
open -a simulator

echo "Launch the app"
xcrun simctl launch $UDID ${{ inputs.app-id }}

echo "Running tests with Maestro"
export MAESTRO_DRIVER_STARTUP_TIMEOUT=1500000 # 25 min. CI is extremely slow

# Add retries for flakyness
MAX_ATTEMPTS=3
CURR_ATTEMPT=0
RESULT=1

while [[ $CURR_ATTEMPT -lt $MAX_ATTEMPTS ]] && [[ $RESULT -ne 0 ]]; do
CURR_ATTEMPT=$((CURR_ATTEMPT+1))
echo "Attempt number $CURR_ATTEMPT"

echo "Start video record using pid: video_record_${{ inputs.jsengine }}_$CURR_ATTEMPT.pid"
xcrun simctl io booted recordVideo video_record_$CURR_ATTEMPT.mov & echo $! > video_record_${{ inputs.jsengine }}_$CURR_ATTEMPT.pid

echo '$HOME/.maestro/bin/maestro --udid=$UDID test ${{ inputs.maestro-flow }} --format junit -e APP_ID=${{ inputs.app-id }}'
$HOME/.maestro/bin/maestro --udid=$UDID test ${{ inputs.maestro-flow }} --format junit -e APP_ID=${{ inputs.app-id }} --debug-output /tmp/MaestroLogs

RESULT=$?

# Stop video
kill -SIGINT $(cat video_record_${{ inputs.jsengine }}_$CURR_ATTEMPT.pid)
done

exit $RESULT
- name: Store video record
if: always()
uses: actions/upload-artifact@v4
with:
name: e2e_ios_${{ inputs.app-id }}_report_${{ inputs.jsengine }}
path: |
video_record_1.mov
video_record_2.mov
video_record_3.mov
report.xml
- name: Store Logs
if: failure() && steps.run-tests.outcome == 'failure'
uses: actions/upload-artifact@v4
with:
name: maestro-logs-${{ inputs.app-id }}-${{ inputs.jsengine }}
path: /tmp/MaestroLogs
21 changes: 20 additions & 1 deletion .github/actions/test-ios-rntester/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ inputs:
react-native-version:
description: The version of react-native
required: true
run-e2e-tests:
description: Whether we want to run E2E tests or not
required: false
default: false

runs:
using: composite
Expand Down Expand Up @@ -114,17 +118,32 @@ runs:
bundle install
bundle exec pod install
- name: Build RNTester
if: ${{ inputs.run-unit-tests != 'true' }}
if: ${{ inputs.run-unit-tests != 'true' && inputs.run-e2e-tests == 'false' }}
shell: bash
run: |
xcodebuild build \
-workspace packages/rn-tester/RNTesterPods.xcworkspace \
-scheme RNTester \
-sdk iphonesimulator
- name: Build RNTester (E2E Tests)
shell: bash
if: ${{ inputs.run-e2e-tests == 'true' }}
run: |
xcrun xcodebuild \
-scheme "RNTester" \
-workspace packages/rn-tester/RNTesterPods.xcworkspace \
-configuration "Release" \
-sdk "iphonesimulator" \
-destination "generic/platform=iOS Simulator" \
-derivedDataPath "/tmp/RNTesterBuild"

echo "Print path to *.app file"
find "/tmp/RNTesterBuild" -type d -name "*.app"
- name: "Run Tests: iOS Unit and Integration Tests"
if: ${{ inputs.run-unit-tests == 'true' }}
shell: bash
run: yarn test-ios

- name: Zip Derived data folder
if: ${{ inputs.run-unit-tests == 'true' }}
shell: bash
Expand Down
63 changes: 63 additions & 0 deletions .github/workflows/test-all.yml
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,40 @@ jobs:
hermes-version: ${{ needs.prepare_hermes_workspace.outputs.hermes-version }}
react-native-version: ${{ needs.prepare_hermes_workspace.outputs.react-native-version }}

test_e2e_ios_rntester:
runs-on: macos-13
needs:
[build_apple_slices_hermes, prepare_hermes_workspace, build_hermes_macos]
env:
HERMES_WS_DIR: /tmp/hermes
HERMES_TARBALL_ARTIFACTS_DIR: /tmp/hermes/hermes-runtime-darwin
continue-on-error: true
strategy:
fail-fast: false
matrix:
jsengine: [Hermes, JSC]
architecture: [NewArch]
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Run it
uses: ./.github/actions/test-ios-rntester
with:
jsengine: ${{ matrix.jsengine }}
architecture: ${{ matrix.architecture }}
run-unit-tests: "false"
use-frameworks: StaticLibraries
hermes-version: ${{ needs.prepare_hermes_workspace.outputs.hermes-version }}
react-native-version: ${{ needs.prepare_hermes_workspace.outputs.react-native-version }}
run-e2e-tests: "true"
- name: Run E2E Tests
uses: ./.github/actions/maestro-ios
with:
app-path: "/tmp/RNTesterBuild/Build/Products/Release-iphonesimulator/RNTester.app"
app-id: com.meta.RNTester.localDevelopment
jsengine: ${{ matrix.jsengine }}
maestro-flow: ./packages/rn-tester/.maestro/

build_hermesc_linux:
runs-on: ubuntu-latest
needs: prepare_hermes_workspace
Expand Down Expand Up @@ -231,6 +265,35 @@ jobs:
with:
release-type: ${{ needs.set_release_type.outputs.RELEASE_TYPE }}

test_e2e_android_rntester:
runs-on: ubuntu-latest
needs: [build_android]
strategy:
fail-fast: false
matrix:
jsengine: [hermes, jsc]
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup node.js
uses: ./.github/actions/setup-node
- name: Install node dependencies
uses: ./.github/actions/yarn-install-with-cache
- name: Download APK
uses: actions/download-artifact@v4
with:
name: rntester-${{ matrix.jsengine }}-release
path: ./packages/rn-tester/android/app/build/outputs/apk/${{ matrix.jsengine }}/release/
- name: Print folder structure
run: ls -lR ./packages/rn-tester/android/app/build/outputs/apk/${{ matrix.jsengine }}/release/
- name: Run E2E Tests
uses: ./.github/actions/maestro-android
with:
app-path: ./packages/rn-tester/android/app/build/outputs/apk/${{ matrix.jsengine }}/release/app-${{ matrix.jsengine }}-x86-release.apk
app-id: com.facebook.react.uiapp
jsengine: ${{ matrix.jsengine }}
maestro-flow: ./packages/rn-tester/.maestro/

build_npm_package:
runs-on: 8-core-ubuntu
needs:
Expand Down
11 changes: 11 additions & 0 deletions packages/rn-tester/.maestro/start.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
appId: ${APP_ID} # iOS: com.meta.RNTester.localDevelopment | Android: com.facebook.react.uiapp
---
- launchApp
- assertVisible: "Components"
- scrollUntilVisible:
element:
id: "Modal"
direction: DOWN
speed: 60
- tapOn:
id: "Modal"
4 changes: 4 additions & 0 deletions scripts/e2e/.maestro/start.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
appId: ${APP_ID} # iOS: org.reactjs.native.example.RNTestProject | Android: com.rntestproject
---
- launchApp
- assertVisible: "Step One"