Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Show snackbar in large screen #1296

Open
wants to merge 59 commits into
base: main
Choose a base branch
from

Conversation

Jaehwa-Noh
Copy link
Contributor

@Jaehwa-Noh Jaehwa-Noh commented Mar 18, 2024

What I have done and why
Add SafeDrawing bottom padding to show snackbar over bottom navigation bar

Fixes #1295

Foldable

For you Saved Interests
For you Saved Interests

Tablet

For you Saved Interests
For you Saved Interests

Open to contribute anyone on test code if you want.

Change-Id: I3af6fbfff20392749a7ff3eb72426b18fbf2f37e
Change-Id: I15a3c68a0a590e067a65c5e28ec753c06a4dfa46
Change-Id: I6e77ff7c0c3e6a40eb6aa28650c2f8c9f97cda4a
Change-Id: Ifc1e70441c6bb10af101abc658fa067d04b57007
Change-Id: I54be63d7641873c8209836948a3a8aebd6f23156
- compactWidth_WhenNotConnectedAndForYou_ConnectSnackBarShowUp
- compactWidth_WhenNotConnectedAndSaved_ConnectSnackBarShowUp
- compactWidth_WhenNotConnectedAndInterests_ConnectSnackBarShowUp
- mediumWidth_WhenNotConnectedAndForYou_ConnectSnackBarShowUp
- mediumWidth_WhenNotConnectedAndSaved_ConnectSnackBarShowUp
- mediumWidth_WhenNotConnectedAndInterests_ConnectSnackBarShowUp
- expandedWidth_WhenNotConnectedAndForYou_ConnectSnackBarShowUp
- expandedWidth_WhenNotConnectedAndSaved_ConnectSnackBarShowUp
- expandedWidth_WhenNotConnectedAndInterests_ConnectSnackBarShowUp

Change-Id: I59404391ef0d62e278677014b5c972b59392660c
Change-Id: I52eb78e836eba9c9acdb2beec9baa4cc3fe969ef
@JoseAlcerreca
Copy link
Contributor

Any chance to cover this with an UI behavior or screenshot regression test?

@Jaehwa-Noh
Copy link
Contributor Author

Jaehwa-Noh commented Mar 18, 2024

@JoseAlcerreca
Unfortunately, I can't.
I try to make some tests, but assertIsDisplay is always true whether behind System UI or not.
And screenshot test always throw exception

java.lang.RuntimeException: Unable to resolve activity for Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] cmp=com.google.samples.apps.nowinandroid.core.designsystem.test/androidx.activity.ComponentActivity }

Does it exception cause because of I am using Windows 11?

@JoseAlcerreca
Copy link
Contributor

How are you running the test?

@Jaehwa-Noh
Copy link
Contributor Author

Jaehwa-Noh commented Mar 18, 2024

Oh It had discussed in issues. I forgotten.
• Run with ./gradlew testDemoDebug
The result as #1242

test



• Run test directly, you can see above mentioned exception.

By this reason, It is hard to make screenshot test on my own.

@Jaehwa-Noh
Copy link
Contributor Author

Jaehwa-Noh commented Mar 18, 2024

I finally found the formular to check position, but it only work when the simulator was Foldable(Resizable), not Phone and Tablet.
The problem is how to run tests only on Foldable device.

