How to write UI unit test case for these composables in android?

131 Views Asked by At

I want to write UI test cases for composable I searched a lot but did not get any appropriate solution till now,I need to understand the way of writing test cases in Android Kotlin. I go through Google's limited explanation for UI testing in Android but these docs are quite limited in explanation to understand it properly Please help me to get into this
Here is my composable class


@SuppressLint("UnusedMaterial3ScaffoldPaddingParameter")
@OptIn(ExperimentalMaterial3Api::class)
@ExperimentalCoilApi
@Composable
fun CatScreen(
    state: CatContract.State,
    effectFlow: Flow<BaseContract.Effect>?,
    onNavigationRequested: (itemUrl: String, imageId: String,isFavourite:Boolean) -> Unit
) {
    val snackBarHostState = remember { SnackbarHostState() }
    val context = LocalContext.current
    val catMessage = stringResource(R.string.cats_are_loaded)
    //initializing the default selected item
    var navigationSelectedItem by remember {
        mutableIntStateOf(0)
    }

    /**
     * by using the rememberNavController()
     * we can get the instance of the navController
     */
    val navController = rememberNavController()
    // Listen for side effects from the VM
    LaunchedEffect(effectFlow) {
        effectFlow?.onEach { effect ->
            if (effect is BaseContract.Effect.DataWasLoaded)
                snackBarHostState.showSnackbar(
                    message = catMessage,
                    duration = SnackbarDuration.Short
                )
        }?.collect { value ->
            if (value is BaseContract.Effect.Error) {
                // Handle other emitted values if needed
                Toast.makeText(context, value.errorMessage, Toast.LENGTH_LONG).show()
            }

        }
    }
    Scaffold(
        topBar = {
            CatAppBar()
        }, bottomBar = {
            NavigationBar {
                //getting the list of bottom navigation items for our data class
                getBottomNavigationItems(context).forEachIndexed { index, navigationItem ->

                    //iterating all items with their respective indexes
                    NavigationBarItem(
                        selected = index == navigationSelectedItem,
                        label = {
                            Text(navigationItem.title)
                        },
                        icon = {
                            Icon(
                                navigationItem.icon,
                                contentDescription = navigationItem.title
                            )
                        },
                        onClick = {
                            navigationSelectedItem = index
                            navController.navigate(navigationItem.screenRoute) {
                                popUpTo(navController.graph.findStartDestination().id) {
                                    saveState = true
                                }
                                launchSingleTop = true
                                restoreState = true
                            }
                        }
                    )
                }
            }
        }
    ) { paddingValues ->
        //We need to setup our NavHost in here
        NavHost(
            navController = navController,
            startDestination = NavigationScreens.Home.screenRoute,
            modifier = Modifier.padding(paddingValues = paddingValues)
        ) {
            composable(NavigationScreens.Home.screenRoute) {
                UserView(
                    state,
                    false,
                    onNavigationRequested = onNavigationRequested
                )
            }
            composable(NavigationScreens.MyFavorites.screenRoute) {
                UserView(
                    state,
                    true,
                    onNavigationRequested = onNavigationRequested
                )
            }
        }
    }
}

@Composable
fun UserView(
    state: CatContract.State,
    isFavCatsCall: Boolean,
    onNavigationRequested: (itemUrl: String, imageId: String,isFavourite:Boolean) -> Unit
) {
    Surface {
        Box {
            val cats = if (isFavCatsCall) state.favCatsList else state.cats
            CatsList(cats = cats) { itemUrl, imageId ->
                onNavigationRequested(itemUrl, imageId,isFavCatsCall)
            }
            if (state.isLoading)
                LoadingBar()
        }

    }
}


@OptIn(ExperimentalMaterial3Api::class)
@Composable
private fun CatAppBar() {
    TopAppBar(
        navigationIcon = {
            Icon(
                imageVector = Icons.Default.Home,
                modifier = Modifier.padding(horizontal = 12.dp),
                contentDescription = stringResource(R.string.action_icon)
            )
        },
        title = {
            Text(
                text = stringResource(R.string.app_name),
                color = colorResource(id = R.color.white)
            )
        },
        colors = TopAppBarDefaults.smallTopAppBarColors(
            containerColor = colorResource(R.color.colorPrimary),
            titleContentColor = Color(R.color.white),
            navigationIconContentColor = MaterialTheme.colorScheme.onPrimary,
            actionIconContentColor = MaterialTheme.colorScheme.onSecondary
        )
    )
}

@Composable
fun CatsList(
    cats: List<CatDataModel>,
    onItemClicked: (url: String, imageId: String) -> Unit = { _: String, _: String -> }
) {
    LazyVerticalStaggeredGrid(
        columns = StaggeredGridCells.Fixed(2),
        horizontalArrangement = Arrangement.spacedBy(2.dp),
        content = {
            this.items(cats) { item ->
                Card(
                    shape = RoundedCornerShape(8.dp),
                    colors = CardDefaults.cardColors(
                        containerColor = MaterialTheme.colorScheme.surface,
                    ),
                    elevation = CardDefaults.cardElevation(
                        defaultElevation = 6.dp
                    ),
                    border = BorderStroke(0.5.dp, Color.Gray),
                    modifier = Modifier
                        .fillMaxWidth()
                        .padding(start = 10.dp, end = 10.dp, top = 10.dp)
                        .clickable { onItemClicked(item.url, item.imageId) }
                ) {
                    ItemThumbnail(thumbnailUrl = item.url)
                }
            }
        }, modifier = Modifier.fillMaxSize()

    )
}

@Composable
fun ItemThumbnail(
    thumbnailUrl: String
) {
    GlideImage(
        imageModel = thumbnailUrl,
        modifier = Modifier
            .wrapContentSize()
            .wrapContentHeight()
            .fillMaxWidth(),
        // shows a progress indicator when loading an image.
        contentScale = ContentScale.Crop,
        circularReveal = CircularReveal(duration = 100),
        shimmerParams = ShimmerParams(
            baseColor = MaterialTheme.colorScheme.background,
            highlightColor = Color.Gray,
            durationMillis = 500,
            dropOff = 0.55f,
            tilt = 20f
        ), contentDescription = stringResource(R.string.cat_thumbnail_picture)
    )
}

@Composable
fun LoadingBar() {
    Box( modifier = Modifier.fillMaxSize(),
        contentAlignment = Alignment.Center

    ) {
        CircularProgressIndicator( modifier = Modifier.testTag(PROGRESS_BAR) )
    }
}


@OptIn(ExperimentalCoilApi::class)
@Preview(showBackground = true)
@Composable
fun DefaultPreview() {
    ComposeSampleTheme {
        CatScreen(CatContract.State(), null) { _: String, _: String,_:Boolean-> }
    }
}

Please help me to understand how to write test cases for these composables. Thank you in advance and would greatly appreciate your efforts.

0

There are 0 best solutions below