Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/profile/edit profile screen UI and tests #108

Merged
merged 18 commits into from
Nov 7, 2024
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
22e27e2
feat: center GlideImage and update EditProfileScreen layout
Harrish92 Oct 30, 2024
d1afd7b
Merge branch 'main' of github.com:PeriodPals/periodpals into feat/pro…
Harrish92 Oct 30, 2024
aa7ae4f
fix: modularize EditProfileScreen without changing UI
Harrish92 Oct 30, 2024
d61be6e
feat: add UI tests for `EditProfileScreen` and validate fields
Harrish92 Oct 31, 2024
250ff12
Merge branch 'main' of github.com:PeriodPals/periodpals into feat/pro…
Harrish92 Oct 31, 2024
72ce683
feat: implement image change on icon click
Harrish92 Oct 31, 2024
7ba8628
Merge branch 'main' into feat/profile/editProfileScreen-ui-and-tests
Harrish92 Oct 31, 2024
69490a9
Merge branch 'main' of github.com:PeriodPals/periodpals into feat/pro…
Harrish92 Nov 3, 2024
27078ca
fix: revamp EditProfile tests, improve layout, and add new UI component
Harrish92 Nov 4, 2024
7837bdf
Merge branch 'main' of github.com:PeriodPals/periodpals into feat/pro…
Harrish92 Nov 4, 2024
325ad76
fix: set the correct content for main
Harrish92 Nov 4, 2024
554440b
fix: add tags for sectors, refactor tests, change profile icon, and u…
Harrish92 Nov 5, 2024
58f02bc
fix: correct `EditProfile` to pass tests
Harrish92 Nov 5, 2024
8a91386
Merge branch 'main' of github.com:PeriodPals/periodpals into feat/pro…
Harrish92 Nov 5, 2024
8aacca8
fix: reformat code for better readability
Harrish92 Nov 5, 2024
c9702af
fix: change function names for `editProfileTest`
Harrish92 Nov 6, 2024
a06a3c4
fix: update UI elements in `EditProfileScreen`
Harrish92 Nov 7, 2024
c17d229
fix: remove color assigned to button
Harrish92 Nov 7, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
francelu marked this conversation as resolved.
Show resolved Hide resolved
Harrish92 marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
import androidx.compose.ui.test.assertIsDisplayed
import androidx.compose.ui.test.assertIsNotDisplayed
import androidx.compose.ui.test.assertTextEquals
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onNodeWithTag
import androidx.compose.ui.test.performClick
import androidx.compose.ui.test.performTextClearance
import androidx.compose.ui.test.performTextInput
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.periodpals.resources.C.Tag.BottomNavigationMenu
import com.android.periodpals.resources.C.Tag.EditProfileScreen
import com.android.periodpals.resources.C.Tag.TopAppBar
import com.android.periodpals.ui.navigation.NavigationActions
import com.android.periodpals.ui.navigation.Route
import com.android.periodpals.ui.navigation.Screen
import com.android.periodpals.ui.profile.EditProfileScreen
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mockito.mock
import org.mockito.Mockito.verify
import org.mockito.Mockito.`when`
import org.mockito.kotlin.any
import org.mockito.kotlin.never