Test Code
/*
 * Copyright 2024 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
 *
 *     https://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.google.samples.apps.nowinandroid.ui

import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.BoxWithConstraints
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.safeDrawing
import androidx.compose.material3.windowsizeclass.ExperimentalMaterial3WindowSizeClassApi
import androidx.compose.material3.windowsizeclass.WindowSizeClass
import androidx.compose.runtime.Composable
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.test.SemanticsNodeInteraction
import androidx.compose.ui.test.assertIsDisplayed
import androidx.compose.ui.test.assertIsSelected
import androidx.compose.ui.test.assertTopPositionInRootIsEqualTo
import androidx.compose.ui.test.hasAnyDescendant
import androidx.compose.ui.test.hasTestTag
import androidx.compose.ui.test.hasText
import androidx.compose.ui.test.isSelectable
import androidx.compose.ui.test.junit4.createAndroidComposeRule
import androidx.compose.ui.test.performClick
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.DpSize
import androidx.compose.ui.unit.dp
import com.google.accompanist.testharness.TestHarness
import com.google.samples.apps.nowinandroid.MainActivity
import com.google.samples.apps.nowinandroid.R
import com.google.samples.apps.nowinandroid.core.data.repository.CompositeUserNewsResourceRepository
import com.google.samples.apps.nowinandroid.core.data.test.networkmonitor.AlwaysOfflineNetworkMonitor
import com.google.samples.apps.nowinandroid.core.data.util.NetworkMonitor
import com.google.samples.apps.nowinandroid.core.data.util.TimeZoneMonitor
import com.google.samples.apps.nowinandroid.core.rules.GrantPostNotificationsPermissionRule
import com.google.samples.apps.nowinandroid.extensions.stringResource
import dagger.hilt.android.testing.BindValue
import dagger.hilt.android.testing.HiltAndroidRule
import dagger.hilt.android.testing.HiltAndroidTest
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.rules.TemporaryFolder
import javax.inject.Inject

@HiltAndroidTest
class ConnectSnackBarTest {

    /**
     * Manages the components' state and is used to perform injection on your test
     */
    @get:Rule(order = 0)
    val hiltRule = HiltAndroidRule(this)

    /**
     * Create a temporary folder used to create a Data Store file. This guarantees that
     * the file is removed in between each test, preventing a crash.
     */
    @BindValue
    @get:Rule(order = 1)
    val tmpFolder: TemporaryFolder = TemporaryFolder.builder().assureDeletion().build()

    /**
     * Grant [android.Manifest.permission.POST_NOTIFICATIONS] permission.
     */
    @get:Rule(order = 2)
    val postNotificationsPermission = GrantPostNotificationsPermissionRule()

    /**
     * Use the primary activity to initialize the app normally.
     */
    @get:Rule(order = 3)
    val composeTestRule = createAndroidComposeRule<MainActivity>()

    @Inject
    lateinit var userNewsResourceRepository: CompositeUserNewsResourceRepository

    @Inject
    lateinit var timeZoneMonitor: TimeZoneMonitor

    private val networkMonitor: NetworkMonitor = AlwaysOfflineNetworkMonitor()

    private val forYou by composeTestRule.stringResource(com.google.samples.apps.nowinandroid.feature.foryou.R.string.feature_foryou_title)
    private val interests by composeTestRule.stringResource(com.google.samples.apps.nowinandroid.feature.interests.R.string.feature_interests_title)
    private val saved by composeTestRule.stringResource(com.google.samples.apps.nowinandroid.feature.bookmarks.R.string.feature_bookmarks_title)
    private val netConnected by composeTestRule.stringResource(R.string.not_connected)

    private var height = 0.dp
    private var bottomSafeDrawingHeight = 0.dp

    @Before
    fun setup() = hiltRule.inject()

    @Test
    fun mediumWidth_WhenNotConnectedAndForYou_ConnectSnackBarShowUp() {
        composeTestRule.activity.apply {
            setContent {
                TestHarness(size = DpSize(610.dp, 1000.dp)) {
                    BoxWithConstraints {
                        val density = LocalDensity.current
                        height = maxHeight
                        bottomSafeDrawingHeight =
                            WindowInsets.safeDrawing.getBottom(density = density).dp
                        NiaApp(
                            appState = fakeAppState(maxWidth, maxHeight),
                        )
                    }
                }
            }
        }

        composeTestRule.apply {
            findNavigationButton(forYou).apply {
                performClick()
                assertIsSelected()
            }

            findSnackbarWithMessage(message = netConnected)
                .assertIsDisplayed()
                .assertTopPositionInRootIsEqualTo(height - bottomSafeDrawingHeight)
        }
    }

    private fun findSnackbarWithMessage(message: String): SemanticsNodeInteraction =
        composeTestRule.onNode(
            matcher = hasTestTag("Snackbar") and
                hasAnyDescendant(matcher = hasText(message)),
        )

    private fun findNavigationButton(string: String): SemanticsNodeInteraction =
        composeTestRule.onNode(matcher = isSelectable() and hasText(string))

    @OptIn(ExperimentalMaterial3WindowSizeClassApi::class)
    @Composable
    private fun fakeAppState(maxWidth: Dp, maxHeight: Dp) = rememberNiaAppState(
        windowSizeClass = WindowSizeClass.calculateFromSize(DpSize(maxWidth, maxHeight)),
        networkMonitor = networkMonitor,
        userNewsResourceRepository = userNewsResourceRepository,
        timeZoneMonitor = timeZoneMonitor,
    )
}
I would remain test parts to one who want to contribute.

