# MainTestClock

Artifact: [androidx.compose.ui:ui-test](https://developer.android.com/jetpack/androidx/releases/compose-ui) [View Source](https://cs.android.com/search?q=file:androidx/compose/ui/test/MainTestClock.kt+class:androidx.compose.ui.test.MainTestClock) Added in [1.0.0](https://developer.android.com/jetpack/androidx/releases/compose-ui#1.0.0) Common/AllAndroid/JVM
- Cmn

  ```
  interface MainTestClock
  ```

*** ** * ** ***

The clock that drives `https://developer.android.com/reference/kotlin/androidx/compose/runtime/MonotonicFrameClock#withFrameNanos(kotlin.Function1)`, `https://developer.android.com/reference/kotlin/androidx/compose/runtime/Recomposer` and `https://developer.android.com/reference/kotlin/androidx/compose/runtime/LaunchedEffect.composable#LaunchedEffect(kotlin.coroutines.SuspendFunction1)` in compose tests.

This clock is ultimately responsible for driving all recompositions, all subscribers to `https://developer.android.com/reference/kotlin/androidx/compose/runtime/MonotonicFrameClock#withFrameNanos(kotlin.Function1)` (all compose animations) and all coroutines launched with `https://developer.android.com/reference/kotlin/androidx/compose/runtime/LaunchedEffect.composable#LaunchedEffect(kotlin.coroutines.SuspendFunction1)` (for example gesture detection). It is important to realize that if this clock does not tick, recomposition will not happen and animations are frozen.

Measure, layout and draw passes may be driven by this clock, depending on the platform. On Desktop, these are all driven by this clock, but on Android only measure and layout are performed synchronously. The draw pass on Android is driven by the Choreographer and will not happen as a result of forwarding this clock. Note that the Choreographer will also perform measure and layout passes, but these are mostly redundant because we will already have done the measure and layout pass as a result of forwarding this clock to recompose. That means that measure, layout and draw passes can still occur on Android even if this clock is paused.

Therefore, when setting `https://developer.android.com/reference/kotlin/androidx/compose/ui/test/MainTestClock#autoAdvance()` to `false` and taking control over this clock, there are several things to realize:

- Recomposition can only happen when a frame is produced by this clock, with one exception: the initial composition when calling setContent happens immediately.

- Callers of `https://developer.android.com/reference/kotlin/androidx/compose/runtime/MonotonicFrameClock#withFrameNanos(kotlin.Function1)` can only get a frame time when a frame is produced by this clock.

- If there is both a pending recomposition and an animation awaiting a `https://developer.android.com/reference/kotlin/androidx/compose/runtime/MonotonicFrameClock#withFrameNanos(kotlin.Function1)`, ticking this clock will *first* send the new frame time to the animation, and *then* perform recomposition. Any state changes made by the animation will be seen by the recomposition.

- Because animations receive their `https://developer.android.com/reference/kotlin/androidx/compose/runtime/MonotonicFrameClock#withFrameNanos(kotlin.Function1)` *before* recomposition, an animation will not get its start time in the first frame after kicking it off by toggling a state variable. For example, with a frame time of 16ms; when you call `https://developer.android.com/reference/kotlin/androidx/compose/ui/test/MainTestClock#advanceTimeBy(kotlin.Long,kotlin.Boolean)` after you toggled a state variable to kick off an animation, the animation's play time will still be at 0ms. The first frame is produced when the clock has advanced 16ms and will run a recomposition. During that recomposition the animation will be scheduled to start. When the clock has advanced another 16ms, the animation gets its first frame time and initialize the play time to `t=0`.

- Because animations request the next `https://developer.android.com/reference/kotlin/androidx/compose/runtime/MonotonicFrameClock#withFrameNanos(kotlin.Function1)` during the current frame, calling `https://developer.android.com/reference/kotlin/androidx/compose/ui/test/MainTestClock#advanceTimeBy(kotlin.Long,kotlin.Boolean)` while an animation is running will produce 10 frames of 16ms rather than 1 frame of 160ms (assuming a frame time of 16ms). Measure and layout happens after each frame, but draw will not happen in between these frames.

- After modifying a state variable, recomposition needs to happen to reflect the new state in the UI. Advancing the clock by `https://developer.android.com/reference/kotlin/androidx/compose/ui/test/MainTestClock#advanceTimeByFrame()` will commit the changes and run exactly one recomposition and measure and layout if triggered.

- If, after any call to `https://developer.android.com/reference/kotlin/androidx/compose/ui/test/MainTestClock#advanceTimeBy(kotlin.Long,kotlin.Boolean)`, you want to assert anything related to rendering (e.g. SemanticsNodeInteraction.captureToImage), you will need a call to androidx.compose.ui.test.junit4.ComposeTestRule.waitForIdle or androidx.compose.ui.test.junit4.ComposeTestRule.runOnIdle to make sure that any triggered draw pass has been completed.

- If you change a state variable that is read during draw, calling `https://developer.android.com/reference/kotlin/androidx/compose/ui/test/MainTestClock#advanceTimeBy(kotlin.Long,kotlin.Boolean)` will not produce the desired update to the UI. Use androidx.compose.ui.test.junit4.ComposeTestRule.waitForIdle for this case.

- `https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/index.html` `https://developer.android.com/reference/kotlin/androidx/compose/runtime/LaunchedEffect.composable#LaunchedEffect(kotlin.coroutines.SuspendFunction1)`s are resumed on their scheduled time. That means that code like `repeat(2) { delay(1000) }` will complete with a single call to `https://developer.android.com/reference/kotlin/androidx/compose/ui/test/MainTestClock#advanceTimeBy(kotlin.Long,kotlin.Boolean)`.

## Summary

| ### Public functions |
|---|---|---|
| `https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-unit/index.html` | `https://developer.android.com/reference/kotlin/androidx/compose/ui/test/MainTestClock#advanceTimeBy(kotlin.Long,kotlin.Boolean)(milliseconds: https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-long/index.html, ignoreFrameDuration: https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-boolean/index.html)` Advances the clock by the given `https://developer.android.com/reference/kotlin/androidx/compose/ui/test/MainTestClock#advanceTimeBy(kotlin.Long,kotlin.Boolean)`. | Cmn |
| `https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-unit/index.html` | `https://developer.android.com/reference/kotlin/androidx/compose/ui/test/MainTestClock#advanceTimeByFrame()()` `https://developer.android.com/reference/kotlin/androidx/compose/ui/test/MainTestClock#advanceTimeBy(kotlin.Long,kotlin.Boolean)` the main clock by the duration of one frame. | Cmn |
| `https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-unit/index.html` | `https://developer.android.com/reference/kotlin/androidx/compose/ui/test/MainTestClock#advanceTimeUntil(kotlin.Long,kotlin.Function0)(timeoutMillis: https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-long/index.html, condition: () -> https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-boolean/index.html)` Advances the clock in increments of a `https://developer.android.com/reference/kotlin/androidx/compose/ui/test/MainTestClock#advanceTimeByFrame()` until the given `https://developer.android.com/reference/kotlin/androidx/compose/ui/test/MainTestClock#advanceTimeUntil(kotlin.Long,kotlin.Function0)` is satisfied. | Cmn |

| ### Public properties |
|---|---|---|
| `https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-boolean/index.html` | `https://developer.android.com/reference/kotlin/androidx/compose/ui/test/MainTestClock#autoAdvance()` Whether the clock should be advanced by the testing framework while awaiting idleness in order to process any pending work that is driven by this clock. | Cmn |
| `https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-long/index.html` | `https://developer.android.com/reference/kotlin/androidx/compose/ui/test/MainTestClock#currentTime()` The current time of this clock in milliseconds. | Cmn |
| `open https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-test/kotlinx.coroutines.test/-test-coroutine-scheduler/index.html` | `https://developer.android.com/reference/kotlin/androidx/compose/ui/test/MainTestClock#scheduler()` The `https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-test/kotlinx.coroutines.test/-test-coroutine-scheduler/index.html` on which this clock is built. | Cmn |

## Public functions

### advanceTimeBy

Cmn Added in [1.0.0](https://developer.android.com/jetpack/androidx/releases/compose-ui#1.0.0)

```
fun advanceTimeBy(milliseconds: Long, ignoreFrameDuration: Boolean = false): Unit
```

Advances the clock by the given `https://developer.android.com/reference/kotlin/androidx/compose/ui/test/MainTestClock#advanceTimeBy(kotlin.Long,kotlin.Boolean)`. The duration is rounded up to the nearest multiple of the frame duration by default to always produce the same number of frames regardless of the current time of the clock. Use `https://developer.android.com/reference/kotlin/androidx/compose/ui/test/MainTestClock#advanceTimeBy(kotlin.Long,kotlin.Boolean)` to disable this behavior. The frame duration is platform dependent. For example, on a JVM (Android and Desktop) it is 16ms. Note that if `https://developer.android.com/reference/kotlin/androidx/compose/ui/test/MainTestClock#advanceTimeBy(kotlin.Long,kotlin.Boolean)` is true, the last few milliseconds that are advanced might not be observed by anyone, since most processes are only triggered when a frame is produced.

When using this method to advance the time by several frames in one invocation, recomposition is done after each produced frame, but whether measure, layout and draw happen is platform dependent. On Android, measure and layout will be done, but not draw. On Desktop, measure, layout and draw will happen. Frames are only produced if there is a need for them, e.g. when an animation is running, or if state is changed. See `https://developer.android.com/reference/kotlin/androidx/compose/ui/test/MainTestClock` for a more in depth explanation of the behavior of your test when controlling the clock.

It is recommended to set `https://developer.android.com/reference/kotlin/androidx/compose/ui/test/MainTestClock#autoAdvance()` to false when using this method, but it is not strictly necessary. Manually advancing the time is just as fast as automatic advancement and vice versa.

| Parameters |
|---|---|
| `milliseconds: https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-long/index.html` | The minimal duration to advance the main clock by. Will be rounded up to the nearest frame duration, unless `https://developer.android.com/reference/kotlin/androidx/compose/ui/test/MainTestClock#advanceTimeBy(kotlin.Long,kotlin.Boolean)` is `true`. |
| `ignoreFrameDuration: https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-boolean/index.html = false` | Whether to avoid rounding up the `https://developer.android.com/reference/kotlin/androidx/compose/ui/test/MainTestClock#advanceTimeBy(kotlin.Long,kotlin.Boolean)` to the nearest multiple of the frame duration. `false` by default. |

### advanceTimeByFrame

Cmn Added in [1.0.0](https://developer.android.com/jetpack/androidx/releases/compose-ui#1.0.0)

```
fun advanceTimeByFrame(): Unit
```

`https://developer.android.com/reference/kotlin/androidx/compose/ui/test/MainTestClock#advanceTimeBy(kotlin.Long,kotlin.Boolean)` the main clock by the duration of one frame.

### advanceTimeUntil

Cmn Added in [1.0.0](https://developer.android.com/jetpack/androidx/releases/compose-ui#1.0.0)

```
fun advanceTimeUntil(timeoutMillis: Long, condition: () -> Boolean): Unit
```

Advances the clock in increments of a `https://developer.android.com/reference/kotlin/androidx/compose/ui/test/MainTestClock#advanceTimeByFrame()` until the given `https://developer.android.com/reference/kotlin/androidx/compose/ui/test/MainTestClock#advanceTimeUntil(kotlin.Long,kotlin.Function0)` is satisfied.

Note that the condition should only rely on things that are driven by this clock. Depending on the platform, measure, layout or draw passes might not happen in between advancements of the clock while waiting for the condition to become true. On Android and Desktop, measure and layout are happening, but draw only happens on Desktop. If your condition relies on the result of draw, use androidx.compose.ui.test.junit4.ComposeTestRule.waitUntil instead.

See `https://developer.android.com/reference/kotlin/androidx/compose/ui/test/MainTestClock` for a thorough explanation of what is and what isn't going to happen as a result of a call to `advanceTimeBy`.

| Parameters |
|---|---|
| `timeoutMillis: https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-long/index.html` | The time after which this method throws an exception if the given condition is not satisfied. This is test clock time, not the wall clock or cpu time. |
| `condition: () -> https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-boolean/index.html` | A function returning true if the condition is satisfied and false if it is not. |

| Throws |
|---|---|
| `https://developer.android.com/reference/kotlin/androidx/compose/ui/test/ComposeTimeoutException` | the condition is not satisfied after `https://developer.android.com/reference/kotlin/androidx/compose/ui/test/MainTestClock#advanceTimeUntil(kotlin.Long,kotlin.Function0)`. |

## Public properties

### autoAdvance

Cmn Added in [1.0.0](https://developer.android.com/jetpack/androidx/releases/compose-ui#1.0.0)

```
var autoAdvance: Boolean
```

Whether the clock should be advanced by the testing framework while awaiting idleness in order to process any pending work that is driven by this clock. This ensures that when the app is androidx.compose.ui.test.junit4.ComposeTestRule.waitForIdle, there are no more pending recompositions or ongoing animations.

If `https://developer.android.com/reference/kotlin/androidx/compose/ui/test/MainTestClock#autoAdvance()` is false, the clock is not advanced while awaiting idleness. Moreover, having pending recompositions or animations is not taken as a sign of pending work (non-idleness) when awaiting idleness, as waiting for a longer time will not make them happen. Note that pending measure, layout or draw passes will still be awaited when awaiting idleness and having `https://developer.android.com/reference/kotlin/androidx/compose/ui/test/MainTestClock#autoAdvance()` set to false, as those passes are not driven by this clock.

By default this is true.

### currentTime

Cmn Added in [1.0.0](https://developer.android.com/jetpack/androidx/releases/compose-ui#1.0.0)

```
val currentTime: Long
```

The current time of this clock in milliseconds.

### scheduler

Cmn Added in [1.11.0](https://developer.android.com/jetpack/androidx/releases/compose-ui#1.11.0)

```
open val scheduler: TestCoroutineScheduler
```

The `https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-test/kotlinx.coroutines.test/-test-coroutine-scheduler/index.html` on which this clock is built. It drives the execution of coroutines within the composition and is used to dispatch coroutines inside the `https://developer.android.com/reference/kotlin/androidx/compose/runtime/Recomposer` and for `https://developer.android.com/reference/kotlin/androidx/compose/runtime/LaunchedEffect.composable#LaunchedEffect(kotlin.coroutines.SuspendFunction1)`s.

If the test was started with a custom `effectContext` containing a `https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-test/kotlinx.coroutines.test/-test-dispatcher/index.html`, this returns the scheduler from that dispatcher. Otherwise, an internally managed `https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-test/kotlinx.coroutines.test/-test-coroutine-scheduler/index.html` is created.