diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml index 257b71e1..f2f7394e 100644 --- a/.github/workflows/pull_request.yml +++ b/.github/workflows/pull_request.yml @@ -21,16 +21,13 @@ jobs: with: arguments: test --stacktrace -# - name: Run instrumentation tests -# uses: reactivecircus/android-emulator-runner@08b092e904025fada32a01b711af1e7ff7b7a4a3 -# with: -# api-level: 23 -# target: default -# script: | -# adb shell settings put global animator_duration_scale 0 -# adb shell settings put global transition_animation_scale 0 -# adb shell settings put global window_animation_scale 0 -# ./gradlew :app:connectedDebugAndroidTest + - name: Run instrumentation tests + uses: reactivecircus/android-emulator-runner@08b092e904025fada32a01b711af1e7ff7b7a4a3 + with: + api-level: 30 + target: google_apis + script: | + ./gradlew :app:connectedDebugAndroidTest - name: (Fail-only) upload test report if: failure() diff --git a/app/build.gradle.kts b/app/build.gradle.kts index a2743738..41aece73 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -3,6 +3,7 @@ plugins { kotlin("android") kotlin("kapt") id("dagger.hilt.android.plugin") + id("shot") `versioning-plugin` `lobsters-plugin` `core-library-desugaring` @@ -18,7 +19,7 @@ repositories { android { defaultConfig { applicationId = "dev.msfjarvis.lobsters" - testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + testInstrumentationRunner = "com.karumi.shot.ShotTestRunner" } buildFeatures.compose = true diff --git a/app/screenshots/debug/dev.msfjarvis.lobsters.ui.navigation.LobstersBottomNavTest_bottomNavIsRenderedCorrectlyOnScreen.png b/app/screenshots/debug/dev.msfjarvis.lobsters.ui.navigation.LobstersBottomNavTest_bottomNavIsRenderedCorrectlyOnScreen.png new file mode 100644 index 00000000..a40d7ce0 Binary files /dev/null and b/app/screenshots/debug/dev.msfjarvis.lobsters.ui.navigation.LobstersBottomNavTest_bottomNavIsRenderedCorrectlyOnScreen.png differ diff --git a/app/screenshots/debug/dev.msfjarvis.lobsters.ui.navigation.LobstersBottomNavTest_bottomNavUpdatesCorrectly.png b/app/screenshots/debug/dev.msfjarvis.lobsters.ui.navigation.LobstersBottomNavTest_bottomNavUpdatesCorrectly.png new file mode 100644 index 00000000..64e78d3a Binary files /dev/null and b/app/screenshots/debug/dev.msfjarvis.lobsters.ui.navigation.LobstersBottomNavTest_bottomNavUpdatesCorrectly.png differ diff --git a/app/screenshots/debug/dev.msfjarvis.lobsters.ui.posts.LobstersItemTest_postsAreRenderedCorrectlyOnScreen.png b/app/screenshots/debug/dev.msfjarvis.lobsters.ui.posts.LobstersItemTest_postsAreRenderedCorrectlyOnScreen.png new file mode 100644 index 00000000..bc13682e Binary files /dev/null and b/app/screenshots/debug/dev.msfjarvis.lobsters.ui.posts.LobstersItemTest_postsAreRenderedCorrectlyOnScreen.png differ diff --git a/app/src/androidTest/AndroidManifest.xml b/app/src/androidTest/AndroidManifest.xml new file mode 100644 index 00000000..a82a05b3 --- /dev/null +++ b/app/src/androidTest/AndroidManifest.xml @@ -0,0 +1,6 @@ + + + + diff --git a/app/src/androidTest/java/dev/msfjarvis/lobsters/ui/Theme.kt b/app/src/androidTest/java/dev/msfjarvis/lobsters/ui/Theme.kt new file mode 100644 index 00000000..304bb604 --- /dev/null +++ b/app/src/androidTest/java/dev/msfjarvis/lobsters/ui/Theme.kt @@ -0,0 +1,22 @@ +package dev.msfjarvis.lobsters.ui + +import androidx.compose.material.MaterialTheme +import androidx.compose.runtime.Composable +import dev.msfjarvis.lobsters.ui.theme.darkColors +import dev.msfjarvis.lobsters.ui.theme.lightColors + +@Composable +fun LightTestTheme(children: @Composable () -> Unit) { + MaterialTheme( + colors = lightColors, + content = children, + ) +} + +@Composable +fun DarkTestTheme(children: @Composable () -> Unit) { + MaterialTheme( + colors = darkColors, + content = children, + ) +} diff --git a/app/src/androidTest/java/dev/msfjarvis/lobsters/ui/navigation/LobstersBottomNavTest.kt b/app/src/androidTest/java/dev/msfjarvis/lobsters/ui/navigation/LobstersBottomNavTest.kt new file mode 100644 index 00000000..6860b3db --- /dev/null +++ b/app/src/androidTest/java/dev/msfjarvis/lobsters/ui/navigation/LobstersBottomNavTest.kt @@ -0,0 +1,64 @@ +package dev.msfjarvis.lobsters.ui.navigation + +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.graphics.asAndroidBitmap +import androidx.compose.ui.test.assertHasClickAction +import androidx.compose.ui.test.captureToImage +import androidx.compose.ui.test.junit4.createComposeRule +import androidx.compose.ui.test.onNodeWithTag +import androidx.compose.ui.test.onRoot +import androidx.compose.ui.test.performClick +import com.karumi.shot.ScreenshotTest +import dev.msfjarvis.lobsters.ui.DarkTestTheme +import dev.msfjarvis.lobsters.ui.main.LobstersBottomNav +import dev.msfjarvis.lobsters.ui.theme.LobstersTheme +import org.junit.Rule +import org.junit.Test + +class LobstersBottomNavTest : ScreenshotTest { + + @get:Rule + val composeTestRule = createComposeRule() + + @Test + fun bottomNavIsRenderedCorrectlyOnScreen() { + composeTestRule.setContent { + DarkTestTheme { + LobstersBottomNav( + currentDestination = Destination.startDestination, + navigateToDestination = { /*TODO*/ }, + jumpToIndex = { /*TODO*/ } + ) + } + } + + compareScreenshot(composeTestRule.onRoot().captureToImage().asAndroidBitmap()) + } + + @Test + fun bottomNavUpdatesCorrectly() { + composeTestRule.setContent { + DarkTestTheme { + var destination by remember { mutableStateOf(Destination.startDestination) } + + LobstersBottomNav( + currentDestination = destination, + navigateToDestination = { newDestination -> destination = newDestination }, + jumpToIndex = { /*TODO*/ } + ) + } + } + + selectNode(Destination.Saved.name) + + compareScreenshot(composeTestRule.onRoot().captureToImage().asAndroidBitmap()) + } + + private fun selectNode(testTag: String) = composeTestRule + .onNodeWithTag(testTag) + .assertHasClickAction() + .performClick() +} diff --git a/app/src/androidTest/java/dev/msfjarvis/lobsters/ui/posts/LobstersItemTest.kt b/app/src/androidTest/java/dev/msfjarvis/lobsters/ui/posts/LobstersItemTest.kt new file mode 100644 index 00000000..f14380eb --- /dev/null +++ b/app/src/androidTest/java/dev/msfjarvis/lobsters/ui/posts/LobstersItemTest.kt @@ -0,0 +1,32 @@ +package dev.msfjarvis.lobsters.ui.posts + +import androidx.compose.ui.graphics.asAndroidBitmap +import androidx.compose.ui.test.captureToImage +import androidx.compose.ui.test.junit4.createComposeRule +import androidx.compose.ui.test.onRoot +import com.karumi.shot.ScreenshotTest +import dev.msfjarvis.lobsters.ui.DarkTestTheme +import org.junit.Rule +import org.junit.Test + +class LobstersItemTest : ScreenshotTest { + + @get:Rule + val composeTestRule = createComposeRule() + + @Test + fun postsAreRenderedCorrectlyOnScreen() { + composeTestRule.setContent { + DarkTestTheme { + LobstersItem( + post = TEST_POST, + onClick = { /*TODO*/ }, + onLongClick = { /*TODO*/ }, + onSaveButtonClick = { /*TODO*/ }, + isSaved = true, + ) + } + } + compareScreenshot(composeTestRule.onRoot().captureToImage().asAndroidBitmap()) + } +} diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 53f2e72d..0e9e7dbf 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,6 +1,7 @@ + package="dev.msfjarvis.lobsters" + android:sharedUserId="${applicationId}.uid"> diff --git a/app/src/main/java/dev/msfjarvis/lobsters/ui/main/LobstersApp.kt b/app/src/main/java/dev/msfjarvis/lobsters/ui/main/LobstersApp.kt index 5453ee0a..958108ab 100644 --- a/app/src/main/java/dev/msfjarvis/lobsters/ui/main/LobstersApp.kt +++ b/app/src/main/java/dev/msfjarvis/lobsters/ui/main/LobstersApp.kt @@ -100,6 +100,7 @@ fun LobstersBottomNav( }, label = { Text(stringResource(id = screen.labelRes)) }, selected = currentDestination == screen, + modifier = Modifier.testTag(screen.name), alwaysShowLabel = false, onClick = { if (screen != currentDestination) { diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index ac32817f..fcf191cd 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -34,5 +34,6 @@ dependencies { implementation(Plugins.jsemver) implementation(Plugins.lintModel) implementation(Plugins.kotlin) + implementation(Plugins.shot) implementation(Plugins.sqldelight) } diff --git a/buildSrc/src/main/java/Dependencies.kt b/buildSrc/src/main/java/Dependencies.kt index 6849d32a..d2127563 100644 --- a/buildSrc/src/main/java/Dependencies.kt +++ b/buildSrc/src/main/java/Dependencies.kt @@ -11,6 +11,7 @@ object Plugins { const val hilt = "com.google.dagger:hilt-android-gradle-plugin:${DAGGER_HILT_VERSION}" const val kotlin = "org.jetbrains.kotlin:kotlin-gradle-plugin:1.4.30" const val jsemver = "com.github.zafarkhaja:java-semver:0.9.0" + const val shot = "com.karumi:shot:5.8.0" const val sqldelight = "com.squareup.sqldelight:gradle-plugin:1.4.4" }