Skip to content

Commit d9864d6

Browse files
authored
Merge pull request #254 from LookUpGroup27/feat/implement-edit-description-in-collection-screen
feat: add edit description feature and related tests
2 parents ace6c60 + 248b987 commit d9864d6

File tree

13 files changed

+652
-96
lines changed

13 files changed

+652
-96
lines changed

app/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,7 @@ dependencies {
165165
implementation(libs.androidx.navigation.runtime.ktx)
166166
implementation(libs.androidx.navigation.testing)
167167
implementation(libs.test.core.ktx)
168+
implementation (libs.androidx.constraintlayout.compose)
168169

169170
//Camera
170171
implementation (libs.androidx.camera.camera2)

app/src/androidTest/java/com/github/lookupgroup27/lookup/ui/image/EditImageKtTest.kt

Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
11
package com.github.lookupgroup27.lookup.ui.image
22

33
import androidx.compose.ui.test.assertIsDisplayed
4+
import androidx.compose.ui.test.assertTextEquals
45
import androidx.compose.ui.test.junit4.createComposeRule
56
import androidx.compose.ui.test.onNodeWithTag
7+
import androidx.compose.ui.test.onNodeWithText
68
import androidx.compose.ui.test.performClick
9+
import androidx.compose.ui.test.performImeAction
10+
import androidx.compose.ui.test.performTextClearance
11+
import androidx.compose.ui.test.performTextInput
712
import androidx.test.ext.junit.runners.AndroidJUnit4
813
import com.github.lookupgroup27.lookup.model.collection.CollectionRepository
914
import com.github.lookupgroup27.lookup.model.image.EditImageRepository
@@ -17,7 +22,10 @@ import org.junit.Rule
1722
import org.junit.Test
1823
import org.junit.runner.RunWith
1924
import org.mockito.Mockito
25+
import org.mockito.kotlin.any
26+
import org.mockito.kotlin.eq
2027
import org.mockito.kotlin.mock
28+
import org.mockito.kotlin.times
2129
import org.mockito.kotlin.verify
2230

2331
/**
@@ -65,6 +73,7 @@ class EditImageScreenTest {
6573
postAverageStar = 0.0,
6674
postRatedByNb = 0,
6775
postUid = "mock_uid",
76+
postDescription = "mock_description",
6877
editImageViewModel = editImageViewModel,
6978
collectionViewModel = collectionViewModel,
7079
navigationActions = mockNavigationActions,
@@ -85,6 +94,7 @@ class EditImageScreenTest {
8594
postAverageStar = 0.0,
8695
postRatedByNb = 0,
8796
postUid = "mock_uid",
97+
postDescription = "mock_description",
8898
editImageViewModel = editImageViewModel,
8999
collectionViewModel = collectionViewModel,
90100
navigationActions = mockNavigationActions,
@@ -106,6 +116,7 @@ class EditImageScreenTest {
106116
postAverageStar = 0.0,
107117
postRatedByNb = 0,
108118
postUid = "mock_uid",
119+
postDescription = "mock_description",
109120
editImageViewModel = editImageViewModel,
110121
collectionViewModel = collectionViewModel,
111122
navigationActions = mockNavigationActions,
@@ -124,6 +135,7 @@ class EditImageScreenTest {
124135
postAverageStar = 0.0,
125136
postRatedByNb = 0,
126137
postUid = "mock_uid",
138+
postDescription = "mock_description",
127139
editImageViewModel = editImageViewModel,
128140
collectionViewModel = collectionViewModel,
129141
navigationActions = mockNavigationActions,
@@ -146,6 +158,7 @@ class EditImageScreenTest {
146158
postAverageStar = 0.0,
147159
postRatedByNb = 0,
148160
postUid = "mock_uid",
161+
postDescription = "mock_description",
149162
editImageViewModel = editImageViewModel,
150163
collectionViewModel = collectionViewModel,
151164
navigationActions = mockNavigationActions,
@@ -166,6 +179,7 @@ class EditImageScreenTest {
166179
postAverageStar = 0.0,
167180
postRatedByNb = 0,
168181
postUid = "mock_uid",
182+
postDescription = "mock_description",
169183
editImageViewModel = editImageViewModel,
170184
collectionViewModel = collectionViewModel,
171185
navigationActions = mockNavigationActions,
@@ -187,6 +201,7 @@ class EditImageScreenTest {
187201
postAverageStar = 0.0,
188202
postRatedByNb = 0,
189203
postUid = "mock_uid",
204+
postDescription = "mock_description",
190205
editImageViewModel = editImageViewModel,
191206
collectionViewModel = collectionViewModel,
192207
navigationActions = mockNavigationActions,
@@ -205,6 +220,7 @@ class EditImageScreenTest {
205220
postAverageStar = 0.0,
206221
postRatedByNb = 0,
207222
postUid = "mock_uid",
223+
postDescription = "mock_description",
208224
editImageViewModel = editImageViewModel,
209225
collectionViewModel = collectionViewModel,
210226
navigationActions = mockNavigationActions,
@@ -223,6 +239,7 @@ class EditImageScreenTest {
223239
postAverageStar = 0.0,
224240
postRatedByNb = 0,
225241
postUid = "mock_uid",
242+
postDescription = "mock_description",
226243
editImageViewModel = editImageViewModel,
227244
collectionViewModel = collectionViewModel,
228245
navigationActions = mockNavigationActions,
@@ -241,6 +258,7 @@ class EditImageScreenTest {
241258
postAverageStar = 0.0,
242259
postRatedByNb = 0,
243260
postUid = "mock_uid",
261+
postDescription = "mock_description",
244262
editImageViewModel = editImageViewModel,
245263
collectionViewModel = collectionViewModel,
246264
navigationActions = mockNavigationActions,
@@ -249,4 +267,148 @@ class EditImageScreenTest {
249267

250268
composeTestRule.onNodeWithTag("rated_by_collection").assertIsDisplayed()
251269
}
270+
271+
@Test
272+
fun testDescriptionBoxIsDisplayed() {
273+
composeTestRule.setContent {
274+
EditImageScreen(
275+
postUri = "mock_image_url",
276+
postAverageStar = 4.5,
277+
postRatedByNb = 20,
278+
postUid = "mock_uid",
279+
postDescription = "mock_description",
280+
editImageViewModel = editImageViewModel,
281+
collectionViewModel = collectionViewModel,
282+
navigationActions = mockNavigationActions,
283+
postsViewModel = postsViewModel)
284+
}
285+
286+
composeTestRule.onNodeWithTag("description_text").assertIsDisplayed()
287+
}
288+
289+
@Test
290+
fun testEditFieldAppearsOnClick() {
291+
composeTestRule.setContent {
292+
EditImageScreen(
293+
postUri = "mock_image_url",
294+
postAverageStar = 4.5,
295+
postRatedByNb = 20,
296+
postUid = "mock_uid",
297+
postDescription = "mock_description",
298+
editImageViewModel = editImageViewModel,
299+
collectionViewModel = collectionViewModel,
300+
navigationActions = mockNavigationActions,
301+
postsViewModel = postsViewModel)
302+
}
303+
304+
// Simulate clicking the description box
305+
composeTestRule.onNodeWithTag("description_text").performClick()
306+
307+
// Verify that the edit field appears
308+
composeTestRule.onNodeWithTag("edit_description_field").assertIsDisplayed()
309+
}
310+
311+
@Test
312+
fun testOnDoneKeyboardActionDisplaysConfirmationDialogAndSavesDescription() {
313+
val testPostUid = "mock_uid"
314+
val initialDescription = "mock_description"
315+
val updatedDescription = "updated_description"
316+
317+
composeTestRule.setContent {
318+
EditImageScreen(
319+
postUri = "mock_image_url",
320+
postAverageStar = 4.5,
321+
postRatedByNb = 20,
322+
postUid = testPostUid,
323+
postDescription = initialDescription,
324+
editImageViewModel = editImageViewModel,
325+
collectionViewModel = collectionViewModel,
326+
navigationActions = mockNavigationActions,
327+
postsViewModel = postsViewModel)
328+
}
329+
330+
// Click on the description text to enter editing mode
331+
composeTestRule.onNodeWithTag("description_text").performClick()
332+
333+
// Verify the edit field appears
334+
composeTestRule.onNodeWithTag("edit_description_field").assertIsDisplayed()
335+
336+
// Input a new description (resetting any previous value first)
337+
composeTestRule.onNodeWithTag("edit_description_field").performTextClearance()
338+
composeTestRule.onNodeWithTag("edit_description_field").performTextInput(updatedDescription)
339+
340+
// Simulate the "Done" action
341+
composeTestRule.onNodeWithTag("edit_description_field").performImeAction()
342+
343+
// Verify that the confirmation dialog appears
344+
composeTestRule.onNodeWithText("Save Changes?").assertIsDisplayed()
345+
composeTestRule.onNodeWithText("Do you want to save the new description?").assertIsDisplayed()
346+
347+
// Click on the "Save" button in the dialog
348+
composeTestRule.onNodeWithText("Save").performClick()
349+
350+
// Verify that `updateDescription` is called with correct arguments
351+
verify(postsRepository).updateDescription(eq(testPostUid), eq(updatedDescription), any(), any())
352+
353+
// Verify that the description text displays the updated description
354+
composeTestRule.onNodeWithTag("description_text").assertTextEquals(updatedDescription)
355+
356+
// Verify that the editing mode has exited
357+
composeTestRule.onNodeWithTag("edit_description_field").assertDoesNotExist()
358+
359+
// Ensure the confirmation dialog is dismissed
360+
composeTestRule.onNodeWithText("Save Changes?").assertDoesNotExist()
361+
}
362+
363+
@Test
364+
fun testOnDoneKeyboardActionDisplaysConfirmationDialogAndDiscardsDescription() {
365+
val testPostUid = "mock_uid"
366+
val initialDescription = "mock_description"
367+
val updatedDescription = "updated_description"
368+
369+
composeTestRule.setContent {
370+
EditImageScreen(
371+
postUri = "mock_image_url",
372+
postAverageStar = 4.5,
373+
postRatedByNb = 20,
374+
postUid = testPostUid,
375+
postDescription = initialDescription,
376+
editImageViewModel = editImageViewModel,
377+
collectionViewModel = collectionViewModel,
378+
navigationActions = mockNavigationActions,
379+
postsViewModel = postsViewModel)
380+
}
381+
382+
// Click on the description text to enter editing mode
383+
composeTestRule.onNodeWithTag("description_text").performClick()
384+
385+
// Verify the edit field appears
386+
composeTestRule.onNodeWithTag("edit_description_field").assertIsDisplayed()
387+
388+
// Input a new description (resetting any previous value first)
389+
composeTestRule.onNodeWithTag("edit_description_field").performTextClearance()
390+
composeTestRule.onNodeWithTag("edit_description_field").performTextInput(updatedDescription)
391+
392+
// Simulate the "Done" action
393+
composeTestRule.onNodeWithTag("edit_description_field").performImeAction()
394+
395+
// Verify that the confirmation dialog appears
396+
composeTestRule.onNodeWithText("Save Changes?").assertIsDisplayed()
397+
composeTestRule.onNodeWithText("Do you want to save the new description?").assertIsDisplayed()
398+
399+
// Click on the "Discard" button in the dialog
400+
composeTestRule.onNodeWithText("Discard").performClick()
401+
402+
// Verify that `updateDescription` is NOT called
403+
verify(postsRepository, times(0)).updateDescription(any(), any(), any(), any())
404+
405+
// Verify that the description text displays the initial description
406+
composeTestRule.onNodeWithTag("description_text").assertTextEquals(initialDescription)
407+
408+
// Verify that the editing mode has exited
409+
composeTestRule.onNodeWithTag("edit_description_field").assertDoesNotExist()
410+
411+
// Ensure the confirmation dialog is dismissed
412+
composeTestRule.onNodeWithText("Save Changes?").assertDoesNotExist()
413+
}
252414
}

app/src/androidTest/java/com/github/lookupgroup27/lookup/ui/profile/CollectionKtTest.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,7 @@ class CollectionScreenTest {
205205
postAverageStar: Float,
206206
postRatedByNb: Int,
207207
postUid: String,
208+
postDescription: String,
208209
route: String
209210
) {
210211
if (route == Route.EDIT_IMAGE &&

app/src/main/java/com/github/lookupgroup27/lookup/MainActivity.kt

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -144,17 +144,20 @@ fun LookUpApp() {
144144
}
145145

146146
composable(
147-
route = "${Route.EDIT_IMAGE}/{postUri}/{postAverageStar}/{postRatedByNb}/{postUid}",
147+
route =
148+
"${Route.EDIT_IMAGE}/{postUri}/{postAverageStar}/{postRatedByNb}/{postUid}/{postDescription}",
148149
arguments =
149150
listOf(
150151
navArgument("postUri") { type = NavType.StringType },
151152
navArgument("postAverageStar") { type = NavType.FloatType },
152153
navArgument("postRatedByNb") { type = NavType.IntType },
153-
navArgument("postUid") { type = NavType.StringType })) { backStackEntry ->
154+
navArgument("postUid") { type = NavType.StringType },
155+
navArgument("postDescription") { type = NavType.StringType })) { backStackEntry ->
154156
val postUri = backStackEntry.arguments?.getString("postUri") ?: ""
155157
val postAverageStar = backStackEntry.arguments?.getFloat("postAverageStar") ?: 0.0f
156158
val postRatedByNb = backStackEntry.arguments?.getInt("postRatedByNb") ?: 0
157159
val postUid = backStackEntry.arguments?.getString("postUid") ?: ""
160+
val postDescription = backStackEntry.arguments?.getString("postDescription") ?: ""
158161

159162
EditImageScreen(
160163
postUri = postUri,
@@ -164,6 +167,7 @@ fun LookUpApp() {
164167
editImageViewModel = editImageViewModel,
165168
collectionViewModel = collectionViewModel,
166169
postsViewModel = postsViewModel,
170+
postDescription = postDescription,
167171
navigationActions = navigationActions)
168172
}
169173
}

app/src/main/java/com/github/lookupgroup27/lookup/model/post/PostsRepository.kt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,4 +60,18 @@ interface PostsRepository {
6060
* @param onFailure Callback function invoked with an exception if the operation fails.
6161
*/
6262
fun updatePost(post: Post, onSuccess: () -> Unit, onFailure: (Exception) -> Unit)
63+
64+
/**
65+
* Updates the description of an existing post in the repository.
66+
*
67+
* @param postUid The UID of the post to update.
68+
* @param onSuccess Callback function invoked when the operation is successful.
69+
* @param onFailure Callback function invoked with an exception if the operation fails.
70+
*/
71+
fun updateDescription(
72+
postUid: String,
73+
newDescription: String,
74+
onSuccess: () -> Unit,
75+
onFailure: (Exception) -> Unit
76+
)
6377
}

app/src/main/java/com/github/lookupgroup27/lookup/model/post/PostsRepositoryFirestore.kt

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,4 +124,23 @@ class PostsRepositoryFirestore(private val db: FirebaseFirestore) : PostsReposit
124124
onFailure(it)
125125
}
126126
}
127+
128+
override fun updateDescription(
129+
postUid: String,
130+
newDescription: String,
131+
onSuccess: () -> Unit,
132+
onFailure: (Exception) -> Unit
133+
) {
134+
collection
135+
.document(postUid)
136+
.update("description", newDescription)
137+
.addOnSuccessListener {
138+
Log.d(tag, "Description updated successfully")
139+
onSuccess()
140+
}
141+
.addOnFailureListener {
142+
Log.e(tag, "Error updating description", it)
143+
onFailure(it)
144+
}
145+
}
127146
}

0 commit comments

Comments
 (0)