diff --git a/feature/home/impl/src/main/kotlin/com/dminus14/app/feature/home/HomeViewModel.kt b/feature/home/impl/src/main/kotlin/com/dminus14/app/feature/home/HomeViewModel.kt index b2ac1d7e..21eb484a 100644 --- a/feature/home/impl/src/main/kotlin/com/dminus14/app/feature/home/HomeViewModel.kt +++ b/feature/home/impl/src/main/kotlin/com/dminus14/app/feature/home/HomeViewModel.kt @@ -234,11 +234,20 @@ class HomeViewModel ?.map { it.toHomeReportItem() } .orEmpty() reduce { + // 리포트 상세 화면에 갔다가 홈으로 돌아오면 HomeScreen 의 LaunchedEffect(Unit) 이 + // 다시 실행돼 Load 가 재발행되고 이 함수도 다시 탄다. 최초 로드(this.reports 가 + // 비어 있음)에서만 첫 리포트를 기본으로 펼치고, 재조회부터는 사용자가 펼치고 접은 + // 상태를 그대로 유지한다(삭제되어 사라진 리포트 id만 걸러낸다). + val newReportIds = reports.mapTo(mutableSetOf()) { it.id } copy( isLoading = false, reports = reports, - // 첫 리포트만 기본으로 펼치고, 리포트가 없으면 빈 집합. - expandedReportIds = reports.firstOrNull()?.let { setOf(it.id) }.orEmpty(), + expandedReportIds = + if (this.reports.isEmpty()) { + reports.firstOrNull()?.let { setOf(it.id) }.orEmpty() + } else { + expandedReportIds intersect newReportIds + }, ) } } diff --git a/feature/home/impl/src/test/kotlin/com/dminus14/app/feature/home/HomeViewModelTest.kt b/feature/home/impl/src/test/kotlin/com/dminus14/app/feature/home/HomeViewModelTest.kt index f89cc786..1ad0ae23 100644 --- a/feature/home/impl/src/test/kotlin/com/dminus14/app/feature/home/HomeViewModelTest.kt +++ b/feature/home/impl/src/test/kotlin/com/dminus14/app/feature/home/HomeViewModelTest.kt @@ -133,6 +133,59 @@ class HomeViewModelTest { assertFalse(state.isLoading) } + @Test + fun `리포트 상세를 봤다가 홈으로 돌아와 Load가 재발행돼도 사용자가 펼친 카드 상태가 유지된다`() = + runViewModelTest { + val viewModel = + createViewModel( + interviewRepository = + FakeInterviewRepository( + reportListResult = + Result.success( + InterviewReportList( + reports = + listOf(reportItem(1L), reportItem(2L), reportItem(3L)), + ), + ), + ), + ) + + viewModel.onIntent(HomeIntent.Load) + advanceUntilIdle() + viewModel.onIntent(HomeIntent.ClickReportExpand("2")) + assertEquals(setOf("1", "2"), viewModel.state.value.expandedReportIds) + + // 리포트 상세로 이동했다가 뒤로가기로 홈에 재진입하면 HomeScreen의 + // LaunchedEffect(Unit)이 다시 실행돼 Load가 한 번 더 발행된다. + viewModel.onIntent(HomeIntent.Load) + advanceUntilIdle() + + assertEquals(setOf("1", "2"), viewModel.state.value.expandedReportIds) + } + + @Test + fun `재조회 사이 삭제된 리포트 id는 펼침 상태에서도 제거된다`() = + runViewModelTest { + val firstReports = + Result.success( + InterviewReportList(reports = listOf(reportItem(1L), reportItem(2L))), + ) + val fakeRepository = FakeInterviewRepository(reportListResult = firstReports) + val viewModel = createViewModel(interviewRepository = fakeRepository) + + viewModel.onIntent(HomeIntent.Load) + advanceUntilIdle() + viewModel.onIntent(HomeIntent.ClickReportExpand("2")) + assertEquals(setOf("1", "2"), viewModel.state.value.expandedReportIds) + + fakeRepository.reportListResult = + Result.success(InterviewReportList(reports = listOf(reportItem(1L)))) + viewModel.onIntent(HomeIntent.Load) + advanceUntilIdle() + + assertEquals(setOf("1"), viewModel.state.value.expandedReportIds) + } + @Test fun `리포트 조회가 실패해도 빈 목록으로 처리되고 Effect는 발행되지 않는다`() = runViewModelTest { @@ -1200,7 +1253,7 @@ class HomeViewModelTest { } private class FakeInterviewRepository( - private val reportListResult: Result = + var reportListResult: Result = Result.success(InterviewReportList(reports = emptyList())), private val resumeResult: Result? = null, private val abandonResult: Result? = null,