Repository: element-hq/element-x-android (language: kotlin)

Issue:
[Task] Preload account management URLs
A memory cache has been implemented in the SDK. See https://github.com/matrix-org/matrix-rust-sdk/pull/4663

We need the application to pre-load the 2 accounts management URLs to populate the in-memory cache. That way, when the user open the settings, the flickering will not be observed for the two entries:

<img width="366" alt="Image" src="https://github.com/user-attachments/assets/9b636d5e-95fc-40a1-a438-96faef34071a" />

Note that if the app is started without network access, the url cannot be loaded and the settings entries will not be displayed.

There is no change expected on the setting screen, that should still requires the URLs from the SDK.


Discussion hints:
nan

Pull request: Preload account urls
<!-- Please read [CONTRIBUTING.md](https://github.com/element-hq/element-x-android/blob/develop/CONTRIBUTING.md) before submitting your pull request -->
 
## Content

<!-- Describe shortly what has been changed -->
Preload account management URL into SDK memory cache.

## Motivation and context

<!-- Provide link to the corresponding issue if applicable or explain the context -->
Closes #4300

## Screenshots / GIFs

<!--
We have screenshot tests in the project, so attaching screenshots to a PR is not mandatory, as far as there
is a Composable Preview covering the changes. In this case, the change will appear in the file diff.
Note that all the UI composables should be covered by a Composable Preview.

Providing a video of the change is still very useful for the reviewer and for the history of the project.

You can use a table like this to show screenshots comparison.
Uncomment this markdown table below and edit the last line `|||`:
|copy screenshot of before here|copy screenshot of after here|

|Before|After|
|-|-|
|||
 -->

## Tests

<!-- Explain how you tested your development -->

- Signin using an OIDC managed account
- Open the settings
- All the items in the settings screen should load instantely.

## Tested devices

- [ ] Physical
- [x] Emulator
- OS version(s):

## Checklist

<!-- Depending on the Pull Request content, it can be acceptable if some of the following checkboxes stay unchecked. -->

- [ ] Changes have been tested on an Android device or Android emulator with API 24
- [ ] UI change has been tested on both light and dark themes
- [ ] Accessibility has been taken into account. See https://github.com/element-hq/element-x-android/blob/develop/CONTRIBUTING.md#accessibility
- [ ] Pull request is based on the develop branch
- [ ] Pull request title will be used in the release note, it clearly define what will change for the user
- [ ] Pull request includes screenshots or videos if containing UI changes
- [ ] You've made a self review of your PR


Test command: ./gradlew :features:preferences:impl:testDebugUnitTest --tests "io.element.android.features.preferences.impl.root.PreferencesRootPresenterTest" :appnav:testDebugUnitTest --tests "io.element.android.appnav.loggedin.LoggedInPresenterTest"

Fix patch:
diff --git a/appnav/src/main/kotlin/io/element/android/appnav/loggedin/LoggedInPresenter.kt b/appnav/src/main/kotlin/io/element/android/appnav/loggedin/LoggedInPresenter.kt
index 2539f9e1d54..fbecfeb60b8 100644
--- a/appnav/src/main/kotlin/io/element/android/appnav/loggedin/LoggedInPresenter.kt
+++ b/appnav/src/main/kotlin/io/element/android/appnav/loggedin/LoggedInPresenter.kt
@@ -26,6 +26,7 @@ import io.element.android.libraries.core.meta.BuildMeta
 import io.element.android.libraries.matrix.api.MatrixClient
 import io.element.android.libraries.matrix.api.encryption.EncryptionService
 import io.element.android.libraries.matrix.api.encryption.RecoveryState
+import io.element.android.libraries.matrix.api.oidc.AccountManagementAction
 import io.element.android.libraries.matrix.api.roomlist.RoomListService
 import io.element.android.libraries.matrix.api.sync.SlidingSyncVersion
 import io.element.android.libraries.matrix.api.sync.SyncService
@@ -35,6 +36,7 @@ import io.element.android.libraries.matrix.api.verification.SessionVerifiedStatu
 import io.element.android.libraries.push.api.PushService
 import io.element.android.libraries.pushproviders.api.RegistrationFailure
 import io.element.android.services.analytics.api.AnalyticsService
+import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.flow.combine
 import kotlinx.coroutines.flow.launchIn
 import kotlinx.coroutines.flow.onEach
@@ -60,6 +62,7 @@ class LoggedInPresenter @Inject constructor(
             pushService.ignoreRegistrationError(matrixClient.sessionId)
         }.collectAsState(initial = false)
         val pusherRegistrationState = remember<MutableState<AsyncData<Unit>>> { mutableStateOf(AsyncData.Uninitialized) }
+        LaunchedEffect(Unit) { preloadAccountManagementUrl() }
         LaunchedEffect(Unit) {
             sessionVerificationService.sessionVerifiedStatus
                 .onEach { sessionVerifiedStatus ->
@@ -202,4 +205,9 @@ class LoggedInPresenter @Inject constructor(
             analyticsService.capture(CryptoSessionStateChange(changeRecoveryState, changeVerificationState))
         }
     }
+
+    private fun CoroutineScope.preloadAccountManagementUrl() = launch {
+        matrixClient.getAccountManagementUrl(AccountManagementAction.Profile)
+        matrixClient.getAccountManagementUrl(AccountManagementAction.SessionsList)
+    }
 }


Test patch:
diff --git a/appnav/src/test/kotlin/io/element/android/appnav/loggedin/LoggedInPresenterTest.kt b/appnav/src/test/kotlin/io/element/android/appnav/loggedin/LoggedInPresenterTest.kt
index bfd416eaf3a..aac40e000ce 100644
--- a/appnav/src/test/kotlin/io/element/android/appnav/loggedin/LoggedInPresenterTest.kt
+++ b/appnav/src/test/kotlin/io/element/android/appnav/loggedin/LoggedInPresenterTest.kt
@@ -5,12 +5,11 @@
  * Please see LICENSE files in the repository root for full details.
  */
 
+@file:OptIn(ExperimentalCoroutinesApi::class)
+
 package io.element.android.appnav.loggedin
 
-import app.cash.molecule.RecompositionMode
-import app.cash.molecule.moleculeFlow
 import app.cash.turbine.ReceiveTurbine
-import app.cash.turbine.test
 import com.google.common.truth.Truth.assertThat
 import im.vector.app.features.analytics.plan.CryptoSessionStateChange
 import im.vector.app.features.analytics.plan.UserProperties
@@ -19,6 +18,7 @@ import io.element.android.libraries.matrix.api.MatrixClient
 import io.element.android.libraries.matrix.api.core.SessionId
 import io.element.android.libraries.matrix.api.encryption.EncryptionService
 import io.element.android.libraries.matrix.api.encryption.RecoveryState
+import io.element.android.libraries.matrix.api.oidc.AccountManagementAction
 import io.element.android.libraries.matrix.api.roomlist.RoomListService
 import io.element.android.libraries.matrix.api.sync.SlidingSyncVersion
 import io.element.android.libraries.matrix.api.sync.SyncState
@@ -45,8 +45,8 @@ import io.element.android.tests.testutils.lambda.any
 import io.element.android.tests.testutils.lambda.lambdaError
 import io.element.android.tests.testutils.lambda.lambdaRecorder
 import io.element.android.tests.testutils.lambda.value
+import io.element.android.tests.testutils.test
 import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.test.TestScope
 import kotlinx.coroutines.test.advanceUntilIdle
 import kotlinx.coroutines.test.runTest
 import org.junit.Rule
@@ -58,10 +58,7 @@ class LoggedInPresenterTest {
 
     @Test
     fun `present - initial state`() = runTest {
-        val presenter = createLoggedInPresenter()
-        moleculeFlow(RecompositionMode.Immediate) {
-            presenter.present()
-        }.test {
+        createLoggedInPresenter().test {
             val initialState = awaitItem()
             assertThat(initialState.showSyncSpinner).isFalse()
             assertThat(initialState.pusherRegistrationState.isUninitialized()).isTrue()
@@ -69,13 +66,32 @@ class LoggedInPresenterTest {
         }
     }
 
+    @Test
+    fun `present - ensure that account urls are preloaded`() = runTest {
+        val accountManagementUrlResult = lambdaRecorder<AccountManagementAction?, Result<String?>> { Result.success("aUrl") }
+        val matrixClient = FakeMatrixClient(
+            accountManagementUrlResult = accountManagementUrlResult,
+        )
+        createLoggedInPresenter(
+            matrixClient = matrixClient,
+        ).test {
+            awaitItem()
+            advanceUntilIdle()
+            accountManagementUrlResult.assertions().isCalledExactly(2)
+                .withSequence(
+                    listOf(value(AccountManagementAction.Profile)),
+                    listOf(value(AccountManagementAction.SessionsList)),
+                )
+        }
+    }
+
     @Test
     fun `present - show sync spinner`() = runTest {
         val roomListService = FakeRoomListService()
-        val presenter = createLoggedInPresenter(roomListService, SyncState.Running)
-        moleculeFlow(RecompositionMode.Immediate) {
-            presenter.present()
-        }.test {
+        createLoggedInPresenter(
+            syncState = SyncState.Running,
+            matrixClient = FakeMatrixClient(roomListService = roomListService),
+        ).test {
             val initialState = awaitItem()
             assertThat(initialState.showSyncSpinner).isFalse()
             roomListService.postSyncIndicator(RoomListService.SyncIndicator.Show)
@@ -92,18 +108,18 @@ class LoggedInPresenterTest {
         val verificationService = FakeSessionVerificationService()
         val encryptionService = FakeEncryptionService()
         val buildMeta = aBuildMeta()
-        val presenter = LoggedInPresenter(
-            matrixClient = FakeMatrixClient(roomListService = roomListService, encryptionService = encryptionService),
+        LoggedInPresenter(
+            matrixClient = FakeMatrixClient(
+                roomListService = roomListService,
+                encryptionService = encryptionService,
+            ),
             syncService = FakeSyncService(initialSyncState = SyncState.Running),
             pushService = FakePushService(),
             sessionVerificationService = verificationService,
             analyticsService = analyticsService,
             encryptionService = encryptionService,
             buildMeta = buildMeta,
-        )
-        moleculeFlow(RecompositionMode.Immediate) {
-            presenter.present()
-        }.test {
+        ).test {
             encryptionService.emitRecoveryState(RecoveryState.UNKNOWN)
             encryptionService.emitRecoveryState(RecoveryState.INCOMPLETE)
             verificationService.emitVerifiedStatus(SessionVerifiedStatus.Verified)
@@ -129,13 +145,10 @@ class LoggedInPresenterTest {
         val verificationService = FakeSessionVerificationService(
             initialSessionVerifiedStatus = SessionVerifiedStatus.NotVerified
         )
-        val presenter = createLoggedInPresenter(
+        createLoggedInPresenter(
             pushService = pushService,
             sessionVerificationService = verificationService,
-        )
-        moleculeFlow(RecompositionMode.Immediate) {
-            presenter.present()
-        }.test {
+        ).test {
             val finalState = awaitFirstItem()
             assertThat(finalState.pusherRegistrationState.errorOrNull())
                 .isInstanceOf(PusherRegistrationFailure.AccountNotVerified::class.java)
@@ -155,13 +168,13 @@ class LoggedInPresenterTest {
         val pushService = createFakePushService(
             registerWithLambda = lambda,
         )
-        val presenter = createLoggedInPresenter(
+        createLoggedInPresenter(
             pushService = pushService,
             sessionVerificationService = sessionVerificationService,
-        )
-        moleculeFlow(RecompositionMode.Immediate) {
-            presenter.present()
-        }.test {
+            matrixClient = FakeMatrixClient(
+                accountManagementUrlResult = { Result.success(null) },
+            ),
+        ).test {
             val finalState = awaitFirstItem()
             assertThat(finalState.pusherRegistrationState.isSuccess()).isTrue()
             lambda.assertions()
@@ -188,13 +201,13 @@ class LoggedInPresenterTest {
         val pushService = createFakePushService(
             registerWithLambda = lambda,
         )
-        val presenter = createLoggedInPresenter(
+        createLoggedInPresenter(
             pushService = pushService,
             sessionVerificationService = sessionVerificationService,
-        )
-        moleculeFlow(RecompositionMode.Immediate) {
-            presenter.present()
-        }.test {
+            matrixClient = FakeMatrixClient(
+                accountManagementUrlResult = { Result.success(null) },
+            ),
+        ).test {
             val finalState = awaitFirstItem()
             assertThat(finalState.pusherRegistrationState.isFailure()).isTrue()
             lambda.assertions()
@@ -233,13 +246,13 @@ class LoggedInPresenterTest {
             currentPushProvider = { pushProvider },
             registerWithLambda = lambda,
         )
-        val presenter = createLoggedInPresenter(
+        createLoggedInPresenter(
             pushService = pushService,
             sessionVerificationService = sessionVerificationService,
-        )
-        moleculeFlow(RecompositionMode.Immediate) {
-            presenter.present()
-        }.test {
+            matrixClient = FakeMatrixClient(
+                accountManagementUrlResult = { Result.success(null) },
+            ),
+        ).test {
             val finalState = awaitFirstItem()
             assertThat(finalState.pusherRegistrationState.isSuccess()).isTrue()
             lambda.assertions()
@@ -277,13 +290,13 @@ class LoggedInPresenterTest {
             currentPushProvider = { pushProvider },
             registerWithLambda = lambda,
         )
-        val presenter = createLoggedInPresenter(
+        createLoggedInPresenter(
             pushService = pushService,
             sessionVerificationService = sessionVerificationService,
-        )
-        moleculeFlow(RecompositionMode.Immediate) {
-            presenter.present()
-        }.test {
+            matrixClient = FakeMatrixClient(
+                accountManagementUrlResult = { Result.success(null) },
+            ),
+        ).test {
             val finalState = awaitFirstItem()
             assertThat(finalState.pusherRegistrationState.isSuccess()).isTrue()
             lambda.assertions()
@@ -317,13 +330,10 @@ class LoggedInPresenterTest {
             currentPushProvider = { pushProvider },
             registerWithLambda = lambda,
         )
-        val presenter = createLoggedInPresenter(
+        createLoggedInPresenter(
             pushService = pushService,
             sessionVerificationService = sessionVerificationService,
-        )
-        moleculeFlow(RecompositionMode.Immediate) {
-            presenter.present()
-        }.test {
+        ).test {
             val finalState = awaitFirstItem()
             assertThat(finalState.pusherRegistrationState.errorOrNull())
                 .isInstanceOf(PusherRegistrationFailure.NoDistributorsAvailable::class.java)
@@ -345,13 +355,10 @@ class LoggedInPresenterTest {
             registerWithLambda = lambda,
             setIgnoreRegistrationErrorLambda = setIgnoreRegistrationErrorLambda,
         )
-        val presenter = createLoggedInPresenter(
+        createLoggedInPresenter(
             pushService = pushService,
             sessionVerificationService = sessionVerificationService,
-        )
-        moleculeFlow(RecompositionMode.Immediate) {
-            presenter.present()
-        }.test {
+        ).test {
             val finalState = awaitFirstItem()
             assertThat(finalState.pusherRegistrationState.errorOrNull())
                 .isInstanceOf(PusherRegistrationFailure.NoProvidersAvailable::class.java)
@@ -394,13 +401,10 @@ class LoggedInPresenterTest {
             registerWithLambda = lambda,
             selectPushProviderLambda = selectPushProviderLambda,
         )
-        val presenter = createLoggedInPresenter(
+        createLoggedInPresenter(
             pushService = pushService,
             sessionVerificationService = sessionVerificationService,
-        )
-        moleculeFlow(RecompositionMode.Immediate) {
-            presenter.present()
-        }.test {
+        ).test {
             val finalState = awaitFirstItem()
             assertThat(finalState.pusherRegistrationState.errorOrNull())
                 .isInstanceOf(PusherRegistrationFailure.NoDistributorsAvailable::class.java)
@@ -445,13 +449,13 @@ class LoggedInPresenterTest {
             pushProvider1 = pushProvider1,
             registerWithLambda = lambda,
         )
-        val presenter = createLoggedInPresenter(
+        createLoggedInPresenter(
             pushService = pushService,
             sessionVerificationService = sessionVerificationService,
-        )
-        moleculeFlow(RecompositionMode.Immediate) {
-            presenter.present()
-        }.test {
+            matrixClient = FakeMatrixClient(
+                accountManagementUrlResult = { Result.success(null) },
+            ),
+        ).test {
             val finalState = awaitFirstItem()
             assertThat(finalState.pusherRegistrationState.isSuccess()).isTrue()
             lambda.assertions().isCalledOnce()
@@ -505,10 +509,9 @@ class LoggedInPresenterTest {
             currentSlidingSyncVersionLambda = { Result.success(SlidingSyncVersion.Proxy) },
             availableSlidingSyncVersionsLambda = { Result.success(listOf(SlidingSyncVersion.Native)) },
         )
-        val presenter = createLoggedInPresenter(matrixClient = matrixClient)
-        moleculeFlow(RecompositionMode.Immediate) {
-            presenter.present()
-        }.test {
+        createLoggedInPresenter(
+            matrixClient = matrixClient,
+        ).test {
             val initialState = awaitItem()
             assertThat(initialState.forceNativeSlidingSyncMigration).isFalse()
 
@@ -526,13 +529,14 @@ class LoggedInPresenterTest {
             assertThat(ignoreSdkError).isTrue()
             null
         }
-        val matrixClient = FakeMatrixClient().apply {
+        val matrixClient = FakeMatrixClient(
+            accountManagementUrlResult = { Result.success(null) },
+        ).apply {
             this.logoutLambda = logoutLambda
         }
-        val presenter = createLoggedInPresenter(matrixClient = matrixClient)
-        moleculeFlow(RecompositionMode.Immediate) {
-            presenter.present()
-        }.test {
+        createLoggedInPresenter(
+            matrixClient = matrixClient,
+        ).test {
             val initialState = awaitItem()
 
             initialState.eventSink(LoggedInEvents.LogoutAndMigrateToNativeSlidingSync)
@@ -548,14 +552,15 @@ class LoggedInPresenterTest {
         return awaitItem()
     }
 
-    private fun TestScope.createLoggedInPresenter(
-        roomListService: RoomListService = FakeRoomListService(),
+    private fun createLoggedInPresenter(
         syncState: SyncState = SyncState.Running,
         analyticsService: AnalyticsService = FakeAnalyticsService(),
         sessionVerificationService: SessionVerificationService = FakeSessionVerificationService(),
         encryptionService: EncryptionService = FakeEncryptionService(),
         pushService: PushService = FakePushService(),
-        matrixClient: MatrixClient = FakeMatrixClient(roomListService = roomListService),
+        matrixClient: MatrixClient = FakeMatrixClient(
+            accountManagementUrlResult = { Result.success(null) },
+        ),
         buildMeta: BuildMeta = aBuildMeta(),
     ): LoggedInPresenter {
         return LoggedInPresenter(
diff --git a/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/root/PreferencesRootPresenterTest.kt b/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/root/PreferencesRootPresenterTest.kt
index 6f85c436210..72ae8bdb10e 100644
--- a/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/root/PreferencesRootPresenterTest.kt
+++ b/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/root/PreferencesRootPresenterTest.kt
@@ -5,12 +5,11 @@
  * Please see LICENSE files in the repository root for full details.
  */
 
+@file:OptIn(ExperimentalCoroutinesApi::class)
+
 package io.element.android.features.preferences.impl.root
 
-import app.cash.molecule.RecompositionMode
-import app.cash.molecule.moleculeFlow
 import app.cash.turbine.ReceiveTurbine
-import app.cash.turbine.test
 import com.google.common.truth.Truth.assertThat
 import io.element.android.features.logout.api.direct.aDirectLogoutState
 import io.element.android.features.preferences.impl.utils.ShowDeveloperSettingsProvider
@@ -18,6 +17,7 @@ import io.element.android.libraries.core.meta.BuildType
 import io.element.android.libraries.designsystem.utils.snackbar.SnackbarDispatcher
 import io.element.android.libraries.featureflag.test.FakeFeatureFlagService
 import io.element.android.libraries.indicator.impl.DefaultIndicatorService
+import io.element.android.libraries.matrix.api.oidc.AccountManagementAction
 import io.element.android.libraries.matrix.api.user.MatrixUser
 import io.element.android.libraries.matrix.test.AN_AVATAR_URL
 import io.element.android.libraries.matrix.test.A_USER_NAME
@@ -27,6 +27,10 @@ import io.element.android.libraries.matrix.test.encryption.FakeEncryptionService
 import io.element.android.libraries.matrix.test.verification.FakeSessionVerificationService
 import io.element.android.services.analytics.test.FakeAnalyticsService
 import io.element.android.tests.testutils.WarmUpRule
+import io.element.android.tests.testutils.lambda.lambdaRecorder
+import io.element.android.tests.testutils.lambda.value
+import io.element.android.tests.testutils.test
+import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.test.runTest
 import org.junit.Rule
 import org.junit.Test
@@ -37,11 +41,16 @@ class PreferencesRootPresenterTest {
 
     @Test
     fun `present - initial state`() = runTest {
-        val matrixClient = FakeMatrixClient(canDeactivateAccountResult = { true })
-        val presenter = createPresenter(matrixClient = matrixClient)
-        moleculeFlow(RecompositionMode.Immediate) {
-            presenter.present()
-        }.test {
+        val accountManagementUrlResult = lambdaRecorder<AccountManagementAction?, Result<String?>> { action ->
+            Result.success("$action url")
+        }
+        val matrixClient = FakeMatrixClient(
+            canDeactivateAccountResult = { true },
+            accountManagementUrlResult = accountManagementUrlResult,
+        )
+        createPresenter(
+            matrixClient = matrixClient,
+        ).test {
             val initialState = awaitItem()
             assertThat(initialState.myUser).isEqualTo(
                 MatrixUser(
@@ -71,19 +80,26 @@ class PreferencesRootPresenterTest {
             assertThat(loadedState.canDeactivateAccount).isTrue()
             assertThat(loadedState.directLogoutState).isEqualTo(aDirectLogoutState())
             assertThat(loadedState.snackbarMessage).isNull()
+            skipItems(1)
+            val finalState = awaitItem()
+            accountManagementUrlResult.assertions().isCalledExactly(2)
+                .withSequence(
+                    listOf(value(AccountManagementAction.Profile)),
+                    listOf(value(AccountManagementAction.SessionsList)),
+                )
+            assertThat(finalState.accountManagementUrl).isEqualTo("Profile url")
+            assertThat(finalState.devicesManagementUrl).isEqualTo("SessionsList url")
         }
     }
 
     @Test
     fun `present - can deactivate account is false if the Matrix client say so`() = runTest {
-        val presenter = createPresenter(
+        createPresenter(
             matrixClient = FakeMatrixClient(
-                canDeactivateAccountResult = { false }
-            )
-        )
-        moleculeFlow(RecompositionMode.Immediate) {
-            presenter.present()
-        }.test {
+                canDeactivateAccountResult = { false },
+                accountManagementUrlResult = { Result.success(null) },
+            ),
+        ).test {
             val loadedState = awaitFirstItem()
             assertThat(loadedState.canDeactivateAccount).isFalse()
         }
@@ -91,12 +107,13 @@ class PreferencesRootPresenterTest {
 
     @Test
     fun `present - developer settings is hidden by default in release builds`() = runTest {
-        val presenter = createPresenter(
+        createPresenter(
+            matrixClient = FakeMatrixClient(
+                canDeactivateAccountResult = { true },
+                accountManagementUrlResult = { Result.success(null) },
+            ),
             showDeveloperSettingsProvider = ShowDeveloperSettingsProvider(aBuildMeta(BuildType.RELEASE))
-        )
-        moleculeFlow(RecompositionMode.Immediate) {
-            presenter.present()
-        }.test {
+        ).test {
             val loadedState = awaitFirstItem()
             assertThat(loadedState.showDeveloperSettings).isFalse()
         }
@@ -104,12 +121,13 @@ class PreferencesRootPresenterTest {
 
     @Test
     fun `present - developer settings can be enabled in release builds`() = runTest {
-        val presenter = createPresenter(
+        createPresenter(
+            matrixClient = FakeMatrixClient(
+                canDeactivateAccountResult = { true },
+                accountManagementUrlResult = { Result.success(null) },
+            ),
             showDeveloperSettingsProvider = ShowDeveloperSettingsProvider(aBuildMeta(BuildType.RELEASE))
-        )
-        moleculeFlow(RecompositionMode.Immediate) {
-            presenter.present()
-        }.test {
+        ).test {
             val loadedState = awaitFirstItem()
             repeat(times = ShowDeveloperSettingsProvider.DEVELOPER_SETTINGS_COUNTER) {
                 assertThat(loadedState.showDeveloperSettings).isFalse()
@@ -125,7 +143,7 @@ class PreferencesRootPresenterTest {
     }
 
     private fun createPresenter(
-        matrixClient: FakeMatrixClient = FakeMatrixClient(canDeactivateAccountResult = { true }),
+        matrixClient: FakeMatrixClient = FakeMatrixClient(),
         sessionVerificationService: FakeSessionVerificationService = FakeSessionVerificationService(),
         showDeveloperSettingsProvider: ShowDeveloperSettingsProvider = ShowDeveloperSettingsProvider(aBuildMeta(BuildType.DEBUG)),
     ) = PreferencesRootPresenter(
diff --git a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/FakeMatrixClient.kt b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/FakeMatrixClient.kt
index 93c2d4c075a..030e8db7131 100644
--- a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/FakeMatrixClient.kt
+++ b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/FakeMatrixClient.kt
@@ -72,11 +72,11 @@ class FakeMatrixClient(
     private val syncService: FakeSyncService = FakeSyncService(),
     private val encryptionService: FakeEncryptionService = FakeEncryptionService(),
     private val roomDirectoryService: RoomDirectoryService = FakeRoomDirectoryService(),
-    private val accountManagementUrlString: Result<String?> = Result.success(null),
+    private val accountManagementUrlResult: (AccountManagementAction?) -> Result<String?> = { lambdaError() },
     private val resolveRoomAliasResult: (RoomAlias) -> Result<Optional<ResolvedRoomAlias>> = {
         Result.success(
-        Optional.of(ResolvedRoomAlias(A_ROOM_ID, emptyList()))
-    )
+            Optional.of(ResolvedRoomAlias(A_ROOM_ID, emptyList()))
+        )
     },
     private val getRoomPreviewResult: (RoomIdOrAlias, List<String>) -> Result<RoomPreview> = { _, _ -> Result.failure(AN_EXCEPTION) },
     private val clearCacheLambda: () -> Unit = { lambdaError() },
@@ -192,8 +192,8 @@ class FakeMatrixClient(
         return Result.success(result)
     }
 
-    override suspend fun getAccountManagementUrl(action: AccountManagementAction?): Result<String?> {
-        return accountManagementUrlString
+    override suspend fun getAccountManagementUrl(action: AccountManagementAction?): Result<String?> = simulateLongTask {
+        accountManagementUrlResult(action)
     }
 
     override suspend fun uploadMedia(