Skip to content

Commit

Permalink
Merge pull request #234 from SwEnt-Group13/fix/edit-profile-offline
Browse files Browse the repository at this point in the history
Fix/edit profile offline
  • Loading branch information
Romainhir authored Dec 4, 2024
2 parents c161f23 + 3b71e4f commit 7c6c95a
Show file tree
Hide file tree
Showing 4 changed files with 167 additions and 9 deletions.
Original file line number Diff line number Diff line change
@@ -1,24 +1,35 @@
package com.android.unio.components.user

import android.net.ConnectivityManager
import android.net.Network
import androidx.compose.ui.test.assertIsDisplayed
import androidx.compose.ui.test.assertIsNotDisplayed
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onNodeWithTag
import androidx.compose.ui.test.performClick
import androidx.compose.ui.test.performScrollTo
import androidx.compose.ui.test.performTextClearance
import androidx.compose.ui.test.performTextInput
import androidx.core.content.ContextCompat
import androidx.core.content.ContextCompat.getSystemService
import com.android.unio.TearDown
import com.android.unio.addNewUserSocial
import com.android.unio.assertDisplayComponentInScroll
import com.android.unio.mocks.user.MockUser
import com.android.unio.model.strings.test_tags.InterestsOverlayTestTags
import com.android.unio.model.strings.test_tags.SocialsOverlayTestTags
import com.android.unio.model.strings.test_tags.UserEditionTestTags
import com.android.unio.model.user.User
import com.android.unio.ui.navigation.NavigationAction
import com.android.unio.ui.navigation.Screen
import com.android.unio.ui.user.UserProfileEditionScreenContent
import dagger.hilt.android.testing.HiltAndroidRule
import dagger.hilt.android.testing.HiltAndroidTest
import io.mockk.MockKAnnotations
import io.mockk.every
import io.mockk.impl.annotations.MockK
import io.mockk.mockk
import io.mockk.mockkStatic
import org.junit.Before
import org.junit.Rule
import org.junit.Test
Expand All @@ -32,6 +43,11 @@ class UserProfileEditionTest : TearDown() {
@get:Rule val composeTestRule = createComposeRule()
@get:Rule val hiltRule = HiltAndroidRule(this)

@MockK private lateinit var connectivityManager: ConnectivityManager

private lateinit var user: User
private var isOnlineUpdated: Boolean = false

@Before
fun setUp() {
MockKAnnotations.init(this, relaxed = true)
Expand All @@ -40,16 +56,116 @@ class UserProfileEditionTest : TearDown() {
navigationAction = mock(NavigationAction::class.java)
`when`(navigationAction.getCurrentRoute()).thenReturn(Screen.EDIT_PROFILE)

val user = MockUser.createMockUser(interests = emptyList(), profilePicture = "")
user = MockUser.createMockUser(interests = emptyList(), profilePicture = "")

val onOfflineChange = { newUser: User ->
user = newUser
isOnlineUpdated = false
}

val onOnlineChange = { newUser: User ->
user = newUser
isOnlineUpdated = true
}

mockkStatic(Network::class)
mockkStatic(ContextCompat::class)
every { getSystemService(any(), ConnectivityManager::class.java) } returns connectivityManager

composeTestRule.setContent {
UserProfileEditionScreenContent(
user, onDiscardChanges = { navigationAction.goBack() }, { uri, method -> method("") }, {})
user,
{ navigationAction.goBack() },
{ uri, method -> method("") },
onOnlineChange,
onOfflineChange)
}
}

@Test
fun testUpdateUserOffline() {
every { connectivityManager?.activeNetwork } returns null

composeTestRule
.onNodeWithTag(UserEditionTestTags.FIRST_NAME_TEXT_FIELD)
.assertDisplayComponentInScroll()
composeTestRule.onNodeWithTag(UserEditionTestTags.FIRST_NAME_TEXT_FIELD).performTextClearance()
composeTestRule.onNodeWithTag(UserEditionTestTags.FIRST_NAME_TEXT_FIELD).performClick()
composeTestRule
.onNodeWithTag(UserEditionTestTags.FIRST_NAME_TEXT_FIELD)
.performTextInput(UserUpdate.FIRST_NAME)

composeTestRule
.onNodeWithTag(UserEditionTestTags.LAST_NAME_TEXT_FIELD)
.assertDisplayComponentInScroll()
composeTestRule.onNodeWithTag(UserEditionTestTags.LAST_NAME_TEXT_FIELD).performTextClearance()
composeTestRule.onNodeWithTag(UserEditionTestTags.LAST_NAME_TEXT_FIELD).performClick()
composeTestRule
.onNodeWithTag(UserEditionTestTags.LAST_NAME_TEXT_FIELD)
.performTextInput(UserUpdate.LAST_NAME)

composeTestRule
.onNodeWithTag(UserEditionTestTags.BIOGRAPHY_TEXT_FIELD)
.assertDisplayComponentInScroll()
composeTestRule.onNodeWithTag(UserEditionTestTags.BIOGRAPHY_TEXT_FIELD).performTextClearance()
composeTestRule.onNodeWithTag(UserEditionTestTags.BIOGRAPHY_TEXT_FIELD).performClick()
composeTestRule
.onNodeWithTag(UserEditionTestTags.BIOGRAPHY_TEXT_FIELD)
.performTextInput(UserUpdate.BIOGRAPHY)

composeTestRule.onNodeWithTag(UserEditionTestTags.SAVE_BUTTON).assertDisplayComponentInScroll()
composeTestRule.onNodeWithTag(UserEditionTestTags.SAVE_BUTTON).performClick()

assert(user.firstName == UserUpdate.FIRST_NAME)
assert(user.lastName == UserUpdate.LAST_NAME)
assert(user.biography == UserUpdate.BIOGRAPHY)
assert(!isOnlineUpdated)
}

@Test
fun testUpdateUserOnline() {
every { connectivityManager?.activeNetwork } returns mockk<Network>()

composeTestRule
.onNodeWithTag(UserEditionTestTags.FIRST_NAME_TEXT_FIELD)
.assertDisplayComponentInScroll()
composeTestRule.onNodeWithTag(UserEditionTestTags.FIRST_NAME_TEXT_FIELD).performTextClearance()
composeTestRule.onNodeWithTag(UserEditionTestTags.FIRST_NAME_TEXT_FIELD).performClick()
composeTestRule
.onNodeWithTag(UserEditionTestTags.FIRST_NAME_TEXT_FIELD)
.performTextInput(UserUpdate.FIRST_NAME)

composeTestRule
.onNodeWithTag(UserEditionTestTags.LAST_NAME_TEXT_FIELD)
.assertDisplayComponentInScroll()
composeTestRule.onNodeWithTag(UserEditionTestTags.LAST_NAME_TEXT_FIELD).performTextClearance()
composeTestRule.onNodeWithTag(UserEditionTestTags.LAST_NAME_TEXT_FIELD).performClick()
composeTestRule
.onNodeWithTag(UserEditionTestTags.LAST_NAME_TEXT_FIELD)
.performTextInput(UserUpdate.LAST_NAME)

composeTestRule
.onNodeWithTag(UserEditionTestTags.BIOGRAPHY_TEXT_FIELD)
.assertDisplayComponentInScroll()
composeTestRule.onNodeWithTag(UserEditionTestTags.BIOGRAPHY_TEXT_FIELD).performTextClearance()
composeTestRule.onNodeWithTag(UserEditionTestTags.BIOGRAPHY_TEXT_FIELD).performClick()
composeTestRule
.onNodeWithTag(UserEditionTestTags.BIOGRAPHY_TEXT_FIELD)
.performTextInput(UserUpdate.BIOGRAPHY)

composeTestRule.onNodeWithTag(UserEditionTestTags.SAVE_BUTTON).assertDisplayComponentInScroll()
composeTestRule.onNodeWithTag(UserEditionTestTags.SAVE_BUTTON).performClick()

assert(user.firstName == UserUpdate.FIRST_NAME)
assert(user.lastName == UserUpdate.LAST_NAME)
assert(user.biography == UserUpdate.BIOGRAPHY)
assert(isOnlineUpdated)
}

@Test
fun testEverythingIsDisplayed() {
every { connectivityManager?.activeNetwork } returns mockk<Network>()

composeTestRule.onNodeWithTag(UserEditionTestTags.DISCARD_TEXT).assertIsDisplayed()
composeTestRule
.onNodeWithTag(UserEditionTestTags.FIRST_NAME_TEXT, useUnmergedTree = true)
Expand All @@ -66,6 +182,8 @@ class UserProfileEditionTest : TearDown() {

@Test
fun testInterestsButtonWorksCorrectly() {
every { connectivityManager?.activeNetwork } returns mockk<Network>()

composeTestRule
.onNodeWithTag(UserEditionTestTags.INTERESTS_BUTTON)
.performScrollTo()
Expand All @@ -75,6 +193,8 @@ class UserProfileEditionTest : TearDown() {

@Test
fun testSocialsButtonWorksCorrectly() {
every { connectivityManager?.activeNetwork } returns mockk<Network>()

composeTestRule
.onNodeWithTag(UserEditionTestTags.SOCIALS_BUTTON)
.performScrollTo()
Expand All @@ -84,6 +204,8 @@ class UserProfileEditionTest : TearDown() {

@Test
fun testAddingInterestsCorrectlyModifiesTheFlowRow() {
every { connectivityManager?.activeNetwork } returns mockk<Network>()

composeTestRule
.onNodeWithTag(UserEditionTestTags.INTERESTS_BUTTON)
.performScrollTo()
Expand All @@ -104,6 +226,8 @@ class UserProfileEditionTest : TearDown() {

@Test
fun testAddingSocialsCorrectlyModifiesTheFlowRow() {
every { connectivityManager?.activeNetwork } returns mockk<Network>()

composeTestRule
.onNodeWithTag(UserEditionTestTags.SOCIALS_BUTTON)
.performScrollTo()
Expand All @@ -121,6 +245,8 @@ class UserProfileEditionTest : TearDown() {

@Test
fun testCorrectlyExitsInterestOverlayScreen() {
every { connectivityManager?.activeNetwork } returns mockk<Network>()

composeTestRule
.onNodeWithTag(UserEditionTestTags.INTERESTS_BUTTON)
.performScrollTo()
Expand All @@ -131,6 +257,8 @@ class UserProfileEditionTest : TearDown() {

@Test
fun testCorrectlyDisplaysErrorWhenFirstNameIsEmpty() {
every { connectivityManager?.activeNetwork } returns mockk<Network>()

composeTestRule.onNodeWithTag(UserEditionTestTags.FIRST_NAME_TEXT_FIELD).performTextClearance()
composeTestRule.onNodeWithTag(UserEditionTestTags.LAST_NAME_TEXT_FIELD).performTextClearance()

Expand All @@ -142,4 +270,10 @@ class UserProfileEditionTest : TearDown() {
.onNodeWithTag(UserEditionTestTags.LAST_NAME_ERROR_TEXT, useUnmergedTree = true)
.assertExists()
}

object UserUpdate {
const val FIRST_NAME = "Johnny"
const val LAST_NAME = "Däpp"
const val BIOGRAPHY = "Ich bin ein Testbenutzer"
}
}
36 changes: 29 additions & 7 deletions app/src/main/java/com/android/unio/ui/user/UserProfileEdition.kt
Original file line number Diff line number Diff line change
Expand Up @@ -48,14 +48,13 @@ import com.android.unio.model.user.UserSocial
import com.android.unio.model.user.UserViewModel
import com.android.unio.model.user.checkImageUri
import com.android.unio.model.user.checkNewUser
import com.android.unio.model.utils.Utils
import com.android.unio.ui.authentication.overlay.InterestOverlay
import com.android.unio.ui.authentication.overlay.SocialOverlay
import com.android.unio.ui.components.InterestInputChip
import com.android.unio.ui.components.ProfilePicturePicker
import com.android.unio.ui.components.SocialInputChip
import com.android.unio.ui.navigation.NavigationAction
import com.google.firebase.Firebase
import com.google.firebase.auth.auth
import kotlinx.coroutines.flow.MutableStateFlow

@Composable
Expand All @@ -66,9 +65,9 @@ fun UserProfileEditionScreen(
) {

val context = LocalContext.current
val userId = Firebase.auth.currentUser?.uid

val user by userViewModel.user.collectAsState()
val userId = user!!.uid

UserProfileEditionScreenContent(
user = user!!,
Expand Down Expand Up @@ -97,7 +96,7 @@ fun UserProfileEditionScreen(
}
}
},
onUploadUser = { modifiedUser ->
onUploadUserOnline = { modifiedUser ->
userViewModel.addUser(
modifiedUser,
onSuccess = {
Expand All @@ -108,6 +107,23 @@ fun UserProfileEditionScreen(
.show()
navigationAction.goBack()
})
},
onUploadUserOffline = { modifiedUser ->
Toast.makeText(
context,
context.getString(R.string.user_settings_modified_offline),
Toast.LENGTH_LONG)
.show()
userViewModel.addUser(
modifiedUser,
onSuccess = {
Toast.makeText(
context,
context.getString(R.string.user_settings_modified_successfully),
Toast.LENGTH_SHORT)
.show()
})
navigationAction.goBack()
})
}

Expand All @@ -117,7 +133,8 @@ fun UserProfileEditionScreenContent(
user: User,
onDiscardChanges: () -> Unit,
onModifyUser: (MutableState<Uri>, (String) -> Unit) -> Unit,
onUploadUser: (User) -> Unit,
onUploadUserOnline: (User) -> Unit,
onUploadUserOffline: (User) -> Unit
) {

val context = LocalContext.current
Expand All @@ -141,7 +158,7 @@ fun UserProfileEditionScreenContent(
// But if it's the first time entering the page the uri will be the one from firebase
// and therefore cannot be opened in a input stream in the onModifyUser function
// Hence we must check whether the user has changed his profile picture or not to get a local URI.
val profilePictureUri = remember { mutableStateOf<Uri>(user.profilePicture.toUri()) }
val profilePictureUri = remember { mutableStateOf(user.profilePicture.toUri()) }

var showInterestsOverlay by remember { mutableStateOf(false) }
var showSocialsOverlay by remember { mutableStateOf(false) }
Expand All @@ -153,6 +170,7 @@ fun UserProfileEditionScreenContent(
* simply be copied from the user.
*/
val createUser: (String) -> Unit = { uri ->
val hasInternet = Utils.checkInternetConnection(context)
val newUser =
User(
uid = user.uid,
Expand All @@ -169,7 +187,11 @@ fun UserProfileEditionScreenContent(

isErrors = checkNewUser(newUser)
if (isErrors.isEmpty()) {
onUploadUser(newUser)
if (hasInternet) {
onUploadUserOnline(newUser)
} else {
onUploadUserOffline(newUser)
}
}
}

Expand Down
1 change: 1 addition & 0 deletions app/src/main/res/values-fr/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@
<string name="user_settings_discard_changes" translatable="true">Annuler vos modifications</string>
<string name="user_settings_save_changes" translatable="true">Sauvegarder vos modifications</string>
<string name="user_settings_modified_successfully" translatable="true">Changements correctement modifié</string>
<string name="user_settings_modified_offline">Changements enregistrés. Connectez-vous à Internet pour appliquer les changements</string>



Expand Down
1 change: 1 addition & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@
<string name="user_settings_discard_changes" translatable="true">"Discard Changes"</string>
<string name="user_settings_save_changes" translatable="true">Save changes</string>
<string name="user_settings_modified_successfully" translatable="true">Changes Successfully modified</string>
<string name="user_settings_modified_offline">Change has been saved. Turn online to apply change</string>


<!-- EmailVerification Strings -->
Expand Down

0 comments on commit 7c6c95a

Please sign in to comment.