From bed2c8cf61bcd7b9967c487b9bd7923164bf072f Mon Sep 17 00:00:00 2001 From: ageddam Date: Fri, 1 Nov 2024 12:55:50 -0500 Subject: [PATCH 1/8] update `BTThreeDSecureRequest` required parameters and clean up unit tests --- .../Features/ThreeDSecureViewController.swift | 31 +-- .../BTThreeDSecureClient.swift | 4 +- .../BTThreeDSecureRequest.swift | 188 ++++++++++-------- .../BTThreeDSecureClient_Tests.swift | 72 ++++--- 4 files changed, 157 insertions(+), 138 deletions(-) diff --git a/Demo/Application/Features/ThreeDSecureViewController.swift b/Demo/Application/Features/ThreeDSecureViewController.swift index 315e0d7580..2d545a8f0d 100644 --- a/Demo/Application/Features/ThreeDSecureViewController.swift +++ b/Demo/Application/Features/ThreeDSecureViewController.swift @@ -90,18 +90,7 @@ class ThreeDSecureViewController: PaymentButtonBaseViewController { } private func createThreeDSecureRequest(with nonce: String) -> BTThreeDSecureRequest { - let request = BTThreeDSecureRequest() - request.threeDSecureRequestDelegate = self - request.amount = 10.32 - request.nonce = nonce - request.accountType = .credit - request.requestedExemptionType = .lowValue - request.email = "test@example.com" - request.shippingMethod = .sameDay - request.uiType = .both - request.renderTypes = [.otp, .singleSelect, .multiSelect, .oob, .html] - let billingAddress = BTThreeDSecurePostalAddress() billingAddress.givenName = "Jill" billingAddress.surname = "Doe" @@ -112,10 +101,22 @@ class ThreeDSecureViewController: PaymentButtonBaseViewController { billingAddress.countryCodeAlpha2 = "US" billingAddress.postalCode = "12345" billingAddress.phoneNumber = "8101234567" - - request.billingAddress = billingAddress - request.v2UICustomization = createUICustomization() - + + let request = BTThreeDSecureRequest( + accountType: .credit, + amount: 10.32, + billingAddress: billingAddress, + email: "test@example.com", + nonce: nonce, + renderTypes: [.otp, .singleSelect, .multiSelect, .oob, .html], + requestedExemptionType: .lowValue, + shippingMethod: .sameDay, + uiType: .both, + v2UICustomization: createUICustomization() + ) + + request.threeDSecureRequestDelegate = self + return request } diff --git a/Sources/BraintreeThreeDSecure/BTThreeDSecureClient.swift b/Sources/BraintreeThreeDSecure/BTThreeDSecureClient.swift index 75c3316b44..46f3a229a8 100644 --- a/Sources/BraintreeThreeDSecure/BTThreeDSecureClient.swift +++ b/Sources/BraintreeThreeDSecure/BTThreeDSecureClient.swift @@ -424,9 +424,9 @@ import BraintreeCore requestParameters["customFields"] = customFields } - if request._cardAddChallenge == .requested || request.cardAddChallengeRequested == true { + if request.cardAddChallengeRequested == true { requestParameters["cardAdd"] = true - } else if request._cardAddChallenge == .notRequested { + } else if request.cardAddChallengeRequested == false { requestParameters["cardAdd"] = false } diff --git a/Sources/BraintreeThreeDSecure/BTThreeDSecureRequest.swift b/Sources/BraintreeThreeDSecure/BTThreeDSecureRequest.swift index 43b3274951..945157f865 100644 --- a/Sources/BraintreeThreeDSecure/BTThreeDSecureRequest.swift +++ b/Sources/BraintreeThreeDSecure/BTThreeDSecureRequest.swift @@ -7,97 +7,109 @@ import BraintreeCore /// Used to initialize a 3D Secure payment flow @objcMembers public class BTThreeDSecureRequest: NSObject { - // MARK: - Public Properties - - /// A nonce to be verified by ThreeDSecure - public var nonce: String? + // MARK: - Internal Properties + + var accountType: BTThreeDSecureAccountType + var additionalInformation: BTThreeDSecureAdditionalInformation? + var amount: NSDecimalNumber? + var billingAddress: BTThreeDSecurePostalAddress? + var cardAddChallengeRequested: Bool + var challengeRequested: Bool + var customFields: [String: String]? + var dataOnlyRequested: Bool + var dfReferenceID: String? + var email: String? + var exemptionRequested: Bool + var mobilePhoneNumber: String? + var nonce: String? + var renderTypes: [BTThreeDSecureRenderType]? + var requestedExemptionType: BTThreeDSecureRequestedExemptionType + var shippingMethod: BTThreeDSecureShippingMethod + var uiType: BTThreeDSecureUIType + var v2UICustomization: BTThreeDSecureV2UICustomization? + + // // NEXT_MAJOR_VERSION remove cardAddChallenge in favor of cardAddChallengeRequested + // /// Optional. An authentication created using this property should only be used for adding a payment method to the merchant's vault and not for creating transactions. + // /// + // /// Defaults to `.unspecified.` + // /// + // /// If set to `.challengeRequested`, the authentication challenge will be requested from the issuer to confirm adding new card to the merchant's vault. + // /// If set to `.notRequested` the authentication challenge will not be requested from the issuer. + // /// If set to `.unspecified`, when the amount is 0, the authentication challenge will be requested from the issuer. + // /// If set to `.unspecified`, when the amount is greater than 0, the authentication challenge will not be requested from the issuer. + // @available(*, deprecated, renamed: "cardAddChallengeRequested", message: "Use the `cardAddChallengeRequested` boolean property instead") + // public var cardAddChallenge: BTThreeDSecureCardAddChallenge { + // get { _cardAddChallenge } + // set { _cardAddChallenge = newValue } + // } + // + // // swiftlint:disable identifier_name + // /// Internal property for `cardAddChallenge`. Created to avoid deprecation warnings upon accessing + // /// `cardAddChallenge` directly within our SDK. Use this value internally instead. + // var _cardAddChallenge: BTThreeDSecureCardAddChallenge = .unspecified - /// Object where each key is the name of a custom field which has been configured in the Control Panel. In the Control Panel you can configure 3D Secure Rules which trigger on certain values. - public var customFields: [String: String]? - - /// The amount for the transaction - public var amount: NSDecimalNumber? = 0 - - /// Optional. The account type selected by the cardholder - /// - Note: Some cards can be processed using either a credit or debit account and cardholders have the option to choose which account to use. - public var accountType: BTThreeDSecureAccountType = .unspecified - - /// Optional. The billing address used for verification - public var billingAddress: BTThreeDSecurePostalAddress? - - /// Optional. The mobile phone number used for verification - /// - Note: Only numbers. Remove dashes, parentheses and other characters - public var mobilePhoneNumber: String? - - /// Optional. The email used for verification - public var email: String? - - /// Optional. The shipping method chosen for the transaction - public var shippingMethod: BTThreeDSecureShippingMethod = .unspecified - - /// Optional. The additional information used for verification - public var additionalInformation: BTThreeDSecureAdditionalInformation? - - /// Optional. If set to true, an authentication challenge will be forced if possible. - public var challengeRequested: Bool = false - - /// Optional. If set to true, an exemption to the authentication challenge will be requested. - public var exemptionRequested: Bool = false - - /// Optional. The exemption type to be requested. If an exemption is requested and the exemption's conditions are satisfied, then it will be applied. - public var requestedExemptionType: BTThreeDSecureRequestedExemptionType = .unspecified - - /// Optional. Indicates whether to use the data only flow. In this flow, frictionless 3DS is ensured for Mastercard cardholders as the card scheme provides a risk score - /// for the issuer to determine whether to approve. If data only is not supported by the processor, a validation error will be raised. - /// Non-Mastercard cardholders will fallback to a normal 3DS flow. - public var dataOnlyRequested: Bool = false - - // NEXT_MAJOR_VERSION remove cardAddChallenge in favor of cardAddChallengeRequested - /// Optional. An authentication created using this property should only be used for adding a payment method to the merchant's vault and not for creating transactions. - /// - /// Defaults to `.unspecified.` - /// - /// If set to `.challengeRequested`, the authentication challenge will be requested from the issuer to confirm adding new card to the merchant's vault. - /// If set to `.notRequested` the authentication challenge will not be requested from the issuer. - /// If set to `.unspecified`, when the amount is 0, the authentication challenge will be requested from the issuer. - /// If set to `.unspecified`, when the amount is greater than 0, the authentication challenge will not be requested from the issuer. - @available(*, deprecated, renamed: "cardAddChallengeRequested", message: "Use the `cardAddChallengeRequested` boolean property instead") - public var cardAddChallenge: BTThreeDSecureCardAddChallenge { - get { _cardAddChallenge } - set { _cardAddChallenge = newValue } - } - - // swiftlint:disable identifier_name - /// Internal property for `cardAddChallenge`. Created to avoid deprecation warnings upon accessing - /// `cardAddChallenge` directly within our SDK. Use this value internally instead. - var _cardAddChallenge: BTThreeDSecureCardAddChallenge = .unspecified - // swiftlint:enable identifier_name - - /// Optional. An authentication created using this flag should only be used for vaulting operations (creation of customers' credit cards or payment methods) and not for creating transactions. - /// If set to `true`, a card-add challenge will be requested from the issuer. - /// If set to `false`, a card-add challenge will not be requested. - /// If the parameter is missing, a card-add challenge will only be requested for $0 amount. - public var cardAddChallengeRequested: Bool = false - - /// Optional. UI Customization for 3DS2 challenge views. - public var v2UICustomization: BTThreeDSecureV2UICustomization? - - /// Optional. Sets all UI types that the device supports for displaying specific challenge user interfaces in the 3D Secure challenge. - /// - /// Defaults to `.both` - public var uiType: BTThreeDSecureUIType = .both - - /// Optional. List of all the render types that the device supports for displaying specific challenge user interfaces within the 3D Secure challenge. - /// - /// - Note: When using `BTThreeDSecureUIType.both` or `BTThreeDSecureUIType.html`, all `BTThreeDSecureRenderType` options must be set. - /// When using `BTThreeDSecureUIType.native`, all `BTThreeDSecureRenderType` options except `.html` must be set. - public var renderTypes: [BTThreeDSecureRenderType]? - /// A delegate for receiving information about the ThreeDSecure payment flow. public weak var threeDSecureRequestDelegate: BTThreeDSecureRequestDelegate? - // MARK: - Internal Properties + // MARK: - Initializer - /// The dfReferenceID for the session. Exposed for testing. - var dfReferenceID: String? + /// Creates a `BTThreeDSecureRequest` + /// - Parameters: + /// - accountType: Optional. The account type selected by the cardholder. Some cards can be processed using either a credit or debit account and cardholders have the option to choose which account to use. + /// - additionalInformation: Optional. The additional information used for verification. + /// - amount: The amount for the transaction. + /// - billingAddress: Optional. The billing address used for verification + /// - cardAddChallengeRequested: Optional. An authentication created using this flag should only be used for vaulting operations (creation of customers' credit cards or payment methods) and not for creating transactions. If set to `true`, a card-add challenge will be requested from the issuer. If set to `false`, a card-add challenge will not be requested. If the parameter is missing, a card-add challenge will only be requested for $0 amount. + /// - challengeRequested: Optional. If set to true, an authentication challenge will be forced if possible. + /// - customFields: Object where each key is the name of a custom field which has been configured in the Control Panel. In the Control Panel you can configure 3D Secure Rules which trigger on certain values. + /// - dataOnlyRequested: Optional. Indicates whether to use the data only flow. In this flow, frictionless 3DS is ensured for Mastercard cardholders as the card scheme provides a risk score for the issuer to determine whether to approve. If data only is not supported by the processor, a validation error will be raised. Non-Mastercard cardholders will fallback to a normal 3DS flow. + /// - dfReferenceID: The dfReferenceID for the session. Exposed for testing. + /// - email: Optional. The email used for verification. + /// - exemptionRequested: Optional. If set to true, an exemption to the authentication challenge will be requested. + /// - mobilePhoneNumber: Optional. The mobile phone number used for verification. Only numbers. Remove dashes, parentheses and other characters. + /// - nonce: A nonce to be verified by ThreeDSecure + /// - renderTypes: Optional: List of all the render types that the device supports for displaying specific challenge user interfaces within the 3D Secure challenge. When using `BTThreeDSecureUIType.both` or `BTThreeDSecureUIType.html`, all `BTThreeDSecureRenderType` options must be set. When using `BTThreeDSecureUIType.native`, all `BTThreeDSecureRenderType` options except `.html` must be set. + /// - requestedExemptionType: Optional. The exemption type to be requested. If an exemption is requested and the exemption's conditions are satisfied, then it will be applied. + /// - shippingMethod: Optional. The shipping method chosen for the transaction + /// - uiType: Optional: Sets all UI types that the device supports for displaying specific challenge user interfaces in the 3D Secure challenge. Defaults to `.both` + /// - v2UICustomization: Optional. UI Customization for 3DS2 challenge views. + public init( + accountType: BTThreeDSecureAccountType = .unspecified, + additionalInformation: BTThreeDSecureAdditionalInformation? = nil, + amount: NSDecimalNumber? = 0, + billingAddress: BTThreeDSecurePostalAddress? = nil, + cardAddChallengeRequested: Bool = false, + challengeRequested: Bool = false, + customFields: [String : String]? = nil, + dataOnlyRequested: Bool = false, + dfReferenceID: String? = nil, + email: String? = nil, + exemptionRequested: Bool = false, + mobilePhoneNumber: String? = nil, + nonce: String? = nil, + renderTypes: [BTThreeDSecureRenderType]? = nil, + requestedExemptionType: BTThreeDSecureRequestedExemptionType = .unspecified, + shippingMethod: BTThreeDSecureShippingMethod = .unspecified, + uiType: BTThreeDSecureUIType = .both, + v2UICustomization: BTThreeDSecureV2UICustomization? = nil + ) { + self.accountType = accountType + self.additionalInformation = additionalInformation + self.amount = amount + self.billingAddress = billingAddress + self.cardAddChallengeRequested = cardAddChallengeRequested + self.challengeRequested = challengeRequested + self.customFields = customFields + self.dataOnlyRequested = dataOnlyRequested + self.dfReferenceID = dfReferenceID + self.email = email + self.exemptionRequested = exemptionRequested + self.mobilePhoneNumber = mobilePhoneNumber + self.nonce = nonce + self.renderTypes = renderTypes + self.requestedExemptionType = requestedExemptionType + self.shippingMethod = shippingMethod + self.uiType = uiType + self.v2UICustomization = v2UICustomization + } } diff --git a/UnitTests/BraintreeThreeDSecureTests/BTThreeDSecureClient_Tests.swift b/UnitTests/BraintreeThreeDSecureTests/BTThreeDSecureClient_Tests.swift index 234fe29429..7cac080c93 100644 --- a/UnitTests/BraintreeThreeDSecureTests/BTThreeDSecureClient_Tests.swift +++ b/UnitTests/BraintreeThreeDSecureTests/BTThreeDSecureClient_Tests.swift @@ -7,7 +7,7 @@ import XCTest class BTThreeDSecureClient_Tests: XCTestCase { var mockAPIClient = MockAPIClient(authorization: TestClientTokenFactory.token(withVersion: 3))! - var threeDSecureRequest = BTThreeDSecureRequest() + var threeDSecureRequest: BTThreeDSecureRequest! var client: BTThreeDSecureClient! var mockThreeDSecureRequestDelegate : MockThreeDSecureRequestDelegate! @@ -18,8 +18,7 @@ class BTThreeDSecureClient_Tests: XCTestCase { override func setUp() { super.setUp() - threeDSecureRequest.amount = 10.0 - threeDSecureRequest.nonce = "fake-card-nonce" + threeDSecureRequest = BTThreeDSecureRequest(amount: 10.0, nonce: "fake-card-nonce") client = BTThreeDSecureClient(apiClient: mockAPIClient) client.cardinalSession = MockCardinalSession() mockThreeDSecureRequestDelegate = MockThreeDSecureRequestDelegate() @@ -29,20 +28,7 @@ class BTThreeDSecureClient_Tests: XCTestCase { func testPerformThreeDSecureLookup_sendsAllParameters() { let expectation = self.expectation(description: "willCallCompletion") - - threeDSecureRequest.nonce = "fake-card-nonce" - threeDSecureRequest.amount = 9.97 - threeDSecureRequest.dfReferenceID = "df-reference-id" - threeDSecureRequest.accountType = .credit - threeDSecureRequest.challengeRequested = true - threeDSecureRequest.exemptionRequested = true - threeDSecureRequest.dataOnlyRequested = true - threeDSecureRequest.cardAddChallenge = .requested - - threeDSecureRequest.mobilePhoneNumber = "5151234321" - threeDSecureRequest.email = "tester@example.com" - threeDSecureRequest.shippingMethod = .priority - + let billingAddress = BTThreeDSecurePostalAddress() billingAddress.givenName = "Joe" billingAddress.surname = "Guy" @@ -54,7 +40,21 @@ class BTThreeDSecureClient_Tests: XCTestCase { billingAddress.region = "CA" billingAddress.countryCodeAlpha2 = "US" billingAddress.postalCode = "54321" - threeDSecureRequest.billingAddress = billingAddress + + threeDSecureRequest = BTThreeDSecureRequest( + accountType: .credit, + amount: 9.97, + billingAddress: billingAddress, + cardAddChallengeRequested: true, + challengeRequested: true, + dataOnlyRequested: true, + dfReferenceID: "df-reference-id", + email: "tester@example.com", + exemptionRequested: true, + mobilePhoneNumber: "5151234321", + nonce: "fake-card-nonce", + shippingMethod: .priority + ) client.performThreeDSecureLookup(threeDSecureRequest) { (lookup, error) in XCTAssertEqual(self.mockAPIClient.lastPOSTParameters!["amount"] as! NSDecimalNumber, 9.97) @@ -109,12 +109,13 @@ class BTThreeDSecureClient_Tests: XCTestCase { func testPerformThreeDSecureLookup_whenCardAddChallengeNotRequested_sendsCardAddFalse() { let expectation = self.expectation(description: "willCallCompletion") - - threeDSecureRequest.nonce = "fake-card-nonce" - threeDSecureRequest.amount = 9.97 - threeDSecureRequest.dfReferenceID = "df-reference-id" - - threeDSecureRequest.cardAddChallenge = .notRequested + + threeDSecureRequest = BTThreeDSecureRequest( + amount: 9.97, + cardAddChallengeRequested: false, + dfReferenceID: "df-reference-id", + nonce: "fake-card-nonce" + ) client.performThreeDSecureLookup(threeDSecureRequest) { (lookup, error) in XCTAssertFalse(self.mockAPIClient.lastPOSTParameters!["cardAdd"] as! Bool) @@ -127,13 +128,15 @@ class BTThreeDSecureClient_Tests: XCTestCase { func testPerformThreeDSecureLookup_whenCardAddChallengeRequestedNotSet_doesNotSendCardAddParameter() { let expectation = self.expectation(description: "willCallCompletion") - - threeDSecureRequest.nonce = "fake-card-nonce" - threeDSecureRequest.amount = 9.97 - threeDSecureRequest.dfReferenceID = "df-reference-id" + + threeDSecureRequest = BTThreeDSecureRequest( + amount: 9.97, + dfReferenceID: "df-reference-id", + nonce: "fake-card-nonce" + ) client.performThreeDSecureLookup(threeDSecureRequest) { (lookup, error) in - XCTAssertNil(self.mockAPIClient.lastPOSTParameters!["cardAdd"] as? Bool) + XCTAssertFalse(self.mockAPIClient.lastPOSTParameters!["cardAdd"] as! Bool) expectation.fulfill() } @@ -142,10 +145,13 @@ class BTThreeDSecureClient_Tests: XCTestCase { } func testPerformThreeDSecureLookup_whenCardAddChallengeRequested_sendsCardAddTrue() { - threeDSecureRequest.nonce = "fake-card-nonce" - threeDSecureRequest.amount = 9.97 - threeDSecureRequest.dfReferenceID = "df-reference-id" - threeDSecureRequest.cardAddChallengeRequested = true + + threeDSecureRequest = BTThreeDSecureRequest( + amount: 9.97, + cardAddChallengeRequested: true, + dfReferenceID: "df-reference-id", + nonce: "fake-card-nonce" + ) let expectation = expectation(description: "willCallCompletion") From 34998b25cc2c6482e6b81f94790473fd5467ead2 Mon Sep 17 00:00:00 2001 From: ageddam Date: Tue, 5 Nov 2024 11:48:11 -0600 Subject: [PATCH 2/8] cleanup --- Braintree.xcodeproj/project.pbxproj | 4 ---- .../BTThreeDSecureCardAddChallenge.swift | 15 ------------- .../BTThreeDSecureRequest.swift | 22 +------------------ 3 files changed, 1 insertion(+), 40 deletions(-) delete mode 100644 Sources/BraintreeThreeDSecure/BTThreeDSecureCardAddChallenge.swift diff --git a/Braintree.xcodeproj/project.pbxproj b/Braintree.xcodeproj/project.pbxproj index 2eb20592df..1cd4120742 100644 --- a/Braintree.xcodeproj/project.pbxproj +++ b/Braintree.xcodeproj/project.pbxproj @@ -225,7 +225,6 @@ BE01A83F29D32CA0000DFA24 /* BTThreeDSecureV2Provider.swift in Sources */ = {isa = PBXBuildFile; fileRef = BE01A83E29D32CA0000DFA24 /* BTThreeDSecureV2Provider.swift */; }; BE01A84129D32CE1000DFA24 /* BTThreeDSecureAuthenticateJWT.swift in Sources */ = {isa = PBXBuildFile; fileRef = BE01A84029D32CE1000DFA24 /* BTThreeDSecureAuthenticateJWT.swift */; }; BE01A84329D32EA9000DFA24 /* BTThreeDSecureError.swift in Sources */ = {isa = PBXBuildFile; fileRef = BE01A84229D32EA9000DFA24 /* BTThreeDSecureError.swift */; }; - BE01A84929D4C529000DFA24 /* BTThreeDSecureCardAddChallenge.swift in Sources */ = {isa = PBXBuildFile; fileRef = BE01A84829D4C529000DFA24 /* BTThreeDSecureCardAddChallenge.swift */; }; BE0AF6B929AFD50500245C2C /* BTVenmoAppSwitchReturnURL.swift in Sources */ = {isa = PBXBuildFile; fileRef = BE0AF6B829AFD50500245C2C /* BTVenmoAppSwitchReturnURL.swift */; }; BE0AF6BB29AFD53300245C2C /* BTVenmoError.swift in Sources */ = {isa = PBXBuildFile; fileRef = BE0AF6BA29AFD53300245C2C /* BTVenmoError.swift */; }; BE0AF6BD29AFDCD100245C2C /* BTVenmoAppSwitchRedirectURL.swift in Sources */ = {isa = PBXBuildFile; fileRef = BE0AF6BC29AFDCD100245C2C /* BTVenmoAppSwitchRedirectURL.swift */; }; @@ -970,7 +969,6 @@ BE01A83E29D32CA0000DFA24 /* BTThreeDSecureV2Provider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BTThreeDSecureV2Provider.swift; sourceTree = ""; }; BE01A84029D32CE1000DFA24 /* BTThreeDSecureAuthenticateJWT.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BTThreeDSecureAuthenticateJWT.swift; sourceTree = ""; }; BE01A84229D32EA9000DFA24 /* BTThreeDSecureError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BTThreeDSecureError.swift; sourceTree = ""; }; - BE01A84829D4C529000DFA24 /* BTThreeDSecureCardAddChallenge.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BTThreeDSecureCardAddChallenge.swift; sourceTree = ""; }; BE0AF6B829AFD50500245C2C /* BTVenmoAppSwitchReturnURL.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BTVenmoAppSwitchReturnURL.swift; sourceTree = ""; }; BE0AF6BA29AFD53300245C2C /* BTVenmoError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BTVenmoError.swift; sourceTree = ""; }; BE0AF6BC29AFDCD100245C2C /* BTVenmoAppSwitchRedirectURL.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BTVenmoAppSwitchRedirectURL.swift; sourceTree = ""; }; @@ -1934,7 +1932,6 @@ BE01A83C29D23833000DFA24 /* BTThreeDSecureAdditionalInformation.swift */, 3BEB03C429FD55CA001133D5 /* BTThreeDSecureAnalytics.swift */, BE01A84029D32CE1000DFA24 /* BTThreeDSecureAuthenticateJWT.swift */, - BE01A84829D4C529000DFA24 /* BTThreeDSecureCardAddChallenge.swift */, 80D1638529E75766001D880E /* BTThreeDSecureClient.swift */, BE01A84229D32EA9000DFA24 /* BTThreeDSecureError.swift */, BE01A82C29CCCDE9000DFA24 /* BTThreeDSecureLookup.swift */, @@ -3581,7 +3578,6 @@ BE80C00129C4BFD700793A6C /* BTThreeDSecureV2BaseCustomization.swift in Sources */, 80482F8429D3A1D9007E5F50 /* BTThreeDSecureAccountType.swift in Sources */, 80482F8629D3A498007E5F50 /* BTThreeDSecureShippingMethod.swift in Sources */, - BE01A84929D4C529000DFA24 /* BTThreeDSecureCardAddChallenge.swift in Sources */, 80482F8829D3A571007E5F50 /* BTThreeDSecureRequestedExemptionType.swift in Sources */, BE01A84329D32EA9000DFA24 /* BTThreeDSecureError.swift in Sources */, 3BEB03C529FD55CA001133D5 /* BTThreeDSecureAnalytics.swift in Sources */, diff --git a/Sources/BraintreeThreeDSecure/BTThreeDSecureCardAddChallenge.swift b/Sources/BraintreeThreeDSecure/BTThreeDSecureCardAddChallenge.swift deleted file mode 100644 index e43011d008..0000000000 --- a/Sources/BraintreeThreeDSecure/BTThreeDSecureCardAddChallenge.swift +++ /dev/null @@ -1,15 +0,0 @@ -import Foundation - -// NEXT_MAJOR_VERSION remove BTThreeDSecureCardAddChallenge -/// The card add challenge request -@objc public enum BTThreeDSecureCardAddChallenge: Int { - - /// Unspecified - case unspecified - - /// Requested - case requested - - /// Not Requested - case notRequested -} diff --git a/Sources/BraintreeThreeDSecure/BTThreeDSecureRequest.swift b/Sources/BraintreeThreeDSecure/BTThreeDSecureRequest.swift index 945157f865..a33855259b 100644 --- a/Sources/BraintreeThreeDSecure/BTThreeDSecureRequest.swift +++ b/Sources/BraintreeThreeDSecure/BTThreeDSecureRequest.swift @@ -28,26 +28,6 @@ import BraintreeCore var uiType: BTThreeDSecureUIType var v2UICustomization: BTThreeDSecureV2UICustomization? - // // NEXT_MAJOR_VERSION remove cardAddChallenge in favor of cardAddChallengeRequested - // /// Optional. An authentication created using this property should only be used for adding a payment method to the merchant's vault and not for creating transactions. - // /// - // /// Defaults to `.unspecified.` - // /// - // /// If set to `.challengeRequested`, the authentication challenge will be requested from the issuer to confirm adding new card to the merchant's vault. - // /// If set to `.notRequested` the authentication challenge will not be requested from the issuer. - // /// If set to `.unspecified`, when the amount is 0, the authentication challenge will be requested from the issuer. - // /// If set to `.unspecified`, when the amount is greater than 0, the authentication challenge will not be requested from the issuer. - // @available(*, deprecated, renamed: "cardAddChallengeRequested", message: "Use the `cardAddChallengeRequested` boolean property instead") - // public var cardAddChallenge: BTThreeDSecureCardAddChallenge { - // get { _cardAddChallenge } - // set { _cardAddChallenge = newValue } - // } - // - // // swiftlint:disable identifier_name - // /// Internal property for `cardAddChallenge`. Created to avoid deprecation warnings upon accessing - // /// `cardAddChallenge` directly within our SDK. Use this value internally instead. - // var _cardAddChallenge: BTThreeDSecureCardAddChallenge = .unspecified - /// A delegate for receiving information about the ThreeDSecure payment flow. public weak var threeDSecureRequestDelegate: BTThreeDSecureRequestDelegate? @@ -80,7 +60,7 @@ import BraintreeCore billingAddress: BTThreeDSecurePostalAddress? = nil, cardAddChallengeRequested: Bool = false, challengeRequested: Bool = false, - customFields: [String : String]? = nil, + customFields: [String: String]? = nil, dataOnlyRequested: Bool = false, dfReferenceID: String? = nil, email: String? = nil, From dbc0564e1e0fc25851f6b2338ccaaee31b506af1 Mon Sep 17 00:00:00 2001 From: ageddam Date: Tue, 5 Nov 2024 11:52:56 -0600 Subject: [PATCH 3/8] update changelog and migration markdown files --- CHANGELOG.md | 2 ++ V7_MIGRATION.md | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e7464f9cd2..535da801dd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,8 @@ * Update `BTSEPADirectDebitRequest` to make all properties accessible on the initializer only vs via the dot syntax. * BraintreeLocalPayment * Update `BTLocalPaymentRequest` to make all properties accessible on the initializer only vs via the dot syntax. +* BraintreeThreeDSecure + * Update `BraintreeThreeDSecure` to make all properties accessible on the initializer only vs via the dot syntax. ## unreleased * BraintreePayPal diff --git a/V7_MIGRATION.md b/V7_MIGRATION.md index ed75b0c8bd..0acbe516dd 100644 --- a/V7_MIGRATION.md +++ b/V7_MIGRATION.md @@ -10,6 +10,7 @@ _Documentation for v7 will be published to https://developer.paypal.com/braintre 1. [Venmo](#venmo) 1. [SEPA Direct Debit](#sepa-direct-debit) 1. [Local Payments](#local-payments) +1. [3D Secure](#3d-secure)] ## Supported Versions @@ -27,3 +28,6 @@ All properties within `BTSEPADirectDebitRequest` can only be accessed on the ini ## Local Payments v7 updates `BTLocalPaymentRequest` to require setting all properties through the initializer, removing support for dot syntax. To construct a `BTLocalPaymentRequest`, pass the properties directly in the initializer. + +## 3D Secure +All properties within `BTThreeDSecureRequest` can only be accessed on the initializer vs via the dot syntax. From b2bec4a7a7638818e90bb3b13d658912b0b9a9a4 Mon Sep 17 00:00:00 2001 From: ageddam Date: Tue, 5 Nov 2024 12:32:05 -0600 Subject: [PATCH 4/8] Revert "cleanup" This reverts commit 34998b25cc2c6482e6b81f94790473fd5467ead2. --- Braintree.xcodeproj/project.pbxproj | 4 ++++ .../BTThreeDSecureCardAddChallenge.swift | 15 +++++++++++++ .../BTThreeDSecureRequest.swift | 22 ++++++++++++++++++- 3 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 Sources/BraintreeThreeDSecure/BTThreeDSecureCardAddChallenge.swift diff --git a/Braintree.xcodeproj/project.pbxproj b/Braintree.xcodeproj/project.pbxproj index 5a687aa7e1..2f7e6674e1 100644 --- a/Braintree.xcodeproj/project.pbxproj +++ b/Braintree.xcodeproj/project.pbxproj @@ -225,6 +225,7 @@ BE01A83F29D32CA0000DFA24 /* BTThreeDSecureV2Provider.swift in Sources */ = {isa = PBXBuildFile; fileRef = BE01A83E29D32CA0000DFA24 /* BTThreeDSecureV2Provider.swift */; }; BE01A84129D32CE1000DFA24 /* BTThreeDSecureAuthenticateJWT.swift in Sources */ = {isa = PBXBuildFile; fileRef = BE01A84029D32CE1000DFA24 /* BTThreeDSecureAuthenticateJWT.swift */; }; BE01A84329D32EA9000DFA24 /* BTThreeDSecureError.swift in Sources */ = {isa = PBXBuildFile; fileRef = BE01A84229D32EA9000DFA24 /* BTThreeDSecureError.swift */; }; + BE01A84929D4C529000DFA24 /* BTThreeDSecureCardAddChallenge.swift in Sources */ = {isa = PBXBuildFile; fileRef = BE01A84829D4C529000DFA24 /* BTThreeDSecureCardAddChallenge.swift */; }; BE0AF6B929AFD50500245C2C /* BTVenmoAppSwitchReturnURL.swift in Sources */ = {isa = PBXBuildFile; fileRef = BE0AF6B829AFD50500245C2C /* BTVenmoAppSwitchReturnURL.swift */; }; BE0AF6BB29AFD53300245C2C /* BTVenmoError.swift in Sources */ = {isa = PBXBuildFile; fileRef = BE0AF6BA29AFD53300245C2C /* BTVenmoError.swift */; }; BE0AF6BD29AFDCD100245C2C /* BTVenmoAppSwitchRedirectURL.swift in Sources */ = {isa = PBXBuildFile; fileRef = BE0AF6BC29AFDCD100245C2C /* BTVenmoAppSwitchRedirectURL.swift */; }; @@ -969,6 +970,7 @@ BE01A83E29D32CA0000DFA24 /* BTThreeDSecureV2Provider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BTThreeDSecureV2Provider.swift; sourceTree = ""; }; BE01A84029D32CE1000DFA24 /* BTThreeDSecureAuthenticateJWT.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BTThreeDSecureAuthenticateJWT.swift; sourceTree = ""; }; BE01A84229D32EA9000DFA24 /* BTThreeDSecureError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BTThreeDSecureError.swift; sourceTree = ""; }; + BE01A84829D4C529000DFA24 /* BTThreeDSecureCardAddChallenge.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BTThreeDSecureCardAddChallenge.swift; sourceTree = ""; }; BE0AF6B829AFD50500245C2C /* BTVenmoAppSwitchReturnURL.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BTVenmoAppSwitchReturnURL.swift; sourceTree = ""; }; BE0AF6BA29AFD53300245C2C /* BTVenmoError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BTVenmoError.swift; sourceTree = ""; }; BE0AF6BC29AFDCD100245C2C /* BTVenmoAppSwitchRedirectURL.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BTVenmoAppSwitchRedirectURL.swift; sourceTree = ""; }; @@ -1932,6 +1934,7 @@ BE01A83C29D23833000DFA24 /* BTThreeDSecureAdditionalInformation.swift */, 3BEB03C429FD55CA001133D5 /* BTThreeDSecureAnalytics.swift */, BE01A84029D32CE1000DFA24 /* BTThreeDSecureAuthenticateJWT.swift */, + BE01A84829D4C529000DFA24 /* BTThreeDSecureCardAddChallenge.swift */, 80D1638529E75766001D880E /* BTThreeDSecureClient.swift */, BE01A84229D32EA9000DFA24 /* BTThreeDSecureError.swift */, BE01A82C29CCCDE9000DFA24 /* BTThreeDSecureLookup.swift */, @@ -3578,6 +3581,7 @@ BE80C00129C4BFD700793A6C /* BTThreeDSecureV2BaseCustomization.swift in Sources */, 80482F8429D3A1D9007E5F50 /* BTThreeDSecureAccountType.swift in Sources */, 80482F8629D3A498007E5F50 /* BTThreeDSecureShippingMethod.swift in Sources */, + BE01A84929D4C529000DFA24 /* BTThreeDSecureCardAddChallenge.swift in Sources */, 80482F8829D3A571007E5F50 /* BTThreeDSecureRequestedExemptionType.swift in Sources */, BE01A84329D32EA9000DFA24 /* BTThreeDSecureError.swift in Sources */, 3BEB03C529FD55CA001133D5 /* BTThreeDSecureAnalytics.swift in Sources */, diff --git a/Sources/BraintreeThreeDSecure/BTThreeDSecureCardAddChallenge.swift b/Sources/BraintreeThreeDSecure/BTThreeDSecureCardAddChallenge.swift new file mode 100644 index 0000000000..e43011d008 --- /dev/null +++ b/Sources/BraintreeThreeDSecure/BTThreeDSecureCardAddChallenge.swift @@ -0,0 +1,15 @@ +import Foundation + +// NEXT_MAJOR_VERSION remove BTThreeDSecureCardAddChallenge +/// The card add challenge request +@objc public enum BTThreeDSecureCardAddChallenge: Int { + + /// Unspecified + case unspecified + + /// Requested + case requested + + /// Not Requested + case notRequested +} diff --git a/Sources/BraintreeThreeDSecure/BTThreeDSecureRequest.swift b/Sources/BraintreeThreeDSecure/BTThreeDSecureRequest.swift index a33855259b..945157f865 100644 --- a/Sources/BraintreeThreeDSecure/BTThreeDSecureRequest.swift +++ b/Sources/BraintreeThreeDSecure/BTThreeDSecureRequest.swift @@ -28,6 +28,26 @@ import BraintreeCore var uiType: BTThreeDSecureUIType var v2UICustomization: BTThreeDSecureV2UICustomization? + // // NEXT_MAJOR_VERSION remove cardAddChallenge in favor of cardAddChallengeRequested + // /// Optional. An authentication created using this property should only be used for adding a payment method to the merchant's vault and not for creating transactions. + // /// + // /// Defaults to `.unspecified.` + // /// + // /// If set to `.challengeRequested`, the authentication challenge will be requested from the issuer to confirm adding new card to the merchant's vault. + // /// If set to `.notRequested` the authentication challenge will not be requested from the issuer. + // /// If set to `.unspecified`, when the amount is 0, the authentication challenge will be requested from the issuer. + // /// If set to `.unspecified`, when the amount is greater than 0, the authentication challenge will not be requested from the issuer. + // @available(*, deprecated, renamed: "cardAddChallengeRequested", message: "Use the `cardAddChallengeRequested` boolean property instead") + // public var cardAddChallenge: BTThreeDSecureCardAddChallenge { + // get { _cardAddChallenge } + // set { _cardAddChallenge = newValue } + // } + // + // // swiftlint:disable identifier_name + // /// Internal property for `cardAddChallenge`. Created to avoid deprecation warnings upon accessing + // /// `cardAddChallenge` directly within our SDK. Use this value internally instead. + // var _cardAddChallenge: BTThreeDSecureCardAddChallenge = .unspecified + /// A delegate for receiving information about the ThreeDSecure payment flow. public weak var threeDSecureRequestDelegate: BTThreeDSecureRequestDelegate? @@ -60,7 +80,7 @@ import BraintreeCore billingAddress: BTThreeDSecurePostalAddress? = nil, cardAddChallengeRequested: Bool = false, challengeRequested: Bool = false, - customFields: [String: String]? = nil, + customFields: [String : String]? = nil, dataOnlyRequested: Bool = false, dfReferenceID: String? = nil, email: String? = nil, From 0d5d4e0afd78e2b8fde7627cdd693a3467587e2f Mon Sep 17 00:00:00 2001 From: ageddam Date: Wed, 6 Nov 2024 09:20:16 -0600 Subject: [PATCH 5/8] uncomment _cardAddChallenge and address pr comments --- .../BTThreeDSecureClient.swift | 4 +- .../BTThreeDSecureRequest.swift | 38 +++++++++---------- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/Sources/BraintreeThreeDSecure/BTThreeDSecureClient.swift b/Sources/BraintreeThreeDSecure/BTThreeDSecureClient.swift index 46f3a229a8..75c3316b44 100644 --- a/Sources/BraintreeThreeDSecure/BTThreeDSecureClient.swift +++ b/Sources/BraintreeThreeDSecure/BTThreeDSecureClient.swift @@ -424,9 +424,9 @@ import BraintreeCore requestParameters["customFields"] = customFields } - if request.cardAddChallengeRequested == true { + if request._cardAddChallenge == .requested || request.cardAddChallengeRequested == true { requestParameters["cardAdd"] = true - } else if request.cardAddChallengeRequested == false { + } else if request._cardAddChallenge == .notRequested { requestParameters["cardAdd"] = false } diff --git a/Sources/BraintreeThreeDSecure/BTThreeDSecureRequest.swift b/Sources/BraintreeThreeDSecure/BTThreeDSecureRequest.swift index 945157f865..36cfe1d6fd 100644 --- a/Sources/BraintreeThreeDSecure/BTThreeDSecureRequest.swift +++ b/Sources/BraintreeThreeDSecure/BTThreeDSecureRequest.swift @@ -28,25 +28,25 @@ import BraintreeCore var uiType: BTThreeDSecureUIType var v2UICustomization: BTThreeDSecureV2UICustomization? - // // NEXT_MAJOR_VERSION remove cardAddChallenge in favor of cardAddChallengeRequested - // /// Optional. An authentication created using this property should only be used for adding a payment method to the merchant's vault and not for creating transactions. - // /// - // /// Defaults to `.unspecified.` - // /// - // /// If set to `.challengeRequested`, the authentication challenge will be requested from the issuer to confirm adding new card to the merchant's vault. - // /// If set to `.notRequested` the authentication challenge will not be requested from the issuer. - // /// If set to `.unspecified`, when the amount is 0, the authentication challenge will be requested from the issuer. - // /// If set to `.unspecified`, when the amount is greater than 0, the authentication challenge will not be requested from the issuer. - // @available(*, deprecated, renamed: "cardAddChallengeRequested", message: "Use the `cardAddChallengeRequested` boolean property instead") - // public var cardAddChallenge: BTThreeDSecureCardAddChallenge { - // get { _cardAddChallenge } - // set { _cardAddChallenge = newValue } - // } - // - // // swiftlint:disable identifier_name - // /// Internal property for `cardAddChallenge`. Created to avoid deprecation warnings upon accessing - // /// `cardAddChallenge` directly within our SDK. Use this value internally instead. - // var _cardAddChallenge: BTThreeDSecureCardAddChallenge = .unspecified + // NEXT_MAJOR_VERSION remove cardAddChallenge in favor of cardAddChallengeRequested + /// Optional. An authentication created using this property should only be used for adding a payment method to the merchant's vault and not for creating transactions. + /// + /// Defaults to `.unspecified.` + /// + /// If set to `.challengeRequested`, the authentication challenge will be requested from the issuer to confirm adding new card to the merchant's vault. + /// If set to `.notRequested` the authentication challenge will not be requested from the issuer. + /// If set to `.unspecified`, when the amount is 0, the authentication challenge will be requested from the issuer. + /// If set to `.unspecified`, when the amount is greater than 0, the authentication challenge will not be requested from the issuer. + @available(*, deprecated, renamed: "cardAddChallengeRequested", message: "Use the `cardAddChallengeRequested` boolean property instead") + public var cardAddChallenge: BTThreeDSecureCardAddChallenge { + get { _cardAddChallenge } + set { _cardAddChallenge = newValue } + } + + // swiftlint:disable identifier_name + /// Internal property for `cardAddChallenge`. Created to avoid deprecation warnings upon accessing + /// `cardAddChallenge` directly within our SDK. Use this value internally instead. + var _cardAddChallenge: BTThreeDSecureCardAddChallenge = .unspecified /// A delegate for receiving information about the ThreeDSecure payment flow. public weak var threeDSecureRequestDelegate: BTThreeDSecureRequestDelegate? From b6f5382aefb7dc7a3467a891735988bba0a80a0d Mon Sep 17 00:00:00 2001 From: ageddam Date: Tue, 12 Nov 2024 12:44:26 -0600 Subject: [PATCH 6/8] address pr feedback --- .../BTThreeDSecureClient.swift | 2 +- .../BTThreeDSecureRequest.swift | 16 ++++++----- .../BTThreeDSecureClient_Tests.swift | 27 ++++--------------- 3 files changed, 15 insertions(+), 30 deletions(-) diff --git a/Sources/BraintreeThreeDSecure/BTThreeDSecureClient.swift b/Sources/BraintreeThreeDSecure/BTThreeDSecureClient.swift index 75c3316b44..b57146958c 100644 --- a/Sources/BraintreeThreeDSecure/BTThreeDSecureClient.swift +++ b/Sources/BraintreeThreeDSecure/BTThreeDSecureClient.swift @@ -59,7 +59,7 @@ import BraintreeCore return } - if request.amount?.decimalValue.isNaN == true || request.amount == nil { + if request.amount.decimalValue.isNaN == true { NSLog("%@ BTThreeDSecureRequest amount can not be nil or NaN.", BTLogLevelDescription.string(for: .critical)) let error = BTThreeDSecureError.configuration("BTThreeDSecureRequest amount can not be nil or NaN.") notifyFailure(with: error, completion: completion) diff --git a/Sources/BraintreeThreeDSecure/BTThreeDSecureRequest.swift b/Sources/BraintreeThreeDSecure/BTThreeDSecureRequest.swift index 36cfe1d6fd..59d31849a8 100644 --- a/Sources/BraintreeThreeDSecure/BTThreeDSecureRequest.swift +++ b/Sources/BraintreeThreeDSecure/BTThreeDSecureRequest.swift @@ -11,7 +11,7 @@ import BraintreeCore var accountType: BTThreeDSecureAccountType var additionalInformation: BTThreeDSecureAdditionalInformation? - var amount: NSDecimalNumber? + var amount: NSDecimalNumber var billingAddress: BTThreeDSecurePostalAddress? var cardAddChallengeRequested: Bool var challengeRequested: Bool @@ -57,17 +57,17 @@ import BraintreeCore /// - Parameters: /// - accountType: Optional. The account type selected by the cardholder. Some cards can be processed using either a credit or debit account and cardholders have the option to choose which account to use. /// - additionalInformation: Optional. The additional information used for verification. - /// - amount: The amount for the transaction. + /// - amount: Required. The amount for the transaction. /// - billingAddress: Optional. The billing address used for verification /// - cardAddChallengeRequested: Optional. An authentication created using this flag should only be used for vaulting operations (creation of customers' credit cards or payment methods) and not for creating transactions. If set to `true`, a card-add challenge will be requested from the issuer. If set to `false`, a card-add challenge will not be requested. If the parameter is missing, a card-add challenge will only be requested for $0 amount. /// - challengeRequested: Optional. If set to true, an authentication challenge will be forced if possible. - /// - customFields: Object where each key is the name of a custom field which has been configured in the Control Panel. In the Control Panel you can configure 3D Secure Rules which trigger on certain values. + /// - customFields: Optional. Object where each key is the name of a custom field which has been configured in the Control Panel. In the Control Panel you can configure 3D Secure Rules which trigger on certain values. /// - dataOnlyRequested: Optional. Indicates whether to use the data only flow. In this flow, frictionless 3DS is ensured for Mastercard cardholders as the card scheme provides a risk score for the issuer to determine whether to approve. If data only is not supported by the processor, a validation error will be raised. Non-Mastercard cardholders will fallback to a normal 3DS flow. - /// - dfReferenceID: The dfReferenceID for the session. Exposed for testing. + /// - dfReferenceID: Optional. The dfReferenceID for the session, particularly useful for merchants peforming 3DS lookup. Exposed for testing. /// - email: Optional. The email used for verification. /// - exemptionRequested: Optional. If set to true, an exemption to the authentication challenge will be requested. /// - mobilePhoneNumber: Optional. The mobile phone number used for verification. Only numbers. Remove dashes, parentheses and other characters. - /// - nonce: A nonce to be verified by ThreeDSecure + /// - nonce: Optional. A nonce to be verified by ThreeDSecure /// - renderTypes: Optional: List of all the render types that the device supports for displaying specific challenge user interfaces within the 3D Secure challenge. When using `BTThreeDSecureUIType.both` or `BTThreeDSecureUIType.html`, all `BTThreeDSecureRenderType` options must be set. When using `BTThreeDSecureUIType.native`, all `BTThreeDSecureRenderType` options except `.html` must be set. /// - requestedExemptionType: Optional. The exemption type to be requested. If an exemption is requested and the exemption's conditions are satisfied, then it will be applied. /// - shippingMethod: Optional. The shipping method chosen for the transaction @@ -76,11 +76,12 @@ import BraintreeCore public init( accountType: BTThreeDSecureAccountType = .unspecified, additionalInformation: BTThreeDSecureAdditionalInformation? = nil, - amount: NSDecimalNumber? = 0, + amount: NSDecimalNumber = 0, billingAddress: BTThreeDSecurePostalAddress? = nil, + _cardAddChallenge: BTThreeDSecureCardAddChallenge = .unspecified, cardAddChallengeRequested: Bool = false, challengeRequested: Bool = false, - customFields: [String : String]? = nil, + customFields: [String: String]? = nil, dataOnlyRequested: Bool = false, dfReferenceID: String? = nil, email: String? = nil, @@ -97,6 +98,7 @@ import BraintreeCore self.additionalInformation = additionalInformation self.amount = amount self.billingAddress = billingAddress + self._cardAddChallenge = _cardAddChallenge self.cardAddChallengeRequested = cardAddChallengeRequested self.challengeRequested = challengeRequested self.customFields = customFields diff --git a/UnitTests/BraintreeThreeDSecureTests/BTThreeDSecureClient_Tests.swift b/UnitTests/BraintreeThreeDSecureTests/BTThreeDSecureClient_Tests.swift index 7cac080c93..c32567be3e 100644 --- a/UnitTests/BraintreeThreeDSecureTests/BTThreeDSecureClient_Tests.swift +++ b/UnitTests/BraintreeThreeDSecureTests/BTThreeDSecureClient_Tests.swift @@ -45,6 +45,7 @@ class BTThreeDSecureClient_Tests: XCTestCase { accountType: .credit, amount: 9.97, billingAddress: billingAddress, + _cardAddChallenge: .requested, cardAddChallengeRequested: true, challengeRequested: true, dataOnlyRequested: true, @@ -112,6 +113,7 @@ class BTThreeDSecureClient_Tests: XCTestCase { threeDSecureRequest = BTThreeDSecureRequest( amount: 9.97, + _cardAddChallenge: .notRequested, cardAddChallengeRequested: false, dfReferenceID: "df-reference-id", nonce: "fake-card-nonce" @@ -136,7 +138,7 @@ class BTThreeDSecureClient_Tests: XCTestCase { ) client.performThreeDSecureLookup(threeDSecureRequest) { (lookup, error) in - XCTAssertFalse(self.mockAPIClient.lastPOSTParameters!["cardAdd"] as! Bool) + XCTAssertNil(self.mockAPIClient.lastPOSTParameters!["cardAdd"]) expectation.fulfill() } @@ -283,7 +285,7 @@ class BTThreeDSecureClient_Tests: XCTestCase { func testStartPaymentFlow_whenAmountIsNotANumber_throwsError() { mockAPIClient.cannedConfigurationResponseBody = mockConfiguration - let request = BTThreeDSecureRequest() + let request = BTThreeDSecureRequest(nonce: "fake-card-nonce") request.amount = NSDecimalNumber.notANumber let expectation = self.expectation(description: "Callback envoked") @@ -297,28 +299,9 @@ class BTThreeDSecureClient_Tests: XCTestCase { waitForExpectations(timeout: 1) XCTAssertTrue(mockAPIClient.postedAnalyticsEvents.contains(BTThreeDSecureAnalytics.verifyFailed)) } - - func testStartPaymentFlow_whenAmountIsNil_throwsError() { - mockAPIClient.cannedConfigurationResponseBody = mockConfiguration - - let request = BTThreeDSecureRequest() - request.amount = nil - - let expectation = expectation(description: "Callback envoked") - - client.startPaymentFlow(request) { result, error in - XCTAssertNil(result) - XCTAssertEqual(error?.localizedDescription, "BTThreeDSecureRequest amount can not be nil or NaN.") - expectation.fulfill() - } - - waitForExpectations(timeout: 1) - XCTAssertTrue(mockAPIClient.postedAnalyticsEvents.contains(BTThreeDSecureAnalytics.verifyFailed)) - } func testStartPayment_whenNoBodyReturned_returnsAnError() { - threeDSecureRequest = BTThreeDSecureRequest() - threeDSecureRequest.nonce = "fake-card-nonce" + threeDSecureRequest = BTThreeDSecureRequest(nonce: "fake-card-nonce") threeDSecureRequest.threeDSecureRequestDelegate = mockThreeDSecureRequestDelegate let expectation = expectation(description: "willCallCompletion") From 734aceaefd6517d150dde0efeb9df8a816061105 Mon Sep 17 00:00:00 2001 From: ageddam Date: Thu, 14 Nov 2024 10:03:46 -0600 Subject: [PATCH 7/8] code cleanup - update amount to string type, reorder required properties before optional --- .../Features/ThreeDSecureViewController.swift | 6 +- .../BTThreeDSecureClient.swift | 6 +- .../BTThreeDSecureRequest.swift | 18 ++--- .../BTThreeDSecureClient_Tests.swift | 42 +++++------ .../BTThreeDSecureRequest_Tests.swift | 69 ++++++++----------- 5 files changed, 63 insertions(+), 78 deletions(-) diff --git a/Demo/Application/Features/ThreeDSecureViewController.swift b/Demo/Application/Features/ThreeDSecureViewController.swift index 2d545a8f0d..49645b4c3c 100644 --- a/Demo/Application/Features/ThreeDSecureViewController.swift +++ b/Demo/Application/Features/ThreeDSecureViewController.swift @@ -103,11 +103,11 @@ class ThreeDSecureViewController: PaymentButtonBaseViewController { billingAddress.phoneNumber = "8101234567" let request = BTThreeDSecureRequest( - accountType: .credit, - amount: 10.32, + amount: "10.32", + nonce: nonce, + accountType: .credit, billingAddress: billingAddress, email: "test@example.com", - nonce: nonce, renderTypes: [.otp, .singleSelect, .multiSelect, .oob, .html], requestedExemptionType: .lowValue, shippingMethod: .sameDay, diff --git a/Sources/BraintreeThreeDSecure/BTThreeDSecureClient.swift b/Sources/BraintreeThreeDSecure/BTThreeDSecureClient.swift index b57146958c..f6ced339ce 100644 --- a/Sources/BraintreeThreeDSecure/BTThreeDSecureClient.swift +++ b/Sources/BraintreeThreeDSecure/BTThreeDSecureClient.swift @@ -59,7 +59,7 @@ import BraintreeCore return } - if request.amount.decimalValue.isNaN == true { + if request.amount.isEmpty { NSLog("%@ BTThreeDSecureRequest amount can not be nil or NaN.", BTLogLevelDescription.string(for: .critical)) let error = BTThreeDSecureError.configuration("BTThreeDSecureRequest amount can not be nil or NaN.") notifyFailure(with: error, completion: completion) @@ -103,7 +103,7 @@ import BraintreeCore return } - guard request.nonce != nil else { + if request.nonce.isEmpty { notifyFailure( with: BTThreeDSecureError.configuration("BTThreeDSecureRequest nonce can not be nil."), completion: completion @@ -346,7 +346,7 @@ import BraintreeCore } let requestParameters = self.buildRequestDictionary(with: request) - guard let urlSafeNonce = request.nonce?.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) else { + guard let urlSafeNonce = request.nonce.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) else { self.apiClient.sendAnalyticsEvent(BTThreeDSecureAnalytics.lookupFailed) self.notifyFailure( with: BTThreeDSecureError.failedAuthentication("Tokenized card nonce is required."), diff --git a/Sources/BraintreeThreeDSecure/BTThreeDSecureRequest.swift b/Sources/BraintreeThreeDSecure/BTThreeDSecureRequest.swift index 59d31849a8..a4b9855e65 100644 --- a/Sources/BraintreeThreeDSecure/BTThreeDSecureRequest.swift +++ b/Sources/BraintreeThreeDSecure/BTThreeDSecureRequest.swift @@ -9,9 +9,10 @@ import BraintreeCore // MARK: - Internal Properties + var amount: String + var nonce: String var accountType: BTThreeDSecureAccountType var additionalInformation: BTThreeDSecureAdditionalInformation? - var amount: NSDecimalNumber var billingAddress: BTThreeDSecurePostalAddress? var cardAddChallengeRequested: Bool var challengeRequested: Bool @@ -21,7 +22,6 @@ import BraintreeCore var email: String? var exemptionRequested: Bool var mobilePhoneNumber: String? - var nonce: String? var renderTypes: [BTThreeDSecureRenderType]? var requestedExemptionType: BTThreeDSecureRequestedExemptionType var shippingMethod: BTThreeDSecureShippingMethod @@ -55,28 +55,29 @@ import BraintreeCore /// Creates a `BTThreeDSecureRequest` /// - Parameters: + /// - amount: Required. The amount for the transaction. + /// - nonce: Required. A nonce to be verified by ThreeDSecure. /// - accountType: Optional. The account type selected by the cardholder. Some cards can be processed using either a credit or debit account and cardholders have the option to choose which account to use. /// - additionalInformation: Optional. The additional information used for verification. - /// - amount: Required. The amount for the transaction. /// - billingAddress: Optional. The billing address used for verification /// - cardAddChallengeRequested: Optional. An authentication created using this flag should only be used for vaulting operations (creation of customers' credit cards or payment methods) and not for creating transactions. If set to `true`, a card-add challenge will be requested from the issuer. If set to `false`, a card-add challenge will not be requested. If the parameter is missing, a card-add challenge will only be requested for $0 amount. /// - challengeRequested: Optional. If set to true, an authentication challenge will be forced if possible. /// - customFields: Optional. Object where each key is the name of a custom field which has been configured in the Control Panel. In the Control Panel you can configure 3D Secure Rules which trigger on certain values. /// - dataOnlyRequested: Optional. Indicates whether to use the data only flow. In this flow, frictionless 3DS is ensured for Mastercard cardholders as the card scheme provides a risk score for the issuer to determine whether to approve. If data only is not supported by the processor, a validation error will be raised. Non-Mastercard cardholders will fallback to a normal 3DS flow. - /// - dfReferenceID: Optional. The dfReferenceID for the session, particularly useful for merchants peforming 3DS lookup. Exposed for testing. + /// - dfReferenceID: Optional. The dfReferenceID for the session, particularly useful for merchants performing 3DS lookup. /// - email: Optional. The email used for verification. /// - exemptionRequested: Optional. If set to true, an exemption to the authentication challenge will be requested. /// - mobilePhoneNumber: Optional. The mobile phone number used for verification. Only numbers. Remove dashes, parentheses and other characters. - /// - nonce: Optional. A nonce to be verified by ThreeDSecure /// - renderTypes: Optional: List of all the render types that the device supports for displaying specific challenge user interfaces within the 3D Secure challenge. When using `BTThreeDSecureUIType.both` or `BTThreeDSecureUIType.html`, all `BTThreeDSecureRenderType` options must be set. When using `BTThreeDSecureUIType.native`, all `BTThreeDSecureRenderType` options except `.html` must be set. /// - requestedExemptionType: Optional. The exemption type to be requested. If an exemption is requested and the exemption's conditions are satisfied, then it will be applied. /// - shippingMethod: Optional. The shipping method chosen for the transaction /// - uiType: Optional: Sets all UI types that the device supports for displaying specific challenge user interfaces in the 3D Secure challenge. Defaults to `.both` /// - v2UICustomization: Optional. UI Customization for 3DS2 challenge views. public init( + amount: String, + nonce: String, accountType: BTThreeDSecureAccountType = .unspecified, additionalInformation: BTThreeDSecureAdditionalInformation? = nil, - amount: NSDecimalNumber = 0, billingAddress: BTThreeDSecurePostalAddress? = nil, _cardAddChallenge: BTThreeDSecureCardAddChallenge = .unspecified, cardAddChallengeRequested: Bool = false, @@ -87,16 +88,16 @@ import BraintreeCore email: String? = nil, exemptionRequested: Bool = false, mobilePhoneNumber: String? = nil, - nonce: String? = nil, renderTypes: [BTThreeDSecureRenderType]? = nil, requestedExemptionType: BTThreeDSecureRequestedExemptionType = .unspecified, shippingMethod: BTThreeDSecureShippingMethod = .unspecified, uiType: BTThreeDSecureUIType = .both, v2UICustomization: BTThreeDSecureV2UICustomization? = nil ) { + self.amount = amount + self.nonce = nonce self.accountType = accountType self.additionalInformation = additionalInformation - self.amount = amount self.billingAddress = billingAddress self._cardAddChallenge = _cardAddChallenge self.cardAddChallengeRequested = cardAddChallengeRequested @@ -107,7 +108,6 @@ import BraintreeCore self.email = email self.exemptionRequested = exemptionRequested self.mobilePhoneNumber = mobilePhoneNumber - self.nonce = nonce self.renderTypes = renderTypes self.requestedExemptionType = requestedExemptionType self.shippingMethod = shippingMethod diff --git a/UnitTests/BraintreeThreeDSecureTests/BTThreeDSecureClient_Tests.swift b/UnitTests/BraintreeThreeDSecureTests/BTThreeDSecureClient_Tests.swift index c32567be3e..fa17b124d3 100644 --- a/UnitTests/BraintreeThreeDSecureTests/BTThreeDSecureClient_Tests.swift +++ b/UnitTests/BraintreeThreeDSecureTests/BTThreeDSecureClient_Tests.swift @@ -18,7 +18,7 @@ class BTThreeDSecureClient_Tests: XCTestCase { override func setUp() { super.setUp() - threeDSecureRequest = BTThreeDSecureRequest(amount: 10.0, nonce: "fake-card-nonce") + threeDSecureRequest = BTThreeDSecureRequest(amount: "10.00", nonce: "fake-card-nonce") client = BTThreeDSecureClient(apiClient: mockAPIClient) client.cardinalSession = MockCardinalSession() mockThreeDSecureRequestDelegate = MockThreeDSecureRequestDelegate() @@ -42,9 +42,10 @@ class BTThreeDSecureClient_Tests: XCTestCase { billingAddress.postalCode = "54321" threeDSecureRequest = BTThreeDSecureRequest( - accountType: .credit, - amount: 9.97, - billingAddress: billingAddress, + amount: "9.97", + nonce: "fake-card-nonce", + accountType: .credit, + billingAddress: billingAddress, _cardAddChallenge: .requested, cardAddChallengeRequested: true, challengeRequested: true, @@ -53,12 +54,11 @@ class BTThreeDSecureClient_Tests: XCTestCase { email: "tester@example.com", exemptionRequested: true, mobilePhoneNumber: "5151234321", - nonce: "fake-card-nonce", shippingMethod: .priority ) client.performThreeDSecureLookup(threeDSecureRequest) { (lookup, error) in - XCTAssertEqual(self.mockAPIClient.lastPOSTParameters!["amount"] as! NSDecimalNumber, 9.97) + XCTAssertEqual(self.mockAPIClient.lastPOSTParameters!["amount"] as! String, "9.97") XCTAssertEqual(self.mockAPIClient.lastPOSTParameters!["requestedThreeDSecureVersion"] as! String, "2") XCTAssertEqual(self.mockAPIClient.lastPOSTParameters!["dfReferenceId"] as! String, "df-reference-id") XCTAssertEqual(self.mockAPIClient.lastPOSTParameters!["accountType"] as! String, "credit") @@ -93,10 +93,10 @@ class BTThreeDSecureClient_Tests: XCTestCase { let expectation = expectation(description: "willCallCompletion") threeDSecureRequest.nonce = "fake-card-nonce" - threeDSecureRequest.amount = 9.99 + threeDSecureRequest.amount = "9.99" client.performThreeDSecureLookup(threeDSecureRequest) { _, _ in - XCTAssertEqual(self.mockAPIClient.lastPOSTParameters!["amount"] as! NSDecimalNumber, 9.99) + XCTAssertEqual(self.mockAPIClient.lastPOSTParameters!["amount"] as! String, "9.99") XCTAssertEqual(self.mockAPIClient.lastPOSTParameters!["requestedThreeDSecureVersion"] as! String, "2") XCTAssertNil(self.mockAPIClient.lastPOSTParameters!["dfReferenceId"] as? String) XCTAssertNil(self.mockAPIClient.lastPOSTParameters!["accountType"] as? String) @@ -112,11 +112,11 @@ class BTThreeDSecureClient_Tests: XCTestCase { let expectation = self.expectation(description: "willCallCompletion") threeDSecureRequest = BTThreeDSecureRequest( - amount: 9.97, + amount: "9.97", + nonce: "fake-card-nonce", _cardAddChallenge: .notRequested, cardAddChallengeRequested: false, - dfReferenceID: "df-reference-id", - nonce: "fake-card-nonce" + dfReferenceID: "df-reference-id" ) client.performThreeDSecureLookup(threeDSecureRequest) { (lookup, error) in @@ -132,9 +132,9 @@ class BTThreeDSecureClient_Tests: XCTestCase { let expectation = self.expectation(description: "willCallCompletion") threeDSecureRequest = BTThreeDSecureRequest( - amount: 9.97, - dfReferenceID: "df-reference-id", - nonce: "fake-card-nonce" + amount: "9.97", + nonce: "fake-card-nonce", + dfReferenceID: "df-reference-id" ) client.performThreeDSecureLookup(threeDSecureRequest) { (lookup, error) in @@ -149,10 +149,10 @@ class BTThreeDSecureClient_Tests: XCTestCase { func testPerformThreeDSecureLookup_whenCardAddChallengeRequested_sendsCardAddTrue() { threeDSecureRequest = BTThreeDSecureRequest( - amount: 9.97, + amount: "9.97", + nonce: "fake-card-nonce", cardAddChallengeRequested: true, - dfReferenceID: "df-reference-id", - nonce: "fake-card-nonce" + dfReferenceID: "df-reference-id" ) let expectation = expectation(description: "willCallCompletion") @@ -282,11 +282,11 @@ class BTThreeDSecureClient_Tests: XCTestCase { // MARK: - startPaymentFlow - func testStartPaymentFlow_whenAmountIsNotANumber_throwsError() { + func testStartPaymentFlow_whenAmountIsEmpty_throwsError() { mockAPIClient.cannedConfigurationResponseBody = mockConfiguration - let request = BTThreeDSecureRequest(nonce: "fake-card-nonce") - request.amount = NSDecimalNumber.notANumber + let request = BTThreeDSecureRequest(amount: "10.00", nonce: "fake-card-nonce") + request.amount = "" let expectation = self.expectation(description: "Callback envoked") @@ -301,7 +301,7 @@ class BTThreeDSecureClient_Tests: XCTestCase { } func testStartPayment_whenNoBodyReturned_returnsAnError() { - threeDSecureRequest = BTThreeDSecureRequest(nonce: "fake-card-nonce") + threeDSecureRequest = BTThreeDSecureRequest(amount: "10.00", nonce: "fake-card-nonce") threeDSecureRequest.threeDSecureRequestDelegate = mockThreeDSecureRequestDelegate let expectation = expectation(description: "willCallCompletion") diff --git a/UnitTests/BraintreeThreeDSecureTests/BTThreeDSecureRequest_Tests.swift b/UnitTests/BraintreeThreeDSecureTests/BTThreeDSecureRequest_Tests.swift index b02b1e91e0..e3d1033f1d 100644 --- a/UnitTests/BraintreeThreeDSecureTests/BTThreeDSecureRequest_Tests.swift +++ b/UnitTests/BraintreeThreeDSecureTests/BTThreeDSecureRequest_Tests.swift @@ -8,7 +8,7 @@ class BTThreeDSecureRequest_Tests: XCTestCase { // MARK: - accountTypeAsString func testCustomFields_notNil() { - let request = BTThreeDSecureRequest() + let request = BTThreeDSecureRequest(amount: "10.0", nonce: "fake-nonce") XCTAssertNil(request.customFields) request.customFields = ["test": "test"] @@ -16,139 +16,124 @@ class BTThreeDSecureRequest_Tests: XCTestCase { } func testAccountTypeAsString_whenAccountTypeIsCredit_returnsCredit() { - let request = BTThreeDSecureRequest() - request.accountType = .credit + let request = BTThreeDSecureRequest(amount: "10.00", nonce: "fake-nonce", accountType: .credit) XCTAssertEqual(request.accountType.stringValue, "credit") } func testAccountTypeAsString_whenAccountTypeIsDebit_returnsDebit() { - let request = BTThreeDSecureRequest() - request.accountType = .debit + let request = BTThreeDSecureRequest(amount: "10.00", nonce: "fake-nonce", accountType: .debit) XCTAssertEqual(request.accountType.stringValue, "debit") } func testAccountTypeAsString_whenAccountTypeIsUnspecified_returnsNil() { - let request = BTThreeDSecureRequest() - request.accountType = .unspecified + let request = BTThreeDSecureRequest(amount: "10.00", nonce: "fake-nonce", accountType: .unspecified) XCTAssertEqual(request.accountType.stringValue, nil) } func testAccountTypeAsString_whenAccountTypeIsNotSet_returnsNil() { - let request = BTThreeDSecureRequest() + let request = BTThreeDSecureRequest(amount: "10.00", nonce: "fake-nonce") XCTAssertEqual(request.accountType.stringValue, nil) } // MARK: - shippingMethodAsString func testShippingMethodAsString_whenShippingMethodIsSameDay_returns01() { - let request = BTThreeDSecureRequest() - request.shippingMethod = .sameDay + let request = BTThreeDSecureRequest(amount: "10.00", nonce: "fake-nonce", shippingMethod: .sameDay) XCTAssertEqual(request.shippingMethod.stringValue, "01") } func testShippingMethodAsString_whenShippingMethodIsExpedited_returns02() { - let request = BTThreeDSecureRequest() - request.shippingMethod = .expedited + let request = BTThreeDSecureRequest(amount: "10.00", nonce: "fake-nonce", shippingMethod: .expedited) XCTAssertEqual(request.shippingMethod.stringValue, "02") } func testShippingMethodAsString_whenShippingMethodIsPriority_returns03() { - let request = BTThreeDSecureRequest() - request.shippingMethod = .priority + let request = BTThreeDSecureRequest(amount: "10.00", nonce: "fake-nonce", shippingMethod: .priority) XCTAssertEqual(request.shippingMethod.stringValue, "03") } func testShippingMethodAsString_whenShippingMethodIsGround_returns04() { - let request = BTThreeDSecureRequest() - request.shippingMethod = .ground + let request = BTThreeDSecureRequest(amount: "10.00", nonce: "fake-nonce", shippingMethod: .ground) XCTAssertEqual(request.shippingMethod.stringValue, "04") } func testShippingMethodAsString_whenShippingMethodIsElectronicDelivery_returns05() { - let request = BTThreeDSecureRequest() - request.shippingMethod = .electronicDelivery + let request = BTThreeDSecureRequest(amount: "10.00", nonce: "fake-nonce", shippingMethod: .electronicDelivery) XCTAssertEqual(request.shippingMethod.stringValue, "05") } func testShippingMethodAsString_whenShippingMethodIsShipToStore_returns06() { - let request = BTThreeDSecureRequest() - request.shippingMethod = .shipToStore + let request = BTThreeDSecureRequest(amount: "10.00", nonce: "fake-nonce", shippingMethod: .shipToStore) XCTAssertEqual(request.shippingMethod.stringValue, "06") } func testShippingMethodAsString_whenShippingMethodIsUnspecified_returnsNil() { - let request = BTThreeDSecureRequest() - request.shippingMethod = .unspecified + let request = BTThreeDSecureRequest(amount: "10.00", nonce: "fake-nonce", shippingMethod: .unspecified) XCTAssertEqual(request.shippingMethod.stringValue, nil) } func testShippingMethodAsString_whenShippingMethodIsNotSet_returnsNil() { - let request = BTThreeDSecureRequest() + let request = BTThreeDSecureRequest(amount: "10.00", nonce: "fake-nonce") XCTAssertEqual(request.shippingMethod.stringValue, nil) } // MARK: - requestedExemptionTypeAsString func testRequestedExemptionTypeAsString_whenRequestedExemptionTypeIsLowValue_returnsLowValue() { - let request = BTThreeDSecureRequest() - request.requestedExemptionType = .lowValue + let request = BTThreeDSecureRequest(amount: "10.00", nonce: "fake-nonce", requestedExemptionType: .lowValue) XCTAssertEqual(request.requestedExemptionType.stringValue, "low_value") } func testRequestedExemptionTypeAsString_whenRequestedExemptionTypeIsSecureCorporate_returnsSecureCorporate() { - let request = BTThreeDSecureRequest() - request.requestedExemptionType = .secureCorporate + let request = BTThreeDSecureRequest(amount: "10.00", nonce: "fake-nonce", requestedExemptionType: .secureCorporate) XCTAssertEqual(request.requestedExemptionType.stringValue, "secure_corporate") } func testRequestedExemptionTypeAsString_whenRequestedExemptionTypeIsTrustedBeneficiary_returnsTrustedBeneficiary() { - let request = BTThreeDSecureRequest() - request.requestedExemptionType = .trustedBeneficiary + let request = BTThreeDSecureRequest(amount: "10.00", nonce: "fake-nonce", requestedExemptionType: .trustedBeneficiary) XCTAssertEqual(request.requestedExemptionType.stringValue, "trusted_beneficiary") } func testRequestedExemptionTypeAsString_whenRequestedExemptionTypeIsTransactionRiskAnalysis_returnsTransactionRiskAnalysis() { - let request = BTThreeDSecureRequest() - request.requestedExemptionType = .transactionRiskAnalysis + let request = BTThreeDSecureRequest(amount: "10.00", nonce: "fake-nonce", requestedExemptionType: .transactionRiskAnalysis) XCTAssertEqual(request.requestedExemptionType.stringValue, "transaction_risk_analysis") } func testRequestedExemptionTypeAsString_whenAccountTypeIsUnspecified_returnsNil() { - let request = BTThreeDSecureRequest() - request.requestedExemptionType = .unspecified + let request = BTThreeDSecureRequest(amount: "10.00", nonce: "fake-nonce", requestedExemptionType: .unspecified) XCTAssertEqual(request.requestedExemptionType.stringValue, nil) } func testRequestedExemptionTypeAsString_whenAccountTypeIsNotSet_returnsNil() { - let request = BTThreeDSecureRequest() + let request = BTThreeDSecureRequest(amount: "10.00", nonce: "fake-nonce") XCTAssertEqual(request.requestedExemptionType.stringValue, nil) } // MARK: - UIType func testUIType_whenUITypeNative_setsCardinalUITypeNative() { - let request = BTThreeDSecureRequest() - request.uiType = .native + let request = BTThreeDSecureRequest(amount: "10.00", nonce: "fake-nonce", uiType: .native) XCTAssertEqual(request.uiType.cardinalValue, CardinalSessionUIType.native) } func testUIType_whenUITypeHTML_setsCardinalUITypeHTML() { - let request = BTThreeDSecureRequest() - request.uiType = .html + let request = BTThreeDSecureRequest(amount: "10.00", nonce: "fake-nonce", uiType: .html) XCTAssertEqual(request.uiType.cardinalValue, CardinalSessionUIType.HTML) } func testUIType_whenUITypeBoth_setsCardinalUITypeBoth() { - let request = BTThreeDSecureRequest() - request.uiType = .both + let request = BTThreeDSecureRequest(amount: "10.00", nonce: "fake-nonce", uiType: .both) XCTAssertEqual(request.uiType.cardinalValue, CardinalSessionUIType.both) } // MARK: RenderTypes func testRenderTypes_whenAllRenderTypesAreSet_setsAllCardinalRenderTypes() { - let request = BTThreeDSecureRequest() - request.renderTypes = [.otp, .singleSelect, .multiSelect, .oob, .html] + let request = BTThreeDSecureRequest( + amount: "10.00", + nonce: "fake-nonce", + renderTypes: [.otp, .singleSelect, .multiSelect, .oob, .html] + ) XCTAssertEqual( request.renderTypes?.compactMap { $0.cardinalValue }, From db2c4182c757dfeb5f9c29c331ffa3ae09587980 Mon Sep 17 00:00:00 2001 From: ageddam Date: Mon, 18 Nov 2024 11:57:36 -0600 Subject: [PATCH 8/8] cleanup and address pr feedback --- CHANGELOG.md | 1 + Sources/BraintreeThreeDSecure/BTThreeDSecureClient.swift | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6177eec7d4..1f0641449f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ * Remove `BTCardRequest`, use `BTCard` directly instead * BraintreeThreeDSecure * Update `BTThreeDSecureRequest` to make all properties accessible on the initializer only vs via the dot syntax. + * Update `BTThreeDSecureRequest.amount` to be a `String` ## unreleased * BraintreePayPal diff --git a/Sources/BraintreeThreeDSecure/BTThreeDSecureClient.swift b/Sources/BraintreeThreeDSecure/BTThreeDSecureClient.swift index f6ced339ce..672da2c270 100644 --- a/Sources/BraintreeThreeDSecure/BTThreeDSecureClient.swift +++ b/Sources/BraintreeThreeDSecure/BTThreeDSecureClient.swift @@ -60,7 +60,7 @@ import BraintreeCore } if request.amount.isEmpty { - NSLog("%@ BTThreeDSecureRequest amount can not be nil or NaN.", BTLogLevelDescription.string(for: .critical)) + NSLog("%@ BTThreeDSecureRequest amount cannot be an empty string.", BTLogLevelDescription.string(for: .critical)) let error = BTThreeDSecureError.configuration("BTThreeDSecureRequest amount can not be nil or NaN.") notifyFailure(with: error, completion: completion) return @@ -105,7 +105,7 @@ import BraintreeCore if request.nonce.isEmpty { notifyFailure( - with: BTThreeDSecureError.configuration("BTThreeDSecureRequest nonce can not be nil."), + with: BTThreeDSecureError.configuration("BTThreeDSecureRequest nonce cannot be an empty string."), completion: completion ) return