Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import androidx.compose.ui.test.waitUntilAtLeastOneExists
import androidx.lifecycle.SavedStateHandle
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.afternote.afternote_fe.test.FailureArtifactRule
import com.afternote.afternote_fe.test.FakeDailyQuestionRepository
import com.afternote.afternote_fe.test.FakeDiaryRepository
import com.afternote.afternote_fe.test.FakeUserRepository
import com.afternote.core.domain.repository.PhotoUploadRepository
Expand All @@ -22,6 +23,7 @@ import com.afternote.feature.mindrecord.domain.model.TodayMood
import com.afternote.feature.mindrecord.presentation.screen.sender.DiaryWriteScreen
import com.afternote.feature.mindrecord.presentation.viewmodel.DailyQuestionWriteViewModel
import com.afternote.feature.mindrecord.presentation.viewmodel.DiaryWriteViewModel
import com.afternote.feature.mindrecord.presentation.viewmodel.MindRecordDraftLoader
import com.afternote.feature.mindrecord.presentation.viewmodel.SubmitState
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
Expand Down Expand Up @@ -102,15 +104,14 @@ class MindRecordFlowAndroidTest {

@Test
fun dailyQuestion_failureThenRetry_keepsAnswerAndAvoidsDuplicateSuccess() {
val repository =
com.afternote.afternote_fe.test
.FakeDailyQuestionRepository()
val repository = FakeDailyQuestionRepository()
repository.createResults.addLast(Result.failure(IllegalStateException("offline")))
repository.createResults.addLast(Result.success(Unit))
repository.createResults.addLast(Result.success(1L))
val viewModel =
DailyQuestionWriteViewModel(
repository = repository,
photoUploadRepository = PhotoUploadRepository { _, _ -> Result.success("https://cdn.test/question.jpg") },
draftLoader = MindRecordDraftLoader(FakeDiaryRepository(), repository),
)
composeRule.setContent { AfternoteTheme {} }
composeRule.waitUntil(timeoutMillis = 5_000) { !viewModel.uiState.value.isQuestionLoading }
Expand Down Expand Up @@ -150,5 +151,6 @@ class MindRecordFlowAndroidTest {
repository = repository,
photoUploadRepository = PhotoUploadRepository { _, _ -> Result.success("https://cdn.test/image.jpg") },
userRepository = FakeUserRepository(),
draftLoader = MindRecordDraftLoader(repository, FakeDailyQuestionRepository()),
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ import com.afternote.feature.mindrecord.presentation.viewmodel.DiaryListUiState
import com.afternote.feature.mindrecord.presentation.viewmodel.DiaryListViewModel
import com.afternote.feature.mindrecord.presentation.viewmodel.DraftListUiState
import com.afternote.feature.mindrecord.presentation.viewmodel.DraftListViewModel
import com.afternote.feature.mindrecord.presentation.viewmodel.MindRecordDraftLoader
import com.afternote.feature.mindrecord.presentation.viewmodel.ReceiverMindRecordFilter
import com.afternote.feature.mindrecord.presentation.viewmodel.ReceiverMindRecordUiState
import com.afternote.feature.mindrecord.presentation.viewmodel.ReceiverMindRecordViewModel
Expand Down Expand Up @@ -149,7 +150,12 @@ class MindRecordLifecycleAndroidTest {
),
),
)
val viewModel = DraftListViewModel(diaryRepository, dailyQuestionRepository)
val viewModel =
DraftListViewModel(
loader = MindRecordDraftLoader(diaryRepository, dailyQuestionRepository),
diaryRepository = diaryRepository,
dailyQuestionRepository = dailyQuestionRepository,
)

composeRule.setContent {
AfternoteTheme {
Expand All @@ -174,7 +180,7 @@ class MindRecordLifecycleAndroidTest {
assertTrue(diaryRepository.deleteCalls.isEmpty())

composeRule.waitUntil(timeoutMillis = TIMEOUT) {
(viewModel.uiState.value as? DraftListUiState.Success)?.deleteCompleted == false
(viewModel.uiState.value as? DraftListUiState.Success)?.deleteOutcome == null
}
composeRule.onNodeWithText("선택").performClick()
composeRule.onNodeWithText("전체 삭제").performClick()
Expand Down Expand Up @@ -216,12 +222,14 @@ class MindRecordLifecycleAndroidTest {
diaryId = 301L,
day = wednesday.dayOfMonth,
isDiary = true,
countsAsRecord = true,
emotion = TodayMood.HAPPY,
),
WeeklyReportDay(
diaryId = 302L,
day = wednesday.dayOfMonth,
isDiary = false,
countsAsRecord = true,
emotion = null,
),
),
Expand All @@ -240,7 +248,7 @@ class MindRecordLifecycleAndroidTest {
val success = viewModel.uiState.value as WeeklyReportUiState.Success
assertEquals(7, success.weekDays.size)
assertEquals(DayOfWeek.entries.toList(), success.weekDays.map { it.dayOfWeek })
assertEquals(DayContent.EmojiWithDot("😊"), success.weekDays[2].content)
assertEquals(DayContent.EmojiOnly("😊"), success.weekDays[2].content)
assertEquals(DayBackground.Green, success.weekDays[2].background)
assertEquals(2, success.recordedDays)
assertEquals(emptyList<Any>(), success.emotionKeywords)
Expand Down Expand Up @@ -379,12 +387,12 @@ private class PrivateDailyQuestionRepository(

override suspend fun getToday(): Result<TodayDailyQuestion> = error("Unexpected today question load")

override suspend fun create(payload: DailyQuestionCreatePayload): Result<Unit> = error("Unexpected question create")
override suspend fun create(payload: DailyQuestionCreatePayload): Result<Long> = error("Unexpected question create")

override suspend fun update(
id: Long,
payload: DailyQuestionUpdatePayload,
): Result<Unit> = error("Unexpected question update")
): Result<Long> = error("Unexpected question update")

override suspend fun delete(id: Long): Result<Unit> {
deleteCalls += id
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,9 @@ import com.afternote.feature.mindrecord.presentation.viewmodel.DailyQuestionList
import com.afternote.feature.mindrecord.presentation.viewmodel.DailyQuestionWriteViewModel
import com.afternote.feature.mindrecord.presentation.viewmodel.DiaryWriteViewModel
import com.afternote.feature.mindrecord.presentation.viewmodel.DraftListViewModel
import com.afternote.feature.mindrecord.presentation.viewmodel.MemorySpaceUiState
import com.afternote.feature.mindrecord.presentation.viewmodel.MemorySpaceViewModel
import com.afternote.feature.mindrecord.presentation.viewmodel.MindRecordDraftLoader
import com.afternote.feature.mindrecord.presentation.viewmodel.SubmitState
import com.afternote.feature.mindrecord.presentation.viewmodel.WeeklyReportUiState
import com.afternote.feature.mindrecord.presentation.viewmodel.WeeklyReportViewModel
Expand Down Expand Up @@ -414,6 +416,7 @@ class TimeLetterMindRecordCompletionAndroidTest {
DailyQuestionWriteViewModel(
repository = repository,
photoUploadRepository = CompletionPhotoUploadRepository,
draftLoader = MindRecordDraftLoader(CompletionDiaryRepository(mutableListOf()), repository),
)
}
composeRule.waitUntil(timeoutMillis = TIMEOUT) {
Expand Down Expand Up @@ -458,10 +461,12 @@ class TimeLetterMindRecordCompletionAndroidTest {
),
),
)
val draftDailyQuestionRepository = CompletionDailyQuestionRepository()
val draftListViewModel =
DraftListViewModel(
loader = MindRecordDraftLoader(repository, draftDailyQuestionRepository),
diaryRepository = repository,
dailyQuestionRepository = CompletionDailyQuestionRepository(),
dailyQuestionRepository = draftDailyQuestionRepository,
)
var routedArguments: Pair<Long, String>? = null
var writeViewModel by mutableStateOf<DiaryWriteViewModel?>(null)
Expand All @@ -487,6 +492,8 @@ class TimeLetterMindRecordCompletionAndroidTest {
repository = repository,
photoUploadRepository = CompletionPhotoUploadRepository,
userRepository = FakeUserRepository(),
draftLoader =
MindRecordDraftLoader(repository, draftDailyQuestionRepository),
)
},
)
Expand Down Expand Up @@ -534,7 +541,24 @@ class TimeLetterMindRecordCompletionAndroidTest {

@Test
fun memorySpace_supportedSuccess_opensAndClosesDetailThenNavigatesBack() {
val viewModel = MemorySpaceViewModel()
val memoryDate = LocalDate.now()
val diaryRepository =
CompletionDiaryRepository(
drafts =
mutableListOf(
Diary(
diaryId = 501L,
title = "추억이 된 하루",
content = "이 순간은 나에게 특별한 의미가 있었습니다.",
date = memoryDate.toString(),
createdAt = memoryDate.toString(),
todayMood = TodayMood.HAPPY,
imageUrl = "https://afternote.test/memory.jpg",
isDraft = false,
),
),
)
val viewModel = MemorySpaceViewModel(diaryRepository, CompletionDailyQuestionRepository())
var backCalls = 0

composeRule.setContent {
Expand All @@ -547,11 +571,15 @@ class TimeLetterMindRecordCompletionAndroidTest {
}

composeRule.onNodeWithText("MEMORY SPACE").assertIsDisplayed()
composeRule.onNodeWithContentDescription("기억 1").performClick()
composeRule.waitUntil(timeoutMillis = TIMEOUT) {
viewModel.uiState.value is MemorySpaceUiState.Success
}
composeRule.onNodeWithContentDescription("추억이 된 하루").performClick()
composeRule
.onNodeWithText("이 순간은 나에게 특별한 의미가 있었습니다.", substring = true)
.assertIsDisplayed()
composeRule.onNodeWithText("#평온").assertIsDisplayed()
// 태그는 사용자가 고른 오늘의 기분 이모지다 — 종전 더미의 `#평온` 은 출처가 없었다 (#559).
composeRule.onNodeWithText("#😊").assertIsDisplayed()
composeRule.onNodeWithContentDescription("닫기").performClick()
composeRule
.onNodeWithText("이 순간은 나에게 특별한 의미가 있었습니다.", substring = true)
Expand Down Expand Up @@ -763,25 +791,26 @@ private class CompletionDailyQuestionRepository(
return Result.success(today)
}

override suspend fun create(payload: DailyQuestionCreatePayload): Result<Unit> {
override suspend fun create(payload: DailyQuestionCreatePayload): Result<Long> {
createCalls += payload
val createdId = 800L + createCalls.size
storedAnswers +=
DailyQuestion(
dailyQuestionId = 800L + createCalls.size,
dailyQuestionId = createdId,
title = today.content,
content = payload.content,
createdAt = "2026-08-22",
imageUrl = payload.imageUrl,
isDraft = payload.isDraft,
)
today = today.copy(isAnswered = !payload.isDraft, isDraft = payload.isDraft)
return Result.success(Unit)
return Result.success(createdId)
}

override suspend fun update(
id: Long,
payload: DailyQuestionUpdatePayload,
): Result<Unit> {
): Result<Long> {
updateCalls += id to payload
storedAnswers.replaceAll { answer ->
if (answer.dailyQuestionId == id) {
Expand All @@ -794,7 +823,7 @@ private class CompletionDailyQuestionRepository(
answer
}
}
return Result.success(Unit)
return Result.success(id)
}

override suspend fun delete(id: Long): Result<Unit> {
Expand Down Expand Up @@ -931,6 +960,7 @@ private fun completeWeeklyReport(monday: LocalDate): WeeklyReport =
diaryId = 91L,
day = monday.dayOfMonth,
isDiary = true,
countsAsRecord = true,
emotion = TodayMood.HAPPY,
),
),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,7 @@ class FakeDailyQuestionRepository(
Result.success(TodayDailyQuestion(1L, 1, "오늘의 질문", false)),
) : DailyQuestionRepository {
val createdPayloads = mutableListOf<DailyQuestionCreatePayload>()
val createResults = ArrayDeque<Result<Unit>>()
val createResults = ArrayDeque<Result<Long>>()

override suspend fun getList(
date: String?,
Expand All @@ -271,17 +271,22 @@ class FakeDailyQuestionRepository(

override suspend fun getToday(): Result<TodayDailyQuestion> = todayResult

override suspend fun create(payload: DailyQuestionCreatePayload): Result<Unit> {
override suspend fun create(payload: DailyQuestionCreatePayload): Result<Long> {
createdPayloads += payload
return createResults.removeFirstOrNull() ?: Result.success(Unit)
return createResults.removeFirstOrNull() ?: Result.success(CREATED_DAILY_QUESTION_ID)
}

override suspend fun update(
id: Long,
payload: DailyQuestionUpdatePayload,
): Result<Unit> = Result.success(Unit)
): Result<Long> = Result.success(id)

override suspend fun delete(id: Long): Result<Unit> = Result.success(Unit)

private companion object {
/** 서버가 돌려주는 `userDailyQuestionId` 자리 (#573). 값 자체에 의미는 없다. */
const val CREATED_DAILY_QUESTION_ID = 1L
}
}

class FakeErrorReporter : ErrorReporter {
Expand Down
Loading