Skip to content

Commit 10b495f

Browse files
committed
Add DomainStore for domain suggestions.
1 parent 2e6985a commit 10b495f

File tree

6 files changed

+165
-0
lines changed

6 files changed

+165
-0
lines changed

Yosemite/Yosemite.xcodeproj/project.pbxproj

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@
3939
022F9319257F24730011CD94 /* MockShippingLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 022F9318257F24730011CD94 /* MockShippingLabel.swift */; };
4040
022F931D257F27B40011CD94 /* MockShippingLabelAddress.swift in Sources */ = {isa = PBXBuildFile; fileRef = 022F931C257F27B40011CD94 /* MockShippingLabelAddress.swift */; };
4141
0232372922F7DA6E00715FAB /* StatsTimeRangeV4.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0232372822F7DA6E00715FAB /* StatsTimeRangeV4.swift */; };
42+
02393065291A018600B2632F /* DomainAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02393064291A018600B2632F /* DomainAction.swift */; };
43+
02393067291A02AC00B2632F /* DomainStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02393066291A02AC00B2632F /* DomainStore.swift */; };
4244
0248B3652459018100A271A4 /* ResultsController+FilterProducts.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0248B3642459018100A271A4 /* ResultsController+FilterProducts.swift */; };
4345
0248B3672459020500A271A4 /* ResultsController+FilterProductTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0248B3662459020500A271A4 /* ResultsController+FilterProductTests.swift */; };
4446
0248B36924590FC300A271A4 /* ProductStore+FilterProductsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0248B36824590FC300A271A4 /* ProductStore+FilterProductsTests.swift */; };
@@ -65,6 +67,8 @@
6567
02C254FA2563B66600A04423 /* ShippingLabelRefund+ReadOnlyConvertible.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02C254F92563B66600A04423 /* ShippingLabelRefund+ReadOnlyConvertible.swift */; };
6668
02C254FE2563C6E500A04423 /* ShippingLabelSettings+ReadOnlyConvertible.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02C254FD2563C6E500A04423 /* ShippingLabelSettings+ReadOnlyConvertible.swift */; };
6769
02C255022563C76A00A04423 /* ShippingLabel+ReadOnlyConvertible.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02C255012563C76A00A04423 /* ShippingLabel+ReadOnlyConvertible.swift */; };
70+
02DAE7F8291A9F11009342B7 /* DomainStoreTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02DAE7F7291A9F11009342B7 /* DomainStoreTests.swift */; };
71+
02DAE7FA291A9F36009342B7 /* MockDomainRemote.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02DAE7F9291A9F36009342B7 /* MockDomainRemote.swift */; };
6872
02E262BD238CE46A00B79588 /* ShippingSettingsService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02E262BC238CE46A00B79588 /* ShippingSettingsService.swift */; };
6973
02E262C0238CE80100B79588 /* StorageShippingSettingsServiceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02E262BF238CE80100B79588 /* StorageShippingSettingsServiceTests.swift */; };
7074
02E262C2238CF74D00B79588 /* StorageShippingSettingsService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02E262C1238CF74D00B79588 /* StorageShippingSettingsService.swift */; };
@@ -456,6 +460,8 @@
456460
022F9318257F24730011CD94 /* MockShippingLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockShippingLabel.swift; sourceTree = "<group>"; };
457461
022F931C257F27B40011CD94 /* MockShippingLabelAddress.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockShippingLabelAddress.swift; sourceTree = "<group>"; };
458462
0232372822F7DA6E00715FAB /* StatsTimeRangeV4.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatsTimeRangeV4.swift; sourceTree = "<group>"; };
463+
02393064291A018600B2632F /* DomainAction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DomainAction.swift; sourceTree = "<group>"; };
464+
02393066291A02AC00B2632F /* DomainStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DomainStore.swift; sourceTree = "<group>"; };
459465
0248B3642459018100A271A4 /* ResultsController+FilterProducts.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ResultsController+FilterProducts.swift"; sourceTree = "<group>"; };
460466
0248B3662459020500A271A4 /* ResultsController+FilterProductTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ResultsController+FilterProductTests.swift"; sourceTree = "<group>"; };
461467
0248B36824590FC300A271A4 /* ProductStore+FilterProductsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ProductStore+FilterProductsTests.swift"; sourceTree = "<group>"; };
@@ -482,6 +488,8 @@
482488
02C254F92563B66600A04423 /* ShippingLabelRefund+ReadOnlyConvertible.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ShippingLabelRefund+ReadOnlyConvertible.swift"; sourceTree = "<group>"; };
483489
02C254FD2563C6E500A04423 /* ShippingLabelSettings+ReadOnlyConvertible.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ShippingLabelSettings+ReadOnlyConvertible.swift"; sourceTree = "<group>"; };
484490
02C255012563C76A00A04423 /* ShippingLabel+ReadOnlyConvertible.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ShippingLabel+ReadOnlyConvertible.swift"; sourceTree = "<group>"; };
491+
02DAE7F7291A9F11009342B7 /* DomainStoreTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DomainStoreTests.swift; sourceTree = "<group>"; };
492+
02DAE7F9291A9F36009342B7 /* MockDomainRemote.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockDomainRemote.swift; sourceTree = "<group>"; };
485493
02E262BC238CE46A00B79588 /* ShippingSettingsService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShippingSettingsService.swift; sourceTree = "<group>"; };
486494
02E262BF238CE80100B79588 /* StorageShippingSettingsServiceTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StorageShippingSettingsServiceTests.swift; sourceTree = "<group>"; };
487495
02E262C1238CF74D00B79588 /* StorageShippingSettingsService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StorageShippingSettingsService.swift; sourceTree = "<group>"; };
@@ -1188,6 +1196,7 @@
11881196
02A26F1D2744FE97008E4EDB /* MockAccountRemote.swift */,
11891197
029249E7274B8AEE002E9C34 /* MockMediaRemote.swift */,
11901198
021BA0C328576940006E9886 /* MockDotcomAccountRemote.swift */,
1199+
02DAE7F9291A9F36009342B7 /* MockDomainRemote.swift */,
11911200
);
11921201
path = Remote;
11931202
sourceTree = "<group>";
@@ -1399,6 +1408,7 @@
13991408
DE3404FD28BC5F4200CF0D97 /* JetpackConnectionStore.swift */,
14001409
68BD37B428DB2E9800C2A517 /* CustomerStore.swift */,
14011410
02E3B622290267D3007E0F13 /* AccountCreationStore.swift */,
1411+
02393066291A02AC00B2632F /* DomainStore.swift */,
14021412
);
14031413
path = Stores;
14041414
sourceTree = "<group>";
@@ -1458,6 +1468,7 @@
14581468
DE50296628C7114800551736 /* JetpackConnectionStoreTests.swift */,
14591469
68BD37B828DB323D00C2A517 /* CustomerStoreTests.swift */,
14601470
02E3B629290622DE007E0F13 /* AccountCreationStoreTests.swift */,
1471+
02DAE7F7291A9F11009342B7 /* DomainStoreTests.swift */,
14611472
);
14621473
path = Stores;
14631474
sourceTree = "<group>";
@@ -1643,6 +1654,7 @@
16431654
B9AECD3D2850F41100E78584 /* OrderCardPresentPaymentEligibilityAction.swift */,
16441655
DE3404FB28BC5E7800CF0D97 /* JetpackConnectionAction.swift */,
16451656
02E3B624290267F2007E0F13 /* AccountCreationAction.swift */,
1657+
02393064291A018600B2632F /* DomainAction.swift */,
16461658
);
16471659
path = Actions;
16481660
sourceTree = "<group>";
@@ -2036,6 +2048,7 @@
20362048
2618707C2540B6A4006522A1 /* ShippingLineTax+ReadOnlyConvertible.swift in Sources */,
20372049
749375002249605E007D85D1 /* ProductAction.swift in Sources */,
20382050
D831E2E4230E3524000037D0 /* ProductReviewAction.swift in Sources */,
2051+
02393065291A018600B2632F /* DomainAction.swift in Sources */,
20392052
D831E2E6230E7149000037D0 /* ProductReview+ReadOnlyConvertible.swift in Sources */,
20402053
CE4FD4502350F27C00A16B31 /* OrderItemTax+ReadOnlyConvertible.swift in Sources */,
20412054
02FF055123D983F30058E6E7 /* MediaAssetExporter.swift in Sources */,
@@ -2162,6 +2175,7 @@
21622175
453305F7245AE68C00264E50 /* SitePostStore.swift in Sources */,
21632176
026CF62A237D92C6009563D4 /* ProductVariation+ReadOnlyConvertible.swift in Sources */,
21642177
02F6AAAC270556A4002425D0 /* Models+Copiable.generated.swift in Sources */,
2178+
02393067291A02AC00B2632F /* DomainStore.swift in Sources */,
21652179
);
21662180
runOnlyForDeploymentPostprocessing = 0;
21672181
};
@@ -2192,6 +2206,7 @@
21922206
E1F54D0427AD4DAF00012983 /* CardPresentConfigurationTests.swift in Sources */,
21932207
025CA2D0238F54E800B05C81 /* ProductShippingClassStoreTests.swift in Sources */,
21942208
74A7688E20D45ED400F9D437 /* OrderStoreTests.swift in Sources */,
2209+
02DAE7F8291A9F11009342B7 /* DomainStoreTests.swift in Sources */,
21952210
D8652E322630741000350F37 /* PaymentIntent+ReceiptParametersTests.swift in Sources */,
21962211
029249E8274B8AEE002E9C34 /* MockMediaRemote.swift in Sources */,
21972212
021BA0C428576940006E9886 /* MockDotcomAccountRemote.swift in Sources */,
@@ -2249,6 +2264,7 @@
22492264
265BCA0024301ACD004E53EE /* ProductCategoryStoreTests.swift in Sources */,
22502265
02FF056D23DEDCB90058E6E7 /* MockImageSourceWriter.swift in Sources */,
22512266
FE28F6F2268462A6004465C7 /* UserStoreTests.swift in Sources */,
2267+
02DAE7FA291A9F36009342B7 /* MockDomainRemote.swift in Sources */,
22522268
741F34842195F752005F5BD9 /* CommentStoreTests.swift in Sources */,
22532269
B5C9DE282087FF20006B910A /* MockSiteStore.swift in Sources */,
22542270
FEEB2F5F268A1C5E0075A6E0 /* User+RolesTests.swift in Sources */,
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import Foundation
2+
3+
// MARK: - DomainAction: Defines all of the Actions supported by the DomainStore.
4+
//
5+
public enum DomainAction: Action {
6+
case loadFreeDomainSuggestions(query: String, completion: (Result<[FreeDomainSuggestion], Error>) -> Void)
7+
}

