diff --git a/.github/workflows/Build.yaml b/.github/workflows/Build.yaml index db326c380..32d89f5d9 100644 --- a/.github/workflows/Build.yaml +++ b/.github/workflows/Build.yaml @@ -128,6 +128,13 @@ jobs: name: local-test-results path: '**/build/test-results/test*UnitTest/**.xml' + - name: Upload screenshot results (PNG) + if: always() + uses: actions/upload-artifact@v4 + with: + name: screenshot-test-results + path: '**/build/outputs/roborazzi/*_compare.png' + - name: Check lint run: ./gradlew :app:lintProdRelease :app-nia-catalog:lintRelease :lint:lint diff --git a/app/build.gradle.kts b/app/build.gradle.kts index afd37736f..ae1c0d686 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -113,6 +113,7 @@ dependencies { testImplementation(projects.core.dataTest) testImplementation(projects.core.testing) + testImplementation(projects.sync.syncTest) testImplementation(libs.androidx.compose.ui.test) testImplementation(libs.hilt.android.testing) testImplementation(libs.work.testing) diff --git a/app/src/testDemo/kotlin/com/google/samples/apps/nowinandroid/ui/NiaAppScreenSizesScreenshotTests.kt b/app/src/testDemo/kotlin/com/google/samples/apps/nowinandroid/ui/NiaAppScreenSizesScreenshotTests.kt index e84335246..32bdfe9d9 100644 --- a/app/src/testDemo/kotlin/com/google/samples/apps/nowinandroid/ui/NiaAppScreenSizesScreenshotTests.kt +++ b/app/src/testDemo/kotlin/com/google/samples/apps/nowinandroid/ui/NiaAppScreenSizesScreenshotTests.kt @@ -16,7 +16,6 @@ package com.google.samples.apps.nowinandroid.ui -import android.util.Log import androidx.compose.material3.windowsizeclass.ExperimentalMaterial3WindowSizeClassApi import androidx.compose.material3.windowsizeclass.WindowSizeClass import androidx.compose.runtime.CompositionLocalProvider @@ -28,10 +27,6 @@ import androidx.compose.ui.test.onRoot import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.DpSize import androidx.compose.ui.unit.dp -import androidx.test.platform.app.InstrumentationRegistry -import androidx.work.Configuration -import androidx.work.testing.SynchronousExecutor -import androidx.work.testing.WorkManagerTestInitHelper import com.github.takahirom.roborazzi.captureRoboImage import com.google.samples.apps.nowinandroid.core.data.repository.TopicsRepository import com.google.samples.apps.nowinandroid.core.data.repository.UserDataRepository @@ -109,17 +104,6 @@ class NiaAppScreenSizesScreenshotTests { @Before fun setup() { - val config = Configuration.Builder() - .setMinimumLoggingLevel(Log.DEBUG) - .setExecutor(SynchronousExecutor()) - .build() - - // Initialize WorkManager for instrumentation tests. - WorkManagerTestInitHelper.initializeTestWorkManager( - InstrumentationRegistry.getInstrumentation().context, - config, - ) - hiltRule.inject() // Configure user data diff --git a/app/src/testDemo/kotlin/com/google/samples/apps/nowinandroid/ui/SnackbarScreenshotTests.kt b/app/src/testDemo/kotlin/com/google/samples/apps/nowinandroid/ui/SnackbarScreenshotTests.kt index c3ad18591..ab67f8399 100644 --- a/app/src/testDemo/kotlin/com/google/samples/apps/nowinandroid/ui/SnackbarScreenshotTests.kt +++ b/app/src/testDemo/kotlin/com/google/samples/apps/nowinandroid/ui/SnackbarScreenshotTests.kt @@ -16,13 +16,14 @@ package com.google.samples.apps.nowinandroid.ui -import android.util.Log import androidx.compose.foundation.layout.BoxWithConstraints import androidx.compose.material3.SnackbarDuration.Indefinite import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.windowsizeclass.ExperimentalMaterial3WindowSizeClassApi import androidx.compose.material3.windowsizeclass.WindowSizeClass +import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.ui.platform.LocalInspectionMode import androidx.compose.ui.test.DeviceConfigurationOverride import androidx.compose.ui.test.ForcedSize import androidx.compose.ui.test.junit4.createAndroidComposeRule @@ -30,10 +31,6 @@ import androidx.compose.ui.test.onRoot import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.DpSize import androidx.compose.ui.unit.dp -import androidx.test.platform.app.InstrumentationRegistry -import androidx.work.Configuration -import androidx.work.testing.SynchronousExecutor -import androidx.work.testing.WorkManagerTestInitHelper import com.github.takahirom.roborazzi.captureRoboImage import com.google.samples.apps.nowinandroid.core.data.repository.TopicsRepository import com.google.samples.apps.nowinandroid.core.data.repository.UserNewsResourceRepository @@ -60,6 +57,7 @@ import org.robolectric.RobolectricTestRunner import org.robolectric.annotation.Config import org.robolectric.annotation.GraphicsMode import org.robolectric.annotation.LooperMode +import java.util.TimeZone import javax.inject.Inject /** @@ -112,17 +110,6 @@ class SnackbarScreenshotTests { @Before fun setup() { - val config = Configuration.Builder() - .setMinimumLoggingLevel(Log.DEBUG) - .setExecutor(SynchronousExecutor()) - .build() - - // Initialize WorkManager for instrumentation tests. - WorkManagerTestInitHelper.initializeTestWorkManager( - InstrumentationRegistry.getInstrumentation().context, - config, - ) - hiltRule.inject() // Configure user data @@ -135,6 +122,12 @@ class SnackbarScreenshotTests { } } + @Before + fun setTimeZone() { + // Make time zone deterministic in tests + TimeZone.setDefault(TimeZone.getTimeZone("UTC")) + } + @Test fun phone_noSnackbar() { val snackbarHostState = SnackbarHostState() @@ -207,22 +200,27 @@ class SnackbarScreenshotTests { ) { lateinit var scope: CoroutineScope composeTestRule.setContent { - scope = rememberCoroutineScope() - - DeviceConfigurationOverride( - DeviceConfigurationOverride.ForcedSize(DpSize(width, height)), + CompositionLocalProvider( + // Replaces images with placeholders + LocalInspectionMode provides true, ) { - BoxWithConstraints { - val appState = rememberNiaAppState( - windowSizeClass = WindowSizeClass.calculateFromSize( - DpSize(maxWidth, maxHeight), - ), - networkMonitor = networkMonitor, - userNewsResourceRepository = userNewsResourceRepository, - timeZoneMonitor = timeZoneMonitor, - ) - NiaTheme { - NiaApp(appState, snackbarHostState, false, {}, {}) + scope = rememberCoroutineScope() + + DeviceConfigurationOverride( + DeviceConfigurationOverride.ForcedSize(DpSize(width, height)), + ) { + BoxWithConstraints { + val appState = rememberNiaAppState( + windowSizeClass = WindowSizeClass.calculateFromSize( + DpSize(maxWidth, maxHeight), + ), + networkMonitor = networkMonitor, + userNewsResourceRepository = userNewsResourceRepository, + timeZoneMonitor = timeZoneMonitor, + ) + NiaTheme { + NiaApp(appState, snackbarHostState, false, {}, {}) + } } } } diff --git a/app/src/testDemo/screenshots/snackbar_compact_medium.png b/app/src/testDemo/screenshots/snackbar_compact_medium.png index 70d15deb3..147c9ce6b 100644 Binary files a/app/src/testDemo/screenshots/snackbar_compact_medium.png and b/app/src/testDemo/screenshots/snackbar_compact_medium.png differ diff --git a/app/src/testDemo/screenshots/snackbar_compact_medium_noSnackbar.png b/app/src/testDemo/screenshots/snackbar_compact_medium_noSnackbar.png index 9c3eb133d..2767ff9b5 100644 Binary files a/app/src/testDemo/screenshots/snackbar_compact_medium_noSnackbar.png and b/app/src/testDemo/screenshots/snackbar_compact_medium_noSnackbar.png differ diff --git a/app/src/testDemo/screenshots/snackbar_expanded_expanded.png b/app/src/testDemo/screenshots/snackbar_expanded_expanded.png index e4c7520ab..5360d68de 100644 Binary files a/app/src/testDemo/screenshots/snackbar_expanded_expanded.png and b/app/src/testDemo/screenshots/snackbar_expanded_expanded.png differ diff --git a/app/src/testDemo/screenshots/snackbar_medium_medium.png b/app/src/testDemo/screenshots/snackbar_medium_medium.png index a9f131fd7..b60112101 100644 Binary files a/app/src/testDemo/screenshots/snackbar_medium_medium.png and b/app/src/testDemo/screenshots/snackbar_medium_medium.png differ diff --git a/sync/sync-test/src/main/kotlin/com/google/samples/apps/nowinandroid/core/sync/test/TestSyncModule.kt b/sync/sync-test/src/main/kotlin/com/google/samples/apps/nowinandroid/core/sync/test/TestSyncModule.kt index d1c0f562f..ceca1cb5c 100644 --- a/sync/sync-test/src/main/kotlin/com/google/samples/apps/nowinandroid/core/sync/test/TestSyncModule.kt +++ b/sync/sync-test/src/main/kotlin/com/google/samples/apps/nowinandroid/core/sync/test/TestSyncModule.kt @@ -18,6 +18,8 @@ package com.google.samples.apps.nowinandroid.core.sync.test import com.google.samples.apps.nowinandroid.core.data.util.SyncManager import com.google.samples.apps.nowinandroid.sync.di.SyncModule +import com.google.samples.apps.nowinandroid.sync.status.StubSyncSubscriber +import com.google.samples.apps.nowinandroid.sync.status.SyncSubscriber import dagger.Binds import dagger.Module import dagger.hilt.components.SingletonComponent @@ -33,4 +35,9 @@ internal interface TestSyncModule { fun bindsSyncStatusMonitor( syncStatusMonitor: NeverSyncingSyncManager, ): SyncManager + + @Binds + fun bindsSyncSubscriber( + syncSubscriber: StubSyncSubscriber, + ): SyncSubscriber } diff --git a/sync/work/src/main/kotlin/com/google/samples/apps/nowinandroid/sync/status/StubSyncSubscriber.kt b/sync/work/src/main/kotlin/com/google/samples/apps/nowinandroid/sync/status/StubSyncSubscriber.kt index 83286eeec..0ef90fb29 100644 --- a/sync/work/src/main/kotlin/com/google/samples/apps/nowinandroid/sync/status/StubSyncSubscriber.kt +++ b/sync/work/src/main/kotlin/com/google/samples/apps/nowinandroid/sync/status/StubSyncSubscriber.kt @@ -24,7 +24,7 @@ private const val TAG = "StubSyncSubscriber" /** * Stub implementation of [SyncSubscriber] */ -internal class StubSyncSubscriber @Inject constructor() : SyncSubscriber { +class StubSyncSubscriber @Inject constructor() : SyncSubscriber { override suspend fun subscribe() { Log.d(TAG, "Subscribing to sync") }