Skip to content

Recipe: Test a presenter that shows an overlay

Problem: your presenter shows an overlay (a confirm dialog, a picker) and acts on the result. You want to test that logic without standing up real overlay UI.

Do not drive a real OverlayHost in a unit test. If you model the overlay as nullable state, then “is the overlay requested?” and “what happens with each result?” are just plain state-and-event assertions like any other presenter test.

@Test
fun `delete asks for confirmation, then deletes on confirm`() = runTest {
  val repository = FakeItemRepository(items = listOf(item1))
  val presenter = ItemPresenter(ItemScreen(item1.id), FakeNavigator(ItemScreen(item1.id)), repository)

  presenter.test {
    val loaded = assertIs<ItemState.Loaded>(awaitItem())
    assertNull(loaded.pendingDelete)                 // no dialog yet

    loaded.eventSink(ItemEvent.DeleteClicked(item1.id))

    // The presenter now requests the dialog by exposing pendingDelete.
    val confirming = assertIs<ItemState.Loaded>(awaitItem())
    assertEquals(item1.id, confirming.pendingDelete)

    // Simulate the user confirming — the same event the OverlayEffect would send.
    confirming.eventSink(ItemEvent.DeleteAnswered(item1.id, confirmed = true))

    assertTrue(repository.wasDeleted(item1.id))
  }
}

@Test
fun `dismissing the confirmation deletes nothing`() = runTest {
  val repository = FakeItemRepository(items = listOf(item1))
  val presenter = ItemPresenter(ItemScreen(item1.id), FakeNavigator(ItemScreen(item1.id)), repository)

  presenter.test {
    val loaded = assertIs<ItemState.Loaded>(awaitItem())
    loaded.eventSink(ItemEvent.DeleteClicked(item1.id))
    awaitItem()   // pendingDelete set

    loaded.eventSink(ItemEvent.DeleteAnswered(item1.id, confirmed = false))
    assertFalse(repository.wasDeleted(item1.id))
  }
}

Because the overlay result re-enters the presenter as an event (DeleteAnswered(confirmed = …)), you can cover the confirm and dismiss paths without real overlay UI. Render the actual overlay in previews or snapshot tests.

See also: Ask for confirmation with a dialog · Test a presenter that navigates