Yosemite/Yosemite/Model/Model.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ public typealias Customer = Networking.Customer
2727
public typealias DotcomDevice = Networking.DotcomDevice
2828
public typealias DotcomUser = Networking.DotcomUser
2929
public typealias Feature = WordPressKit.Feature
30+
public typealias FreeDomainSuggestion = Networking.FreeDomainSuggestion
3031
public typealias InboxNote = Networking.InboxNote
3132
public typealias InboxAction = Networking.InboxAction
3233
public typealias JetpackUser = Networking.JetpackUser
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import Foundation
2+
import Networking
3+
import protocol Storage.StorageManagerType
4+
5+
/// Handles `DomainAction`.
6+
///
7+
public final class DomainStore: Store {
8+
// Keeps a strong reference to remote to keep requests alive.
9+
private let remote: DomainRemoteProtocol
10+
11+
public init(dispatcher: Dispatcher, storageManager: StorageManagerType, network: Network, remote: DomainRemoteProtocol) {
12+
self.remote = remote
13+
super.init(dispatcher: dispatcher, storageManager: storageManager, network: network)
14+
}
15+
16+
public override convenience init(dispatcher: Dispatcher, storageManager: StorageManagerType, network: Network) {
17+
let remote = DomainRemote(network: network)
18+
self.init(dispatcher: dispatcher, storageManager: storageManager, network: network, remote: remote)
19+
}
20+
21+
public override func registerSupportedActions(in dispatcher: Dispatcher) {
22+
dispatcher.register(processor: self, for: DomainAction.self)
23+
}
24+
25+
/// Called whenever a given Action is dispatched.
26+
///
27+
public override func onAction(_ action: Action) {
28+
guard let action = action as? DomainAction else {
29+
assertionFailure("DomainStore received an unsupported action: \(action)")
30+
return
31+
}
32+
switch action {
33+
case .loadFreeDomainSuggestions(let query, let completion):
34+
loadFreeDomainSuggestions(query: query, completion: completion)
35+
}
36+
}
37+
}
38+
39+
private extension DomainStore {
40+
func loadFreeDomainSuggestions(query: String, completion: @escaping (Result<[FreeDomainSuggestion], Error>) -> Void) {
41+
Task { @MainActor in
42+
let result = await remote.loadFreeDomainSuggestions(query: query)
43+
completion(result)
44+
}
45+
}
46+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import Networking
2+
import XCTest
3+
4+
/// Mock for `DomainRemote`.
5+
///
6+
final class MockDomainRemote {
7+
/// The results to return in `loadDomainSuggestions`.
8+
private var loadDomainSuggestionsResult: Result<[FreeDomainSuggestion], Error>?
9+
10+
/// Returns the value when `loadDomainSuggestions` is called.
11+
func whenLoadingDomainSuggestions(thenReturn result: Result<[FreeDomainSuggestion], Error>) {
12+
loadDomainSuggestionsResult = result
13+
}
14+
}
15+
16+
extension MockDomainRemote: DomainRemoteProtocol {
17+
func loadFreeDomainSuggestions(query: String) async -> Result<[FreeDomainSuggestion], Error> {
18+
guard let result = loadDomainSuggestionsResult else {
19+
XCTFail("Could not find result for loading domain suggestions.")
20+
return .failure(NetworkError.notFound)
21+
}
22+
return result
23+
}
24+
}
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import XCTest
2+
@testable import Networking
3+
@testable import Yosemite
4+
5+
final class DomainStoreTests: XCTestCase {
6+
/// Mock Dispatcher.
7+
private var dispatcher: Dispatcher!
8+
9+
/// Mock Storage: InMemory.
10+
private var storageManager: MockStorageManager!
11+
12+
/// Mock Network: Allows us to inject predefined responses.
13+
private var network: MockNetwork!
14+
15+
private var remote: MockDomainRemote!
16+
private var store: DomainStore!
17+
18+
override func setUp() {
19+
super.setUp()
20+
dispatcher = Dispatcher()
21+
storageManager = MockStorageManager()
22+
network = MockNetwork()
23+
remote = MockDomainRemote()
24+
store = DomainStore(dispatcher: dispatcher, storageManager: storageManager, network: network, remote: remote)
25+
}
26+
27+
override func tearDown() {
28+
store = nil
29+
remote = nil
30+
network = nil
31+
storageManager = nil
32+
dispatcher = nil
33+
super.tearDown()
34+
}
35+
36+
func test_loadFreeDomainSuggestions_returns_suggestions_on_success() throws {
37+
// Given
38+
remote.whenLoadingDomainSuggestions(thenReturn: .success([.init(name: "freedomaintesting", isFree: false)]))
39+
40+
// When
41+
let result: Result<[FreeDomainSuggestion], Error> = waitFor { promise in
42+
let action = DomainAction.loadFreeDomainSuggestions(query: "domain") { result in
43+
promise(result)
44+
}
45+
self.store.onAction(action)
46+
}
47+
48+
// Then
49+
XCTAssertTrue(result.isSuccess)
50+
let suggestions = try XCTUnwrap(result.get())
51+
XCTAssertEqual(suggestions, [.init(name: "freedomaintesting", isFree: false)])
52+
}
53+
54+
func test_loadFreeDomainSuggestions_returns_error_on_failure() throws {
55+
// Given
56+
remote.whenLoadingDomainSuggestions(thenReturn: .failure(NetworkError.timeout))
57+
58+
// When
59+
let result: Result<[FreeDomainSuggestion], Error> = waitFor { promise in
60+
let action = DomainAction.loadFreeDomainSuggestions(query: "domain") { result in
61+
promise(result)
62+
}
63+
self.store.onAction(action)
64+
}
65+
66+
// Then
67+
XCTAssertTrue(result.isFailure)
68+
let error = try XCTUnwrap(result.failure)
69+
XCTAssertEqual(error as? NetworkError, .timeout)
70+
}
71+
}

0 commit comments

Comments
 (0)