From f4214946746b6295d2747390c5b11babbeda6890 Mon Sep 17 00:00:00 2001 From: opficdev Date: Fri, 25 Sep 2026 15:22:37 +0900 Subject: [PATCH 1/4] =?UTF-8?q?refactor:=20TodayView=20=ED=83=90=EC=83=89?= =?UTF-8?q?=20=EA=B2=BD=EB=A1=9C=20=EC=86=8C=EC=9C=A0=EA=B6=8C=20=EC=A0=95?= =?UTF-8?q?=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Application/Presentation/TodayTab/Sources/TodayView.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Application/Presentation/TodayTab/Sources/TodayView.swift b/Application/Presentation/TodayTab/Sources/TodayView.swift index 3a1f5b63..a24d1fe8 100644 --- a/Application/Presentation/TodayTab/Sources/TodayView.swift +++ b/Application/Presentation/TodayTab/Sources/TodayView.swift @@ -12,7 +12,7 @@ import PresentationShared public struct TodayView: View { @Environment(\.scenePhase) private var scenePhase - @State private var path = [TodayRoute]() + @State private var router = NavigationRouter() @State private var store: StoreOf private let isSelected: Bool private let windowEvent: TodoEditorWindowEvent @@ -31,7 +31,7 @@ public struct TodayView: View { } public var body: some View { - NavigationStack(path: $path) { + NavigationStack(path: $router.path) { ScrollView { let sections = store.sections LazyVStack(alignment: .leading, spacing: 0) { @@ -45,7 +45,7 @@ public struct TodayView: View { TodoSection( section: section, isNavigationEnabled: !store.isTodoInspectorPresented, - onSelect: { path.append(.todo(TodoIdItem(id: $0.id))) }, + onSelect: { router.push(.todo(TodoIdItem(id: $0.id))) }, onInspect: { store.send(.showTodoInspector($0)) } ) .padding(.bottom, section.id == sections.last?.id ? 0 : 8) From 79fe9258b0844f9c361136464ed429b05ba55c2c Mon Sep 17 00:00:00 2001 From: opficdev Date: Fri, 25 Sep 2026 15:24:11 +0900 Subject: [PATCH 2/4] =?UTF-8?q?refactor:=20HomeView=20=EC=83=81=ED=83=9C?= =?UTF-8?q?=20=EC=86=8C=EC=9C=A0=EA=B6=8C=20=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Sources/Home/DevelopmentGoalSection.swift | 14 -------- .../HomeTab/Sources/Home/HomeFeature.swift | 25 ++++++++++++- .../HomeTab/Sources/Home/HomeView.swift | 35 ++++++++----------- .../Tests/Home/HomeFeatureTestSupport.swift | 14 ++++++++ .../HomeTab/Tests/Home/HomeFeatureTests.swift | 17 +++++++++ 5 files changed, 70 insertions(+), 35 deletions(-) diff --git a/Application/Presentation/HomeTab/Sources/Home/DevelopmentGoalSection.swift b/Application/Presentation/HomeTab/Sources/Home/DevelopmentGoalSection.swift index 11a7f6f9..78e3794c 100644 --- a/Application/Presentation/HomeTab/Sources/Home/DevelopmentGoalSection.swift +++ b/Application/Presentation/HomeTab/Sources/Home/DevelopmentGoalSection.swift @@ -225,17 +225,3 @@ private struct DevelopmentGoalStatusBadge: View { .background(Color.accent.opacity(0.1), in: .capsule) } } - -enum GoalPresentation: Identifiable { - case create - case detail(String) - - var id: String { - switch self { - case .create: - "create" - case .detail(let goalID): - goalID - } - } -} diff --git a/Application/Presentation/HomeTab/Sources/Home/HomeFeature.swift b/Application/Presentation/HomeTab/Sources/Home/HomeFeature.swift index 8682a9fa..072fb4d0 100644 --- a/Application/Presentation/HomeTab/Sources/Home/HomeFeature.swift +++ b/Application/Presentation/HomeTab/Sources/Home/HomeFeature.swift @@ -59,6 +59,8 @@ struct HomeFeature { case startObserving case fetchData case todoEditorCreated + case tapCreateDevelopmentGoal + case tapDevelopmentGoal(String) case tapManageTodoCategory case tapTodoCategoryExpansionButton case tapTodoCategory(TodoCategory) @@ -80,6 +82,8 @@ struct HomeFeature { enum SheetState: Equatable { case reorderTodo(CategoryManageFeature.State) case contentPicker + case goalCreate + case goalDetail(String) var categoryManageState: CategoryManageFeature.State? { get { @@ -91,6 +95,15 @@ struct HomeFeature { self = .reorderTodo(newValue) } } + + var isDevelopmentGoalPresentation: Bool { + switch self { + case .goalCreate, .goalDetail: + true + case .reorderTodo, .contentPicker: + false + } + } } @CasePathable @@ -170,7 +183,13 @@ struct HomeFeature { state.selectedTodoCategory = nil case .fullScreenCover: break - case .sheet(.dismiss), .sheet(.presented(.tapCloseButton)): + case .sheet(.dismiss): + let refreshesDevelopmentGoals = state.sheet?.isDevelopmentGoalPresentation == true + state.sheet = nil + if refreshesDevelopmentGoals { + return .send(.view(.fetchData)) + } + case .sheet(.presented(.tapCloseButton)): state.sheet = nil case .sheet(.presented(.categoryManage(.delegate(.done(let preferences))))): return orderTodoCategory(preferences, state: &state) @@ -230,6 +249,10 @@ private extension HomeFeature { trackTodoCreateEffect(), .send(.view(.fetchData)) ) + case .tapCreateDevelopmentGoal: + state.sheet = .goalCreate + case .tapDevelopmentGoal(let goalID): + state.sheet = .goalDetail(goalID) case .tapManageTodoCategory: state.sheet = .reorderTodo(CategoryManageFeature.State(preferences: state.preferences)) case .tapTodoCategoryExpansionButton: diff --git a/Application/Presentation/HomeTab/Sources/Home/HomeView.swift b/Application/Presentation/HomeTab/Sources/Home/HomeView.swift index 082e9c2d..f38fbbc9 100644 --- a/Application/Presentation/HomeTab/Sources/Home/HomeView.swift +++ b/Application/Presentation/HomeTab/Sources/Home/HomeView.swift @@ -17,8 +17,7 @@ public struct HomeView: View { @Environment(\.isiOSAppOnMac) private var isiOSAppOnMac @ScaledMetric(relativeTo: .largeTitle) private var labelWidth = CGFloat(34) @ScaledMetric(relativeTo: .title2) private var categoryIconSize = CGFloat(64) - @State private var path = [HomeRoute]() - @State private var goalPresentation: GoalPresentation? + @State private var router = NavigationRouter() @State private var searchStore: StoreOf @State private var store: StoreOf private let isSelected: Bool @@ -44,7 +43,7 @@ public struct HomeView: View { } public var body: some View { - NavigationStack(path: $path) { + NavigationStack(path: $router.path) { ScrollView { LazyVStack(alignment: .leading, spacing: 16) { DevelopmentSummaryCard( @@ -59,8 +58,8 @@ public struct HomeView: View { isLoading: store.isDevelopmentGoalsLoading, hasLoaded: store.hasDevelopmentGoalsLoaded, hasLoadFailure: store.hasDevelopmentGoalsLoadFailure, - onCreate: { goalPresentation = .create }, - onSelect: { goalPresentation = .detail($0.id) }, + onCreate: { store.send(.view(.tapCreateDevelopmentGoal)) }, + onSelect: { store.send(.view(.tapDevelopmentGoal($0.id))) }, onRetry: { store.send(.view(.fetchData)) } ) } @@ -88,14 +87,6 @@ public struct HomeView: View { .activePresentation(when: isSelected), content: sheetContent ) - .sheet(item: $goalPresentation, onDismiss: refreshDevelopmentGoals) { presentation in - switch presentation { - case .create: - GoalCreateView() - case .detail(let goalID): - GoalDetailView(goalId: goalID) - } - } .fullScreenCover( item: $store.scope(state: \.fullScreenCover, action: \.fullScreenCover) .activePresentation(when: isSelected), @@ -251,7 +242,8 @@ public struct HomeView: View { @ViewBuilder private func sheetContent(_ sheetStore: Store) -> some View { - if case .contentPicker = sheetStore.state { + switch sheetStore.state { + case .contentPicker: NavigationStack { List { Section { @@ -291,8 +283,14 @@ public struct HomeView: View { } } } - } else if let store = sheetStore.scope(state: \.categoryManageState, action: \.categoryManage) { - CategoryManageView(store: store) + case .reorderTodo: + if let store = sheetStore.scope(state: \.categoryManageState, action: \.categoryManage) { + CategoryManageView(store: store) + } + case .goalCreate: + GoalCreateView() + case .goalDetail(let goalID): + GoalDetailView(goalId: goalID) } } @@ -319,7 +317,7 @@ public struct HomeView: View { TodoListFeature() }, windowEvent: windowEvent, - onSelectTodo: { path.append(.todo(TodoIdItem(id: $0))) } + onSelectTodo: { router.push(.todo(TodoIdItem(id: $0))) } ) .id(item.id) case .todo(let item): @@ -390,9 +388,6 @@ public struct HomeView: View { store.send(.view(.tapTodoCategory(todoCategory))) } } - private func refreshDevelopmentGoals() { - store.send(.view(.fetchData)) - } } public enum HomeRoute: Hashable { diff --git a/Application/Presentation/HomeTab/Tests/Home/HomeFeatureTestSupport.swift b/Application/Presentation/HomeTab/Tests/Home/HomeFeatureTestSupport.swift index cf2135dc..c8491cd3 100644 --- a/Application/Presentation/HomeTab/Tests/Home/HomeFeatureTestSupport.swift +++ b/Application/Presentation/HomeTab/Tests/Home/HomeFeatureTestSupport.swift @@ -29,6 +29,7 @@ struct StoreTestAdapter { store.state.sheet?.categoryManageState != nil } var showTodoEditor: Bool { store.state.showTodoEditor } + var sheet: HomeFeature.SheetState? { store.state.sheet } init( fetchPreferencesUseCase: FetchTodoCategoryPreferencesUseCase = FetchTodoCategoryPreferencesUseCaseSpy(), @@ -91,6 +92,19 @@ struct StoreTestAdapter { await drainReceivedActions() } + func tapCreateDevelopmentGoal() async { + await store.send(.view(.tapCreateDevelopmentGoal)) + } + + func tapDevelopmentGoal(_ goalID: String) async { + await store.send(.view(.tapDevelopmentGoal(goalID))) + } + + func dismissSheet() async { + await store.send(.sheet(.dismiss)) + await drainReceivedActions() + } + func tapTodoCategoryExpansionButton() async { await store.send(.view(.tapTodoCategoryExpansionButton)) } diff --git a/Application/Presentation/HomeTab/Tests/Home/HomeFeatureTests.swift b/Application/Presentation/HomeTab/Tests/Home/HomeFeatureTests.swift index 73ec662f..d83185b2 100644 --- a/Application/Presentation/HomeTab/Tests/Home/HomeFeatureTests.swift +++ b/Application/Presentation/HomeTab/Tests/Home/HomeFeatureTests.swift @@ -139,6 +139,23 @@ struct HomeFeatureTests { #expect(adapter.isTodoCategoryExpanded) } + @Test("개발 목표 생성과 상세 선택은 Feature sheet 상태를 전환한다") + func 개발_목표_생성과_상세_선택은_Feature_sheet_상태를_전환한다() async { + let adapter = StoreTestAdapter() + + await adapter.tapCreateDevelopmentGoal() + + #expect(adapter.sheet == .goalCreate) + + await adapter.dismissSheet() + + #expect(adapter.sheet == nil) + + await adapter.tapDevelopmentGoal("goal") + + #expect(adapter.sheet == .goalDetail("goal")) + } + @Test("TodoEditor 생성 delegate는 editor를 닫고 홈 데이터를 다시 조회한다") func TodoEditor_생성_delegate는_editor를_닫고_홈_데이터를_다시_조회한다() async throws { let context = makeHomeFetchDataContext() From 1c465f0a09e4cf557e2bdf48e0b133ceaa6f1678 Mon Sep 17 00:00:00 2001 From: opficdev Date: Fri, 25 Sep 2026 15:24:39 +0900 Subject: [PATCH 3/4] =?UTF-8?q?refactor:=20ProfileView=20=ED=83=90?= =?UTF-8?q?=EC=83=89=20=EA=B2=BD=EB=A1=9C=20=EC=86=8C=EC=9C=A0=EA=B6=8C=20?= =?UTF-8?q?=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ProfileTab/Sources/Profile/ProfileView.swift | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Application/Presentation/ProfileTab/Sources/Profile/ProfileView.swift b/Application/Presentation/ProfileTab/Sources/Profile/ProfileView.swift index 4387af8c..4481f055 100644 --- a/Application/Presentation/ProfileTab/Sources/Profile/ProfileView.swift +++ b/Application/Presentation/ProfileTab/Sources/Profile/ProfileView.swift @@ -13,7 +13,7 @@ import PresentationShared public struct ProfileView: View { @State private var settingsStore: StoreOf @State private var store: StoreOf - @State private var path = [ProfileRoute]() + @State private var router = NavigationRouter() private let isSelected: Bool private let windowEvent: TodoEditorWindowEvent @@ -34,12 +34,12 @@ public struct ProfileView: View { } public var body: some View { - NavigationStack(path: $path) { + NavigationStack(path: $router.path) { ScrollView { LazyVStack(alignment: .leading, spacing: 16) { UserInfoCard(store: store, isSelected: isSelected) ActivityCard(store: store) { todoId in - path.append(.activity(todoId)) + router.push(.activity(todoId)) } GoalSummaryCard( goals: store.developmentGoals, @@ -49,7 +49,7 @@ public struct ProfileView: View { onRetry: { store.send(.retryDevelopmentGoals) } ) RecentActivityCard(store: store) { todoId in - path.append(.recentTodo(todoId)) + router.push(.recentTodo(todoId)) } } .padding(.horizontal, 16) @@ -97,7 +97,7 @@ public struct ProfileView: View { .font(.largeTitle.bold()) Spacer() Button { - path.append(.settings) + router.push(.settings) } label: { Image(systemName: "gearshape") } @@ -114,7 +114,7 @@ public struct ProfileView: View { private func destinationView(_ route: ProfileRoute) -> some View { switch route { case .settings: - SettingsView(store: settingsStore) { path.append($0) } + SettingsView(store: settingsStore) { router.push($0) } case .activity(let todoId): TodoDetailView(store: Store( initialState: TodoDetailFeature.State(todoId: todoId, showEditButton: false) From c5a2c590b305c0c03af48bf10211983894b6ef05 Mon Sep 17 00:00:00 2001 From: opficdev Date: Fri, 25 Sep 2026 15:30:12 +0900 Subject: [PATCH 4/4] =?UTF-8?q?refactor:=20RecordDetail=20=ED=91=9C?= =?UTF-8?q?=EC=8B=9C=20=EC=83=81=ED=83=9C=20=EC=86=8C=EC=9C=A0=EA=B6=8C=20?= =?UTF-8?q?=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Record/Detail/RecordDetailFeature.swift | 56 +++++++++++++++++++ .../Record/Detail/RecordDetailView.swift | 16 +++--- .../History/RecordVersionHistoryView.swift | 15 ++--- .../Record/RecordDetailFeatureTests.swift | 33 +++++++++++ 4 files changed, 103 insertions(+), 17 deletions(-) diff --git a/Application/Presentation/Development/Sources/Record/Detail/RecordDetailFeature.swift b/Application/Presentation/Development/Sources/Record/Detail/RecordDetailFeature.swift index 75eb028d..390e9339 100644 --- a/Application/Presentation/Development/Sources/Record/Detail/RecordDetailFeature.swift +++ b/Application/Presentation/Development/Sources/Record/Detail/RecordDetailFeature.swift @@ -13,6 +13,9 @@ struct RecordDetailFeature { @ObservableState struct State: Equatable { @Presents var alert: AlertState? + @Presents var sheet: SheetState? + @Presents var history: RecordHistoryDestination? + @Presents var versionDetail: RecordVersionDetailDestination? let goalTitle: String let allowsMutation: Bool var record: DevelopmentRecord @@ -63,6 +66,9 @@ struct RecordDetailFeature { enum Action: Equatable { case alert(PresentationAction) + case sheet(PresentationAction) + case history(PresentationAction) + case versionDetail(PresentationAction) case view(ViewAction) case store(StoreAction) @@ -72,7 +78,11 @@ struct RecordDetailFeature { enum ViewAction: Equatable { case fetch + case finishEditing case restore(DevelopmentRecord.Version) + case selectVersion(DevelopmentRecord.Version) + case tapCorrection + case tapHistory } enum StoreAction: Equatable { @@ -83,6 +93,11 @@ struct RecordDetailFeature { } } + @ObservableState + enum SheetState: Equatable { + case editor + } + @Dependency(\.developmentFetchRecordsUseCase) private var fetchRecordsUseCase @Dependency(\.developmentFetchRecordHistoryUseCase) private var fetchRecordHistoryUseCase @Dependency(\.developmentRestoreRecordUseCase) private var restoreRecordUseCase @@ -114,6 +129,19 @@ struct RecordDetailFeature { ) case .alert: break + case .sheet(.dismiss): + state.sheet = nil + case .sheet: + break + case .history(.dismiss): + state.history = nil + state.versionDetail = nil + case .history: + break + case .versionDetail(.dismiss): + state.versionDetail = nil + case .versionDetail: + break case .view(.fetch): guard state.contentState != .loading, !state.isRestoring, @@ -122,12 +150,28 @@ struct RecordDetailFeature { state.contentState = .loading state.restoredSourceVersionID = nil return fetchEffect(goalID: state.record.goalId, recordID: state.record.id) + case .view(.finishEditing): + state.sheet = nil + return .send(.view(.fetch)) case .view(.restore(let version)): guard !state.isRestoring, state.allowsMutation, state.record.draft == nil, version.id != state.currentVersionID else { break } state.alert = Self.restoreConfirmationAlert(version) + case .view(.selectVersion(let version)): + guard version.id != state.currentVersionID, + state.versions.contains(where: { $0.id == version.id }) else { break } + state.versionDetail = RecordVersionDetailDestination(version: version) + case .view(.tapCorrection): + guard state.allowsMutation, + state.contentState == .loaded, + state.currentVersion != nil else { break } + state.sheet = .editor + case .view(.tapHistory): + guard state.contentState == .loaded, + state.currentVersion != nil else { break } + state.history = RecordHistoryDestination(recordID: state.record.id) case .store(.loaded(let record, let versions)): state.record = record state.versions = versions.sorted { $0.number < $1.number } @@ -158,6 +202,18 @@ struct RecordDetailFeature { } } +@ObservableState +struct RecordHistoryDestination: Equatable, Identifiable { + let recordID: String + var id: String { recordID } +} + +@ObservableState +struct RecordVersionDetailDestination: Equatable, Identifiable { + let version: DevelopmentRecord.Version + var id: String { version.id } +} + private extension RecordDetailFeature { func fetchEffect(goalID: String, recordID: String) -> Effect { .run { [fetchRecordsUseCase, fetchRecordHistoryUseCase] send in diff --git a/Application/Presentation/Development/Sources/Record/Detail/RecordDetailView.swift b/Application/Presentation/Development/Sources/Record/Detail/RecordDetailView.swift index 8bfb3706..72345461 100644 --- a/Application/Presentation/Development/Sources/Record/Detail/RecordDetailView.swift +++ b/Application/Presentation/Development/Sources/Record/Detail/RecordDetailView.swift @@ -13,8 +13,6 @@ public struct RecordDetailView: View { @Environment(\.dismiss) private var dismiss private let onUpdate: () -> Void @State private var store: StoreOf - @State private var isEditorPresented = false - @State private var isHistoryPresented = false public init( goalTitle: String, @@ -70,7 +68,7 @@ public struct RecordDetailView: View { .toolbarVisibility(.hidden, for: .navigationBar) .onAppear { store.send(.view(.fetch)) } .prominentAlert(store, state: \.alert, action: \.alert) - .sheet(isPresented: $isEditorPresented) { + .sheet(item: $store.scope(state: \.sheet, action: \.sheet)) { _ in RecordEditorView( goalId: store.record.goalId, goalTitle: store.goalTitle, @@ -79,7 +77,10 @@ public struct RecordDetailView: View { onCompletion: finishEditing ) } - .navigationDestination(isPresented: $isHistoryPresented, interactivePop: true) { + .navigationDestination( + item: $store.scope(state: \.history, action: \.history), + interactivePop: true + ) { _ in RecordVersionHistoryView(store: store) } .overlay { @@ -212,7 +213,7 @@ public struct RecordDetailView: View { private var correctionButton: some View { Button { - isEditorPresented = true + store.send(.view(.tapCorrection)) } label: { Label( RecordPresentation.text("development_record_correct"), @@ -228,7 +229,7 @@ public struct RecordDetailView: View { private var historyButton: some View { Button { - isHistoryPresented = true + store.send(.view(.tapHistory)) } label: { Label( RecordPresentation.text("development_record_history_title"), @@ -246,8 +247,7 @@ public struct RecordDetailView: View { } private func finishEditing() { - isEditorPresented = false - store.send(.view(.fetch)) + store.send(.view(.finishEditing)) onUpdate() } } diff --git a/Application/Presentation/Development/Sources/Record/History/RecordVersionHistoryView.swift b/Application/Presentation/Development/Sources/Record/History/RecordVersionHistoryView.swift index 8774b402..d7e3a874 100644 --- a/Application/Presentation/Development/Sources/Record/History/RecordVersionHistoryView.swift +++ b/Application/Presentation/Development/Sources/Record/History/RecordVersionHistoryView.swift @@ -11,9 +11,8 @@ import PresentationShared struct RecordVersionHistoryView: View { @Environment(\.dismiss) private var dismiss - @State private var destination: VersionDestination? - let store: StoreOf + @Bindable var store: StoreOf private var sortedVersions: [DevelopmentRecord.Version] { store.versions.sorted { $1.number < $0.number } @@ -37,7 +36,10 @@ struct RecordVersionHistoryView: View { .safeAreaInset(edge: .bottom, spacing: 0) { footer } .background(Color.appBackground) .toolbarVisibility(.hidden, for: .navigationBar) - .navigationDestination(item: $destination, interactivePop: true) { destination in + .navigationDestination( + item: $store.scope(state: \.versionDetail, action: \.versionDetail), + interactivePop: true + ) { destination in RecordVersionDetailView( store: store, version: destination.version @@ -106,7 +108,7 @@ struct RecordVersionHistoryView: View { if version.id == store.currentVersionID { dismiss() } else { - destination = VersionDestination(version: version) + store.send(.view(.selectVersion(version))) } } label: { VersionHistoryRow( @@ -263,8 +265,3 @@ struct RecordVersionBadge: View { ) } } - -private struct VersionDestination: Identifiable { - let version: DevelopmentRecord.Version - var id: String { version.id } -} diff --git a/Application/Presentation/Development/Tests/Record/RecordDetailFeatureTests.swift b/Application/Presentation/Development/Tests/Record/RecordDetailFeatureTests.swift index 3a0ce762..946c1372 100644 --- a/Application/Presentation/Development/Tests/Record/RecordDetailFeatureTests.swift +++ b/Application/Presentation/Development/Tests/Record/RecordDetailFeatureTests.swift @@ -12,6 +12,39 @@ import PresentationShared @MainActor struct RecordDetailFeatureTests { + @Test("편집과 이력 화면 표시는 Feature 상태를 전환한다") + func 편집과_이력_화면_표시는_Feature_상태를_전환한다() async throws { + let currentVersion = try makeDevelopmentRecordVersion(id: "version-2", number: 2) + let previousVersion = try makeDevelopmentRecordVersion(id: "version-1") + let record = try makeConfirmedDevelopmentRecord( + versionId: currentVersion.id, + versionNumber: currentVersion.number + ) + var state = RecordDetailFeature.State(goalTitle: "개발 목표", record: record) + state.versions = [previousVersion, currentVersion] + state.contentState = .loaded + let store = TestStore(initialState: state) { + RecordDetailFeature() + } + + await store.send(.view(.tapCorrection)) { + $0.sheet = .editor + } + await store.send(.sheet(.dismiss)) { + $0.sheet = nil + } + await store.send(.view(.tapHistory)) { + $0.history = RecordHistoryDestination(recordID: record.id) + } + await store.send(.view(.selectVersion(previousVersion))) { + $0.versionDetail = RecordVersionDetailDestination(version: previousVersion) + } + await store.send(.history(.dismiss)) { + $0.history = nil + $0.versionDetail = nil + } + } + @Test("상세는 currentVersion과 일치하는 확정 버전을 표시한다") func 상세는_currentVersion과_일치하는_확정_버전을_표시한다() async throws { let record = try makeConfirmedDevelopmentRecord()