I want to test a button that changes it's state on...
# compose
z
I want to test a button that changes it's state on click to a progress indicator and then a few seconds later becomes disabled. How can i make the test wait or speed up to test the final state?
Copy code
@Test
    fun test_button_completed_state_correct(): Unit = runBlocking {

        val completedText = mockStateButtonsList.items.first().contents.first { it.state == StateButtonListContent.ButtonState.COMPLETED }.button.caption.orEmpty()

        // Given
        composeTestRule.setContent {
            TestStateButtonList(
                StateButtonListStateReducer(mockStateButtonsList, this)
            )
        }

        // When
        composeTestRule
            .onAllNodesWithTag(STATE_BUTTON)
            .onFirst()
            .performClick()

        // Wait 5000 milliseconds

        // Then
        composeTestRule
            .onAllNodesWithTag(STATE_BUTTON)
            .onFirst()
            .assert(hasText(completedText))
    }
l
You can use delay(Long) to delay a certain time. If I remember correctly, delay(Long) will cause other coroutines to immediately act like there was a delay.
this should help
Copy code
rule.mainClock.advanceTimeBy(DefaultDurationMillis.toLong())
can you use advanceTimeBy to test this ? 🤔
l
That looks cool. I didn’t know about rule.mainClock
o
Let me know if that worked for you!
z
mainClock.autoAdvance = false
failes the test
But
delay
worked
However, the test would be long (number of secondes i wait in delay)
l
after setting autoAdvance to false, did you use advanceTimeBy?
z
Yes, the test failed faster 🥲
Copy code
java.lang.AssertionError: Failed to assert the following: (Text + EditableText contains 'IN PROGRESS' (ignoreCase: false))
Semantics of the node:
Node #66 at (l=605.0, t=107.0, r=1033.0, b=258.0)px, Tag: 'test_button'
Role = 'Button'
Focused = 'false'
Text = '[CONNECT]'
Actions = [OnClick, GetTextLayoutResult]
MergeDescendants = 'true'
Has 11 siblings
Selector used: ((TestTag = 'test_button')[0])
l
If you use runTest {} instead of run blocking, delay will signal other coroutines, but not actually delay.
z
I have to use runBlocking because i need a couroutine scope to test with.
The button uses a coroutine scope internally
l
runBlockingTest?
z
Trying
l
runTest should provide a coroutine scope.
z
runBlockingTest
worked!!!
Thank you!!
s
Wait where does
runBlockingTest
come from?
l
It’s in the coroutines test package. They do recommend replacing it with runTest where possible.
s
Aha alright, that's the old API then I guess, I thought maybe it was coming from somewhere else.