A question about Compose Tests building on Wear Co...
# compose-wear
y
A question about Compose Tests building on Wear Compose / Material. I ended up with a test like
Copy code
@Test
    fun testAutoHide() {
        composeTestRule.setContent {
            VolumePositionIndicator(
                modifier = Modifier.testTag(TEST_TAG),
                volumeState = { volumeState },
                autoHide = true
            )
        }

        val positionIndicator = composeTestRule.onNodeWithTag(TEST_TAG)

        positionIndicator.assertDoesNotExist()

        volumeState = volumeState.copy(current = 51)

        composeTestRule.mainClock.advanceTimeByFrame()
        composeTestRule.mainClock.advanceTimeBy(500L)

        composeTestRule.onRoot(useUnmergedTree = true).printToLog("testAutoHide")

        positionIndicator.assertIsDisplayed()
    }
Two questions
1. I found the advanceTimeByFrame + advanceTimeBy pattern in stackoverflow, without the frame advance, the animations don't seem to run. Is this known, expected?
2. It's awkward trying to test again classes like PositionIndicator. The Scroll State classes that you use internally to validate the behaviour are internal. Are there any patterns used in mobile compose - for validating the state of core library classes like PositionIndicator?
I guess I'm asking for this - https://developer.android.com/jetpack/compose/testing#custom-semantics-properties Maybe with an optional flag to enable?
j
@Steve Bower [G]
s
Hi - I would expect to see
Copy code
composeTestRule.mainClock.autoAdvance = false
at the start of the test if the clock is going to be manually driven. In which case, yes, the clock will be fixed and the animations won't run until the clock is advanced manually. For (2), could you be more specific about the tests you want to run against PositionIndicator? There are a number of overloads for which the scroll state is public (e.g. ScalingLazyListState) or you can add your own PositionIndicatorState implementation.
y
Yep - I've got multiple tests so using.
Copy code
@get:Rule
    val composeTestRule = createComposeRule().apply {
        mainClock.autoAdvance = false
    }
I'm trying to test my own component which uses PositionIndicator. Specifically the float one.
Copy code
@Composable
public fun PositionIndicator(
    value: () -> Float,
    modifier: Modifier = Modifier,
    range: ClosedFloatingPointRange<Float> = 0f..1f,
    color: Color = MaterialTheme.colors.onBackground,
    reverseDirection: Boolean = false
) = PositionIndicator(
    state = FractionPositionIndicatorState {
        (value() - range.start) / (range.endInclusive - range.start)
    },
FractionPositionIndicatorState is internal but created inside anyway.
I was imagining that Composable's with testTag could output state that shows up in SemanticNodeInteraction.printToLog and can be tested against. But I think you raise a great point, normally you test via real objects, not poking around quasi-internal api through the semantics node. It's very brittle if you don't own those objects.
s
Yep - better to pass in a mock or stub test object, then you can record whatever interactions were expected.