Handle TopicUiState.Error without crashing TopicScreen

Replace TODO() with error UI when topic or news loading fails, and add a compose test for the error state.

Fixes #2108
pull/2117/head
Saad Khan 6 days ago
parent 7d45eae4f8
commit 4ed499289a

@ -16,4 +16,6 @@
-->
<resources>
<string name="feature_topic_api_loading">Loading topic</string>
<string name="feature_topic_api_error">Unable to load topic</string>
<string name="feature_topic_api_news_error">Unable to load news</string>
</resources>

@ -42,11 +42,13 @@ class TopicScreenTest {
val composeTestRule = createAndroidComposeRule<ComponentActivity>()
private lateinit var topicLoading: String
private lateinit var topicError: String
@Before
fun setup() {
composeTestRule.activity.apply {
topicLoading = getString(R.string.feature_topic_api_loading)
topicError = getString(R.string.feature_topic_api_error)
}
}
@ -70,6 +72,26 @@ class TopicScreenTest {
.assertExists()
}
@Test
fun topicError_whenTopicIsError_isShown() {
composeTestRule.setContent {
TopicScreen(
topicUiState = TopicUiState.Error,
newsUiState = NewsUiState.Loading,
showBackButton = true,
onBackClick = {},
onFollowClick = {},
onTopicClick = {},
onBookmarkChanged = { _, _ -> },
onNewsResourceViewed = {},
)
}
composeTestRule
.onNodeWithText(topicError)
.assertExists()
}
@Test
fun topicTitle_whenTopicIsSuccess_isShown() {
val testTopic = followableTopicTestData.first()

@ -129,7 +129,17 @@ internal fun TopicScreen(
)
}
TopicUiState.Error -> TODO()
TopicUiState.Error -> {
item {
TopicErrorToolbar(
showBackButton = showBackButton,
onBackClick = onBackClick,
)
}
item {
TopicErrorState()
}
}
is TopicUiState.Success -> {
item {
TopicToolbar(
@ -177,7 +187,7 @@ private fun topicItemsSize(
topicUiState: TopicUiState,
newsUiState: NewsUiState,
) = when (topicUiState) {
TopicUiState.Error -> 0 // Nothing
TopicUiState.Error -> 2 // Toolbar and error message
TopicUiState.Loading -> 1 // Loading bar
is TopicUiState.Success -> when (newsUiState) {
NewsUiState.Error -> 0 // Nothing
@ -250,7 +260,11 @@ private fun LazyListScope.userNewsResourceCards(
}
else -> item {
Text("Error") // TODO
Text(
text = stringResource(id = TopicR.string.feature_topic_api_news_error),
modifier = Modifier.padding(24.dp),
style = MaterialTheme.typography.bodyLarge,
)
}
}
}
@ -273,6 +287,44 @@ private fun TopicBodyPreview() {
}
}
@Composable
private fun TopicErrorState(modifier: Modifier = Modifier) {
Text(
text = stringResource(id = TopicR.string.feature_topic_api_error),
modifier = modifier
.fillMaxWidth()
.padding(24.dp)
.testTag("topic:error"),
style = MaterialTheme.typography.bodyLarge,
)
}
@Composable
private fun TopicErrorToolbar(
showBackButton: Boolean,
onBackClick: () -> Unit,
modifier: Modifier = Modifier,
) {
Row(
horizontalArrangement = Arrangement.Start,
verticalAlignment = Alignment.CenterVertically,
modifier = modifier
.fillMaxWidth()
.padding(bottom = 32.dp),
) {
if (showBackButton) {
IconButton(onClick = onBackClick) {
Icon(
imageVector = NiaIcons.ArrowBack,
contentDescription = stringResource(
id = UiR.string.core_ui_back,
),
)
}
}
}
}
@Composable
private fun TopicToolbar(
uiState: FollowableTopic,

Loading…
Cancel
Save