KakaoCup / Compose

Nice and simple DSL for Espresso Compose UI testing in Kotlin
https://kakaocup.github.io/Compose/
Apache License 2.0
146 stars 15 forks source link

Problems with matching child nodes for the Compose Screen #25

Closed AJIEKCX closed 2 years ago

AJIEKCX commented 2 years ago

Hi, I have a problem with matching child nodes for the ComposeScreen. It works in simple cases but for the current screen it won’t work:

fun SimpleScreen() {
   Scaffold(Modifier.testTag(TestTag.SimpleScreen.Tag)) {
       Card {
           Text(
               "TestTitle",
               Modifier
                   .padding(16.dp)
                   .testTag(TestTag.SimpleScreen.Title)
           )
       }
   }
}

The following PageObject can’t find our title at this screen:

class KSimpleScreen(semanticsProvider: SemanticsNodeInteractionsProvider) : ComposeScreen<KSimpleScreen>(
   semanticsProvider = semanticsProvider,
   viewBuilderAction = { hasTestTag(TestTag.SimpleScreen.Tag) }
) {
   val title: KNode = child {
       hasTestTag(TestTag.SimpleScreen.Title)
   }
}

It can be fixed by deleting child and using hasAnyAncestor matcher:

val title: KNode = KNode(semanticsProvider) {
   hasAnyAncestor((androidx.compose.ui.test.hasTestTag(TestTag.SimpleScreen.Tag)))
   hasTestTag(TestTag.SimpleScreen.Title)
}

But it’s not convenient and it would be great if BaseNode had this matcher by default for the parent node or allowed to change this behavior.

AJIEKCX commented 2 years ago

Also there is another problem with nested page objects. Because BaseNode inherits only direct parent node matchers but not all ancestors:

override val delegate: ComposeDelegate by lazy(LazyThreadSafetyMode.NONE) {
   ComposeDelegate(
       nodeProvider = NodeProvider(
           nodeMatcher = NodeMatcher(
               matcher = if (parentNode == null) nodeMatcher.matcher else hasParent(parentNode.nodeMatcher.matcher) and nodeMatcher.matcher,
               position = nodeMatcher.position,
               useUnmergedTree = nodeMatcher.useUnmergedTree
           ),
           semanticsProvider = semanticsProvider
       ),
       parentDelegate = parentNode?.delegate
   )
}

And it can be a problem for some cases. I think we should combine matchers from all ancestor nodes.

AJIEKCX commented 2 years ago

I will try to work on this issue

AJIEKCX commented 2 years ago

I've done it in #28