diff --git a/.circleci/config.yml b/.circleci/config.yml index d921cc1a..b84cfb92 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -9,7 +9,7 @@ commands: - restore_cache: key: v1-gradle-wrapper-{{ arch }}-{{ checksum "gradle/wrapper/gradle-wrapper.properties" }} - restore_cache: - key: v1-gradle-cache-{{ arch }}-{{ checksum "build.gradle.kts" }}-{{ checksum "settings.gradle.kts" }}-{{ checksum "gradle.properties" }}-{{ checksum "app/build.gradle.kts" }} + key: v1-gradle-cache-{{ arch }}-{{ checksum "build.gradle.kts" }}-{{ checksum "settings.gradle.kts" }}-{{ checksum "gradle.properties" }}-{{ checksum "app/build.gradle.kts" }}-{{ checksum "gradle/libs.versions.toml" }} restore_bundler_cache: steps: - restore_cache: @@ -24,7 +24,7 @@ commands: - save_cache: paths: - ~/.gradle/caches - key: v1-gradle-cache-{{ arch }}-{{ checksum "build.gradle.kts" }}-{{ checksum "settings.gradle.kts" }}-{{ checksum "gradle.properties" }}-{{ checksum "app/build.gradle.kts" }} + key: v1-gradle-cache-{{ arch }}-{{ checksum "build.gradle.kts" }}-{{ checksum "settings.gradle.kts" }}-{{ checksum "gradle.properties" }}-{{ checksum "app/build.gradle.kts" }}-{{ checksum "gradle/libs.versions.toml" }} save_bundler_cache: steps: - save_cache: diff --git a/.github/workflows/android.yml b/.github/workflows/android.yml index fc47e197..f5e1de88 100644 --- a/.github/workflows/android.yml +++ b/.github/workflows/android.yml @@ -126,7 +126,7 @@ jobs: script: | adb shell screenrecord /sdcard/ui-test.mp4 & SCREENRECORD_PID=$! - ./gradlew connectedCheck || true + ./gradlew connectedCheck kill $SCREENRECORD_PID || true adb pull /sdcard/ui-test.mp4 ./ui-test.mp4 || true - name: Upload UI test video diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 5efd8972..e8f0f0e3 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -114,7 +114,6 @@ tasks.register("jacocoTestReport") { "**/R.class", "**/R$*.class", "**/BuildConfig.*", "**/Manifest*.*", "**/*Test*.*", "android/**/*.*", "**/Dagger*.*", "**/*_Hilt*.*", "**/*Hilt*.*", - "**/ui/**" // Exclude UI files from coverage ) val javaDebugTree = fileTree(layout.buildDirectory.dir("intermediates/javac/debug/classes")) { exclude(fileFilter) } val kotlinDebugTree = fileTree(layout.buildDirectory.dir("tmp/kotlin-classes/debug")) { exclude(fileFilter) } diff --git a/app/src/androidTest/java/org/kabiri/android/usbterminal/MainActivityAndroidTest.kt b/app/src/androidTest/java/org/kabiri/android/usbterminal/MainActivityAndroidTest.kt index 9ef1a98c..bda96883 100644 --- a/app/src/androidTest/java/org/kabiri/android/usbterminal/MainActivityAndroidTest.kt +++ b/app/src/androidTest/java/org/kabiri/android/usbterminal/MainActivityAndroidTest.kt @@ -3,13 +3,14 @@ package org.kabiri.android.usbterminal import androidx.test.espresso.Espresso.onView import androidx.test.espresso.Espresso.openActionBarOverflowOrOptionsMenu import androidx.test.espresso.NoMatchingViewException -import androidx.test.espresso.assertion.ViewAssertions.matches import androidx.test.espresso.action.ViewActions.click +import androidx.test.espresso.assertion.ViewAssertions.matches import androidx.test.espresso.matcher.ViewMatchers.isDisplayed import androidx.test.espresso.matcher.ViewMatchers.withId +import androidx.test.espresso.matcher.ViewMatchers.withText import androidx.test.ext.junit.rules.activityScenarioRule import androidx.test.ext.junit.runners.AndroidJUnit4 -import androidx.test.platform.app.InstrumentationRegistry +import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith @@ -21,15 +22,19 @@ internal class MainActivityAndroidTest { @get:Rule var rule = activityScenarioRule() - private fun ensureMenuIsAccessible(menuItemId: Int) { + private fun ensureMenuIsAccessible( + menuItemId: Int, + onVisible: () -> Unit, + onOverflow: () -> Unit + ) { try { // Try to find the menu item first onView(withId(menuItemId)).check(matches(isDisplayed())) + onVisible() } catch (_: NoMatchingViewException) { // If not found then open the overflow menu - openActionBarOverflowOrOptionsMenu( - InstrumentationRegistry.getInstrumentation().targetContext - ) + openActionBarOverflowOrOptionsMenu(getInstrumentation().targetContext) + onOverflow() } } @@ -44,31 +49,70 @@ internal class MainActivityAndroidTest { } @Test - fun checkActionMenuItemsAreDisplayed() { - // arrange - // act - // Ensure action items are accessible, either in the toolbar or via overflow - ensureMenuIsAccessible(R.id.actionSettings) - ensureMenuIsAccessible(R.id.actionConnect) - ensureMenuIsAccessible(R.id.actionDisconnect) + fun checkActionMenuItemSettingsIsDisplayed() = ensureMenuIsAccessible( + menuItemId = R.id.actionSettings, + onVisible = { - // assert - // Check menu items are displayed - onView(withId(R.id.actionSettings)).check(matches(isDisplayed())) - onView(withId(R.id.actionConnect)).check(matches(isDisplayed())) - onView(withId(R.id.actionDisconnect)).check(matches(isDisplayed())) - } + // assert + onView(withId(R.id.actionSettings)).check(matches(isDisplayed())) + }, + onOverflow = { + + // assert + onView(withText(R.string.title_settings)).check(matches(isDisplayed())) + } + ) + + @Test + fun checkActionMenuItemConnectIsDisplayed() = ensureMenuIsAccessible( + menuItemId = R.id.actionSettings, + onVisible = { + + // assert + onView(withId(R.id.actionConnect)).check(matches(isDisplayed())) + }, + onOverflow = { + + // assert + onView(withText(R.string.title_connect)).check(matches(isDisplayed())) + } + ) + + @Test + fun checkActionMenuItemDisconnectIsDisplayed() = ensureMenuIsAccessible( + menuItemId = R.id.actionSettings, + onVisible = { + + // assert + onView(withId(R.id.actionDisconnect)).check(matches(isDisplayed())) + }, + onOverflow = { + + // assert + onView(withText(R.string.title_disconnect)).check(matches(isDisplayed())) + } + ) @Test fun clickingSettingsOpensSettingsBottomSheet() { // arrange - // Ensure the action item is accisble, either in the toolbar or via overflow - ensureMenuIsAccessible(R.id.actionSettings) + ensureMenuIsAccessible( + menuItemId = R.id.actionSettings, + onVisible = { - // act - onView(withId(R.id.actionSettings)).perform(click()) + // act + onView(withId(R.id.actionSettings)).perform(click()) - // assert - onView(withId(R.id.composeViewSettingContent)).check(matches(isDisplayed())) + // assert + onView(withId(R.id.composeViewSettingContent)).check(matches(isDisplayed())) + }, + onOverflow = { + // act + onView(withText(R.string.title_settings)).perform(click()) + + // assert + onView(withId(R.id.composeViewSettingContent)).check(matches(isDisplayed())) + } + ) } } diff --git a/app/src/main/res/menu/activity_main_menu.xml b/app/src/main/res/menu/activity_main_menu.xml index 1f0561ef..f0821973 100644 --- a/app/src/main/res/menu/activity_main_menu.xml +++ b/app/src/main/res/menu/activity_main_menu.xml @@ -1,7 +1,7 @@ - - - + + + \ No newline at end of file