diff --git a/StripeCore/StripeCore/Source/Analytics/STPAnalyticEvent.swift b/StripeCore/StripeCore/Source/Analytics/STPAnalyticEvent.swift index f5d0286e1e6..caef58186ad 100644 --- a/StripeCore/StripeCore/Source/Analytics/STPAnalyticEvent.swift +++ b/StripeCore/StripeCore/Source/Analytics/STPAnalyticEvent.swift @@ -75,6 +75,9 @@ import Foundation case mcInitCustomDefault = "mc_custom_init_default" case mcInitCompleteDefault = "mc_complete_init_default" + // MARK: - Embedded Payment Element init + case mcInitEmbedded = "mc_embedded_init" + // MARK: - PaymentSheet Show case mcShowCustomNewPM = "mc_custom_sheet_newpm_show" case mcShowCustomSavedPM = "mc_custom_sheet_savedpm_show" @@ -102,6 +105,9 @@ import Foundation case mcPaymentCompleteApplePayFailure = "mc_complete_payment_applepay_failure" case mcPaymentCompleteLinkFailure = "mc_complete_payment_link_failure" + case mcPaymentEmbeddedSuccess = "mc_embedded_payment_success" + case mcPaymentEmbeddedFailure = "mc_embedded_payment_failure" + // MARK: - PaymentSheet Option Selected case mcOptionSelectCustomNewPM = "mc_custom_paymentoption_newpm_select" case mcOptionSelectCustomSavedPM = "mc_custom_paymentoption_savedpm_select" @@ -111,10 +117,12 @@ import Foundation case mcOptionSelectCompleteSavedPM = "mc_complete_paymentoption_savedpm_select" case mcOptionSelectCompleteApplePay = "mc_complete_paymentoption_applepay_select" case mcOptionSelectCompleteLink = "mc_complete_paymentoption_link_select" + case mcOptionSelectEmbeddedSavedPM = "mc_embedded_paymentoption_savedpm_select" // MARK: - PaymentSheet Saved Payment Method Removed case mcOptionRemoveCustomSavedPM = "mc_custom_paymentoption_removed" case mcOptionRemoveCompleteSavedPM = "mc_complete_paymentoption_removed" + case mcOptionRemoveEmbeddedSavedPM = "mc_embedded_paymentoption_removed" // MARK: - Link Signup case linkSignupCheckboxChecked = "link.signup.checkbox_checked" @@ -264,6 +272,7 @@ import Foundation case unexpectedPaymentSheetViewControllerError = "unexpected_error.paymentsheet.paymentsheetviewcontroller" case unexpectedFlowControllerViewControllerError = "unexpected_error.paymentsheet.flowcontrollerviewcontroller" case unexpectedPaymentHandlerError = "unexpected_error.paymenthandler" + case unexpectedErrorPaymentSheetAnalytics = "unexpected_error.paymentsheetanalyticshelper" // MARK: - Misc. errors case stripePaymentSheetDownloadManagerError = "stripepaymentsheet.downloadmanager.error" diff --git a/StripePaymentSheet/StripePaymentSheet/Source/Analytics/PaymentSheetAnalyticsHelper.swift b/StripePaymentSheet/StripePaymentSheet/Source/Analytics/PaymentSheetAnalyticsHelper.swift index 9e5846ee827..2822e1773be 100644 --- a/StripePaymentSheet/StripePaymentSheet/Source/Analytics/PaymentSheetAnalyticsHelper.swift +++ b/StripePaymentSheet/StripePaymentSheet/Source/Analytics/PaymentSheetAnalyticsHelper.swift @@ -11,8 +11,8 @@ import Foundation final class PaymentSheetAnalyticsHelper { let analyticsClient: STPAnalyticsClient - let isCustom: Bool - let configuration: PaymentSheet.Configuration + let integrationShape: IntegrationShape + let configuration: PaymentElementConfiguration // Vars set later as PaymentSheet successfully loads, etc. var intent: Intent? @@ -20,27 +20,49 @@ final class PaymentSheetAnalyticsHelper { var loadingStartDate: Date? private var startTimes: [TimeMeasurement: Date] = [:] + enum IntegrationShape { + case flowController + case complete + case embedded + } + init( - isCustom: Bool, - configuration: PaymentSheet.Configuration, + integrationShape: IntegrationShape, + configuration: PaymentElementConfiguration, analyticsClient: STPAnalyticsClient = .sharedClient ) { - self.isCustom = isCustom + self.integrationShape = integrationShape self.configuration = configuration self.analyticsClient = analyticsClient } func logInitialized() { let event: STPAnalyticEvent = { - switch (configuration.customer != nil, configuration.applePay != nil) { - case (false, false): - return isCustom ? .mcInitCustomDefault : .mcInitCompleteDefault - case (true, false): - return isCustom ? .mcInitCustomCustomer : .mcInitCompleteCustomer - case (false, true): - return isCustom ? .mcInitCustomApplePay : .mcInitCompleteApplePay - case (true, true): - return isCustom ? .mcInitCustomCustomerApplePay : .mcInitCompleteCustomerApplePay + switch integrationShape { + case .flowController: + switch (configuration.customer != nil, configuration.applePay != nil) { + case (false, false): + return .mcInitCustomDefault + case (true, false): + return .mcInitCustomCustomer + case (false, true): + return .mcInitCustomApplePay + case (true, true): + return .mcInitCustomCustomerApplePay + } + case .complete: + switch (configuration.customer != nil, configuration.applePay != nil) { + case (false, false): + return .mcInitCompleteDefault + case (true, false): + return .mcInitCompleteCustomer + case (false, true): + return .mcInitCompleteApplePay + case (true, true): + return .mcInitCompleteCustomerApplePay + } + case .embedded: + return .mcInitEmbedded } }() log(event: event) @@ -110,6 +132,11 @@ final class PaymentSheetAnalyticsHelper { } func logShow(showingSavedPMList: Bool) { + if case .embedded = integrationShape { + stpAssertionFailure("logShow() is not supported for embedded integration") + return + } + let isCustom = integrationShape == .flowController if !isCustom { startTimeMeasurement(.checkout) } @@ -126,7 +153,8 @@ final class PaymentSheetAnalyticsHelper { func logSavedPMScreenOptionSelected(option: SavedPaymentOptionsViewController.Selection) { let (event, selectedLPM): (STPAnalyticEvent, String?) = { - if isCustom { + switch integrationShape { + case .flowController: switch option { case .add: return (.mcOptionSelectCustomNewPM, nil) @@ -137,7 +165,7 @@ final class PaymentSheetAnalyticsHelper { case .link: return (.mcOptionSelectCustomLink, nil) } - } else { + case .complete: switch option { case .add: return (.mcOptionSelectCompleteNewPM, nil) @@ -148,6 +176,13 @@ final class PaymentSheetAnalyticsHelper { case .link: return (.mcOptionSelectCompleteLink, nil) } + case .embedded: + if case .saved(let paymentMethod) = option { + return (.mcOptionSelectEmbeddedSavedPM, paymentMethod.type.identifier) + } else { + stpAssertionFailure("Embedded should only use this function to record tapped saved payment methods") + return (.unexpectedErrorPaymentSheetAnalytics, nil) + } } }() log(event: event, selectedLPM: selectedLPM) @@ -157,7 +192,16 @@ final class PaymentSheetAnalyticsHelper { log(event: .paymentSheetCarouselPaymentMethodTapped, selectedLPM: paymentMethodTypeIdentifier) } func logSavedPaymentMethodRemoved(paymentMethod: STPPaymentMethod) { - let event: STPAnalyticEvent = isCustom ? .mcOptionRemoveCustomSavedPM : .mcOptionRemoveCompleteSavedPM + let event: STPAnalyticEvent = { + switch integrationShape { + case .flowController: + return .mcOptionRemoveCustomSavedPM + case .complete: + return .mcOptionRemoveCompleteSavedPM + case .embedded: + return .mcOptionRemoveEmbeddedSavedPM + } + }() log(event: event, selectedLPM: paymentMethod.type.identifier) } @@ -233,7 +277,8 @@ final class PaymentSheetAnalyticsHelper { } let event: STPAnalyticEvent = { - if isCustom { + switch integrationShape { + case .flowController: switch paymentOption { case .new, .external: return success ? .mcPaymentCustomNewPMSuccess : .mcPaymentCustomNewPMFailure @@ -244,7 +289,7 @@ final class PaymentSheetAnalyticsHelper { case .link: return success ? .mcPaymentCustomLinkSuccess : .mcPaymentCustomLinkFailure } - } else { + case .complete: switch paymentOption { case .new, .external: return success ? .mcPaymentCompleteNewPMSuccess : .mcPaymentCompleteNewPMFailure @@ -255,6 +300,8 @@ final class PaymentSheetAnalyticsHelper { case .link: return success ? .mcPaymentCompleteLinkSuccess : .mcPaymentCompleteLinkFailure } + case .embedded: + return success ? .mcPaymentEmbeddedSuccess : .mcPaymentEmbeddedFailure } }() @@ -338,6 +385,21 @@ extension STPAnalyticsClient { extension PaymentSheet.Configuration { /// Serializes the configuration into a safe dictionary containing no PII for analytics logging var analyticPayload: [String: Any] { + var payload = commonAnalyticPayload + payload["payment_method_layout"] = paymentMethodLayout.description + return payload + } +} + +extension EmbeddedPaymentElement.Configuration { + /// Serializes the configuration into a safe dictionary containing no PII for analytics logging + var analyticPayload: [String: Any] { + return commonAnalyticPayload + } +} + +extension PaymentElementConfiguration { + var commonAnalyticPayload: [String: Any] { var payload = [String: Any]() payload["allows_delayed_payment_methods"] = allowsDelayedPaymentMethods payload["apple_pay_config"] = applePay != nil @@ -350,9 +412,7 @@ extension PaymentSheet.Configuration { payload["appearance"] = appearance.analyticPayload payload["billing_details_collection_configuration"] = billingDetailsCollectionConfiguration.analyticPayload payload["preferred_networks"] = preferredNetworks?.map({ STPCardBrandUtilities.apiValue(from: $0) }).joined(separator: ", ") - payload["payment_method_layout"] = paymentMethodLayout.description payload["card_brand_acceptance"] = cardBrandAcceptance != .all - return payload } } diff --git a/StripePaymentSheet/StripePaymentSheet/Source/PaymentSheet/CustomerSheet/CustomerAddPaymentMethodViewController.swift b/StripePaymentSheet/StripePaymentSheet/Source/PaymentSheet/CustomerSheet/CustomerAddPaymentMethodViewController.swift index a132c49919e..a332211f69a 100644 --- a/StripePaymentSheet/StripePaymentSheet/Source/PaymentSheet/CustomerSheet/CustomerAddPaymentMethodViewController.swift +++ b/StripePaymentSheet/StripePaymentSheet/Source/PaymentSheet/CustomerSheet/CustomerAddPaymentMethodViewController.swift @@ -244,7 +244,7 @@ class CustomerAddPaymentMethodViewController: UIViewController { isSettingUp: true, countryCode: nil, savePaymentMethodConsentBehavior: savePaymentMethodConsentBehavior, - analyticsHelper: .init(isCustom: false, configuration: PaymentSheet.Configuration.init()) // TODO(MOBILESDK-2548) Just use a dummy analytics helper; we don't look at these analytics. + analyticsHelper: nil ).make() formElement.delegate = self return formElement diff --git a/StripePaymentSheet/StripePaymentSheet/Source/PaymentSheet/Elements/CardSection/CardSectionElement.swift b/StripePaymentSheet/StripePaymentSheet/Source/PaymentSheet/Elements/CardSection/CardSectionElement.swift index c4f92714a79..4e32d737443 100644 --- a/StripePaymentSheet/StripePaymentSheet/Source/PaymentSheet/Elements/CardSection/CardSectionElement.swift +++ b/StripePaymentSheet/StripePaymentSheet/Source/PaymentSheet/Elements/CardSection/CardSectionElement.swift @@ -35,7 +35,7 @@ final class CardSectionElement: ContainerElement { #endif }() let cardSection: SectionElement - let analyticsHelper: PaymentSheetAnalyticsHelper + let analyticsHelper: PaymentSheetAnalyticsHelper? struct DefaultValues { internal init(name: String? = nil, pan: String? = nil, cvc: String? = nil, expiry: String? = nil) { @@ -68,7 +68,7 @@ final class CardSectionElement: ContainerElement { cardBrandChoiceEligible: Bool = false, hostedSurface: HostedSurface, theme: ElementsAppearance = .default, - analyticsHelper: PaymentSheetAnalyticsHelper, + analyticsHelper: PaymentSheetAnalyticsHelper?, cardBrandFilter: CardBrandFilter = .default ) { self.hostedSurface = hostedSurface @@ -193,20 +193,20 @@ final class CardSectionElement: ContainerElement { STPAnalyticsClient.sharedClient.logPaymentSheetEvent(event: .paymentSheetCardNumberCompleted) } } - + // Send an analytic if we are disallowing a card brand if case .invalid(let error, _) = panElement.validationState, let specificError = error as? TextFieldElement.PANConfiguration.Error, case .disallowedBrand(let brand) = specificError, lastDisallowedCardBrandLogged != brand { - + STPAnalyticsClient.sharedClient.logPaymentSheetEvent( event: .paymentSheetDisallowedCardBrand, params: ["brand": STPCardBrandUtilities.apiValue(from: brand)] ) lastDisallowedCardBrandLogged = brand } - + delegate?.didUpdate(element: self) } diff --git a/StripePaymentSheet/StripePaymentSheet/Source/PaymentSheet/Elements/CardSection/CardSectionWithScannerView.swift b/StripePaymentSheet/StripePaymentSheet/Source/PaymentSheet/Elements/CardSection/CardSectionWithScannerView.swift index 602cb7bd6f0..c16785c5aff 100644 --- a/StripePaymentSheet/StripePaymentSheet/Source/PaymentSheet/Elements/CardSection/CardSectionWithScannerView.swift +++ b/StripePaymentSheet/StripePaymentSheet/Source/PaymentSheet/Elements/CardSection/CardSectionWithScannerView.swift @@ -22,7 +22,7 @@ import UIKit @objc(STP_Internal_CardSectionWithScannerView) final class CardSectionWithScannerView: UIView { let cardSectionView: UIView - let analyticsHelper: PaymentSheetAnalyticsHelper + let analyticsHelper: PaymentSheetAnalyticsHelper? lazy var cardScanButton: UIButton = { let button = UIButton.makeCardScanButton(theme: theme) button.addTarget(self, action: #selector(didTapCardScanButton), for: .touchUpInside) @@ -38,7 +38,7 @@ final class CardSectionWithScannerView: UIView { weak var delegate: CardSectionWithScannerViewDelegate? private let theme: ElementsAppearance - init(cardSectionView: UIView, delegate: CardSectionWithScannerViewDelegate, theme: ElementsAppearance = .default, analyticsHelper: PaymentSheetAnalyticsHelper) { + init(cardSectionView: UIView, delegate: CardSectionWithScannerViewDelegate, theme: ElementsAppearance = .default, analyticsHelper: PaymentSheetAnalyticsHelper?) { self.cardSectionView = cardSectionView self.delegate = delegate self.theme = theme @@ -62,7 +62,7 @@ final class CardSectionWithScannerView: UIView { } @objc func didTapCardScanButton() { - analyticsHelper.logFormInteracted(paymentMethodTypeIdentifier: "card") + analyticsHelper?.logFormInteracted(paymentMethodTypeIdentifier: "card") setCardScanVisible(true) cardScanningView.start() becomeFirstResponder() diff --git a/StripePaymentSheet/StripePaymentSheet/Source/PaymentSheet/Embedded/EmbeddedPaymentElement+Internal.swift b/StripePaymentSheet/StripePaymentSheet/Source/PaymentSheet/Embedded/EmbeddedPaymentElement+Internal.swift index 56c33aedc01..4e80858929c 100644 --- a/StripePaymentSheet/StripePaymentSheet/Source/PaymentSheet/Embedded/EmbeddedPaymentElement+Internal.swift +++ b/StripePaymentSheet/StripePaymentSheet/Source/PaymentSheet/Embedded/EmbeddedPaymentElement+Internal.swift @@ -10,6 +10,7 @@ extension EmbeddedPaymentElement { static func makeView( configuration: Configuration, loadResult: PaymentSheetLoader.LoadResult, + analyticsHelper: PaymentSheetAnalyticsHelper, delegate: EmbeddedPaymentMethodsViewDelegate? = nil ) -> EmbeddedPaymentMethodsView { let shouldShowApplePay = PaymentSheet.isApplePayEnabled(elementsSession: loadResult.elementsSession, configuration: configuration) @@ -36,7 +37,8 @@ extension EmbeddedPaymentElement { let mandateProvider = VerticalListMandateProvider( configuration: configuration, elementsSession: loadResult.elementsSession, - intent: loadResult.intent + intent: loadResult.intent, + analyticsHelper: analyticsHelper ) return EmbeddedPaymentMethodsView( initialSelection: initialSelection, diff --git a/StripePaymentSheet/StripePaymentSheet/Source/PaymentSheet/Embedded/EmbeddedPaymentElement.swift b/StripePaymentSheet/StripePaymentSheet/Source/PaymentSheet/Embedded/EmbeddedPaymentElement.swift index 22636934077..03a18e24f9e 100644 --- a/StripePaymentSheet/StripePaymentSheet/Source/PaymentSheet/Embedded/EmbeddedPaymentElement.swift +++ b/StripePaymentSheet/StripePaymentSheet/Source/PaymentSheet/Embedded/EmbeddedPaymentElement.swift @@ -63,9 +63,9 @@ public final class EmbeddedPaymentElement { intentConfiguration: IntentConfiguration, configuration: Configuration ) async throws -> EmbeddedPaymentElement { - // TODO(porter) Should we create a new analytics helper specific to embedded? Figured this out when we do analytics. - let analyticsHelper = PaymentSheetAnalyticsHelper(isCustom: true, configuration: PaymentSheet.Configuration()) AnalyticsHelper.shared.generateSessionID() + STPAnalyticsClient.sharedClient.addClass(toProductUsageIfNecessary: EmbeddedPaymentElement.self) + let analyticsHelper = PaymentSheetAnalyticsHelper(integrationShape: .embedded, configuration: configuration) let loadResult = try await PaymentSheetLoader.load( mode: .deferredIntent(intentConfiguration), @@ -75,7 +75,8 @@ public final class EmbeddedPaymentElement { ) let embeddedPaymentElement: EmbeddedPaymentElement = .init( configuration: configuration, - loadResult: loadResult + loadResult: loadResult, + analyticsHelper: analyticsHelper ) return embeddedPaymentElement } @@ -167,21 +168,33 @@ public final class EmbeddedPaymentElement { internal private(set) var embeddedPaymentMethodsView: EmbeddedPaymentMethodsView internal private(set) var loadResult: PaymentSheetLoader.LoadResult internal private(set) var currentUpdateTask: Task? + private let analyticsHelper: PaymentSheetAnalyticsHelper private init( configuration: Configuration, - loadResult: PaymentSheetLoader.LoadResult + loadResult: PaymentSheetLoader.LoadResult, + analyticsHelper: PaymentSheetAnalyticsHelper, + delegate: EmbeddedPaymentElementDelegate? = nil ) { self.configuration = configuration self.loadResult = loadResult self.embeddedPaymentMethodsView = Self.makeView( configuration: configuration, - loadResult: loadResult + loadResult: loadResult, + analyticsHelper: analyticsHelper ) + self.analyticsHelper = analyticsHelper + analyticsHelper.logInitialized() self.embeddedPaymentMethodsView.delegate = self } } +// MARK: - STPAnalyticsProtocol +/// :nodoc: +@_spi(STP) extension EmbeddedPaymentElement: STPAnalyticsProtocol { + @_spi(STP) public static let stp_analyticsIdentifier: String = "EmbeddedPaymentElement" +} + // MARK: - Completion-block based APIs extension EmbeddedPaymentElement { /// Creates an instance of `EmbeddedPaymentElement` diff --git a/StripePaymentSheet/StripePaymentSheet/Source/PaymentSheet/Embedded/MandateTextProvider.swift b/StripePaymentSheet/StripePaymentSheet/Source/PaymentSheet/Embedded/MandateTextProvider.swift index e38fa0ede36..95cc5f9e1d3 100644 --- a/StripePaymentSheet/StripePaymentSheet/Source/PaymentSheet/Embedded/MandateTextProvider.swift +++ b/StripePaymentSheet/StripePaymentSheet/Source/PaymentSheet/Embedded/MandateTextProvider.swift @@ -18,11 +18,13 @@ class VerticalListMandateProvider: MandateTextProvider { private let configuration: PaymentElementConfiguration private let elementsSession: STPElementsSession private let intent: Intent - - init(configuration: PaymentElementConfiguration, elementsSession: STPElementsSession, intent: Intent) { + private let analyticsHelper: PaymentSheetAnalyticsHelper + + init(configuration: PaymentElementConfiguration, elementsSession: STPElementsSession, intent: Intent, analyticsHelper: PaymentSheetAnalyticsHelper) { self.configuration = configuration self.elementsSession = elementsSession self.intent = intent + self.analyticsHelper = analyticsHelper } /// Builds the attributed string for a given payment method type. @@ -56,7 +58,7 @@ class VerticalListMandateProvider: MandateTextProvider { paymentMethod: paymentMethodType, previousCustomerInput: nil, linkAccount: LinkAccountContext.shared.account, - analyticsHelper: .init(isCustom: false, configuration: PaymentSheet.Configuration()) // Dummy, not used + analyticsHelper: analyticsHelper ).make() guard !form.collectsUserInput else { diff --git a/StripePaymentSheet/StripePaymentSheet/Source/PaymentSheet/PaymentElementConfiguration.swift b/StripePaymentSheet/StripePaymentSheet/Source/PaymentSheet/PaymentElementConfiguration.swift index 0493cd33ab9..ad84d64db81 100644 --- a/StripePaymentSheet/StripePaymentSheet/Source/PaymentSheet/PaymentElementConfiguration.swift +++ b/StripePaymentSheet/StripePaymentSheet/Source/PaymentSheet/PaymentElementConfiguration.swift @@ -35,6 +35,7 @@ protocol PaymentElementConfiguration: PaymentMethodRequirementProvider { var paymentMethodOrder: [String]? { get set } var allowsRemovalOfLastSavedPaymentMethod: Bool { get set } var cardBrandAcceptance: PaymentSheet.CardBrandAcceptance { get set } + var analyticPayload: [String: Any] { get } } extension PaymentElementConfiguration { diff --git a/StripePaymentSheet/StripePaymentSheet/Source/PaymentSheet/PaymentSheet.swift b/StripePaymentSheet/StripePaymentSheet/Source/PaymentSheet/PaymentSheet.swift index f4a188979c1..f13ef0a56a9 100644 --- a/StripePaymentSheet/StripePaymentSheet/Source/PaymentSheet/PaymentSheet.swift +++ b/StripePaymentSheet/StripePaymentSheet/Source/PaymentSheet/PaymentSheet.swift @@ -108,7 +108,7 @@ public class PaymentSheet { analyticsClient.addClass(toProductUsageIfNecessary: PaymentSheet.self) self.mode = mode self.configuration = configuration - self.analyticsHelper = PaymentSheetAnalyticsHelper(isCustom: false, configuration: configuration) + self.analyticsHelper = PaymentSheetAnalyticsHelper(integrationShape: .complete, configuration: configuration) analyticsHelper.logInitialized() } diff --git a/StripePaymentSheet/StripePaymentSheet/Source/PaymentSheet/PaymentSheetFlowController.swift b/StripePaymentSheet/StripePaymentSheet/Source/PaymentSheet/PaymentSheetFlowController.swift index bb1954f2efc..86f4ca479c4 100644 --- a/StripePaymentSheet/StripePaymentSheet/Source/PaymentSheet/PaymentSheetFlowController.swift +++ b/StripePaymentSheet/StripePaymentSheet/Source/PaymentSheet/PaymentSheetFlowController.swift @@ -259,7 +259,7 @@ extension PaymentSheet { completion: @escaping (Result) -> Void ) { analyticsClient.addClass(toProductUsageIfNecessary: PaymentSheet.FlowController.self) - let analyticsHelper = PaymentSheetAnalyticsHelper(isCustom: true, configuration: configuration) + let analyticsHelper = PaymentSheetAnalyticsHelper(integrationShape: .flowController, configuration: configuration) AnalyticsHelper.shared.generateSessionID() PaymentSheetLoader.load( mode: mode, diff --git a/StripePaymentSheet/StripePaymentSheet/Source/PaymentSheet/PaymentSheetFormFactory/PaymentSheetFormFactory+FormSpec.swift b/StripePaymentSheet/StripePaymentSheet/Source/PaymentSheet/PaymentSheetFormFactory/PaymentSheetFormFactory+FormSpec.swift index 899c69fa521..53c5ad56a0e 100644 --- a/StripePaymentSheet/StripePaymentSheet/Source/PaymentSheet/PaymentSheetFormFactory/PaymentSheetFormFactory+FormSpec.swift +++ b/StripePaymentSheet/StripePaymentSheet/Source/PaymentSheet/PaymentSheetFormFactory/PaymentSheetFormFactory+FormSpec.swift @@ -178,7 +178,7 @@ extension PaymentSheetFormFactory { let errorAnalytic = ErrorAnalytic(event: .unexpectedPaymentSheetFormFactoryError, error: Error.missingV1FromSelectorSpec, additionalNonPIIParams: ["payment_method": paymentMethod.identifier]) - analyticsHelper.analyticsClient.log(analytic: errorAnalytic) + analyticsHelper?.analyticsClient.log(analytic: errorAnalytic) } stpAssert(selectorSpec.apiPath?["v1"] != nil) // If there's no api path, the dropdown selection is unused! let dropdownItems: [DropdownFieldElement.DropdownItem] = selectorSpec.items.map { diff --git a/StripePaymentSheet/StripePaymentSheet/Source/PaymentSheet/PaymentSheetFormFactory/PaymentSheetFormFactory.swift b/StripePaymentSheet/StripePaymentSheet/Source/PaymentSheet/PaymentSheetFormFactory/PaymentSheetFormFactory.swift index e24aee90b76..3dd6de8ccf7 100644 --- a/StripePaymentSheet/StripePaymentSheet/Source/PaymentSheet/PaymentSheetFormFactory/PaymentSheetFormFactory.swift +++ b/StripePaymentSheet/StripePaymentSheet/Source/PaymentSheet/PaymentSheetFormFactory/PaymentSheetFormFactory.swift @@ -35,7 +35,7 @@ class PaymentSheetFormFactory { let countryCode: String? let cardBrandChoiceEligible: Bool let savePaymentMethodConsentBehavior: SavePaymentMethodConsentBehavior - let analyticsHelper: PaymentSheetAnalyticsHelper + let analyticsHelper: PaymentSheetAnalyticsHelper? var shouldDisplaySaveCheckbox: Bool { switch savePaymentMethodConsentBehavior { @@ -67,7 +67,7 @@ class PaymentSheetFormFactory { previousCustomerInput: IntentConfirmParams? = nil, addressSpecProvider: AddressSpecProvider = .shared, linkAccount: PaymentSheetLinkAccount? = nil, - analyticsHelper: PaymentSheetAnalyticsHelper + analyticsHelper: PaymentSheetAnalyticsHelper? ) { /// Whether or not the card form should show the link inline signup checkbox @@ -110,7 +110,7 @@ class PaymentSheetFormFactory { isSettingUp: Bool, countryCode: String?, savePaymentMethodConsentBehavior: SavePaymentMethodConsentBehavior, - analyticsHelper: PaymentSheetAnalyticsHelper + analyticsHelper: PaymentSheetAnalyticsHelper? ) { self.configuration = configuration self.paymentMethod = paymentMethod @@ -182,7 +182,7 @@ class PaymentSheetFormFactory { guard let spec = FormSpecProvider.shared.formSpec(for: paymentMethod.identifier) else { stpAssertionFailure("Failed to get form spec for \(paymentMethod.identifier)!") let errorAnalytic = ErrorAnalytic(event: .unexpectedPaymentSheetFormFactoryError, error: Error.missingFormSpec, additionalNonPIIParams: ["payment_method": paymentMethod.identifier]) - analyticsHelper.analyticsClient.log(analytic: errorAnalytic) + analyticsHelper?.analyticsClient.log(analytic: errorAnalytic) return FormElement(elements: [], theme: theme) } if paymentMethod == .iDEAL { diff --git a/StripePaymentSheet/StripePaymentSheet/Source/PaymentSheet/ViewControllers/PaymentSheetVerticalViewController.swift b/StripePaymentSheet/StripePaymentSheet/Source/PaymentSheet/ViewControllers/PaymentSheetVerticalViewController.swift index 3f75f953e35..00324b691d0 100644 --- a/StripePaymentSheet/StripePaymentSheet/Source/PaymentSheet/ViewControllers/PaymentSheetVerticalViewController.swift +++ b/StripePaymentSheet/StripePaymentSheet/Source/PaymentSheet/ViewControllers/PaymentSheetVerticalViewController.swift @@ -253,7 +253,7 @@ class PaymentSheetVerticalViewController: UIViewController, FlowControllerViewCo } func updateMandate(animated: Bool = true) { - let mandateProvider = VerticalListMandateProvider(configuration: configuration, elementsSession: elementsSession, intent: intent) + let mandateProvider = VerticalListMandateProvider(configuration: configuration, elementsSession: elementsSession, intent: intent, analyticsHelper: analyticsHelper) let newMandateText = mandateProvider.mandate(for: selectedPaymentOption?.paymentMethodType, savedPaymentMethod: selectedPaymentOption?.savedPaymentMethod, bottomNoticeAttributedString: paymentMethodFormViewController?.bottomNoticeAttributedString) diff --git a/StripePaymentSheet/StripePaymentSheetTests/PaymentSheet/FormMandateProviderTests.swift b/StripePaymentSheet/StripePaymentSheetTests/PaymentSheet/FormMandateProviderTests.swift index 5ebe5413fe3..7735141401f 100644 --- a/StripePaymentSheet/StripePaymentSheetTests/PaymentSheet/FormMandateProviderTests.swift +++ b/StripePaymentSheet/StripePaymentSheetTests/PaymentSheet/FormMandateProviderTests.swift @@ -28,7 +28,7 @@ class FormMandateProviderTests: XCTestCase { confirmHandler: { _, _, _ in } ) let intent = Intent.deferredIntent(intentConfig: intentConfig) - let formMandateProvider = VerticalListMandateProvider(configuration: embeddedConfiguration, elementsSession: elementsSession, intent: intent) + let formMandateProvider = VerticalListMandateProvider(configuration: embeddedConfiguration, elementsSession: elementsSession, intent: intent, analyticsHelper: ._testValue()) let result = formMandateProvider.mandate(for: .stripe(.card), savedPaymentMethod: nil, bottomNoticeAttributedString: nil) XCTAssertNil(result) @@ -42,7 +42,7 @@ class FormMandateProviderTests: XCTestCase { confirmHandler: { _, _, _ in } ) let intent = Intent.deferredIntent(intentConfig: intentConfig) - let formMandateProvider = VerticalListMandateProvider(configuration: configuration, elementsSession: elementsSession, intent: intent) + let formMandateProvider = VerticalListMandateProvider(configuration: configuration, elementsSession: elementsSession, intent: intent, analyticsHelper: ._testValue()) let result = formMandateProvider.mandate(for: nil, savedPaymentMethod: nil, bottomNoticeAttributedString: nil) XCTAssertNil(result) @@ -58,7 +58,7 @@ class FormMandateProviderTests: XCTestCase { confirmHandler: { _, _, _ in } ) let intent = Intent.deferredIntent(intentConfig: intentConfig) - let formMandateProvider = VerticalListMandateProvider(configuration: configuration, elementsSession: elementsSession, intent: intent) + let formMandateProvider = VerticalListMandateProvider(configuration: configuration, elementsSession: elementsSession, intent: intent, analyticsHelper: ._testValue()) let paymentMethod: STPPaymentMethod = ._testUSBankAccount() let result = formMandateProvider.mandate(for: .stripe(.USBankAccount), savedPaymentMethod: paymentMethod, bottomNoticeAttributedString: nil) @@ -76,7 +76,7 @@ class FormMandateProviderTests: XCTestCase { confirmHandler: { _, _, _ in } ) let intent = Intent.deferredIntent(intentConfig: intentConfig) - let formMandateProvider = VerticalListMandateProvider(configuration: configuration, elementsSession: elementsSession, intent: intent) + let formMandateProvider = VerticalListMandateProvider(configuration: configuration, elementsSession: elementsSession, intent: intent, analyticsHelper: ._testValue()) let paymentMethod: STPPaymentMethod = ._testSEPA() let result = formMandateProvider.mandate(for: .stripe(.SEPADebit), savedPaymentMethod: paymentMethod, bottomNoticeAttributedString: nil) @@ -94,7 +94,7 @@ class FormMandateProviderTests: XCTestCase { confirmHandler: { _, _, _ in } ) let intent = Intent.deferredIntent(intentConfig: intentConfig) - let formMandateProvider = VerticalListMandateProvider(configuration: configuration, elementsSession: elementsSession, intent: intent) + let formMandateProvider = VerticalListMandateProvider(configuration: configuration, elementsSession: elementsSession, intent: intent, analyticsHelper: ._testValue()) let paymentMethod: STPPaymentMethod = ._testCard() let result = formMandateProvider.mandate(for: .stripe(.card), savedPaymentMethod: paymentMethod, bottomNoticeAttributedString: nil) @@ -112,7 +112,7 @@ class FormMandateProviderTests: XCTestCase { confirmHandler: { _, _, _ in } ) let intent = Intent.deferredIntent(intentConfig: intentConfig) - let formMandateProvider = VerticalListMandateProvider(configuration: configuration, elementsSession: elementsSession, intent: intent) + let formMandateProvider = VerticalListMandateProvider(configuration: configuration, elementsSession: elementsSession, intent: intent, analyticsHelper: ._testValue()) let bottomNoticeAttributedString = NSAttributedString(string: "Test Bottom Notice") let result = formMandateProvider.mandate(for: .stripe(.USBankAccount), savedPaymentMethod: nil, bottomNoticeAttributedString: bottomNoticeAttributedString) @@ -129,7 +129,7 @@ class FormMandateProviderTests: XCTestCase { confirmHandler: { _, _, _ in } ) let intent = Intent.deferredIntent(intentConfig: intentConfig) - let formMandateProvider = VerticalListMandateProvider(configuration: configuration, elementsSession: elementsSession, intent: intent) + let formMandateProvider = VerticalListMandateProvider(configuration: configuration, elementsSession: elementsSession, intent: intent, analyticsHelper: ._testValue()) let result = formMandateProvider.mandate(for: .stripe(.cashApp), savedPaymentMethod: nil, bottomNoticeAttributedString: nil) let expected = "By continuing, you authorize Test Merchant to debit your Cash App account for this payment and future payments in accordance with Test Merchant\'s terms, until this authorization is revoked. You can change this anytime in your Cash App Settings." @@ -146,7 +146,7 @@ class FormMandateProviderTests: XCTestCase { confirmHandler: { _, _, _ in } ) let intent = Intent.deferredIntent(intentConfig: intentConfig) - let formMandateProvider = VerticalListMandateProvider(configuration: configuration, elementsSession: elementsSession, intent: intent) + let formMandateProvider = VerticalListMandateProvider(configuration: configuration, elementsSession: elementsSession, intent: intent, analyticsHelper: ._testValue()) let result = formMandateProvider.mandate(for: .stripe(.cashApp), savedPaymentMethod: nil, bottomNoticeAttributedString: nil) let expected = "By continuing, you authorize Test Merchant to debit your Cash App account for this payment and future payments in accordance with Test Merchant\'s terms, until this authorization is revoked. You can change this anytime in your Cash App Settings." @@ -163,7 +163,7 @@ class FormMandateProviderTests: XCTestCase { confirmHandler: { _, _, _ in } ) let intent = Intent.deferredIntent(intentConfig: intentConfig) - let formMandateProvider = VerticalListMandateProvider(configuration: configuration, elementsSession: elementsSession, intent: intent) + let formMandateProvider = VerticalListMandateProvider(configuration: configuration, elementsSession: elementsSession, intent: intent, analyticsHelper: ._testValue()) let result = formMandateProvider.mandate(for: .stripe(.cashApp), savedPaymentMethod: nil, bottomNoticeAttributedString: nil) XCTAssertNil(result) diff --git a/StripePaymentSheet/StripePaymentSheetTests/PaymentSheet/PaymentSheet+APITest.swift b/StripePaymentSheet/StripePaymentSheetTests/PaymentSheet/PaymentSheet+APITest.swift index 8d56706fb7d..98c43b0539c 100644 --- a/StripePaymentSheet/StripePaymentSheetTests/PaymentSheet/PaymentSheet+APITest.swift +++ b/StripePaymentSheet/StripePaymentSheetTests/PaymentSheet/PaymentSheet+APITest.swift @@ -81,7 +81,7 @@ class PaymentSheetAPITest: STPNetworkStubbingTestCase { PaymentSheetLoader.load( mode: .paymentIntentClientSecret(clientSecret), configuration: self.configuration, - analyticsHelper: .init(isCustom: false, configuration: self.configuration), + analyticsHelper: .init(integrationShape: .complete, configuration: self.configuration), integrationShape: .complete ) { result in switch result { @@ -165,7 +165,7 @@ class PaymentSheetAPITest: STPNetworkStubbingTestCase { PaymentSheetLoader.load( mode: .deferredIntent(intentConfig), configuration: self.configuration, - analyticsHelper: .init(isCustom: false, configuration: configuration), + analyticsHelper: .init(integrationShape: .complete, configuration: configuration), integrationShape: .complete ) { result in switch result { @@ -232,7 +232,7 @@ class PaymentSheetAPITest: STPNetworkStubbingTestCase { PaymentSheetLoader.load( mode: .deferredIntent(intentConfig), configuration: self.configuration, - analyticsHelper: .init(isCustom: false, configuration: configuration), + analyticsHelper: .init(integrationShape: .complete, configuration: configuration), integrationShape: .complete ) { result in switch result { @@ -290,7 +290,7 @@ class PaymentSheetAPITest: STPNetworkStubbingTestCase { PaymentSheetLoader.load( mode: .paymentIntentClientSecret(clientSecret), configuration: self.configuration, - analyticsHelper: .init(isCustom: false, configuration: self.configuration), + analyticsHelper: .init(integrationShape: .complete, configuration: self.configuration), integrationShape: .complete ) { result in guard case .success(let loadResult) = result else { diff --git a/StripePaymentSheet/StripePaymentSheetTests/PaymentSheet/PaymentSheetAnalyticsHelperTest.swift b/StripePaymentSheet/StripePaymentSheetTests/PaymentSheet/PaymentSheetAnalyticsHelperTest.swift index 922c70c3a15..e96282f8bcf 100644 --- a/StripePaymentSheet/StripePaymentSheetTests/PaymentSheet/PaymentSheetAnalyticsHelperTest.swift +++ b/StripePaymentSheet/StripePaymentSheetTests/PaymentSheet/PaymentSheetAnalyticsHelperTest.swift @@ -66,19 +66,19 @@ final class PaymentSheetAnalyticsHelperTest: XCTestCase { } func testPaymentSheetInit() { - let testcases: [(isCustom: Bool, isApplePayEnabled: Bool, isCustomerProvided: Bool, expected: String)] = [ - (isCustom: true, isApplePayEnabled: false, isCustomerProvided: false, expected: "mc_custom_init_default"), - (isCustom: true, isApplePayEnabled: false, isCustomerProvided: true, expected: "mc_custom_init_customer"), - (isCustom: true, isApplePayEnabled: true, isCustomerProvided: false, expected: "mc_custom_init_applepay"), - (isCustom: true, isApplePayEnabled: true, isCustomerProvided: true, expected: "mc_custom_init_customer_applepay"), - (isCustom: false, isApplePayEnabled: false, isCustomerProvided: false, expected: "mc_complete_init_default"), - (isCustom: false, isApplePayEnabled: false, isCustomerProvided: true, expected: "mc_complete_init_customer"), - (isCustom: false, isApplePayEnabled: true, isCustomerProvided: false, expected: "mc_complete_init_applepay"), - (isCustom: false, isApplePayEnabled: true, isCustomerProvided: true, expected: "mc_complete_init_customer_applepay"), + let testcases: [(integrationShape: PaymentSheetAnalyticsHelper.IntegrationShape, isApplePayEnabled: Bool, isCustomerProvided: Bool, expected: String)] = [ + (integrationShape: .flowController, isApplePayEnabled: false, isCustomerProvided: false, expected: "mc_custom_init_default"), + (integrationShape: .flowController, isApplePayEnabled: false, isCustomerProvided: true, expected: "mc_custom_init_customer"), + (integrationShape: .flowController, isApplePayEnabled: true, isCustomerProvided: false, expected: "mc_custom_init_applepay"), + (integrationShape: .flowController, isApplePayEnabled: true, isCustomerProvided: true, expected: "mc_custom_init_customer_applepay"), + (integrationShape: .complete, isApplePayEnabled: false, isCustomerProvided: false, expected: "mc_complete_init_default"), + (integrationShape: .complete, isApplePayEnabled: false, isCustomerProvided: true, expected: "mc_complete_init_customer"), + (integrationShape: .complete, isApplePayEnabled: true, isCustomerProvided: false, expected: "mc_complete_init_applepay"), + (integrationShape: .complete, isApplePayEnabled: true, isCustomerProvided: true, expected: "mc_complete_init_customer_applepay"), ] - for (isCustom, isApplePayEnabled, isCustomerProvided, expected) in testcases { + for (integrationShape, isApplePayEnabled, isCustomerProvided, expected) in testcases { let sut = PaymentSheetAnalyticsHelper( - isCustom: isCustom, + integrationShape: integrationShape, configuration: makeConfig( applePay: isApplePayEnabled ? .init(merchantId: "", merchantCountryCode: "") : nil, customer: isCustomerProvided ? .init(id: "", ephemeralKeySecret: "") : nil @@ -91,7 +91,7 @@ final class PaymentSheetAnalyticsHelperTest: XCTestCase { } func testLogLoadFailed() { - let sut = PaymentSheetAnalyticsHelper(isCustom: false, configuration: PaymentSheet.Configuration(), analyticsClient: analyticsClient) + let sut = PaymentSheetAnalyticsHelper(integrationShape: .complete, configuration: PaymentSheet.Configuration(), analyticsClient: analyticsClient) // Load started -> failed sut.logLoadStarted() sut.logLoadFailed(error: NSError(domain: "domain", code: 1)) @@ -101,7 +101,7 @@ final class PaymentSheetAnalyticsHelperTest: XCTestCase { } func testLogLoadSucceeded() { - let sut = PaymentSheetAnalyticsHelper(isCustom: false, configuration: PaymentSheet.Configuration(), analyticsClient: analyticsClient) + let sut = PaymentSheetAnalyticsHelper(integrationShape: .complete, configuration: PaymentSheet.Configuration(), analyticsClient: analyticsClient) // Load started -> succeeded sut.logLoadStarted() sut.logLoadSucceeded( @@ -121,13 +121,13 @@ final class PaymentSheetAnalyticsHelperTest: XCTestCase { } func testLogShow() { - let paymentSheetHelper = PaymentSheetAnalyticsHelper(isCustom: false, configuration: PaymentSheet.Configuration(), analyticsClient: analyticsClient) + let paymentSheetHelper = PaymentSheetAnalyticsHelper(integrationShape: .complete, configuration: PaymentSheet.Configuration(), analyticsClient: analyticsClient) paymentSheetHelper.logShow(showingSavedPMList: true) XCTAssertEqual(analyticsClient._testLogHistory.last!["event"] as? String, "mc_complete_sheet_savedpm_show") paymentSheetHelper.logShow(showingSavedPMList: false) XCTAssertEqual(analyticsClient._testLogHistory.last!["event"] as? String, "mc_complete_sheet_newpm_show") - let flowControllerSUT = PaymentSheetAnalyticsHelper(isCustom: true, configuration: PaymentSheet.Configuration(), analyticsClient: analyticsClient) + let flowControllerSUT = PaymentSheetAnalyticsHelper(integrationShape: .flowController, configuration: PaymentSheet.Configuration(), analyticsClient: analyticsClient) flowControllerSUT.logShow(showingSavedPMList: true) XCTAssertEqual(analyticsClient._testLogHistory.last!["event"] as? String, "mc_custom_sheet_savedpm_show") flowControllerSUT.logShow(showingSavedPMList: false) @@ -135,22 +135,22 @@ final class PaymentSheetAnalyticsHelperTest: XCTestCase { } func testLogSavedPMScreenOptionSelected() { - func _createHelper(isCustom: Bool) -> PaymentSheetAnalyticsHelper { - let sut = PaymentSheetAnalyticsHelper(isCustom: isCustom, configuration: PaymentSheet.Configuration(), analyticsClient: analyticsClient) + func _createHelper(integrationShape: PaymentSheetAnalyticsHelper.IntegrationShape) -> PaymentSheetAnalyticsHelper { + let sut = PaymentSheetAnalyticsHelper(integrationShape: integrationShape, configuration: PaymentSheet.Configuration(), analyticsClient: analyticsClient) return sut } - let testcases: [(isCustom: Bool, option: SavedPaymentOptionsViewController.Selection, expectedEvent: String, expectedSelectedLPM: String?)] = [ - (isCustom: false, option: .applePay, expectedEvent: "mc_complete_paymentoption_applepay_select", nil), - (isCustom: false, option: .link, expectedEvent: "mc_complete_paymentoption_link_select", nil), - (isCustom: false, option: .add, expectedEvent: "mc_complete_paymentoption_newpm_select", nil), - (isCustom: false, option: .saved(paymentMethod: ._testCard()), expectedEvent: "mc_complete_paymentoption_savedpm_select", "card"), - (isCustom: true, option: .applePay, expectedEvent: "mc_custom_paymentoption_applepay_select", nil), - (isCustom: true, option: .link, expectedEvent: "mc_custom_paymentoption_link_select", nil), - (isCustom: true, option: .add, expectedEvent: "mc_custom_paymentoption_newpm_select", nil), - (isCustom: true, option: .saved(paymentMethod: ._testCard()), expectedEvent: "mc_custom_paymentoption_savedpm_select", "card"), + let testcases: [(integrationShape: PaymentSheetAnalyticsHelper.IntegrationShape, option: SavedPaymentOptionsViewController.Selection, expectedEvent: String, expectedSelectedLPM: String?)] = [ + (integrationShape: .complete, option: .applePay, expectedEvent: "mc_complete_paymentoption_applepay_select", nil), + (integrationShape: .complete, option: .link, expectedEvent: "mc_complete_paymentoption_link_select", nil), + (integrationShape: .complete, option: .add, expectedEvent: "mc_complete_paymentoption_newpm_select", nil), + (integrationShape: .complete, option: .saved(paymentMethod: ._testCard()), expectedEvent: "mc_complete_paymentoption_savedpm_select", "card"), + (integrationShape: .flowController, option: .applePay, expectedEvent: "mc_custom_paymentoption_applepay_select", nil), + (integrationShape: .flowController, option: .link, expectedEvent: "mc_custom_paymentoption_link_select", nil), + (integrationShape: .flowController, option: .add, expectedEvent: "mc_custom_paymentoption_newpm_select", nil), + (integrationShape: .flowController, option: .saved(paymentMethod: ._testCard()), expectedEvent: "mc_custom_paymentoption_savedpm_select", "card"), ] for testcase in testcases { - let sut = _createHelper(isCustom: testcase.isCustom) + let sut = _createHelper(integrationShape: testcase.integrationShape) sut.logSavedPMScreenOptionSelected(option: testcase.option) XCTAssertEqual(analyticsClient._testLogHistory.last!["event"] as? String, testcase.expectedEvent) if let expectedLpm = testcase.expectedSelectedLPM { @@ -159,25 +159,25 @@ final class PaymentSheetAnalyticsHelperTest: XCTestCase { } } func testLogPaymentMethodRemoved_complete() { - let sut = PaymentSheetAnalyticsHelper(isCustom: false, configuration: PaymentSheet.Configuration(), analyticsClient: analyticsClient) + let sut = PaymentSheetAnalyticsHelper(integrationShape: .complete, configuration: PaymentSheet.Configuration(), analyticsClient: analyticsClient) sut.logSavedPaymentMethodRemoved(paymentMethod: ._testCard()) XCTAssertEqual(analyticsClient._testLogHistory.last!["event"] as? String, "mc_complete_paymentoption_removed") XCTAssertEqual(analyticsClient._testLogHistory.last!["selected_lpm"] as? String, "card") } func testLogPaymentMethodRemoved_custom() { - let sut = PaymentSheetAnalyticsHelper(isCustom: true, configuration: PaymentSheet.Configuration(), analyticsClient: analyticsClient) + let sut = PaymentSheetAnalyticsHelper(integrationShape: .flowController, configuration: PaymentSheet.Configuration(), analyticsClient: analyticsClient) sut.logSavedPaymentMethodRemoved(paymentMethod: ._testCard()) XCTAssertEqual(analyticsClient._testLogHistory.last!["event"] as? String, "mc_custom_paymentoption_removed") XCTAssertEqual(analyticsClient._testLogHistory.last!["selected_lpm"] as? String, "card") } func testLogNewPaymentMethodSelected() { - let sut = PaymentSheetAnalyticsHelper(isCustom: true, configuration: PaymentSheet.Configuration(), analyticsClient: analyticsClient) + let sut = PaymentSheetAnalyticsHelper(integrationShape: .flowController, configuration: PaymentSheet.Configuration(), analyticsClient: analyticsClient) sut.logNewPaymentMethodSelected(paymentMethodTypeIdentifier: "card") XCTAssertEqual(analyticsClient._testLogHistory.last!["event"] as? String, "mc_carousel_payment_method_tapped") XCTAssertEqual(analyticsClient._testLogHistory.last!["selected_lpm"] as? String, "card") } func testLogFormCompleted() { - let sut = PaymentSheetAnalyticsHelper(isCustom: true, configuration: PaymentSheet.Configuration(), analyticsClient: analyticsClient) + let sut = PaymentSheetAnalyticsHelper(integrationShape: .flowController, configuration: PaymentSheet.Configuration(), analyticsClient: analyticsClient) sut.logFormShown(paymentMethodTypeIdentifier: "card") sut.logFormCompleted(paymentMethodTypeIdentifier: "card") XCTAssertEqual(analyticsClient._testLogHistory.last!["event"] as? String, "mc_form_completed") @@ -185,7 +185,7 @@ final class PaymentSheetAnalyticsHelperTest: XCTestCase { } func testLogFormShownAndInteracted() { - let sut = PaymentSheetAnalyticsHelper(isCustom: false, configuration: PaymentSheet.Configuration(), analyticsClient: analyticsClient) + let sut = PaymentSheetAnalyticsHelper(integrationShape: .complete, configuration: PaymentSheet.Configuration(), analyticsClient: analyticsClient) sut.logFormShown(paymentMethodTypeIdentifier: "card") XCTAssertEqual(analyticsClient._testLogHistory.last!["event"] as? String, "mc_form_shown") XCTAssertEqual(analyticsClient._testLogHistory.last!["selected_lpm"] as? String, "card") @@ -203,29 +203,29 @@ final class PaymentSheetAnalyticsHelperTest: XCTestCase { let new = PaymentOption.new(confirmParams: .init(type: .stripe(.cashApp))) let saved = PaymentOption.saved(paymentMethod: ._testCard(), confirmParams: nil) let error = NSError(domain: "domain", code: 123) - let testcases: [(isCustom: Bool, paymentOption: PaymentOption, result: PaymentSheetResult, expected: String)] = [ - (isCustom: true, paymentOption: new, result: .completed, expected: "mc_custom_payment_newpm_success"), - (isCustom: true, paymentOption: saved, result: .completed, expected: "mc_custom_payment_savedpm_success"), - (isCustom: true, paymentOption: .applePay, result: .completed, expected: "mc_custom_payment_applepay_success"), - (isCustom: true, paymentOption: .link(option: .wallet), result: .completed, expected: "mc_custom_payment_link_success"), - (isCustom: true, paymentOption: .new(confirmParams: .init(type: .stripe(.cashApp))), result: .failed(error: error), expected: "mc_custom_payment_newpm_failure"), - (isCustom: true, paymentOption: saved, result: .failed(error: error), expected: "mc_custom_payment_savedpm_failure"), - (isCustom: true, paymentOption: .applePay, result: .failed(error: error), expected: "mc_custom_payment_applepay_failure"), - (isCustom: true, paymentOption: .link(option: .wallet), result: .failed(error: error), expected: "mc_custom_payment_link_failure"), - - (isCustom: false, paymentOption: new, result: .completed, expected: "mc_complete_payment_newpm_success"), - (isCustom: false, paymentOption: saved, result: .completed, expected: "mc_complete_payment_savedpm_success"), - (isCustom: false, paymentOption: .applePay, result: .completed, expected: "mc_complete_payment_applepay_success"), - (isCustom: false, paymentOption: .link(option: .wallet), result: .completed, expected: "mc_complete_payment_link_success"), - (isCustom: false, paymentOption: .new(confirmParams: .init(type: .stripe(.cashApp))), result: .failed(error: error), expected: "mc_complete_payment_newpm_failure"), - (isCustom: false, paymentOption: saved, result: .failed(error: error), expected: "mc_complete_payment_savedpm_failure"), - (isCustom: false, paymentOption: .applePay, result: .failed(error: error), expected: "mc_complete_payment_applepay_failure"), - (isCustom: false, paymentOption: .link(option: .wallet), result: .failed(error: error), expected: "mc_complete_payment_link_failure"), + let testcases: [(integrationShape: PaymentSheetAnalyticsHelper.IntegrationShape, paymentOption: PaymentOption, result: PaymentSheetResult, expected: String)] = [ + (integrationShape: .flowController, paymentOption: new, result: .completed, expected: "mc_custom_payment_newpm_success"), + (integrationShape: .flowController, paymentOption: saved, result: .completed, expected: "mc_custom_payment_savedpm_success"), + (integrationShape: .flowController, paymentOption: .applePay, result: .completed, expected: "mc_custom_payment_applepay_success"), + (integrationShape: .flowController, paymentOption: .link(option: .wallet), result: .completed, expected: "mc_custom_payment_link_success"), + (integrationShape: .flowController, paymentOption: .new(confirmParams: .init(type: .stripe(.cashApp))), result: .failed(error: error), expected: "mc_custom_payment_newpm_failure"), + (integrationShape: .flowController, paymentOption: saved, result: .failed(error: error), expected: "mc_custom_payment_savedpm_failure"), + (integrationShape: .flowController, paymentOption: .applePay, result: .failed(error: error), expected: "mc_custom_payment_applepay_failure"), + (integrationShape: .flowController, paymentOption: .link(option: .wallet), result: .failed(error: error), expected: "mc_custom_payment_link_failure"), + + (integrationShape: .complete, paymentOption: new, result: .completed, expected: "mc_complete_payment_newpm_success"), + (integrationShape: .complete, paymentOption: saved, result: .completed, expected: "mc_complete_payment_savedpm_success"), + (integrationShape: .complete, paymentOption: .applePay, result: .completed, expected: "mc_complete_payment_applepay_success"), + (integrationShape: .complete, paymentOption: .link(option: .wallet), result: .completed, expected: "mc_complete_payment_link_success"), + (integrationShape: .complete, paymentOption: .new(confirmParams: .init(type: .stripe(.cashApp))), result: .failed(error: error), expected: "mc_complete_payment_newpm_failure"), + (integrationShape: .complete, paymentOption: saved, result: .failed(error: error), expected: "mc_complete_payment_savedpm_failure"), + (integrationShape: .complete, paymentOption: .applePay, result: .failed(error: error), expected: "mc_complete_payment_applepay_failure"), + (integrationShape: .complete, paymentOption: .link(option: .wallet), result: .failed(error: error), expected: "mc_complete_payment_link_failure"), ] - for (isCustom, paymentOption, result, expected) in testcases { + for (integrationShape, paymentOption, result, expected) in testcases { let sut = PaymentSheetAnalyticsHelper( - isCustom: isCustom, + integrationShape: integrationShape, configuration: PaymentSheet.Configuration(), analyticsClient: analyticsClient ) @@ -249,7 +249,7 @@ final class PaymentSheetAnalyticsHelperTest: XCTestCase { func testLogPaymentSendsDeferredIntentConfirmationType() { // Check deferred_intent_confirmation_type gets sent let sut = PaymentSheetAnalyticsHelper( - isCustom: false, + integrationShape: .complete, configuration: PaymentSheet.Configuration(), analyticsClient: analyticsClient ) @@ -269,7 +269,7 @@ final class PaymentSheetAnalyticsHelperTest: XCTestCase { } func testLogConfirmButtonTapped() { - let sut = PaymentSheetAnalyticsHelper(isCustom: false, configuration: PaymentSheet.Configuration(), analyticsClient: analyticsClient) + let sut = PaymentSheetAnalyticsHelper(integrationShape: .complete, configuration: PaymentSheet.Configuration(), analyticsClient: analyticsClient) sut.logFormShown(paymentMethodTypeIdentifier: "card") sut.logConfirmButtonTapped(paymentOption: .applePay) @@ -308,8 +308,8 @@ final class PaymentSheetAnalyticsHelperTest: XCTestCase { let linkCardBrand = PaymentOption.new(confirmParams: linkCardBrandConfirmParams) let sut = PaymentSheetAnalyticsHelper( - isCustom: true, - configuration: .init(), + integrationShape: .flowController, + configuration: PaymentSheet.Configuration(), analyticsClient: analyticsClient ) sut.intent = ._testValue() diff --git a/StripePaymentSheet/StripePaymentSheetTests/PaymentSheet/PaymentSheetLoaderStubbedTest.swift b/StripePaymentSheet/StripePaymentSheetTests/PaymentSheet/PaymentSheetLoaderStubbedTest.swift index e86727e2341..15474fc077e 100644 --- a/StripePaymentSheet/StripePaymentSheetTests/PaymentSheet/PaymentSheetLoaderStubbedTest.swift +++ b/StripePaymentSheet/StripePaymentSheetTests/PaymentSheet/PaymentSheetLoaderStubbedTest.swift @@ -37,7 +37,7 @@ class PaymentSheetLoaderStubbedTest: APIStubbedTestCase { PaymentSheetLoader.load( mode: .paymentIntentClientSecret("pi_12345_secret_54321"), configuration: configuration, - analyticsHelper: .init(isCustom: false, configuration: configuration, analyticsClient: analyticsClient), + analyticsHelper: .init(integrationShape: .flowController, configuration: configuration, analyticsClient: analyticsClient), integrationShape: .flowController ) { result in switch result { @@ -74,7 +74,7 @@ class PaymentSheetLoaderStubbedTest: APIStubbedTestCase { PaymentSheetLoader.load( mode: .paymentIntentClientSecret("pi_12345_secret_54321"), configuration: configuration, - analyticsHelper: .init(isCustom: false, configuration: configuration, analyticsClient: analyticsClient), + analyticsHelper: .init(integrationShape: .flowController, configuration: configuration, analyticsClient: analyticsClient), integrationShape: .flowController ) { result in switch result { @@ -109,7 +109,7 @@ class PaymentSheetLoaderStubbedTest: APIStubbedTestCase { PaymentSheetLoader.load( mode: .paymentIntentClientSecret("pi_12345_secret_54321"), configuration: configuration, - analyticsHelper: .init(isCustom: false, configuration: configuration), + analyticsHelper: .init(integrationShape: .flowController, configuration: configuration), integrationShape: .flowController ) { result in switch result { @@ -141,7 +141,7 @@ class PaymentSheetLoaderStubbedTest: APIStubbedTestCase { PaymentSheetLoader.load( mode: .paymentIntentClientSecret("pi_12345_secret_54321"), configuration: configuration, - analyticsHelper: .init(isCustom: false, configuration: configuration), + analyticsHelper: .init(integrationShape: .flowController, configuration: configuration), integrationShape: .flowController ) { result in switch result { @@ -188,7 +188,7 @@ class PaymentSheetLoaderStubbedTest: APIStubbedTestCase { PaymentSheetLoader.load( mode: .paymentIntentClientSecret("pi_1234_secret_1234"), configuration: configuration, - analyticsHelper: .init(isCustom: false, configuration: configuration, analyticsClient: analyticsClient), + analyticsHelper: .init(integrationShape: .complete, configuration: configuration, analyticsClient: analyticsClient), integrationShape: .complete ) { result in loaded.fulfill() @@ -250,7 +250,7 @@ class PaymentSheetLoaderStubbedTest: APIStubbedTestCase { PaymentSheetLoader.load( mode: .setupIntentClientSecret("seti_1234_secret_1234"), configuration: configuration, - analyticsHelper: .init(isCustom: false, configuration: configuration, analyticsClient: analyticsClient), + analyticsHelper: .init(integrationShape: .complete, configuration: configuration, analyticsClient: analyticsClient), integrationShape: .complete ) { result in loaded.fulfill() @@ -310,7 +310,7 @@ class PaymentSheetLoaderStubbedTest: APIStubbedTestCase { PaymentSheetLoader.load( mode: .deferredIntent(intentConfig), configuration: configuration, - analyticsHelper: .init(isCustom: false, configuration: configuration, analyticsClient: analyticsClient), + analyticsHelper: .init(integrationShape: .complete, configuration: configuration, analyticsClient: analyticsClient), integrationShape: .complete ) { result in loaded.fulfill() @@ -353,7 +353,7 @@ class PaymentSheetLoaderStubbedTest: APIStubbedTestCase { PaymentSheetLoader.load( mode: .deferredIntent(intentConfig), configuration: configuration, - analyticsHelper: .init(isCustom: false, configuration: configuration, analyticsClient: analyticsClient), + analyticsHelper: .init(integrationShape: .complete, configuration: configuration, analyticsClient: analyticsClient), integrationShape: .complete ) { result in loaded2.fulfill() @@ -408,7 +408,7 @@ class PaymentSheetLoaderStubbedTest: APIStubbedTestCase { PaymentSheetLoader.load( mode: .deferredIntent(intentConfig), configuration: PaymentSheet.Configuration._testValue_MostPermissive(), - analyticsHelper: .init(isCustom: false, configuration: PaymentSheet.Configuration._testValue_MostPermissive(), analyticsClient: analyticsClient), + analyticsHelper: .init(integrationShape: .complete, configuration: PaymentSheet.Configuration._testValue_MostPermissive(), analyticsClient: analyticsClient), integrationShape: .complete ) { result in loadExpectation.fulfill() diff --git a/StripePaymentSheet/StripePaymentSheetTests/PaymentSheet/PaymentSheetLoaderTest.swift b/StripePaymentSheet/StripePaymentSheetTests/PaymentSheet/PaymentSheetLoaderTest.swift index 8ad5e5c6bdd..3444912914b 100644 --- a/StripePaymentSheet/StripePaymentSheetTests/PaymentSheet/PaymentSheetLoaderTest.swift +++ b/StripePaymentSheet/StripePaymentSheetTests/PaymentSheet/PaymentSheetLoaderTest.swift @@ -39,7 +39,7 @@ final class PaymentSheetLoaderTest: STPNetworkStubbingTestCase { let types = ["ideal", "card", "bancontact", "sofort"] let clientSecret = try await STPTestingAPIClient.shared.fetchPaymentIntent(types: types) // Given a PaymentIntent client secret... - PaymentSheetLoader.load(mode: .paymentIntentClientSecret(clientSecret), configuration: self.configuration, analyticsHelper: .init(isCustom: false, configuration: configuration), integrationShape: .complete) { result in + PaymentSheetLoader.load(mode: .paymentIntentClientSecret(clientSecret), configuration: self.configuration, analyticsHelper: .init(integrationShape: .complete, configuration: configuration), integrationShape: .complete) { result in expectation.fulfill() switch result { case .success(let loadResult): @@ -72,7 +72,7 @@ final class PaymentSheetLoaderTest: STPNetworkStubbingTestCase { PaymentSheetLoader.load( mode: .setupIntentClientSecret(clientSecret), configuration: self.configuration, - analyticsHelper: .init(isCustom: false, configuration: configuration), + analyticsHelper: .init(integrationShape: .complete, configuration: configuration), integrationShape: .complete ) { result in switch result { @@ -108,7 +108,7 @@ final class PaymentSheetLoaderTest: STPNetworkStubbingTestCase { PaymentSheetLoader.load( mode: .setupIntentClientSecret(clientSecret), configuration: self.configuration, - analyticsHelper: .init(isCustom: false, configuration: self.configuration), + analyticsHelper: .init(integrationShape: .complete, configuration: self.configuration), integrationShape: .complete ) { result in defer { expectation.fulfill() } @@ -140,7 +140,7 @@ final class PaymentSheetLoaderTest: STPNetworkStubbingTestCase { ] for (index, intentConfig) in intentConfigTestcases.enumerated() { let loadExpectation = XCTestExpectation(description: "Load PaymentSheet") - PaymentSheetLoader.load(mode: .deferredIntent(intentConfig), configuration: self.configuration, analyticsHelper: .init(isCustom: false, configuration: configuration), integrationShape: .flowController) { result in + PaymentSheetLoader.load(mode: .deferredIntent(intentConfig), configuration: self.configuration, analyticsHelper: .init(integrationShape: .flowController, configuration: configuration), integrationShape: .flowController) { result in switch result { case .success(let loadResult): guard case .deferredIntent = loadResult.intent else { @@ -159,7 +159,7 @@ final class PaymentSheetLoaderTest: STPNetworkStubbingTestCase { } func testPaymentSheetLoadDeferredIntentFails() { - let analyticsHelper = PaymentSheetAnalyticsHelper(isCustom: false, configuration: configuration, analyticsClient: STPAnalyticsClient()) + let analyticsHelper = PaymentSheetAnalyticsHelper(integrationShape: .complete, configuration: configuration, analyticsClient: STPAnalyticsClient()) let loadExpectation = XCTestExpectation(description: "Load PaymentSheet") // Test PaymentSheetLoader.load can load various IntentConfigurations let confirmHandler: PaymentSheet.IntentConfiguration.ConfirmHandler = {_, _, _ in @@ -226,7 +226,7 @@ final class PaymentSheetLoaderTest: STPNetworkStubbingTestCase { XCTFail("Confirm handler shouldn't be called.") } let intentConfig = PaymentSheet.IntentConfiguration(mode: .payment(amount: 1000, currency: "JPY"), confirmHandler: confirmHandler) - PaymentSheetLoader.load(mode: .deferredIntent(intentConfig), configuration: configuration, analyticsHelper: .init(isCustom: false, configuration: configuration), integrationShape: .flowController) { result in + PaymentSheetLoader.load(mode: .deferredIntent(intentConfig), configuration: configuration, analyticsHelper: .init(integrationShape: .flowController, configuration: configuration), integrationShape: .flowController) { result in loadExpectation.fulfill() switch result { case .success(let loadResult): @@ -251,7 +251,7 @@ final class PaymentSheetLoaderTest: STPNetworkStubbingTestCase { externalPaymentMethods: ["external_paypal"], externalPaymentMethodConfirmHandler: { _, _, _ in /* no-op */ } ) - PaymentSheetLoader.load(mode: .paymentIntentClientSecret(clientSecret), configuration: configuration, analyticsHelper: .init(isCustom: false, configuration: configuration), integrationShape: .complete) { result in + PaymentSheetLoader.load(mode: .paymentIntentClientSecret(clientSecret), configuration: configuration, analyticsHelper: .init(integrationShape: .complete, configuration: configuration), integrationShape: .complete) { result in expectation.fulfill() switch result { case .success(let loadResult): @@ -292,7 +292,7 @@ final class PaymentSheetLoaderTest: STPNetworkStubbingTestCase { externalPaymentMethods: ["external_invalid_value"], externalPaymentMethodConfirmHandler: { _, _, _ in /* no-op */ } ) - PaymentSheetLoader.load(mode: .paymentIntentClientSecret(clientSecret), configuration: configuration, analyticsHelper: .init(isCustom: false, configuration: configuration), integrationShape: .flowController) { result in + PaymentSheetLoader.load(mode: .paymentIntentClientSecret(clientSecret), configuration: configuration, analyticsHelper: .init(integrationShape: .flowController, configuration: configuration), integrationShape: .flowController) { result in expectation.fulfill() switch result { case .success(let loadResult): @@ -350,7 +350,7 @@ final class PaymentSheetLoaderTest: STPNetworkStubbingTestCase { XCTFail("Confirm handler shouldn't be called.") } let intentConfig = PaymentSheet.IntentConfiguration(mode: .payment(amount: 1000, currency: "JPY"), confirmHandler: confirmHandler) - PaymentSheetLoader.load(mode: .deferredIntent(intentConfig), configuration: configuration, analyticsHelper: .init(isCustom: false, configuration: configuration), integrationShape: .complete) { result in + PaymentSheetLoader.load(mode: .deferredIntent(intentConfig), configuration: configuration, analyticsHelper: .init(integrationShape: .complete, configuration: configuration), integrationShape: .complete) { result in loadExpectation.fulfill() switch result { case .success(let loadResult): @@ -377,7 +377,7 @@ final class PaymentSheetLoaderTest: STPNetworkStubbingTestCase { // Set it to another number to manually run if you're making changes to load and want to measure its performance. measure(options: options) { let e = expectation(description: "") - PaymentSheetLoader.load(mode: .deferredIntent(intentConfig), configuration: configuration, analyticsHelper: .init(isCustom: false, configuration: configuration), integrationShape: .flowController) { result in + PaymentSheetLoader.load(mode: .deferredIntent(intentConfig), configuration: configuration, analyticsHelper: .init(integrationShape: .flowController, configuration: configuration), integrationShape: .flowController) { result in switch result { case .failure(let error): XCTFail(error.localizedDescription) diff --git a/StripePaymentSheet/StripePaymentSheetTests/PaymentSheet/STPFixtures+PaymentSheet.swift b/StripePaymentSheet/StripePaymentSheetTests/PaymentSheet/STPFixtures+PaymentSheet.swift index 5f1dd9a6caf..fd15db852e4 100644 --- a/StripePaymentSheet/StripePaymentSheetTests/PaymentSheet/STPFixtures+PaymentSheet.swift +++ b/StripePaymentSheet/StripePaymentSheetTests/PaymentSheet/STPFixtures+PaymentSheet.swift @@ -279,7 +279,7 @@ extension PaymentSheetLoader.LoadResult { extension PaymentSheetAnalyticsHelper { static func _testValue(analyticsClient: STPAnalyticsClient = .sharedClient) -> Self { - return .init(isCustom: false, configuration: PaymentSheet.Configuration(), analyticsClient: analyticsClient) + return .init(integrationShape: .complete, configuration: PaymentSheet.Configuration(), analyticsClient: analyticsClient) } }