@RunWith(AndroidJUnit4::class)
class EditProfileTest {

private lateinit var navigationActions: NavigationActions
@get:Rule val composeTestRule = createComposeRule()

@Before
// Set up the EditProfileScreen
fun setUp() {
navigationActions = mock(NavigationActions::class.java)

`when`(navigationActions.currentRoute()).thenReturn(Route.PROFILE)

composeTestRule.setContent { EditProfileScreen(navigationActions) }
}

@Test
fun displayAllComponents() {
Harrish92 marked this conversation as resolved.
Show resolved Hide resolved

composeTestRule.onNodeWithTag(EditProfileScreen.NAME_FIELD).assertIsDisplayed()
composeTestRule.onNodeWithTag(EditProfileScreen.DOB_FIELD).assertIsDisplayed()
composeTestRule.onNodeWithTag(EditProfileScreen.DESCRIPTION_FIELD).assertIsDisplayed()
composeTestRule.onNodeWithTag(EditProfileScreen.EMAIL_FIELD).assertIsDisplayed()
composeTestRule.onNodeWithTag(EditProfileScreen.PROFILE_PICTURE).assertIsDisplayed()
composeTestRule.onNodeWithTag(EditProfileScreen.ADD_CIRCLE_ICON).assertIsDisplayed()
composeTestRule.onNodeWithTag(EditProfileScreen.EDIT_PROFILE_SCREEN).assertIsDisplayed()
Harrish92 marked this conversation as resolved.
Show resolved Hide resolved

composeTestRule.onNodeWithTag(BottomNavigationMenu.BOTTOM_NAVIGATION_MENU).assertDoesNotExist()
composeTestRule.onNodeWithTag(TopAppBar.TOP_BAR).assertIsDisplayed()
composeTestRule.onNodeWithTag(TopAppBar.GO_BACK_BUTTON).assertIsDisplayed()
composeTestRule.onNodeWithTag(TopAppBar.EDIT_BUTTON).assertIsNotDisplayed()

composeTestRule
.onNodeWithTag(EditProfileScreen.SAVE_BUTTON)
.assertIsDisplayed()
.assertTextEquals("Save Changes")
}

@Test
fun createValidProfile() {
Harrish92 marked this conversation as resolved.
Show resolved Hide resolved
composeTestRule.onNodeWithTag(EditProfileScreen.NAME_FIELD).performTextClearance()
composeTestRule.onNodeWithTag(EditProfileScreen.DOB_FIELD).performTextClearance()
composeTestRule.onNodeWithTag(EditProfileScreen.DESCRIPTION_FIELD).performTextClearance()
composeTestRule.onNodeWithTag(EditProfileScreen.EMAIL_FIELD).performTextClearance()

composeTestRule.onNodeWithTag(EditProfileScreen.NAME_FIELD).performTextInput("John Doe")
composeTestRule.onNodeWithTag(EditProfileScreen.DOB_FIELD).performTextInput("01/01/1990")
composeTestRule
.onNodeWithTag(EditProfileScreen.DESCRIPTION_FIELD)
.performTextInput("A short bio")
composeTestRule
.onNodeWithTag(EditProfileScreen.EMAIL_FIELD)
.performTextInput("john.doe@example.com")
composeTestRule.onNodeWithTag(EditProfileScreen.SAVE_BUTTON).performClick()
verify(navigationActions).navigateTo(Screen.PROFILE)
}

@Test
fun createInvalidProfileNoName() {
composeTestRule.onNodeWithTag(EditProfileScreen.NAME_FIELD).performTextClearance()
composeTestRule.onNodeWithTag(EditProfileScreen.DOB_FIELD).performTextClearance()
composeTestRule.onNodeWithTag(EditProfileScreen.DESCRIPTION_FIELD).performTextClearance()
composeTestRule.onNodeWithTag(EditProfileScreen.EMAIL_FIELD).performTextClearance()

composeTestRule.onNodeWithTag(EditProfileScreen.DOB_FIELD).performTextInput("01/01/1990")
composeTestRule
.onNodeWithTag(EditProfileScreen.DESCRIPTION_FIELD)
.performTextInput("A short bio")
composeTestRule
.onNodeWithTag(EditProfileScreen.EMAIL_FIELD)
.performTextInput("john.doe@example.com")
composeTestRule.onNodeWithTag(EditProfileScreen.SAVE_BUTTON).performClick()
verify(navigationActions, never()).navigateTo(any<String>())
}

@Test
fun createInvalidProfileNoDOB() {
composeTestRule.onNodeWithTag(EditProfileScreen.NAME_FIELD).performTextClearance()
composeTestRule.onNodeWithTag(EditProfileScreen.DOB_FIELD).performTextClearance()
composeTestRule.onNodeWithTag(EditProfileScreen.DESCRIPTION_FIELD).performTextClearance()
composeTestRule.onNodeWithTag(EditProfileScreen.EMAIL_FIELD).performTextClearance()

composeTestRule.onNodeWithTag(EditProfileScreen.NAME_FIELD).performTextInput("John Doe")
composeTestRule
.onNodeWithTag(EditProfileScreen.DESCRIPTION_FIELD)
.performTextInput("A short bio")
composeTestRule
.onNodeWithTag(EditProfileScreen.EMAIL_FIELD)
.performTextInput("john.doe@example.com")
composeTestRule.onNodeWithTag(EditProfileScreen.SAVE_BUTTON).performClick()
verify(navigationActions, never()).navigateTo(any<String>())
}

@Test
fun createInvalidProfileNoDescription() {
composeTestRule.onNodeWithTag(EditProfileScreen.NAME_FIELD).performTextClearance()
composeTestRule.onNodeWithTag(EditProfileScreen.DOB_FIELD).performTextClearance()
composeTestRule.onNodeWithTag(EditProfileScreen.DESCRIPTION_FIELD).performTextClearance()
composeTestRule.onNodeWithTag(EditProfileScreen.EMAIL_FIELD).performTextClearance()

composeTestRule.onNodeWithTag(EditProfileScreen.NAME_FIELD).performTextInput("John Doe")
composeTestRule.onNodeWithTag(EditProfileScreen.DOB_FIELD).performTextInput("01/01/1990")
composeTestRule
.onNodeWithTag(EditProfileScreen.EMAIL_FIELD)
.performTextInput("john.doe@example.com")
composeTestRule.onNodeWithTag(EditProfileScreen.SAVE_BUTTON).performClick()
verify(navigationActions, never()).navigateTo(any<String>())
}

@Test
fun createInvalidProfileNoEmail() {
composeTestRule.onNodeWithTag(EditProfileScreen.NAME_FIELD).performTextClearance()
composeTestRule.onNodeWithTag(EditProfileScreen.DOB_FIELD).performTextClearance()
composeTestRule.onNodeWithTag(EditProfileScreen.DESCRIPTION_FIELD).performTextClearance()
composeTestRule.onNodeWithTag(EditProfileScreen.EMAIL_FIELD).performTextClearance()

composeTestRule.onNodeWithTag(EditProfileScreen.NAME_FIELD).performTextInput("John Doe")
composeTestRule.onNodeWithTag(EditProfileScreen.DOB_FIELD).performTextInput("01/01/1990")
composeTestRule
.onNodeWithTag(EditProfileScreen.DESCRIPTION_FIELD)
.performTextInput("A short bio")
composeTestRule.onNodeWithTag(EditProfileScreen.SAVE_BUTTON).performClick()
verify(navigationActions, never()).navigateTo(any<String>())
}

@Test
fun createInvalidProfileAllEmptyFields() {
composeTestRule.onNodeWithTag(EditProfileScreen.NAME_FIELD).performTextClearance()
composeTestRule.onNodeWithTag(EditProfileScreen.DOB_FIELD).performTextClearance()
composeTestRule.onNodeWithTag(EditProfileScreen.DESCRIPTION_FIELD).performTextClearance()
composeTestRule.onNodeWithTag(EditProfileScreen.EMAIL_FIELD).performTextClearance()

composeTestRule.onNodeWithTag(EditProfileScreen.SAVE_BUTTON).performClick()
verify(navigationActions, never()).navigateTo(any<String>())
}
}
8 changes: 8 additions & 0 deletions app/src/main/java/com/android/periodpals/resources/C.kt
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,15 @@ object C {

/** Constants for tagging UI components in the EditProfileScreen. */
object EditProfileScreen {
const val EDIT_PROFILE_SCREEN = "editProfileScreen"
Harrish92 marked this conversation as resolved.
Show resolved Hide resolved
const val SCREEN = "screen"
const val PROFILE_PICTURE = "profilePicture"
const val ADD_CIRCLE_ICON = "addCircleIcon"
Harrish92 marked this conversation as resolved.
Show resolved Hide resolved
const val EMAIL_FIELD = "emailField"
const val DOB_FIELD = "dobField"
const val NAME_FIELD = "nameField"
Harrish92 marked this conversation as resolved.
Show resolved Hide resolved
const val DESCRIPTION_FIELD = "descriptionField"
const val SAVE_BUTTON = "saveButton"
}
Harrish92 marked this conversation as resolved.
Show resolved Hide resolved

/** Constants for tagging UI components in the ProfileScreen. */
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package com.android.periodpals.ui.components

import androidx.compose.foundation.layout.height
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp

/**
* A composable that displays an instruction text with [text] and [testTag] for testing purposes.
*/
@Composable
fun ProfileText(text: String, testTag: String) {
Harrish92 marked this conversation as resolved.
Show resolved Hide resolved
Text(
modifier = Modifier.testTag(testTag),
text = text,
style =
MaterialTheme.typography.bodyLarge.copy(fontSize = 20.sp, fontWeight = FontWeight.Medium))
}

/**
* A composable that displays a description input with [description] and [onValueChange] action and
* [testTag]
*/
@Composable
fun ProfileDescriptionInput(description: String, onValueChange: (String) -> Unit, testTag: String) {
OutlinedTextField(
value = description,
onValueChange = onValueChange,
label = { Text("Description") },
placeholder = { Text("Enter a description") },
modifier = Modifier.height(124.dp).testTag(testTag),
)
}
Harrish92 marked this conversation as resolved.
Show resolved Hide resolved
Loading
Loading