From 9384122b01f6d7e640f12f4b4c6e81ee344a1716 Mon Sep 17 00:00:00 2001 From: Rob Orgiu Date: Thu, 6 Nov 2025 17:24:43 +0100 Subject: [PATCH 01/16] Refactor tests to avoid code duplication --- .../example/cahier/CahierListDetailTest.kt | 50 ++++++++++--------- 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/app/src/androidTest/java/com/example/cahier/CahierListDetailTest.kt b/app/src/androidTest/java/com/example/cahier/CahierListDetailTest.kt index 507ba65..08ec8b7 100644 --- a/app/src/androidTest/java/com/example/cahier/CahierListDetailTest.kt +++ b/app/src/androidTest/java/com/example/cahier/CahierListDetailTest.kt @@ -1,5 +1,6 @@ package com.example.cahier +import androidx.compose.runtime.Composable import androidx.compose.ui.test.DeviceConfigurationOverride import androidx.compose.ui.test.ForcedSize import androidx.compose.ui.test.junit4.createComposeRule @@ -25,19 +26,9 @@ class CahierListDetailTest { fun homeScreen_showListOnly() { composeTestRule.setContent { DeviceConfigurationOverride( - DeviceConfigurationOverride.ForcedSize( - DpSize( - width = 400.dp, - height = 900.dp - ) - ) + DeviceConfigurationOverride.ForcedSize(compatWidthWindow) ) { - HomePane( - navigateToCanvas = { _ -> }, - navigateToDrawingCanvas = { _ -> }, - navigateUp = {}, - homeScreenViewModel = fakeViewModel - ) + HomeContent() } } @@ -49,23 +40,34 @@ class CahierListDetailTest { fun homeScreen_showListAndDetail() { composeTestRule.setContent { DeviceConfigurationOverride( - DeviceConfigurationOverride.ForcedSize( - DpSize( - width = 1200.dp, - height = 900.dp - ) - ) + DeviceConfigurationOverride.ForcedSize(mediumWidthWindow) ) { - HomePane( - navigateToCanvas = { _ -> }, - navigateToDrawingCanvas = { _ -> }, - navigateUp = {}, - homeScreenViewModel = fakeViewModel - ) + HomeContent() } } composeTestRule.onNodeWithTag("List").assertExists() composeTestRule.onNodeWithTag("Detail").assertExists() } + + + private val mediumWidthWindow = DpSize( + width = 1200.dp, + height = 900.dp + ) + + private val compatWidthWindow = DpSize( + width = 400.dp, + height = 900.dp + ) + + @Composable + private fun HomeContent() { + HomePane( + navigateToCanvas = { _ -> }, + navigateToDrawingCanvas = { _ -> }, + navigateUp = {}, + homeScreenViewModel = fakeViewModel + ) + } } \ No newline at end of file From 724856bb8d471cc40ba6566fab794f173c1c4cc9 Mon Sep 17 00:00:00 2001 From: Rob Orgiu Date: Thu, 6 Nov 2025 17:24:55 +0100 Subject: [PATCH 02/16] Add and enable screenshot testing feature --- app/build.gradle.kts | 7 +++++++ gradle.properties | 3 ++- gradle/libs.versions.toml | 4 +++- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 266099f..721c7b6 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -17,6 +17,7 @@ plugins { alias(libs.plugins.androidApplication) alias(libs.plugins.jetbrainsKotlinAndroid) alias(libs.plugins.ksp) + alias(libs.plugins.screenshotTesting) id("org.jetbrains.kotlin.plugin.compose") version "2.2.20" id("kotlin-parcelize") kotlin("plugin.serialization") @@ -61,6 +62,8 @@ android { excludes += "/META-INF/{AL2.0,LGPL2.1}" } } + + experimentalProperties["android.experimental.enableScreenshotTest"] = true } dependencies { @@ -145,6 +148,10 @@ dependencies { //Coil implementation(libs.coil.compose) implementation(libs.coil.network.okhttp) + + //Screenshot Testing + screenshotTestImplementation(platform(libs.androidx.compose.bom)) + screenshotTestImplementation (libs.androidx.ui.tooling) } java { toolchain { diff --git a/gradle.properties b/gradle.properties index 4616b11..afd9708 100644 --- a/gradle.properties +++ b/gradle.properties @@ -21,4 +21,5 @@ kotlin.code.style=official # resources declared in the library itself and none from the library's dependencies, # thereby reducing the size of the R class for that library android.nonTransitiveRClass=true -android.enableJetifier=false \ No newline at end of file +android.enableJetifier=false +android.experimental.enableScreenshotTest=true \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 289cdf3..4e76da9 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -28,6 +28,7 @@ ksp = "2.2.20-2.0.3" roomCompiler = "2.8.1" material3AdaptiveNavigationSuiteAndroidVersion = "1.4.0" inputMotionprediction = "1.0.0-beta06" +screenshotTesting = "0.0.1-alpha11" #Tests mockito = "5.20.0" @@ -99,4 +100,5 @@ androidx-compose-material3-window-size-class1 = { group = "androidx.compose.mate androidApplication = { id = "com.android.application", version.ref = "agp" } androidLibrary = { id = "com.android.library", version.ref = "agp" } jetbrainsKotlinAndroid = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } -ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" } \ No newline at end of file +ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" } +screenshotTesting = { id = "com.android.compose.screenshot", version.ref="screenshotTesting"} \ No newline at end of file From 50a2b46f79661812d930dab58d753d055f55eddc Mon Sep 17 00:00:00 2001 From: Rob Orgiu Date: Thu, 6 Nov 2025 18:28:35 +0100 Subject: [PATCH 03/16] Add screenshot testing feature --- app/build.gradle.kts | 1 + .../com/example/cahier/ScreenshotTesting.kt | 31 +++++++++++++++++++ gradle/libs.versions.toml | 2 ++ 3 files changed, 34 insertions(+) create mode 100644 app/src/androidTest/java/com/example/cahier/ScreenshotTesting.kt diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 721c7b6..83d524b 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -90,6 +90,7 @@ dependencies { //Room implementation(libs.androidx.room.runtime) implementation(libs.androidx.compose.material3.window.size.class1) + implementation(libs.screenshot.validation.api) ksp(libs.androidx.room.compiler) implementation(libs.androidx.room.ktx) diff --git a/app/src/androidTest/java/com/example/cahier/ScreenshotTesting.kt b/app/src/androidTest/java/com/example/cahier/ScreenshotTesting.kt new file mode 100644 index 0000000..f4a1392 --- /dev/null +++ b/app/src/androidTest/java/com/example/cahier/ScreenshotTesting.kt @@ -0,0 +1,31 @@ +package com.example.cahier + +import androidx.compose.runtime.Composable +import androidx.compose.ui.tooling.preview.Devices.PIXEL_9 +import androidx.compose.ui.tooling.preview.Devices.PIXEL_TABLET +import androidx.compose.ui.tooling.preview.Preview +import com.android.tools.screenshot.PreviewTest +import com.example.cahier.data.FakeNotesRepository +import com.example.cahier.ui.HomePane +import com.example.cahier.ui.theme.CahierAppTheme +import com.example.cahier.ui.viewmodels.HomeScreenViewModel + +class ScreenshotTesting { + + private val fakeViewModel = HomeScreenViewModel(FakeNotesRepository()) + + @PreviewTest + @Preview(name = "Compact Window", showSystemUi = true, device = PIXEL_9) + @Preview(name = "Medium Window", showSystemUi = true, device = PIXEL_TABLET) + @Composable + fun CahierAppPreview() { + CahierAppTheme { + HomePane( + navigateToDrawingCanvas = {_ -> }, + navigateToCanvas = {_ -> }, + navigateUp = {}, + homeScreenViewModel = fakeViewModel + ) + } + } +} \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 4e76da9..e8ae0f2 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -37,6 +37,7 @@ coreTesting = "2.2.0" kotlinxCoroutinesTest = "1.10.2" turbine = "1.2.1" material3WindowSizeClass = "1.4.0" +screenshotValidationApi = "0.0.1-alpha11" [libraries] androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" } @@ -95,6 +96,7 @@ hilt-android-testing = { module = "com.google.dagger:hilt-android-testing", vers turbine = { module = "app.cash.turbine:turbine", version.ref = "turbine" } mockito-android = { module = "org.mockito:mockito-android", version.ref = "mockito" } androidx-compose-material3-window-size-class1 = { group = "androidx.compose.material3", name = "material3-window-size-class", version.ref = "material3WindowSizeClass" } +screenshot-validation-api = { group = "com.android.tools.screenshot", name = "screenshot-validation-api", version.ref = "screenshotValidationApi" } [plugins] androidApplication = { id = "com.android.application", version.ref = "agp" } From f60d09541ed3f2f53dc30b3ff873e14789803299 Mon Sep 17 00:00:00 2001 From: Rob Orgiu Date: Fri, 7 Nov 2025 15:09:31 +0100 Subject: [PATCH 04/16] Remove Screenshot library --- app/build.gradle.kts | 8 ----- .../com/example/cahier/ScreenshotTesting.kt | 31 ------------------- gradle/libs.versions.toml | 8 +---- 3 files changed, 1 insertion(+), 46 deletions(-) delete mode 100644 app/src/androidTest/java/com/example/cahier/ScreenshotTesting.kt diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 83d524b..266099f 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -17,7 +17,6 @@ plugins { alias(libs.plugins.androidApplication) alias(libs.plugins.jetbrainsKotlinAndroid) alias(libs.plugins.ksp) - alias(libs.plugins.screenshotTesting) id("org.jetbrains.kotlin.plugin.compose") version "2.2.20" id("kotlin-parcelize") kotlin("plugin.serialization") @@ -62,8 +61,6 @@ android { excludes += "/META-INF/{AL2.0,LGPL2.1}" } } - - experimentalProperties["android.experimental.enableScreenshotTest"] = true } dependencies { @@ -90,7 +87,6 @@ dependencies { //Room implementation(libs.androidx.room.runtime) implementation(libs.androidx.compose.material3.window.size.class1) - implementation(libs.screenshot.validation.api) ksp(libs.androidx.room.compiler) implementation(libs.androidx.room.ktx) @@ -149,10 +145,6 @@ dependencies { //Coil implementation(libs.coil.compose) implementation(libs.coil.network.okhttp) - - //Screenshot Testing - screenshotTestImplementation(platform(libs.androidx.compose.bom)) - screenshotTestImplementation (libs.androidx.ui.tooling) } java { toolchain { diff --git a/app/src/androidTest/java/com/example/cahier/ScreenshotTesting.kt b/app/src/androidTest/java/com/example/cahier/ScreenshotTesting.kt deleted file mode 100644 index f4a1392..0000000 --- a/app/src/androidTest/java/com/example/cahier/ScreenshotTesting.kt +++ /dev/null @@ -1,31 +0,0 @@ -package com.example.cahier - -import androidx.compose.runtime.Composable -import androidx.compose.ui.tooling.preview.Devices.PIXEL_9 -import androidx.compose.ui.tooling.preview.Devices.PIXEL_TABLET -import androidx.compose.ui.tooling.preview.Preview -import com.android.tools.screenshot.PreviewTest -import com.example.cahier.data.FakeNotesRepository -import com.example.cahier.ui.HomePane -import com.example.cahier.ui.theme.CahierAppTheme -import com.example.cahier.ui.viewmodels.HomeScreenViewModel - -class ScreenshotTesting { - - private val fakeViewModel = HomeScreenViewModel(FakeNotesRepository()) - - @PreviewTest - @Preview(name = "Compact Window", showSystemUi = true, device = PIXEL_9) - @Preview(name = "Medium Window", showSystemUi = true, device = PIXEL_TABLET) - @Composable - fun CahierAppPreview() { - CahierAppTheme { - HomePane( - navigateToDrawingCanvas = {_ -> }, - navigateToCanvas = {_ -> }, - navigateUp = {}, - homeScreenViewModel = fakeViewModel - ) - } - } -} \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index e8ae0f2..44c7148 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -3,7 +3,6 @@ agp = "8.13.0" appcompatV7 = "1.7.1" coilCompose = "3.3.0" foundation = "1.9.2" -gson = "2.13.2" hiltAndroid = "2.57.1" hiltNavigationCompose = "1.3.0" ink = "1.0.0-beta01" @@ -28,7 +27,6 @@ ksp = "2.2.20-2.0.3" roomCompiler = "2.8.1" material3AdaptiveNavigationSuiteAndroidVersion = "1.4.0" inputMotionprediction = "1.0.0-beta06" -screenshotTesting = "0.0.1-alpha11" #Tests mockito = "5.20.0" @@ -37,7 +35,6 @@ coreTesting = "2.2.0" kotlinxCoroutinesTest = "1.10.2" turbine = "1.2.1" material3WindowSizeClass = "1.4.0" -screenshotValidationApi = "0.0.1-alpha11" [libraries] androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" } @@ -56,7 +53,6 @@ appcompat-v7 = { module = "androidx.appcompat:appcompat", version.ref = "appcomp appcompat-v7-resources = { module = "androidx.appcompat:appcompat-resources", version.ref = "appcompatV7" } coil-compose = { module = "io.coil-kt.coil3:coil-compose", version.ref = "coilCompose" } coil-network-okhttp = { module = "io.coil-kt.coil3:coil-network-okhttp", version.ref = "coilCompose" } -gson = { module = "com.google.code.gson:gson", version.ref = "gson" } hilt-android = { module = "com.google.dagger:hilt-android", version.ref = "hiltAndroid" } hilt-android-compiler = { module = "com.google.dagger:hilt-android-compiler", version.ref = "hiltAndroid" } junit = { group = "junit", name = "junit", version.ref = "junit" } @@ -96,11 +92,9 @@ hilt-android-testing = { module = "com.google.dagger:hilt-android-testing", vers turbine = { module = "app.cash.turbine:turbine", version.ref = "turbine" } mockito-android = { module = "org.mockito:mockito-android", version.ref = "mockito" } androidx-compose-material3-window-size-class1 = { group = "androidx.compose.material3", name = "material3-window-size-class", version.ref = "material3WindowSizeClass" } -screenshot-validation-api = { group = "com.android.tools.screenshot", name = "screenshot-validation-api", version.ref = "screenshotValidationApi" } [plugins] androidApplication = { id = "com.android.application", version.ref = "agp" } androidLibrary = { id = "com.android.library", version.ref = "agp" } jetbrainsKotlinAndroid = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } -ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" } -screenshotTesting = { id = "com.android.compose.screenshot", version.ref="screenshotTesting"} \ No newline at end of file +ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" } \ No newline at end of file From 1ee646200698cd7e8f14c9401c92733039637bc8 Mon Sep 17 00:00:00 2001 From: Rob Orgiu Date: Fri, 7 Nov 2025 15:12:11 +0100 Subject: [PATCH 05/16] Remove experimental flag --- gradle.properties | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/gradle.properties b/gradle.properties index afd9708..4616b11 100644 --- a/gradle.properties +++ b/gradle.properties @@ -21,5 +21,4 @@ kotlin.code.style=official # resources declared in the library itself and none from the library's dependencies, # thereby reducing the size of the R class for that library android.nonTransitiveRClass=true -android.enableJetifier=false -android.experimental.enableScreenshotTest=true \ No newline at end of file +android.enableJetifier=false \ No newline at end of file From 6be4921a02bcefa3adbb6fb7233d68395155c43f Mon Sep 17 00:00:00 2001 From: Rob Orgiu Date: Fri, 7 Nov 2025 15:44:09 +0100 Subject: [PATCH 06/16] Include Robolectric --- app/build.gradle.kts | 6 ++++++ gradle/libs.versions.toml | 2 ++ 2 files changed, 8 insertions(+) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 266099f..f0106bc 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -61,6 +61,11 @@ android { excludes += "/META-INF/{AL2.0,LGPL2.1}" } } + testOptions { + unitTests { + isIncludeAndroidResources = true + } + } } dependencies { @@ -97,6 +102,7 @@ dependencies { testImplementation(libs.androidx.arch.core.testing) testImplementation(libs.kotlinx.coroutines.test) testImplementation(libs.turbine) + testImplementation(libs.robolectric) // Android Testing - For instrumented tests androidTestImplementation(libs.androidx.junit) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 44c7148..7509a10 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -27,6 +27,7 @@ ksp = "2.2.20-2.0.3" roomCompiler = "2.8.1" material3AdaptiveNavigationSuiteAndroidVersion = "1.4.0" inputMotionprediction = "1.0.0-beta06" +robolectric = "4.11.1" #Tests mockito = "5.20.0" @@ -92,6 +93,7 @@ hilt-android-testing = { module = "com.google.dagger:hilt-android-testing", vers turbine = { module = "app.cash.turbine:turbine", version.ref = "turbine" } mockito-android = { module = "org.mockito:mockito-android", version.ref = "mockito" } androidx-compose-material3-window-size-class1 = { group = "androidx.compose.material3", name = "material3-window-size-class", version.ref = "material3WindowSizeClass" } +robolectric = { group = "org.robolectric", name = "robolectric", version.ref = "robolectric" } [plugins] androidApplication = { id = "com.android.application", version.ref = "agp" } From f81c62ba04b7427f5d33e61c16da88a121e57fd1 Mon Sep 17 00:00:00 2001 From: Rob Orgiu Date: Fri, 7 Nov 2025 15:49:08 +0100 Subject: [PATCH 07/16] Include Roborazzi --- app/build.gradle.kts | 4 ++++ gradle/libs.versions.toml | 9 +++++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index f0106bc..5539a0e 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -17,6 +17,7 @@ plugins { alias(libs.plugins.androidApplication) alias(libs.plugins.jetbrainsKotlinAndroid) alias(libs.plugins.ksp) + alias(libs.plugins.roborazzi) id("org.jetbrains.kotlin.plugin.compose") version "2.2.20" id("kotlin-parcelize") kotlin("plugin.serialization") @@ -103,6 +104,9 @@ dependencies { testImplementation(libs.kotlinx.coroutines.test) testImplementation(libs.turbine) testImplementation(libs.robolectric) + testImplementation(libs.roborazzi) + testImplementation(libs.roborazzi.compose) + testImplementation(libs.roborazzi.rule) // Android Testing - For instrumented tests androidTestImplementation(libs.androidx.junit) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 7509a10..328512f 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -27,7 +27,6 @@ ksp = "2.2.20-2.0.3" roomCompiler = "2.8.1" material3AdaptiveNavigationSuiteAndroidVersion = "1.4.0" inputMotionprediction = "1.0.0-beta06" -robolectric = "4.11.1" #Tests mockito = "5.20.0" @@ -36,6 +35,8 @@ coreTesting = "2.2.0" kotlinxCoroutinesTest = "1.10.2" turbine = "1.2.1" material3WindowSizeClass = "1.4.0" +robolectric = "4.11.1" +roborazzi = "1.8.0-alpha-5" [libraries] androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" } @@ -94,9 +95,13 @@ turbine = { module = "app.cash.turbine:turbine", version.ref = "turbine" } mockito-android = { module = "org.mockito:mockito-android", version.ref = "mockito" } androidx-compose-material3-window-size-class1 = { group = "androidx.compose.material3", name = "material3-window-size-class", version.ref = "material3WindowSizeClass" } robolectric = { group = "org.robolectric", name = "robolectric", version.ref = "robolectric" } +roborazzi = { group = "io.github.takahirom.roborazzi", name = "roborazzi", version.ref = "roborazzi" } +roborazzi-compose = { group = "io.github.takahirom.roborazzi", name = "roborazzi-compose", version.ref = "roborazzi" } +roborazzi-rule = { group = "io.github.takahirom.roborazzi", name = "roborazzi-junit-rule", version.ref = "roborazzi" } [plugins] androidApplication = { id = "com.android.application", version.ref = "agp" } androidLibrary = { id = "com.android.library", version.ref = "agp" } jetbrainsKotlinAndroid = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } -ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" } \ No newline at end of file +ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" } +roborazzi = { id = "io.github.takahirom.roborazzi", version.ref = "roborazzi" } \ No newline at end of file From 9540ca7ab6b3d652e5d3ac948f3101a65864189f Mon Sep 17 00:00:00 2001 From: Rob Orgiu Date: Fri, 7 Nov 2025 16:12:49 +0100 Subject: [PATCH 08/16] Create global ui navigation screenshot tests --- app/build.gradle.kts | 5 ++ app/screenshots/screenshot_bottomnavbar.png | Bin 0 -> 37965 bytes app/screenshots/screenshot_navrail.png | Bin 0 -> 34446 bytes .../java/com/example/cahier/ScreenshotTest.kt | 53 ++++++++++++++++++ app/src/test/resources/robolectric.properties | 1 + 5 files changed, 59 insertions(+) create mode 100644 app/screenshots/screenshot_bottomnavbar.png create mode 100644 app/screenshots/screenshot_navrail.png create mode 100644 app/src/test/java/com/example/cahier/ScreenshotTest.kt create mode 100644 app/src/test/resources/robolectric.properties diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 5539a0e..bc45ded 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -67,6 +67,9 @@ android { isIncludeAndroidResources = true } } + roborazzi { + outputDir.set(file("src/screenshots")) + } } dependencies { @@ -107,6 +110,8 @@ dependencies { testImplementation(libs.roborazzi) testImplementation(libs.roborazzi.compose) testImplementation(libs.roborazzi.rule) + testImplementation(platform(libs.androidx.compose.bom)) + testImplementation(libs.androidx.ui.test.junit4) // Android Testing - For instrumented tests androidTestImplementation(libs.androidx.junit) diff --git a/app/screenshots/screenshot_bottomnavbar.png b/app/screenshots/screenshot_bottomnavbar.png new file mode 100644 index 0000000000000000000000000000000000000000..68a61c88a3c07e13c5500c0b67507c2d58a16d5e GIT binary patch literal 37965 zcmeIbcT`i`);=5#3Koiu-t4G!QCes=zy>M;QiC9b-b?5x3P-9QMNlAs3LHujfzZ1M zQCcVxI-v*w0)zmehkQH1bIA~zoVEM|MtSwKfQYGt=W_%RC) z&YiIGzueO&5A*|p?ijl=uAyR$I}K;Y1?UZ-ugM(rt7a37J|O6*jVdes`r0}zuQFj*zt9Wdzu zlOE7H)KQ0KkAr5190T?hgJ>(F1dz*%$QjG}~!CaM?pj zk9X?1mZx^=xDTH1)Nc*PcFMl-%-eKrG1bC^0{{c2l`y>n0E1AbS7f~OV|qoVS7drc zCOKeoMZgM}8jss=}%{VB=OqrM|6Vod)$pMob(1XH%K@LKD^RN6y z?|X>`3HYotvJ3cc?Tww&wx15|oU+aPvU50BV&_mU^EOj0bi^>>z&Ml6v=XLwU^-0@ z(+rqqz%&D<88Epbof|PZGLs|IalqurOpXk|fSExvKIdh6MW$C|dPOEVVAd7sR`6eu z1I^hXYN3UJA7(Tp|M9)dPTbp>=)GxQqvG%H;pK5ZdE?WJCD`Qg)5EX-eD3z*WN7$4 zyQ6H!M-7hNIGK6p=mCq9vjuUnS9*@``O#c&5&*%rTs&64KB2l<9kTwYwI2k!`*|m8 zWnP(jphJ?0111ibIAGcV(+@EH0MidJ{Q%PsF#W)P?+0o(r>5jlTyc2X@~2Ilc(_o) z3a62CsrA~-ZgBX`He*p~l^~+qwuY-foBCY&sC9@ZCn=0vp+-AlYFJGqgT-n#$pVr! zWXVS8;+JixA^h(8VCdl!jMFH)sul+w>#HlcxROwVRfoXM2W})aLcNDde7I}28|p^8 zPhfHg`zpbVgr;_{%5v{geXP`GgoJdtjnWbciFkiHX#Gp}&H5ghYVT5K;uQ&Oao}(* zM4T~tCA&6PO~IklJv8FVLrPAJLFFSsTymv*Y2Z-X=*on)A>2=yz1H+F=9m%_Y1+ z;cr{d7wFY6H{p=L(cVwQM(uEKi$h=C&9d9w!uxG}Ejx>78HQ<)aJj2oj=KF1u3d%6G#dB&v{uar+ZI2i zpCq)z!MBH^>Jv1mug(cy{;Xs=9v$z=uD_$SLT|zfo&%cdW6rbxn0<1-S_RkrC3gMO z42>3|E77QZPZxsAA9e+G3xB@9mtOm-opoAogP+^?`S{jCMNQ7+!Au>-B5iHPdq_D} zMlUpG}+XD_R>ApJ?7;_I& zzkiy1)bX}B#jmNTetW0}HOc3{Bf~4Nwc7pl;u>D&JnL!K06~WqW=U~|o*Y$&=s*bl zrtGs!8I2-H8@Y3vtaR`9&1-Q{#Sxz#-h=h1Ax@?&|NyywJ9!N-I1Z5N9b0=VrR8Ob-MV@ zKzsFQ^9`fX`U(at-2PrTysO3AX^*yazMpsTYg^6+m0@ryCc($RldI|gW5M%7zJyl> z=&-Z=kT=F{;N=|+mHPl-4IG^n%C%(Icl)N?EFo{vriRvKOkG|K?Rk6-SNA$ve51K6 z0>{`!%^qnrQs%kub+65eS0)|i)4dtfwj#gV$lo{Lq>~cDt7h%kqLQ#aHAWW%p#@WQE1#~I{RRDT+Sk#9+^SIA9y&}ljaFt=?ldSRzH(=8`nz$E)G`;2~4e~&1H zo6Gx6xTWKlX%gVR`t-iirU9NsV(o{14oqk(Pv1wMUE}jVO`iu2a-?@|G(WS-YI1x> zNo(IDY9PCn5j0?3Gm;GZFErDUnwtsr2X@SktaGo8# z1L5+!;fjfc9vW$diN9BQrv87? z)DNO5d`@D;QbU{20Q@q36}eTjNHC86Mb>=&0pt)^m?Ymw_z(B2&D4jrVcR4Bv^lRw zV;cBTJxc$n-EFMw_Ak1zmK!7wX8y~Bx~e7FzbI5P{4mz}+%HOu8vWv#^vj+#S}FZE zLp2tk5{H}K|7Cl5>z@-8e%aEP1~<(AZ2bT6QU~57!(8tEg31RR;_!iAm+C;2>8Bv8hw|o{-7Onbr5dBG|#YbdD;&%{4)~hWJId z-!l)wR}E|UihkLIy8#t^EGvudW9unrf6;r<^<-Ez?m5Bt{jZ~(J_t{N1#ADZBU;Xf zM*D!SAAjwNgM11)r7o^kO1je*PFwVI!|Ma<{*&x`CPc>JU(nHb_$y{JI=ytukN3kb zqewRLC&aBDglj1M%M*YS_5a_L_#gNC-=SG7rA!`t|BGJo`Tqkr!T-8R|K<4q)1~$n z|M=n=^^2nAYpY!JqZm@ z{^A}UKNch;di)6+AFOJ+bIB#=v+%7xrKJf`&D{}Q(Gtu#USCmVdV@S`5f$buTcQyogpbiVe^bLtsmfLo1| z623+N&%V&+p^R@oyu__S4D-jX#ecJ88aj`do;Sno5CiLm0D@v8%*7HXtR`NtT?|Vp%N>|1uiUhnIJyp?y6}oF}6Jv}8pqa@h5+xW)9C237r@b9bf~;kOZrdb3 zCr>;ckACgR>iM&>z-nz)IaXM5pZwCVeC)mHE+|ZBXY7iFsj7(GQvyO^OG>O0W*}NB zLnjNOKtkW-Hc%W9PD$-k&$B4X-}m}f{kvC+TnUg;&tC8GdI@Z0GV2I}vEv}|sj@3F zoF!Wek4N!9X=80I`=&wVN11W?t^S&!^2J*Xwy>QPGc?U8PFN_I8WmRWjqg`8^V-0j zbLh+@8#`BftbQUP!z8eu0+F>9JN1^zxLEb2nWmdlKKP9-#C?D=&kK@q}h~t4!geAC0YKFpt)Z6Zs1jTEl*zw{J z{aJ2Eu>P`>wd@zDP^x<%j{Ft_6~kW& z6R!vi)IPKeTl+iDoWSwKyr-@9Zr`q-svbwJ*neZpvcFDV_WjibewL4){FV=01`b$j zt{zrpJ)tFhl`o3w`n%dUF45b452>=&OZ$|loP41*CUas;=2WLQ{XllK*%PQ` zukbXFQdjw&w7F2=cPE6-ABC}nn=Q|)m4dl>(|PiJmP6>xFK;h!aAf!9m*b_ODn}f@ z&eQjkzYJL53uUx8_kr}o5v!9#xD)I#))8Bfe=xs2dO*?j$Po+!53Xw_V1KRk7pFq=`A!15~ zv$XTvYnCS?i#8~Afg-HH%5GQB_K)FdgtHlms`fV&G(cfD7dX%eUv1I(IvpR&ta>&U zQ2Di|4fdgf$UXU8>n!|$s?($*R(_<5dWAixnD%D_S^l_QKdzgx#7bXKZRj*nwbT$b z2pbHaCA=osxmF`tK>Ws?Bc=M&Tfm=G0(RT7YGCPToX3{?${%B?)vIA+o3ynstKqz? zf}XS5d81zDz{))GObgZb$AXJ|D4TuWAbwR~Gc?h?{K60?)jPLTSNq3mwg@zw_Lii@ zP2%+6Xw~`#u#!g)!2ESfWaTd6jwYI`)zcapEn%J$;bV}HwJ1q1cJ}VuD~)k@tc=;6|&x+?sxk*KHXAh zZsG#K?rQ530!#`)@)8D30Fae(PqQp5c2a#%Qlu3k9f=bXLJyzO&ztkA0tBi&t@rMa z-57)BgzDsOql-jNweSQb0o1&(E+PTWwN z&2t|C+Hw^Q{_Gnog&MMTNzN6g-?xRvAfcd84}?kC5L(H<64v(rmfpHd}bXb458kj3#Vah8#X1Lg!gJ%=x;i#KXk8E z#L6f*RCQ#tg69A%oarhpJpCx$HPL@)xe56LU48C1e6M+OtdI^Y8P^k8HZC}wm{VF( zit#f0ef2etwLKA#{)Q`|?V4$H2vrPGf-7~~y2v_1+xj2|H?haRv`BcIPZR*92`>>; zUp_0&_6+v6$cNQ+TG5bK;^oMATXt5%+sSUmK2_hJVH`W%vwI&86)st3sBc%mMhn6p z`bn`L`3()ImKMt=}w=40i z0QOyW#Jt%Rrz|V$bDq|$5%+CIsLby3>l>zVUZN(49o2)lKp;Ew5a;tM7m34VeHZmR zl9WY^G6lNkzajT((wFE3LyeS)beNoY^5eo0mq%l3j_<-7I_j1CT|bTsu6J;U+%1dn z65ZhYIo9oEZQU#V1x1}R@8jQyq&VQR1Vax4_J4(oN4WGxKs2ccXEI*1T^}NLCm`Cd z5T1h`*CAw!_Xk`JQekgxc&C>NI2MyGho~r@tF(#UZ-cXzwK)ikqZM?y&l=l0dA2z| z0g_wa{k*7p=QOp!tkhzz(%NY8(;IlTlpY0u^a z#MjS#=dbD!yhUcEV^h9`@%)Yn&_%J=`qIY%e8*#9N>!QF6*5X=>l*Kd!XamQKzoU; zT{(8maxY$hpUh10q_kZL%3tXsuz*4v$299a+ups{U09^PZRsf&(snpLrFq(sa@G9p zoaFIJ7jJg2?*Io-Hara^qQRLf5h<-u*!4JYTM}z zI3Wxvzr``N1w8<`$HZ;_bJ|hS{Tl`nhJ1>;Z{KuxKD83VZ^mQ+p<0E!A z2vjyzmK>g6qzkrjsz2aI%oK^YRCLIp*e`(j-^c`&VX3W&K6>@T9r+*1R<>uJ!#k&y zK!BD+wEcHsTd($Reqcf4_-ECd%kuYjBiOw@9c)nbg#{_$#o1>g4Z4Y`4W2^qU5vidJ|#*sRYC zn6@NQ?l-Tl(A`6ZdP>;gWj_G<`2KDZ^q3Q3Dn2>(tp3wR;_yaVXH8j0>_owGPg40S z)&nfMbR~SK@s#e@znTP|lXef1BET&%aa*_#*^{y9MO)10GgnQJ|?4u8j( z{TPV;G)qdG-2LMx#q4O)UR?B?sr71UQaCExuKu9fA6@x#4~jf)*Hpwhrl?Qmb#iS- z9RT;+f9%mI>NnhFi9Vpp8YHZC6owS%bR<4k;9Cm+#DKx2?erp?(DZ}qY}NhKODv$; zy)iz*S;r-}*TP!+)*dGYkp`WH4I6ZS=zb;vz?$)e`WiePnudjT+yY$esAb(oXPN>} zML1sgG5gB3inx$*{_F@};8LotJ))$1d0=N5r|RTEwYB%T#vI*C+?IdW z#q_kj!X?IwJiD_VPv` zz$?v`-QXRULw)nLd-ABa%{Z0+R|I_Ln0T8}< zR&3Cbc^rZ2o-+ zx7u&7G9OWjIyVX$>Yhzs%smb9aW;hTkj^65)8qj1tSwmWe)*pl{zhF41VW$wJanNH z5$UFgK*i${oB>P}IvQR(1IHO5%&EbK+?v(^$BMfE8-IG?&$-5Sg({LuAomriAax*q zwCW6#D+Bu?XWtq4sItDM>o&bxE6D!NK+Ioz^M@h8I_HGGf#FHJzy8(f7z`=H=};ku zzD=qS!q?yFC%Ih$g%&ql3bc1K_1;JndZZ3Q?$`o0HTEyp=B5Ctj)*xy_hAXtk{$v%&XSm+((9gXY+%}Jh1ZQGf zE)U%Qo?)G9+nW5U`{xcBP-ayVyR&TZU_~Kz%^v-JIw)jGCEOEqTx(t0y-y;0BTSe6`ehsm)0h6a;vF zb*|YKR;8xB&bzTgr{K?)*Fm7PYNbyo?4WA_k%lIY_vzM`srDv!3{>molqLGM;%J5LIUiH*j~Fir z&)?{wAuX;xAkK!NttW)}pSoB`K_vMW51O240epSea9j4eC;aQAozc^8(_1kd7jDH3 z^|AUvKp&m~P#@Qc8!3Zd_|sV&&7;FFJ8hQ+{`i5whU9~Y^ zq=|c8b(L+(zgRhzC5DPJ?+2v#@RmN#6ic0_8UTx51QACIer?np2aF|F?02ODvMD77 z`9ftW?PcfspImiIX*0#r1AilHv@PJ^U$MEpKHRUcAFj7fE^Q)GzBt+k#gF(cFyb2C z&!etW5_Y@6WkUBd-XzyBPr5NiO|e4j#KGupit0MnCi7 zpt}e-`NR>K3c_M}Fc&zQm}w2t0@uki^0hIo3Wlznd5@L|sVWL3+@PaIyW(eftbU*6 zE?A2b^u;}Oy7kuIM6iAaE-OIDh)WHEGDLI*UT+ET`#WKtR4Z zv$l~oq8!gwH21W4j_vDQ?9Gf{gmWQIrWhYEl`yfo;1F=I;wdRny-+Er#Tbt(5oGf{ zj=UQXQbL3h3iQ1fJgE!qJ$ls)cRfcn5TbLPHz=;qv>K$V~fK*F_XRyPFWK=Ia>Cc zm*8|5*y}vN`C>rir`qJHDJ&qi)BaL%LIEzkO}NOR*0>h)c30GooIj&{_@|5dd4kf| zJ?2V#;xu}btKQ%;dRRul0P2w+*wF)j?g-xc+aoo&b}Wkf2Ns~0t=+|_Gy1d9vF%D# z7P-eO;e(HSy~T0JV2uh<5dNSlE2n)4Ib~-L6*XOa&CZFKN+3iKR;^iBAX7#N|J@a-lQ{xk@nH1@Qa;*gi_=vXr%mch1 z)tFX%HW!-#Q5?1x~K$|tY^b*?g+Sf z#5u~rH<+p~Y8l?yN>}BoL_ri_+k=%KeM)XG9s&e)&-QXcpncHpe;x&CmI;c?@6XDpm@N^B`*ChW3o*EmgPQ94!DJRW_Z~ZRDA*ntKJ_mNWz6b z5j@W4P2?uU36HFE-|hYiB*k(Xq6y|%FM%1B-+j29NA?J7+xo>sOAaX2E2yTL5{4RJO^IY zgi}?Mc846n<|GivOWH@eWZ>O#f90%ncL|n-@^MrK#b9psL9Bu>kY>+nUJ6wJYASD{ zSIn{YcT9_Ye0LtVDgoHX*RI*n+C2$f8#zrddk%G-cSM{w(J zKYZ*HSY*-kVu*16s|eo@mju7RxgAGH=W|px#{+c(j#mGRC6045tA#tIhT71;pan)P z=?l0Iz*FBWOw=Sl+*&G&CwknCbcoqJa2Uqzb_MH6g8dQqG}ZR`abCglc!-O>#Z zqnI-P^@=i6B0n&j{i02e?WlVNyJv0eMpbU}dmTONn$@v@ zpl^>$>azaux%PWX+fFZ$bqD+uarKsOWYIe$1SmXNx&hjconCFx$wJZ3opVS5S;)Ro z`4jQ&^aHNpaG;{qS~ui3#a@4Xie7T7zp}vb`om-uwOagaQXM5gN`T7>1EQ|uRv8$EBXeg zN}gL(AjL{*Pckq=8W@n`pf*UYd@tk2P5O@#8|#giJT6bYf&^m7=EPCD^2FHz#>sR1 zg{m26dQD5%&GME6@z0ZMy3bmHn{JB$u+68xZd*5`tKpAS4G^Eci`F5VH~8}6%{PMR zRc>)U;CYG_#%X!iHc;7ghmrEfM&=I#RbAiYJ>XULijVBK1B=N57^q09U*HN^T2lAqIilB{ETQ!9QB-+yJ^0A@_TWUT6|5(qEeI?K!89e`4J+-SQ57yVGW*|ddSXQi&!s!6 z;Oz<>8fIn-_YTzbrgZ-%dx1U<00)rU`R6IkMXSMj0 z-l8{>{tCH{A77DC2$=k)+2>-ck4+JXgA;&>H$4qcmRxZnNd*T@x)#==9a{9TXWG`g zpWcwAE{UbSsj~3ySWn>F^c88F6uXh6=+Zh*T)c^Fnh~6S6o^HJ8N))T-HJBeAP$kg z#}h2-NtBy|Ta9nrZs=g8tq$}nNs{Wl#rPEQFjGS@s|Yt0+MSt`O48PWvx&i0+waGQ z!B9Ru8Gob_nq+6lTH8)XIbgh?+HaQFgw3ebt$}RgUKKh)a-JDw7j15AFdNVitHvEl z0X$$VyXB+59~g<}gJ7TF@}bH4!t?6^hDnhr?c>-oSs^iSP*;C?r@hmvRW9dAmok>DQcXt2(&fGUwcl7%HoxjvG8A^j8&B=@EODl>aiC2$mZ%kfbjpL1L-PF%_A}@|neHGEm0fT(0E;0(v zYwyQejqu;*3GbIq2W|T6aBmX50=tbiX~S94bo3XNn*$yUDAj z-}g{7b#;4dOp%>D& zdMnVE+;kJgw_hwM$0Mcpnix^4n%HZfieu$qW9anWLZ$Q4yw!?Y94{dzDY@0ayUrCU zJ*oET&)zCZ1>|&+@%mO$pRgE`idHIJwafpZC&SCPy)rXP$=RGwhAhu2t<9N51XN4E zkqk^PT^l@W?A$$6qJG~`Y&r;Sg?MSMkK2(6Jb+B%g=LV<7peWm%BLth!}YO&|% zKYcsdYvW>wH5A!PJ(T`_4k2_nYKSPZTc!E-#l0 z9{&#E+w@sWc&@ol4xLg2)UTC_Tspeij{qHyDY)CGmgRbvHPZ1HgUDrF&0!=@;E zTA$S1ION{U+ORzoQP^J-wBW~EjnTE20?3l?@8(!2%_ESP&F~sX@RFPGk&+Oj?M3>@C||$)Zgb257N`nsBH;r5pc!uMd>EnBwn~JM z8ocZ$w-W7HupvGv)8tT(L~NeJLrg*_B$qz}Y9YcV{LZ&KH`*m(78^g7jH%J4^KCPi zceT_Y3y0yRi&lpF+t1RS*353K%`^aG(bnli3F+;ijzS6Ulw2RDJ|o`DPhQss5taP1ySsm(=XPHr{!kB7af=}pX@d6Gjd8LeUz(3erQ?YIEbbaKV-TN{nHsDd)Sf2Fv{qPUB zwM>kNK)wX`yABM*tIWaqW9evi;GF_Pd?zJ<9kK;{I= z3SOiAU?&BX+E+X?>3DM7r#!fbM(Q)8462Q9JH?)gf`6NFxVAsStHq$ELOM4Wi23tg zfyQ;7=xQCJgR@!9Ss~B$Q$|ql^kJ?gJDWdn8Smq~RglIDftcmD##FHD1$Cp->bY5b zYCRYsRAtIP1lb3-Hu`pL95tserWQ@4c76HIm+FK?dUxBDJn~LY8Sxw6z!u2)-VQmF zo6D2#)gPw3?F-1)bknsBSr}ltjoqc+W8vdMLvMd=oF4?->CG4o!e@2s#;xV(@EVNwAz@#Y>O8aR7J|y?%4TchO6@ z))IIjZk}Zkx;d?FT2Q{dHPLXfPZcN)#NmS8b!)6eU<%8%GVyB>PFrvE7R~pZxCle? zRr-!C)vQnOfzo)~|1_UXWOHhnnYdPDk?4i6hT=ZOd~aqRf5eJ|ZW!vVkO`)T9@cQ>ia z4BH~W4INjkOc0Y*x(7Id9(3{H7%rn-K&jZyoxCCxf>=JHd!^w3`?yHI?**aNVX#m^ zziu9+M6N<>iUG&m$8HG!ht2>h1NH2O5Q;-@ySuw|7lbVy6c;D~Ued;z_&n^?c-q%` zH3)PG^!ggZl=i`iA|r~lba6ob`7&o+1@+&?(Jmj^uwuwo-#}lh@lD`}QK-*V5Ou14 zf1#{gXuIs5 zt_pbRDweilqrj~xKzGvu$PvGKh@uUpkmPqE*YQz5MZS*^iIcD90-9C|2=rGvp8AYvFDujYm zfONOK&22aK;Grx^4@CJyZmxJRISF_J<`hVpM-}wH6jUYk7RcmQjg8@f!v~;c*Xh*M z=HF_GNWor`A!V}EXEDZjs2IEWX}Jfwt&mH+FHR5nrkqb5Ic*mzy}R1-r2QqcyeY2_ zs%BO9(^dhFj+e;PeG6|D*$BXc=78dYIkfZ%VNaY))kwHg3zFAoK6tT?udh@Hg~X3L z1G^G4TywYpD2mQ^C*Z$+uCa@IfxEc0xP-FxyhC$I$(#$d_Vkf5(%VpsacF@fOj}*<|rFRa2tPZZ|uB0sY|?< zzoaJ8a|UKX-f}c{Mqjy3beQWKPKvQ#76qvsW9$qYma?G=IX_x%h2h&Q=+C(=R1C23 zX4YYV)3i9$>u|v}OpIuubxJTf1cE1h382(RUdfbAuWb&;S8)MO{xjF+z8YZ&P*f6+4_P%+D+ z479h6C=aSos+|U3e=FfjQk<;$J!E-!ax5~+wP^;5bqYK)3aq|mz~^82_$1GhNwspkOwG5q@MbQWNvPM#R>fNO*)-F6q{K@ z@j4%T^s!sFB|A1^MMSD`8{=BAK_-|zP!9Z5tl%$Ovpg%o$;|@DhhdBJ#J)}J)+ig9 zZZf$}9ETR#wtbrcKJFXM<4w~CD(^%N-v!|a4vPnbv|8D@@PH^kZpoZd`zEzM;=|5o zio5|O1e*AJhmY*o0S&xq-$Y96{)FU^Aa|PiQWR!V-9QyavW~Ck>w0&fBDKqp1*G-i zTAa+c%e6Us%*Ek~*_{QWlR~Z%$nvd?F@PrEM{>6NmA>c>XpLi)C_V9xgTAX*8k`mJ z#(jP%xTn3;5I${m`xb003>0EfdC#YIi%Kc;s+N~}pzML5c&(3G&GH1OwyV^Os74g! zYMg5m^0iT@*5He&Dehgc7&kxu5D;#(z9`jj_$H83thOZ@0r|U1(qWJ#Iuc%a@O;+e z5zUs;iTN=d*KHK`9ub!(6HG1y+#e!Q#m3);&s7DAP%c~wBRX8%Zx0sGXxCKYxV9iX zUr8BuYSFy7A6{R{F4o+L&Z$}DXa~-(0V)6G1>xg?47cQY!J~De%d{NpvIkxd6$>#2 zSkOQLxm7ZFY`vWJgBw^x6mEaQ?aK4}cW=s1Wiseil`OZgU&+U<;OZxIvougq|q zUH1sF$#Pby&Z&7(JVc(`^%;n?7|5RQ;K6)&ue16@Q+6MA6JT2tjj5uh=hJFxl_tcY zM}W$QbkhDbpw5^^jD9_$EIb&1hE0CsX?QIm$o@&u%v(D@a5`6tv^e($xH(O&X^@bq zHn5lbqfMWYPm7kW=9jB|VgXG_a3xd_S2iQ%^}yi$`y5kNlcJ)Y#Ysy01m=q;ec(A5 zu3oY{(Uk5nJy=xt0|<4-)0E^`*VA0u(V&YdGH8znmf-P$y-y>~!I1vW4M`0Rd|T2& zV(&?w=r6y!X_(}GMAZPX%ckV4<=PD-OUHy_>N@|ETjw(56qR@Nh9zR#&epp z!#MrC;JKluDonB%aEW4U&k$^fk97svAT53cDS)_X1tzJ??OzZ9HrKbt` zw%z?r8+*wF>~=9CBZUaE0b&SHOpFE{T%m1YvTW)+u}BYE0gL6CJ@k*_L2TcOTfq_t zDU&|?%10fA##5^HV?Xk^(u98AzBFrD{o{$mIhMumXSbu=o=hpXi7V#M0SzGD)O3cRb3=`AGBgdy%KibBO21nn4<^e*jIy(nK3J8+(TkejuY#+ON zdOiU?93Xs;dXHHJsX$Q62?OjqIJT5W`PR~%kU*p$K$(x&X{xjmG@e;fZ(+d%H1zj!-dw4N-M#y%(q273_PabiyR>c3UrT-e_sU0Zep+52hD(>!hB(Trbdwl zC@QNe4B-y8dG%XOGX+1BuSvmQK&V5b&-yZ98BQe({3VGo*vF z9>}{|LU)i7mcNw0fI^VXN2B9E_}Kg?r;;J*U=?2-X|Tnt)ci|s`V0u5f7b`FIznlL zw!)YRHCh3aw%Cs_2$0|~(oQS4v^1hsCVT+Hj|I&pvt+F_cq7H$TWm)QcZx5{2~xvJ zhR=^b9;Kyqh{Mw;S}1QLEKU=@P-!K&pYN5S5(fSS7o0UpU9Sw-+!0`VUovv!vf;Qh z+H$0zq0&llGynYakrJO~%7=90;33IGH}r~p7vgbFf!P=pEq z1VyL-Kv0AVGJW{}GgJ`85`~RXtbC4sh^C#Ni|TVE2V1N> z?T`)MqN>o(046hAeV;Wd|~i%n;b zCV-#Fv&rYi^26JeR)XRi$I{1ZWeMR2mq)Y9iq1#V?h4qyeUDHG-00U5g{qByMp77= zZ{ODx=5_SLqr$O_evwtU)Nh}v6~Tlem{5dKiZDtsWBIn+MiD?N0!T&ZtO%X|m6OS~ zGJ%YO0(TfU8{cCijPDJR4A8;HqEiwHW;H`hvzofZ(i*%p%Yy-n2qLUwWj}AqN~SJC5+Mc zY6TzVYxEOXJsY@WtOuJAC{XgAu4B~COO8UZZx+fbei*eqo_$I!wEEI4{iygC(u%%r zBY)5A)6 zo&5w7G8qr(tQrL1B%9qzhl;g6l4~ceqd0 ziE&|qbe#8+F&H*(f{gOk!&XNlW-!8h*!QWQ~IYs441IF1#22#qqf0xK%zQg9F!wUEv>{@YrmWY zIP}XXoWtVw15%W-z*#JsN2KDSw?n8n= za-cCBF|)+_3m*twTI^`>OgS^HkV+`c`jnQ{x0udDizOSnmz88HNqRLTB|0jS?i8~0 za$(;eEo2kxy44p-r_^6HtuQv+CF^}!R*Z=#FqqkcblE}=`o#N4Pbj^>$6CM}O)wiX zF^lFz|FM}~(^&SVv3oh7;J0x|S3x1UgoIKlx|aYyh>(0W0JQg{b4$e?gRc1)qZNTe zl6svX$)=KfUkt!1-s9se-wg$FQYA4`W9bhh2XVk6wi=_aAdde7iR&=W7SPPYN}~Gk z{l?Tt-H*P2_fN(YsSX$g;{=&F6{f}h$cri+a8A<`73*MhLjx{5B8=7so;W0TGOxVW1$C&*KKE*5Kt z)dqSsj#Bnqh$IcLR%!|K;G|duwsQ;_x}}UuT+SE&#K^3VTrj$mJ54TiJlyS>yU2A!-c zGgl4L6Z7of=@X1BfZ(4PF0F6QTZC5A|!k<02~OTNblF+wG*mf6nwJ`&<|?JR&q#Ppybsv%!;0vDT!+*-Mb zJRc~~-(w0y8L>?NE_nXA?^f94LAh%|CNy{=fW~&)dmAJ*uU-dbr^@K=Hv)2PSvG13 z(?g-aV108NWQUKnhK5>yogJP%_|YEk$|(QtXd8rrz(sfceX3R>sQxT_Qn!D6j?997 zM_W)^XP4*Yp1Xl(=lN$k4CR@_@{wC%W&rwe`HYwWS*TY!Uzpst_FS?v6MVxsJVvJH zk4i1iQFx|Pn9kDnbb=R^6-V@n{jQx*r5oS7?5sIHYU)}|50pp;@HJ>$o!81WtA`xp z{Gu`0ZVVx6a-{B3m%o{+K#LBIX;H*XD7*-zoz>z|v-LgUN!*}8{Eo_XWHn&gSB*)L z&2dP-JEV$b1?he(v#oM18Ei;sc{pCicEovLJ&#Tg(inVc;u2fZ*d7EpVtahNx7kp* z%n$T6CjWT@c|?chyW?!aJ}eM~!n0$Fk@Ftv1wPZ2RcW--Nw>s0Qn$<(XmD=in5ZmT z0;yA1{2=;``_%yuVK`p30rJ*wFu7NJt~t$TdeA1Ia8@@*6`%4@x$v|!o?(5vq(a8) zfEBXWe~-OxQ!cD2a-{(85m6KPy2MzEXF>)+M9Z`BF@`|;k@Gx7OYQc$aJMX)d4}*6s0b=0M?qRKo^?dj&#=pIc5up^(o* z&!cs?5&)DfehertPiVOOYW)g!!tkEL1B-cGtr@*@0ZrE9Gzp;IaCM{w7Tw7Jfe{0s z&fubS*+*!AuCVyA?{t*)3n3F-bR!#tEdye_MKZ^})nWQ_dT8@SA03fw2helZu||ov zlpGDw-T^D#Xm%$gsQREBv@BrAm`cn-out=~m(Wj##1S*2$)u*?=y2X4GRc<)fC@7o zbJzdHGg{%yE44;339m?<`g7XI{R?YULI&HLTH zY2}e?vu-~4Yw6D`_ZDAqyf_`U`^f66^A^6_WV?I8-+P}QAZBRt0yx(3{_3AEY=|a@ zyR6H0t~KcOjP6@@0tmDzR{lk`pjsQ_G+ckDvMuD8&*_ofG%GFSUr!yj2qM1sba>KJ z4oVY3XY*KYoXXIRLO4G^faWPpaqx4l3GG`B40rCeHx3J!@z-a6+nN(ZXF=XIsfZJB zt?mDut>k!RCL#%Ehu&6pr|J;xVSvGlz0UM%6!VkY-hSJzgM|*u2>N6-NAggge%$uk z)am_vuyYRB4Z-z)^)Ss;X(bq-!EAG1P)^*wH zgl{G(>6B1(h2qh4Kc(K%7m=HEmYHLb8fQs7T9M~WBe8M%NqLMra4RiOaqf0utDe*@ zq$#v^4XGgcejxix?RKlmrZO6-O+>BggC>Q^V;ThLi7yu~eb zIGT>>%XSkrM7X(>RTqDBCz~HV9N4+1zOJLmas%pF08m#`n<)UHmlbWF3Gpz3J=;C| zYmLdlg1+tPgdNjtH@gPiq;U9A?@mRHFhECi|cERBP7*^I3(j? z<=~4H`@^CAk_;>p{X&@9^})3s>FjK$OA2ngSzCJ%nfavB*w>9IXv!2P4Z#3AewhOM zu;&b<;8&)VOY}WI)6RV3Wy*yM+Ox@vDhULp2QM6zI=k|9+Wf9;IJ2ov6H1nHOi<## z^8VVP*hErO_xeu8XN&=H2N88o0S?uvr-ysaCYO(v!d z>9&zyd$JRaU0y?*_aW2{x*XHVe-<#*ew}H^%Lo~6#AZ2Q{e4)1+?q}2#F6K^-YrQ) zAvp~;s2zZf-{In$3O=aIP||kY56-lJHSZHZf}*a z&M0&b>*5P1RwX41aAS%p^)}65A672R970oH({!p2(1M)YT{=3fX9riRn?ZLU=}8~6 zT%;lAvj-}}Uj|^ls)YfH?52>kV-6JitHwcu9o%W)a;;3MsKVxB7*;ciek&YRscr=| zND_a#0PMZ@x+yex&zM$7SY-6c0OeN91$Y;|xtxn=2DeT+@du$ZndZoFt>ZFD*ewKLy6BjFf|-8u_`2Xd0S z(s1To33S4_pltt-Lv@@%%6dc&I?gY&v+YYZ6F9@EQme0`j~MLbFXs<-mrR&H7$!YMZy6c(&USX$X_P1Sx0^DTeW zl>=|K?r9!!^)xX^0B<|4AfMf`rHm2jT(l0s`y@%R%q^bit-Tje4b)^*b{M-mXfZTj{Bs$HIF`MO^5ROT%dI4I-+ z_ziF=aQJ_SL(GjIxEd#I3(UxK9THLeLHGYGn9_z?`l;7>^LwHU&e~@Cl_}S<=kok2kv$E^r~^X2v5&)b zahvbjLwBonV;{a9P7tz#pD#6bvvpZ}Ijj#*1?^fhWkAc8)+}t#PV{Sj@758y?3tOg zKaeG5@SCl7D!SJ8jGwIunTO?^~UEV!c(pa}uDU zDygKF%`sx;zA+RpAR?X4h_1o(}L11Bx^gR zHQD-l3nt7Hy=Tl>&>;_ZrZ1YH@@nZeSp|zaz^I`DAhhnf%GYqvA>6`f-FQ8Zr(zQ@ z0<+W!^Dz&{R!?Nz!~Av`i|*Ov0a+_IJ-V$y94Tkyt%2@g6aZ{_)P$~k=RLyrnVVqT zHkKS%Ykrqv7{e2_tu#>%seZBAjr<1&yY2LT&mFHrC@) z(R=GMep5yT{xNy5gs*I!{gS8l7j;p&!|`~Fy+D;bXZd3bZ&tJYSWY)52UMQg$m|<&GaXGMVRXmvmG>e}kAa9gtpY?9|(GMH14^`JU zk>xngEtn{BQ7a5`7JYe)AGSl)4%PxYf*}5*gXPVJYFt7Xw!xLFfn^Ex%Jm$0;*-q; z?JrNCAWYByIk6tcn$=&DLwk=;WyR)qa`U&aG!5_erHe9{IFF^RXwFQ?_S*cBWuM+g`i9 z5$(xl$%dCTVR%M6^B4u~j%0xL6~d(FXIk`b1j2y;dTUG=tl1xeZbYO={m<%4zh(=k z)&j2Z=fNV>Mdu67!XoqH-R(2Fdn`%fdF7=AIz9AM%g0&A1B}@ zJCbPCyYWb1C1`NZ)p2<>1;4M)n?O1Ez2N5w)BxJo?Nku(Uq%3Na(Wo>^iSzUnorts>=sBd*coS^IWhSDW$Cj}T!=imH*7M_j-ub7W|=wfdUW8KR1o8Y z5)G@CTIpuw=1>H6ITYhHf!+W7ok$-Xir4sD2{=O5tGzJ?!bm$CHf z*`94BET*M~-LUjjL4){gPsnCnSvbLkRZ5F`+i&S+LlIkF!*uh;?RqUU>w5*5o01* zvXt#`v#0F zU9}`JaYwuf3&yzao*EmY)yQwOvI{V0oeCDVIJ(@5(jnF5-AO~AHz$+%tko6)l_qFu zP1oaE_tf<|_l}6WZ|gpL;Z&L7Oiri?Rz4#VQ*uP&o;v#JW-|InqKP1_j!c&^rb1W8 zA1kb?OUxGD+HOHQX-*pGa_jz@m0Ghm!QQU-V_7W-^{uqT^wMmZUm4HX(w@(Nj=ic^ z?_P^V9?6#0kb%qPd$TIL5_HKdBkep+hAOJVLfi?Sd$JrTo4?*`e_Cn@Qj%H25-iSF zSTWns#md1TYbc>TMLY47CkA2G!x<3O=vcxfZ~C(NT4JV8tq#WLcP7~e?~zIshFjx5 zvssd$_#GZksUW2Iw0lg1mn~9q3|>vWRvP_P#jUd<)FLA=nZoOnP(0v(t1s_wmJrAT z_5po}XJ2^mQyU8y8C@6){l~tcAW0p-4r;4PNe$OJSp`Bap-AU|mY1D7=?G%8ZkeNU z;h&UDozxZiEv2&fBpDVQ_un=7aDB&Oy z=F;inhubJ%*d=CJ>oNxtdIXNh?H#u{58o|@lKDf{yp-#)3(RuJwB}(;GH})t>1a?1 zD@)Ppb_>lL!l3=mXdiWlp}KWav)$`JK$&dk$5(R7ZMS0RcqArzG*r&6g;Qy29}inDrDav9d)KlDHsfWGBefiRnQ$L)joS4pzs{ zXZQjYQ9m)xKT9P?o8TfUNRS^-#IV~By|24t(zA?-39f#cp5=rN+?frcara6Q-yl(V z?9YZ!j;Rmb(fPhg*y@5%)@cEPH^_)Kc~|hAfvc^<7tE$rFB9iE;ViM}!yMTB zXTD?u7xO1nS>x?M$!rkj-4cTKuj}%WU~VX}fM@a-Qe)>VfYx@>1E{kz zbI{?wl}4GmxPys)Pw`5?W$qeJ{b>#YnVWA1+Yj@9*O|@DDb+&1)J4{G^Nn4cN)xCC z5f|vD)2|Ds>*{`1a@-m)K$0B#Ri#~Fi$Rj+Z--Hzl$!@0pxls$1sHbF}Mc#2nypP|0ZSASZe`LY~8 z_5s`uG;l?=svPzcxrQ)r#12m{Jdk4F$Q35zHzcz<=YJ$E#hhk#6Dw@oNgyo&reqUs z{J}dLLvt7M{KGxPj~;BK#T$u-v(m|5O87Z40Uj)Ou&QShP<^4gkex2*#FIVASfF88A>zJq<`5Tno{3_+76RHcm?7**>uP714ZU;wbxwX@ z|KoH#zZjMG7(e|`qTjxazZ^vL9zgsQ$=w$Wqp8)43S7{GvF_?_9o|2LIbep!b=*9u zadi_Ew;?}8Q1O`5V=E+q=`uB*c3odwo$7w1{p%6NsTXGjk>2^Tx%{O&|lk{0to% zsd^{pvm}8N#5~x&JG3vhm|9J;6CnSP-szlQDF2T5WGt-9KfMI%*I8ySLG^fEDoa+g zF+>=U5|!PxY}W(xg!Fm62y%Kl+dlu5A^*~mM7(q( zNm@mb&0wYKV}=)eCp`F=EI9<6-J!4bWb-WM2^losDOR2y)bY3rZ&jXlNYf|SzkII6 zlfB|U5Bk@htv@c)h8jZI4>+uHWq0DE8qGf+A4}Q3wBlggqoRcYr*Y8a{SUy{*IIS8mckS4sTg4gO01m}@aR7v` zDq-NS;yiZnIYV&@{YoGTievvl4)X5UnsLQ>>_8^||2#QOaW)`et>SDz83+mqmw})- zMp%Y|A}j4PE|1|WPdR0!kzO6S*M5+v=b z9bm?S0x}LQY_-6ld#Dx(G;U=K4n1UM5)xcG7u`F+pz|cD0TMMP{k+7SNe_@jG3mjQ z3ML&(SH3eTP36tCkB~@u-BZG~hCg@GP$u42I|{54Fhc&at4h{mTft@Xw89EOxi&6n zW8lYm(NcfO4xBiN1Pjp%96!K8miO}ZEg0^^=!@Tm#%TVfCqc}Wknw_Q7fD~QW~zaV^D(w?@>4t z70>2-b0r-P3HIpL+9Ko?J)6b)nh|0@D3)!;OMIjfuU%AiiwYaNs_W#QAP2; zjvi?_HYdd6T)r0w-{>6)|+qg%J-uG%&+u0VJl&PQn^ zN`L7+Ko9!jts0p0#c{&_$>)8d64TFP()+4*Jt~Q3y%Db9YF`Md`Bxbl?-OoC+ctJI zUGR5`IxkG`=w#v<^R)yYe%{Yu8`4*DrXg;R?pv2@MaEkz6JA9Pkr&c3?~xBO5z+ev zE-h&_>D@baNRA9wN1882Eb5ftjf1aN1-gsc=fZ;p0xKN6d8U2lqy{^T1L;oTGotWy zMRP;CytM;~qZ|9>2KnyLzXAmU-A0tr{F@ zgS*}b!kfggUF&jc>Tt%A@}CWzKJxbl>E#}qgzLfJPD17|U7AtI-^;Z5B5pY}NjNum zf<=P0yF5ygx#|6AZ|%v{4SXW3fM0UDu0bP=!VZo#M&Z%hdE2zbj z_-(Dx-cKiw-iTjCGT80x0i$o=%!r#zb!8?=cx{(sNe;K7|KAmp^M^$rQ}7t+>hQuy zPi8z(^fomd^>)o<^7`fAZOtf(gA1dIj9Y)2JaRsf&i}aUWQqUqdyb^G73+O%5^>4- zQauyojE}kM%%(3>DhF|NjD!B;%dd7ZT5mze{D2^f+})D|?AVIoDmwhqS=(@KPyf_D z#i}a|{?p4pkC*tDO&R5_-z{}JXEcmo zg$u!~{~mn->-)=i_*LH5T*@7dKPH0c=f1$oS$Y2LHn=$-e~*ILd3UyhkCo%XY}9#nPWS= zf6j-FRp>S{bJh2n+@aAoA7i4?huyq)RFT_N!XW7OPZwXlzKR>>zP`%4w59Ev%UC%| zWyK!RI~;jWzINn~qsG-hX(iZu^6r7hrZ#O!$fh>q(~C|_zI(XoF=tjC;`yN03FNhvu8+_Vx_TVmp-PHC)y|5VM=_NIvyfmg#ilp`*)VQ-n zttVhAK=zu+^7~Kp zxZKeTC!*B-e3oQW0|zg(mTSjTrwAPr+vM9NocK&N3 zJ9@L_WEJ4{y_WtHOg$0$=U($3%h{z?d9b%9Co5OACLR9yvh(N9UJE&@8mlHNWw1zM zMfenXU!4u7Q0H#iJ-PK)Ir&?f1A3h7JoawH+jGCxrMHP&c23p{Ycq9X%?~c0tGyO* zrfd8*sre5SegA+4WKpc0-(EGi2{Jw)DNrx>@MQWZES=C#mt8)8@|w^2L1VJf_&{LY zamgEwT%St)g*J23zXp%&PJDctgH^V>RPwhEqgM3_Lu%W_R?%2LiHNnW*>Dov7FmnP zTO5^G>*YP5Q<^6%d^~TGRfzTRmR4>0!^tIk**ikv}TPK4SQU>BT<~;W5~I= zwLW{A&t!YrMo&Lp*nwXsQeGTv zX2)7r-?NLc!M%g6d8q=&r~^r%cnhOmN*z*@gvnh#xzB2Q0};);sD239w^V~E$TZoO zAKWfx3$J|qSEn2Y1a`R>v7>6!8OGb@{vNY%49Wkc5Zih_Vv_N;K51vGg+&iXwI(A( z8M7(F=e-01MEEXdLD7(12}dJf=Op1M|3K+4>FstxsOe!?H#d1Zq40LXhTc+bI!(ZC z2)B`6FPhvH+W|DYArZXo=D|C1=3efGzV)Q?) zdX&|yXAm@f-@e_yAOBxH5C!oNbVI)S<$sw3Dj4@)X55D5Hl2IdL-MQ19kG6zDY)H# z(&z<6%}V|d%BiP;vwFe(?dPI@WM{8|tL3BHXwl(zcnSfWRwTO$hbT?g<;S!AbSN~x zZfXnO!LCWmGUR0;k4z#sP7tggSa;g@i-(>qxC2*%J<8@s5T8SbOZv@H2z}ogW@hXC zJ(RNwOa`C_k+sExUWK3txO#(n%pZ@oBEOIUFy}5>`sf6 zV)KEIT&T1XlzQxuk)XLKI@8Z-5%>ibwcyv}eR5fMg4ao$p+j_^C!3<0j^P1$<4 z$pueGNOt8H)p~s%p`qKdr{|Y~ly5J%pBqnC;iiG}kipdutjq7lNsLDhrn6?@JOY$8 zFj6sSm8tx(qn;r#mqv^a zxg!U8pFX#&HRf=ZpTC7 }, + navigateToDrawingCanvas = { _ -> }, + navigateUp = {}, + homeScreenViewModel = fakeViewModel + ) + } + + @Config(qualifiers = RobolectricDeviceQualifiers.MediumTablet) + @Test + fun globalNavigation_showNavRail() { + composeTestRule.setContent { HomeContent() } + + composeTestRule.onRoot().captureRoboImage("screenshots/screenshot_navrail.png") + } + + @Config(qualifiers = RobolectricDeviceQualifiers.Pixel7Pro) + @Test + fun globalNavigation_showBottomNavBar() { + composeTestRule.setContent { HomeContent() } + + composeTestRule.onRoot().captureRoboImage("screenshots/screenshot_bottomnavbar.png") + } +} \ No newline at end of file diff --git a/app/src/test/resources/robolectric.properties b/app/src/test/resources/robolectric.properties new file mode 100644 index 0000000..4b38ad5 --- /dev/null +++ b/app/src/test/resources/robolectric.properties @@ -0,0 +1 @@ +sdk=34 \ No newline at end of file From 5ab2e3c2fd9e58a241cc137cf999a57808a6c6d1 Mon Sep 17 00:00:00 2001 From: Rob Orgiu Date: Fri, 7 Nov 2025 16:19:30 +0100 Subject: [PATCH 09/16] Move tests on different workflow --- .github/workflows/build.yml | 22 ---------------------- .github/workflows/test.yml | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 22 deletions(-) create mode 100644 .github/workflows/test.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index da3ceb7..a33358d 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -28,25 +28,3 @@ jobs: - name: Build debug app run: ./gradlew :app:assembleDebug - test: - runs-on: ubuntu-latest - steps: - - name: checkout - uses: actions/checkout@v4 - - - name: Enable KVM - run: | - echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules - sudo udevadm control --reload-rules - sudo udevadm trigger --name-match=kvm - - - name: Run unit tests - run: ./gradlew :app:testDebugUnitTest - - - name: Run Android tests on Large Desktop Emulator - uses: reactivecircus/android-emulator-runner@v2 - with: - api-level: 33 - device: desktop_large - arch: x86_64 - script: ./gradlew :app:connectedAndroidTest diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..4088df6 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,32 @@ +name: Test Cahier + +on: + workflow_dispatch: + push: + branches: [ main ] + pull_request: + branches: [ main ] + +jobs: + test: + runs-on: ubuntu-latest + steps: + - name: checkout + uses: actions/checkout@v4 + + - name: Enable KVM + run: | + echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules + sudo udevadm control --reload-rules + sudo udevadm trigger --name-match=kvm + + - name: Run unit tests + run: ./gradlew :app:testDebugUnitTest + + - name: Run Android tests on Large Desktop Emulator + uses: reactivecircus/android-emulator-runner@v2 + with: + api-level: 33 + device: desktop_large + arch: x86_64 + script: ./gradlew :app:connectedAndroidTest From 86c90eb8adeb6ce38c4cb280c787dc96d88ae3de Mon Sep 17 00:00:00 2001 From: Rob Orgiu Date: Fri, 7 Nov 2025 16:23:15 +0100 Subject: [PATCH 10/16] Add Roborazzi workflow --- .github/workflows/screenshot_test.yml | 59 +++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 .github/workflows/screenshot_test.yml diff --git a/.github/workflows/screenshot_test.yml b/.github/workflows/screenshot_test.yml new file mode 100644 index 0000000..730a712 --- /dev/null +++ b/.github/workflows/screenshot_test.yml @@ -0,0 +1,59 @@ +name: Screenshot tests + +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + +env: + GRADLE_OPTS: "-Dorg.gradle.jvmargs=-Xmx6g -Dorg.gradle.daemon=false -Dkotlin.incremental=false" + +jobs: + test: + runs-on: macos-latest + + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-java@v3.9.0 + with: + distribution: 'zulu' + java-version: 19 + + - name: Gradle cache + uses: gradle/gradle-build-action@v2 + + # Download screenshots from main branch + - uses: dawidd6/action-download-artifact@v2 + with: + name: screenshots + path: app/screenshots + workflow: screenshot_test.yaml + branch: main + + - name: verify test + id: verify-test + run: | + # If there is a difference between the screenshots, the test will fail. + ./gradlew app:verifyRoborazziDebug --stacktrace + + - uses: actions/upload-artifact@v3 + if: ${{ always() }} + with: + name: screenshot-diff + path: app/screenshots + retention-days: 30 + + - uses: actions/upload-artifact@v3 + if: ${{ always() }} + with: + name: screenshot-diff-reports + path: app/screenshots/reports + retention-days: 30 + + - uses: actions/upload-artifact@v3 + if: ${{ always() }} + with: + name: screenshot-diff-test-results + path: app/screenshots/test-results + retention-days: 30 From 84dabeb685698f8b55c194408e13b376a813db4e Mon Sep 17 00:00:00 2001 From: Rob Orgiu Date: Fri, 7 Nov 2025 16:29:52 +0100 Subject: [PATCH 11/16] Update Roborazzi --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 328512f..2cde4ba 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -36,7 +36,7 @@ kotlinxCoroutinesTest = "1.10.2" turbine = "1.2.1" material3WindowSizeClass = "1.4.0" robolectric = "4.11.1" -roborazzi = "1.8.0-alpha-5" +roborazzi = "1.51.0" [libraries] androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" } From b094154dbc75a00fae509fe2f1bd8606e40b3cdf Mon Sep 17 00:00:00 2001 From: Rob Orgiu Date: Fri, 7 Nov 2025 16:31:24 +0100 Subject: [PATCH 12/16] Update Actions artifacts --- .github/workflows/screenshot_test.yml | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/.github/workflows/screenshot_test.yml b/.github/workflows/screenshot_test.yml index 730a712..ab22381 100644 --- a/.github/workflows/screenshot_test.yml +++ b/.github/workflows/screenshot_test.yml @@ -14,11 +14,12 @@ jobs: runs-on: macos-latest steps: - - uses: actions/checkout@v3 - - uses: actions/setup-java@v3.9.0 + - uses: actions/checkout@v4 + - uses: actions/setup-java@v4 with: distribution: 'zulu' - java-version: 19 + java-version: '19' + cache: 'gradle' - name: Gradle cache uses: gradle/gradle-build-action@v2 @@ -37,21 +38,21 @@ jobs: # If there is a difference between the screenshots, the test will fail. ./gradlew app:verifyRoborazziDebug --stacktrace - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 if: ${{ always() }} with: name: screenshot-diff path: app/screenshots retention-days: 30 - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 if: ${{ always() }} with: name: screenshot-diff-reports path: app/screenshots/reports retention-days: 30 - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 if: ${{ always() }} with: name: screenshot-diff-test-results From 8111a8cec1ebec27985c66c3bf35e3617f57a46c Mon Sep 17 00:00:00 2001 From: Rob Orgiu Date: Fri, 7 Nov 2025 16:45:16 +0100 Subject: [PATCH 13/16] Move screenshots to build folder --- app/build.gradle.kts | 2 +- app/screenshots/screenshot_bottomnavbar.png | Bin 37965 -> 0 bytes app/screenshots/screenshot_navrail.png | Bin 34446 -> 0 bytes .../java/com/example/cahier/ScreenshotTest.kt | 4 ++-- gradle.properties | 4 +++- 5 files changed, 6 insertions(+), 4 deletions(-) delete mode 100644 app/screenshots/screenshot_bottomnavbar.png delete mode 100644 app/screenshots/screenshot_navrail.png diff --git a/app/build.gradle.kts b/app/build.gradle.kts index bc45ded..b99276b 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -68,7 +68,7 @@ android { } } roborazzi { - outputDir.set(file("src/screenshots")) + outputDir.set(file("build/screenshots")) } } diff --git a/app/screenshots/screenshot_bottomnavbar.png b/app/screenshots/screenshot_bottomnavbar.png deleted file mode 100644 index 68a61c88a3c07e13c5500c0b67507c2d58a16d5e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 37965 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 Date: Fri, 7 Nov 2025 16:48:32 +0100 Subject: [PATCH 14/16] Create job to update screenshots --- .github/workflows/create_screenshots.yml | 34 ++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 .github/workflows/create_screenshots.yml diff --git a/.github/workflows/create_screenshots.yml b/.github/workflows/create_screenshots.yml new file mode 100644 index 0000000..c48ead4 --- /dev/null +++ b/.github/workflows/create_screenshots.yml @@ -0,0 +1,34 @@ +name: store screenshots + +on: + push + +env: + GRADLE_OPTS: "-Dorg.gradle.jvmargs=-Xmx6g -Dorg.gradle.daemon=false -Dkotlin.incremental=false" + +jobs: + test: + runs-on: macos-latest + + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-java@v4 + with: + distribution: 'zulu' + java-version: '19' + cache: 'gradle' + + - name: Gradle cache + uses: gradle/gradle-build-action@v2 + + - name: test + run: | + # Create screenshots + ./gradlew app:recordRoborazziDebug --stacktrace + + # Upload screenshots to GitHub Actions Artifacts + - uses: actions/upload-artifact@v3 + with: + name: screenshots + path: app/build/screenshots + retention-days: 30 \ No newline at end of file From b279254b60186d8bbb8c5c3e3e5e6706eb36cabf Mon Sep 17 00:00:00 2001 From: Rob Orgiu Date: Fri, 7 Nov 2025 16:54:01 +0100 Subject: [PATCH 15/16] Update job --- .github/workflows/create_screenshots.yml | 2 +- .github/workflows/screenshot_test.yml | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/create_screenshots.yml b/.github/workflows/create_screenshots.yml index c48ead4..daca39e 100644 --- a/.github/workflows/create_screenshots.yml +++ b/.github/workflows/create_screenshots.yml @@ -27,7 +27,7 @@ jobs: ./gradlew app:recordRoborazziDebug --stacktrace # Upload screenshots to GitHub Actions Artifacts - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 with: name: screenshots path: app/build/screenshots diff --git a/.github/workflows/screenshot_test.yml b/.github/workflows/screenshot_test.yml index ab22381..0164149 100644 --- a/.github/workflows/screenshot_test.yml +++ b/.github/workflows/screenshot_test.yml @@ -28,7 +28,7 @@ jobs: - uses: dawidd6/action-download-artifact@v2 with: name: screenshots - path: app/screenshots + path: app/build/screenshots workflow: screenshot_test.yaml branch: main @@ -42,19 +42,19 @@ jobs: if: ${{ always() }} with: name: screenshot-diff - path: app/screenshots + path: app/build/screenshots retention-days: 30 - uses: actions/upload-artifact@v4 if: ${{ always() }} with: name: screenshot-diff-reports - path: app/screenshots/reports + path: app/build/reports retention-days: 30 - uses: actions/upload-artifact@v4 if: ${{ always() }} with: name: screenshot-diff-test-results - path: app/screenshots/test-results + path: app/build/test-results retention-days: 30 From 95f191f4906eb24f0eb6901591ca2567112e9965 Mon Sep 17 00:00:00 2001 From: Rob Orgiu Date: Fri, 7 Nov 2025 17:12:05 +0100 Subject: [PATCH 16/16] Merge workflows for faster response time, and stores the two screenshots for verification --- .github/workflows/build.yml | 30 --------- .github/workflows/create_screenshots.yml | 34 ---------- .github/workflows/screenshot_test.yml | 60 ------------------ .github/workflows/{test.yml => verify.yml} | 31 ++++++++- app/build.gradle.kts | 2 +- .../reference_screenshot_bottomnavbar.png | Bin 0 -> 37965 bytes screenshots/reference_screenshot_navrail.png | Bin 0 -> 34446 bytes 7 files changed, 30 insertions(+), 127 deletions(-) delete mode 100644 .github/workflows/build.yml delete mode 100644 .github/workflows/create_screenshots.yml delete mode 100644 .github/workflows/screenshot_test.yml rename .github/workflows/{test.yml => verify.yml} (50%) create mode 100644 screenshots/reference_screenshot_bottomnavbar.png create mode 100644 screenshots/reference_screenshot_navrail.png diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml deleted file mode 100644 index a33358d..0000000 --- a/.github/workflows/build.yml +++ /dev/null @@ -1,30 +0,0 @@ -name: Build cahier - -on: - workflow_dispatch: - push: - branches: [ main ] - pull_request: - branches: [ main ] - -jobs: - build: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - - name: Set Up JDK - uses: actions/setup-java@v4 - with: - distribution: 'zulu' - java-version: '17' - cache: 'gradle' - - - name: Setup Gradle - uses: gradle/actions/setup-gradle@v4 - - - name: Make gradlew executable - run: chmod +x ./gradlew - - - name: Build debug app - run: ./gradlew :app:assembleDebug diff --git a/.github/workflows/create_screenshots.yml b/.github/workflows/create_screenshots.yml deleted file mode 100644 index daca39e..0000000 --- a/.github/workflows/create_screenshots.yml +++ /dev/null @@ -1,34 +0,0 @@ -name: store screenshots - -on: - push - -env: - GRADLE_OPTS: "-Dorg.gradle.jvmargs=-Xmx6g -Dorg.gradle.daemon=false -Dkotlin.incremental=false" - -jobs: - test: - runs-on: macos-latest - - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-java@v4 - with: - distribution: 'zulu' - java-version: '19' - cache: 'gradle' - - - name: Gradle cache - uses: gradle/gradle-build-action@v2 - - - name: test - run: | - # Create screenshots - ./gradlew app:recordRoborazziDebug --stacktrace - - # Upload screenshots to GitHub Actions Artifacts - - uses: actions/upload-artifact@v4 - with: - name: screenshots - path: app/build/screenshots - retention-days: 30 \ No newline at end of file diff --git a/.github/workflows/screenshot_test.yml b/.github/workflows/screenshot_test.yml deleted file mode 100644 index 0164149..0000000 --- a/.github/workflows/screenshot_test.yml +++ /dev/null @@ -1,60 +0,0 @@ -name: Screenshot tests - -on: - push: - branches: [ main ] - pull_request: - branches: [ main ] - -env: - GRADLE_OPTS: "-Dorg.gradle.jvmargs=-Xmx6g -Dorg.gradle.daemon=false -Dkotlin.incremental=false" - -jobs: - test: - runs-on: macos-latest - - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-java@v4 - with: - distribution: 'zulu' - java-version: '19' - cache: 'gradle' - - - name: Gradle cache - uses: gradle/gradle-build-action@v2 - - # Download screenshots from main branch - - uses: dawidd6/action-download-artifact@v2 - with: - name: screenshots - path: app/build/screenshots - workflow: screenshot_test.yaml - branch: main - - - name: verify test - id: verify-test - run: | - # If there is a difference between the screenshots, the test will fail. - ./gradlew app:verifyRoborazziDebug --stacktrace - - - uses: actions/upload-artifact@v4 - if: ${{ always() }} - with: - name: screenshot-diff - path: app/build/screenshots - retention-days: 30 - - - uses: actions/upload-artifact@v4 - if: ${{ always() }} - with: - name: screenshot-diff-reports - path: app/build/reports - retention-days: 30 - - - uses: actions/upload-artifact@v4 - if: ${{ always() }} - with: - name: screenshot-diff-test-results - path: app/build/test-results - retention-days: 30 diff --git a/.github/workflows/test.yml b/.github/workflows/verify.yml similarity index 50% rename from .github/workflows/test.yml rename to .github/workflows/verify.yml index 4088df6..0a5a0a5 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/verify.yml @@ -1,4 +1,4 @@ -name: Test Cahier +name: Build and verify cahier on: workflow_dispatch: @@ -8,10 +8,31 @@ on: branches: [ main ] jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Checkout codebase + uses: actions/checkout@v4 + + - name: Set Up JDK + uses: actions/setup-java@v4 + with: + distribution: 'zulu' + java-version: '17' + cache: 'gradle' + + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v4 + + - name: Make gradlew executable + run: chmod +x ./gradlew + + - name: Build debug app + run: ./gradlew :app:assembleDebug test: runs-on: ubuntu-latest steps: - - name: checkout + - name: Checkout codebase uses: actions/checkout@v4 - name: Enable KVM @@ -30,3 +51,9 @@ jobs: device: desktop_large arch: x86_64 script: ./gradlew :app:connectedAndroidTest + + - name: Run Roborazzi + id: verify-test + run: | + # If there is a difference between the screenshots, the test will fail. + ./gradlew app:verifyRoborazziDebug --stacktrace \ No newline at end of file diff --git a/app/build.gradle.kts b/app/build.gradle.kts index b99276b..5a8be7c 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -68,7 +68,7 @@ android { } } roborazzi { - outputDir.set(file("build/screenshots")) + outputDir.set(file("../screenshots")) } } diff --git a/screenshots/reference_screenshot_bottomnavbar.png b/screenshots/reference_screenshot_bottomnavbar.png new file mode 100644 index 0000000000000000000000000000000000000000..68a61c88a3c07e13c5500c0b67507c2d58a16d5e GIT binary patch literal 37965 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