Skip to content

Commit

Permalink
Merge branch 'main' into create-encodable-for-credit-cards-post
Browse files Browse the repository at this point in the history
  • Loading branch information
warmkesselj committed Dec 16, 2024
2 parents 9062d97 + 652e696 commit d1e9d9b
Show file tree
Hide file tree
Showing 24 changed files with 180 additions and 198 deletions.
1 change: 1 addition & 0 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ Thank you for your contribution to Braintree.
### Checklist

- [ ] Added a changelog entry
- [ ] Tested and confirmed payment flows affected by this change are functioning as expected

### Authors
> List GitHub usernames for everyone who contributed to this pull request.
Expand Down
2 changes: 1 addition & 1 deletion Braintree.podspec
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = "Braintree"
s.version = "6.24.0"
s.version = "6.25.0"
s.summary = "Braintree iOS SDK: Helps you accept card and alternative payments in your iOS app."
s.description = <<-DESC
Braintree is a full-stack payments platform for developers
Expand Down
4 changes: 4 additions & 0 deletions Braintree.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@
800ED7832B4F5B66007D8A30 /* BTEligiblePaymentsRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 800ED7822B4F5B66007D8A30 /* BTEligiblePaymentsRequest.swift */; };
800FC544257FDC5100DEE132 /* BTApplePayCardNonce_Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 800FC543257FDC5100DEE132 /* BTApplePayCardNonce_Tests.swift */; };
8014221C2BAE935B009F9999 /* BTPayPalApprovalURLParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8014221B2BAE935B009F9999 /* BTPayPalApprovalURLParser.swift */; };
802055222CDC29FE000BE30F /* BraintreeAmexExpress_IntegrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 802055212CDC29FE000BE30F /* BraintreeAmexExpress_IntegrationTests.swift */; };
8037BFB02B2CCC130017072C /* BTShopperInsightsAnalytics.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8037BFAF2B2CCC130017072C /* BTShopperInsightsAnalytics.swift */; };
804326BF2B1A5C5B0044E90B /* BTApplePaymentTokensRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 804326BE2B1A5C5B0044E90B /* BTApplePaymentTokensRequest.swift */; };
804698372B27C5390090878E /* BTShopperInsightsClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8064F38E2B1E492F0059C4CB /* BTShopperInsightsClient.swift */; };
Expand Down Expand Up @@ -841,6 +842,7 @@
800ED7822B4F5B66007D8A30 /* BTEligiblePaymentsRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BTEligiblePaymentsRequest.swift; sourceTree = "<group>"; };
800FC543257FDC5100DEE132 /* BTApplePayCardNonce_Tests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BTApplePayCardNonce_Tests.swift; sourceTree = "<group>"; };
8014221B2BAE935B009F9999 /* BTPayPalApprovalURLParser.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BTPayPalApprovalURLParser.swift; sourceTree = "<group>"; };
802055212CDC29FE000BE30F /* BraintreeAmexExpress_IntegrationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BraintreeAmexExpress_IntegrationTests.swift; sourceTree = "<group>"; };
8037BFAF2B2CCC130017072C /* BTShopperInsightsAnalytics.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BTShopperInsightsAnalytics.swift; sourceTree = "<group>"; };
804326BE2B1A5C5B0044E90B /* BTApplePaymentTokensRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BTApplePaymentTokensRequest.swift; sourceTree = "<group>"; };
804698302B27C5340090878E /* BraintreeShopperInsights.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = BraintreeShopperInsights.framework; sourceTree = BUILT_PRODUCTS_DIR; };
Expand Down Expand Up @@ -1778,6 +1780,7 @@
isa = PBXGroup;
children = (
A7ABD65D1B702FF000A1223C /* Braintree-API-Integration-Specs */,
802055212CDC29FE000BE30F /* BraintreeAmexExpress_IntegrationTests.swift */,
BE7BBDAE2AE9B628004E7AFC /* BraintreeApplePay_IntegrationTests.swift */,
BE7BBDB22AE9B913004E7AFC /* BraintreeDataCollector_IntegrationTests.swift */,
57D9436F296CC79B0079EAB1 /* BraintreePayPal_IntegrationTests.swift */,
Expand Down Expand Up @@ -3462,6 +3465,7 @@
57D94372296CCA2F0079EAB1 /* String+NonceValidation.swift in Sources */,
BE1ACEF72938F0B800707330 /* BTHTTP_SSLPinning_IntegrationTests.swift in Sources */,
BEEB565B2AE9B3030029F264 /* BTIntegrationTestsConstants.swift in Sources */,
802055222CDC29FE000BE30F /* BraintreeAmexExpress_IntegrationTests.swift in Sources */,
BE7BBDB32AE9B913004E7AFC /* BraintreeDataCollector_IntegrationTests.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand Down
8 changes: 7 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
# Braintree iOS SDK Release Notes

## unreleased
## 6.25.0 (2024-12-11)
* BraintreePayPal
* Add `BTPayPalRequest.userPhoneNumber` optional property
* Send `url` in `event_params` for App Switch events to PayPal's analytics service (FPTI)
* BraintreeVenmo
* Send `url` in `event_params` for App Switch events to PayPal's analytics service (FPTI)
* Add `BTVenmoClient(apiClient:universalLink:)` to use Universal Links when redirecting back from the Venmo flow
* BraintreeCore
* Deprecate `BTAppContextSwitcher.sharedInstance.returnURLScheme`
* BraintreeThreeDSecure
* Add `BTThreeDSecureRequest.requestorAppURL`

## 6.24.0 (2024-10-15)
* BraintreePayPal
Expand Down
18 changes: 14 additions & 4 deletions Demo/Application/Features/VenmoViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,16 @@ import UIKit
import BraintreeVenmo

class VenmoViewController: PaymentButtonBaseViewController {

// swiftlint:disable:next implicitly_unwrapped_optional
var venmoClient: BTVenmoClient!

let webFallbackToggle = Toggle(title: "Enable Web Fallback")
let vaultToggle = Toggle(title: "Vault")

let universalLinkReturnToggle = Toggle(title: "Use Universal Link Return")

override func viewDidLoad() {
super.heightConstraint = 150
super.viewDidLoad()
venmoClient = BTVenmoClient(apiClient: apiClient)
title = "Custom Venmo Button"
Expand All @@ -18,7 +20,7 @@ class VenmoViewController: PaymentButtonBaseViewController {
override func createPaymentButton() -> UIView {
let venmoButton = createButton(title: "Venmo", action: #selector(tappedVenmo))

let stackView = UIStackView(arrangedSubviews: [webFallbackToggle, vaultToggle, venmoButton])
let stackView = UIStackView(arrangedSubviews: [webFallbackToggle, vaultToggle, universalLinkReturnToggle, venmoButton])
stackView.axis = .vertical
stackView.spacing = 15
stackView.alignment = .fill
Expand All @@ -40,7 +42,15 @@ class VenmoViewController: PaymentButtonBaseViewController {
if vaultToggle.isOn {
venmoRequest.vault = true
}


if universalLinkReturnToggle.isOn {
venmoClient = BTVenmoClient(
apiClient: apiClient,
// swiftlint:disable:next force_unwrapping
universalLink: URL(string: "https://mobile-sdk-demo-site-838cead5d3ab.herokuapp.com/braintree-payments")!
)
}

Task {
do {
let venmoAccount = try await venmoClient.tokenize(venmoRequest)
Expand Down
4 changes: 2 additions & 2 deletions Demo/Application/Supporting Files/Braintree-Demo-Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>6.24.0</string>
<string>6.25.0</string>
<key>CFBundleURLTypes</key>
<array>
<dict>
Expand All @@ -56,7 +56,7 @@
</dict>
</array>
<key>CFBundleVersion</key>
<string>6.24.0</string>
<string>6.25.0</string>
<key>LSApplicationQueriesSchemes</key>
<array>
<string>com.braintreepayments.Demo.payments</string>
Expand Down
12 changes: 0 additions & 12 deletions Demo/Demo.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
42C574B725FA66FB008B3681 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 42C574B625FA66FB008B3681 /* Assets.xcassets */; };
42C574BA25FA66FB008B3681 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 42C574B825FA66FB008B3681 /* LaunchScreen.storyboard */; };
42C574D525FA6CAC008B3681 /* AppSwitcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42C574D425FA6CAC008B3681 /* AppSwitcher.swift */; };
42C5BDD625A4CE4800E8FF40 /* AmericanExpress_UITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42C5BDD525A4CE4800E8FF40 /* AmericanExpress_UITests.swift */; };
45DDDDA92C08FB0B00C262E5 /* PayPalMessages in Frameworks */ = {isa = PBXBuildFile; productRef = 45DDDDA82C08FB0B00C262E5 /* PayPalMessages */; };
57108A152832E789004EB870 /* PayPalNativeCheckoutViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57108A142832E789004EB870 /* PayPalNativeCheckoutViewController.swift */; };
57108A172832EA04004EB870 /* BraintreePayPalNativeCheckout.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 57108A162832EA04004EB870 /* BraintreePayPalNativeCheckout.framework */; };
Expand Down Expand Up @@ -141,7 +140,6 @@
42C574B925FA66FB008B3681 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
42C574BB25FA66FB008B3681 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
42C574D425FA6CAC008B3681 /* AppSwitcher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppSwitcher.swift; sourceTree = "<group>"; };
42C5BDD525A4CE4800E8FF40 /* AmericanExpress_UITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AmericanExpress_UITests.swift; sourceTree = "<group>"; };
42F3F6DB2603B83100401B0D /* CardinalMobile.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = CardinalMobile.xcframework; path = ../Frameworks/CardinalMobile.xcframework; sourceTree = "<group>"; };
570B93D32853A6D30041BAFE /* BraintreeCoreSwift.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = BraintreeCoreSwift.framework; sourceTree = BUILT_PRODUCTS_DIR; };
57108A142832E789004EB870 /* PayPalNativeCheckoutViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PayPalNativeCheckoutViewController.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -272,14 +270,6 @@
path = MockVenmo;
sourceTree = "<group>";
};
42C5BDD425A4CE2E00E8FF40 /* American Express UI Tests */ = {
isa = PBXGroup;
children = (
42C5BDD525A4CE4800E8FF40 /* AmericanExpress_UITests.swift */,
);
path = "American Express UI Tests";
sourceTree = "<group>";
};
80581A752553187800006F53 /* Venmo UI Tests */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -414,7 +404,6 @@
A9B5ABDF24EB2A2200A4E1C8 /* UI Tests */ = {
isa = PBXGroup;
children = (
42C5BDD425A4CE2E00E8FF40 /* American Express UI Tests */,
42456E3B25474B620018374E /* Helpers */,
A9B5ABE224EB2A2200A4E1C8 /* Info.plist */,
BEF137E32B33818C00B9B225 /* PayPal Messaging UI Tests */,
Expand Down Expand Up @@ -729,7 +718,6 @@
A9C4E07B24EC290F002F6FF2 /* PayPal_Vault_UITests.swift in Sources */,
A9C4E07D24EC297F002F6FF2 /* ThreeDSecure_V2_UITests.swift in Sources */,
42456E3E25474B620018374E /* BTUITest.swift in Sources */,
42C5BDD625A4CE4800E8FF40 /* AmericanExpress_UITests.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,10 @@ final class PayPalMessaging_Success_UITests: XCTestCase {
func testStart_withValidRequest_firesDelegates() {
XCTAssertTrue(app.buttons["DELEGATE: didAppear fired"].waitForExistence(timeout: 30))

let expectedButtonText = "PayPal - Pay monthly for purchases of $199-$10,000. Learn more"
waitForElementToBeHittable(app.buttons[expectedButtonText])
app.buttons[expectedButtonText].tap()
let expectedButtonTextPredicate = NSPredicate(format: "label CONTAINS[c] 'Pay monthly for purchases of'")
let button = app.buttons.containing(expectedButtonTextPredicate)
waitForElementToBeHittable(button.element)
button.element.tap()
sleep(2)

app.buttons["PayPal learn more modal close"].tap()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,38 +22,18 @@ internal extension XCUIApplication {
return buttons["Tokenize and Verify New Card"]
}

var webViewPasswordTextField: XCUIElement {
return webViews.element.otherElements.children(matching: .other).children(matching: .secureTextField).element
}

var webViewSubmitButton: XCUIElement {
return webViews.element.otherElements.children(matching: .other).children(matching: .other).buttons["Submit"]
}

var cardinalSubmitButton: XCUIElement {
return buttons["SUBMIT"]
}

var liabilityShiftedMessage: XCUIElement {
return buttons["Liability shift possible and liability shifted"]
}

var authenticationFailedMessage: XCUIElement {
return buttons["Failed to authenticate, please try a different form of payment."]
}


var liabilityCouldNotBeShiftedMessage: XCUIElement {
return buttons["3D Secure authentication was attempted but liability shift is not possible"]
}

var unexpectedErrorMessage: XCUIElement {
return buttons["An unexpected error occurred"]
}

var internalErrorMessage: XCUIElement {
return buttons["Internal Error."]
}

func enterCardDetailsWith(cardNumber: String, expirationDate: String = UITestDateGenerator.sharedInstance.futureDate()) {
cardNumberTextField.tap()
cardNumberTextField.typeText(cardNumber)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,6 @@ class ThreeDSecure_V2_UITests: XCTestCase {
app.launch()
}

func testThreeDSecurePaymentFlowV2_frictionlessFlow_andTransacts() {
waitForElementToAppear(app.cardNumberTextField)
app.enterCardDetailsWith(cardNumber: "4000000000001000", expirationDate: expirationDate)
app.tokenizeButton.tap()
sleep(2)

waitForElementToAppear(app.liabilityShiftedMessage)
}

func testThreeDSecurePaymentFlowV2_challengeFlow_andTransacts() {
waitForElementToAppear(app.cardNumberTextField)
app.enterCardDetailsWith(cardNumber: "4000000000001091", expirationDate: expirationDate)
Expand All @@ -44,16 +35,7 @@ class ThreeDSecure_V2_UITests: XCTestCase {

waitForElementToAppear(app.liabilityShiftedMessage)
}

func testThreeDSecurePaymentFlowV2_noChallenge_andFails() {
waitForElementToAppear(app.cardNumberTextField)
app.enterCardDetailsWith(cardNumber: "5200000000001013", expirationDate: expirationDate)
app.tokenizeButton.tap()
sleep(2)

waitForElementToAppear(app.liabilityCouldNotBeShiftedMessage)
}


func testThreeDSecurePaymentFlowV2_challengeFlow_andFails() {
waitForElementToAppear(app.cardNumberTextField)
app.enterCardDetailsWith(cardNumber: "4000000000001109", expirationDate: expirationDate)
Expand All @@ -74,26 +56,6 @@ class ThreeDSecure_V2_UITests: XCTestCase {
waitForElementToAppear(app.liabilityCouldNotBeShiftedMessage, timeout: 30)
}

func testThreeDSecurePaymentFlowV2_acceptsPassword_failsToAuthenticateNonce_dueToCardinalError() {
waitForElementToAppear(app.cardNumberTextField)
app.enterCardDetailsWith(cardNumber: "4000000000001125")
app.tokenizeButton.tap()
sleep(2)

waitForElementToAppear(app.staticTexts["Purchase Authentication"], timeout: .threeDSecureTimeout)

let textField = app.textFields.element(boundBy: 0)
waitForElementToBeHittable(textField)
textField.forceTapElement()
sleep(2)
textField.typeText("1234")

app.cardinalSubmitButton.forceTapElement()
sleep(2)

waitForElementToAppear(app.internalErrorMessage, timeout: 30)
}

func testThreeDSecurePaymentFlowV2_returnsToApp_whenCancelTapped() {
waitForElementToAppear(app.cardNumberTextField)
app.enterCardDetailsWith(cardNumber: "4000000000001091")
Expand All @@ -106,31 +68,4 @@ class ThreeDSecure_V2_UITests: XCTestCase {

waitForElementToAppear(app.buttons["Canceled 🎲"])
}

func testThreeDSecurePaymentFlowV2_bypassedAuthentication() {
waitForElementToAppear(app.cardNumberTextField)
app.enterCardDetailsWith(cardNumber: "4000000000001083")
app.tokenizeButton.tap()
sleep(2)

waitForElementToAppear(app.liabilityCouldNotBeShiftedMessage)
}

func testThreeDSecurePaymentFlowV2_lookupError() {
waitForElementToAppear(app.cardNumberTextField)
app.enterCardDetailsWith(cardNumber: "4000000000001034")
app.tokenizeButton.tap()
sleep(2)

waitForElementToAppear(app.liabilityCouldNotBeShiftedMessage)
}

func testThreeDSecurePaymentFlowV2_timeout() {
waitForElementToAppear(app.cardNumberTextField)
app.enterCardDetailsWith(cardNumber: "4000000000001075")
app.tokenizeButton.tap()
sleep(2)

waitForElementToAppear(app.liabilityCouldNotBeShiftedMessage, timeout: 45)
}
}
31 changes: 31 additions & 0 deletions IntegrationTests/BraintreeAmexExpress_IntegrationTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import XCTest
@testable import BraintreeAmericanExpress
@testable import BraintreeCard
@testable import BraintreeCore

class BraintreeAmexExpress_IntegrationTests: XCTestCase {

func testGetRewardsBalance_returnsResult() async {
let apiClient = BTAPIClient(authorization: BTIntegrationTestsConstants.sandboxClientTokenVersion3)!
let cardClient = BTCardClient(apiClient: apiClient)
let amexClient = BTAmericanExpressClient(apiClient: apiClient)

let card = BTCard()
card.number = "371260714673002"
card.expirationMonth = "12"
card.expirationYear = Helpers.shared.futureYear()
card.cvv = "1234"

do {
let tokenizedCard = try await cardClient.tokenize(card)
let rewardsBalance = try await amexClient.getRewardsBalance(forNonce: tokenizedCard.nonce, currencyISOCode: "USD")

XCTAssertEqual(rewardsBalance.rewardsAmount, "45256433")
XCTAssertEqual(rewardsBalance.rewardsUnit, "Points")
XCTAssertEqual(rewardsBalance.currencyAmount, "316795.03")
XCTAssertEqual(rewardsBalance.currencyIsoCode, "USD")
} catch {
XCTFail("Unexpected error: \(error.localizedDescription)")
}
}
}
Loading

0 comments on commit d1e9d9b

Please sign in to comment.