Skip to content

Commit d429afe

Browse files
committed
Update tests
1 parent ce19173 commit d429afe

File tree

5 files changed

+325
-60
lines changed

5 files changed

+325
-60
lines changed

Tests/ApexyAlamofireTests/AlamofireClientTests.swift

Lines changed: 15 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -22,46 +22,38 @@ final class AlamofireClientTests: XCTestCase {
2222
client = AlamofireClient(baseURL: url, configuration: config)
2323
}
2424

25-
func testClientRequest() {
25+
@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
26+
func testClientRequest() async throws {
2627
let endpoint = EmptyEndpoint()
2728
let data = "Test".data(using: .utf8)!
2829
MockURLProtocol.requestHandler = { request in
2930
let response = HTTPURLResponse(url: request.url!, statusCode: 200, httpVersion: "2.0", headerFields: nil)!
3031
return (response, data)
3132
}
3233

33-
let exp = expectation(description: "wait for response")
34-
_ = client.request(endpoint) { result in
35-
switch result {
36-
case .success(let content):
37-
XCTAssertEqual(content, data)
38-
case .failure:
39-
XCTFail("Expected result: .success, actual result: .failure")
40-
}
41-
exp.fulfill()
34+
do {
35+
let content = try await client.request(endpoint)
36+
XCTAssertEqual(content, data)
37+
} catch {
38+
XCTFail("Expected result: .success, actual result: .failure")
4239
}
43-
wait(for: [exp], timeout: 1)
4440
}
4541

46-
func testClientUpload() {
42+
@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
43+
func testClientUpload() async throws {
4744
let data = "apple".data(using: .utf8)!
4845
let endpoint = SimpleUploadEndpoint(data: data)
4946
MockURLProtocol.requestHandler = { request in
5047
let response = HTTPURLResponse(url: request.url!, statusCode: 200, httpVersion: "2.0", headerFields: nil)!
5148
return (response, data)
5249
}
5350

54-
let exp = expectation(description: "wait for response")
55-
_ = client.upload(endpoint, completionHandler: { result in
56-
switch result {
57-
case .success(let content):
58-
XCTAssertEqual(content, data)
59-
case .failure:
60-
XCTFail("Expected result: .success, actual result: .failure")
61-
}
62-
exp.fulfill()
63-
})
64-
wait(for: [exp], timeout: 1)
51+
do {
52+
let content = try await client.upload(endpoint)
53+
XCTAssertEqual(content, data)
54+
} catch {
55+
XCTFail("Expected result: .success, actual result: .failure")
56+
}
6557
}
6658
}
6759

Tests/ApexyLoaderTests/ContentLoaderTests.swift

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,4 +164,61 @@ final class ContentLoaderTests: XCTestCase {
164164
[.initial, .success(content: 1)],
165165
"The state didn't changed and the handler didn't triggered")
166166
}
167+
168+
// MARK: - Async/Await Tests
169+
170+
@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
171+
func testAsyncStateChanges() async {
172+
// Test that async state changes trigger observations
173+
let expectation = XCTestExpectation(description: "State change observed")
174+
175+
// Set up observation
176+
let observation = contentLoader.observe {
177+
expectation.fulfill()
178+
}
179+
180+
// Change state asynchronously
181+
Task {
182+
contentLoader.state = .success(content: 42)
183+
}
184+
185+
// Wait for observation to be triggered
186+
await fulfillment(of: [expectation], timeout: 1.0)
187+
188+
// Verify state
189+
switch contentLoader.state {
190+
case .success(let content):
191+
XCTAssertEqual(content, 42)
192+
default:
193+
XCTFail("Expected success state")
194+
}
195+
196+
// Clean up
197+
_ = observation
198+
}
199+
200+
@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
201+
func testAsyncStateChangesCombine() async {
202+
// Test that async state changes trigger Combine publishers
203+
let expectation = XCTestExpectation(description: "State change published")
204+
205+
// Set up publisher
206+
let cancellable = contentLoader.statePublisher
207+
.sink { state in
208+
if case .success(let content) = state, content == 42 {
209+
expectation.fulfill()
210+
}
211+
}
212+
213+
// Change state asynchronously
214+
Task {
215+
contentLoader.state = .success(content: 42)
216+
}
217+
218+
// Wait for publisher to emit
219+
await fulfillment(of: [expectation], timeout: 1.0)
220+
221+
// Clean up
222+
cancellable.cancel()
223+
}
167224
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import Apexy
2+
import Foundation
3+
4+
// MARK: - Mock Client
5+
6+
@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
7+
final class MockClient: Client {
8+
var mockResult: Result<String, Error> = .success("Mock Content")
9+
10+
func request<T>(_ endpoint: T) async throws -> T.Content where T: Endpoint {
11+
switch mockResult {
12+
case .success(let content):
13+
return content as! T.Content
14+
case .failure(let error):
15+
throw error
16+
}
17+
}
18+
19+
func upload<T>(_ endpoint: T) async throws -> T.Content where T: UploadEndpoint {
20+
switch mockResult {
21+
case .success(let content):
22+
return content as! T.Content
23+
case .failure(let error):
24+
throw error
25+
}
26+
}
27+
}
28+
29+
// MARK: - Mock Endpoint
30+
31+
struct MockEndpoint: Endpoint {
32+
typealias Content = String
33+
34+
func makeRequest() throws -> URLRequest {
35+
return URLRequest(url: URL(string: "https://example.com")!)
36+
}
37+
38+
func content(from response: URLResponse?, with body: Data) throws -> Content {
39+
return String(data: body, encoding: .utf8) ?? ""
40+
}
41+
42+
func validate(_ request: URLRequest?, response: HTTPURLResponse, data: Data?) throws {
43+
// No validation needed for tests
44+
}
45+
}
Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
@testable import ApexyLoader
2+
import Apexy
3+
import XCTest
4+
5+
@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
6+
final class WebLoaderTests: XCTestCase {
7+
8+
private var mockClient: MockClient!
9+
private var webLoader: WebLoader<String>!
10+
11+
override func setUp() {
12+
super.setUp()
13+
mockClient = MockClient()
14+
webLoader = WebLoader(apiClient: mockClient)
15+
}
16+
17+
override func tearDown() {
18+
webLoader = nil
19+
mockClient = nil
20+
super.tearDown()
21+
}
22+
23+
// MARK: - Async Request Tests
24+
25+
func testAsyncRequestSuccess() async {
26+
// Given
27+
let expectedContent = "Test Content"
28+
mockClient.mockResult = .success(expectedContent)
29+
let endpoint = MockEndpoint()
30+
31+
// When
32+
guard webLoader.startLoading() else {
33+
XCTFail("Should be able to start loading")
34+
return
35+
}
36+
37+
await webLoader.request(endpoint)
38+
39+
// Then
40+
switch webLoader.state {
41+
case .success(let content):
42+
XCTAssertEqual(content, expectedContent)
43+
default:
44+
XCTFail("Expected success state, got \(webLoader.state)")
45+
}
46+
}
47+
48+
func testAsyncRequestFailure() async {
49+
// Given
50+
let expectedError = URLError(.networkConnectionLost)
51+
mockClient.mockResult = .failure(expectedError)
52+
let endpoint = MockEndpoint()
53+
54+
// When
55+
guard webLoader.startLoading() else {
56+
XCTFail("Should be able to start loading")
57+
return
58+
}
59+
60+
await webLoader.request(endpoint)
61+
62+
// Then
63+
switch webLoader.state {
64+
case .failure(let error, let cache):
65+
XCTAssertEqual(error as? URLError, expectedError)
66+
XCTAssertNil(cache)
67+
default:
68+
XCTFail("Expected failure state, got \(webLoader.state)")
69+
}
70+
}
71+
72+
func testAsyncRequestWithTransformation() async {
73+
// Given
74+
let rawContent = "Raw Content"
75+
let transformedContent = "Transformed: Raw Content"
76+
mockClient.mockResult = .success(rawContent)
77+
let endpoint = MockEndpoint()
78+
79+
// When
80+
guard webLoader.startLoading() else {
81+
XCTFail("Should be able to start loading")
82+
return
83+
}
84+
85+
await webLoader.request(endpoint) { raw in
86+
return "Transformed: \(raw)"
87+
}
88+
89+
// Then
90+
switch webLoader.state {
91+
case .success(let content):
92+
XCTAssertEqual(content, transformedContent)
93+
default:
94+
XCTFail("Expected success state, got \(webLoader.state)")
95+
}
96+
}
97+
98+
func testAsyncRequestWithCompletion() async {
99+
// Given
100+
let expectedContent = "Test Content"
101+
mockClient.mockResult = .success(expectedContent)
102+
let endpoint = MockEndpoint()
103+
var completionCalled = false
104+
var receivedResult: Result<String, Error>?
105+
106+
// When
107+
guard webLoader.startLoading() else {
108+
XCTFail("Should be able to start loading")
109+
return
110+
}
111+
112+
await webLoader.request(endpoint) { result in
113+
completionCalled = true
114+
receivedResult = result
115+
}
116+
117+
// Then
118+
XCTAssertTrue(completionCalled)
119+
switch receivedResult {
120+
case .success(let content):
121+
XCTAssertEqual(content, expectedContent)
122+
case .failure:
123+
XCTFail("Expected success result")
124+
case .none:
125+
XCTFail("Expected result to be set")
126+
}
127+
}
128+
129+
func testAsyncRequestWithoutStartLoading() async {
130+
// Given
131+
let endpoint = MockEndpoint()
132+
133+
// When
134+
await webLoader.request(endpoint)
135+
136+
// Then
137+
// The request method should still work even without startLoading
138+
// but it will call finishLoading which changes the state
139+
switch webLoader.state {
140+
case .success(let content):
141+
XCTAssertEqual(content, "Mock Content")
142+
default:
143+
XCTFail("Expected success state, got \(webLoader.state)")
144+
}
145+
}
146+
147+
func testAsyncLoadMethod() async {
148+
// Given
149+
let expectedContent = "Test Content"
150+
mockClient.mockResult = .success(expectedContent)
151+
let endpoint = MockEndpoint()
152+
153+
// Create a custom loader that has a custom load method
154+
let customLoader = CustomWebLoader(apiClient: mockClient, endpoint: endpoint)
155+
156+
// When
157+
await customLoader.customLoad()
158+
159+
// Then
160+
switch customLoader.state {
161+
case .success(let content):
162+
XCTAssertEqual(content, expectedContent)
163+
default:
164+
XCTFail("Expected success state, got \(customLoader.state)")
165+
}
166+
}
167+
168+
}
169+
170+
171+
@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
172+
private final class CustomWebLoader: WebLoader<String> {
173+
private let testEndpoint: MockEndpoint
174+
175+
init(apiClient: Client, endpoint: MockEndpoint) {
176+
self.testEndpoint = endpoint
177+
super.init(apiClient: apiClient)
178+
}
179+
180+
func customLoad() async {
181+
guard startLoading() else { return }
182+
await request(testEndpoint)
183+
}
184+
}

0 commit comments

Comments
 (0)