Skip to content

Commit

Permalink
Test register screen composable (#3062)
Browse files Browse the repository at this point in the history
* Testing Register Screen

* Add resource type files

* Register Screen Test

* Change testTag name

* Add fab test

* Add test to BooleanExtensionTest

* Add pagination to list resource

* Refactor test tags in register view model

* Update RegisterScreen

* Add modifier to called functions
---------

Co-authored-by: Sebastian <[email protected]>
  • Loading branch information
Raynafs and SebaMutuku authored Mar 19, 2024
1 parent 1c01276 commit 73a67d3
Show file tree
Hide file tree
Showing 4 changed files with 241 additions and 58 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ fun LoaderDialog(
onDismissRequest = { openDialog.value = true },
properties = DialogProperties(dismissOnBackPress = true),
) {
Box(Modifier.size(240.dp, 180.dp)) {
Box(modifier.size(240.dp, 180.dp)) {
Column(
modifier = modifier.padding(8.dp),
verticalArrangement = Arrangement.Center,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,38 +16,208 @@

package org.smartregister.fhircore.quest.integration.ui.register

import androidx.compose.runtime.mutableStateOf
import androidx.compose.ui.Modifier
import androidx.compose.ui.test.assertCountEquals
import androidx.compose.ui.test.assertIsDisplayed
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onAllNodesWithTag
import androidx.compose.ui.test.onChildAt
import androidx.compose.ui.test.onNodeWithTag
import androidx.navigation.compose.rememberNavController
import androidx.paging.PagingData
import androidx.paging.compose.LazyPagingItems
import androidx.paging.compose.collectAsLazyPagingItems
import dagger.hilt.android.testing.HiltAndroidTest
import org.junit.Before
import io.mockk.mockk
import kotlinx.coroutines.flow.flowOf
import org.hl7.fhir.r4.model.ResourceType
import org.junit.Rule
import org.junit.Test
import org.smartregister.fhircore.engine.configuration.ConfigType
import org.smartregister.fhircore.engine.configuration.ConfigurationRegistry
import org.smartregister.fhircore.engine.configuration.register.NoResultsConfig
import org.smartregister.fhircore.engine.domain.model.ResourceData
import org.smartregister.fhircore.quest.integration.Faker
import org.smartregister.fhircore.quest.ui.register.FAB_BUTTON_REGISTER_TEST_TAG
import org.smartregister.fhircore.quest.ui.register.FIRST_TIME_SYNC_DIALOG
import org.smartregister.fhircore.quest.ui.register.NO_REGISTER_VIEW_COLUMN_TEST_TAG
import org.smartregister.fhircore.quest.ui.register.NoRegisterDataView
import org.smartregister.fhircore.quest.ui.register.REGISTER_CARD_TEST_TAG
import org.smartregister.fhircore.quest.ui.register.RegisterScreen
import org.smartregister.fhircore.quest.ui.register.RegisterUiState
import org.smartregister.fhircore.quest.ui.register.TOP_REGISTER_SCREEN_TEST_TAG

@HiltAndroidTest
class RegisterScreenTest {
@get:Rule val composeTestRule = createComposeRule()

@get:Rule val composeRegisterTestRule = createComposeRule()

private val noResults = NoResultsConfig()

@Before
fun setUp() {
@Test
fun testFloatingActionButtonIsDisplayed() {
val configurationRegistry: ConfigurationRegistry = Faker.buildTestConfigurationRegistry()
val registerUiState =
RegisterUiState(
screenTitle = "Register101",
isFirstTimeSync = false,
registerConfiguration =
configurationRegistry.retrieveConfiguration(ConfigType.Register, "householdRegister"),
registerId = "register101",
totalRecordsCount = 1,
filteredRecordsCount = 0,
pagesCount = 0,
progressPercentage = flowOf(0),
isSyncUpload = flowOf(false),
params = emptyMap(),
)
val searchText = mutableStateOf("")
val currentPage = mutableStateOf(0)

composeTestRule.setContent {
NoRegisterDataView(modifier = Modifier, noResults = noResults, onClick = {})
val data = listOf(ResourceData("1", ResourceType.Patient, emptyMap()))

val pagingItems = flowOf(PagingData.from(data)).collectAsLazyPagingItems()

RegisterScreen(
modifier = Modifier,
openDrawer = {},
onEvent = {},
registerUiState = registerUiState,
searchText = searchText,
currentPage = currentPage,
pagingItems = pagingItems,
navController = rememberNavController(),
)
}
composeTestRule.waitUntil(5_000) { true }
composeTestRule.onAllNodesWithTag(FAB_BUTTON_REGISTER_TEST_TAG, useUnmergedTree = true)
}

@Test
fun testRegisterCardListIsRendered() {
val configurationRegistry: ConfigurationRegistry = Faker.buildTestConfigurationRegistry()
val registerUiState =
RegisterUiState(
screenTitle = "Register101",
isFirstTimeSync = false,
registerConfiguration =
configurationRegistry.retrieveConfiguration(ConfigType.Register, "householdRegister"),
registerId = "register101",
totalRecordsCount = 1,
filteredRecordsCount = 0,
pagesCount = 1,
progressPercentage = flowOf(0),
isSyncUpload = flowOf(false),
params = emptyMap(),
)
val searchText = mutableStateOf("")
val currentPage = mutableStateOf(0)

composeTestRule.setContent {
val data = listOf(ResourceData("1", ResourceType.Patient, emptyMap()))

val pagingItems = flowOf(PagingData.from(data)).collectAsLazyPagingItems()

RegisterScreen(
modifier = Modifier,
openDrawer = {},
onEvent = {},
registerUiState = registerUiState,
searchText = searchText,
currentPage = currentPage,
pagingItems = pagingItems,
navController = rememberNavController(),
)
}

composeTestRule
.onNodeWithTag(REGISTER_CARD_TEST_TAG, useUnmergedTree = true)
.assertExists()
.assertIsDisplayed()
}

@Test
fun testThatDialogIsDisplayedDuringSyncing() {
val configurationRegistry: ConfigurationRegistry = Faker.buildTestConfigurationRegistry()
val registerUiState =
RegisterUiState(
screenTitle = "Register101",
isFirstTimeSync = true,
registerConfiguration =
configurationRegistry.retrieveConfiguration(ConfigType.Register, "childRegister"),
registerId = "register101",
totalRecordsCount = 0,
filteredRecordsCount = 0,
pagesCount = 1,
progressPercentage = flowOf(0),
isSyncUpload = flowOf(false),
params = emptyMap(),
)
val searchText = mutableStateOf("")
val currentPage = mutableStateOf(0)
val pagingItems = mockk<LazyPagingItems<ResourceData>>().apply {}

composeTestRule.setContent {
RegisterScreen(
modifier = Modifier,
openDrawer = {},
onEvent = {},
registerUiState = registerUiState,
searchText = searchText,
currentPage = currentPage,
pagingItems = pagingItems,
navController = rememberNavController(),
)
}
composeTestRule.onNodeWithTag(FIRST_TIME_SYNC_DIALOG, useUnmergedTree = true)
}

@Test
fun testThatTopScreenIsRendered() {
val configurationRegistry: ConfigurationRegistry = Faker.buildTestConfigurationRegistry()
val registerUiState =
RegisterUiState(
screenTitle = "Register101",
isFirstTimeSync = false,
registerConfiguration =
configurationRegistry.retrieveConfiguration(ConfigType.Register, "householdRegister"),
registerId = "register101",
totalRecordsCount = 1,
filteredRecordsCount = 0,
pagesCount = 0,
progressPercentage = flowOf(0),
isSyncUpload = flowOf(false),
params = emptyMap(),
)
val searchText = mutableStateOf("")
val currentPage = mutableStateOf(0)

composeTestRule.setContent {
val data = listOf(ResourceData("1", ResourceType.Patient, emptyMap()))

val pagingItems = flowOf(PagingData.from(data)).collectAsLazyPagingItems()

RegisterScreen(
modifier = Modifier,
openDrawer = {},
onEvent = {},
registerUiState = registerUiState,
searchText = searchText,
currentPage = currentPage,
pagingItems = pagingItems,
navController = rememberNavController(),
)
}
composeTestRule.waitUntil(5_000) { true }
composeTestRule.onNodeWithTag(TOP_REGISTER_SCREEN_TEST_TAG, useUnmergedTree = true)
}

@Test
fun testNoRegisterDataViewDisplaysNoTestTag() {
composeTestRule.setContent {
NoRegisterDataView(modifier = Modifier, noResults = noResults, onClick = {})
}
composeTestRule
.onNodeWithTag(NO_REGISTER_VIEW_COLUMN_TEST_TAG, useUnmergedTree = true)
.assertExists()
Expand All @@ -56,13 +226,19 @@ class RegisterScreenTest {

@Test
fun testCountAllNodeNoRegisterDataViewDisplaysNoTestTag() {
composeTestRule.setContent {
NoRegisterDataView(modifier = Modifier, noResults = noResults, onClick = {})
}
composeTestRule
.onAllNodesWithTag(NO_REGISTER_VIEW_COLUMN_TEST_TAG, useUnmergedTree = true)
.assertCountEquals(1)
}

@Test
fun checkNodeWithNoRegisterViewColumTestTag() {
composeTestRule.setContent {
NoRegisterDataView(modifier = Modifier, noResults = noResults, onClick = {})
}
composeTestRule
.onNodeWithTag(NO_REGISTER_VIEW_COLUMN_TEST_TAG, useUnmergedTree = true)
.onChildAt(0)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,12 @@ import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyListState
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.material.Button
import androidx.compose.material.Icon
import androidx.compose.material.Scaffold
import androidx.compose.material.Text
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Add
import androidx.compose.material3.Button
import androidx.compose.material3.Icon
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.collectAsState
Expand Down Expand Up @@ -63,6 +63,10 @@ const val NO_REGISTER_VIEW_MESSAGE_TEST_TAG = "noRegisterViewMessageTestTag"
const val NO_REGISTER_VIEW_BUTTON_TEST_TAG = "noRegisterViewButtonTestTag"
const val NO_REGISTER_VIEW_BUTTON_ICON_TEST_TAG = "noRegisterViewButtonIconTestTag"
const val NO_REGISTER_VIEW_BUTTON_TEXT_TEST_TAG = "noRegisterViewButtonTextTestTag"
const val REGISTER_CARD_TEST_TAG = "registerCardListTestTag"
const val FIRST_TIME_SYNC_DIALOG = "firstTimeSyncTestTag"
const val FAB_BUTTON_REGISTER_TEST_TAG = "fabTestTag"
const val TOP_REGISTER_SCREEN_TEST_TAG = "topScreenTestTag"

@Composable
fun RegisterScreen(
Expand All @@ -80,52 +84,54 @@ fun RegisterScreen(

Scaffold(
topBar = {
Column {
// Top section has toolbar and a results counts view
val filterActions = registerUiState.registerConfiguration?.registerFilter?.dataFilterActions
TopScreenSection(
title = registerUiState.screenTitle,
searchText = searchText.value,
filteredRecordsCount = registerUiState.filteredRecordsCount,
searchPlaceholder = registerUiState.registerConfiguration?.searchBar?.display,
toolBarHomeNavigation = toolBarHomeNavigation,
onSearchTextChanged = { searchText ->
onEvent(RegisterEvent.SearchRegister(searchText = searchText))
},
isFilterIconEnabled = filterActions?.isNotEmpty() ?: false,
) { event ->
when (event) {
ToolbarClickEvent.Navigate ->
when (toolBarHomeNavigation) {
ToolBarHomeNavigation.OPEN_DRAWER -> openDrawer(true)
ToolBarHomeNavigation.NAVIGATE_BACK -> navController.popBackStack()
}
ToolbarClickEvent.FilterData -> {
onEvent(RegisterEvent.ResetFilterRecordsCount)
filterActions?.handleClickEvent(navController)
// Top section has toolbar and a results counts view
val filterActions = registerUiState.registerConfiguration?.registerFilter?.dataFilterActions
TopScreenSection(
modifier = modifier.testTag(TOP_REGISTER_SCREEN_TEST_TAG),
title = registerUiState.screenTitle,
searchText = searchText.value,
filteredRecordsCount = registerUiState.filteredRecordsCount,
searchPlaceholder = registerUiState.registerConfiguration?.searchBar?.display,
toolBarHomeNavigation = toolBarHomeNavigation,
onSearchTextChanged = { searchText ->
onEvent(RegisterEvent.SearchRegister(searchText = searchText))
},
isFilterIconEnabled = filterActions?.isNotEmpty() ?: false,
) { event ->
when (event) {
ToolbarClickEvent.Navigate ->
when (toolBarHomeNavigation) {
ToolBarHomeNavigation.OPEN_DRAWER -> openDrawer(true)
ToolBarHomeNavigation.NAVIGATE_BACK -> navController.popBackStack()
}
ToolbarClickEvent.FilterData -> {
onEvent(RegisterEvent.ResetFilterRecordsCount)
filterActions?.handleClickEvent(navController)
}
}
// Only show counter during search
if (searchText.value.isNotEmpty()) RegisterHeader(resultCount = pagingItems.itemCount)
}
// Only show counter during search
if (searchText.value.isNotEmpty()) RegisterHeader(resultCount = pagingItems.itemCount)
},
floatingActionButton = {
val fabActions = registerUiState.registerConfiguration?.fabActions
if (!fabActions.isNullOrEmpty() && fabActions.first().visible) {
ExtendedFab(
modifier = modifier.testTag(FAB_BUTTON_REGISTER_TEST_TAG),
fabActions = fabActions,
navController = navController,
lazyListState = lazyListState,
)
}
},
) { innerPadding ->
Box(modifier = modifier.padding(innerPadding)) {
Box(
modifier = modifier.padding(innerPadding),
) {
if (registerUiState.isFirstTimeSync) {
val isSyncUpload = registerUiState.isSyncUpload.collectAsState(initial = false).value
LoaderDialog(
modifier = modifier,
modifier = modifier.testTag(FIRST_TIME_SYNC_DIALOG),
percentageProgressFlow = registerUiState.progressPercentage,
dialogMessage =
stringResource(
Expand All @@ -134,25 +140,26 @@ fun RegisterScreen(
showPercentageProgress = true,
)
}
if (
registerUiState.totalRecordsCount > 0 &&
registerUiState.registerConfiguration?.registerCard != null
) {
RegisterCardList(
registerCardConfig = registerUiState.registerConfiguration.registerCard,
pagingItems = pagingItems,
navController = navController,
lazyListState = lazyListState,
onEvent = onEvent,
registerUiState = registerUiState,
currentPage = currentPage,
showPagination = searchText.value.isEmpty(),
)
} else {
registerUiState.registerConfiguration?.noResults?.let { noResultConfig ->
NoRegisterDataView(modifier = modifier, noResults = noResultConfig) {
noResultConfig.actionButton?.actions?.handleClickEvent(navController)
}
}
if (
registerUiState.totalRecordsCount > 0 &&
registerUiState.registerConfiguration?.registerCard != null
) {
RegisterCardList(
modifier = modifier.testTag(REGISTER_CARD_TEST_TAG),
registerCardConfig = registerUiState.registerConfiguration.registerCard,
pagingItems = pagingItems,
navController = navController,
lazyListState = lazyListState,
onEvent = onEvent,
registerUiState = registerUiState,
currentPage = currentPage,
showPagination = searchText.value.isEmpty(),
)
} else {
registerUiState.registerConfiguration?.noResults?.let { noResultConfig ->
NoRegisterDataView(modifier = modifier, noResults = noResultConfig) {
noResultConfig.actionButton?.actions?.handleClickEvent(navController)
}
}
}
Expand Down
Loading

0 comments on commit 73a67d3

Please sign in to comment.