55// Created by Daniel Koster on 10/13/25.
66//
77import QuickHatchHTTP
8+ @testable import QuickHatchHTTPMocks
89import Foundation
910import Testing
11+ import Combine
1012
11- struct HTTPRequestTests {
13+ final class HTTPRequestTests {
14+ private var cancellables = Set < AnyCancellable > ( )
1215
1316 @Test
1417 func asURLRequest_expectHeadersCorrectlyParsed( ) throws {
15- let sut = QHHTTPRequest ( headers: [ " Content-Type " : " json " ] ,
16- url: " quickhatch.com " ,
17- method: . get)
18+ let sut = QHHTTPRequest < DataModel > ( headers: [ " Content-Type " : " json " ] ,
19+ url: " quickhatch.com " ,
20+ method: . get)
1821
1922 let result = try sut. asURLRequest ( )
2023
@@ -26,4 +29,144 @@ struct HTTPRequestTests {
2629 #expect( headers == [ " Content-Type " : " json " ] )
2730 #expect( method == " GET " )
2831 }
32+
33+ @Test
34+ func response_whenNoErrorSpecified_expectCorrectResponse( ) async throws {
35+ let requestFactoryMock = NetworkRequestFactoryMock ( )
36+ let sut = QHHTTPRequest < DataModel > ( url: " quickhatch.com " , method: . get, requestFactory: requestFactoryMock)
37+ requestFactoryMock. asyncDataResponseResult = URLSessionMocks . anyResponse ( )
38+
39+ do {
40+ _ = try await sut. response ( )
41+ #expect( requestFactoryMock. invokedAsyncDataCount == 1 )
42+ }
43+ catch _ {
44+ #expect( Bool ( false ) )
45+ }
46+ }
47+
48+ @Test func response_whenErrorThrown_expectCatchToWork( ) async throws {
49+ let requestFactoryMock = NetworkRequestFactoryMock ( )
50+ let sut = QHHTTPRequest < DataModel > ( url: " quickhatch.com " , method: . get, requestFactory: requestFactoryMock)
51+ requestFactoryMock. asyncDataResponseResult = URLSessionMocks . anyResponse ( )
52+ requestFactoryMock. asyncDataErrorThrown = RequestError . requestWithError ( statusCode: HTTPStatusCode . badRequest)
53+
54+ do {
55+ _ = try await sut. response ( )
56+ }
57+ catch let error as RequestError {
58+ #expect( error == . requestWithError( statusCode: . badRequest) )
59+ #expect( requestFactoryMock. invokedAsyncDataCount == 1 )
60+ }
61+ }
62+
63+ @Test
64+ func responseDecoded_whenNoErrorSpecified_expectCorrectResponse( ) async throws {
65+ let requestFactoryMock = NetworkRequestFactoryMock ( )
66+ let sut = QHHTTPRequest < DataModel > ( url: " quickhatch.com " , method: . get, requestFactory: requestFactoryMock)
67+ requestFactoryMock. asyncDataResponseResult = URLSessionMocks . anyResponse ( withData: URLSessionMocks . anyDataModelSample)
68+
69+ do {
70+ let response = try await sut. responseDecoded ( )
71+ let dataExpected = DataModel ( name: " dan " , nick: " sp " , age: 12 )
72+ #expect( requestFactoryMock. invokedAsyncDataCount == 1 )
73+ #expect( dataExpected. name == response. data. name)
74+ }
75+ catch _ {
76+ #expect( Bool ( false ) )
77+ }
78+ }
79+
80+ @Test func responseDecoded_whenErrorThrown_expectCatchToWork( ) async throws {
81+ let requestFactoryMock = NetworkRequestFactoryMock ( )
82+ let sut = QHHTTPRequest < DataModel > ( url: " quickhatch.com " , method: . get, requestFactory: requestFactoryMock)
83+ requestFactoryMock. asyncDataResponseResult = URLSessionMocks . anyResponse ( )
84+ requestFactoryMock. asyncDataErrorThrown = RequestError . requestWithError ( statusCode: HTTPStatusCode . badRequest)
85+
86+ do {
87+ _ = try await sut. responseDecoded ( )
88+ }
89+ catch let error as RequestError {
90+ #expect( error == . requestWithError( statusCode: . badRequest) )
91+ #expect( requestFactoryMock. invokedAsyncDataCount == 1 )
92+ }
93+ }
94+
95+ @Test func responseDecodedPublisher_whenErrorThrown_expectCatchToWork( ) async throws {
96+ let requestFactoryMock = NetworkRequestFactoryMock ( )
97+ let sut = QHHTTPRequest < DataModel > ( url: " quickhatch.com " , method: . get, requestFactory: requestFactoryMock)
98+ requestFactoryMock. subject. send ( completion: Subscribers . Completion. failure ( RequestError . requestWithError ( statusCode: HTTPStatusCode . badRequest) ) )
99+
100+ await confirmation ( " " ) { confirmation in
101+ sut. responseDecodedPublisher. sink ( receiveCompletion: { completion in
102+ switch completion {
103+ case . failure( let error as RequestError ) :
104+ #expect( error == . requestWithError( statusCode: HTTPStatusCode . badRequest) )
105+ confirmation. confirm ( )
106+ case . failure( _) : break
107+ case . finished: break
108+ }
109+ } ,
110+ receiveValue: { dataModel in } ) . store ( in: & cancellables)
111+ }
112+ }
113+
114+ @Test func responseDecodedPublisher_whenNoErrorThrown_expectCorrectResponse( ) async throws {
115+ let requestFactoryMock = NetworkRequestFactoryMock ( )
116+ let sut = QHHTTPRequest < DataModel > ( url: " quickhatch.com " , method: . get, requestFactory: requestFactoryMock)
117+ let response = DataModel ( name: " dan " , nick: " sp " , age: 12 )
118+
119+ await confirmation ( " " ) { confirmation in
120+ sut. responseDecodedPublisher. sink ( receiveCompletion: { completion in
121+ switch completion {
122+ case . failure( _) : break
123+ case . finished: break
124+ }
125+ } ,
126+ receiveValue: { dataModel in
127+ #expect( dataModel. name == response. name)
128+ confirmation. confirm ( )
129+ } ) . store ( in: & cancellables)
130+ requestFactoryMock. subject. send ( URLSessionMocks . anyResponse ( withData: URLSessionMocks . anyDataModelSample) )
131+ }
132+ }
133+
134+ @Test func responsePublisher_whenErrorThrown_expectCatchToWork( ) async throws {
135+ let requestFactoryMock = NetworkRequestFactoryMock ( )
136+ let sut = QHHTTPRequest < DataModel > ( url: " quickhatch.com " , method: . get, requestFactory: requestFactoryMock)
137+ requestFactoryMock. subject. send ( completion: Subscribers . Completion. failure ( RequestError . requestWithError ( statusCode: HTTPStatusCode . badRequest) ) )
138+
139+ await confirmation ( " " ) { confirmation in
140+ sut. responsePublisher. sink ( receiveCompletion: { completion in
141+ switch completion {
142+ case . failure( let error as RequestError ) :
143+ #expect( error == . requestWithError( statusCode: HTTPStatusCode . badRequest) )
144+ confirmation. confirm ( )
145+ case . failure( _) : break
146+ case . finished: break
147+ }
148+ } ,
149+ receiveValue: { _ in } ) . store ( in: & cancellables)
150+ }
151+ }
152+
153+ @Test func responsePublisher_whenNoErrorThrown_expectCorrectResponse( ) async throws {
154+ let requestFactoryMock = NetworkRequestFactoryMock ( )
155+ let sut = QHHTTPRequest < DataModel > ( url: " quickhatch.com " , method: . get, requestFactory: requestFactoryMock)
156+
157+ await confirmation ( " " ) { confirmation in
158+ sut. responsePublisher. sink ( receiveCompletion: { completion in
159+ switch completion {
160+ case . failure( _) : break
161+ case . finished: break
162+ }
163+ } ,
164+ receiveValue: { response in
165+ #expect( response. body != nil )
166+ confirmation. confirm ( )
167+ } ) . store ( in: & cancellables)
168+ requestFactoryMock. subject. send ( URLSessionMocks . anyResponse ( withData: URLSessionMocks . anyDataModelSample) )
169+ }
170+ }
171+
29172}
0 commit comments