@@ -265,7 +265,7 @@ if [ -z "$GRADLE_PROJECT_DIR" ]; then
265265 exit 1
266266fi
267267
268- # --- Inject Robolectric UI test into Gradle project ---
268+ # --- Inject instrumentation UI test into Gradle project ---
269269APP_MODULE_DIR=$( find " $GRADLE_PROJECT_DIR " -maxdepth 1 -type d -name " app" | head -n 1 || true)
270270if [ -z " $APP_MODULE_DIR " ]; then
271271 ba_log " Unable to locate Gradle app module inside $GRADLE_PROJECT_DIR " >&2
@@ -278,14 +278,14 @@ if [ ! -f "$UI_TEST_TEMPLATE" ]; then
278278 exit 1
279279fi
280280
281- UI_TEST_DIR=" $APP_MODULE_DIR /src/test /java/${PACKAGE_PATH} "
281+ UI_TEST_DIR=" $APP_MODULE_DIR /src/androidTest /java/${PACKAGE_PATH} "
282282mkdir -p " $UI_TEST_DIR "
283283UI_TEST_FILE=" $UI_TEST_DIR /${MAIN_NAME} UiTest.java"
284284
285285sed -e " s|@PACKAGE@|$PACKAGE_NAME |g" \
286286 -e " s|@MAIN_NAME@|$MAIN_NAME |g" \
287287 " $UI_TEST_TEMPLATE " > " $UI_TEST_FILE "
288- ba_log " Created Robolectric UI test at $UI_TEST_FILE "
288+ ba_log " Created instrumentation UI test at $UI_TEST_FILE "
289289
290290APP_BUILD_GRADLE=" $APP_MODULE_DIR /build.gradle"
291291if [ ! -f " $APP_BUILD_GRADLE " ]; then
295295
296296" $SCRIPT_DIR /update_android_ui_test_gradle.py" " $APP_BUILD_GRADLE "
297297
298- # Capture UI test screenshots in a deterministic directory
299- SCREENSHOT_OUTPUT_DIR=" $GRADLE_PROJECT_DIR /test-artifacts/screenshots"
300- rm -rf " $SCREENSHOT_OUTPUT_DIR "
301- mkdir -p " $SCREENSHOT_OUTPUT_DIR "
302- export CN1_TEST_SCREENSHOT_DIR=" $SCREENSHOT_OUTPUT_DIR "
303-
304298FINAL_ARTIFACT_DIR=" ${CN1_TEST_SCREENSHOT_EXPORT_DIR:- $REPO_ROOT / build-artifacts} "
305299mkdir -p " $FINAL_ARTIFACT_DIR "
306300if [ -n " ${GITHUB_ENV:- } " ]; then
@@ -311,24 +305,156 @@ ba_log "Invoking Gradle build in $GRADLE_PROJECT_DIR"
311305chmod +x " $GRADLE_PROJECT_DIR /gradlew"
312306ORIGINAL_JAVA_HOME=" $JAVA_HOME "
313307export JAVA_HOME=" $JAVA17_HOME "
314- if command -v sdkmanager > /dev/null 2>&1 ; then
315- yes | sdkmanager --licenses > /dev/null 2>&1 || true
316- elif [ -x " $ANDROID_SDK_ROOT /cmdline-tools/latest/bin/sdkmanager" ]; then
317- yes | " $ANDROID_SDK_ROOT /cmdline-tools/latest/bin/sdkmanager" --licenses > /dev/null 2>&1 || true
308+ export PATH=" $ANDROID_SDK_ROOT /platform-tools:$ANDROID_SDK_ROOT /emulator:$PATH "
309+
310+ SDKMANAGER_BIN=" "
311+ if [ -x " $ANDROID_SDK_ROOT /cmdline-tools/latest/bin/sdkmanager" ]; then
312+ SDKMANAGER_BIN=" $ANDROID_SDK_ROOT /cmdline-tools/latest/bin/sdkmanager"
313+ elif [ -x " $ANDROID_SDK_ROOT /cmdline-tools/bin/sdkmanager" ]; then
314+ SDKMANAGER_BIN=" $ANDROID_SDK_ROOT /cmdline-tools/bin/sdkmanager"
315+ elif command -v sdkmanager > /dev/null 2>&1 ; then
316+ SDKMANAGER_BIN=" $( command -v sdkmanager) "
317+ fi
318+
319+ AVDMANAGER_BIN=" "
320+ if [ -x " $ANDROID_SDK_ROOT /cmdline-tools/latest/bin/avdmanager" ]; then
321+ AVDMANAGER_BIN=" $ANDROID_SDK_ROOT /cmdline-tools/latest/bin/avdmanager"
322+ elif [ -x " $ANDROID_SDK_ROOT /cmdline-tools/bin/avdmanager" ]; then
323+ AVDMANAGER_BIN=" $ANDROID_SDK_ROOT /cmdline-tools/bin/avdmanager"
324+ elif command -v avdmanager > /dev/null 2>&1 ; then
325+ AVDMANAGER_BIN=" $( command -v avdmanager) "
326+ fi
327+
328+ ADB_BIN=" $ANDROID_SDK_ROOT /platform-tools/adb"
329+ if [ ! -x " $ADB_BIN " ]; then
330+ if command -v adb > /dev/null 2>&1 ; then
331+ ADB_BIN=" $( command -v adb) "
332+ else
333+ ba_log " adb not found in Android SDK. Ensure platform-tools are installed." >&2
334+ exit 1
335+ fi
336+ fi
337+
338+ EMULATOR_BIN=" $ANDROID_SDK_ROOT /emulator/emulator"
339+ if [ ! -x " $EMULATOR_BIN " ]; then
340+ if command -v emulator > /dev/null 2>&1 ; then
341+ EMULATOR_BIN=" $( command -v emulator) "
342+ else
343+ ba_log " Android emulator binary not found" >&2
344+ exit 1
345+ fi
346+ fi
347+
348+ install_android_packages () {
349+ local manager=" $1 "
350+ if [ -z " $manager " ]; then
351+ ba_log " sdkmanager not available; cannot install system images" >&2
352+ exit 1
353+ fi
354+ yes | " $manager " --licenses > /dev/null 2>&1 || true
355+ " $manager " --install " platform-tools" " platforms;android-33" " system-images;android-33;google_apis;x86_64" > /dev/null 2>&1 || true
356+ }
357+
358+ create_avd () {
359+ local manager=" $1 "
360+ local name=" $2 "
361+ local image=" $3 "
362+ local avd_dir=" $4 "
363+ if [ -z " $manager " ]; then
364+ ba_log " avdmanager not available; cannot create emulator" >&2
365+ exit 1
366+ fi
367+ rm -rf " $avd_dir "
368+ mkdir -p " $avd_dir "
369+ ANDROID_AVD_HOME=" $avd_dir " \
370+ printf ' no\n' | " $manager " create avd -n " $name " -k " $image " --device " pixel_6" --force > /dev/null
371+ }
372+
373+ wait_for_emulator () {
374+ local serial=" $1 "
375+ " $ADB_BIN " start-server > /dev/null
376+ " $ADB_BIN " -s " $serial " wait-for-device
377+ local booted=" 0"
378+ for _ in $( seq 1 120) ; do
379+ booted=" $( $ADB_BIN -s " $serial " shell getprop sys.boot_completed 2> /dev/null | tr -d ' \r' ) "
380+ if [ " $booted " = " 1" ]; then
381+ break
382+ fi
383+ sleep 2
384+ done
385+ if [ " $booted " != " 1" ]; then
386+ ba_log " Emulator $serial failed to boot within expected time" >&2
387+ return 1
388+ fi
389+ " $ADB_BIN " -s " $serial " shell settings put global window_animation_scale 0 > /dev/null 2>&1 || true
390+ " $ADB_BIN " -s " $serial " shell settings put global transition_animation_scale 0 > /dev/null 2>&1 || true
391+ " $ADB_BIN " -s " $serial " shell settings put global animator_duration_scale 0 > /dev/null 2>&1 || true
392+ " $ADB_BIN " -s " $serial " shell input keyevent 82 > /dev/null 2>&1 || true
393+ return 0
394+ }
395+
396+ get_emulator_serial () {
397+ " $ADB_BIN " devices | awk ' /emulator-/{print $1; exit}'
398+ }
399+
400+ stop_emulator () {
401+ if [ -n " ${EMULATOR_SERIAL:- } " ]; then
402+ " $ADB_BIN " -s " $EMULATOR_SERIAL " emu kill > /dev/null 2>&1 || true
403+ fi
404+ if [ -n " ${EMULATOR_PID:- } " ]; then
405+ kill " $EMULATOR_PID " > /dev/null 2>&1 || true
406+ wait " $EMULATOR_PID " 2> /dev/null || true
407+ fi
408+ }
409+
410+ install_android_packages " $SDKMANAGER_BIN "
411+
412+ AVD_NAME=" cn1UiTestAvd"
413+ SYSTEM_IMAGE=" system-images;android-33;google_apis;x86_64"
414+ AVD_HOME=" $WORK_DIR /android-avd"
415+ create_avd " $AVDMANAGER_BIN " " $AVD_NAME " " $SYSTEM_IMAGE " " $AVD_HOME "
416+
417+ ANDROID_AVD_HOME=" $AVD_HOME " " $ADB_BIN " start-server > /dev/null
418+
419+ EMULATOR_LOG=" $GRADLE_PROJECT_DIR /emulator.log"
420+ ba_log " Starting headless Android emulator $AVD_NAME "
421+ ANDROID_AVD_HOME=" $AVD_HOME " " $EMULATOR_BIN " -avd " $AVD_NAME " -no-window -no-snapshot -gpu swiftshader_indirect -no-audio -no-boot-anim -accel off > " $EMULATOR_LOG " 2>&1 &
422+ EMULATOR_PID=$!
423+ trap stop_emulator EXIT
424+
425+ sleep 5
426+ EMULATOR_SERIAL=" "
427+ for _ in $( seq 1 30) ; do
428+ EMULATOR_SERIAL=" $( get_emulator_serial) "
429+ if [ -n " $EMULATOR_SERIAL " ]; then
430+ break
431+ fi
432+ sleep 2
433+ done
434+ if [ -z " $EMULATOR_SERIAL " ]; then
435+ ba_log " Failed to determine emulator serial" >&2
436+ stop_emulator
437+ exit 1
438+ fi
439+ ba_log " Using emulator serial $EMULATOR_SERIAL "
440+
441+ if ! wait_for_emulator " $EMULATOR_SERIAL " ; then
442+ stop_emulator
443+ exit 1
318444fi
319445
320- UI_TEST_TIMEOUT_SECONDS=" ${UI_TEST_TIMEOUT_SECONDS:- 600 } "
446+ UI_TEST_TIMEOUT_SECONDS=" ${UI_TEST_TIMEOUT_SECONDS:- 900 } "
321447if ! [[ " $UI_TEST_TIMEOUT_SECONDS " =~ ^[0-9]+$ ]] || [ " $UI_TEST_TIMEOUT_SECONDS " -le 0 ]; then
322- ba_log " Invalid UI_TEST_TIMEOUT_SECONDS=$UI_TEST_TIMEOUT_SECONDS provided; falling back to 600 "
323- UI_TEST_TIMEOUT_SECONDS=600
448+ ba_log " Invalid UI_TEST_TIMEOUT_SECONDS=$UI_TEST_TIMEOUT_SECONDS provided; falling back to 900 "
449+ UI_TEST_TIMEOUT_SECONDS=900
324450fi
325451
326- GRADLE_TEST_CMD=(" ./gradlew" " --no-daemon" " test " )
452+ GRADLE_TEST_CMD=(" ./gradlew" " --no-daemon" " connectedDebugAndroidTest " )
327453if command -v timeout > /dev/null 2>&1 ; then
328- ba_log " Running Gradle UI tests with external timeout of ${UI_TEST_TIMEOUT_SECONDS} s"
454+ ba_log " Running instrumentation UI tests with external timeout of ${UI_TEST_TIMEOUT_SECONDS} s"
329455 GRADLE_TEST_CMD=(" timeout" " $UI_TEST_TIMEOUT_SECONDS " " ${GRADLE_TEST_CMD[@]} " )
330456else
331- ba_log " timeout command not found; running Gradle UI tests without external watchdog"
457+ ba_log " timeout command not found; running instrumentation tests without external watchdog"
332458fi
333459
334460GRADLE_UI_TEST_LOG=" $GRADLE_PROJECT_DIR /gradle-ui-test.log"
@@ -349,9 +475,82 @@ if [ -f "$GRADLE_UI_TEST_LOG" ]; then
349475fi
350476
351477if [ " $TEST_EXIT_CODE " -eq 124 ]; then
352- ba_log " Gradle UI tests exceeded ${UI_TEST_TIMEOUT_SECONDS} s timeout and were terminated"
478+ ba_log " Instrumentation tests exceeded ${UI_TEST_TIMEOUT_SECONDS} s timeout and were terminated"
353479elif [ " $TEST_EXIT_CODE " -ne 0 ]; then
354- ba_log " Gradle UI tests exited with status $TEST_EXIT_CODE "
480+ ba_log " Instrumentation tests exited with status $TEST_EXIT_CODE "
481+ fi
482+
483+ copy_device_file () {
484+ local src=" $1 "
485+ local dest=" $2 "
486+ if ! " $ADB_BIN " -s " $EMULATOR_SERIAL " shell run-as " $PACKAGE_NAME " ls " $src " > /dev/null 2>&1 ; then
487+ return 1
488+ fi
489+ if " $ADB_BIN " -s " $EMULATOR_SERIAL " exec-out run-as " $PACKAGE_NAME " cat " $src " > " $dest " ; then
490+ return 0
491+ fi
492+ rm -f " $dest "
493+ return 1
494+ }
495+
496+ SCREENSHOT_STATUS=0
497+ ANDROID_SCREENSHOT=" "
498+ CODENAMEONE_SCREENSHOT=" "
499+ DEFAULT_SCREENSHOT=" "
500+
501+ SCREENSHOT_DIR_ON_DEVICE=" files/ui-test-screenshots"
502+ ANDROID_SCREENSHOT_NAME=" ${MAIN_NAME} -android-ui.png"
503+ CODENAMEONE_SCREENSHOT_NAME=" ${MAIN_NAME} -codenameone-ui.png"
504+
505+ ANDROID_SCREENSHOT_PATH_DEVICE=" $SCREENSHOT_DIR_ON_DEVICE /$ANDROID_SCREENSHOT_NAME "
506+ CODENAMEONE_SCREENSHOT_PATH_DEVICE=" $SCREENSHOT_DIR_ON_DEVICE /$CODENAMEONE_SCREENSHOT_NAME "
507+
508+ ANDROID_SCREENSHOT_DEST=" $FINAL_ARTIFACT_DIR /$ANDROID_SCREENSHOT_NAME "
509+ CODENAMEONE_SCREENSHOT_DEST=" $FINAL_ARTIFACT_DIR /$CODENAMEONE_SCREENSHOT_NAME "
510+
511+ if copy_device_file " $ANDROID_SCREENSHOT_PATH_DEVICE " " $ANDROID_SCREENSHOT_DEST " ; then
512+ ba_log " Android screenshot copied to $ANDROID_SCREENSHOT_DEST "
513+ ANDROID_SCREENSHOT=" $ANDROID_SCREENSHOT_DEST "
514+ DEFAULT_SCREENSHOT=" $ANDROID_SCREENSHOT_DEST "
515+ else
516+ ba_log " Android screenshot not found at $ANDROID_SCREENSHOT_PATH_DEVICE " >&2
517+ SCREENSHOT_STATUS=1
518+ fi
519+
520+ if copy_device_file " $CODENAMEONE_SCREENSHOT_PATH_DEVICE " " $CODENAMEONE_SCREENSHOT_DEST " ; then
521+ ba_log " Codename One screenshot copied to $CODENAMEONE_SCREENSHOT_DEST "
522+ CODENAMEONE_SCREENSHOT=" $CODENAMEONE_SCREENSHOT_DEST "
523+ if [ -z " $DEFAULT_SCREENSHOT " ]; then
524+ DEFAULT_SCREENSHOT=" $CODENAMEONE_SCREENSHOT_DEST "
525+ fi
526+ else
527+ ba_log " Codename One screenshot not found at $CODENAMEONE_SCREENSHOT_PATH_DEVICE " >&2
528+ SCREENSHOT_STATUS=1
529+ fi
530+
531+ if [ -f " $EMULATOR_LOG " ]; then
532+ cp " $EMULATOR_LOG " " $FINAL_ARTIFACT_DIR /emulator.log" || true
533+ fi
534+
535+ TEST_RESULT_DIR=" $APP_MODULE_DIR /build/outputs/androidTest-results/connected"
536+ if [ -d " $TEST_RESULT_DIR " ]; then
537+ RESULT_DEST=" $FINAL_ARTIFACT_DIR /androidTest-results"
538+ rm -rf " $RESULT_DEST "
539+ mkdir -p " $RESULT_DEST "
540+ cp -R " $TEST_RESULT_DIR /." " $RESULT_DEST /"
541+ ba_log " Android test results copied to $RESULT_DEST "
542+ fi
543+
544+ if [ -n " ${GITHUB_ENV:- } " ]; then
545+ if [ -n " $DEFAULT_SCREENSHOT " ]; then
546+ printf ' CN1_UI_TEST_SCREENSHOT=%s\n' " $DEFAULT_SCREENSHOT " >> " $GITHUB_ENV "
547+ fi
548+ if [ -n " $ANDROID_SCREENSHOT " ]; then
549+ printf ' CN1_UI_TEST_ANDROID_SCREENSHOT=%s\n' " $ANDROID_SCREENSHOT " >> " $GITHUB_ENV "
550+ fi
551+ if [ -n " $CODENAMEONE_SCREENSHOT " ]; then
552+ printf ' CN1_UI_TEST_CODENAMEONE_SCREENSHOT=%s\n' " $CODENAMEONE_SCREENSHOT " >> " $GITHUB_ENV "
553+ fi
355554fi
356555
357556if [ " $TEST_EXIT_CODE " -eq 0 ]; then
@@ -360,55 +559,13 @@ if [ "$TEST_EXIT_CODE" -eq 0 ]; then
360559 ./gradlew --no-daemon assembleDebug
361560 )
362561else
363- ba_log " UI tests failed (exit code $TEST_EXIT_CODE ); skipping assembleDebug"
562+ ba_log " Instrumentation tests failed (exit code $TEST_EXIT_CODE ); skipping assembleDebug"
364563fi
564+
365565export JAVA_HOME=" $ORIGINAL_JAVA_HOME "
366566
367- readarray -t SCREENSHOT_FILES < <( find " $SCREENSHOT_OUTPUT_DIR " -maxdepth 1 -type f -name ' *.png' -print | sort)
368- SCREENSHOT_STATUS=0
369- if [ " ${# SCREENSHOT_FILES[@]} " -eq 0 ]; then
370- ba_log " UI test completed but no screenshot was produced in $SCREENSHOT_OUTPUT_DIR " >&2
371- SCREENSHOT_STATUS=1
372- else
373- DEFAULT_SCREENSHOT=" "
374- ANDROID_SCREENSHOT=" "
375- CODENAMEONE_SCREENSHOT=" "
376- for src in " ${SCREENSHOT_FILES[@]} " ; do
377- base=$( basename " $src " )
378- dest=" $FINAL_ARTIFACT_DIR /$base "
379- cp " $src " " $dest "
380- label=" UI test"
381- case " $base " in
382- * -android-* .png)
383- ANDROID_SCREENSHOT=" $dest "
384- label=" Android"
385- ;;
386- * -codenameone-* .png)
387- CODENAMEONE_SCREENSHOT=" $dest "
388- label=" Codename One"
389- ;;
390- esac
391- if [ -z " $DEFAULT_SCREENSHOT " ]; then
392- DEFAULT_SCREENSHOT=" $dest "
393- fi
394- ba_log " $label screenshot copied to $dest "
395- done
396- if [ -n " $ANDROID_SCREENSHOT " ]; then
397- DEFAULT_SCREENSHOT=" $ANDROID_SCREENSHOT "
398- fi
399- if [ -n " ${GITHUB_ENV:- } " ]; then
400- if [ -n " $DEFAULT_SCREENSHOT " ]; then
401- printf ' CN1_UI_TEST_SCREENSHOT=%s\n' " $DEFAULT_SCREENSHOT " >> " $GITHUB_ENV "
402- fi
403- if [ -n " $ANDROID_SCREENSHOT " ]; then
404- printf ' CN1_UI_TEST_ANDROID_SCREENSHOT=%s\n' " $ANDROID_SCREENSHOT " >> " $GITHUB_ENV "
405- fi
406- if [ -n " $CODENAMEONE_SCREENSHOT " ]; then
407- printf ' CN1_UI_TEST_CODENAMEONE_SCREENSHOT=%s\n' " $CODENAMEONE_SCREENSHOT " >> " $GITHUB_ENV "
408- fi
409- fi
410- fi
411- unset CN1_TEST_SCREENSHOT_DIR
567+ stop_emulator
568+ trap - EXIT
412569
413570if [ " $TEST_EXIT_CODE " -ne 0 ]; then
414571 exit " $TEST_EXIT_CODE "
0 commit comments