Skip to content

Commit ead3f49

Browse files
Fixes flakiness in app's screenshot tests (#1395)
* Disables WM init in app's screenshot tests Change-Id: Ib0994e744f49b53f58c0eebd52f80c0eba67bbed * Spotless Change-Id: Ic0212889354481433ce45ec4292ae7be9bd24b2e * [CI] Uploads roborazzi reports if they fail Change-Id: I5a25a7e156d3fcb72a396d3b503e62068a20b417 * Uses unused test module and enables LocalInspection Change-Id: Iac36347dc3d702248d7515a74823e0bc0cbf2a2b * Fixes timezone in snackbar screenshot tests Change-Id: Ic517e8822218abeaddd3f8d2740b03e651d72d31 * Fixes conflict Change-Id: Ia42fb78781d2469a608183594fc25c7c69f7e76c * 🤖 Updates screenshots
1 parent 1da560f commit ead3f49

File tree

10 files changed

+45
-48
lines changed

10 files changed

+45
-48
lines changed

.github/workflows/Build.yaml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,13 @@ jobs:
128128
name: local-test-results
129129
path: '**/build/test-results/test*UnitTest/**.xml'
130130

131+
- name: Upload screenshot results (PNG)
132+
if: always()
133+
uses: actions/upload-artifact@v4
134+
with:
135+
name: screenshot-test-results
136+
path: '**/build/outputs/roborazzi/*_compare.png'
137+
131138
- name: Check lint
132139
run: ./gradlew :app:lintProdRelease :app-nia-catalog:lintRelease :lint:lint
133140

