diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index 7c363b41..01ea1270 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -68,3 +68,24 @@ jobs: with: name: android-lint-report path: composeApp/build/reports/ktlint/ + + common-tests: + name: Common Tests + runs-on: macos-latest + needs: [ build ] + + steps: + - uses: actions/checkout@v4 + + - name: Setup + uses: ./.github/actions/setup + + - name: Run common tests + run: ./gradlew copyBrandingToCommonResources :composeApp:iosSimulatorArm64Test + + - name: Uploads test reports + uses: actions/upload-artifact@v4 + if: failure() + with: + name: android-lint-report + path: composeApp/build/reports/tests/iosSimulatorArm64Test/ diff --git a/README.md b/README.md index f37c9728..63806833 100644 --- a/README.md +++ b/README.md @@ -43,8 +43,6 @@ besides platform-specific code that we can’t avoid, such as the loading our pr * `data` data layer code (database, preferences, network...) * `ui` UI layer code, organized into features/screens - - ### Build, Install, and Run To build, install, and run your application, use the following commands: @@ -59,7 +57,8 @@ To build, install, and run your application, use the following commands: ./gradlew runDebug -Porganization=dw ``` -There is a custom gradle task(`copyBrandingToCommonResources`) that is used to copy brand specific resources to the common resources folder. This task is called before the `preBuild` task. +There is a custom gradle task(`copyBrandingToCommonResources`) that is used to copy brand specific +resources to the common resources folder. This task is called before the `preBuild` task. ### Creating Run Configurations in Android Studio @@ -82,11 +81,22 @@ Configure run configurations for easy execution within Android Studio: #### OONI Probe iOS Configuration -The "Run/Debug Configurations" already has the proper configuration and you just need to select the XCode Project Scheme `OONIProbe` and run it. +The "Run/Debug Configurations" already has the proper configuration and you just need to select the +XCode Project Scheme `OONIProbe` and run it. #### News Media Scan iOS Configuration -The "Run/Debug Configurations" already has the proper configuration and you just need to select the XCode Project Scheme `NewsMediaScan` and run it. + +The "Run/Debug Configurations" already has the proper configuration and you just need to select the +XCode Project Scheme `NewsMediaScan` and run it. #### Switching between OONI Probe and News Media Scan + - Ensure you can run clean and build the project successfully. - Run `pod install` in the `iosApp` directory. + +## Testing + +Common tests (tests inside `commonTest`) only run on the iOS Simulator. +Choosing the option `android (local)` won't work. This is a current +[issue](https://www.jetbrains.com/help/kotlin-multiplatform-dev/compose-test.html#f03e048) with +the official testing library. diff --git a/composeApp/build.gradle.kts b/composeApp/build.gradle.kts index e77fd2a0..5c03ce11 100644 --- a/composeApp/build.gradle.kts +++ b/composeApp/build.gradle.kts @@ -1,3 +1,4 @@ +import org.jetbrains.compose.ExperimentalComposeLibrary import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi import org.jetbrains.kotlin.gradle.dsl.JvmTarget @@ -84,10 +85,16 @@ kotlin { kotlin.srcDir(config.srcRoot) } } + commonTest.dependencies { + implementation(kotlin("test")) + @OptIn(ExperimentalComposeLibrary::class) + implementation(compose.uiTest) + } all { languageSettings { optIn("kotlinx.coroutines.ExperimentalCoroutinesApi") optIn("androidx.compose.material3.ExperimentalMaterial3Api") + optIn("androidx.compose.ui.test.ExperimentalTestApi") } } } diff --git a/composeApp/src/commonTest/kotlin/org/ooni/probe/ui/result/ResultScreenTest.kt b/composeApp/src/commonTest/kotlin/org/ooni/probe/ui/result/ResultScreenTest.kt new file mode 100644 index 00000000..71e6f6c0 --- /dev/null +++ b/composeApp/src/commonTest/kotlin/org/ooni/probe/ui/result/ResultScreenTest.kt @@ -0,0 +1,42 @@ +package org.ooni.probe.ui.result + +import androidx.compose.ui.test.onNodeWithContentDescription +import androidx.compose.ui.test.onNodeWithText +import androidx.compose.ui.test.performClick +import androidx.compose.ui.test.runComposeUiTest +import org.ooni.probe.data.models.TestResult +import kotlin.test.Test +import kotlin.test.assertEquals + +class ResultScreenTest { + @Test + fun showResult() = + runComposeUiTest { + val result = TestResult(TestResult.Id("ABCDEF")) + setContent { + ResultScreen( + state = ResultViewModel.State(result), + onEvent = {}, + ) + } + + onNodeWithText(result.id.value).assertExists() + } + + @Test + fun pressBack() = + runComposeUiTest { + val events = mutableListOf() + val result = TestResult(TestResult.Id("ABCDEF")) + setContent { + ResultScreen( + state = ResultViewModel.State(result), + onEvent = events::add, + ) + } + + onNodeWithContentDescription("Back").performClick() + assertEquals(1, events.size) + assertEquals(ResultViewModel.Event.BackClicked, events.first()) + } +} diff --git a/composeApp/src/commonTest/kotlin/org/ooni/probe/ui/result/ResultViewModelTest.kt b/composeApp/src/commonTest/kotlin/org/ooni/probe/ui/result/ResultViewModelTest.kt new file mode 100644 index 00000000..e6c08302 --- /dev/null +++ b/composeApp/src/commonTest/kotlin/org/ooni/probe/ui/result/ResultViewModelTest.kt @@ -0,0 +1,21 @@ +package org.ooni.probe.ui.result + +import org.ooni.probe.data.models.TestResult +import kotlin.test.Test +import kotlin.test.assertTrue + +class ResultViewModelTest { + @Test + fun backClicked() { + var backPressed = false + + val viewModel = + ResultViewModel( + resultId = TestResult.Id("1234"), + onBack = { backPressed = true }, + ) + + viewModel.onEvent(ResultViewModel.Event.BackClicked) + assertTrue(backPressed) + } +}