Add additional test cases for MyLocationsList

This commit is contained in:
Nebojsa Vuksic 2025-07-31 15:01:00 +02:00
parent e791d63d22
commit 45ef9a28da

View File

@ -3,6 +3,7 @@ package org.jetbrains.plugins.template
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.test.assertIsSelected
import androidx.compose.ui.test.junit4.ComposeContentTestRule import androidx.compose.ui.test.junit4.ComposeContentTestRule
import androidx.compose.ui.test.junit4.createComposeRule import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onNodeWithContentDescription import androidx.compose.ui.test.onNodeWithContentDescription
@ -23,24 +24,136 @@ import org.junit.Test
internal class MyLocationListTest { internal class MyLocationListTest {
@get:Rule @get:Rule
val composeRule = createComposeRule() val composeRule = createComposeRule()
private val noLocations = emptyList<Location>()
private val myLocationsViewModelApi = FakeMyLocationsViewModel(locations = noLocations)
@Test @Test
fun `show placeholder when no locations is added`() = runTest { fun `verify placeholder is shown when no locations is added`() = composeRule.runComposeTest {
val myLocationsRobot = MyLocationListRobot(composeRule) val myLocationsRobot = MyLocationListRobot(this)
composeRule.setContentWrappedInTheme {
val noLocations = emptyList<Location>()
val myLocationsViewModel = FakeMyLocationsViewModel(locations = noLocations)
MyLocationsListWithEmptyListPlaceholder(
modifier = Modifier.fillMaxWidth(),
myLocationsViewModelApi = myLocationsViewModel
)
}
myLocationsRobot myLocationsRobot
.verifyNoLocationsPlaceHolderVisible() .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( private class FakeMyLocationsViewModel(
locations: List<Location> = emptyList() locations: List<Location> = emptyList()
) : MyLocationsViewModelApi { ) : MyLocationsViewModelApi {
@ -60,13 +173,17 @@ internal class MyLocationListTest {
override fun onAddLocation(locationToAdd: Location) { override fun onAddLocation(locationToAdd: Location) {
val currentLocations = locationsFlow.value val currentLocations = locationsFlow.value
currentLocations.add(locationToAdd) currentLocations.add(locationToAdd)
locationsFlow.value = currentLocations locationsFlow.value = currentLocations
selectedItemIndex.value = currentLocations.lastIndex
} }
override fun onDeleteLocation(locationToDelete: Location) { override fun onDeleteLocation(locationToDelete: Location) {
val currentLocations = locationsFlow.value val currentLocations = locationsFlow.value
currentLocations.remove(locationToDelete) currentLocations.remove(locationToDelete)
locationsFlow.value = currentLocations locationsFlow.value = currentLocations
selectedItemIndex.value = currentLocations.lastIndex
} }
override fun onLocationSelected(selectedLocationIndex: Int) { override fun onLocationSelected(selectedLocationIndex: Int) {
@ -84,6 +201,7 @@ internal class MyLocationListTest {
} }
private class MyLocationListRobot(private val composableRule: ComposeContentTestRule) { private class MyLocationListRobot(private val composableRule: ComposeContentTestRule) {
fun clickOnItemWithText(text: String) { fun clickOnItemWithText(text: String) {
composableRule composableRule
.onNodeWithText(text) .onNodeWithText(text)
@ -94,8 +212,28 @@ private class MyLocationListRobot(private val composableRule: ComposeContentTest
composableRule composableRule
.onNodeWithText("No locations added yet. Go and add the first location.") .onNodeWithText("No locations added yet. Go and add the first location.")
.assertExists() .assertExists()
composableRule composableRule
.onNodeWithContentDescription("Empty list icon.") .onNodeWithContentDescription("Empty list icon.")
.assertExists() .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()
}
} }