Skip to content

Add method awaitUntil(predicate: (item: T) -> Boolean): T#438

Open
fr-gonzalez-globant wants to merge 1 commit intocashapp:trunkfrom
fr-gonzalez-globant:trunk
Open

Add method awaitUntil(predicate: (item: T) -> Boolean): T#438
fr-gonzalez-globant wants to merge 1 commit intocashapp:trunkfrom
fr-gonzalez-globant:trunk

Conversation

@fr-gonzalez-globant
Copy link

Add method awaitUntil(predicate: (item: T) -> Boolean): T

Sometimes you just want to await for a certain item to emit when testing a flow but you don't know how many items to skip in order to catch that item.

flowOf(1, 2, 3).test {
  val item = awaitUntil { it == 3 }
  assertEquals(3, item)
  awaitComplete()
}

@JakeWharton
Copy link
Collaborator

We need to agree upon, document, and then test the timeout behavior. Unlike other functions, this can suspend forever so long as events are flowing. Is that what we want? Or should an overall timeout be enforced?

@fr-gonzalez-globant
Copy link
Author

fr-gonzalez-globant commented Feb 4, 2026

We need to agree upon, document, and then test the timeout behavior. Unlike other functions, this can suspend forever so long as events are flowing. Is that what we want? Or should an overall timeout be enforced?

I never thought of that scenario, but yes, it is possible to suspend forever with a continous flow that never matches the predicate. I tried modifying the function to receive a duration and use withAppropriateTimeout like:

// ReceiveTurbine.kt
public suspend fun awaitUntil(timeout: Duration = 3.seconds, predicate: (item: T) -> Boolean): T
// channel.kt
public suspend fun <T> ReceiveChannel<T>.awaitUntil(
  name: String? = null,
  timeout: Duration,
  predicate: (item: T) -> Boolean): T = withAppropriateTimeout(timeout) {
    //try to find and return the item
}

This makes this test pass:

@Test
fun awaitUntilThrowsOnTimeout() = runTest {
  var item = 0
  flow {
    while (true) {
      emit(item++)
      delay(1.seconds)
    }
  }.test {
    val message = assertFailsWith<TurbineTimeoutCancellationException> {
      awaitUntil { it < 0 }
    }.message
    assertEquals("Timed out waiting for 3s", message)
  }
}

But I don't know if this is the right way to tackle the problem or if this solution suits the way this library was designed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants