From 2f51e8142cdb65dac716b1f3ef874c41eba5e586 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Wed, 21 Oct 2026 18:35:03 +0000 Subject: [PATCH] test: add missing reactive-completion tests for task detail Closes #135 --- .../taskdetail/TaskDetailScreenTest.kt | 30 +++++++++++++++++++ .../taskdetail/TaskDetailViewModelTest.kt | 27 +++++++++++++++++ 2 files changed, 57 insertions(+) diff --git a/foliary/src/commonTest/kotlin/dev/appoutlet/foliary/feature/taskdetail/TaskDetailScreenTest.kt b/foliary/src/commonTest/kotlin/dev/appoutlet/foliary/feature/taskdetail/TaskDetailScreenTest.kt index 53944d3..af5e1fa 100644 --- a/foliary/src/commonTest/kotlin/dev/appoutlet/foliary/feature/taskdetail/TaskDetailScreenTest.kt +++ b/foliary/src/commonTest/kotlin/dev/appoutlet/foliary/feature/taskdetail/TaskDetailScreenTest.kt @@ -1,5 +1,8 @@ package dev.appoutlet.foliary.feature.taskdetail +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.setValue import androidx.compose.ui.test.ExperimentalTestApi import androidx.compose.ui.test.assertIsDisplayed import androidx.compose.ui.test.assertTextEquals @@ -283,4 +286,31 @@ class TaskDetailScreenTest { .assertDoesNotExist() event shouldBe null } + + @Test + fun `should toggle completion action when view data changes`() = runComposeUiTest { + val events = mutableListOf() + var viewData by mutableStateOf( + TaskDetailViewData.Loaded(TaskDetailViewData.Loaded.TaskViewData.fixture()) + ) + + setContent { TaskDetailScreen(viewData = viewData, onEvent = events::add) } + + onNodeWithTag("TaskDetailScreen:MarkAsComplete") + .assertIsDisplayed() + .performClick() + events shouldBe listOf(TaskDetailEvent.MarkCompletedClicked) + + viewData = TaskDetailViewData.Loaded( + viewData.task.copy(isComplete = true, completionDate = "21 Oct 2026") + ) + waitForIdle() + + onNodeWithTag("TaskDetailScreen:UnmarkAsComplete").assertIsDisplayed() + onNodeWithTag("TaskDetailScreen:MarkAsComplete").assertDoesNotExist() + onNodeWithTag("TaskDetailScreen:CompletionDate").assertIsDisplayed() + + onNodeWithTag("TaskDetailScreen:UnmarkAsComplete").performClick() + events.last() shouldBe TaskDetailEvent.MarkNotCompletedClicked + } } diff --git a/foliary/src/commonTest/kotlin/dev/appoutlet/foliary/feature/taskdetail/TaskDetailViewModelTest.kt b/foliary/src/commonTest/kotlin/dev/appoutlet/foliary/feature/taskdetail/TaskDetailViewModelTest.kt index 18ea3c6..9c52b7c 100644 --- a/foliary/src/commonTest/kotlin/dev/appoutlet/foliary/feature/taskdetail/TaskDetailViewModelTest.kt +++ b/foliary/src/commonTest/kotlin/dev/appoutlet/foliary/feature/taskdetail/TaskDetailViewModelTest.kt @@ -13,9 +13,11 @@ import dev.mokkery.mock import dev.mokkery.verify import dev.mokkery.verifySuspend import kotlinx.coroutines.delay +import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.flowOf import kotlin.test.Test import kotlin.time.Duration.Companion.milliseconds +import kotlin.time.Instant import kotlin.uuid.Uuid class TaskDetailViewModelTest : ViewModelTest() { @@ -91,6 +93,31 @@ class TaskDetailViewModelTest : ViewModelTest(incompleteTask) + + every { mockTaskRepository.observeById(taskId) } returns tasks + every { mockTaskViewDataMapper(incompleteTask) } returns incompleteViewData + every { mockTaskViewDataMapper(completedTask) } returns completedViewData + + test { + expectState(TaskDetailViewData.Loading) + expectState(TaskDetailViewData.Loaded(task = incompleteViewData)) + + tasks.value = completedTask + + expectState(TaskDetailViewData.Loaded(task = completedViewData)) + } + } + @Test fun `should mark task as completed when mark completed is clicked`() { val task = Task.fixture(id = taskId)