Change-Id: Iaaf41bfc4d6a0a604d7a731ba80b9dee06ecd3b2
Change-Id: Ieea183d9e66d598e663db26a75322da770ad8a54
Change-Id: Ic292512fb024e58a64db455fdfd2ace56a1e8ef5
Change-Id: Ic8655c5102ed94edc3772e6f0bc170115fa3f19b
Change-Id: I836bdbbe40c714048c62e7c2246ab5a251b6bf21
Change-Id: I252dd48426bc34bf0597a515ee6557d36f07fda2
- compactWidth_WhenNotConnectedAndForYou_ConnectSnackBarShowUp
- compactWidth_WhenNotConnectedAndSaved_ConnectSnackBarShowUp
- compactWidth_WhenNotConnectedAndInterests_ConnectSnackBarShowUp
- mediumWidth_WhenNotConnectedAndForYou_ConnectSnackBarShowUp
- mediumWidth_WhenNotConnectedAndSaved_ConnectSnackBarShowUp
- mediumWidth_WhenNotConnectedAndInterests_ConnectSnackBarShowUp
- expandedWidth_WhenNotConnectedAndForYou_ConnectSnackBarShowUp
- expandedWidth_WhenNotConnectedAndSaved_ConnectSnackBarShowUp
- expandedWidth_WhenNotConnectedAndInterests_ConnectSnackBarShowUp

Change-Id: I736fcb3624da6b05e5a43f4407062aed22c3143a
…st' into show-snackbar-in-large-screen-test

Change-Id: I36a8863c4918f171af4068302a0d18815872c995
@Jaehwa-Noh
Copy link
Contributor Author

Jaehwa-Noh commented Mar 19, 2024

I added test case.
But I don't say that this is best practices, but It is the only way to test, now.

Edit:
There's no way to test it.
The git action device is Phone size, and there are no Tablet or Foldable to test.

Change-Id: I75e8d49b0448fd96eaceadb70cfee5c5c3741fc7
@Jaehwa-Noh Jaehwa-Noh marked this pull request as draft March 19, 2024 06:21
Change-Id: I11586ce6e134539a573e9d518f4fcd2d88f21996
Change-Id: I3b445d1b48c5c4e4a30f76c955d759ad5603c8b2
Change-Id: Id22296bf04f9611702cef42a74aa4f1ddd48225d
@Jaehwa-Noh Jaehwa-Noh marked this pull request as draft April 12, 2024 12:37
Change-Id: I2c7cb9c0ef3d5e239007dd9526b0c5b021ddb043
Change-Id: I13d2bc4471d7b904dd9c779af004b639754b67c0
…d-remote-main

Change-Id: I49b7e75fec1dc12f8f0f6ac3f59f93f9a96c644a
Change-Id: I01a1d3b759847db89c7b129358407cd3530eb7ad
Change-Id: I60c2a46bd98afd4663fd85ac1aa7b022ab84a75d
Change-Id: I55a6fcfc53f1c96f376cab77079e248bdc2df44f
@Jaehwa-Noh Jaehwa-Noh force-pushed the show-snackbar-in-large-screen branch from 18c1eee to 57eeb76 Compare April 16, 2024 07:51
@Jaehwa-Noh Jaehwa-Noh marked this pull request as ready for review April 16, 2024 08:13
@Jaehwa-Noh
Copy link
Contributor Author

Jaehwa-Noh commented Apr 16, 2024

Does Anyone have ideas giving the fake insets to WindowInsets.safeDrawing to test screenshot test?
My code does avoid System UI by calculate WindowInsets.safeDrawing.

val bottomNavigationHeight = density.run {
        WindowInsets.safeDrawing
            .getBottom(density = density)
            .toDp()
    }

Kindly leave your ideas in #1347

If you think my instrumented test ConnectSnackBarTest.kt is sufficient to test that avoid System UI logic, kindly merge this pull request.

Change-Id: Ib94dbb319e74f83d6c76fa30ad9c065ea54aa156
@Jaehwa-Noh Jaehwa-Noh marked this pull request as draft April 17, 2024 02:59
Change-Id: Idb2e617263963a6dd10240ed477cf971a5fffd3c
Change-Id: I3ce9a857cc266b74eac35b319d757d1c57bbf11f
Change-Id: Iae760e99678e291e6757f97d38c71eca22429ebc
Change-Id: Ifdc722c5e093a584322c30b51764e7319b166ef8
@Jaehwa-Noh
Copy link
Contributor Author

I'd added screenshots. Done.

@Jaehwa-Noh Jaehwa-Noh marked this pull request as ready for review April 17, 2024 05:07
Change-Id: Ic85b4c18b86664c8ca1c964818d703b04467147a

# Conflicts:
#	app/src/testDemo/kotlin/com/google/samples/apps/nowinandroid/ui/SnackbarScreenshotTests.kt
#	app/src/testDemo/screenshots/snackbar_expanded_expanded.png
#	app/src/testDemo/screenshots/snackbar_medium_medium.png
@Jaehwa-Noh Jaehwa-Noh marked this pull request as draft May 9, 2024 13:09
Change-Id: I629ff6093a13378bf0df8014e9a3cfa9d71b9123
@Jaehwa-Noh Jaehwa-Noh marked this pull request as ready for review May 10, 2024 05:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[Bug]: Can't see a snackbar in medium and expanded screen
2 participants