Skip to content
Merged
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
29 changes: 29 additions & 0 deletions .github/actions/android-sdk-packages/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
name: Android SDK packages
description: >-
Installs the SDK packages reactivecircus/android-emulator-runner would download, with retries.
The action downloads the emulator and the system image on every run and doesn't retry: a
corrupted download ("Error reading Zip content from a SeekableByteChannel") fails the job before
the emulator boots. sdkmanager skips packages that are installed and current, so the action's own
install becomes a no-op.
inputs:
api-level:
description: The system image API level, as passed to android-emulator-runner
required: true
runs:
using: composite
steps:
- name: Install the emulator and the system image
shell: bash
env:
API_LEVEL: ${{ inputs.api-level }}
run: |
sdkmanager="$ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager"
packages=(emulator platform-tools "platforms;android-$API_LEVEL" "system-images;android-$API_LEVEL;default;x86_64")
yes | "$sdkmanager" --licenses > /dev/null || true
for attempt in 1 2 3; do
"$sdkmanager" --install "${packages[@]}" --channel=0 > /dev/null && exit 0
echo "::warning::sdkmanager failed (attempt $attempt of 3); retrying in 30 s"
sleep 30
done
echo "::error::Could not install ${packages[*]}"
exit 1
10 changes: 9 additions & 1 deletion .github/workflows/e2e-test-cron.yml
Original file line number Diff line number Diff line change
Expand Up @@ -352,6 +352,10 @@ jobs:
working-directory: examples/SampleApp
run: bundle exec fastlane allure_launch cron:true
continue-on-error: true
# The emulator runner downloads these without retrying; a corrupted download fails the job.
- uses: ./.github/actions/android-sdk-packages
with:
api-level: ${{ matrix.api-level }}
- name: Run e2e tests (Android emulator)
id: tests
uses: reactivecircus/android-emulator-runner@v2
Expand All @@ -362,7 +366,10 @@ jobs:
emulator-options: ${{ env.ANDROID_EMULATOR_OPTIONS }}
disable-animations: true
working-directory: examples/SampleApp
script: bundle exec fastlane test_e2e platform:android device:att skip_build:true mock_server_branch:"$MOCK_SERVER_BRANCH" coverage:${{ matrix.coverage == true }} batch:${{ matrix.batch }} batch_count:${{ matrix.batch_count }}
# Logcat is written on the runner, so it survives the emulator dying mid-run (RN-513).
script: |
nohup "$ANDROID_HOME/platform-tools/adb" -s emulator-5554 logcat -b all -v threadtime > "$RUNNER_TEMP/logcat.txt" 2>&1 < /dev/null &
bundle exec fastlane test_e2e platform:android device:att skip_build:true mock_server_branch:"$MOCK_SERVER_BRANCH" coverage:${{ matrix.coverage == true }} batch:${{ matrix.batch }} batch_count:${{ matrix.batch_count }}

# Also when tests failed: those keep their coverage from the previous map. Not when they never
# ran: a batch without its failed-tests file keeps the whole previous map.
Expand Down Expand Up @@ -407,6 +414,7 @@ jobs:
examples/E2ETestApp/stream-chat-test-mock-server/logs
examples/E2ETestApp/artifacts
/tmp/android-runner
${{ runner.temp }}/logcat.txt

coverage_map:
name: Build e2e coverage map
Expand Down
4 changes: 4 additions & 0 deletions .github/workflows/e2e-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,10 @@ jobs:
with:
name: e2e-selection
path: examples/E2ETestApp
# The emulator runner downloads these without retrying; a corrupted download fails the job.
- uses: ./.github/actions/android-sdk-packages
with:
api-level: ${{ env.ANDROID_API_LEVEL }}
- name: Run e2e tests (Android emulator)
uses: reactivecircus/android-emulator-runner@v2
with:
Expand Down
13 changes: 5 additions & 8 deletions examples/E2ETestApp/e2e/robots/UserRobot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,10 @@ const tapInContextMenu = async (selector: Detox.NativeMatcher) => {
};

/**
* Long-presses a message until its menu opens. iOS runs without Detox's idle sync, so a long press
* that lands while the list is still settling after a scroll is cancelled by the movement, and the
* menu never opens. `target` is re-resolved on each attempt, since the frames may have moved.
* Long-presses a message until its menu opens. A long press that lands while the list is still
* settling after a scroll is cancelled by the movement, and the menu never opens: on iOS, which runs
* without Detox's idle sync, and now and then on Android too. `target` is re-resolved on each
* attempt, since the frames may have moved.
*/
const longPressUntilMenuOpens = async (
target: () => Promise<{ index: number; selector: Detox.NativeMatcher }>,
Expand All @@ -68,11 +69,7 @@ const longPressUntilMenuOpens = async (
for (let attempt = 1; ; attempt++) {
const { index, selector } = await target();
await waitToAppearAndLongPress(selector, { index });
if (
device.getPlatform() !== 'ios' ||
attempt >= attempts ||
(await waitForExistence(ContextMenu.backdrop, { timeout: 3000 }))
) {
if (attempt >= attempts || (await waitForExistence(ContextMenu.backdrop, { timeout: 3000 }))) {
return;
}
}
Expand Down
Loading