-
Notifications
You must be signed in to change notification settings - Fork 3.1k
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
Show snackbar in large screen #1296
Conversation
Any chance to cover this with an UI behavior or screenshot regression test? |
@JoseAlcerreca
Does it exception cause because of I am using Windows 11? |
How are you running the test? |
Oh It had discussed in issues. I forgotten. • Run test directly, you can see above mentioned exception. By this reason, It is hard to make screenshot test on my own. |
I finally found the formular to check position, but it only work when the simulator was Foldable(Resizable), not Phone and Tablet. 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,
)
} |
Edit: |
I breakthrough the testing by check the height of spacer. |
The test failed from testharness.
The
And I start discussion for screenshot test #1347, for this issue #1295. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For testing, how about you add it to #1343? You are checking for dimensions, so screenshots are a much easier way to do it.
I think you can do this by overriding WindowInsetsHolder? It has a setUseTestInsets
function, but I haven't looked into this.
app/src/androidTest/kotlin/com/google/samples/apps/nowinandroid/extensions/GetString.kt
Outdated
Show resolved
Hide resolved
...oogle/samples/apps/nowinandroid/core/data/test/networkmonitor/AlwaysOfflineNetworkMonitor.kt
Outdated
Show resolved
Hide resolved
Thank you for your review.
Spacer(
modifier = Modifier
.height(bottomNavigationHeight)
.semantics {
testTag = "Bottom padding for snackbar"
},
)
Best regards. |
18c1eee
to
57eeb76
Compare
Does Anyone have ideas giving the fake insets to val bottomNavigationHeight = density.run {
WindowInsets.safeDrawing
.getBottom(density = density)
.toDp()
} Kindly leave your ideas in #1347 If you think my instrumented test |
I'd added screenshots. Done. |
With the merging of #1498 , we should be able to directly test the fix here for the snackbar across device configurations. Would you be able to rebase on top of latest to check the result? |
@alexvanyo Thank you for introducing. I'll try it or re-open this PR. |
Change-Id: If26e71be75bb76b3f31b575a92044ea72aafc641
Change-Id: I93dbc31d9cdf6d23fb8cf5b080846f6e23e8a855
Change-Id: I914d391730d00860d23668d13359e3734e9d6324
Change-Id: Ie592f98a7ecd4fba0d02a671a4083859976e0cf2
Change-Id: I063eb5ec8dc55baaf48206db8801a050c4d6035a
a7089e2
to
644e618
Compare
Change-Id: I59dd7c3071a0d11d8a747c9b801d3de136e67770
Change-Id: I71bc6279b4fc9fe12a4783d87b2ed43491cace04
…ackbar-copy Change-Id: I176216bbbf1562f951fe7c9be0cb0d9a6f94f4e5
Shot screenshot test
@alexvanyo @JoseAlcerreca Thank you all. |
Superseded by #1697 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yyy
What I have done and why
Add
SafeDrawing bottom padding
to show snackbar overbottom navigation bar
I'd set the
windowInsetsPadding
toNiaBackground
, because SnackBar was drawn on theNiaBackground
notNiaApp
.Fixes #1295
Foldable
Tablet