Search code examples
kotlintestingcompose-desktop

Compose Desktop testing - how to check if something is visible?


Given some simple content:

@Composable
fun MyContent() {
    var showThing by remember { mutableStateOf(false) }
    if (showThing) {
        Box(Modifier.testTag("thing")) {
            Text("The Thing")
        }
    }
}

If I try to test whether the thing has been displayed:

@OptIn(ExperimentalTestApi::class)
class Scratch {
    @get:Rule
    val compose = createComposeRule()

    @Test
    fun test() {
        runBlocking(Dispatchers.Main) {
            compose.setContent {
                MyContent()
            }
            compose.awaitIdle()

            compose.onNodeWithTag("thing").assertIsNotDisplayed()
        }
    }
}

I get this:

An operation is not implemented.
kotlin.NotImplementedError: An operation is not implemented.
    at androidx.compose.ui.test.DesktopAssertions_desktopKt.checkIsDisplayed(DesktopAssertions.desktop.kt:23)
    at androidx.compose.ui.test.AssertionsKt.assertIsNotDisplayed(Assertions.kt:49)
    at Scratch$test$1.invokeSuspend(Scratch.kt:44)
    at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
    at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
    ...

I thought testing whether something was displayed or not would be the most basic thing to test, but it isn't supported by the framework yet. The test framework is experimental, so I was expecting to find things missing, but not like this.

Is there another way to do this which I'm missing? All the tutorials out there talk about assertIsDisplayed() being the way, but maybe there is an alternative?


Solution

  • It's not a direct substitute, but unfortunately, JB Compose Desktop has these limitations in the UI test suite. Aside from using only JUnit 4, and not being compatible with the newer version, many assertion methods and also screen interaction methods are not implemented, such as the .assertIsNotDisplayed() that you tried to use, and also actions like .performTextInput().

    An alternative for your problem would be using other methods like .assertDoesNotExist() and .assertExists().

    It's not going to tell you if the element is in the boundaries of the screen and visible, but at least will tell you that your node exists and is instantiated, which is something, and it's better than nothing.

    Until JetBrains implement the complete desktop test suite, we need to work with what we have, or maybe try implementing some things as a workaround.

    In your case, this will work:

    @OptIn(ExperimentalTestApi::class)
    class Scratch {
        @get:Rule
        val compose = createComposeRule()
    
    @Test
    fun test() {
        runBlocking(Dispatchers.Main) {
            compose.setContent {
                MyContent()
            }
            compose.awaitIdle()
    
            compose.onNodeWithTag("thing").assertDoesNotExist()
        }
    }