@@ -6,13 +6,13 @@ import SwiftUI
66final class ObservableStoreTests : XCTestCase {
77 /// App state
88 struct AppModel : ModelProtocol {
9- enum Action {
9+ enum Action : Hashable {
1010 case increment
1111 case delayIncrement( Double )
1212 case setCount( Int )
1313 case setEditor( Editor )
1414 }
15-
15+
1616 /// Services like API methods go here
1717 struct Environment {
1818 func delayIncrement(
@@ -26,7 +26,7 @@ final class ObservableStoreTests: XCTestCase {
2626 . eraseToAnyPublisher ( )
2727 }
2828 }
29-
29+
3030 /// State update function
3131 static func update(
3232 state: AppModel ,
@@ -53,44 +53,44 @@ final class ObservableStoreTests: XCTestCase {
5353 return Update ( state: model)
5454 }
5555 }
56-
57- struct Editor : Equatable {
58- struct Input : Equatable {
56+
57+ struct Editor : Hashable {
58+ struct Input : Hashable {
5959 var text : String = " "
6060 var isFocused : Bool = true
6161 }
6262 var input = Input ( )
6363 }
64-
64+
6565 var count = 0
6666 var editor = Editor ( )
6767 }
68-
68+
6969 struct SimpleCountView : View {
7070 @Binding var count : Int
71-
71+
7272 var body : some View {
7373 Text ( " Count: \( count) " )
7474 }
7575 }
76-
76+
7777 var cancellables = Set < AnyCancellable > ( )
78-
78+
7979 override func setUp( ) {
8080 // Empty cancellables
8181 self . cancellables = Set ( )
8282 }
83-
83+
8484 func testStateAdvance( ) throws {
8585 let store = Store (
8686 state: AppModel ( ) ,
8787 environment: AppModel . Environment ( )
8888 )
89-
89+
9090 store. send ( . increment)
9191 XCTAssertEqual ( store. state. count, 1 , " state is advanced " )
9292 }
93-
93+
9494 func testBinding( ) throws {
9595 let store = Store (
9696 state: AppModel ( ) ,
@@ -107,7 +107,7 @@ final class ObservableStoreTests: XCTestCase {
107107 XCTAssertEqual ( view. count, 2 , " binding is set " )
108108 XCTAssertEqual ( store. state. count, 2 , " binding sends action to store " )
109109 }
110-
110+
111111 func testDeepBinding( ) throws {
112112 let store = Store (
113113 state: AppModel ( ) ,
@@ -118,16 +118,16 @@ final class ObservableStoreTests: XCTestCase {
118118 get: \. editor,
119119 tag: AppModel . Action. setEditor
120120 )
121- . input
122- . text
121+ . input
122+ . text
123123 binding. wrappedValue = " floop "
124124 XCTAssertEqual (
125125 store. state. editor. input. text,
126126 " floop " ,
127127 " specialized binding sets deep property "
128128 )
129129 }
130-
130+
131131 func testEmptyFxRemovedOnComplete( ) {
132132 let store = Store (
133133 state: AppModel ( ) ,
@@ -149,7 +149,7 @@ final class ObservableStoreTests: XCTestCase {
149149 }
150150 wait ( for: [ expectation] , timeout: 0.1 )
151151 }
152-
152+
153153 func testAsyncFxRemovedOnComplete( ) {
154154 let store = Store (
155155 state: AppModel ( ) ,
@@ -170,24 +170,24 @@ final class ObservableStoreTests: XCTestCase {
170170 }
171171 wait ( for: [ expectation] , timeout: 0.5 )
172172 }
173-
173+
174174 func testPublishedPropertyFires( ) throws {
175175 let store = Store (
176176 state: AppModel ( ) ,
177177 environment: AppModel . Environment ( )
178178 )
179-
179+
180180 var count = 0
181181 store. $state
182182 . sink ( receiveValue: { _ in
183183 count = count + 1
184184 } )
185185 . store ( in: & cancellables)
186-
186+
187187 store. send ( . increment)
188188 store. send ( . increment)
189189 store. send ( . increment)
190-
190+
191191 let expectation = XCTestExpectation (
192192 description: " publisher fires when state changes "
193193 )
@@ -201,25 +201,25 @@ final class ObservableStoreTests: XCTestCase {
201201 }
202202 wait ( for: [ expectation] , timeout: 0.2 )
203203 }
204-
204+
205205 func testStateOnlySetWhenNotEqual( ) {
206206 let store = Store (
207207 state: AppModel ( ) ,
208208 environment: AppModel . Environment ( )
209209 )
210-
210+
211211 var count = 0
212212 store. $state
213213 . sink ( receiveValue: { _ in
214214 count = count + 1
215215 } )
216216 . store ( in: & cancellables)
217-
217+
218218 store. send ( . setCount( 10 ) )
219219 store. send ( . setCount( 10 ) )
220220 store. send ( . setCount( 10 ) )
221221 store. send ( . setCount( 10 ) )
222-
222+
223223 let expectation = XCTestExpectation (
224224 description: " publisher does not fire when state does not change "
225225 )
@@ -235,7 +235,7 @@ final class ObservableStoreTests: XCTestCase {
235235 }
236236 wait ( for: [ expectation] , timeout: 0.2 )
237237 }
238-
238+
239239 /// Definition for app to test updates
240240 struct TestUpdateMergeFxState : ModelProtocol {
241241 enum Action {
@@ -246,9 +246,9 @@ final class ObservableStoreTests: XCTestCase {
246246 case setTitle( String )
247247 case setSubtitle( String )
248248 }
249-
249+
250250 struct Environment { }
251-
251+
252252 /// Update function for Fx tests (below)
253253 static func update(
254254 state: Self ,
@@ -276,7 +276,7 @@ final class ObservableStoreTests: XCTestCase {
276276 . mergeFx ( b)
277277 }
278278 }
279-
279+
280280 var title : String = " "
281281 var subtitle : String = " "
282282 }
@@ -292,11 +292,11 @@ final class ObservableStoreTests: XCTestCase {
292292 subtitle: " subtitle "
293293 )
294294 )
295-
295+
296296 let expectation = XCTestExpectation (
297297 description: " check that update fx are merged "
298298 )
299-
299+
300300 DispatchQueue . main. asyncAfter ( deadline: . now( ) + 0.1 ) {
301301 XCTAssertEqual (
302302 store. state. title,
@@ -312,4 +312,57 @@ final class ObservableStoreTests: XCTestCase {
312312 }
313313 wait ( for: [ expectation] , timeout: 0.2 )
314314 }
315+
316+ func testInitialActionInit( ) throws {
317+ let store = Store (
318+ state: AppModel ( ) ,
319+ action: . increment,
320+ environment: AppModel . Environment ( )
321+ )
322+ XCTAssertEqual (
323+ store. state. count,
324+ 1 ,
325+ " action was sent to store during init "
326+ )
327+ }
328+
329+ func testActionsPublisher( ) throws {
330+ let store = Store (
331+ state: AppModel ( ) ,
332+ action: . increment,
333+ environment: AppModel . Environment ( )
334+ )
335+
336+ var actions : [ AppModel . Action ] = [ ]
337+ store. actions
338+ . sink ( receiveValue: { action in
339+ actions. append ( action)
340+ } )
341+ . store ( in: & cancellables)
342+
343+ store. send ( . setCount( 1 ) )
344+ store. send ( . setCount( 2 ) )
345+ store. send ( . setCount( 3 ) )
346+
347+ let expectation = XCTestExpectation (
348+ description: " actions publisher fires for every action "
349+ )
350+
351+ DispatchQueue . main. async {
352+
353+ // Publisher should fire twice: once for initial state,
354+ // once for state change.
355+ XCTAssertEqual (
356+ actions,
357+ [
358+ . setCount( 1 ) ,
359+ . setCount( 2 ) ,
360+ . setCount( 3 )
361+ ] ,
362+ " publisher does not fire when state does not change "
363+ )
364+ expectation. fulfill ( )
365+ }
366+ wait ( for: [ expectation] , timeout: 0.1 )
367+ }
315368}
0 commit comments