33//
44
55import XCTest
6- import Combine
76import UIKit
87import EssentialApp
98import EssentialFeed
@@ -12,15 +11,15 @@ import EssentialFeediOS
1211@MainActor
1312class CommentsUIIntegrationTests : XCTestCase {
1413
15- func test_commentsView_hasTitle( ) {
14+ func test_commentsView_hasTitle( ) async {
1615 let ( sut, _) = makeSUT ( )
1716
1817 sut. simulateAppearance ( )
1918
2019 XCTAssertEqual ( sut. title, commentsTitle)
2120 }
2221
23- func test_loadCommentsActions_requestCommentsFromLoader( ) {
22+ func test_loadCommentsActions_requestCommentsFromLoader( ) async {
2423 let ( sut, loader) = makeSUT ( )
2524 XCTAssertEqual ( loader. loadCommentsCallCount, 0 , " Expected no loading requests before view appears " )
2625
@@ -30,16 +29,16 @@ class CommentsUIIntegrationTests: XCTestCase {
3029 sut. simulateUserInitiatedReload ( )
3130 XCTAssertEqual ( loader. loadCommentsCallCount, 1 , " Expected no request until previous completes " )
3231
33- loader. completeCommentsLoading ( at: 0 )
32+ await loader. completeCommentsLoading ( at: 0 )
3433 sut. simulateUserInitiatedReload ( )
3534 XCTAssertEqual ( loader. loadCommentsCallCount, 2 , " Expected another loading request once user initiates a reload " )
3635
37- loader. completeCommentsLoading ( at: 1 )
36+ await loader. completeCommentsLoading ( at: 1 )
3837 sut. simulateUserInitiatedReload ( )
3938 XCTAssertEqual ( loader. loadCommentsCallCount, 3 , " Expected yet another loading request once user initiates another reload " )
4039 }
4140
42- func test_loadCommentsActions_runsAutomaticallyOnlyOnFirstAppearance( ) {
41+ func test_loadCommentsActions_runsAutomaticallyOnlyOnFirstAppearance( ) async {
4342 let ( sut, loader) = makeSUT ( )
4443 XCTAssertEqual ( loader. loadCommentsCallCount, 0 , " Expected no loading requests before view appears " )
4544
@@ -50,120 +49,121 @@ class CommentsUIIntegrationTests: XCTestCase {
5049 XCTAssertEqual ( loader. loadCommentsCallCount, 1 , " Expected no loading request the second time view appears " )
5150 }
5251
53- func test_loadingCommentsIndicator_isVisibleWhileLoadingComments( ) {
52+ func test_loadingCommentsIndicator_isVisibleWhileLoadingComments( ) async {
5453 let ( sut, loader) = makeSUT ( )
5554
5655 sut. simulateAppearance ( )
5756 XCTAssertTrue ( sut. isShowingLoadingIndicator, " Expected loading indicator once view appears " )
5857
59- loader. completeCommentsLoading ( at: 0 )
58+ await loader. completeCommentsLoading ( at: 0 )
6059 XCTAssertFalse ( sut. isShowingLoadingIndicator, " Expected no loading indicator once loading completes successfully " )
6160
6261 sut. simulateUserInitiatedReload ( )
6362 XCTAssertTrue ( sut. isShowingLoadingIndicator, " Expected loading indicator once user initiates a reload " )
6463
65- loader. completeCommentsLoadingWithError ( at: 1 )
64+ await loader. completeCommentsLoadingWithError ( at: 1 )
6665 XCTAssertFalse ( sut. isShowingLoadingIndicator, " Expected no loading indicator once user initiated loading completes with error " )
6766 }
6867
69- func test_loadCommentsCompletion_rendersSuccessfullyLoadedComments( ) {
68+ func test_loadCommentsCompletion_rendersSuccessfullyLoadedComments( ) async {
7069 let comment0 = makeComment ( message: " a message " , username: " a username " )
7170 let comment1 = makeComment ( message: " another message " , username: " another username " )
7271 let ( sut, loader) = makeSUT ( )
7372
7473 sut. simulateAppearance ( )
7574 assertThat ( sut, isRendering: [ ImageComment] ( ) )
7675
77- loader. completeCommentsLoading ( with: [ comment0] , at: 0 )
76+ await loader. completeCommentsLoading ( with: [ comment0] , at: 0 )
7877 assertThat ( sut, isRendering: [ comment0] )
7978
8079 sut. simulateUserInitiatedReload ( )
81- loader. completeCommentsLoading ( with: [ comment0, comment1] , at: 1 )
80+ await loader. completeCommentsLoading ( with: [ comment0, comment1] , at: 1 )
8281 assertThat ( sut, isRendering: [ comment0, comment1] )
8382 }
8483
85- func test_loadCommentsCompletion_rendersSuccessfullyLoadedEmptyCommentsAfterNonEmptyComments( ) {
84+ func test_loadCommentsCompletion_rendersSuccessfullyLoadedEmptyCommentsAfterNonEmptyComments( ) async {
8685 let comment = makeComment ( )
8786 let ( sut, loader) = makeSUT ( )
8887
8988 sut. simulateAppearance ( )
90- loader. completeCommentsLoading ( with: [ comment] , at: 0 )
89+ await loader. completeCommentsLoading ( with: [ comment] , at: 0 )
9190 assertThat ( sut, isRendering: [ comment] )
9291
9392 sut. simulateUserInitiatedReload ( )
94- loader. completeCommentsLoading ( with: [ ] , at: 1 )
93+ await loader. completeCommentsLoading ( with: [ ] , at: 1 )
9594 assertThat ( sut, isRendering: [ ImageComment] ( ) )
9695 }
9796
98- func test_loadCommentsCompletion_doesNotAlterCurrentRenderingStateOnError( ) {
97+ func test_loadCommentsCompletion_doesNotAlterCurrentRenderingStateOnError( ) async {
9998 let comment = makeComment ( )
10099 let ( sut, loader) = makeSUT ( )
101100
102101 sut. simulateAppearance ( )
103- loader. completeCommentsLoading ( with: [ comment] , at: 0 )
102+ await loader. completeCommentsLoading ( with: [ comment] , at: 0 )
104103 assertThat ( sut, isRendering: [ comment] )
105104
106105 sut. simulateUserInitiatedReload ( )
107- loader. completeCommentsLoadingWithError ( at: 1 )
106+ await loader. completeCommentsLoadingWithError ( at: 1 )
108107 assertThat ( sut, isRendering: [ comment] )
109108 }
110109
111- func test_loadCommentsCompletion_rendersErrorMessageOnErrorUntilNextReload( ) {
110+ func test_loadCommentsCompletion_rendersErrorMessageOnErrorUntilNextReload( ) async {
112111 let ( sut, loader) = makeSUT ( )
113112
114113 sut. simulateAppearance ( )
115114 XCTAssertEqual ( sut. errorMessage, nil )
116115
117- loader. completeCommentsLoadingWithError ( at: 0 )
116+ await loader. completeCommentsLoadingWithError ( at: 0 )
118117 XCTAssertEqual ( sut. errorMessage, loadError)
119118
120119 sut. simulateUserInitiatedReload ( )
121120 XCTAssertEqual ( sut. errorMessage, nil )
122121 }
123122
124- func test_tapOnErrorView_hidesErrorMessage( ) {
123+ func test_tapOnErrorView_hidesErrorMessage( ) async {
125124 let ( sut, loader) = makeSUT ( )
126125
127126 sut. simulateAppearance ( )
128127 XCTAssertEqual ( sut. errorMessage, nil )
129128
130- loader. completeCommentsLoadingWithError ( at: 0 )
129+ await loader. completeCommentsLoadingWithError ( at: 0 )
131130 XCTAssertEqual ( sut. errorMessage, loadError)
132131
133132 sut. simulateErrorViewTap ( )
134133 XCTAssertEqual ( sut. errorMessage, nil )
135134 }
136135
137- func test_deinit_cancelsRunningRequest( ) {
138- var cancelCallCount = 0
139-
136+ func test_deinit_cancelsRunningRequest( ) async throws {
137+ let loader = LoaderSpy < Void , [ ImageComment ] > ( )
140138 var sut : ListViewController ?
141139
142140 autoreleasepool {
143- sut = CommentsUIComposer . commentsComposedWith ( commentsLoader: {
144- PassthroughSubject < [ ImageComment ] , Error > ( )
145- . handleEvents ( receiveCancel: {
146- cancelCallCount += 1
147- } ) . eraseToAnyPublisher ( )
148- } )
149-
141+ sut = CommentsUIComposer . commentsComposedWith ( commentsLoader: loader. loadComments)
142+
150143 sut? . simulateAppearance ( )
151144 }
152145
153- XCTAssertEqual ( cancelCallCount , 0 )
146+ XCTAssertEqual ( loader . cancelledCommentsRequestsCount , 0 )
154147
155148 sut = nil
149+ let result = try await loader. result ( at: 0 )
156150
157- XCTAssertEqual ( cancelCallCount, 1 )
151+ XCTAssertEqual ( result, . cancelled)
152+ XCTAssertEqual ( loader. cancelledCommentsRequestsCount, 1 )
158153 }
159154
160155 // MARK: - Helpers
161156
162- private func makeSUT( file: StaticString = #filePath, line: UInt = #line) -> ( sut: ListViewController , loader: LoaderSpy ) {
163- let loader = LoaderSpy ( )
164- let sut = CommentsUIComposer . commentsComposedWith ( commentsLoader: loader. loadPublisher )
157+ private func makeSUT( file: StaticString = #filePath, line: UInt = #line) -> ( sut: ListViewController , loader: LoaderSpy < Void , [ ImageComment ] > ) {
158+ let loader = LoaderSpy < Void , [ ImageComment ] > ( )
159+ let sut = CommentsUIComposer . commentsComposedWith ( commentsLoader: loader. loadComments )
165160 trackForMemoryLeaks ( loader, file: file, line: line)
166161 trackForMemoryLeaks ( sut, file: file, line: line)
162+
163+ addTeardownBlock { [ weak loader] in
164+ try await loader? . cancelPendingRequests ( )
165+ }
166+
167167 return ( sut, loader)
168168 }
169169
@@ -182,28 +182,27 @@ class CommentsUIIntegrationTests: XCTestCase {
182182 XCTAssertEqual ( sut. commentUsername ( at: index) , comment. username, " username at \( index) " , file: file, line: line)
183183 }
184184 }
185+ }
186+
187+ private extension LoaderSpy where Param == Void , Resource == [ ImageComment ] {
188+ var loadCommentsCallCount : Int {
189+ return requests. count
190+ }
185191
186- private class LoaderSpy {
187- private var requests = [ PassthroughSubject < [ ImageComment ] , Error > ] ( )
188-
189- var loadCommentsCallCount : Int {
190- return requests. count
191- }
192-
193- func loadPublisher( ) -> AnyPublisher < [ ImageComment ] , Error > {
194- let publisher = PassthroughSubject < [ ImageComment ] , Error > ( )
195- requests. append ( publisher)
196- return publisher. eraseToAnyPublisher ( )
197- }
198-
199- func completeCommentsLoading( with comments: [ ImageComment ] = [ ] , at index: Int = 0 ) {
200- requests [ index] . send ( comments)
201- requests [ index] . send ( completion: . finished)
202- }
203-
204- func completeCommentsLoadingWithError( at index: Int = 0 ) {
205- let error = NSError ( domain: " an error " , code: 0 )
206- requests [ index] . send ( completion: . failure( error) )
207- }
192+ var cancelledCommentsRequestsCount : Int {
193+ requests. count { $0. result == . cancelled }
194+ }
195+
196+ func loadComments( ) async throws -> [ ImageComment ] {
197+ try await load ( ( ) )
198+ }
199+
200+ func completeCommentsLoading( with comments: [ ImageComment ] = [ ] , at index: Int = 0 ) async {
201+ await complete ( with: comments, at: index)
202+ }
203+
204+ func completeCommentsLoadingWithError( at index: Int = 0 ) async {
205+ let error = NSError ( domain: " an error " , code: 0 )
206+ await fail ( with: error, at: index)
208207 }
209208}
0 commit comments