@@ -11,125 +11,12 @@ import ComposableArchitecture
1111import DevLogCore
1212import DevLogDomain
1313@testable import DevLogPresentation
14+ import Foundation
1415
1516@MainActor
16- protocol HomeStateDriving {
17- var preferences : [ TodoCategoryItem ] { get }
18- var recentTodos : [ RecentTodoItem ] { get }
19- var webPages : [ WebPageItem ] { get }
20- var isNetworkConnected : Bool { get }
21- var showContentPicker : Bool { get }
22- var showWebPageInputNavigation : Bool { get }
23- var showTodoEditor : Bool { get }
24- var showAlert : Bool { get }
25- var alertType : HomeFeature . AlertType ? { get }
26- var alertTitle : String { get }
27- var webPageURLInput : String { get }
28-
29- func startObserving( ) async
30- func fetchData( ) async
31- func openWebPageInput( ) async
32- func setPresentation( _ presentation: HomeFeature . Presentation , _ isPresented: Bool ) async
33- func setAlert( isPresented: Bool , type: HomeFeature . AlertType ? ) async
34- func tapTodoCategory( _ category: TodoCategory ) async
35- func orderTodoCategory( _ items: [ TodoCategoryItem ] ) async
36- func updateWebPageURLInput( _ input: String ) async
37- func addWebPage( ) async
38- func deleteWebPage( _ page: WebPageItem ) async
39- func undoDeleteWebPage( ) async
40- func finishDeleteWebPageToast( _ urlString: String ) async
41- }
42-
43- @MainActor
44- struct HomeViewModelTestAdapter : HomeStateDriving {
45- private let viewModel : HomeViewModel
46-
47- var preferences : [ TodoCategoryItem ] { viewModel. state. preferences }
48- var recentTodos : [ RecentTodoItem ] { viewModel. state. recentTodos }
49- var webPages : [ WebPageItem ] { viewModel. state. webPages }
50- var isNetworkConnected : Bool { viewModel. state. isNetworkConnected }
51- var showContentPicker : Bool { viewModel. state. showContentPicker }
52- var showWebPageInputNavigation : Bool { false }
53- var showTodoEditor : Bool { viewModel. state. showTodoEditor }
54- var showAlert : Bool { viewModel. state. showAlert }
55- var alertType : HomeFeature . AlertType ? { viewModel. state. alertType? . featureValue }
56- var alertTitle : String { viewModel. state. alertTitle }
57- var webPageURLInput : String { viewModel. state. webPageURLInput }
58-
59- init (
60- fetchPreferencesUseCase: FetchTodoCategoryPreferencesUseCase = FetchTodoCategoryPreferencesUseCaseSpy ( ) ,
61- updatePreferencesUseCase: UpdateTodoCategoryPreferencesUseCase = UpdateTodoCategoryPreferencesUseCaseSpy ( ) ,
62- addWebPageUseCase: AddWebPageUseCase = AddWebPageUseCaseSpy ( ) ,
63- deleteWebPageUseCase: DeleteWebPageUseCase = DeleteWebPageUseCaseSpy ( ) ,
64- undoDeleteWebPageUseCase: UndoDeleteWebPageUseCase = UndoDeleteWebPageUseCaseSpy ( ) ,
65- fetchTodosUseCase: FetchTodosUseCase = FetchTodosUseCaseSpy ( ) ,
66- fetchWebPagesUseCase: FetchWebPagesUseCase = FetchWebPagesUseCaseSpy ( webPages: [ ] ) ,
67- networkConnectivityUseCase: ObserveNetworkConnectivityUseCase = ObserveNetworkConnectivityUseCaseSpy ( ) ,
68- trackAnalyticsEventUseCase: TrackAnalyticsEventUseCase = HomeTrackAnalyticsEventUseCaseSpy ( )
69- ) {
70- viewModel = HomeViewModel (
71- fetchPreferencesUseCase: fetchPreferencesUseCase,
72- updatePreferencesUseCase: updatePreferencesUseCase,
73- addWebPageUseCase: addWebPageUseCase,
74- deleteWebPageUseCase: deleteWebPageUseCase,
75- undoDeleteWebPageUseCase: undoDeleteWebPageUseCase,
76- fetchTodosUseCase: fetchTodosUseCase,
77- fetchWebPagesUseCase: fetchWebPagesUseCase,
78- networkConnectivityUseCase: networkConnectivityUseCase,
79- trackAnalyticsEventUseCase: trackAnalyticsEventUseCase
80- )
81- }
82-
83- func startObserving( ) async { }
84-
85- func fetchData( ) async {
86- viewModel. send ( . fetchData)
87- }
88-
89- func openWebPageInput( ) async {
90- viewModel. send ( . setAlert( isPresented: true , type: . webPageInput) )
91- }
92-
93- func setPresentation( _ presentation: HomeFeature . Presentation , _ isPresented: Bool ) async {
94- viewModel. send ( . setPresentation( presentation. viewModelValue, isPresented) )
95- }
96-
97- func setAlert( isPresented: Bool , type: HomeFeature . AlertType ? ) async {
98- viewModel. send ( . setAlert( isPresented: isPresented, type: type? . viewModelValue) )
99- }
100-
101- func tapTodoCategory( _ category: TodoCategory ) async {
102- viewModel. send ( . tapTodoCategory( category) )
103- }
104-
105- func orderTodoCategory( _ items: [ TodoCategoryItem ] ) async {
106- viewModel. send ( . orderTodoCategory( items) )
107- }
108-
109- func updateWebPageURLInput( _ input: String ) async {
110- viewModel. send ( . updateWebPageURLInput( input) )
111- }
112-
113- func addWebPage( ) async {
114- viewModel. send ( . addWebPage)
115- }
116-
117- func deleteWebPage( _ page: WebPageItem ) async {
118- viewModel. send ( . deleteWebPage( page) )
119- }
120-
121- func undoDeleteWebPage( ) async {
122- viewModel. send ( . undoDeleteWebPage)
123- }
124-
125- func finishDeleteWebPageToast( _ urlString: String ) async {
126- viewModel. send ( . finishDeleteWebPageToast( urlString) )
127- }
128- }
129-
130- @MainActor
131- struct HomeStoreTestAdapter : HomeStateDriving {
17+ struct HomeStoreTestAdapter {
13218 private let store : TestStoreOf < HomeFeature >
19+ private let clock : TestClock < Duration >
13320
13421 var preferences : [ TodoCategoryItem ] { store. state. preferences }
13522 var recentTodos : [ RecentTodoItem ] { store. state. recentTodos }
@@ -171,6 +58,8 @@ struct HomeStoreTestAdapter: HomeStateDriving {
17158 trackAnalyticsEventUseCase: TrackAnalyticsEventUseCase ? = HomeTrackAnalyticsEventUseCaseSpy ( ) ,
17259 configureDependencies: ( ( inout DependencyValues ) -> Void ) ? = nil
17360 ) {
61+ let clock = TestClock ( )
62+ self . clock = clock
17463 store = TestStore ( initialState: HomeFeature . State ( ) ) {
17564 HomeFeature ( )
17665 } withDependencies: {
@@ -183,7 +72,7 @@ struct HomeStoreTestAdapter: HomeStateDriving {
18372 $0. homeFetchWebPagesUseCase = fetchWebPagesUseCase
18473 $0. networkConnectivityUseCase = networkConnectivityUseCase
18574 $0. trackAnalyticsEventUseCase = trackAnalyticsEventUseCase
186- $0. continuousClock = ContinuousClock ( )
75+ $0. continuousClock = clock
18776 configureDependencies ? ( & $0)
18877 }
18978 store. exhaustivity = . off( showSkippedAssertions: false )
@@ -215,7 +104,8 @@ struct HomeStoreTestAdapter: HomeStateDriving {
215104
216105 func tapTodoCategory( _ category: TodoCategory ) async {
217106 await store. send ( . tapTodoCategory( category) )
218- await drainReceivedActions ( )
107+ await clock. advance ( by: . seconds( 1 ) )
108+ await settle ( )
219109 }
220110
221111 func orderTodoCategory( _ items: [ TodoCategoryItem ] ) async {
@@ -246,11 +136,16 @@ struct HomeStoreTestAdapter: HomeStateDriving {
246136 await store. send ( . finishDeleteWebPageToast( urlString) )
247137 }
248138
249- private func drainReceivedActions( ) async {
139+ func drainReceivedActions( ) async {
250140 for _ in 0 ..< 12 {
251141 await store. skipReceivedActions ( strict: false )
252142 }
253143 }
144+
145+ func settle( ) async {
146+ await Task . yield ( )
147+ await drainReceivedActions ( )
148+ }
254149}
255150
256151final class HomeTrackAnalyticsEventUseCaseSpy : TrackAnalyticsEventUseCase {
@@ -301,38 +196,3 @@ func makeHomeWebPage(
301196 imageURL: nil
302197 )
303198}
304-
305- private extension HomeViewModel . AlertType {
306- var featureValue : HomeFeature . AlertType {
307- switch self {
308- case . invalidURL:
309- return . invalidURL
310- case . error:
311- return . error
312- }
313- }
314- }
315-
316- private extension HomeFeature . AlertType {
317- var viewModelValue : HomeViewModel . AlertType {
318- switch self {
319- case . invalidURL:
320- return . invalidURL
321- case . error:
322- return . error
323- }
324- }
325- }
326-
327- private extension HomeFeature . Presentation {
328- var viewModelValue : HomeViewModel . Presentation {
329- switch self {
330- case . todoEditor:
331- return . todoEditor
332- case . contentPicker:
333- return . contentPicker
334- case . searchView:
335- return . searchView
336- }
337- }
338- }
0 commit comments