Status Update
Comments
je...@google.com <je...@google.com> #2
Hello, thanks for reporting.
I can reproduce this issue by targeting SDK 35 and running the test on an emulator running Android 35.
I couldn't reproduce in a test that detects that content is occluded though. Both isDisplayed()
and !isNotDisplayed()
still return true, which seems to be caused by a bug in View.getGlobalVisibleRect
, which doesn't take the action bar into account either and which we rely on to get the clipped bounds of the AbstractComposeView.
I also couldn't reproduce with a View only test using Espresso and the following assertion: Espresso.onView(withText("Hello World")).check(matches(isCompletelyDisplayed()))
. Espresso also seems to rely on View.getGlobalVisibleRect
(
ta...@gmail.com <ta...@gmail.com> #3
Thank you for addressing this issue. I believe verifying the visibility and clickability of UI components is crucial for both UI and AI agent tests. Therefore, I think it's worth filing an issue to address this. Currently, I can achieve this through touch events, but it's not an ideal solution.
@RunWith(AndroidJUnit4::class)
class ExampleInstrumentedTest {
@get:Rule
val composeTestRule = createComposeRule()
@Test
fun useAppContext() {
composeTestRule.setContent {
Column {
var isClicked by remember { mutableStateOf(false) }
// You can click the Button with this text
// Text("Hello\n\n\n\n\n\n\n\n\n\n World, $isClicked")
Button(onClick = { isClicked = true }) {
Text("Click me $isClicked")
}
}
}
val rect = composeTestRule.onNode(hasText("Click me false")).getBoundsInRoot()
val activity = (composeTestRule as AndroidComposeTestRule<*, *>).activity
val metrics = activity.windowManager.currentWindowMetrics
val density = metrics.density
println("density: $density $rect")
val x = (rect.left.value + rect.width.value / 2F) * density
val y = (rect.top.value + rect.height.value / 2F) * density
println("x: $x, y: $y")
activity.runOnUiThread {
activity.window.decorView.dispatchTouchEvent(MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, x, y, 0))
activity.window.decorView.dispatchTouchEvent(MotionEvent.obtain(0, 0, MotionEvent.ACTION_UP, x, y, 0))
}
composeTestRule.onNode(hasText("Click me true")).assertIsDisplayed()
}
}
je...@google.com <je...@google.com> #4
Clicks sent with the input injection methods (performClick
, performTouchInput
, etc) are not affected by the occlusion because we're essentially doing the same as in your workaround; we send the MotionEvents directly to the View that's hosting the compose content. You should be able to replace your custom injection logic with composeTestRule.onNode(hasText("Click me false")).performClick()
. If that doesn't pass, can you try the following test?
@Test
fun clickUnderActionBar() {
var clicked = false
composeTestRule.setContent {
Button(onClick = { clicked = true }) { Text("Click me") }
}
composeTestRule.onNodeWithText("Click me").performClick()
composeTestRule.runOnIdle { assert(clicked) { "Box was not clicked" } }
}
an...@google.com <an...@google.com>
ta...@gmail.com <ta...@gmail.com> #5
Thank you for your continued work on this issue and the information about performClick()
.
I confirmed that both composeTestRule.onNode(hasText("Click me false")).performClick()
and the clickUnderActionBar()
test work as expected.
My aim was to provide a reproducing test case that demonstrates user clicks are unable to reach components as expected when they are overlaid by the ActionBar.
I'm very positive about the current direction of applying the appropriate theme, and I believe this approach will effectively resolve the underlying issue.
Thank you again for your efforts.
ap...@google.com <ap...@google.com> #6
Project: platform/frameworks/support
Branch: androidx-main
Author: Jelle Fresen <
Link:
Use NoActionBar theme for default test activity
Expand for full commit details
Use NoActionBar theme for default test activity
When targeting SDK 35, an activity is edge-to-edge by default. The
default theme has an ActionBar, which is now overlapping with the UI.
Fix this by setting a NoActionBar theme to remove the ActionBar. This
should not be a problem for existing tests, as the intended usecase for
using the ComponentActivity as a compose host is to test composables in
isolation.
Also changes the inappropriately named ActivityWithActionBar we use for
internal testing with the more appropriate name
CustomComposeHostActivity, as it had nothing to do with having an action
bar or not.
Bug: 383368165
Test: Added regression test in ComponentActivityLaunchesTest
Relnote: "The activity that is used as the host for the composable under
test when using `ComposeContentTestRule.setContent` now uses the theme
`Theme.Material.Light.NoActionBar`, to avoid the ActionBar from
overlapping with test content when targeting SDK 35. To opt out of this
behavior, you can remove the dependency on `ui-test-manifest` and add an
activity entry in your test app's AndroidManifest.xml for
ComponentActivity with the theme of your choice."
Change-Id: I7ae1bd28f5e341dafc07442b35ee4249793d257d
Files:
- M
compose/material/material-navigation/build.gradle
- M
compose/ui/ui-test-manifest/integration-tests/testapp/build.gradle
- M
compose/ui/ui-test-manifest/integration-tests/testapp/src/androidTest/java/androidx/compose/ui/test/manifest/integration/testapp/ComponentActivityLaunchesTest.kt
- M
compose/ui/ui-test-manifest/src/main/AndroidManifest.xml
- M
compose/ui/ui-test/src/androidInstrumentedTest/AndroidManifest.xml
- M
compose/ui/ui-test/src/androidInstrumentedTest/kotlin/androidx/compose/ui/test/BitmapCapturingTest.kt
- M
compose/ui/ui-test/src/androidInstrumentedTest/kotlin/androidx/compose/ui/test/CustomComposeHostActivity.kt
- M
compose/ui/ui-test/src/androidInstrumentedTest/kotlin/androidx/compose/ui/test/IsDisplayedTest.kt
- M
compose/ui/ui-test/src/androidInstrumentedTest/kotlin/androidx/compose/ui/test/gesturescope/SendClickTest.kt
- M
constraintlayout/constraintlayout-compose/build.gradle
Hash: 18d7693b4eba2ec6b1d1162b2154e914ba6ef25d
Date: Mon Dec 16 20:31:21 2024
je...@google.com <je...@google.com>
pr...@google.com <pr...@google.com> #7
The following release(s) address this bug.It is possible this bug has only been partially addressed:
androidx.compose.material:material-navigation:1.8.0-alpha08
androidx.compose.ui:ui-test:1.8.0-alpha08
androidx.compose.ui:ui-test-android:1.8.0-alpha08
androidx.compose.ui:ui-test-jvmstubs:1.8.0-alpha08
androidx.compose.ui:ui-test-linuxx64stubs:1.8.0-alpha08
androidx.compose.ui:ui-test-manifest:1.8.0-alpha08
Description
Jetpack Compose version:
BOM 2024.09.00
Jetpack Compose component(s) used:
Compose Testing (createComposeRule)
Android Studio Build:
Android Studio Meerkat | 2024.3.1 Canary 3 Build #AI-243.21565.193.2431.12691553, built on November 21, 2024 Runtime version: 21.0.5+-12651406-b631.16 aarch64 VM: OpenJDK 64-Bit Server VM by JetBrains s.r.o. Toolkit: sun.lwawt.macosx.LWCToolkit macOS 14.4.1
Steps to Reproduce or Code Sample to Reproduce:
Expected Behavior:
The default theme should prevent the ActionBar from overlapping the Compose content, as most users use themes without ActionBars in Compose-based projects. In fact, newly created Android projects use
android:Theme.Material.Light.NoActionBar
by default, which naturally avoids this issue. Updating the default testing environment to setwindowActionBar=false
would better align with typical use cases and expected behaviors.Actual Behavior:
The ActionBar is displayed and overlaps the Compose content. This leads to confusion, especially for beginners or developers trying to test simple layouts, as their content may not appear as expected.
Related links
Reproduced Repository:
https://github.com/takahirom/createComposeRule-ActionBar-Overrapping-issue/blob/main/module/src/androidTest/java/com/github/takahirom/module/ExampleInstrumentedTest.kt
Relevant Pull Request:
https://github.com/android/nowinandroid/pull/1719