From 45ef9a28da863d1322fc8ffbc3ccc21325c160fb Mon Sep 17 00:00:00 2001 From: Nebojsa Vuksic Date: Thu, 31 Jul 2025 15:01:00 +0200 Subject: [PATCH] Add additional test cases for MyLocationsList --- .../plugins/template/MyLocationListTest.kt | 160 ++++++++++++++++-- 1 file changed, 149 insertions(+), 11 deletions(-) diff --git a/src/test/kotlin/org/jetbrains/plugins/template/MyLocationListTest.kt b/src/test/kotlin/org/jetbrains/plugins/template/MyLocationListTest.kt index 84d5491..297af5c 100644 --- a/src/test/kotlin/org/jetbrains/plugins/template/MyLocationListTest.kt +++ b/src/test/kotlin/org/jetbrains/plugins/template/MyLocationListTest.kt @@ -3,6 +3,7 @@ package org.jetbrains.plugins.template import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier +import androidx.compose.ui.test.assertIsSelected import androidx.compose.ui.test.junit4.ComposeContentTestRule import androidx.compose.ui.test.junit4.createComposeRule import androidx.compose.ui.test.onNodeWithContentDescription @@ -23,24 +24,136 @@ import org.junit.Test internal class MyLocationListTest { @get:Rule val composeRule = createComposeRule() + private val noLocations = emptyList() + private val myLocationsViewModelApi = FakeMyLocationsViewModel(locations = noLocations) @Test - fun `show placeholder when no locations is added`() = runTest { - val myLocationsRobot = MyLocationListRobot(composeRule) - - composeRule.setContentWrappedInTheme { - val noLocations = emptyList() - val myLocationsViewModel = FakeMyLocationsViewModel(locations = noLocations) - MyLocationsListWithEmptyListPlaceholder( - modifier = Modifier.fillMaxWidth(), - myLocationsViewModelApi = myLocationsViewModel - ) - } + fun `verify placeholder is shown when no locations is added`() = composeRule.runComposeTest { + val myLocationsRobot = MyLocationListRobot(this) myLocationsRobot .verifyNoLocationsPlaceHolderVisible() } + @Test + fun `verify location is selected when user adds location`() = composeRule.runComposeTest { locationsViewModelApi -> + val myLocationsRobot = MyLocationListRobot(this) + + locationsViewModelApi.onAddLocation(Location("Munich", "Germany")) + + myLocationsRobot + .verifyListItemWithTextIsSelected("Munich, Germany") + } + + @Test + fun `verify item selection when multiple items are present`() = composeRule.runComposeTest { locationsViewModelApi -> + val myLocationsRobot = MyLocationListRobot(this) + + // Add multiple locations + locationsViewModelApi.onAddLocation(Location("Munich", "Germany")) + locationsViewModelApi.onAddLocation(Location("Berlin", "Germany")) + locationsViewModelApi.onAddLocation(Location("Paris", "France")) + + // Initially, the last added location (Paris) should be selected + myLocationsRobot.verifyListItemWithTextIsSelected("Paris, France") + + // Select a different location + myLocationsRobot.clickOnItemWithText("Berlin, Germany") + + // Verify the clicked location is now selected + myLocationsRobot.verifyListItemWithTextIsSelected("Berlin, Germany") + } + + @Test + fun `verify item deletion when multiple items are present`() = composeRule.runComposeTest { locationsViewModelApi -> + val myLocationsRobot = MyLocationListRobot(this) + + // Add multiple locations + val munich = Location("Munich", "Germany") + val berlin = Location("Berlin", "Germany") + val paris = Location("Paris", "France") + + locationsViewModelApi.onAddLocation(munich) + locationsViewModelApi.onAddLocation(berlin) + locationsViewModelApi.onAddLocation(paris) + + // Initially, the last added location (Paris) should be selected + myLocationsRobot.verifyListItemWithTextIsSelected("Paris, France") + + // Delete the selected location (Paris) + locationsViewModelApi.onDeleteLocation(paris) + + // Verify Paris is no longer in the list and Berlin is now selected + // (as it's the last item in the list after deletion) + myLocationsRobot.verifyItemDoesNotExist("Paris, France") + myLocationsRobot.verifyListItemWithTextIsSelected("Berlin, Germany") + } + + @Test + fun `verify middle item deletion when three items are present`() = composeRule.runComposeTest { locationsViewModelApi -> + val myLocationsRobot = MyLocationListRobot(this) + + // Add three locations + val munich = Location("Munich", "Germany") + val berlin = Location("Berlin", "Germany") + val paris = Location("Paris", "France") + + locationsViewModelApi.onAddLocation(munich) + locationsViewModelApi.onAddLocation(berlin) + locationsViewModelApi.onAddLocation(paris) + + // Initially, the last added location (Paris) should be selected + myLocationsRobot.verifyListItemWithTextIsSelected("Paris, France") + + // Delete the middle location (Berlin) + locationsViewModelApi.onDeleteLocation(berlin) + + // Verify Berlin is no longer in the list + myLocationsRobot.verifyItemDoesNotExist("Berlin, Germany") + + // Verify Munich and Paris still exist + myLocationsRobot.verifyItemExists("Munich, Germany") + myLocationsRobot.verifyItemExists("Paris, France") + + // Paris should still be selected as it was the selected item before deletion + myLocationsRobot.verifyListItemWithTextIsSelected("Paris, France") + } + + @Test + fun `verify deletion of the only item in list`() = composeRule.runComposeTest { locationsViewModelApi -> + val myLocationsRobot = MyLocationListRobot(this) + + // Add one location + val munich = Location("Munich", "Germany") + locationsViewModelApi.onAddLocation(munich) + + // Verify the location is selected + myLocationsRobot.verifyListItemWithTextIsSelected("Munich, Germany") + + // Delete the only location + locationsViewModelApi.onDeleteLocation(munich) + + // Verify the location is no longer in the list + myLocationsRobot.verifyItemDoesNotExist("Munich, Germany") + + // Verify the empty list placeholder is shown + myLocationsRobot.verifyNoLocationsPlaceHolderVisible() + } + + private fun ComposeContentTestRule.runComposeTest( + myLocationsViewModelApi: MyLocationsViewModelApi = this@MyLocationListTest.myLocationsViewModelApi, + block: suspend ComposeContentTestRule.(MyLocationsViewModelApi) -> Unit + ) = runTest { + this@runComposeTest.setContentWrappedInTheme { + MyLocationsListWithEmptyListPlaceholder( + modifier = Modifier.fillMaxWidth(), + myLocationsViewModelApi = myLocationsViewModelApi + ) + } + + this@runComposeTest.block(myLocationsViewModelApi) + } + private class FakeMyLocationsViewModel( locations: List = emptyList() ) : MyLocationsViewModelApi { @@ -60,13 +173,17 @@ internal class MyLocationListTest { override fun onAddLocation(locationToAdd: Location) { val currentLocations = locationsFlow.value currentLocations.add(locationToAdd) + locationsFlow.value = currentLocations + selectedItemIndex.value = currentLocations.lastIndex } override fun onDeleteLocation(locationToDelete: Location) { val currentLocations = locationsFlow.value currentLocations.remove(locationToDelete) + locationsFlow.value = currentLocations + selectedItemIndex.value = currentLocations.lastIndex } override fun onLocationSelected(selectedLocationIndex: Int) { @@ -84,6 +201,7 @@ internal class MyLocationListTest { } private class MyLocationListRobot(private val composableRule: ComposeContentTestRule) { + fun clickOnItemWithText(text: String) { composableRule .onNodeWithText(text) @@ -94,8 +212,28 @@ private class MyLocationListRobot(private val composableRule: ComposeContentTest composableRule .onNodeWithText("No locations added yet. Go and add the first location.") .assertExists() + composableRule .onNodeWithContentDescription("Empty list icon.") .assertExists() } + + fun verifyListItemWithTextIsSelected(text: String) { + composableRule + .onNodeWithText(text) + .assertExists() + .assertIsSelected() + } + + fun verifyItemDoesNotExist(text: String) { + composableRule + .onNodeWithText(text) + .assertDoesNotExist() + } + + fun verifyItemExists(text: String) { + composableRule + .onNodeWithText(text) + .assertExists() + } } \ No newline at end of file