From ee50f22ea6fe1cae1e5c681c73cfe561f7eabeb1 Mon Sep 17 00:00:00 2001 From: iamgabrielma Date: Fri, 20 Jun 2025 11:49:40 +0700 Subject: [PATCH 1/2] first pass remove domain purchase networking + yosemite --- .../Sources/Fakes/Networking.generated.swift | 19 - .../Networking/Remote/DomainRemote.swift | 390 ---------------- .../Networking/Remote/PaymentRemote.swift | 68 --- .../Yosemite/Actions/DomainAction.swift | 47 -- .../Sources/Yosemite/Stores/DomainStore.swift | 199 -------- .../Networking.xcodeproj/project.pbxproj | 4 - .../Remote/DomainRemoteTests.swift | 191 -------- .../Remote/PaymentRemoteTests.swift | 50 --- .../Responses/domain-contact-info.json | 15 - .../Responses/domain-products.json | 64 --- .../Responses/domain-suggestions-paid.json | 43 -- .../Responses/domain-suggestions.json | 12 - .../Responses/site-domains.json | 217 --------- .../validate-domain-contact-info-failure.json | 15 - .../validate-domain-contact-info-success.json | 3 - .../Classes/Analytics/WooAnalyticsStat.swift | 7 - .../Classes/Yosemite/AuthenticatedState.swift | 1 - Yosemite/Yosemite.xcodeproj/project.pbxproj | 8 - .../Networking/Remote/MockDomainRemote.swift | 118 ----- .../Networking/Remote/MockPaymentRemote.swift | 8 - .../Stores/DomainStoreTests.swift | 425 ------------------ 21 files changed, 1904 deletions(-) delete mode 100644 Modules/Sources/Networking/Remote/DomainRemote.swift delete mode 100644 Modules/Sources/Yosemite/Actions/DomainAction.swift delete mode 100644 Modules/Sources/Yosemite/Stores/DomainStore.swift delete mode 100644 Networking/NetworkingTests/Remote/DomainRemoteTests.swift delete mode 100644 Networking/NetworkingTests/Responses/domain-contact-info.json delete mode 100644 Networking/NetworkingTests/Responses/domain-products.json delete mode 100644 Networking/NetworkingTests/Responses/domain-suggestions-paid.json delete mode 100644 Networking/NetworkingTests/Responses/domain-suggestions.json delete mode 100644 Networking/NetworkingTests/Responses/site-domains.json delete mode 100644 Networking/NetworkingTests/Responses/validate-domain-contact-info-failure.json delete mode 100644 Networking/NetworkingTests/Responses/validate-domain-contact-info-success.json delete mode 100644 Yosemite/YosemiteTests/Mocks/Networking/Remote/MockDomainRemote.swift delete mode 100644 Yosemite/YosemiteTests/Stores/DomainStoreTests.swift diff --git a/Modules/Sources/Fakes/Networking.generated.swift b/Modules/Sources/Fakes/Networking.generated.swift index 18b1c872de9..7b9fe233b18 100644 --- a/Modules/Sources/Fakes/Networking.generated.swift +++ b/Modules/Sources/Fakes/Networking.generated.swift @@ -452,25 +452,6 @@ extension Networking.Customer { ) } } -extension Networking.DomainContactInfo { - /// Returns a "ready to use" type filled with fake values. - /// - public static func fake() -> Networking.DomainContactInfo { - .init( - firstName: .fake(), - lastName: .fake(), - organization: .fake(), - address1: .fake(), - address2: .fake(), - postcode: .fake(), - city: .fake(), - state: .fake(), - countryCode: .fake(), - phone: .fake(), - email: .fake() - ) - } -} extension Networking.DotcomSitePlugin { /// Returns a "ready to use" type filled with fake values. /// diff --git a/Modules/Sources/Networking/Remote/DomainRemote.swift b/Modules/Sources/Networking/Remote/DomainRemote.swift deleted file mode 100644 index f7f7006a3e4..00000000000 --- a/Modules/Sources/Networking/Remote/DomainRemote.swift +++ /dev/null @@ -1,390 +0,0 @@ -import Codegen -import Foundation - -/// Protocol for `DomainRemote` mainly used for mocking. -public protocol DomainRemoteProtocol { - /// Loads domain suggestions that are free (`*.wordpress.com` only) based on the query. - /// - Parameter query: What the domain suggestions are based on. - /// - Returns: The result of free domain suggestions. - func loadFreeDomainSuggestions(query: String) async throws -> [FreeDomainSuggestion] - - /// Loads domain suggestions that are not free based on the query. - /// - Parameter query: What the domain suggestions are based on. - /// - Returns: A list of paid domain suggestions. - func loadPaidDomainSuggestions(query: String) async throws -> [PaidDomainSuggestion] - - /// Loads the price information for a premium domain. - /// - Parameter domain: Name of a premium domain. - /// - Returns: Price information of a premium domain. - func loadPremiumDomainPrice(domain: String) async throws -> PremiumDomainPrice - - /// Loads WPCOM domain products for domain cost and sale info in `loadPaidDomainSuggestions`. - /// - Returns: A list of domain products. - func loadDomainProducts() async throws -> [DomainProduct] - - /// Loads all domains for a site. - /// - Parameter siteID: ID of the site to load the domains for. - /// - Returns: A list of domains. - func loadDomains(siteID: Int64) async throws -> [SiteDomain] - - /// Loads the contact info for domain registration. - /// - Returns: pre-existing contact info from WPCOM if available. - func loadDomainContactInfo() async throws -> DomainContactInfo - - /// Validates the contact info for domain registration. - /// - Parameters: - /// - domainContactInfo: Contact info to validate. - /// - domain: Domain name for domain registration. The validation rules vary between domains. - func validate(domainContactInfo: DomainContactInfo, domain: String) async throws -} - -/// Domain: Remote Endpoints -/// -public class DomainRemote: Remote, DomainRemoteProtocol { - public func loadFreeDomainSuggestions(query: String) async throws -> [FreeDomainSuggestion] { - let path = Path.domainSuggestions - let parameters: [String: Any] = [ - ParameterKey.query: query, - ParameterKey.quantity: Defaults.domainSuggestionsQuantity, - ParameterKey.wordPressDotComSubdomainsOnly: true - ] - let request = DotcomRequest(wordpressApiVersion: .mark1_1, method: .get, path: path, parameters: parameters) - return try await enqueue(request) - } - - public func loadPaidDomainSuggestions(query: String) async throws -> [PaidDomainSuggestion] { - let path = Path.domainSuggestions - let parameters: [String: Any] = [ - ParameterKey.query: query, - ParameterKey.quantity: Defaults.domainSuggestionsQuantity, - ParameterKey.dotcomDomainsIncluded: false, - ParameterKey.dotblogDomainsIncluded: false, - ParameterKey.vendor: "variation8_front" - ] - let request = DotcomRequest(wordpressApiVersion: .mark1_1, method: .get, path: path, parameters: parameters) - return try await enqueue(request) - } - - public func loadPremiumDomainPrice(domain: String) async throws -> PremiumDomainPrice { - let path = Path.premiumDomainPrice(domain: domain) - let request = DotcomRequest(wordpressApiVersion: .mark1_1, method: .get, path: path) - return try await enqueue(request) - } - - public func loadDomainProducts() async throws -> [DomainProduct] { - let path = Path.domainProducts - let parameters: [String: Any] = [ - ParameterKey.domainProductType: "domains" - ] - let request = DotcomRequest(wordpressApiVersion: .mark1_1, method: .get, path: path, parameters: parameters) - let productsByName: [String: DomainProduct] = try await enqueue(request) - return Array(productsByName.values) - } - - public func loadDomains(siteID: Int64) async throws -> [SiteDomain] { - let path = "sites/\(siteID)/\(Path.domains)" - let request = DotcomRequest(wordpressApiVersion: .mark1_1, method: .get, path: path) - let response: SiteDomainEnvelope = try await enqueue(request) - return response.domains - } - - public func loadDomainContactInfo() async throws -> DomainContactInfo { - let path = Path.domainContactInfo - let request = DotcomRequest(wordpressApiVersion: .mark1_1, method: .get, path: path) - return try await enqueue(request) - } - - public func validate(domainContactInfo: DomainContactInfo, domain: String) async throws { - let path = "\(Path.domainContactInfo)/validate" - let domainContactInfoDictionary = try domainContactInfo.toDictionary() - let parameters: [String: Any] = [ - ParameterKey.domainContactInfo: domainContactInfoDictionary, - ParameterKey.domainNames: domain - ] - let request = DotcomRequest(wordpressApiVersion: .mark1_1, method: .post, path: path, parameters: parameters) - let response: DomainContactInfoValidationResponse = try await enqueue(request) - guard response.success else { - throw DomainContactInfoError.invalid(messages: response.errorMessages) - } - } -} - -/// Necessary data for a free domain suggestion. -public struct FreeDomainSuggestion: Decodable, Equatable { - /// Domain name. - public let name: String - /// Theoretically `true` for all domains in the result, but the client side can still filter any exceptions in the UI. - public let isFree: Bool - - public init(name: String, isFree: Bool) { - self.name = name - self.isFree = isFree - } - - private enum CodingKeys: String, CodingKey { - case name = "domain_name" - case isFree = "is_free" - } -} - -/// Necessary data for a paid domain suggestion. -public struct PaidDomainSuggestion: Decodable, Equatable { - /// Domain name. - public let name: String - /// WPCOM product ID. - public let productID: Int64 - /// Whether there is privacy support. Used when creating a cart with a domain product. - public let supportsPrivacy: Bool - /// Whether the domain is a premium domain, which cannot be redeemed with a domain credit. - /// Non-premium domains don't have this field, thus this is marked as optional. - public let isPremium: Bool? - - public init(name: String, productID: Int64, supportsPrivacy: Bool, isPremium: Bool?) { - self.name = name - self.productID = productID - self.supportsPrivacy = supportsPrivacy - self.isPremium = isPremium - } - - private enum CodingKeys: String, CodingKey { - case name = "domain_name" - case productID = "product_id" - case supportsPrivacy = "supports_privacy" - case isPremium = "is_premium" - } -} - -/// Necessary data for a premium domain price. -public struct PremiumDomainPrice: Decodable, Equatable { - /// Cost value. - public let cost: Decimal - /// Optional sale cost value. - public let saleCost: Decimal? - /// Currency. - public let currency: String - - private enum CodingKeys: String, CodingKey { - case cost = "raw_price" - case saleCost = "sale_cost" - case currency = "currency_code" - } -} - -/// Necessary data for a WPCOM domain product. -public struct DomainProduct: Decodable, Equatable { - /// WPCOM product ID. - public let productID: Int64 - /// The duration of the product, localized on the backend (e.g. "year"). - public let term: String - /// Cost string including the currency. - public let cost: String - /// Optional sale cost string including the currency. - public let saleCost: String? - - private enum CodingKeys: String, CodingKey { - case productID = "product_id" - case term = "product_term" - case cost = "combined_cost_display" - case saleCost = "combined_sale_cost_display" - } -} - -/// Necessary data for a site's domain. -public struct SiteDomain: Decodable, Equatable { - /// Domain name. - public let name: String - - /// Whether the domain is the site's primary domain. - public let isPrimary: Bool - - /// Whether the domain is a free staging domain from certain WPCOM plans. - public let isWPCOMStagingDomain: Bool - - /// The type of domain, e.g. "wpcom" for WPCOM domains and "mapping" for other domains mapped to the WPCOM domains. - public let type: DomainType - - /// The next renewal date, if available. - public let renewalDate: Date? - - public init(name: String, isPrimary: Bool, isWPCOMStagingDomain: Bool, type: DomainType, renewalDate: Date? = nil) { - self.name = name - self.isPrimary = isPrimary - self.isWPCOMStagingDomain = isWPCOMStagingDomain - self.type = type - self.renewalDate = renewalDate - } - - /// Custom decoding implementation since `renewalDate` is an empty string instead of `null` when it's unavailable. - public init(from decoder: Decoder) throws { - let container = try decoder.container(keyedBy: CodingKeys.self) - let name = try container.decode(String.self, forKey: .name) - let isPrimary = try container.decode(Bool.self, forKey: .isPrimary) - let isWPCOMStagingDomain = try container.decode(Bool.self, forKey: .isWPCOMStagingDomain) - let type = try container.decode(DomainType.self, forKey: .type) - - let renewalDate: Date? = { - guard let dateString = try? container.decodeIfPresent(String.self, forKey: .renewalDate) else { - return nil - } - let dateFormatter = DateFormatter() - dateFormatter.dateFormat = "MMMM d, yyyy" - return dateFormatter.date(from: dateString) - }() - - self.init(name: name, isPrimary: isPrimary, isWPCOMStagingDomain: isWPCOMStagingDomain, type: type, renewalDate: renewalDate) - } - - private enum CodingKeys: String, CodingKey { - case name = "domain" - case isPrimary = "primary_domain" - case isWPCOMStagingDomain = "is_wpcom_staging_domain" - case type - case renewalDate = "auto_renewal_date" - } -} - -public extension SiteDomain { - /// The type of domain. Most often we filter domains by WPCOM and non-WPCOM domains. - enum DomainType: Decodable, Equatable { - case wpcom - case mapping - case other(type: String) - } -} - -extension SiteDomain.DomainType: RawRepresentable { - public init(rawValue: String) { - switch rawValue { - case Keys.wpcom: - self = .wpcom - case Keys.mapping: - self = .mapping - default: - self = .other(type: rawValue) - } - } - - public var rawValue: String { - switch self { - case .wpcom: return Keys.wpcom - case .mapping: return Keys.mapping - case .other(let type): return type - } - } - - private enum Keys { - static let wpcom = "wpcom" - static let mapping = "mapping" - } -} - -/// Contact info required for redeeming a domain with domain credit. -public struct DomainContactInfo: Codable, GeneratedFakeable, Equatable { - public let firstName: String - public let lastName: String - public let organization: String? - public let address1: String - public let address2: String? - public let postcode: String - public let city: String - public let state: String? - public let countryCode: String - public let phone: String? - public let email: String? - - public init(firstName: String, - lastName: String, - organization: String?, - address1: String, - address2: String?, - postcode: String, - city: String, - state: String?, - countryCode: String, - phone: String?, - email: String?) { - self.firstName = firstName - self.lastName = lastName - self.organization = organization - self.address1 = address1 - self.address2 = address2 - self.postcode = postcode - self.city = city - self.state = state - self.countryCode = countryCode - self.phone = phone - self.email = email - } - - private enum CodingKeys: String, CodingKey { - case firstName = "first_name" - case lastName = "last_name" - case organization - case address1 = "address_1" - case address2 = "address_2" - case postcode = "postal_code" - case city - case state - case countryCode = "country_code" - case phone - case email - } -} - -public enum DomainContactInfoError: Error, Equatable { - case invalid(messages: [String]?) -} - -/// Maps to a list of domains to match the API response. -private struct SiteDomainEnvelope: Decodable { - let domains: [SiteDomain] -} - -private struct DomainContactInfoValidationResponse: Decodable { - let success: Bool - let errorMessages: [String]? - - private enum CodingKeys: String, CodingKey { - case success - case errorMessages = "messages_simple" - } -} - -// MARK: - Constants -// -private extension DomainRemote { - enum Defaults { - static let domainSuggestionsQuantity = 20 - } - - enum ParameterKey { - /// Term (e.g "flowers") or domain name (e.g. "flowers.com") to search alternative domain names from. - static let query = "query" - /// Maximum number of suggestions to return. - static let quantity = "quantity" - /// Whether to restrict suggestions to only wordpress.com subdomains. If `true`, only `quantity` and `query` parameters are respected. - static let wordPressDotComSubdomainsOnly = "only_wordpressdotcom" - /// The type of WPCOM products. - static let domainProductType = "type" - /// Domain contact info parameter for validating contact info. - static let domainContactInfo = "contact_information" - /// Domain names parameter for validating contact info. - static let domainNames = "domain_names" - /// Whether or not to include wordpress.com subdomains. - static let dotcomDomainsIncluded = "include_wordpressdotcom" - /// Whether or not to include .blog subdomains. - static let dotblogDomainsIncluded = "include_dotblogsubdomain" - /// Suggestions vendor to use. - static let vendor = "vendor" - } - - enum Path { - static let domainSuggestions = "domains/suggestions" - static let domainProducts = "products" - static let domains = "domains" - static let domainContactInfo = "me/domain-contact-information" - static func premiumDomainPrice(domain: String) -> String { - "domains/\(domain)/price" - } - } -} diff --git a/Modules/Sources/Networking/Remote/PaymentRemote.swift b/Modules/Sources/Networking/Remote/PaymentRemote.swift index 6a04aa34cae..8858b22f53e 100644 --- a/Modules/Sources/Networking/Remote/PaymentRemote.swift +++ b/Modules/Sources/Networking/Remote/PaymentRemote.swift @@ -24,20 +24,6 @@ public protocol PaymentRemoteProtocol { /// - Returns: The remote response from creating a cart. func createCart(siteID: Int64, productID: Int64) async throws - /// Creates a cart with the given domain for the site ID. - /// - Parameters: - /// - siteID: The ID of the site that the domain is being mapped to. - /// - domain: The domain product to purchase. - /// - isTemporary: Whether the cart is temporary. - /// When the cart is being passed to a subsequent API request for checkout, this needs to be `true`. - /// When it's necessary to create a persistent cart for later checkout, this is set to `false`. The default value is `true`. - /// - Returns: The remote response from creating a cart. - func createCart(siteID: Int64, domain: DomainToPurchase, isTemporary: Bool) async throws -> CartResponse - - /// Checks out the given cart using domain credit as the payment method. - /// - Parameter cart: Cart generated from one of the `createCart` functions. - /// - Parameter contactInfo: Contact info for the domain that needs to be validated beforehand. - func checkoutCartWithDomainCredit(cart: CartResponse, contactInfo: DomainContactInfo) async throws } /// WPCOM Payment Endpoints @@ -87,44 +73,6 @@ public class PaymentRemote: Remote, PaymentRemoteProtocol { throw CreateCartError.productNotInCart } } - - public func createCart(siteID: Int64, domain: DomainToPurchase, isTemporary: Bool) async throws -> CartResponse { - let parameters: [String: Any] = [ - "products": [ - [ - "product_id": domain.productID, - "volume": 1, - "meta": domain.name, - "extra": [ - "privacy": domain.supportsPrivacy - ] - ] as [String: Any] - ], - "temporary": isTemporary - ] - let response: CartResponse = try await createCart(siteID: siteID, parameters: parameters, encoding: JSONEncoding.default) - - // Casting the values of `[String: Any]` to fixed-size integer types like `Int64` results in `nil`. - // https://stackoverflow.com/questions/36786883/swift-cast-any-object-to-int64-nil - guard let productsInCart = response["products"]?.value as? [[String: Any]], - productsInCart.contains(where: { ($0["product_id"] as? Int) == Int(domain.productID) }) else { - throw CreateCartError.productNotInCart - } - return response - } - - public func checkoutCartWithDomainCredit(cart: CartResponse, contactInfo: DomainContactInfo) async throws { - let path = "\(Path.cartCheckout)" - let cartDictionary = try cart.toDictionary() - let contactInformationDictionary = try contactInfo.toDictionary() - let parameters: [String: Any] = [ - "cart": cartDictionary, - "domain_details": contactInformationDictionary, - "payment": ["payment_method": PaymentMethod.credit.rawValue] - ] - let request = DotcomRequest(wordpressApiVersion: .mark1_1, method: .post, path: path, parameters: parameters, encoding: JSONEncoding.default) - let _: DomainCreditCheckoutCartResponse = try await enqueue(request) - } } private extension PaymentRemote { @@ -154,22 +102,6 @@ public struct WPComPlan: Decodable, Equatable { } } -/// Necessary data of a domain to create a cart. Contains a subset of properties of `PaidDomainSuggestion`. -public struct DomainToPurchase: Equatable { - /// Domain name. - public let name: String - /// WPCOM product ID. - public let productID: Int64 - /// Whether there is privacy support. Used when creating a cart with a domain product. - public let supportsPrivacy: Bool - - public init(name: String, productID: Int64, supportsPrivacy: Bool) { - self.name = name - self.productID = productID - self.supportsPrivacy = supportsPrivacy - } -} - /// Contains necessary data for a site's WPCOM plan. public struct WPComSitePlan: Equatable { /// ID of the WPCOM plan. diff --git a/Modules/Sources/Yosemite/Actions/DomainAction.swift b/Modules/Sources/Yosemite/Actions/DomainAction.swift deleted file mode 100644 index e283ea11aee..00000000000 --- a/Modules/Sources/Yosemite/Actions/DomainAction.swift +++ /dev/null @@ -1,47 +0,0 @@ -import Foundation -import class WooFoundation.CurrencySettings - -// MARK: - DomainAction: Defines all of the Actions supported by the DomainStore. -// -public enum DomainAction: Action { - case loadFreeDomainSuggestions(query: String, completion: (Result<[FreeDomainSuggestion], Error>) -> Void) - case loadPaidDomainSuggestions(query: String, currencySettings: CurrencySettings, completion: (Result<[PaidDomainSuggestion], Error>) -> Void) - case loadDomains(siteID: Int64, completion: (Result<[SiteDomain], Error>) -> Void) - case createDomainShoppingCart(siteID: Int64, - domain: DomainToPurchase, - completion: (Result) -> Void) - case redeemDomainCredit(siteID: Int64, - domain: DomainToPurchase, - contactInfo: DomainContactInfo, - completion: (Result) -> Void) - case loadDomainContactInfo(completion: (Result) -> Void) - case validate(domainContactInfo: DomainContactInfo, domain: String, completion: (Result) -> Void) -} - -/// Necessary data for the domain selector flow with paid domains. -public struct PaidDomainSuggestion: Equatable { - /// ID of the WPCOM product. - public let productID: Int64 - /// Whether there is privacy support. Used when creating a cart with a domain product. - public let supportsPrivacy: Bool - /// Domain name. - public let name: String - /// Duration of the product subscription (e.g. "year"), localized on the backend. - public let term: String - /// Cost string including the currency. - public let cost: String - /// Optional sale cost string including the currency. - public let saleCost: String? - /// Whether the domain is a premium domain. A premium domain cannot be redeemed with domain credit. - public let isPremium: Bool - - public init(productID: Int64, supportsPrivacy: Bool, name: String, term: String, cost: String, saleCost: String? = nil, isPremium: Bool) { - self.productID = productID - self.supportsPrivacy = supportsPrivacy - self.name = name - self.term = term - self.cost = cost - self.saleCost = saleCost - self.isPremium = isPremium - } -} diff --git a/Modules/Sources/Yosemite/Stores/DomainStore.swift b/Modules/Sources/Yosemite/Stores/DomainStore.swift deleted file mode 100644 index 4f9452b747d..00000000000 --- a/Modules/Sources/Yosemite/Stores/DomainStore.swift +++ /dev/null @@ -1,199 +0,0 @@ -import Foundation -import Networking -import WooFoundation -import protocol Storage.StorageManagerType - -/// Handles `DomainAction`. -/// -public final class DomainStore: Store { - // Keeps a strong reference to remotes to keep requests alive. - private let remote: DomainRemoteProtocol - private let paymentRemote: PaymentRemoteProtocol - - public init(dispatcher: Dispatcher, - storageManager: StorageManagerType, - network: Network, - remote: DomainRemoteProtocol, - paymentRemote: PaymentRemoteProtocol) { - self.remote = remote - self.paymentRemote = paymentRemote - super.init(dispatcher: dispatcher, storageManager: storageManager, network: network) - } - - public override convenience init(dispatcher: Dispatcher, storageManager: StorageManagerType, network: Network) { - let remote = DomainRemote(network: network) - let paymentRemote = PaymentRemote(network: network) - self.init(dispatcher: dispatcher, storageManager: storageManager, network: network, remote: remote, paymentRemote: paymentRemote) - } - - public override func registerSupportedActions(in dispatcher: Dispatcher) { - dispatcher.register(processor: self, for: DomainAction.self) - } - - /// Called whenever a given Action is dispatched. - /// - public override func onAction(_ action: Action) { - guard let action = action as? DomainAction else { - assertionFailure("DomainStore received an unsupported action: \(action)") - return - } - switch action { - case .loadFreeDomainSuggestions(let query, let completion): - loadFreeDomainSuggestions(query: query, completion: completion) - case .loadPaidDomainSuggestions(let query, let currencySettings, let completion): - loadPaidDomainSuggestions(query: query, currencySettings: currencySettings, completion: completion) - case .loadDomains(let siteID, let completion): - loadDomains(siteID: siteID, completion: completion) - case .createDomainShoppingCart(let siteID, let domain, let completion): - createDomainShoppingCart(siteID: siteID, domain: domain, completion: completion) - case .redeemDomainCredit(let siteID, let domain, let contactInfo, let completion): - redeemDomainCredit(siteID: siteID, domain: domain, contactInfo: contactInfo, completion: completion) - case .loadDomainContactInfo(let completion): - loadDomainContactInfo(completion: completion) - case .validate(let domainContactInfo, let domain, let completion): - validate(domainContactInfo: domainContactInfo, domain: domain, completion: completion) - } - } -} - -private extension DomainStore { - func loadFreeDomainSuggestions(query: String, completion: @escaping (Result<[FreeDomainSuggestion], Error>) -> Void) { - Task { @MainActor in - let result = await Result { try await remote.loadFreeDomainSuggestions(query: query) } - completion(result) - } - } - - func loadPaidDomainSuggestions(query: String, currencySettings: CurrencySettings, completion: @escaping (Result<[PaidDomainSuggestion], Error>) -> Void) { - Task { @MainActor in - do { - // Fetches domain products and domain suggestions at the same time. - async let domainProducts = remote.loadDomainProducts() - async let domainSuggestions = remote.loadPaidDomainSuggestions(query: query) - let domainProductsByID = try await domainProducts.reduce([Int64: DomainProduct](), { partialResult, product in - var productsByID = partialResult - productsByID[product.productID] = product - return productsByID - }) - - let suggestions = try await domainSuggestions - let pricesByPremiumDomainName = await loadPriceForPremiumDomains(suggestions) - let paidDomainSuggestions: [PaidDomainSuggestion] = suggestions.compactMap { domainSuggestion -> PaidDomainSuggestion? in - let productID = domainSuggestion.productID - guard let domainProduct = domainProductsByID[productID] else { - return nil - } - - if domainSuggestion.isPremium == true { - guard let price = pricesByPremiumDomainName[domainSuggestion.name] else { - return nil - } - let currencyFormatter = CurrencyFormatter(currencySettings: currencySettings) - return PaidDomainSuggestion(productID: domainSuggestion.productID, - supportsPrivacy: domainSuggestion.supportsPrivacy, - name: domainSuggestion.name, - term: domainProduct.term, - cost: currencyFormatter.formatAmount(price.cost, with: price.currency) ?? "", - saleCost: price.saleCost.map { currencyFormatter.formatAmount($0, with: price.currency) ?? "" }, - isPremium: true) - } else { - return PaidDomainSuggestion(productID: domainSuggestion.productID, - supportsPrivacy: domainSuggestion.supportsPrivacy, - name: domainSuggestion.name, - term: domainProduct.term, - cost: domainProduct.cost, - saleCost: domainProduct.saleCost, - isPremium: false) - } - } - completion(.success(paidDomainSuggestions)) - } catch { - completion(.failure(error)) - } - } - } - - /// Loads the price asynchronously for each premium domain in the domain suggestions. - /// - Returns: A dictionary that maps a domain name to its price. - func loadPriceForPremiumDomains(_ domains: [Networking.PaidDomainSuggestion]) async -> [String: PremiumDomainPrice] { - await withTaskGroup(of: (String, PremiumDomainPrice)?.self, returning: [String: PremiumDomainPrice].self) { group in - var pricesByDomainName: [String: PremiumDomainPrice] = [:] - - // For each domain suggestion, adds a new task to the group to load the price if the domain is a premium domain. - for domain in domains { - if domain.isPremium == true { - group.addTask { - do { - let price = try await self.remote.loadPremiumDomainPrice(domain: domain.name) - return (domain.name, price) - } catch { - // If the domain price fetching fails, we don't want to fail the whole domain suggestions request. - DDLogError("⛔️ Error loading the price for premium domain \(domain.name): \(error)") - return nil - } - } - } - } - - for await nameAndPrice in group.compactMap({ $0 }) { - pricesByDomainName[nameAndPrice.0] = nameAndPrice.1 - } - return pricesByDomainName - } - } - - func loadDomains(siteID: Int64, completion: @escaping (Result<[SiteDomain], Error>) -> Void) { - Task { @MainActor in - let result = await Result { try await remote.loadDomains(siteID: siteID) } - completion(result) - } - } - - func createDomainShoppingCart(siteID: Int64, - domain: DomainToPurchase, - completion: @escaping (Result) -> Void) { - Task { @MainActor in - let result = await Result { - try await paymentRemote.createCart(siteID: siteID, - domain: .init(name: domain.name, - productID: domain.productID, - supportsPrivacy: domain.supportsPrivacy), - isTemporary: false) - } - completion(result.map { _ in () }) - } - } - - func redeemDomainCredit(siteID: Int64, - domain: DomainToPurchase, - contactInfo: DomainContactInfo, - completion: @escaping (Result) -> Void) { - Task { @MainActor in - do { - let cart = try await paymentRemote.createCart(siteID: siteID, - domain: .init(name: domain.name, - productID: domain.productID, - supportsPrivacy: domain.supportsPrivacy), - isTemporary: true) - try await paymentRemote.checkoutCartWithDomainCredit(cart: cart, contactInfo: contactInfo) - completion(.success(())) - } catch { - completion(.failure(error)) - } - } - } - - func loadDomainContactInfo(completion: @escaping (Result) -> Void) { - Task { @MainActor in - let result = await Result { try await remote.loadDomainContactInfo() } - completion(result) - } - } - - func validate(domainContactInfo: DomainContactInfo, domain: String, completion: @escaping (Result) -> Void) { - Task { @MainActor in - let result = await Result { try await remote.validate(domainContactInfo: domainContactInfo, domain: domain) } - completion(result) - } - } -} diff --git a/Networking/Networking.xcodeproj/project.pbxproj b/Networking/Networking.xcodeproj/project.pbxproj index 697b6d6bf64..2b92041e881 100644 --- a/Networking/Networking.xcodeproj/project.pbxproj +++ b/Networking/Networking.xcodeproj/project.pbxproj @@ -11,7 +11,6 @@ 020D07C023D8587700FD9580 /* MediaRemoteTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 020D07BF23D8587700FD9580 /* MediaRemoteTests.swift */; }; 020D0C03291504DE00BB3DCE /* UnauthenticatedRequestTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 020D0C02291504DE00BB3DCE /* UnauthenticatedRequestTests.swift */; }; 0212683524C046CB00F8A892 /* MockNetwork+Path.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0212683424C046CB00F8A892 /* MockNetwork+Path.swift */; }; - 0239306B291A96F800B2632F /* DomainRemoteTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0239306A291A96F800B2632F /* DomainRemoteTests.swift */; }; 025CA2C6238F4F3500B05C81 /* ProductShippingClassRemoteTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 025CA2C5238F4F3500B05C81 /* ProductShippingClassRemoteTests.swift */; }; 025F9A252B020F1900B91F1D /* MockURLProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 025F9A242B020F1900B91F1D /* MockURLProtocol.swift */; }; 02616F8C292132800095BC00 /* SiteRemoteTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02616F8B292132800095BC00 /* SiteRemoteTests.swift */; }; @@ -247,7 +246,6 @@ 020D07BF23D8587700FD9580 /* MediaRemoteTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaRemoteTests.swift; sourceTree = ""; }; 020D0C02291504DE00BB3DCE /* UnauthenticatedRequestTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnauthenticatedRequestTests.swift; sourceTree = ""; }; 0212683424C046CB00F8A892 /* MockNetwork+Path.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MockNetwork+Path.swift"; sourceTree = ""; }; - 0239306A291A96F800B2632F /* DomainRemoteTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DomainRemoteTests.swift; sourceTree = ""; }; 025CA2C5238F4F3500B05C81 /* ProductShippingClassRemoteTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProductShippingClassRemoteTests.swift; sourceTree = ""; }; 025F9A242B020F1900B91F1D /* MockURLProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockURLProtocol.swift; sourceTree = ""; }; 02616F8B292132800095BC00 /* SiteRemoteTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SiteRemoteTests.swift; sourceTree = ""; }; @@ -574,7 +572,6 @@ DE34051E28BDFB0B00CF0D97 /* JetpackConnectionRemoteTests.swift */, 68BD37B228D9B8BD00C2A517 /* CustomerRemoteTests.swift */, 68F48B0E28E3BB850045C15B /* WCAnalyticsCustomerRemoteTests.swift */, - 0239306A291A96F800B2632F /* DomainRemoteTests.swift */, 02616F8B292132800095BC00 /* SiteRemoteTests.swift */, 02EF166D292F0C5800D90AD6 /* PaymentRemoteTests.swift */, DE2E8EAC295418D8002E4B14 /* WordPressSiteRemoteTests.swift */, @@ -987,7 +984,6 @@ 68F48B0F28E3BB850045C15B /* WCAnalyticsCustomerRemoteTests.swift in Sources */, EECDBEE029684AC500293C4E /* WordPressAPIVersionTests.swift in Sources */, 93D8BC01226BC20600AD2EB3 /* AccountSettingsRemoteTests.swift in Sources */, - 0239306B291A96F800B2632F /* DomainRemoteTests.swift in Sources */, 262E5AD5255ACD6F000B2416 /* PaymentGatewayListMapperTests.swift in Sources */, 03DCB7442624AD9B00C8953D /* CouponListMapperTests.swift in Sources */, AE2D6623272A8F6E004A2C3A /* TelemetryRemoteTests.swift in Sources */, diff --git a/Networking/NetworkingTests/Remote/DomainRemoteTests.swift b/Networking/NetworkingTests/Remote/DomainRemoteTests.swift deleted file mode 100644 index 0f2f5fe338c..00000000000 --- a/Networking/NetworkingTests/Remote/DomainRemoteTests.swift +++ /dev/null @@ -1,191 +0,0 @@ -import XCTest -import TestKit -@testable import Networking -@testable import NetworkingCore - -final class DomainRemoteTests: XCTestCase { - /// Mock network wrapper. - private var network: MockNetwork! - - override func setUp() { - super.setUp() - network = MockNetwork() - } - - override func tearDown() { - network = nil - super.tearDown() - } - - // MARK: - `loadFreeDomainSuggestions` - - func test_loadFreeDomainSuggestions_returns_suggestions_on_success() async throws { - // Given - let remote = DomainRemote(network: network) - network.simulateResponse(requestUrlSuffix: "domains/suggestions", filename: "domain-suggestions") - - // When - let suggestions = try await remote.loadFreeDomainSuggestions(query: "domain") - - // Then - XCTAssertEqual(suggestions, [ - .init(name: "domaintestingtips.wordpress.com", isFree: true), - .init(name: "domaintestingtoday.wordpress.com", isFree: true), - ]) - } - - func test_loadFreeDomainSuggestions_returns_error_on_empty_response() async throws { - // Given - let remote = DomainRemote(network: network) - - await assertThrowsError({_ = try await remote.loadFreeDomainSuggestions(query: "domain")}, errorAssert: { ($0 as? NetworkError) == .notFound() }) - } - - // MARK: - `loadPaidDomainSuggestions` - - func test_loadPaidDomainSuggestions_returns_suggestions_on_success() async throws { - // Given - let remote = DomainRemote(network: network) - network.simulateResponse(requestUrlSuffix: "domains/suggestions", filename: "domain-suggestions-paid") - - // When - let suggestions = try await remote.loadPaidDomainSuggestions(query: "domain") - - // Then - XCTAssertEqual(suggestions, [ - .init(name: "color.bar", productID: 356, supportsPrivacy: true, isPremium: nil), - .init(name: "color.ink", productID: 359, supportsPrivacy: true, isPremium: nil), - .init(name: "pizzas.blog", productID: 76, supportsPrivacy: true, isPremium: true) - ]) - } - - func test_loadPaidDomainSuggestions_returns_error_on_empty_response() async throws { - // Given - let remote = DomainRemote(network: network) - - await assertThrowsError({_ = try await remote.loadPaidDomainSuggestions(query: "domain")}, errorAssert: { ($0 as? NetworkError) == .notFound() }) - } - - // MARK: - `loadDomainProducts` - - func test_loadDomainProducts_returns_products_on_success() async throws { - // Given - let remote = DomainRemote(network: network) - network.simulateResponse(requestUrlSuffix: "products", filename: "domain-products") - - // When - // Products are in random order because of the product name mapping. - // They are sorted here to ensure the same order for unit testing. - let products = try await remote.loadDomainProducts().sorted(by: { $0.productID < $1.productID }) - - // Then - XCTAssertEqual(products, [ - .init(productID: 355, term: "year", cost: "US$15.00", saleCost: "US$3.90"), - .init(productID: 356, term: "year", cost: "US$60.00", saleCost: nil) - ]) - } - - func test_loadDomainProducts_returns_error_on_empty_response() async throws { - // Given - let remote = DomainRemote(network: network) - - await assertThrowsError({_ = try await remote.loadDomainProducts()}, errorAssert: { ($0 as? NetworkError) == .notFound() }) - } - - // MARK: - `loadDomains` - - func test_loadDomains_returns_domains_on_success() async throws { - // Given - let remote = DomainRemote(network: network) - network.simulateResponse(requestUrlSuffix: "domains", filename: "site-domains") - - // When - let domains = try await remote.loadDomains(siteID: 23) - - // Then - let dateFormatter = DateFormatter() - dateFormatter.dateFormat = "MMMM d, yyyy" - let renewalDate = try XCTUnwrap(dateFormatter.date(from: "December 10, 2023")) - assertEqual(domains, [ - .init(name: "crabparty.wpcomstaging.com", isPrimary: true, isWPCOMStagingDomain: true, type: .wpcom), - .init(name: "crabparty.com", isPrimary: false, isWPCOMStagingDomain: false, type: .mapping, renewalDate: renewalDate), - .init(name: "crabparty.wordpress.com", isPrimary: false, isWPCOMStagingDomain: false, type: .wpcom) - ]) - } - - func test_loadDomains_returns_error_on_empty_response() async throws { - // Given - let remote = DomainRemote(network: network) - - await assertThrowsError({_ = try await remote.loadDomains(siteID: 23)}, errorAssert: { ($0 as? NetworkError) == .notFound() }) - } - - // MARK: - `loadDomainContactInfo` - - func test_loadDomainContactInfo_returns_contact_info_on_success() async throws { - // Given - let remote = DomainRemote(network: network) - network.simulateResponse(requestUrlSuffix: "me/domain-contact-information", filename: "domain-contact-info") - - // When - let contactInfo = try await remote.loadDomainContactInfo() - - // Then - XCTAssertEqual(contactInfo, .init(firstName: "Woo", - lastName: "Merch", - organization: nil, - address1: "No 77", - address2: nil, - postcode: "94111", - city: "SF", - state: nil, - countryCode: "US", - phone: "+886.123456", - email: "woo@merch.com")) - } - - func test_loadDomainContactInfo_returns_error_on_empty_response() async throws { - // Given - let remote = DomainRemote(network: network) - - await assertThrowsError({ _ = try await remote.loadDomainContactInfo() }, errorAssert: { ($0 as? NetworkError) == .notFound() }) - } - - // MARK: - `validateDomainContactInfo` - - func test_validateDomainContactInfo_returns_contact_info_on_success() async throws { - // Given - let remote = DomainRemote(network: network) - network.simulateResponse(requestUrlSuffix: "domain-contact-information/validate", filename: "validate-domain-contact-info-success") - - // When - do { - try await remote.validate(domainContactInfo: .fake(), domain: "") - } catch { - // Then - XCTFail("Unexpected error: \(error)") - } - } - - func test_validateDomainContactInfo_returns_invalid_error_on_validation_failure() async throws { - // Given - let remote = DomainRemote(network: network) - network.simulateResponse(requestUrlSuffix: "domain-contact-information/validate", filename: "validate-domain-contact-info-failure") - - // When/Then - let error = DomainContactInfoError.invalid(messages: [ - "There was an error validating your contact information. The field \"Last Name\" is not valid.", - "There was an error validating your contact information. The field \"Phone\" is not valid." - ]) - await assertThrowsError({ _ = try await remote.validate(domainContactInfo: .fake(), domain: "") }, - errorAssert: { ($0 as? DomainContactInfoError) == error }) - } - - func test_validateDomainContactInfo_returns_error_on_empty_response() async throws { - // Given - let remote = DomainRemote(network: network) - - await assertThrowsError({_ = try await remote.validate(domainContactInfo: .fake(), domain: "")}, - errorAssert: { ($0 as? NetworkError) == .notFound() }) - } -} diff --git a/Networking/NetworkingTests/Remote/PaymentRemoteTests.swift b/Networking/NetworkingTests/Remote/PaymentRemoteTests.swift index 329095864ec..6d571e38c68 100644 --- a/Networking/NetworkingTests/Remote/PaymentRemoteTests.swift +++ b/Networking/NetworkingTests/Remote/PaymentRemoteTests.swift @@ -151,57 +151,7 @@ final class PaymentRemoteTests: XCTestCase { } } - // MARK: - `createCart` with a domain - - func test_createCartWithDomain_returns_on_success() async throws { - // Given - let siteID: Int64 = 606 - let remote = PaymentRemote(network: network) - network.simulateResponse(requestUrlSuffix: "me/shopping-cart/\(siteID)", filename: "create-doman-cart-success") - - // When - do { - let response = try await remote.createCart(siteID: siteID, - domain: .init(name: "fun.toys", productID: 254, supportsPrivacy: true), - isTemporary: false) - // Then - XCTAssertFalse(response.values.isEmpty) - } catch { - // Then - XCTFail("Unexpected error: \(error)") - } - } - - func test_createCartWithDomain_throws_productNotInCart_error_when_response_does_not_include_domain_product_id() async throws { - // Given - let siteID: Int64 = 606 - let remote = PaymentRemote(network: network) - network.simulateResponse(requestUrlSuffix: "me/shopping-cart/\(siteID)", filename: "create-doman-cart-success") - - // When - await assertThrowsError { - _ = try await remote.createCart(siteID: siteID, domain: .init(name: "fun.toys", productID: 685, supportsPrivacy: true), isTemporary: false) - } errorAssert: { error in - // Then - (error as? CreateCartError) == .productNotInCart - } - } - - func test_createCartWithDomain_throws_notFound_error_when_no_response() async throws { - // Given - let remote = PaymentRemote(network: network) - - // When - await assertThrowsError { - _ = try await remote.createCart(siteID: 606, domain: .init(name: "fun.toys", productID: 254, supportsPrivacy: true), isTemporary: false) - } errorAssert: { error in - // Then - (error as? NetworkError) == .notFound() - } - } - // MARK: - `checkoutCartWithDomainCredit` with a domain - func test_checkoutCartWithDomainCredit_returns_on_success() async throws { // Given let remote = PaymentRemote(network: network) diff --git a/Networking/NetworkingTests/Responses/domain-contact-info.json b/Networking/NetworkingTests/Responses/domain-contact-info.json deleted file mode 100644 index a1c9379bf5b..00000000000 --- a/Networking/NetworkingTests/Responses/domain-contact-info.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "first_name": "Woo", - "last_name": "Merch", - "organization": null, - "address_1": "No 77", - "address_2": null, - "postal_code": "94111", - "city": "SF", - "state": null, - "country_code": "US", - "email": "woo@merch.com", - "phone": "+886.123456", - "fax": null, - "extra": null -} diff --git a/Networking/NetworkingTests/Responses/domain-products.json b/Networking/NetworkingTests/Responses/domain-products.json deleted file mode 100644 index 26bcfeb1769..00000000000 --- a/Networking/NetworkingTests/Responses/domain-products.json +++ /dev/null @@ -1,64 +0,0 @@ -{ - "dotart_domain": { - "product_id": 355, - "product_name": ".art Domain Registration", - "product_slug": "dotart_domain", - "description": "", - "product_type": "domain_reg", - "available": true, - "billing_product_slug": "wp-dot-art-registration", - "is_domain_registration": true, - "cost_display": "US$2.00", - "combined_cost_display": "US$15.00", - "cost": 2, - "cost_smallest_unit": 200, - "currency_code": "USD", - "price_tier_list": [], - "price_tier_usage_quantity": null, - "product_term": "year", - "price_tiers": [], - "price_tier_slug": "", - "tld": "art", - "is_privacy_protection_product_purchase_allowed": true, - "sale_cost": 3.9, - "combined_sale_cost_display": "US$3.90", - "sale_coupon": { - "start_date": "2022-12-01 00:01:00", - "expires": "2023-03-31 00:00:00", - "discount": 74, - "purchase_types": [ - 3 - ], - "product_ids": [ - 355 - ], - "allowed_for_domain_transfers": false, - "allowed_for_renewals": false, - "allowed_for_new_purchases": true, - "code": "7ea7af1f76879264", - "tld_rank": null - } - }, - "dotbar_domain": { - "product_id": 356, - "product_name": ".bar Domain Registration", - "product_slug": "dotbar_domain", - "description": "", - "product_type": "domain_reg", - "available": true, - "billing_product_slug": "wp-dot-bar-registration", - "is_domain_registration": true, - "cost_display": "US$47.00", - "combined_cost_display": "US$60.00", - "cost": 47, - "cost_smallest_unit": 4700, - "currency_code": "USD", - "price_tier_list": [], - "price_tier_usage_quantity": null, - "product_term": "year", - "price_tiers": [], - "price_tier_slug": "", - "tld": "bar", - "is_privacy_protection_product_purchase_allowed": true - } -} diff --git a/Networking/NetworkingTests/Responses/domain-suggestions-paid.json b/Networking/NetworkingTests/Responses/domain-suggestions-paid.json deleted file mode 100644 index 78b4c9f593a..00000000000 --- a/Networking/NetworkingTests/Responses/domain-suggestions-paid.json +++ /dev/null @@ -1,43 +0,0 @@ -[ - { - "domain_name": "color.bar", - "relevance": 0.33, - "supports_privacy": true, - "vendor": "donuts", - "match_reasons": [ - "exact-match" - ], - "product_id": 356, - "product_slug": "dotbar_domain", - "cost": "US$60.00", - "raw_price": 60, - "currency_code": "USD" - }, - { - "domain_name": "color.ink", - "relevance": 0.33, - "supports_privacy": true, - "vendor": "donuts", - "match_reasons": [ - "exact-match" - ], - "product_id": 359, - "product_slug": "dotink_domain", - "cost": "US$25.00", - "raw_price": 25, - "currency_code": "USD" - }, - { - "domain_name": "pizzas.blog", - "relevance": 0.99, - "supports_privacy": true, - "vendor": "donuts", - "is_premium": true, - "match_reasons": [ - "tld-common", - "similar-match" - ], - "product_id": 76, - "product_slug": "dotblog_domain" - } -] diff --git a/Networking/NetworkingTests/Responses/domain-suggestions.json b/Networking/NetworkingTests/Responses/domain-suggestions.json deleted file mode 100644 index 32075e6919e..00000000000 --- a/Networking/NetworkingTests/Responses/domain-suggestions.json +++ /dev/null @@ -1,12 +0,0 @@ -[ - { - "domain_name": "domaintestingtips.wordpress.com", - "cost": "Free", - "is_free": true - }, - { - "domain_name": "domaintestingtoday.wordpress.com", - "cost": "Free", - "is_free": true - } -] diff --git a/Networking/NetworkingTests/Responses/site-domains.json b/Networking/NetworkingTests/Responses/site-domains.json deleted file mode 100644 index 6f6087e2cdd..00000000000 --- a/Networking/NetworkingTests/Responses/site-domains.json +++ /dev/null @@ -1,217 +0,0 @@ -{ - "domains": [ - { - "primary_domain": true, - "blog_id": 2023, - "subscription_id": null, - "can_manage_dns_records": false, - "can_manage_name_servers": false, - "can_update_contact_info": false, - "cannot_manage_dns_records_reason": null, - "cannot_manage_name_servers_reason": null, - "cannot_update_contact_info_reason": null, - "connection_mode": null, - "current_user_can_add_email": false, - "current_user_can_create_site_from_domain_only": true, - "current_user_cannot_add_email_reason": null, - "current_user_can_manage": true, - "current_user_is_owner": null, - "can_set_as_primary": true, - "domain": "crabparty.wpcomstaging.com", - "domain_notice_states": null, - "supports_domain_connect": null, - "email_forwards_count": 0, - "expiry": false, - "expiry_soon": false, - "expired": false, - "auto_renewing": false, - "pending_registration": false, - "pending_registration_time": "", - "has_registration": false, - "has_email_forward_dns_records": null, - "points_to_wpcom": true, - "privacy_available": false, - "private_domain": false, - "partner_domain": false, - "wpcom_domain": true, - "has_zone": false, - "is_renewable": false, - "is_redeemable": false, - "is_subdomain": true, - "is_eligible_for_inbound_transfer": false, - "is_locked": false, - "is_wpcom_staging_domain": true, - "transfer_away_eligible_at": null, - "type": "wpcom", - "registration_date": "", - "auto_renewal_date": "", - "google_apps_subscription": null, - "titan_mail_subscription": null, - "pending_whois_update": false, - "tld_maintenance_end_time": null, - "ssl_status": null, - "supports_gdpr_consent_management": false, - "supports_transfer_approval": false, - "domain_registration_agreement_url": "", - "contact_info_disclosure_available": false, - "contact_info_disclosed": false, - "renewable_until": null, - "redeemable_until": null, - "bundled_plan_subscription_id": null, - "product_slug": null, - "owner": "", - "pending_renewal": false, - "aftermarket_auction": false, - "aftermarket_auction_start": null, - "aftermarket_auction_end": null - }, - { - "primary_domain": false, - "blog_id": 2023, - "subscription_id": "20023245", - "can_manage_dns_records": true, - "can_manage_name_servers": true, - "can_update_contact_info": true, - "cannot_manage_dns_records_reason": null, - "cannot_manage_name_servers_reason": null, - "cannot_update_contact_info_reason": null, - "connection_mode": null, - "current_user_can_add_email": true, - "current_user_can_create_site_from_domain_only": false, - "current_user_cannot_add_email_reason": null, - "current_user_can_manage": true, - "current_user_is_owner": true, - "can_set_as_primary": true, - "domain": "crabparty.com", - "domain_notice_states": null, - "supports_domain_connect": null, - "email_forwards_count": 0, - "expiry": "January 9, 2024", - "expiry_soon": false, - "expired": false, - "auto_renewing": 1, - "pending_registration": false, - "pending_registration_time": "", - "has_registration": true, - "has_email_forward_dns_records": null, - "points_to_wpcom": false, - "privacy_available": true, - "private_domain": false, - "partner_domain": false, - "wpcom_domain": false, - "has_zone": true, - "is_renewable": true, - "is_redeemable": false, - "is_subdomain": false, - "is_eligible_for_inbound_transfer": true, - "is_locked": true, - "is_wpcom_staging_domain": false, - "transfer_away_eligible_at": "2023-03-10 04:11:04", - "type": "mapping", - "registration_date": "January 9, 2023", - "auto_renewal_date": "December 10, 2023", - "google_apps_subscription": { - "status": "no_subscription", - "is_eligible_for_introductory_offer": false - }, - "titan_mail_subscription": { - "status": "no_subscription", - "is_eligible_for_introductory_offer": true - }, - "pending_whois_update": false, - "tld_maintenance_end_time": 0, - "ssl_status": "pending", - "supports_gdpr_consent_management": false, - "supports_transfer_approval": true, - "domain_registration_agreement_url": "https://wordpress.com/automattic-domain-name-registration-agreement/", - "contact_info_disclosure_available": true, - "contact_info_disclosed": false, - "renewable_until": "February 21, 2024", - "redeemable_until": null, - "bundled_plan_subscription_id": null, - "product_slug": "domain_reg", - "owner": "Jaclyn Chen (wasseryi)", - "pending_renewal": false, - "aftermarket_auction": false, - "aftermarket_auction_start": null, - "aftermarket_auction_end": null, - "has_private_registration": false, - "is_pending_icann_verification": true, - "manual_transfer_required": false, - "is_icann_verification_suspended": false, - "registrar": "KS_RAM", - "domain_locking_available": true, - "is_premium": false, - "transfer_lock_on_whois_update_optional": true, - "whois_update_unmodifiable_fields": [], - "is_whois_editable": true, - "pending_transfer": false, - "has_wpcom_nameservers": true - }, - { - "primary_domain": false, - "blog_id": 2023, - "subscription_id": null, - "can_manage_dns_records": false, - "can_manage_name_servers": false, - "can_update_contact_info": false, - "cannot_manage_dns_records_reason": null, - "cannot_manage_name_servers_reason": null, - "cannot_update_contact_info_reason": null, - "connection_mode": null, - "current_user_can_add_email": false, - "current_user_can_create_site_from_domain_only": true, - "current_user_cannot_add_email_reason": null, - "current_user_can_manage": true, - "current_user_is_owner": null, - "can_set_as_primary": true, - "domain": "crabparty.wordpress.com", - "domain_notice_states": null, - "supports_domain_connect": null, - "email_forwards_count": 0, - "expiry": false, - "expiry_soon": false, - "expired": false, - "auto_renewing": false, - "pending_registration": false, - "pending_registration_time": "", - "has_registration": false, - "has_email_forward_dns_records": null, - "points_to_wpcom": true, - "privacy_available": false, - "private_domain": false, - "partner_domain": false, - "wpcom_domain": true, - "has_zone": false, - "is_renewable": false, - "is_redeemable": false, - "is_subdomain": true, - "is_eligible_for_inbound_transfer": false, - "is_locked": false, - "is_wpcom_staging_domain": false, - "transfer_away_eligible_at": null, - "type": "wpcom", - "registration_date": "", - "auto_renewal_date": "", - "google_apps_subscription": null, - "titan_mail_subscription": null, - "pending_whois_update": false, - "tld_maintenance_end_time": null, - "ssl_status": null, - "supports_gdpr_consent_management": false, - "supports_transfer_approval": false, - "domain_registration_agreement_url": "", - "contact_info_disclosure_available": false, - "contact_info_disclosed": false, - "renewable_until": null, - "redeemable_until": null, - "bundled_plan_subscription_id": null, - "product_slug": null, - "owner": "", - "pending_renewal": false, - "aftermarket_auction": false, - "aftermarket_auction_start": null, - "aftermarket_auction_end": null - } - ] -} diff --git a/Networking/NetworkingTests/Responses/validate-domain-contact-info-failure.json b/Networking/NetworkingTests/Responses/validate-domain-contact-info-failure.json deleted file mode 100644 index da20fa848c0..00000000000 --- a/Networking/NetworkingTests/Responses/validate-domain-contact-info-failure.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "success": false, - "messages": { - "last_name": [ - "Enter your last name." - ], - "phone": [ - "Enter a valid country code followed by a dot (for example +1.6285550199)." - ] - }, - "messages_simple": [ - "There was an error validating your contact information. The field \"Last Name\" is not valid.", - "There was an error validating your contact information. The field \"Phone\" is not valid." - ] -} diff --git a/Networking/NetworkingTests/Responses/validate-domain-contact-info-success.json b/Networking/NetworkingTests/Responses/validate-domain-contact-info-success.json deleted file mode 100644 index 33c0c847e8a..00000000000 --- a/Networking/NetworkingTests/Responses/validate-domain-contact-info-success.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "success": true -} diff --git a/WooCommerce/Classes/Analytics/WooAnalyticsStat.swift b/WooCommerce/Classes/Analytics/WooAnalyticsStat.swift index 8ab003392c5..8f25c48bb96 100644 --- a/WooCommerce/Classes/Analytics/WooAnalyticsStat.swift +++ b/WooCommerce/Classes/Analytics/WooAnalyticsStat.swift @@ -348,13 +348,6 @@ enum WooAnalyticsStat: String { case notificationSettingsSavingSuccess = "notification_settings_saving_success" case notificationSettingsSavingFailed = "notification_settings_saving_failed" - // MARK: Domain Settings - // - case domainSettingsStep = "custom_domains_step" - case domainContactInfoValidationFailed = "domain_contact_info_validation_failed" - case domainSettingsCustomDomainPurchaseSuccess = "custom_domain_purchase_success" - case domainSettingsCustomDomainPurchaseFailed = "custom_domain_purchase_failed" - // MARK: Card Reader Connection Events // case cardReaderSelectTypeShown = "card_present_select_reader_type_shown" diff --git a/WooCommerce/Classes/Yosemite/AuthenticatedState.swift b/WooCommerce/Classes/Yosemite/AuthenticatedState.swift index f9672e09c89..ed1e45a7a2a 100644 --- a/WooCommerce/Classes/Yosemite/AuthenticatedState.swift +++ b/WooCommerce/Classes/Yosemite/AuthenticatedState.swift @@ -40,7 +40,6 @@ class AuthenticatedState: StoresManagerState { CouponStore(dispatcher: dispatcher, storageManager: storageManager, network: network), CustomerStore(dispatcher: dispatcher, storageManager: storageManager, network: network), DataStore(dispatcher: dispatcher, storageManager: storageManager, network: network), - DomainStore(dispatcher: dispatcher, storageManager: storageManager, network: network), FeatureFlagStore(dispatcher: dispatcher, storageManager: storageManager, network: network), InAppPurchaseStore(dispatcher: dispatcher, storageManager: storageManager, network: network), InboxNotesStore(dispatcher: dispatcher, storageManager: storageManager, network: network), diff --git a/Yosemite/Yosemite.xcodeproj/project.pbxproj b/Yosemite/Yosemite.xcodeproj/project.pbxproj index cc4ca6e42d2..3df0e0f2466 100644 --- a/Yosemite/Yosemite.xcodeproj/project.pbxproj +++ b/Yosemite/Yosemite.xcodeproj/project.pbxproj @@ -43,8 +43,6 @@ 029B00A7230D64E800B0AE66 /* StatsTimeRangeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 029B00A6230D64E800B0AE66 /* StatsTimeRangeTests.swift */; }; 02A26F1E2744FE97008E4EDB /* MockAccountRemote.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02A26F1D2744FE97008E4EDB /* MockAccountRemote.swift */; }; 02AB40802784176600929CF3 /* TopEarnerStatsItem+ComparableTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02AB407F2784176600929CF3 /* TopEarnerStatsItem+ComparableTests.swift */; }; - 02DAE7F8291A9F11009342B7 /* DomainStoreTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02DAE7F7291A9F11009342B7 /* DomainStoreTests.swift */; }; - 02DAE7FA291A9F36009342B7 /* MockDomainRemote.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02DAE7F9291A9F36009342B7 /* MockDomainRemote.swift */; }; 02DF98092A136BFB0009E2EA /* MockSitePluginsRemote.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02DF98082A136BFB0009E2EA /* MockSitePluginsRemote.swift */; }; 02E262C0238CE80100B79588 /* StorageShippingSettingsServiceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02E262BF238CE80100B79588 /* StorageShippingSettingsServiceTests.swift */; }; 02E3B62A290622DE007E0F13 /* AccountCreationStoreTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02E3B629290622DE007E0F13 /* AccountCreationStoreTests.swift */; }; @@ -235,8 +233,6 @@ 029B00A6230D64E800B0AE66 /* StatsTimeRangeTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatsTimeRangeTests.swift; sourceTree = ""; }; 02A26F1D2744FE97008E4EDB /* MockAccountRemote.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockAccountRemote.swift; sourceTree = ""; }; 02AB407F2784176600929CF3 /* TopEarnerStatsItem+ComparableTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TopEarnerStatsItem+ComparableTests.swift"; sourceTree = ""; }; - 02DAE7F7291A9F11009342B7 /* DomainStoreTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DomainStoreTests.swift; sourceTree = ""; }; - 02DAE7F9291A9F36009342B7 /* MockDomainRemote.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockDomainRemote.swift; sourceTree = ""; }; 02DF98082A136BFB0009E2EA /* MockSitePluginsRemote.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockSitePluginsRemote.swift; sourceTree = ""; }; 02E262BF238CE80100B79588 /* StorageShippingSettingsServiceTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StorageShippingSettingsServiceTests.swift; sourceTree = ""; }; 02E3B629290622DE007E0F13 /* AccountCreationStoreTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountCreationStoreTests.swift; sourceTree = ""; }; @@ -560,7 +556,6 @@ D4CBAE5F26D440FA00BBE6D1 /* MockAnnouncementsRemote.swift */, 02A26F1D2744FE97008E4EDB /* MockAccountRemote.swift */, 029249E7274B8AEE002E9C34 /* MockMediaRemote.swift */, - 02DAE7F9291A9F36009342B7 /* MockDomainRemote.swift */, 02616F932921E1CD0095BC00 /* MockSiteRemote.swift */, 02F2722E292F18FD00C36419 /* MockPaymentRemote.swift */, EEB4E2CC29B04CE900371C3C /* MockStoreOnboardingTasksRemote.swift */, @@ -666,7 +661,6 @@ DE50296628C7114800551736 /* JetpackConnectionStoreTests.swift */, 68BD37B828DB323D00C2A517 /* CustomerStoreTests.swift */, 02E3B629290622DE007E0F13 /* AccountCreationStoreTests.swift */, - 02DAE7F7291A9F11009342B7 /* DomainStoreTests.swift */, 02616F912921E1530095BC00 /* SiteStoreTests.swift */, 02F2722C292F18BF00C36419 /* PaymentStoreTests.swift */, DE2E8EAE29541C32002E4B14 /* WordPressSiteStoreTests.swift */, @@ -922,7 +916,6 @@ 206BFD582DF31432000BD68E /* POSProductOrVariationResolverTests.swift in Sources */, 025CA2D0238F54E800B05C81 /* ProductShippingClassStoreTests.swift in Sources */, 74A7688E20D45ED400F9D437 /* OrderStoreTests.swift in Sources */, - 02DAE7F8291A9F11009342B7 /* DomainStoreTests.swift in Sources */, DED91DF62AD67F8F00CDCC53 /* MockBlazeRemote.swift in Sources */, 20BCF6F52B0E57AB00954840 /* MockSystemStatusService.swift in Sources */, D8652E322630741000350F37 /* PaymentIntent+ReceiptParametersTests.swift in Sources */, @@ -1020,7 +1013,6 @@ 02FF056D23DEDCB90058E6E7 /* MockImageSourceWriter.swift in Sources */, 02F2722F292F18FD00C36419 /* MockPaymentRemote.swift in Sources */, FE28F6F2268462A6004465C7 /* UserStoreTests.swift in Sources */, - 02DAE7FA291A9F36009342B7 /* MockDomainRemote.swift in Sources */, 741F34842195F752005F5BD9 /* CommentStoreTests.swift in Sources */, B5C9DE282087FF20006B910A /* MockSiteStore.swift in Sources */, 20F616462CF4B4E500F9FA2A /* POSOrderServiceTests.swift in Sources */, diff --git a/Yosemite/YosemiteTests/Mocks/Networking/Remote/MockDomainRemote.swift b/Yosemite/YosemiteTests/Mocks/Networking/Remote/MockDomainRemote.swift deleted file mode 100644 index bf0f3dcf930..00000000000 --- a/Yosemite/YosemiteTests/Mocks/Networking/Remote/MockDomainRemote.swift +++ /dev/null @@ -1,118 +0,0 @@ -import Networking -import XCTest - -/// Mock for `DomainRemote`. -/// -final class MockDomainRemote { - /// The results to return in `loadFreeDomainSuggestions`. - private var loadDomainSuggestionsResult: Result<[FreeDomainSuggestion], Error>? - - /// The results to return in `loadPaidDomainSuggestions`. - private var loadPaidDomainSuggestionsResult: Result<[PaidDomainSuggestion], Error>? - - /// The results to return in `loadPremiumDomainPrice`. - private var loadPremiumDomainPriceResult: [String: PremiumDomainPrice] = [:] - - /// The results to return in `loadDomainProducts`. - private var loadDomainProductsResult: Result<[DomainProduct], Error>? - - /// The results to return in `loadDomains`. - private var loadDomainsResult: Result<[SiteDomain], Error>? - - /// The results to return in `loadDomainContactInfo`. - private var loadDomainContactInfoResult: Result? - - /// The results to return in `validateDomainContactInfo`. - private var validateDomainContactInfoResult: Result? - - /// Returns the value when `loadDomainSuggestions` is called. - func whenLoadingDomainSuggestions(thenReturn result: Result<[FreeDomainSuggestion], Error>) { - loadDomainSuggestionsResult = result - } - - /// Returns the value when `loadPaidDomainSuggestions` is called. - func whenLoadingPaidDomainSuggestions(thenReturn result: Result<[PaidDomainSuggestion], Error>) { - loadPaidDomainSuggestionsResult = result - } - - func whenLoadingPremiumDomainPrice(domain: String, thenReturn price: PremiumDomainPrice) { - loadPremiumDomainPriceResult[domain] = price - } - - /// Returns the value when `loadDomainProducts` is called. - func whenLoadingDomainProducts(thenReturn result: Result<[DomainProduct], Error>) { - loadDomainProductsResult = result - } - - /// Returns the value when `loadDomains` is called. - func whenLoadingDomains(thenReturn result: Result<[SiteDomain], Error>) { - loadDomainsResult = result - } - - /// Returns the value when `loadDomainContactInfo` is called. - func whenLoadingDomainContactInfo(thenReturn result: Result) { - loadDomainContactInfoResult = result - } - - /// Returns the value when `validateDomainContactInfo` is called. - func whenValidatingDomainContactInfo(thenReturn result: Result) { - validateDomainContactInfoResult = result - } -} - -extension MockDomainRemote: DomainRemoteProtocol { - func loadFreeDomainSuggestions(query: String) async throws -> [FreeDomainSuggestion] { - guard let result = loadDomainSuggestionsResult else { - XCTFail("Could not find result for loading domain suggestions.") - throw NetworkError.notFound() - } - return try result.get() - } - - func loadPaidDomainSuggestions(query: String) async throws -> [PaidDomainSuggestion] { - guard let result = loadPaidDomainSuggestionsResult else { - XCTFail("Could not find result for loading domain suggestions.") - throw NetworkError.notFound() - } - return try result.get() - } - - func loadPremiumDomainPrice(domain: String) async throws -> PremiumDomainPrice { - guard let price = loadPremiumDomainPriceResult[domain] else { - throw NetworkError.notFound() - } - return price - } - - func loadDomainProducts() async throws -> [DomainProduct] { - guard let result = loadDomainProductsResult else { - XCTFail("Could not find result for loading domain products.") - throw NetworkError.notFound() - } - return try result.get() - } - - func loadDomains(siteID: Int64) async throws -> [SiteDomain] { - guard let result = loadDomainsResult else { - XCTFail("Could not find result for loading domains.") - throw NetworkError.notFound() - } - return try result.get() - } - - func loadDomainContactInfo() async throws -> DomainContactInfo { - guard let result = loadDomainContactInfoResult else { - XCTFail("Could not find result for loading domain contact info.") - throw NetworkError.notFound() - } - return try result.get() - } - - func validate(domainContactInfo: DomainContactInfo, domain: String) async throws { - guard let result = validateDomainContactInfoResult else { - XCTFail("Could not find result for validating domain contact info.") - throw NetworkError.notFound() - } - return try result.get() - } -} diff --git a/Yosemite/YosemiteTests/Mocks/Networking/Remote/MockPaymentRemote.swift b/Yosemite/YosemiteTests/Mocks/Networking/Remote/MockPaymentRemote.swift index a983330b858..444d98f1c91 100644 --- a/Yosemite/YosemiteTests/Mocks/Networking/Remote/MockPaymentRemote.swift +++ b/Yosemite/YosemiteTests/Mocks/Networking/Remote/MockPaymentRemote.swift @@ -70,14 +70,6 @@ extension MockPaymentRemote: PaymentRemoteProtocol { return try result.get() } - func createCart(siteID: Int64, domain: DomainToPurchase, isTemporary: Bool) async throws -> CartResponse { - guard let result = createDomainCartResult else { - XCTFail("Could not find result for creating a domain cart.") - throw NetworkError.notFound() - } - return try result.get() - } - func checkoutCartWithDomainCredit(cart: CartResponse, contactInfo: DomainContactInfo) async throws { guard let result = checkoutCartWithDomainCreditResult else { XCTFail("Could not find result for checking out a cart with domain credit.") diff --git a/Yosemite/YosemiteTests/Stores/DomainStoreTests.swift b/Yosemite/YosemiteTests/Stores/DomainStoreTests.swift deleted file mode 100644 index 4c4133d8afa..00000000000 --- a/Yosemite/YosemiteTests/Stores/DomainStoreTests.swift +++ /dev/null @@ -1,425 +0,0 @@ -import XCTest -import class WooFoundation.CurrencySettings -@testable import Networking -@testable import Yosemite - -final class DomainStoreTests: XCTestCase { - /// Mock Dispatcher. - private var dispatcher: Dispatcher! - - /// Mock Storage: InMemory. - private var storageManager: MockStorageManager! - - /// Mock Network: Allows us to inject predefined responses. - private var network: MockNetwork! - - private var remote: MockDomainRemote! - private var paymentRemote: MockPaymentRemote! - private var store: DomainStore! - - override func setUp() { - super.setUp() - dispatcher = Dispatcher() - storageManager = MockStorageManager() - network = MockNetwork() - remote = MockDomainRemote() - paymentRemote = MockPaymentRemote() - store = DomainStore(dispatcher: dispatcher, - storageManager: storageManager, - network: network, - remote: remote, - paymentRemote: paymentRemote) - } - - override func tearDown() { - store = nil - remote = nil - paymentRemote = nil - network = nil - storageManager = nil - dispatcher = nil - super.tearDown() - } - - // MARK: - `loadFreeDomainSuggestions` - - func test_loadFreeDomainSuggestions_returns_suggestions_on_success() throws { - // Given - remote.whenLoadingDomainSuggestions(thenReturn: .success([.init(name: "freedomaintesting", isFree: false)])) - - // When - let result: Result<[FreeDomainSuggestion], Error> = waitFor { promise in - let action = DomainAction.loadFreeDomainSuggestions(query: "domain") { result in - promise(result) - } - self.store.onAction(action) - } - - // Then - XCTAssertTrue(result.isSuccess) - let suggestions = try XCTUnwrap(result.get()) - XCTAssertEqual(suggestions, [.init(name: "freedomaintesting", isFree: false)]) - } - - func test_loadFreeDomainSuggestions_returns_error_on_failure() throws { - // Given - remote.whenLoadingDomainSuggestions(thenReturn: .failure(NetworkError.timeout())) - - // When - let result: Result<[FreeDomainSuggestion], Error> = waitFor { promise in - let action = DomainAction.loadFreeDomainSuggestions(query: "domain") { result in - promise(result) - } - self.store.onAction(action) - } - - // Then - XCTAssertTrue(result.isFailure) - let error = try XCTUnwrap(result.failure) - XCTAssertEqual(error as? NetworkError, .timeout()) - } - - // MARK: - `loadPaidDomainSuggestions` - - func test_loadPaidDomainSuggestions_returns_suggestions_on_success() throws { - // Given - remote.whenLoadingPaidDomainSuggestions(thenReturn: .success([.init(name: "paid.domain", productID: 203, supportsPrivacy: true, isPremium: false)])) - remote.whenLoadingDomainProducts(thenReturn: .success([.init(productID: 203, term: "year", cost: "NT$610.00", saleCost: "NT$154.00")])) - - // When - let result = waitFor { promise in - self.store.onAction(DomainAction.loadPaidDomainSuggestions(query: "domain", currencySettings: .init()) { result in - promise(result) - }) - } - - // Then - XCTAssertTrue(result.isSuccess) - let suggestions = try XCTUnwrap(result.get()) - XCTAssertEqual(suggestions, [ - .init(productID: 203, - supportsPrivacy: true, - name: "paid.domain", - term: "year", - cost: "NT$610.00", - saleCost: "NT$154.00", - isPremium: false) - ]) - } - - func test_loadPaidDomainSuggestions_returns_empty_suggestions_from_failed_productID_mapping() throws { - // Given - remote.whenLoadingPaidDomainSuggestions(thenReturn: .success([.init(name: "paid.domain", productID: 203, supportsPrivacy: true, isPremium: false)])) - // The product ID does not match the domain suggestion. - remote.whenLoadingDomainProducts(thenReturn: .success([.init(productID: 156, term: "year", cost: "NT$610.00", saleCost: "NT$154.00")])) - - // When - let result = waitFor { promise in - self.store.onAction(DomainAction.loadPaidDomainSuggestions(query: "domain", currencySettings: .init()) { result in - promise(result) - }) - } - - // Then - XCTAssertTrue(result.isSuccess) - let suggestions = try XCTUnwrap(result.get()) - XCTAssertEqual(suggestions, []) - } - - func test_loadPaidDomainSuggestions_returns_premium_domain_with_formatted_price_from_loadPremiumDomainPrice() throws { - // Given - let domainName = "premium.domain" - remote.whenLoadingPaidDomainSuggestions(thenReturn: .success([ - .init(name: domainName, productID: 645, supportsPrivacy: true, isPremium: true) - ])) - remote.whenLoadingDomainProducts(thenReturn: .success([.init(productID: 645, term: "year", cost: "NT$610.00", saleCost: "NT$154.00")])) - remote.whenLoadingPremiumDomainPrice(domain: domainName, thenReturn: .init(cost: 1000.5, saleCost: 6.8, currency: "TWD")) - let currencySettings = CurrencySettings(currencyCode: .USD, - currencyPosition: .leftSpace, - thousandSeparator: ",", - decimalSeparator: ".", - numberOfDecimals: 1) - - // When - let result = waitFor { promise in - self.store.onAction(DomainAction.loadPaidDomainSuggestions(query: "domain", currencySettings: currencySettings) { result in - promise(result) - }) - } - - // Then - XCTAssertTrue(result.isSuccess) - let suggestions = try XCTUnwrap(result.get()) - XCTAssertEqual(suggestions, [ - .init(productID: 645, supportsPrivacy: true, name: "premium.domain", term: "year", cost: "NT$ 1,000.5", saleCost: "NT$ 6.8", isPremium: true) - ]) - } - - func test_loadPaidDomainSuggestions_skips_premium_domains_without_a_price() throws { - // Given - remote.whenLoadingPaidDomainSuggestions(thenReturn: .success([ - .init(name: "premium.domain", productID: 645, supportsPrivacy: true, isPremium: true), - .init(name: "not.premium.domain", productID: 645, supportsPrivacy: true, isPremium: false) - ])) - remote.whenLoadingDomainProducts(thenReturn: .success([.init(productID: 645, term: "year", cost: "NT$610.00", saleCost: "NT$154.00")])) - - // When - let result = waitFor { promise in - self.store.onAction(DomainAction.loadPaidDomainSuggestions(query: "domain", currencySettings: .init()) { result in - promise(result) - }) - } - - // Then - XCTAssertTrue(result.isSuccess) - let suggestions = try XCTUnwrap(result.get()) - XCTAssertEqual(suggestions, [ - .init(productID: 645, supportsPrivacy: true, name: "not.premium.domain", term: "year", cost: "NT$610.00", saleCost: "NT$154.00", isPremium: false) - ]) - } - - func test_loadPaidDomainSuggestions_returns_error_on_failure() throws { - // Given - remote.whenLoadingPaidDomainSuggestions(thenReturn: .failure(NetworkError.invalidURL)) - remote.whenLoadingDomainProducts(thenReturn: .failure(NetworkError.timeout())) - - // When - let result = waitFor { promise in - self.store.onAction(DomainAction.loadPaidDomainSuggestions(query: "domain", currencySettings: .init()) { result in - promise(result) - }) - } - - // Then - XCTAssertTrue(result.isFailure) - let error = try XCTUnwrap(result.failure) - // The error of `loadDomainProducts` is returned since it is the first async call. - XCTAssertEqual(error as? NetworkError, .timeout()) - } - - - // MARK: - `loadDomains` - - func test_loadDomains_returns_domains_on_success() throws { - // Given - remote.whenLoadingDomains(thenReturn: .success([ - .init(name: "candy.land", isPrimary: true, isWPCOMStagingDomain: true, type: .wpcom, renewalDate: .distantFuture), - .init(name: "pods.pro", isPrimary: true, isWPCOMStagingDomain: false, type: .mapping) - ])) - - // When - let result: Result<[SiteDomain], Error> = waitFor { promise in - self.store.onAction(DomainAction.loadDomains(siteID: 606) { result in - promise(result) - }) - } - - // Then - XCTAssertTrue(result.isSuccess) - let suggestions = try XCTUnwrap(result.get()) - XCTAssertEqual(suggestions, [ - .init(name: "candy.land", isPrimary: true, isWPCOMStagingDomain: true, type: .wpcom, renewalDate: .distantFuture), - .init(name: "pods.pro", isPrimary: true, isWPCOMStagingDomain: false, type: .mapping) - ]) - } - - func test_loadDomains_returns_error_on_failure() throws { - // Given - remote.whenLoadingDomains(thenReturn: .failure(NetworkError.timeout())) - - // When - let result: Result<[SiteDomain], Error> = waitFor { promise in - self.store.onAction(DomainAction.loadDomains(siteID: 606) { result in - promise(result) - }) - } - - // Then - XCTAssertTrue(result.isFailure) - let error = try XCTUnwrap(result.failure) - XCTAssertEqual(error as? NetworkError, .timeout()) - } - - // MARK: - `createDomainShoppingCart` - - func test_createDomainShoppingCart_returns_response_on_success() throws { - // Given - paymentRemote.whenCreatingDomainCart(thenReturn: .success([:])) - - // When - let result = waitFor { promise in - self.store.onAction(DomainAction.createDomainShoppingCart(siteID: 606, - domain: .init(name: "", - productID: 1, - supportsPrivacy: true)) { result in - promise(result) - }) - } - - // Then - XCTAssertTrue(result.isSuccess) - } - - func test_createDomainShoppingCart_returns_error_on_failure() throws { - // Given - paymentRemote.whenCreatingDomainCart(thenReturn: .failure(NetworkError.timeout())) - - // When - let result = waitFor { promise in - self.store.onAction(DomainAction.createDomainShoppingCart(siteID: 606, - domain: .init(name: "", - productID: 1, - supportsPrivacy: true)) { result in - promise(result) - }) - } - - // Then - XCTAssertTrue(result.isFailure) - let error = try XCTUnwrap(result.failure) - XCTAssertEqual(error as? NetworkError, .timeout()) - } - - // MARK: - `redeemDomainCredit` - - func test_redeemDomainCredit_returns_response_on_success() throws { - // Given - paymentRemote.whenCreatingDomainCart(thenReturn: .success([:])) - paymentRemote.whenCheckingOutCartWithDomainCredit(thenReturn: .success(())) - - // When - let result = waitFor { promise in - self.store.onAction(DomainAction.redeemDomainCredit(siteID: 606, domain: .init(name: "", - productID: 1, - supportsPrivacy: true), - contactInfo: .fake()) { result in - promise(result) - }) - } - - // Then - XCTAssertTrue(result.isSuccess) - } - - func test_redeemDomainCredit_returns_createCart_error_on_failure() throws { - // Given - paymentRemote.whenCreatingDomainCart(thenReturn: .failure(NetworkError.timeout())) - - // When - let result = waitFor { promise in - self.store.onAction(DomainAction.redeemDomainCredit(siteID: 606, domain: .init(name: "", - productID: 1, - supportsPrivacy: true), - contactInfo: .fake()) { result in - promise(result) - }) - } - - // Then - XCTAssertTrue(result.isFailure) - let error = try XCTUnwrap(result.failure) - XCTAssertEqual(error as? NetworkError, .timeout()) - } - - func test_redeemDomainCredit_returns_checkoutCartWithDomainCredit_error_on_failure() throws { - // Given - paymentRemote.whenCreatingDomainCart(thenReturn: .success([:])) - paymentRemote.whenCheckingOutCartWithDomainCredit(thenReturn: .failure(NetworkError.notFound())) - - // When - let result = waitFor { promise in - self.store.onAction(DomainAction.redeemDomainCredit(siteID: 606, domain: .init(name: "", - productID: 1, - supportsPrivacy: true), - contactInfo: .fake()) { result in - promise(result) - }) - } - - // Then - XCTAssertTrue(result.isFailure) - let error = try XCTUnwrap(result.failure) - XCTAssertEqual(error as? NetworkError, .notFound()) - } - - // MARK: - `loadDomainContactInfo` - - func test_loadDomainContactInfo_returns_contact_info_on_success() throws { - // Given - let contactInfo = DomainContactInfo(firstName: "woo", - lastName: "Merch", - organization: "Woo", - address1: "No 300", - address2: nil, - postcode: "18888", - city: "SF", - state: "CA", - countryCode: "US", - phone: "181800", - email: "woo@merch.com") - remote.whenLoadingDomainContactInfo(thenReturn: .success(contactInfo)) - - // When - let result = waitFor { promise in - self.store.onAction(DomainAction.loadDomainContactInfo { result in - promise(result) - }) - } - - // Then - XCTAssertTrue(result.isSuccess) - let returnedContactInfo = try XCTUnwrap(result.get()) - XCTAssertEqual(returnedContactInfo, contactInfo) - } - - func test_loadDomainContactInfo_returns_error_on_failure() throws { - // Given - remote.whenLoadingDomainContactInfo(thenReturn: .failure(NetworkError.timeout())) - - // When - let result = waitFor { promise in - self.store.onAction(DomainAction.loadDomainContactInfo { result in - promise(result) - }) - } - - // Then - XCTAssertTrue(result.isFailure) - let error = try XCTUnwrap(result.failure) - XCTAssertEqual(error as? NetworkError, .timeout()) - } - - // MARK: - `validateDomainContactInfo` - - func test_validateDomainContactInfo_returns_on_success() throws { - // Given - remote.whenValidatingDomainContactInfo(thenReturn: .success(())) - - // When - let result = waitFor { promise in - self.store.onAction(DomainAction.validate(domainContactInfo: .fake(), domain: "") { result in - promise(result) - }) - } - - // Then - XCTAssertTrue(result.isSuccess) - } - - func test_validateDomainContactInfo_returns_error_on_failure() throws { - // Given - remote.whenValidatingDomainContactInfo(thenReturn: .failure(NetworkError.timeout())) - - // When - let result = waitFor { promise in - self.store.onAction(DomainAction.validate(domainContactInfo: .fake(), domain: "") { result in - promise(result) - }) - } - - // Then - XCTAssertTrue(result.isFailure) - let error = try XCTUnwrap(result.failure) - XCTAssertEqual(error as? NetworkError, .timeout()) - } -} From bd06297d9b8205d29269b9c5d189bd5a5c194648 Mon Sep 17 00:00:00 2001 From: iamgabrielma Date: Fri, 20 Jun 2025 12:04:09 +0700 Subject: [PATCH 2/2] remove typealiases and additional files --- Modules/Sources/Yosemite/Model/Model.swift | 5 -- .../Remote/PaymentRemoteTests.swift | 28 ----------- ...doman-cart-with-domain-credit-success.json | 49 ------------------- .../Networking/Remote/MockPaymentRemote.swift | 24 --------- 4 files changed, 106 deletions(-) delete mode 100644 Networking/NetworkingTests/Responses/checkout-doman-cart-with-domain-credit-success.json diff --git a/Modules/Sources/Yosemite/Model/Model.swift b/Modules/Sources/Yosemite/Model/Model.swift index c7f77cb5b04..09f868a20be 100644 --- a/Modules/Sources/Yosemite/Model/Model.swift +++ b/Modules/Sources/Yosemite/Model/Model.swift @@ -37,13 +37,9 @@ public typealias CreateAccountError = Networking.CreateAccountError public typealias Credentials = Networking.Credentials public typealias CreateProductVariation = Networking.CreateProductVariation public typealias Customer = Networking.Customer -public typealias DomainContactInfo = Networking.DomainContactInfo -public typealias DomainContactInfoError = Networking.DomainContactInfoError -public typealias DomainToPurchase = Networking.DomainToPurchase public typealias DotcomDevice = Networking.DotcomDevice public typealias DotcomUser = Networking.DotcomUser public typealias Feature = Networking.Feature -public typealias FreeDomainSuggestion = Networking.FreeDomainSuggestion public typealias GoogleAdsCampaign = Networking.GoogleAdsCampaign public typealias GoogleAdsConnection = Networking.GoogleAdsConnection public typealias GiftCardStats = Networking.GiftCardStats @@ -52,7 +48,6 @@ public typealias GiftCardStatsTotals = Networking.GiftCardStatsTotals public typealias GoogleAdsCampaignStats = Networking.GoogleAdsCampaignStats public typealias GoogleAdsCampaignStatsTotals = Networking.GoogleAdsCampaignStatsTotals public typealias GoogleAdsCampaignStatsItem = Networking.GoogleAdsCampaignStatsItem -public typealias SiteDomain = Networking.SiteDomain public typealias InboxNote = Networking.InboxNote public typealias InboxAction = Networking.InboxAction public typealias JetpackUser = Networking.JetpackUser diff --git a/Networking/NetworkingTests/Remote/PaymentRemoteTests.swift b/Networking/NetworkingTests/Remote/PaymentRemoteTests.swift index 6d571e38c68..7356b26a871 100644 --- a/Networking/NetworkingTests/Remote/PaymentRemoteTests.swift +++ b/Networking/NetworkingTests/Remote/PaymentRemoteTests.swift @@ -150,34 +150,6 @@ final class PaymentRemoteTests: XCTestCase { (error as? NetworkError) == .notFound() } } - - // MARK: - `checkoutCartWithDomainCredit` with a domain - func test_checkoutCartWithDomainCredit_returns_on_success() async throws { - // Given - let remote = PaymentRemote(network: network) - network.simulateResponse(requestUrlSuffix: "me/transactions", filename: "checkout-doman-cart-with-domain-credit-success") - - // When - do { - try await remote.checkoutCartWithDomainCredit(cart: [:], contactInfo: .fake()) - } catch { - // Then - XCTFail("Unexpected error: \(error)") - } - } - - func test_checkoutCartWithDomainCredit_throws_notFound_error_when_no_response() async throws { - // Given - let remote = PaymentRemote(network: network) - - // When - await assertThrowsError { - try await remote.checkoutCartWithDomainCredit(cart: [:], contactInfo: .fake()) - } errorAssert: { error in - // Then - (error as? NetworkError) == .notFound() - } - } } private extension PaymentRemoteTests { diff --git a/Networking/NetworkingTests/Responses/checkout-doman-cart-with-domain-credit-success.json b/Networking/NetworkingTests/Responses/checkout-doman-cart-with-domain-credit-success.json deleted file mode 100644 index 7c27fb01682..00000000000 --- a/Networking/NetworkingTests/Responses/checkout-doman-cart-with-domain-credit-success.json +++ /dev/null @@ -1,49 +0,0 @@ -{ - "receipt_id": 76588039, - "purchases": { - "16": [ - { - "is_gift_purchase": false, - "will_auto_renew": false, - "expiry": "2024-01-30", - "user_email": "", - "product_id": 76, - "product_slug": "dotblog_domain", - "product_name": ".blog Domain Registration", - "product_name_short": null, - "product_type": "domain_reg", - "free_trial": false, - "is_domain_registration": true, - "meta": "testing.blog", - "ownership_id": 36, - "is_renewal": false - }, - { - "is_gift_purchase": false, - "will_auto_renew": false, - "expiry": "2024-01-30", - "user_email": "", - "product_id": 5, - "product_slug": "domain_map", - "product_name": "Domain Connection", - "product_name_short": null, - "product_type": "domain_map", - "free_trial": false, - "is_domain_registration": false, - "meta": "testing.blog", - "ownership_id": 36, - "is_renewal": false - } - ] - }, - "display_price": "US$0.00", - "price_integer": 0, - "price_float": 0, - "currency": "USD", - "is_gift_purchase": false, - "success": true, - "error_code": "", - "error_message": "", - "order_id": "", - "failed_purchases": [] -} diff --git a/Yosemite/YosemiteTests/Mocks/Networking/Remote/MockPaymentRemote.swift b/Yosemite/YosemiteTests/Mocks/Networking/Remote/MockPaymentRemote.swift index 444d98f1c91..7214f19d0e8 100644 --- a/Yosemite/YosemiteTests/Mocks/Networking/Remote/MockPaymentRemote.swift +++ b/Yosemite/YosemiteTests/Mocks/Networking/Remote/MockPaymentRemote.swift @@ -13,12 +13,6 @@ final class MockPaymentRemote { /// The results to return in `createCart`. private var createCartResult: Result? - /// The results to return in `createCart` with a domain. - private var createDomainCartResult: Result? - - /// The results to return in `checkoutCartWithDomainCredit` with a domain. - private var checkoutCartWithDomainCreditResult: Result? - /// Returns the value when `loadPlan` is called. func whenLoadingPlan(thenReturn result: Result) { loadPlanResult = result @@ -33,16 +27,6 @@ final class MockPaymentRemote { func whenCreatingCart(thenReturn result: Result) { createCartResult = result } - - /// Returns the value when `createCart` with a domain is called. - func whenCreatingDomainCart(thenReturn result: Result) { - createDomainCartResult = result - } - - /// Returns the value when `checkoutCartWithDomainCredit` with a domain is called. - func whenCheckingOutCartWithDomainCredit(thenReturn result: Result) { - checkoutCartWithDomainCreditResult = result - } } extension MockPaymentRemote: PaymentRemoteProtocol { @@ -69,12 +53,4 @@ extension MockPaymentRemote: PaymentRemoteProtocol { } return try result.get() } - - func checkoutCartWithDomainCredit(cart: CartResponse, contactInfo: DomainContactInfo) async throws { - guard let result = checkoutCartWithDomainCreditResult else { - XCTFail("Could not find result for checking out a cart with domain credit.") - throw NetworkError.notFound() - } - return try result.get() - } }