app/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ dependencies {
113113

114114
testImplementation(projects.core.dataTest)
115115
testImplementation(projects.core.testing)
116+
testImplementation(projects.sync.syncTest)
116117
testImplementation(libs.androidx.compose.ui.test)
117118
testImplementation(libs.hilt.android.testing)
118119
testImplementation(libs.work.testing)

app/src/testDemo/kotlin/com/google/samples/apps/nowinandroid/ui/NiaAppScreenSizesScreenshotTests.kt

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616

1717
package com.google.samples.apps.nowinandroid.ui
1818

19-
import android.util.Log
2019
import androidx.compose.material3.windowsizeclass.ExperimentalMaterial3WindowSizeClassApi
2120
import androidx.compose.material3.windowsizeclass.WindowSizeClass
2221
import androidx.compose.runtime.CompositionLocalProvider
@@ -28,10 +27,6 @@ import androidx.compose.ui.test.onRoot
2827
import androidx.compose.ui.unit.Dp
2928
import androidx.compose.ui.unit.DpSize
3029
import androidx.compose.ui.unit.dp
31-
import androidx.test.platform.app.InstrumentationRegistry
32-
import androidx.work.Configuration
33-
import androidx.work.testing.SynchronousExecutor
34-
import androidx.work.testing.WorkManagerTestInitHelper
3530
import com.github.takahirom.roborazzi.captureRoboImage
3631
import com.google.samples.apps.nowinandroid.core.data.repository.TopicsRepository
3732
import com.google.samples.apps.nowinandroid.core.data.repository.UserDataRepository
@@ -109,17 +104,6 @@ class NiaAppScreenSizesScreenshotTests {
109104

110105
@Before
111106
fun setup() {
112-
val config = Configuration.Builder()
113-
.setMinimumLoggingLevel(Log.DEBUG)
114-
.setExecutor(SynchronousExecutor())
115-
.build()
116-
117-
// Initialize WorkManager for instrumentation tests.
118-
WorkManagerTestInitHelper.initializeTestWorkManager(
119-
InstrumentationRegistry.getInstrumentation().context,
120-
config,
121-
)
122-
123107
hiltRule.inject()
124108

125109
// Configure user data

app/src/testDemo/kotlin/com/google/samples/apps/nowinandroid/ui/SnackbarScreenshotTests.kt

Lines changed: 29 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -16,24 +16,21 @@
1616

1717
package com.google.samples.apps.nowinandroid.ui
1818

19-
import android.util.Log
2019
import androidx.compose.foundation.layout.BoxWithConstraints
2120
import androidx.compose.material3.SnackbarDuration.Indefinite
2221
import androidx.compose.material3.SnackbarHostState
2322
import androidx.compose.material3.windowsizeclass.ExperimentalMaterial3WindowSizeClassApi
2423
import androidx.compose.material3.windowsizeclass.WindowSizeClass
24+
import androidx.compose.runtime.CompositionLocalProvider
2525
import androidx.compose.runtime.rememberCoroutineScope
26+
import androidx.compose.ui.platform.LocalInspectionMode
2627
import androidx.compose.ui.test.DeviceConfigurationOverride
2728
import androidx.compose.ui.test.ForcedSize
2829
import androidx.compose.ui.test.junit4.createAndroidComposeRule
2930
import androidx.compose.ui.test.onRoot
3031
import androidx.compose.ui.unit.Dp
3132
import androidx.compose.ui.unit.DpSize
3233
import androidx.compose.ui.unit.dp
33-
import androidx.test.platform.app.InstrumentationRegistry
34-
import androidx.work.Configuration
35-
import androidx.work.testing.SynchronousExecutor
36-
import androidx.work.testing.WorkManagerTestInitHelper
3734
import com.github.takahirom.roborazzi.captureRoboImage
3835
import com.google.samples.apps.nowinandroid.core.data.repository.TopicsRepository
3936
import com.google.samples.apps.nowinandroid.core.data.repository.UserNewsResourceRepository
@@ -60,6 +57,7 @@ import org.robolectric.RobolectricTestRunner
6057
import org.robolectric.annotation.Config
6158
import org.robolectric.annotation.GraphicsMode
6259
import org.robolectric.annotation.LooperMode
60+
import java.util.TimeZone
6361
import javax.inject.Inject
6462

6563
/**
@@ -112,17 +110,6 @@ class SnackbarScreenshotTests {
112110

113111
@Before
114112
fun setup() {
115-
val config = Configuration.Builder()
116-
.setMinimumLoggingLevel(Log.DEBUG)
117-
.setExecutor(SynchronousExecutor())
118-
.build()
119-
120-
// Initialize WorkManager for instrumentation tests.
121-
WorkManagerTestInitHelper.initializeTestWorkManager(
122-
InstrumentationRegistry.getInstrumentation().context,
123-
config,
124-
)
125-
126113
hiltRule.inject()
127114

128115
// Configure user data
@@ -135,6 +122,12 @@ class SnackbarScreenshotTests {
135122
}
136123
}
137124

125+
@Before
126+
fun setTimeZone() {
127+
// Make time zone deterministic in tests
128+
TimeZone.setDefault(TimeZone.getTimeZone("UTC"))
129+
}
130+
138131
@Test
139132
fun phone_noSnackbar() {
140133
val snackbarHostState = SnackbarHostState()
@@ -207,22 +200,27 @@ class SnackbarScreenshotTests {
207200
) {
208201
lateinit var scope: CoroutineScope
209202
composeTestRule.setContent {
210-
scope = rememberCoroutineScope()
211-
212-
DeviceConfigurationOverride(
213-
DeviceConfigurationOverride.ForcedSize(DpSize(width, height)),
203+
CompositionLocalProvider(
204+
// Replaces images with placeholders
205+
LocalInspectionMode provides true,
214206
) {
215-
BoxWithConstraints {
216-
val appState = rememberNiaAppState(
217-
windowSizeClass = WindowSizeClass.calculateFromSize(
218-
DpSize(maxWidth, maxHeight),
219-
),
220-
networkMonitor = networkMonitor,
221-
userNewsResourceRepository = userNewsResourceRepository,
222-
timeZoneMonitor = timeZoneMonitor,
223-
)
224-
NiaTheme {
225-
NiaApp(appState, snackbarHostState, false, {}, {})
207+
scope = rememberCoroutineScope()
208+
209+
DeviceConfigurationOverride(
210+
DeviceConfigurationOverride.ForcedSize(DpSize(width, height)),
211+
) {
212+
BoxWithConstraints {
213+
val appState = rememberNiaAppState(
214+
windowSizeClass = WindowSizeClass.calculateFromSize(
215+
DpSize(maxWidth, maxHeight),
216+
),
217+
networkMonitor = networkMonitor,
218+
userNewsResourceRepository = userNewsResourceRepository,
219+
timeZoneMonitor = timeZoneMonitor,
220+
)
221+
NiaTheme {
222+
NiaApp(appState, snackbarHostState, false, {}, {})
223+
}
226224
}
227225
}
228226
}
15.8 KB
Loading
15.9 KB
Loading
54.1 KB
Loading
24.1 KB
Loading

sync/sync-test/src/main/kotlin/com/google/samples/apps/nowinandroid/core/sync/test/TestSyncModule.kt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ package com.google.samples.apps.nowinandroid.core.sync.test
1818

1919
import com.google.samples.apps.nowinandroid.core.data.util.SyncManager
2020
import com.google.samples.apps.nowinandroid.sync.di.SyncModule
21+
import com.google.samples.apps.nowinandroid.sync.status.StubSyncSubscriber
22+
import com.google.samples.apps.nowinandroid.sync.status.SyncSubscriber
2123
import dagger.Binds
2224
import dagger.Module
2325
import dagger.hilt.components.SingletonComponent
@@ -33,4 +35,9 @@ internal interface TestSyncModule {
3335
fun bindsSyncStatusMonitor(
3436
syncStatusMonitor: NeverSyncingSyncManager,
3537
): SyncManager
38+
39+
@Binds
40+
fun bindsSyncSubscriber(
41+
syncSubscriber: StubSyncSubscriber,
42+
): SyncSubscriber
3643
}

sync/work/src/main/kotlin/com/google/samples/apps/nowinandroid/sync/status/StubSyncSubscriber.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ private const val TAG = "StubSyncSubscriber"
2424
/**
2525
* Stub implementation of [SyncSubscriber]
2626
*/
27-
internal class StubSyncSubscriber @Inject constructor() : SyncSubscriber {
27+
class StubSyncSubscriber @Inject constructor() : SyncSubscriber {
2828
override suspend fun subscribe() {
2929
Log.d(TAG, "Subscribing to sync")
3030
}

0 commit comments

Comments
 (0)