I have a `ClickableText` (with an annotated strin...
# compose
b
I have a
ClickableText
(with an annotated string), and I only handle clicks on a certain portion of the string, like this:
Copy code
onClick = { pos ->
    if (pos in linkStart..linkEnd) {
        onLoginClicked()
    }
}
How can I test this? I need a way in the test to click on a certain position (string index) in the text.
performClick()
doesn’t take any parameters that I could use to click at a certain position. Using
performTouchInput()
let’s me move by a number of pixels, but I’m not sure how that helps since I need to click based on string position.
b
A test written that way would be testing Compose itself. Instead, consider limiting the scope to your own code. You shouldn't need to test that Compose is correctly handling clicks (let Google handle that). Only test that your code onClick function is correct, which you can do by calling directly without Compose.
b
@Brian G - Well, what I’m trying to test is the containing composable, and that the
onLoginClicked()
callback it’s given is called appropriately. For example, if another dev on the team comes along and makes this change:
Copy code
onClick = { pos ->
    if (pos in linkStart..linkEnd) {
        //Removing this, we don't want to do anything when the text is clicked.  
        //onLoginClicked()
    }
}
Then I want a test somewhere to fail because the callback was not called
Basically this test:
Copy code
@Test
fun LoginClickCallbackIsCalled() {
   var loginClicked = false

   composeTestRule.setContent {
      MyComposable(onLoginClicked = { loginClicked = true })
   }

   composeTestRule.onNodeWithContentDescription("The ClickableText").performClick()

   assertTrue("Login callback should be called when login is clicked", loginClicked)
}
b
Right, if you want to test that function, you extract it and test the function itself.
If this mystery "dev" can comment out that function call, they can also comment out the assertTrue call in your test...
Normally you use tests to verify some complex logic. Trying to test that "clicking calls click handler" is akin to testing "1 == 1". The only logic in your function is checking for a certain index... If you want to test that, you can extract your callback to a function, like:
fun onTextClick(index: Int)
containing that logic, and test THAT function in your unit test.
b
@Brian G Fair enough, and my example is admittedly contrived … but what about integration tests or end to end tests? I still contend that there should be some way with the Compose Test Rules to be able to
perofrmClick
on a certain character position in a ClickableText
z
SemanticsNodeInteraction has a performGesture method that lets you send touch events to exact points.
Look at the impl of eg performClick
b
@Zach Klippenstein (he/him) [MOD] yep. I started down that path. The “problem” there is that I’d have to calculate the click point using some algorithm to figure out the x/y point for a character (or set of characters) at position X in a string. And maybe that’s the only way to do it. I was just hoping for something easier, or something that does that for me in the same way that
ClickableText
does it and gives me a string position in the callback and not an x/y point.
z
We are aware ClickableText has issues and want to replace it with a better api. This testing use case is good to track though. Can you file a feature request please?
b
Sure thing
@Zach Klippenstein (he/him) [MOD] done. I filed the issue against the Testing component, since my particular problem is with the inability to test and not with
ClickableText
itself (which does exactly what I need). https://issuetracker.google.com/issues/207325144
z
Thanks!
c
Bump, its been a year, this api could use some love 💚
z
We’re focusing on fixing major issues with text field at the moment, but this is still very much on our radar and I’m hoping to work on it next
200 Views