create room : fix tests and remove auto-fill alias for now.
This commit is contained in:
@@ -46,6 +46,7 @@ class CreateRoomDataStore @Inject constructor(
|
||||
|
||||
fun setRoomName(roomName: String) {
|
||||
createRoomConfigFlow.getAndUpdate { config ->
|
||||
/*
|
||||
val newVisibility = when (config.roomVisibility) {
|
||||
is RoomVisibilityState.Public -> {
|
||||
val roomAddress = config.roomVisibility.roomAddress
|
||||
@@ -59,9 +60,9 @@ class CreateRoomDataStore @Inject constructor(
|
||||
}
|
||||
else -> config.roomVisibility
|
||||
}
|
||||
*/
|
||||
config.copy(
|
||||
roomName = roomName.takeIf { it.isNotEmpty() },
|
||||
roomVisibility = newVisibility,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,6 @@ import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.selection.selectable
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
@@ -36,13 +35,13 @@ fun RoomAccessOption(
|
||||
isSelected: Boolean = false,
|
||||
) {
|
||||
Row(
|
||||
modifier
|
||||
.fillMaxWidth()
|
||||
.selectable(
|
||||
selected = isSelected,
|
||||
onClick = { onOptionClick(roomAccessItem) },
|
||||
role = Role.RadioButton,
|
||||
)
|
||||
modifier
|
||||
.fillMaxWidth()
|
||||
.selectable(
|
||||
selected = isSelected,
|
||||
onClick = { onOptionClick(roomAccessItem) },
|
||||
role = Role.RadioButton,
|
||||
)
|
||||
) {
|
||||
Column(Modifier.weight(1f)) {
|
||||
Text(
|
||||
@@ -59,8 +58,8 @@ fun RoomAccessOption(
|
||||
}
|
||||
RadioButton(
|
||||
modifier = Modifier
|
||||
.align(Alignment.CenterVertically)
|
||||
.size(48.dp),
|
||||
.align(Alignment.CenterVertically)
|
||||
.size(48.dp),
|
||||
selected = isSelected,
|
||||
// null recommended for accessibility with screenreaders
|
||||
onClick = null
|
||||
|
||||
@@ -50,7 +50,7 @@ fun RoomVisibilityOption(
|
||||
)
|
||||
) {
|
||||
Box(
|
||||
modifier = modifier
|
||||
modifier = Modifier
|
||||
.size(30.dp)
|
||||
.clip(RoundedCornerShape(8.dp))
|
||||
.background(ElementTheme.colors.bgSubtleSecondary)
|
||||
@@ -60,7 +60,7 @@ fun RoomVisibilityOption(
|
||||
Icon(
|
||||
resourceId = roomPrivacyItem.icon,
|
||||
contentDescription = null,
|
||||
tint = if(isSelected) ElementTheme.colors.iconPrimary else ElementTheme.colors.iconSecondary,
|
||||
tint = if (isSelected) ElementTheme.colors.iconPrimary else ElementTheme.colors.iconSecondary,
|
||||
)
|
||||
}
|
||||
Spacer(Modifier.size(16.dp))
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
|
||||
package io.element.android.features.createroom.impl.configureroom
|
||||
|
||||
import io.element.android.features.createroom.impl.CreateRoomConfig
|
||||
import io.element.android.libraries.matrix.api.user.MatrixUser
|
||||
import io.element.android.libraries.matrix.ui.media.AvatarAction
|
||||
|
||||
@@ -18,7 +17,7 @@ sealed interface ConfigureRoomEvents {
|
||||
data class RoomAccessChanged(val roomAccess: RoomAccessItem) : ConfigureRoomEvents
|
||||
data class RoomAddressChanged(val roomAddress: String) : ConfigureRoomEvents
|
||||
data class RemoveUserFromSelection(val matrixUser: MatrixUser) : ConfigureRoomEvents
|
||||
data class CreateRoom(val config: CreateRoomConfig) : ConfigureRoomEvents
|
||||
data object CreateRoom : ConfigureRoomEvents
|
||||
data class HandleAvatarAction(val action: AvatarAction) : ConfigureRoomEvents
|
||||
data object CancelCreateRoom : ConfigureRoomEvents
|
||||
}
|
||||
|
||||
@@ -22,14 +22,13 @@ import io.element.android.features.createroom.impl.CreateRoomConfig
|
||||
import io.element.android.features.createroom.impl.CreateRoomDataStore
|
||||
import io.element.android.libraries.architecture.AsyncAction
|
||||
import io.element.android.libraries.architecture.Presenter
|
||||
import io.element.android.libraries.architecture.runUpdatingState
|
||||
import io.element.android.libraries.architecture.runCatchingUpdatingState
|
||||
import io.element.android.libraries.core.mimetype.MimeTypes
|
||||
import io.element.android.libraries.featureflag.api.FeatureFlagService
|
||||
import io.element.android.libraries.featureflag.api.FeatureFlags
|
||||
import io.element.android.libraries.matrix.api.MatrixClient
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.createroom.CreateRoomParameters
|
||||
import io.element.android.libraries.matrix.api.createroom.JoinRuleOverride
|
||||
import io.element.android.libraries.matrix.api.createroom.RoomPreset
|
||||
import io.element.android.libraries.matrix.api.createroom.RoomVisibility
|
||||
import io.element.android.libraries.matrix.ui.media.AvatarAction
|
||||
@@ -61,7 +60,7 @@ class ConfigureRoomPresenter @Inject constructor(
|
||||
val cameraPermissionState = cameraPermissionPresenter.present()
|
||||
val createRoomConfig = dataStore.createRoomConfig.collectAsState(CreateRoomConfig())
|
||||
val homeserverName = remember { matrixClient.userIdServerName() }
|
||||
val isKnockFeatureEnabled by featureFlagService.isFeatureEnabledFlow(FeatureFlags.Knock).collectAsState(initial = false)
|
||||
val isKnockFeatureEnabled by featureFlagService.isFeatureEnabledFlow(FeatureFlags.Knock).collectAsState(initial = false)
|
||||
|
||||
val cameraPhotoPicker = mediaPickerProvider.registerCameraPhotoPicker(
|
||||
onResult = { uri -> if (uri != null) dataStore.setAvatarUri(uri = uri, cached = true) },
|
||||
@@ -103,7 +102,7 @@ class ConfigureRoomPresenter @Inject constructor(
|
||||
is ConfigureRoomEvents.RemoveUserFromSelection -> dataStore.selectedUserListDataStore.removeUserFromSelection(event.matrixUser)
|
||||
is ConfigureRoomEvents.RoomAccessChanged -> dataStore.setRoomAccess(event.roomAccess)
|
||||
is ConfigureRoomEvents.RoomAddressChanged -> dataStore.setRoomAddress(event.roomAddress)
|
||||
is ConfigureRoomEvents.CreateRoom -> createRoom(event.config)
|
||||
is ConfigureRoomEvents.CreateRoom -> createRoom(createRoomConfig.value)
|
||||
is ConfigureRoomEvents.HandleAvatarAction -> {
|
||||
when (event.action) {
|
||||
AvatarAction.ChoosePhoto -> galleryImagePicker.launch()
|
||||
@@ -118,7 +117,6 @@ class ConfigureRoomPresenter @Inject constructor(
|
||||
}
|
||||
|
||||
ConfigureRoomEvents.CancelCreateRoom -> createRoomAction.value = AsyncAction.Uninitialized
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -137,20 +135,33 @@ class ConfigureRoomPresenter @Inject constructor(
|
||||
config: CreateRoomConfig,
|
||||
createRoomAction: MutableState<AsyncAction<RoomId>>
|
||||
) = launch {
|
||||
runUpdatingState(createRoomAction) {
|
||||
suspend {
|
||||
val avatarUrl = config.avatarUri?.let { uploadAvatar(it) }
|
||||
val params = CreateRoomParameters(
|
||||
name = config.roomName,
|
||||
topic = config.topic,
|
||||
isEncrypted = config.roomVisibility is RoomVisibilityState.Private,
|
||||
isDirect = false,
|
||||
visibility = if (config.roomVisibility is RoomVisibilityState.Public) RoomVisibility.PUBLIC else RoomVisibility.PRIVATE,
|
||||
joinRuleOverride = if (config.roomVisibility is RoomVisibilityState.Public) config.roomVisibility.roomAccess.toJoinRule() else JoinRuleOverride.None,
|
||||
preset = if (config.roomVisibility is RoomVisibilityState.Public) RoomPreset.PUBLIC_CHAT else RoomPreset.PRIVATE_CHAT,
|
||||
invite = config.invites.map { it.userId },
|
||||
avatar = avatarUrl,
|
||||
canonicalAlias = config.roomVisibility.roomAddress()
|
||||
)
|
||||
val params = if (config.roomVisibility is RoomVisibilityState.Public) {
|
||||
CreateRoomParameters(
|
||||
name = config.roomName,
|
||||
topic = config.topic,
|
||||
isEncrypted = false,
|
||||
isDirect = false,
|
||||
visibility = RoomVisibility.PUBLIC,
|
||||
joinRuleOverride = config.roomVisibility.roomAccess.toJoinRule(),
|
||||
preset = RoomPreset.PUBLIC_CHAT,
|
||||
invite = config.invites.map { it.userId },
|
||||
avatar = avatarUrl,
|
||||
canonicalAlias = config.roomVisibility.roomAddress()
|
||||
)
|
||||
} else {
|
||||
CreateRoomParameters(
|
||||
name = config.roomName,
|
||||
topic = config.topic,
|
||||
isEncrypted = config.roomVisibility is RoomVisibilityState.Private,
|
||||
isDirect = false,
|
||||
visibility = RoomVisibility.PRIVATE,
|
||||
preset = RoomPreset.PRIVATE_CHAT,
|
||||
invite = config.invites.map { it.userId },
|
||||
avatar = avatarUrl,
|
||||
)
|
||||
}
|
||||
matrixClient.createRoom(params)
|
||||
.onFailure { failure ->
|
||||
Timber.e(failure, "Failed to create room")
|
||||
@@ -159,7 +170,8 @@ class ConfigureRoomPresenter @Inject constructor(
|
||||
dataStore.clearCachedData()
|
||||
analyticsService.capture(CreatedRoom(isDM = false))
|
||||
}
|
||||
}
|
||||
.getOrThrow()
|
||||
}.runCatchingUpdatingState(createRoomAction)
|
||||
}
|
||||
|
||||
private suspend fun uploadAvatar(avatarUri: Uri): String {
|
||||
|
||||
@@ -15,7 +15,6 @@ import io.element.android.libraries.matrix.ui.components.aMatrixUserList
|
||||
import io.element.android.libraries.matrix.ui.media.AvatarAction
|
||||
import io.element.android.libraries.permissions.api.PermissionsState
|
||||
import io.element.android.libraries.permissions.api.aPermissionsState
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
|
||||
open class ConfigureRoomStateProvider : PreviewParameterProvider<ConfigureRoomState> {
|
||||
@@ -23,6 +22,7 @@ open class ConfigureRoomStateProvider : PreviewParameterProvider<ConfigureRoomSt
|
||||
get() = sequenceOf(
|
||||
aConfigureRoomState(),
|
||||
aConfigureRoomState(
|
||||
isKnockFeatureEnabled = false,
|
||||
config = CreateRoomConfig(
|
||||
roomName = "Room 101",
|
||||
topic = "Room topic for this room when the text goes onto multiple lines and is really long, there shouldn’t be more than 3 lines",
|
||||
@@ -35,7 +35,6 @@ open class ConfigureRoomStateProvider : PreviewParameterProvider<ConfigureRoomSt
|
||||
),
|
||||
),
|
||||
aConfigureRoomState(
|
||||
isKnockFeatureEnabled = false,
|
||||
config = CreateRoomConfig(
|
||||
roomName = "Room 101",
|
||||
topic = "Room topic for this room when the text goes onto multiple lines and is really long, there shouldn’t be more than 3 lines",
|
||||
|
||||
@@ -44,7 +44,6 @@ import io.element.android.libraries.designsystem.components.async.AsyncActionVie
|
||||
import io.element.android.libraries.designsystem.components.button.BackButton
|
||||
import io.element.android.libraries.designsystem.modifiers.clearFocusOnTap
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreview
|
||||
import io.element.android.libraries.designsystem.preview.PreviewWithLargeHeight
|
||||
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
||||
import io.element.android.libraries.designsystem.theme.aliasScreenTitle
|
||||
import io.element.android.libraries.designsystem.theme.components.Scaffold
|
||||
@@ -82,7 +81,7 @@ fun ConfigureRoomView(
|
||||
onBackClick = onBackClick,
|
||||
onNextClick = {
|
||||
focusManager.clearFocus()
|
||||
state.eventSink(ConfigureRoomEvents.CreateRoom(state.config))
|
||||
state.eventSink(ConfigureRoomEvents.CreateRoom)
|
||||
},
|
||||
)
|
||||
}
|
||||
@@ -164,7 +163,7 @@ fun ConfigureRoomView(
|
||||
},
|
||||
onSuccess = { onCreateRoomSuccess(it) },
|
||||
errorMessage = { stringResource(R.string.screen_create_room_error_creating_room) },
|
||||
onRetry = { state.eventSink(ConfigureRoomEvents.CreateRoom(state.config)) },
|
||||
onRetry = { state.eventSink(ConfigureRoomEvents.CreateRoom) },
|
||||
onErrorDismiss = { state.eventSink(ConfigureRoomEvents.CancelCreateRoom) },
|
||||
)
|
||||
|
||||
@@ -326,7 +325,7 @@ private fun RoomAddressField(
|
||||
color = MaterialTheme.colorScheme.primary,
|
||||
text = "Room address",
|
||||
)
|
||||
|
||||
|
||||
TextField(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
value = address.value,
|
||||
@@ -359,7 +358,6 @@ private fun RoomAddressField(
|
||||
}
|
||||
|
||||
@PreviewsDayNight
|
||||
@PreviewWithLargeHeight
|
||||
@Composable
|
||||
internal fun ConfigureRoomViewPreview(@PreviewParameter(ConfigureRoomStateProvider::class) state: ConfigureRoomState) = ElementPreview {
|
||||
ConfigureRoomView(
|
||||
|
||||
@@ -10,7 +10,8 @@ package io.element.android.features.createroom.impl.configureroom
|
||||
import io.element.android.libraries.matrix.api.createroom.JoinRuleOverride
|
||||
|
||||
enum class RoomAccess {
|
||||
Anyone, Knocking
|
||||
Anyone,
|
||||
Knocking
|
||||
}
|
||||
|
||||
fun RoomAccess.toJoinRule(): JoinRuleOverride {
|
||||
|
||||
@@ -23,4 +23,3 @@ enum class RoomAccessItem(
|
||||
description = CommonStrings.screen_create_room_access_section_knocking_option_description,
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
@@ -8,15 +8,16 @@
|
||||
package io.element.android.features.createroom.impl.configureroom
|
||||
|
||||
import android.net.Uri
|
||||
import app.cash.molecule.RecompositionMode
|
||||
import app.cash.molecule.moleculeFlow
|
||||
import app.cash.turbine.test
|
||||
import app.cash.turbine.TurbineTestContext
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import im.vector.app.features.analytics.plan.CreatedRoom
|
||||
import io.element.android.features.createroom.impl.CreateRoomConfig
|
||||
import io.element.android.features.createroom.impl.CreateRoomDataStore
|
||||
import io.element.android.features.createroom.impl.userlist.UserListDataStore
|
||||
import io.element.android.libraries.architecture.AsyncAction
|
||||
import io.element.android.libraries.featureflag.api.FeatureFlags
|
||||
import io.element.android.libraries.featureflag.test.FakeFeatureFlagService
|
||||
import io.element.android.libraries.matrix.api.MatrixClient
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.test.AN_AVATAR_URL
|
||||
import io.element.android.libraries.matrix.test.A_MESSAGE
|
||||
@@ -25,13 +26,18 @@ import io.element.android.libraries.matrix.test.A_THROWABLE
|
||||
import io.element.android.libraries.matrix.test.FakeMatrixClient
|
||||
import io.element.android.libraries.matrix.ui.components.aMatrixUser
|
||||
import io.element.android.libraries.matrix.ui.media.AvatarAction
|
||||
import io.element.android.libraries.mediapickers.api.PickerProvider
|
||||
import io.element.android.libraries.mediapickers.test.FakePickerProvider
|
||||
import io.element.android.libraries.mediaupload.api.MediaPreProcessor
|
||||
import io.element.android.libraries.mediaupload.api.MediaUploadInfo
|
||||
import io.element.android.libraries.mediaupload.test.FakeMediaPreProcessor
|
||||
import io.element.android.libraries.permissions.api.PermissionsPresenter
|
||||
import io.element.android.libraries.permissions.test.FakePermissionsPresenter
|
||||
import io.element.android.libraries.permissions.test.FakePermissionsPresenterFactory
|
||||
import io.element.android.services.analytics.api.AnalyticsService
|
||||
import io.element.android.services.analytics.test.FakeAnalyticsService
|
||||
import io.element.android.tests.testutils.WarmUpRule
|
||||
import io.element.android.tests.testutils.test
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import io.mockk.mockkStatic
|
||||
@@ -56,33 +62,8 @@ class ConfigureRoomPresenterTest {
|
||||
@get:Rule
|
||||
val warmUpRule = WarmUpRule()
|
||||
|
||||
private lateinit var presenter: ConfigureRoomPresenter
|
||||
private lateinit var userListDataStore: UserListDataStore
|
||||
private lateinit var createRoomDataStore: CreateRoomDataStore
|
||||
private lateinit var fakeMatrixClient: FakeMatrixClient
|
||||
private lateinit var fakePickerProvider: FakePickerProvider
|
||||
private lateinit var fakeMediaPreProcessor: FakeMediaPreProcessor
|
||||
private lateinit var fakeAnalyticsService: FakeAnalyticsService
|
||||
private lateinit var fakePermissionsPresenter: FakePermissionsPresenter
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
fakeMatrixClient = FakeMatrixClient()
|
||||
userListDataStore = UserListDataStore()
|
||||
createRoomDataStore = CreateRoomDataStore(userListDataStore)
|
||||
fakePickerProvider = FakePickerProvider()
|
||||
fakeMediaPreProcessor = FakeMediaPreProcessor()
|
||||
fakeAnalyticsService = FakeAnalyticsService()
|
||||
fakePermissionsPresenter = FakePermissionsPresenter()
|
||||
presenter = ConfigureRoomPresenter(
|
||||
dataStore = createRoomDataStore,
|
||||
matrixClient = fakeMatrixClient,
|
||||
mediaPickerProvider = fakePickerProvider,
|
||||
mediaPreProcessor = fakeMediaPreProcessor,
|
||||
analyticsService = fakeAnalyticsService,
|
||||
permissionsPresenterFactory = FakePermissionsPresenterFactory(fakePermissionsPresenter),
|
||||
)
|
||||
|
||||
mockkStatic(File::readBytes)
|
||||
every { any<File>().readBytes() } returns byteArrayOf()
|
||||
}
|
||||
@@ -94,50 +75,56 @@ class ConfigureRoomPresenterTest {
|
||||
|
||||
@Test
|
||||
fun `present - initial state`() = runTest {
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
presenter.present()
|
||||
}.test {
|
||||
val initialState = awaitItem()
|
||||
val presenter = createConfigureRoomPresenter()
|
||||
presenter.test {
|
||||
val initialState = initialState()
|
||||
assertThat(initialState.config).isEqualTo(CreateRoomConfig())
|
||||
assertThat(initialState.config.roomName).isNull()
|
||||
assertThat(initialState.config.topic).isNull()
|
||||
assertThat(initialState.config.invites).isEmpty()
|
||||
assertThat(initialState.config.avatarUri).isNull()
|
||||
assertThat(initialState.config.roomVisibility).isEqualTo(RoomVisibilityState.Private)
|
||||
assertThat(initialState.createRoomAction).isInstanceOf(AsyncAction.Uninitialized::class.java)
|
||||
assertThat(initialState.homeserverName).isEqualTo("matrix.org")
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `present - create room button is enabled only if the required fields are completed`() = runTest {
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
presenter.present()
|
||||
}.test {
|
||||
val initialState = awaitItem()
|
||||
val presenter = createConfigureRoomPresenter()
|
||||
presenter.test {
|
||||
val initialState = initialState()
|
||||
var config = initialState.config
|
||||
assertThat(initialState.isCreateButtonEnabled).isFalse()
|
||||
assertThat(initialState.config.isValid).isFalse()
|
||||
|
||||
// Room name not empty
|
||||
initialState.eventSink(ConfigureRoomEvents.RoomNameChanged(A_ROOM_NAME))
|
||||
var newState: ConfigureRoomState = awaitItem()
|
||||
config = config.copy(roomName = A_ROOM_NAME)
|
||||
assertThat(newState.config).isEqualTo(config)
|
||||
assertThat(newState.isCreateButtonEnabled).isTrue()
|
||||
assertThat(newState.config.isValid).isTrue()
|
||||
|
||||
// Clear room name
|
||||
newState.eventSink(ConfigureRoomEvents.RoomNameChanged(""))
|
||||
newState = awaitItem()
|
||||
config = config.copy(roomName = null)
|
||||
assertThat(newState.config).isEqualTo(config)
|
||||
assertThat(newState.isCreateButtonEnabled).isFalse()
|
||||
assertThat(newState.config.isValid).isFalse()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `present - state is updated when fields are changed`() = runTest {
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
presenter.present()
|
||||
}.test {
|
||||
val initialState = awaitItem()
|
||||
val userListDataStore = UserListDataStore()
|
||||
val pickerProvider = FakePickerProvider()
|
||||
val permissionsPresenter = FakePermissionsPresenter()
|
||||
val presenter = createConfigureRoomPresenter(
|
||||
createRoomDataStore = CreateRoomDataStore(userListDataStore),
|
||||
pickerProvider = pickerProvider,
|
||||
permissionsPresenter = permissionsPresenter,
|
||||
)
|
||||
presenter.test {
|
||||
val initialState = initialState()
|
||||
var expectedConfig = CreateRoomConfig()
|
||||
assertThat(initialState.config).isEqualTo(expectedConfig)
|
||||
|
||||
@@ -165,22 +152,22 @@ class ConfigureRoomPresenterTest {
|
||||
|
||||
// Room avatar
|
||||
// Pick avatar
|
||||
fakePickerProvider.givenResult(null)
|
||||
pickerProvider.givenResult(null)
|
||||
// From gallery
|
||||
val uriFromGallery = Uri.parse(AN_URI_FROM_GALLERY)
|
||||
fakePickerProvider.givenResult(uriFromGallery)
|
||||
pickerProvider.givenResult(uriFromGallery)
|
||||
newState.eventSink(ConfigureRoomEvents.HandleAvatarAction(AvatarAction.ChoosePhoto))
|
||||
newState = awaitItem()
|
||||
expectedConfig = expectedConfig.copy(avatarUri = uriFromGallery)
|
||||
assertThat(newState.config).isEqualTo(expectedConfig)
|
||||
// From camera
|
||||
val uriFromCamera = Uri.parse(AN_URI_FROM_CAMERA)
|
||||
fakePickerProvider.givenResult(uriFromCamera)
|
||||
pickerProvider.givenResult(uriFromCamera)
|
||||
assertThat(newState.cameraPermissionState.permissionGranted).isFalse()
|
||||
newState.eventSink(ConfigureRoomEvents.HandleAvatarAction(AvatarAction.TakePhoto))
|
||||
newState = awaitItem()
|
||||
assertThat(newState.cameraPermissionState.showDialog).isTrue()
|
||||
fakePermissionsPresenter.setPermissionGranted()
|
||||
permissionsPresenter.setPermissionGranted()
|
||||
newState = awaitItem()
|
||||
assertThat(newState.cameraPermissionState.permissionGranted).isTrue()
|
||||
newState = awaitItem()
|
||||
@@ -188,7 +175,7 @@ class ConfigureRoomPresenterTest {
|
||||
assertThat(newState.config).isEqualTo(expectedConfig)
|
||||
// Do it again, no permission is requested
|
||||
val uriFromCamera2 = Uri.parse(AN_URI_FROM_CAMERA_2)
|
||||
fakePickerProvider.givenResult(uriFromCamera2)
|
||||
pickerProvider.givenResult(uriFromCamera2)
|
||||
newState.eventSink(ConfigureRoomEvents.HandleAvatarAction(AvatarAction.TakePhoto))
|
||||
newState = awaitItem()
|
||||
expectedConfig = expectedConfig.copy(avatarUri = uriFromCamera2)
|
||||
@@ -200,9 +187,15 @@ class ConfigureRoomPresenterTest {
|
||||
assertThat(newState.config).isEqualTo(expectedConfig)
|
||||
|
||||
// Room privacy
|
||||
newState.eventSink(ConfigureRoomEvents.RoomVisibilityChanged(RoomVisibilityState.Public))
|
||||
newState.eventSink(ConfigureRoomEvents.RoomVisibilityChanged(RoomVisibilityItem.Public))
|
||||
newState = awaitItem()
|
||||
expectedConfig = expectedConfig.copy(roomVisibility = RoomVisibilityState.Public)
|
||||
expectedConfig = expectedConfig.copy(
|
||||
roomVisibility = RoomVisibilityState.Public(
|
||||
roomAddress = RoomAddress.AutoFilled(expectedConfig.roomName ?: ""),
|
||||
roomAddressErrorState = RoomAddressErrorState.None,
|
||||
roomAccess = RoomAccess.Anyone,
|
||||
)
|
||||
)
|
||||
assertThat(newState.config).isEqualTo(expectedConfig)
|
||||
|
||||
// Remove user
|
||||
@@ -215,15 +208,17 @@ class ConfigureRoomPresenterTest {
|
||||
|
||||
@Test
|
||||
fun `present - trigger create room action`() = runTest {
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
presenter.present()
|
||||
}.test {
|
||||
val initialState = awaitItem()
|
||||
val matrixClient = createMatrixClient()
|
||||
val presenter = createConfigureRoomPresenter(
|
||||
matrixClient = matrixClient
|
||||
)
|
||||
presenter.test {
|
||||
val initialState = initialState()
|
||||
val createRoomResult = Result.success(RoomId("!createRoomResult:domain"))
|
||||
|
||||
fakeMatrixClient.givenCreateRoomResult(createRoomResult)
|
||||
matrixClient.givenCreateRoomResult(createRoomResult)
|
||||
|
||||
initialState.eventSink(ConfigureRoomEvents.CreateRoom(initialState.config))
|
||||
initialState.eventSink(ConfigureRoomEvents.CreateRoom)
|
||||
assertThat(awaitItem().createRoomAction).isInstanceOf(AsyncAction.Loading::class.java)
|
||||
val stateAfterCreateRoom = awaitItem()
|
||||
assertThat(stateAfterCreateRoom.createRoomAction).isInstanceOf(AsyncAction.Success::class.java)
|
||||
@@ -233,18 +228,22 @@ class ConfigureRoomPresenterTest {
|
||||
|
||||
@Test
|
||||
fun `present - record analytics when creating room`() = runTest {
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
presenter.present()
|
||||
}.test {
|
||||
val initialState = awaitItem()
|
||||
val matrixClient = createMatrixClient()
|
||||
val analyticsService = FakeAnalyticsService()
|
||||
val presenter = createConfigureRoomPresenter(
|
||||
matrixClient = matrixClient,
|
||||
analyticsService = analyticsService
|
||||
)
|
||||
presenter.test {
|
||||
val initialState = initialState()
|
||||
val createRoomResult = Result.success(RoomId("!createRoomResult:domain"))
|
||||
|
||||
fakeMatrixClient.givenCreateRoomResult(createRoomResult)
|
||||
matrixClient.givenCreateRoomResult(createRoomResult)
|
||||
|
||||
initialState.eventSink(ConfigureRoomEvents.CreateRoom(initialState.config))
|
||||
initialState.eventSink(ConfigureRoomEvents.CreateRoom)
|
||||
skipItems(2)
|
||||
|
||||
val analyticsEvent = fakeAnalyticsService.capturedEvents.filterIsInstance<CreatedRoom>().firstOrNull()
|
||||
val analyticsEvent = analyticsService.capturedEvents.filterIsInstance<CreatedRoom>().firstOrNull()
|
||||
assertThat(analyticsEvent).isNotNull()
|
||||
assertThat(analyticsEvent?.isDM).isFalse()
|
||||
}
|
||||
@@ -252,23 +251,31 @@ class ConfigureRoomPresenterTest {
|
||||
|
||||
@Test
|
||||
fun `present - trigger create room with upload error and retry`() = runTest {
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
presenter.present()
|
||||
}.test {
|
||||
skipItems(1)
|
||||
val matrixClient = createMatrixClient()
|
||||
val analyticsService = FakeAnalyticsService()
|
||||
val mediaPreProcessor = FakeMediaPreProcessor()
|
||||
val createRoomDataStore = CreateRoomDataStore(UserListDataStore())
|
||||
val presenter = createConfigureRoomPresenter(
|
||||
createRoomDataStore = createRoomDataStore,
|
||||
mediaPreProcessor = mediaPreProcessor,
|
||||
matrixClient = matrixClient,
|
||||
analyticsService = analyticsService
|
||||
)
|
||||
presenter.test {
|
||||
val initialState = initialState()
|
||||
createRoomDataStore.setAvatarUri(Uri.parse(AN_URI_FROM_GALLERY))
|
||||
fakeMediaPreProcessor.givenResult(Result.success(MediaUploadInfo.Image(mockk(), mockk(), mockk())))
|
||||
fakeMatrixClient.givenUploadMediaResult(Result.failure(A_THROWABLE))
|
||||
skipItems(1)
|
||||
mediaPreProcessor.givenResult(Result.success(MediaUploadInfo.Image(mockk(), mockk(), mockk())))
|
||||
matrixClient.givenUploadMediaResult(Result.failure(A_THROWABLE))
|
||||
|
||||
val initialState = awaitItem()
|
||||
initialState.eventSink(ConfigureRoomEvents.CreateRoom(initialState.config))
|
||||
initialState.eventSink(ConfigureRoomEvents.CreateRoom)
|
||||
assertThat(awaitItem().createRoomAction).isInstanceOf(AsyncAction.Loading::class.java)
|
||||
val stateAfterCreateRoom = awaitItem()
|
||||
assertThat(stateAfterCreateRoom.createRoomAction).isInstanceOf(AsyncAction.Failure::class.java)
|
||||
assertThat(fakeAnalyticsService.capturedEvents.filterIsInstance<CreatedRoom>()).isEmpty()
|
||||
assertThat(analyticsService.capturedEvents.filterIsInstance<CreatedRoom>()).isEmpty()
|
||||
|
||||
fakeMatrixClient.givenUploadMediaResult(Result.success(AN_AVATAR_URL))
|
||||
stateAfterCreateRoom.eventSink(ConfigureRoomEvents.CreateRoom(initialState.config))
|
||||
matrixClient.givenUploadMediaResult(Result.success(AN_AVATAR_URL))
|
||||
stateAfterCreateRoom.eventSink(ConfigureRoomEvents.CreateRoom)
|
||||
assertThat(awaitItem().createRoomAction).isInstanceOf(AsyncAction.Uninitialized::class.java)
|
||||
assertThat(awaitItem().createRoomAction).isInstanceOf(AsyncAction.Loading::class.java)
|
||||
assertThat(awaitItem().createRoomAction).isInstanceOf(AsyncAction.Success::class.java)
|
||||
@@ -277,23 +284,25 @@ class ConfigureRoomPresenterTest {
|
||||
|
||||
@Test
|
||||
fun `present - trigger retry and cancel actions`() = runTest {
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
presenter.present()
|
||||
}.test {
|
||||
val initialState = awaitItem()
|
||||
val fakeMatrixClient = createMatrixClient()
|
||||
val presenter = createConfigureRoomPresenter(
|
||||
matrixClient = fakeMatrixClient
|
||||
)
|
||||
presenter.test {
|
||||
val initialState = initialState()
|
||||
val createRoomResult = Result.failure<RoomId>(A_THROWABLE)
|
||||
|
||||
fakeMatrixClient.givenCreateRoomResult(createRoomResult)
|
||||
|
||||
// Create
|
||||
initialState.eventSink(ConfigureRoomEvents.CreateRoom(initialState.config))
|
||||
initialState.eventSink(ConfigureRoomEvents.CreateRoom)
|
||||
assertThat(awaitItem().createRoomAction).isInstanceOf(AsyncAction.Loading::class.java)
|
||||
val stateAfterCreateRoom = awaitItem()
|
||||
assertThat(stateAfterCreateRoom.createRoomAction).isInstanceOf(AsyncAction.Failure::class.java)
|
||||
assertThat((stateAfterCreateRoom.createRoomAction as? AsyncAction.Failure)?.error).isEqualTo(createRoomResult.exceptionOrNull())
|
||||
|
||||
// Retry
|
||||
stateAfterCreateRoom.eventSink(ConfigureRoomEvents.CreateRoom(initialState.config))
|
||||
stateAfterCreateRoom.eventSink(ConfigureRoomEvents.CreateRoom)
|
||||
assertThat(awaitItem().createRoomAction).isInstanceOf(AsyncAction.Uninitialized::class.java)
|
||||
assertThat(awaitItem().createRoomAction).isInstanceOf(AsyncAction.Loading::class.java)
|
||||
val stateAfterRetry = awaitItem()
|
||||
@@ -305,4 +314,33 @@ class ConfigureRoomPresenterTest {
|
||||
assertThat(awaitItem().createRoomAction).isInstanceOf(AsyncAction.Uninitialized::class.java)
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun TurbineTestContext<ConfigureRoomState>.initialState(): ConfigureRoomState {
|
||||
skipItems(1)
|
||||
return awaitItem()
|
||||
}
|
||||
|
||||
private fun createMatrixClient() = FakeMatrixClient(
|
||||
userIdServerNameLambda = { "matrix.org" },
|
||||
)
|
||||
|
||||
private fun createConfigureRoomPresenter(
|
||||
createRoomDataStore: CreateRoomDataStore = CreateRoomDataStore(UserListDataStore()),
|
||||
matrixClient: MatrixClient = createMatrixClient(),
|
||||
pickerProvider: PickerProvider = FakePickerProvider(),
|
||||
mediaPreProcessor: MediaPreProcessor = FakeMediaPreProcessor(),
|
||||
analyticsService: AnalyticsService = FakeAnalyticsService(),
|
||||
permissionsPresenter: PermissionsPresenter = FakePermissionsPresenter(),
|
||||
isKnockFeatureEnabled: Boolean = true,
|
||||
) = ConfigureRoomPresenter(
|
||||
dataStore = createRoomDataStore,
|
||||
matrixClient = matrixClient,
|
||||
mediaPickerProvider = pickerProvider,
|
||||
mediaPreProcessor = mediaPreProcessor,
|
||||
analyticsService = analyticsService,
|
||||
permissionsPresenterFactory = FakePermissionsPresenterFactory(permissionsPresenter),
|
||||
featureFlagService = FakeFeatureFlagService(
|
||||
mapOf(FeatureFlags.Knock.key to isKnockFeatureEnabled)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user