[go: nahoru, domu]

blob: f9f02c0f20c24c48bc7d9bc7f76d46fd61d35411 [file] [log] [blame]
/*
* Copyright 2020 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 androidx.compose.material
import android.os.Build
import androidx.compose.foundation.Icon
import androidx.compose.foundation.Text
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.wrapContentSize
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Favorite
import androidx.compose.material.icons.filled.Menu
import androidx.compose.runtime.Composable
import androidx.compose.runtime.Providers
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LayoutDirectionAmbient
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.unit.LayoutDirection
import androidx.test.filters.LargeTest
import androidx.test.filters.SdkSuppress
import androidx.test.screenshot.AndroidXScreenshotTestRule
import androidx.test.screenshot.assertAgainstGolden
import androidx.ui.test.captureToBitmap
import androidx.ui.test.createComposeRule
import androidx.ui.test.onNodeWithTag
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
@LargeTest
@RunWith(JUnit4::class)
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
@OptIn(ExperimentalMaterialApi::class)
class ScaffoldScreenshotTest {
@get:Rule
val composeTestRule = createComposeRule()
@get:Rule
val screenshotRule = AndroidXScreenshotTestRule(GOLDEN_MATERIAL)
@Test
fun onlyContent() {
composeTestRule.setContent {
MaterialTheme {
ScreenshotScaffold(
showTopAppBar = false,
showBottomAppBar = false,
showSnackbar = false,
showFab = false
)
}
}
assertScaffoldMatches(
"scaffold_onlyContent"
)
}
@Test
fun topAppBar() {
composeTestRule.setContent {
MaterialTheme {
ScreenshotScaffold(
showTopAppBar = true,
showBottomAppBar = false,
showSnackbar = false,
showFab = false
)
}
}
assertScaffoldMatches(
"scaffold_topAppBar"
)
}
@Test
fun bottomAppBar() {
composeTestRule.setContent {
MaterialTheme {
ScreenshotScaffold(
showTopAppBar = false,
showBottomAppBar = true,
showSnackbar = false,
showFab = false
)
}
}
assertScaffoldMatches("scaffold_bottomAppBar")
}
@Test
fun topAndBottomAppBar() {
composeTestRule.setContent {
MaterialTheme {
ScreenshotScaffold(
showTopAppBar = true,
showBottomAppBar = true,
showSnackbar = false,
showFab = false
)
}
}
assertScaffoldMatches("scaffold_topAndBottomAppBar")
}
@Test
fun centerFab() {
composeTestRule.setContent {
MaterialTheme {
ScreenshotScaffold(
showTopAppBar = false,
showBottomAppBar = false,
showSnackbar = false,
showFab = true,
fabPosition = FabPosition.Center
)
}
}
assertScaffoldMatches("scaffold_centerFab")
}
@Test
fun endFab_ltr() {
composeTestRule.setContent {
MaterialTheme {
ScreenshotScaffold(
showTopAppBar = false,
showBottomAppBar = false,
showSnackbar = false,
showFab = true,
fabPosition = FabPosition.End,
rtl = false
)
}
}
assertScaffoldMatches("scaffold_endFab_ltr")
}
@Test
fun endFab_rtl() {
composeTestRule.setContent {
MaterialTheme {
ScreenshotScaffold(
showTopAppBar = false,
showBottomAppBar = false,
showSnackbar = false,
showFab = true,
fabPosition = FabPosition.End,
rtl = true
)
}
}
assertScaffoldMatches("scaffold_endFab_rtl")
}
@Test
fun topAppBar_centerFab() {
composeTestRule.setContent {
MaterialTheme {
ScreenshotScaffold(
showTopAppBar = true,
showBottomAppBar = false,
showSnackbar = false,
showFab = true,
fabPosition = FabPosition.Center
)
}
}
assertScaffoldMatches("scaffold_topAppBar_centerFab")
}
@Test
fun topAppBar_endFab_ltr() {
composeTestRule.setContent {
MaterialTheme {
ScreenshotScaffold(
showTopAppBar = true,
showBottomAppBar = false,
showSnackbar = false,
showFab = true,
fabPosition = FabPosition.End,
rtl = false
)
}
}
assertScaffoldMatches("scaffold_topAppBar_endFab_ltr")
}
@Test
fun topAppBar_endFab_rtl() {
composeTestRule.setContent {
MaterialTheme {
ScreenshotScaffold(
showTopAppBar = true,
showBottomAppBar = false,
showSnackbar = false,
showFab = true,
fabPosition = FabPosition.End,
rtl = true
)
}
}
assertScaffoldMatches("scaffold_topAppBar_endFab_rtl")
}
@Test
fun bottomAppBar_centerFab_floating() {
composeTestRule.setContent {
MaterialTheme {
ScreenshotScaffold(
showTopAppBar = false,
showBottomAppBar = true,
showSnackbar = false,
showFab = true,
dockedFab = false,
fabPosition = FabPosition.Center
)
}
}
assertScaffoldMatches("scaffold_bottomAppBar_centerFab_floating")
}
@Test
fun bottomAppBar_endFab_floating_ltr() {
composeTestRule.setContent {
MaterialTheme {
ScreenshotScaffold(
showTopAppBar = false,
showBottomAppBar = true,
showSnackbar = false,
showFab = true,
dockedFab = false,
fabPosition = FabPosition.End,
rtl = false
)
}
}
assertScaffoldMatches("scaffold_bottomAppBar_endFab_floating_ltr")
}
@Test
fun bottomAppBar_endFab_floating_rtl() {
composeTestRule.setContent {
MaterialTheme {
ScreenshotScaffold(
showTopAppBar = false,
showBottomAppBar = true,
showSnackbar = false,
showFab = true,
dockedFab = false,
fabPosition = FabPosition.End,
rtl = true
)
}
}
assertScaffoldMatches("scaffold_bottomAppBar_endFab_floating_rtl")
}
@Test
fun bottomAppBar_centerFab_docked() {
composeTestRule.setContent {
MaterialTheme {
ScreenshotScaffold(
showTopAppBar = false,
showBottomAppBar = true,
showSnackbar = false,
showFab = true,
dockedFab = true,
fabPosition = FabPosition.Center
)
}
}
assertScaffoldMatches("scaffold_bottomAppBar_centerFab_docked")
}
@Test
fun bottomAppBar_centerFab_docked_noCutout() {
composeTestRule.setContent {
MaterialTheme {
ScreenshotScaffold(
showTopAppBar = false,
showBottomAppBar = true,
showSnackbar = false,
showFab = true,
dockedFab = true,
fabCutout = false,
fabPosition = FabPosition.Center
)
}
}
assertScaffoldMatches("scaffold_bottomAppBar_centerFab_docked_noCutout")
}
@Test
fun bottomAppBar_endFab_docked_ltr() {
composeTestRule.setContent {
MaterialTheme {
ScreenshotScaffold(
showTopAppBar = false,
showBottomAppBar = true,
showSnackbar = false,
showFab = true,
dockedFab = true,
fabPosition = FabPosition.End,
rtl = false
)
}
}
assertScaffoldMatches("scaffold_bottomAppBar_endFab_docked_ltr")
}
@Test
fun bottomAppBar_endFab_docked_rtl() {
composeTestRule.setContent {
MaterialTheme {
ScreenshotScaffold(
showTopAppBar = false,
showBottomAppBar = true,
showSnackbar = false,
showFab = true,
dockedFab = true,
fabPosition = FabPosition.End,
rtl = true
)
}
}
assertScaffoldMatches("scaffold_bottomAppBar_endFab_docked_rtl")
}
@Test
fun topAndBottomAppBar_centerFab_floating() {
composeTestRule.setContent {
MaterialTheme {
ScreenshotScaffold(
showTopAppBar = true,
showBottomAppBar = true,
showSnackbar = false,
showFab = true,
dockedFab = false,
fabPosition = FabPosition.Center
)
}
}
assertScaffoldMatches("scaffold_topAndBottomAppBar_centerFab_floating")
}
@Test
fun topAndBottomAppBar_endFab_floating_ltr() {
composeTestRule.setContent {
MaterialTheme {
ScreenshotScaffold(
showTopAppBar = true,
showBottomAppBar = true,
showSnackbar = false,
showFab = true,
dockedFab = false,
fabPosition = FabPosition.End,
rtl = false
)
}
}
assertScaffoldMatches("scaffold_topAndBottomAppBar_endFab_floating_ltr")
}
@Test
fun topAndBottomAppBar_endFab_floating_rtl() {
composeTestRule.setContent {
MaterialTheme {
ScreenshotScaffold(
showTopAppBar = true,
showBottomAppBar = true,
showSnackbar = false,
showFab = true,
dockedFab = false,
fabPosition = FabPosition.End,
rtl = true
)
}
}
assertScaffoldMatches("scaffold_topAndBottomAppBar_endFab_floating_rtl")
}
@Test
fun topAndBottomAppBar_centerFab_docked() {
composeTestRule.setContent {
MaterialTheme {
ScreenshotScaffold(
showTopAppBar = true,
showBottomAppBar = true,
showSnackbar = false,
showFab = true,
dockedFab = true,
fabPosition = FabPosition.Center
)
}
}
assertScaffoldMatches("scaffold_topAndBottomAppBar_centerFab_docked")
}
@Test
fun topAndBottomAppBar_endFab_docked_ltr() {
composeTestRule.setContent {
MaterialTheme {
ScreenshotScaffold(
showTopAppBar = true,
showBottomAppBar = true,
showSnackbar = false,
showFab = true,
dockedFab = true,
fabPosition = FabPosition.End,
rtl = false
)
}
}
assertScaffoldMatches("scaffold_topAndBottomAppBar_endFab_docked_ltr")
}
@Test
fun topAndBottomAppBar_endFab_docked_rtl() {
composeTestRule.setContent {
MaterialTheme {
ScreenshotScaffold(
showTopAppBar = true,
showBottomAppBar = true,
showSnackbar = false,
showFab = true,
dockedFab = true,
fabPosition = FabPosition.End,
rtl = true
)
}
}
assertScaffoldMatches("scaffold_topAndBottomAppBar_endFab_docked_rtl")
}
@Test
fun snackbar() {
composeTestRule.setContent {
MaterialTheme {
ScreenshotScaffold(
showTopAppBar = false,
showBottomAppBar = false,
showSnackbar = true,
showFab = false
)
}
}
assertScaffoldMatches("snackbar")
}
@Test
fun topAppBar_snackbar() {
composeTestRule.setContent {
MaterialTheme {
ScreenshotScaffold(
showTopAppBar = true,
showBottomAppBar = false,
showSnackbar = true,
showFab = false
)
}
}
assertScaffoldMatches("topAppBar_snackbar")
}
@Test
fun bottomAppBar_snackbar() {
composeTestRule.setContent {
MaterialTheme {
ScreenshotScaffold(
showTopAppBar = false,
showBottomAppBar = true,
showSnackbar = true,
showFab = false
)
}
}
assertScaffoldMatches("bottomAppBar_snackbar")
}
@Test
fun topAndBottomAppBar_snackbar() {
composeTestRule.setContent {
MaterialTheme {
ScreenshotScaffold(
showTopAppBar = true,
showBottomAppBar = true,
showSnackbar = true,
showFab = false
)
}
}
assertScaffoldMatches("topAndBottomAppBar_snackbar")
}
@Test
fun topAndBottomAppBar_floatingFab_snackbar() {
composeTestRule.setContent {
MaterialTheme {
ScreenshotScaffold(
showTopAppBar = true,
showBottomAppBar = true,
showSnackbar = true,
showFab = true,
dockedFab = false,
fabPosition = FabPosition.Center
)
}
}
assertScaffoldMatches("topAndBottomAppBar_floatingFab_snackbar")
}
@Test
fun topAndBottomAppBar_dockedFab_snackbar() {
composeTestRule.setContent {
MaterialTheme {
ScreenshotScaffold(
showTopAppBar = true,
showBottomAppBar = true,
showSnackbar = true,
showFab = true,
dockedFab = true,
fabPosition = FabPosition.Center
)
}
}
assertScaffoldMatches("topAndBottomAppBar_dockedFab_snackbar")
}
/**
* Asserts that the Scaffold matches the screenshot with identifier [goldenIdentifier].
*
* @param goldenIdentifier the identifier for the corresponding screenshot
*/
private fun assertScaffoldMatches(
goldenIdentifier: String
) {
// Capture and compare screenshots
composeTestRule.onNodeWithTag(Tag)
.captureToBitmap()
.assertAgainstGolden(screenshotRule, goldenIdentifier)
}
}
/**
* Scaffold with typical app bar / FAB content, and a light background color for the main content.
*
* @param showTopAppBar whether to show a [TopAppBar] or not
* @param showBottomAppBar whether to show a [BottomAppBar] or not
* @param showFab whether to show a [FloatingActionButton] or not
* @param dockedFab whether the FAB (if present) is docked to the [BottomAppBar] or not
* @param fabCutout whether the [BottomAppBar] (if present) should draw a cutout where the FAB
* (if present) is, when docked to the [BottomAppBar].
* @param fabPosition the [FabPosition] of the FAB (if present)
* @param rtl whether to set [LayoutDirection.Rtl] as the [LayoutDirection] for this Scaffold and
* its content
*/
@OptIn(ExperimentalMaterialApi::class)
@Composable
private fun ScreenshotScaffold(
showTopAppBar: Boolean,
showBottomAppBar: Boolean,
showSnackbar: Boolean,
showFab: Boolean,
dockedFab: Boolean = false,
fabCutout: Boolean = true,
fabPosition: FabPosition = FabPosition.End,
rtl: Boolean = false
) {
val topAppBar = (@Composable {
TopAppBar(title = { Text("Scaffold") })
}).takeIf { showTopAppBar }
val bottomAppBar = (@Composable {
val cutoutShape = if (fabCutout) CircleShape else null
BottomAppBar(cutoutShape = cutoutShape) {
IconButton(onClick = {}) {
Icon(Icons.Filled.Menu)
}
}
}).takeIf { showBottomAppBar }
val snackbar = @Composable {
if (showSnackbar) {
val snackbarData = object : SnackbarData {
override val message = "Snackbar"
override val actionLabel = "Click me"
override fun dismiss() {}
override fun performAction() {}
override val duration = SnackbarDuration.Indefinite
}
Snackbar(snackbarData)
}
}
val fab = (@Composable {
FloatingActionButton(
icon = { Icon(Icons.Filled.Favorite) },
onClick = {}
)
}).takeIf { showFab }
val layoutDirection = if (rtl) LayoutDirection.Rtl else LayoutDirection.Ltr
Providers(LayoutDirectionAmbient provides layoutDirection) {
Box(Modifier
.fillMaxSize(0.5f)
.wrapContentSize()
.semantics(mergeAllDescendants = true) {}
.testTag(Tag)
) {
Scaffold(
topBar = topAppBar,
bottomBar = bottomAppBar,
snackbarHost = { snackbar() },
floatingActionButton = fab,
floatingActionButtonPosition = fabPosition,
isFloatingActionButtonDocked = dockedFab,
bodyContent = { innerPadding ->
Box(
modifier = Modifier
.padding(innerPadding)
.fillMaxSize()
.background(MaterialTheme.colors.secondary.copy(alpha = 0.3f))
) {
Text(
text = "Scaffold Content",
modifier = Modifier.fillMaxSize().wrapContentSize()
)
}
}
)
}
}
}
private const val Tag = "Scaffold"