Make AppListPage testable
Users could now overwrite AppListPage's appList param to replace the real implementation with fake for testing. Bug: 260660819 Test: Unit test Change-Id: Ia25fecf6d98f7ed18de020f855b9cd31a7199217
This commit is contained in:
@@ -24,7 +24,9 @@ android_library {
|
||||
srcs: ["src/**/*.kt"],
|
||||
|
||||
static_libs: [
|
||||
"SpaLib",
|
||||
"androidx.arch.core_core-testing",
|
||||
"androidx.compose.runtime_runtime",
|
||||
"androidx.compose.ui_ui-test-junit4",
|
||||
"androidx.compose.ui_ui-test-manifest",
|
||||
"mockito",
|
||||
|
||||
@@ -44,9 +44,17 @@ android {
|
||||
jvmTarget = '1.8'
|
||||
freeCompilerArgs = ["-Xjvm-default=all"]
|
||||
}
|
||||
buildFeatures {
|
||||
compose true
|
||||
}
|
||||
composeOptions {
|
||||
kotlinCompilerExtensionVersion jetpack_compose_compiler_version
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
api project(":SpaLib")
|
||||
|
||||
api "androidx.arch.core:core-testing:2.1.0"
|
||||
api "androidx.compose.ui:ui-test-junit4:$jetpack_compose_version"
|
||||
api "com.google.truth:truth:1.1.3"
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.settingslib.spa.testutils
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import com.android.settingslib.spa.framework.compose.LocalNavController
|
||||
import com.android.settingslib.spa.framework.compose.NavControllerWrapper
|
||||
|
||||
class FakeNavControllerWrapper : NavControllerWrapper {
|
||||
var navigateCalledWith: String? = null
|
||||
var navigateBackIsCalled = false
|
||||
|
||||
override fun navigate(route: String) {
|
||||
navigateCalledWith = route
|
||||
}
|
||||
|
||||
override fun navigateBack() {
|
||||
navigateBackIsCalled = true
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun Wrapper(content: @Composable () -> Unit) {
|
||||
CompositionLocalProvider(LocalNavController provides this) {
|
||||
content()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -29,7 +29,7 @@ import kotlinx.coroutines.flow.combine
|
||||
/**
|
||||
* The config used to load the App List.
|
||||
*/
|
||||
internal data class AppListConfig(
|
||||
data class AppListConfig(
|
||||
val userId: Int,
|
||||
val showInstantApps: Boolean,
|
||||
)
|
||||
|
||||
@@ -49,13 +49,13 @@ import kotlinx.coroutines.Dispatchers
|
||||
private const val TAG = "AppList"
|
||||
private const val CONTENT_TYPE_HEADER = "header"
|
||||
|
||||
internal data class AppListState(
|
||||
data class AppListState(
|
||||
val showSystem: State<Boolean>,
|
||||
val option: State<Int>,
|
||||
val searchQuery: State<String>,
|
||||
)
|
||||
|
||||
internal data class AppListInput<T : AppRecord>(
|
||||
data class AppListInput<T : AppRecord>(
|
||||
val config: AppListConfig,
|
||||
val listModel: AppListModel<T>,
|
||||
val state: AppListState,
|
||||
@@ -70,10 +70,13 @@ internal data class AppListInput<T : AppRecord>(
|
||||
* This UI element will take the remaining space on the screen to show the App List.
|
||||
*/
|
||||
@Composable
|
||||
internal fun <T : AppRecord> AppListInput<T>.AppList(
|
||||
appListDataSupplier: @Composable () -> State<AppListData<T>?> = {
|
||||
loadAppListData(config, listModel, state)
|
||||
},
|
||||
fun <T : AppRecord> AppListInput<T>.AppList() {
|
||||
AppListImpl { loadAppListData(config, listModel, state) }
|
||||
}
|
||||
|
||||
@Composable
|
||||
internal fun <T : AppRecord> AppListInput<T>.AppListImpl(
|
||||
appListDataSupplier: @Composable () -> State<AppListData<T>?>,
|
||||
) {
|
||||
LogCompositions(TAG, config.userId.toString())
|
||||
val appListData = appListDataSupplier()
|
||||
|
||||
@@ -28,7 +28,7 @@ import com.android.settingslib.spa.widget.preference.Preference
|
||||
import com.android.settingslib.spa.widget.preference.PreferenceModel
|
||||
import com.android.settingslib.spaprivileged.model.app.AppRecord
|
||||
|
||||
class AppListItemModel<T : AppRecord>(
|
||||
data class AppListItemModel<T : AppRecord>(
|
||||
val record: T,
|
||||
val label: String,
|
||||
val summary: State<String>,
|
||||
|
||||
@@ -47,23 +47,8 @@ fun <T : AppRecord> AppListPage(
|
||||
primaryUserOnly: Boolean = false,
|
||||
moreOptions: @Composable MoreOptionsScope.() -> Unit = {},
|
||||
header: @Composable () -> Unit = {},
|
||||
appList: @Composable AppListInput<T>.() -> Unit = { AppList() },
|
||||
appItem: @Composable AppListItemModel<T>.() -> Unit,
|
||||
) {
|
||||
AppListPageImpl(
|
||||
title, listModel, showInstantApps, primaryUserOnly, moreOptions, header, appItem,
|
||||
) { it.AppList() }
|
||||
}
|
||||
|
||||
@Composable
|
||||
internal fun <T : AppRecord> AppListPageImpl(
|
||||
title: String,
|
||||
listModel: AppListModel<T>,
|
||||
showInstantApps: Boolean = false,
|
||||
primaryUserOnly: Boolean = false,
|
||||
moreOptions: @Composable MoreOptionsScope.() -> Unit = {},
|
||||
header: @Composable () -> Unit = {},
|
||||
appItem: @Composable AppListItemModel<T>.() -> Unit,
|
||||
appList: @Composable (input: AppListInput<T>) -> Unit,
|
||||
) {
|
||||
val showSystem = rememberSaveable { mutableStateOf(false) }
|
||||
SearchScaffold(
|
||||
|
||||
@@ -118,12 +118,12 @@ class AppListPageTest {
|
||||
): State<AppListInput<TestAppRecord>?> {
|
||||
val appListState = mutableStateOf<AppListInput<TestAppRecord>?>(null)
|
||||
composeTestRule.setContent {
|
||||
AppListPageImpl(
|
||||
AppListPage(
|
||||
title = TITLE,
|
||||
listModel = TestAppListModel(options),
|
||||
header = header,
|
||||
appItem = { AppListItem {} },
|
||||
appList = { appListState.value = it },
|
||||
appList = { appListState.value = this },
|
||||
)
|
||||
}
|
||||
return appListState
|
||||
|
||||
@@ -102,7 +102,7 @@ class AppListTest {
|
||||
appItem = { AppListItem {} },
|
||||
bottomPadding = 0.dp,
|
||||
)
|
||||
appListInput.AppList { stateOf(AppListData(appEntries, option = 0)) }
|
||||
appListInput.AppListImpl { stateOf(AppListData(appEntries, option = 0)) }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user