From db41ece861dd541f6f46cfba358f09b96f343966 Mon Sep 17 00:00:00 2001 From: erenbesel Date: Fri, 10 Nov 2023 14:42:08 +0100 Subject: [PATCH 01/31] chore: adding new analytics classes --- Adyen.xcodeproj/project.pbxproj | 20 +++++++++ Adyen/Analytics/Models/AdyenAnalytics.swift | 25 +++++++++++ .../Models/AdyenAnalyticsError.swift | 32 +++++++++++++ .../Models/AdyenAnalyticsEvent.swift | 34 ++++++++++++++ .../Analytics/Models/AdyenAnalyticsLog.swift | 39 ++++++++++++++++ .../Requests/AdyenAnalyticsRequest.swift | 45 +++++++++++++++++++ 6 files changed, 195 insertions(+) create mode 100644 Adyen/Analytics/Models/AdyenAnalytics.swift create mode 100644 Adyen/Analytics/Models/AdyenAnalyticsError.swift create mode 100644 Adyen/Analytics/Models/AdyenAnalyticsEvent.swift create mode 100644 Adyen/Analytics/Models/AdyenAnalyticsLog.swift create mode 100644 Adyen/Analytics/Requests/AdyenAnalyticsRequest.swift diff --git a/Adyen.xcodeproj/project.pbxproj b/Adyen.xcodeproj/project.pbxproj index 56432110ab..67f6575145 100644 --- a/Adyen.xcodeproj/project.pbxproj +++ b/Adyen.xcodeproj/project.pbxproj @@ -265,6 +265,11 @@ A0BC64E628F062E400CED2A1 /* AdyenSessionAware.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0BC64E528F062E400CED2A1 /* AdyenSessionAware.swift */; }; A0C9B59B288AE34600D6BDAB /* InstallmentOptions.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0F41E5526CBCA6E0089AD6C /* InstallmentOptions.swift */; }; A0D48FB827109B0200C0B82C /* ArrayHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0D48FB727109B0200C0B82C /* ArrayHelpers.swift */; }; + A0DB48662AFD020400348C83 /* AdyenAnalyticsRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0DB48652AFD020400348C83 /* AdyenAnalyticsRequest.swift */; }; + A0DB48682AFD068400348C83 /* AdyenAnalytics.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0DB48672AFD068400348C83 /* AdyenAnalytics.swift */; }; + A0DB486A2AFD0BDC00348C83 /* AdyenAnalyticsEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0DB48692AFD0BDC00348C83 /* AdyenAnalyticsEvent.swift */; }; + A0DB486C2AFD0BEE00348C83 /* AdyenAnalyticsLog.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0DB486B2AFD0BEE00348C83 /* AdyenAnalyticsLog.swift */; }; + A0DB486E2AFD0BFC00348C83 /* AdyenAnalyticsError.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0DB486D2AFD0BFC00348C83 /* AdyenAnalyticsError.swift */; }; A0DDA6A72A6162F500EBD6AF /* AdyenSessionResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0DDA6A62A6162F500EBD6AF /* AdyenSessionResult.swift */; }; A0DE8F6D26CEA04500F2F1E8 /* Installments.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0DE8F6C26CEA04500F2F1E8 /* Installments.swift */; }; A0F41EAC26CD4AA50089AD6C /* FormCardInstallmentsItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0F41EAB26CD4AA50089AD6C /* FormCardInstallmentsItem.swift */; }; @@ -1454,6 +1459,11 @@ A0B180302A2DE445003C608E /* MealVoucherDetails.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MealVoucherDetails.swift; sourceTree = ""; }; A0BC64E528F062E400CED2A1 /* AdyenSessionAware.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdyenSessionAware.swift; sourceTree = ""; }; A0D48FB727109B0200C0B82C /* ArrayHelpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArrayHelpers.swift; sourceTree = ""; }; + A0DB48652AFD020400348C83 /* AdyenAnalyticsRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdyenAnalyticsRequest.swift; sourceTree = ""; }; + A0DB48672AFD068400348C83 /* AdyenAnalytics.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdyenAnalytics.swift; sourceTree = ""; }; + A0DB48692AFD0BDC00348C83 /* AdyenAnalyticsEvent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdyenAnalyticsEvent.swift; sourceTree = ""; }; + A0DB486B2AFD0BEE00348C83 /* AdyenAnalyticsLog.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdyenAnalyticsLog.swift; sourceTree = ""; }; + A0DB486D2AFD0BFC00348C83 /* AdyenAnalyticsError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdyenAnalyticsError.swift; sourceTree = ""; }; A0DDA6A62A6162F500EBD6AF /* AdyenSessionResult.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdyenSessionResult.swift; sourceTree = ""; }; A0DE8F6C26CEA04500F2F1E8 /* Installments.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Installments.swift; sourceTree = ""; }; A0F41E5526CBCA6E0089AD6C /* InstallmentOptions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InstallmentOptions.swift; sourceTree = ""; }; @@ -3033,6 +3043,7 @@ children = ( C94632C127BAA81F003DD81F /* TelemetryRequest.swift */, C9BAE20E27BEA68D002F5728 /* CheckoutAttemptIdRequest.swift */, + A0DB48652AFD020400348C83 /* AdyenAnalyticsRequest.swift */, ); path = Requests; sourceTree = ""; @@ -3041,6 +3052,10 @@ isa = PBXGroup; children = ( C9B6683627C8D7FB006950B9 /* TelemetryData.swift */, + A0DB48672AFD068400348C83 /* AdyenAnalytics.swift */, + A0DB48692AFD0BDC00348C83 /* AdyenAnalyticsEvent.swift */, + A0DB486B2AFD0BEE00348C83 /* AdyenAnalyticsLog.swift */, + A0DB486D2AFD0BFC00348C83 /* AdyenAnalyticsError.swift */, ); path = Models; sourceTree = ""; @@ -6363,6 +6378,7 @@ F9A6C41D26550B7100D8CD3E /* AlreadyPaidPaymentComponent.swift in Sources */, F9D644E024D2E4210059CBE3 /* EmailValidator.swift in Sources */, F9639B3324DD96990073F38A /* PaymentStatusRequest.swift in Sources */, + A0DB48662AFD020400348C83 /* AdyenAnalyticsRequest.swift in Sources */, 5AD40E75262F04440090E01C /* UIProgressViewHelpers.swift in Sources */, F91664F023E41D7300C10738 /* AnyEncodable.swift in Sources */, E7D531192446F525000046B4 /* FormSeparatorItemView.swift in Sources */, @@ -6417,6 +6433,7 @@ E224088D22B0FD220058923E /* StoredPayPalPaymentMethod.swift in Sources */, F99D2F0A266136A700BB5B2F /* AppleWalletPassResponse.swift in Sources */, F9639B3524DD97A30073F38A /* PaymentStatusResponse.swift in Sources */, + A0DB486E2AFD0BFC00348C83 /* AdyenAnalyticsError.swift in Sources */, F9BA21C2246E82EE00D36A63 /* SizeUtilities.swift in Sources */, F97C829225BB156600D7F85C /* AbstractPersonalInformationComponent+Extensions.swift in Sources */, 81BA08372A49C93100308160 /* FormSelectableValueItemView.swift in Sources */, @@ -6460,6 +6477,7 @@ 00EACBBD2876F9DC0082B360 /* FormAttributedLabelItem.swift in Sources */, F90E95F227280BD5007E382B /* CoreListDataSource.swift in Sources */, F926D53323F5A5D000D058D3 /* NumericStringValidator.swift in Sources */, + A0DB48682AFD068400348C83 /* AdyenAnalytics.swift in Sources */, E702BDE42602149E00280682 /* Assertion.swift in Sources */, E288EB962267652D000E960C /* AdyenObserver.swift in Sources */, F9EDB7862391734200CFB3C9 /* UnknownError.swift in Sources */, @@ -6490,6 +6508,7 @@ F9D5752A237C6084009C18B5 /* StoredBCMCPaymentMethod.swift in Sources */, E2289B3C23D0BBB1002844BF /* ListSectionHeaderStyle.swift in Sources */, E715A7342A1B96890047B87A /* UIApplicationHelpers.swift in Sources */, + A0DB486C2AFD0BEE00348C83 /* AdyenAnalyticsLog.swift in Sources */, F926D53723F6A35700D058D3 /* NumericFormatter.swift in Sources */, A026C85127C4FE4700E6C34A /* BasicComponentConfiguration.swift in Sources */, E7085B162628B29600D0153B /* FormPhoneExtensionPickerItemView.swift in Sources */, @@ -6510,6 +6529,7 @@ E2C0E096220B04F0008616F6 /* FormViewController.swift in Sources */, F9FE25D62626CD49001874BB /* ReadyToSubmitPaymentComponentDelegate.swift in Sources */, F99D4556262717A500880D72 /* FormErrorItemView.swift in Sources */, + A0DB486A2AFD0BDC00348C83 /* AdyenAnalyticsEvent.swift in Sources */, F96286BD256BDEB000043FE3 /* CoreBundleExtension.swift in Sources */, E7085D7D262EEF6200D0153B /* AllRegions.swift in Sources */, F919DF9124E682480027976E /* ClientKeyResponse.swift in Sources */, diff --git a/Adyen/Analytics/Models/AdyenAnalytics.swift b/Adyen/Analytics/Models/AdyenAnalytics.swift new file mode 100644 index 0000000000..c6252d7f44 --- /dev/null +++ b/Adyen/Analytics/Models/AdyenAnalytics.swift @@ -0,0 +1,25 @@ +// +// Copyright (c) 2023 Adyen N.V. +// +// This file is open source and available under the MIT license. See the LICENSE file for more info. +// + +import Foundation + +internal struct AdyenAnalytics { + + internal struct CommonFields: Encodable { + + internal var timestamp = ISO8601DateFormatter().string(from: Date()) + + internal var component: String + + internal var metadata: [String: String] = [:] + } + +} + +internal protocol AdyenAnalyticsCommonFields: Encodable { + var commonFields: AdyenAnalytics.CommonFields { get } +} + diff --git a/Adyen/Analytics/Models/AdyenAnalyticsError.swift b/Adyen/Analytics/Models/AdyenAnalyticsError.swift new file mode 100644 index 0000000000..ca2aeca39c --- /dev/null +++ b/Adyen/Analytics/Models/AdyenAnalyticsError.swift @@ -0,0 +1,32 @@ +// +// Copyright (c) 2023 Adyen N.V. +// +// This file is open source and available under the MIT license. See the LICENSE file for more info. +// + +import Foundation + +internal extension AdyenAnalytics { + + /// Represents an error in the analytics scheme that indicates the flow was interrupted due to an error in the SDK. + struct Error: AdyenAnalyticsCommonFields { + + internal var commonFields: AdyenAnalytics.CommonFields + + internal var type: ErrorType + + internal var code: String + + internal var message: String + } + + enum ErrorType: String, Encodable { + case network = "Network" + case implementation = "Implementation" + case `internal` = "Internal" + case api = "ApiError" + case sdk = "SdkError" + case thirdParty = "ThirdParty" + case generic = "Generic" + } +} diff --git a/Adyen/Analytics/Models/AdyenAnalyticsEvent.swift b/Adyen/Analytics/Models/AdyenAnalyticsEvent.swift new file mode 100644 index 0000000000..37979b46a8 --- /dev/null +++ b/Adyen/Analytics/Models/AdyenAnalyticsEvent.swift @@ -0,0 +1,34 @@ +// +// Copyright (c) 2023 Adyen N.V. +// +// This file is open source and available under the MIT license. See the LICENSE file for more info. +// + +import Foundation + +internal extension AdyenAnalytics { + + /// Represents an event in the analytics scheme that can occur many times during the checkout flow, such as input field focus/unfocus etc. + struct Event: AdyenAnalyticsCommonFields { + + internal var commonFields: AdyenAnalytics.CommonFields + + internal var type: EventType + + internal var target: String + + internal var isStoredPaymentMethod: Bool + + internal var brand: String + + internal var validationErrorCode: String + + internal var validationErrorMessage: String + } + + enum EventType: String, Encodable { + case selected = "Selected" + case focus = "Focus" + case unfocus = "Unfocus" + } +} diff --git a/Adyen/Analytics/Models/AdyenAnalyticsLog.swift b/Adyen/Analytics/Models/AdyenAnalyticsLog.swift new file mode 100644 index 0000000000..c3ed79cacf --- /dev/null +++ b/Adyen/Analytics/Models/AdyenAnalyticsLog.swift @@ -0,0 +1,39 @@ +// +// Copyright (c) 2023 Adyen N.V. +// +// This file is open source and available under the MIT license. See the LICENSE file for more info. +// + +import Foundation + +internal extension AdyenAnalytics { + + /// A log in the analytics scheme represents important checkpoints such as the pay button press, 3ds challenge etc. + struct Log: AdyenAnalyticsCommonFields { + + internal var commonFields: AdyenAnalytics.CommonFields + + internal var type: LogType + + internal var subType: LogSubType + + internal var target: String + + internal var message: String + } + + enum LogType: String, Encodable { + case action = "Action" + case submit = "Submit" + } + + enum LogSubType: String, Encodable { + case threeDS2 = "ThreeDS2" + case redirect = "Redirect" + case voucher = "Voucher" + case await = "Await" + case qrCode = "QrCode" + case bankTransfer = "BankTransfer" + case sdk = "Sdk" + } +} diff --git a/Adyen/Analytics/Requests/AdyenAnalyticsRequest.swift b/Adyen/Analytics/Requests/AdyenAnalyticsRequest.swift new file mode 100644 index 0000000000..803d083f55 --- /dev/null +++ b/Adyen/Analytics/Requests/AdyenAnalyticsRequest.swift @@ -0,0 +1,45 @@ +// +// Copyright (c) 2023 Adyen N.V. +// +// This file is open source and available under the MIT license. See the LICENSE file for more info. +// + +import AdyenNetworking +import Foundation + +internal struct AdyenAnalyticsRequest: APIRequest { + + internal typealias ResponseType = AdyenAnalyticsResponse + + internal let path: String + + internal var counter: UInt = 0 + + internal let headers: [String: String] = [:] + + internal let queryParameters: [URLQueryItem] = [] + + internal let method: HTTPMethod = .post + + internal var channel: String = "iOS" + + internal var events: [AdyenAnalytics.Event] = [] + + internal var logs: [AdyenAnalytics.Log] = [] + + internal var errors: [AdyenAnalytics.Error] = [] + + init(checkoutAttemptId: String) { + self.path = "/checkoutanalytics/v3/analytics/\(checkoutAttemptId)" + } + + private enum CodingKeys: String, CodingKey { + case channel + case events + case logs + case errors + + } +} + +internal struct AdyenAnalyticsResponse: Response { /* Empty response */ } From 19c8c1e8120bc5c69e28c85fe532f1a44efc2e88 Mon Sep 17 00:00:00 2001 From: erenbesel Date: Thu, 14 Dec 2023 16:42:10 +0100 Subject: [PATCH 02/31] chore: replace telemetry with new one combining with checkout attempt id --- .../AnalyticsProvider/AnalyticsProvider.swift | 84 ++++++++++--- .../AnalyticsProvider/TelemetryTracker.swift | 30 ----- Adyen/Analytics/Models/AdyenAnalytics.swift | 8 +- .../Models/AdyenAnalyticsError.swift | 6 +- .../Models/AdyenAnalyticsEvent.swift | 9 +- .../Analytics/Models/AdyenAnalyticsLog.swift | 8 +- Adyen/Analytics/Models/TelemetryData.swift | 9 +- .../Requests/AdyenAnalyticsRequest.swift | 6 +- .../Requests/CheckoutAttemptIdRequest.swift | 56 ++++++++- Adyen/Core/AdyenContext/AdyenContext.swift | 6 - ...AbstractPersonalInformationComponent.swift | 2 +- .../Components/InstantPaymentComponent.swift | 5 +- .../StoredPaymentMethodComponent.swift | 2 +- .../Core Protocols/PaymentComponent.swift | 2 - .../Core Protocols/PresentableComponent.swift | 21 +++- .../SearchViewController.swift | 12 ++ .../Card/CardComponentExtensions.swift | 4 - .../GiftCardComponent+Extensions.swift | 5 - .../Stored Card/StoredCardComponent.swift | 2 +- AdyenCashAppPay/CashAppPayComponent.swift | 7 +- .../ACHDirectDebitComponent.swift | 5 - .../Apple Pay/ApplePayComponent.swift | 10 +- .../BACSDirectDebitComponent.swift | 3 +- .../Scenes/Input/BACSInputPresenter.swift | 2 +- .../BACSDirectDebitComponentTracker.swift | 18 +-- AdyenComponents/BLIK/BLIKComponent.swift | 8 +- AdyenComponents/Boleto/BoletoComponent.swift | 2 +- .../Issuer List/IssuerListComponent.swift | 12 +- .../SEPADirectDebitComponent.swift | 7 +- .../PaymentMethodListComponent.swift | 6 - .../PreselectedPaymentMethodComponent.swift | 10 +- AdyenDropIn/DropInComponentExtensions.swift | 7 +- AdyenSession/AdyenSession.swift | 2 + .../Analytics/AnalyticsProviderMock.swift | 26 ++-- .../Analytics/AnalyticsProviderTests.swift | 113 ++++++++---------- .../Analytics/TelemetryTrackerTests.swift | 29 +++-- .../Adyen Tests/Core/AdyenContextTests.swift | 4 +- Tests/Card Tests/BCMCComponentTests.swift | 2 +- Tests/Card Tests/CardComponentTests.swift | 2 +- .../Card Tests/StoredCardComponentTests.swift | 2 +- .../StoredPaymentMethodComponentTests.swift | 2 +- .../ACHDirectDebitComponentTests.swift | 2 +- .../Affirm/AffirmComponentTests.swift | 2 +- .../Apple Pay/ApplePayComponentTests.swift | 2 +- .../Apple Pay/PreApplePayComponentTests.swift | 4 +- .../Atome/AtomeComponentTests.swift | 2 +- ...ectDebitComponentTrackerProtocolMock.swift | 11 +- .../Input/BACSInputPresenterTests.swift | 2 +- ...BACSDirectDebitComponentTrackerTests.swift | 8 +- .../BLIK Component/BLIKComponentTests.swift | 2 +- .../Boleto/BoletoComponentTests.swift | 2 +- .../CashAppPayComponentTests.swift | 2 +- .../Doku/DokuComponentTests.swift | 2 +- .../Gift Card/GiftCardComponentTests.swift | 2 +- .../InstantPaymentComponentTests.swift | 15 --- .../IssuerList/IssuerListComponentTests.swift | 2 +- .../MB Way/MBWayComponentTests.swift | 2 +- .../PaymentComponentSubjectTests.swift | 4 +- .../QiwiWalletComponentTests.swift | 2 +- .../SEPADirectDebitComponentTests.swift | 2 +- Tests/Session Tests/SessionTests.swift | 7 +- 61 files changed, 327 insertions(+), 306 deletions(-) diff --git a/Adyen/Analytics/AnalyticsProvider/AnalyticsProvider.swift b/Adyen/Analytics/AnalyticsProvider/AnalyticsProvider.swift index 379c082077..38e68b5834 100644 --- a/Adyen/Analytics/AnalyticsProvider/AnalyticsProvider.swift +++ b/Adyen/Analytics/AnalyticsProvider/AnalyticsProvider.swift @@ -29,15 +29,26 @@ public struct AnalyticsConfiguration { public struct AdditionalAnalyticsFields { /// The amount of the payment public let amount: Amount? + + public let sessionId: String? + + public init(amount: Amount? = nil, sessionId: String? = nil) { + self.amount = amount + self.sessionId = sessionId + } } @_spi(AdyenInternal) -public protocol AnalyticsProviderProtocol: TelemetryTrackerProtocol { +public protocol InitialTelemetryProtocol { - var checkoutAttemptId: String? { get } - func fetchAndCacheCheckoutAttemptIdIfNeeded() + /// Sends the initial data and retrieves the checkout attempt id as a response. + func fetchCheckoutAttemptId(with flavor: TelemetryFlavor, additionalFields: AdditionalAnalyticsFields?) +} + +@_spi(AdyenInternal) +public protocol AnalyticsProviderProtocol: InitialTelemetryProtocol { - var additionalFields: (() -> AdditionalAnalyticsFields)? { get } + var checkoutAttemptId: String? { get } } internal final class AnalyticsProvider: AnalyticsProviderProtocol { @@ -47,8 +58,13 @@ internal final class AnalyticsProvider: AnalyticsProviderProtocol { internal let apiClient: APIClientProtocol internal let configuration: AnalyticsConfiguration internal private(set) var checkoutAttemptId: String? - internal var additionalFields: (() -> AdditionalAnalyticsFields)? private let uniqueAssetAPIClient: UniqueAssetAPIClient + + private var batchTimer: Timer? + + private var events: [AdyenAnalytics.Event] = [] + private var logs: [AdyenAnalytics.Log] = [] + private var errors: [AdyenAnalytics.Error] = [] // MARK: - Initializers @@ -62,28 +78,66 @@ internal final class AnalyticsProvider: AnalyticsProviderProtocol { } // MARK: - Internal - - internal func fetchAndCacheCheckoutAttemptIdIfNeeded() { - fetchCheckoutAttemptId { _ in /* Do nothing, the point is to trigger the fetching and cache the value */ } - } - internal func fetchCheckoutAttemptId(completion: @escaping (String?) -> Void) { - guard configuration.isEnabled else { + internal func fetchCheckoutAttemptId(with flavor: TelemetryFlavor, additionalFields: AdditionalAnalyticsFields?) { + guard configuration.isEnabled, configuration.isTelemetryEnabled else { checkoutAttemptId = "do-not-track" - completion(checkoutAttemptId) return } + if case .dropInComponent = flavor { return } + + let telemetryData = TelemetryData(flavor: flavor, + additionalFields: additionalFields) - let checkoutAttemptIdRequest = CheckoutAttemptIdRequest() + let checkoutAttemptIdRequest = CheckoutAttemptIdRequest(data: telemetryData) uniqueAssetAPIClient.perform(checkoutAttemptIdRequest) { [weak self] result in switch result { case let .success(response): self?.checkoutAttemptId = response.identifier - completion(response.identifier) case .failure: - completion(nil) + self?.checkoutAttemptId = nil } } } + + internal func send(event: AdyenAnalytics.Event) { + events.append(event) + } + + internal func send(log: AdyenAnalytics.Log) { + logs.append(log) + } + + internal func send(error: AdyenAnalytics.Error) { + errors.append(error) + sendAll() + } + + private func setupTimer() { + let timer = Timer(timeInterval: 10, target: self, selector: #selector(sendAll), userInfo: nil, repeats: true) + timer.tolerance = 1 + RunLoop.current.add(timer, forMode: .common) + } + + @objc private func sendAll() { + guard configuration.isEnabled, + let checkoutAttemptId else { return } + var request = AdyenAnalyticsRequest(checkoutAttemptId: checkoutAttemptId) + + request.events = events + request.logs = logs + request.errors = errors + + apiClient.perform(request) { [weak self] _ in + guard let self else { return } + self.clearAll() + } + } + + private func clearAll() { + events = [] + logs = [] + errors = [] + } } diff --git a/Adyen/Analytics/AnalyticsProvider/TelemetryTracker.swift b/Adyen/Analytics/AnalyticsProvider/TelemetryTracker.swift index a4d08e4ddd..4c569f5ac5 100644 --- a/Adyen/Analytics/AnalyticsProvider/TelemetryTracker.swift +++ b/Adyen/Analytics/AnalyticsProvider/TelemetryTracker.swift @@ -27,33 +27,3 @@ public enum TelemetryFlavor { } } } - -@_spi(AdyenInternal) -public protocol TelemetryTrackerProtocol { - func sendTelemetryEvent(flavor: TelemetryFlavor) -} - -// MARK: - TelemetryTrackerProtocol - -@_spi(AdyenInternal) -extension AnalyticsProvider: TelemetryTrackerProtocol { - - internal func sendTelemetryEvent(flavor: TelemetryFlavor) { - guard configuration.isEnabled else { return } - guard configuration.isTelemetryEnabled else { return } - if case .dropInComponent = flavor { return } - - let additionalFields = additionalFields?() - - let telemetryData = TelemetryData( - flavor: flavor, - amount: additionalFields?.amount - ) - - fetchCheckoutAttemptId { [weak self] checkoutAttemptId in - let telemetryRequest = TelemetryRequest(data: telemetryData, - checkoutAttemptId: checkoutAttemptId) - self?.apiClient.perform(telemetryRequest) { _ in } - } - } -} diff --git a/Adyen/Analytics/Models/AdyenAnalytics.swift b/Adyen/Analytics/Models/AdyenAnalytics.swift index c6252d7f44..dc57c9bc46 100644 --- a/Adyen/Analytics/Models/AdyenAnalytics.swift +++ b/Adyen/Analytics/Models/AdyenAnalytics.swift @@ -6,7 +6,12 @@ import Foundation -internal struct AdyenAnalytics { +@_spi(AdyenInternal) +public final class AdyenAnalytics { + + @_spi(AdyenInternal) + /// Needed to be able to determine if using session + public static var sessionId: String? internal struct CommonFields: Encodable { @@ -22,4 +27,3 @@ internal struct AdyenAnalytics { internal protocol AdyenAnalyticsCommonFields: Encodable { var commonFields: AdyenAnalytics.CommonFields { get } } - diff --git a/Adyen/Analytics/Models/AdyenAnalyticsError.swift b/Adyen/Analytics/Models/AdyenAnalyticsError.swift index ca2aeca39c..20c85e6b82 100644 --- a/Adyen/Analytics/Models/AdyenAnalyticsError.swift +++ b/Adyen/Analytics/Models/AdyenAnalyticsError.swift @@ -6,10 +6,10 @@ import Foundation -internal extension AdyenAnalytics { +extension AdyenAnalytics { /// Represents an error in the analytics scheme that indicates the flow was interrupted due to an error in the SDK. - struct Error: AdyenAnalyticsCommonFields { + internal struct Error: AdyenAnalyticsCommonFields { internal var commonFields: AdyenAnalytics.CommonFields @@ -20,7 +20,7 @@ internal extension AdyenAnalytics { internal var message: String } - enum ErrorType: String, Encodable { + internal enum ErrorType: String, Encodable { case network = "Network" case implementation = "Implementation" case `internal` = "Internal" diff --git a/Adyen/Analytics/Models/AdyenAnalyticsEvent.swift b/Adyen/Analytics/Models/AdyenAnalyticsEvent.swift index 37979b46a8..293f6f36c4 100644 --- a/Adyen/Analytics/Models/AdyenAnalyticsEvent.swift +++ b/Adyen/Analytics/Models/AdyenAnalyticsEvent.swift @@ -6,10 +6,11 @@ import Foundation -internal extension AdyenAnalytics { +extension AdyenAnalytics { - /// Represents an event in the analytics scheme that can occur many times during the checkout flow, such as input field focus/unfocus etc. - struct Event: AdyenAnalyticsCommonFields { + /// Represents an event in the analytics scheme that can occur + /// many times during the checkout flow, such as input field focus/unfocus etc. + internal struct Event: AdyenAnalyticsCommonFields { internal var commonFields: AdyenAnalytics.CommonFields @@ -26,7 +27,7 @@ internal extension AdyenAnalytics { internal var validationErrorMessage: String } - enum EventType: String, Encodable { + internal enum EventType: String, Encodable { case selected = "Selected" case focus = "Focus" case unfocus = "Unfocus" diff --git a/Adyen/Analytics/Models/AdyenAnalyticsLog.swift b/Adyen/Analytics/Models/AdyenAnalyticsLog.swift index c3ed79cacf..f2aae21013 100644 --- a/Adyen/Analytics/Models/AdyenAnalyticsLog.swift +++ b/Adyen/Analytics/Models/AdyenAnalyticsLog.swift @@ -6,10 +6,10 @@ import Foundation -internal extension AdyenAnalytics { +extension AdyenAnalytics { /// A log in the analytics scheme represents important checkpoints such as the pay button press, 3ds challenge etc. - struct Log: AdyenAnalyticsCommonFields { + internal struct Log: AdyenAnalyticsCommonFields { internal var commonFields: AdyenAnalytics.CommonFields @@ -22,12 +22,12 @@ internal extension AdyenAnalytics { internal var message: String } - enum LogType: String, Encodable { + internal enum LogType: String, Encodable { case action = "Action" case submit = "Submit" } - enum LogSubType: String, Encodable { + internal enum LogSubType: String, Encodable { case threeDS2 = "ThreeDS2" case redirect = "Redirect" case voucher = "Voucher" diff --git a/Adyen/Analytics/Models/TelemetryData.swift b/Adyen/Analytics/Models/TelemetryData.swift index 8a21cd6fa4..199a10ab74 100644 --- a/Adyen/Analytics/Models/TelemetryData.swift +++ b/Adyen/Analytics/Models/TelemetryData.swift @@ -34,6 +34,8 @@ internal struct TelemetryData: Encodable { return identifier + String(UnicodeScalar(UInt8(value))) } }() + + internal let deviceModel = UIDevice.current.model internal let systemVersion = UIDevice.current.systemVersion @@ -49,15 +51,18 @@ internal struct TelemetryData: Encodable { internal var amount: Amount? + internal var sessionId: String? + internal var paymentMethods: [String] = [] internal let component: String // MARK: - Initializers - internal init(flavor: TelemetryFlavor, amount: Amount?) { + internal init(flavor: TelemetryFlavor, additionalFields: AdditionalAnalyticsFields?) { self.flavor = flavor.value - self.amount = amount + self.amount = additionalFields?.amount + self.sessionId = additionalFields?.sessionId switch flavor { case let .dropIn(type, paymentMethods): diff --git a/Adyen/Analytics/Requests/AdyenAnalyticsRequest.swift b/Adyen/Analytics/Requests/AdyenAnalyticsRequest.swift index 803d083f55..ffd5e0c06e 100644 --- a/Adyen/Analytics/Requests/AdyenAnalyticsRequest.swift +++ b/Adyen/Analytics/Requests/AdyenAnalyticsRequest.swift @@ -7,6 +7,8 @@ import AdyenNetworking import Foundation +internal struct AdyenAnalyticsResponse: Response { /* Empty response */ } + internal struct AdyenAnalyticsRequest: APIRequest { internal typealias ResponseType = AdyenAnalyticsResponse @@ -29,7 +31,7 @@ internal struct AdyenAnalyticsRequest: APIRequest { internal var errors: [AdyenAnalytics.Error] = [] - init(checkoutAttemptId: String) { + internal init(checkoutAttemptId: String) { self.path = "/checkoutanalytics/v3/analytics/\(checkoutAttemptId)" } @@ -41,5 +43,3 @@ internal struct AdyenAnalyticsRequest: APIRequest { } } - -internal struct AdyenAnalyticsResponse: Response { /* Empty response */ } diff --git a/Adyen/Analytics/Requests/CheckoutAttemptIdRequest.swift b/Adyen/Analytics/Requests/CheckoutAttemptIdRequest.swift index 8c1e3fc969..3dd28f1a2c 100644 --- a/Adyen/Analytics/Requests/CheckoutAttemptIdRequest.swift +++ b/Adyen/Analytics/Requests/CheckoutAttemptIdRequest.swift @@ -14,7 +14,7 @@ internal struct CheckoutAttemptIdResponse: Response { internal let identifier: String internal enum CodingKeys: String, CodingKey { - case identifier = "id" + case identifier = "checkoutAttemptId" } } @@ -22,7 +22,7 @@ internal struct CheckoutAttemptIdRequest: APIRequest { internal typealias ResponseType = CheckoutAttemptIdResponse - internal let path: String = "checkoutshopper/v2/analytics/id" + internal let path: String = "/checkoutanalytics/v3/analytics" internal var counter: UInt = 0 @@ -32,9 +32,57 @@ internal struct CheckoutAttemptIdRequest: APIRequest { internal let method: HTTPMethod = .post - internal let experiments: [String] = [] + private var version: String + private let channel: String + private let locale: String + private let flavor: String + private let userAgent: String? + private var deviceBrand: String + private var deviceModel: String + private let systemVersion: String + private let referrer: String + private let screenWidth: Int + private let containerWidth: Int? + private let paymentMethods: [String] + private let component: String + internal let amount: Amount? + internal let sessionId: String? + + // MARK: - Initializers + + internal init(data: TelemetryData) { + self.version = data.version + self.channel = data.channel + self.locale = data.locale + self.flavor = data.flavor + self.userAgent = data.userAgent + self.deviceBrand = data.deviceBrand + self.deviceModel = data.deviceModel + self.systemVersion = data.systemVersion + self.referrer = data.referrer + self.screenWidth = data.screenWidth + self.containerWidth = data.containerWidth + self.paymentMethods = data.paymentMethods + self.component = data.component + self.amount = data.amount + self.sessionId = data.sessionId + } internal enum CodingKeys: CodingKey { - case experiments + case version + case channel + case locale + case flavor + case userAgent + case deviceBrand + case deviceModel + case systemVersion + case referrer + case screenWidth + case containerWidth + case paymentMethods + case component + case amount + case sessionId } } diff --git a/Adyen/Core/AdyenContext/AdyenContext.swift b/Adyen/Core/AdyenContext/AdyenContext.swift index 00ad48b696..f6d160f66d 100644 --- a/Adyen/Core/AdyenContext/AdyenContext.swift +++ b/Adyen/Core/AdyenContext/AdyenContext.swift @@ -40,12 +40,6 @@ public final class AdyenContext: PaymentAware { payment: payment, analyticsProvider: analyticsProvider ) - - analyticsProvider.additionalFields = { [weak self] in - .init( - amount: self?.payment?.amount - ) - } } /// Internal init for testing only diff --git a/Adyen/Core/Components/AbstractPersonalInformationComponent/AbstractPersonalInformationComponent.swift b/Adyen/Core/Components/AbstractPersonalInformationComponent/AbstractPersonalInformationComponent.swift index 3ae1e04486..4b4500115d 100644 --- a/Adyen/Core/Components/AbstractPersonalInformationComponent/AbstractPersonalInformationComponent.swift +++ b/Adyen/Core/Components/AbstractPersonalInformationComponent/AbstractPersonalInformationComponent.swift @@ -258,7 +258,7 @@ extension AbstractPersonalInformationComponent: ViewControllerDelegate { // MARK: - ViewControllerDelegate public func viewWillAppear(viewController: UIViewController) { - sendTelemetryEvent() + fetchCheckoutAttemptId() populateFields() } } diff --git a/Adyen/Core/Components/InstantPaymentComponent.swift b/Adyen/Core/Components/InstantPaymentComponent.swift index bb2dee719d..b90e7a88c8 100644 --- a/Adyen/Core/Components/InstantPaymentComponent.swift +++ b/Adyen/Core/Components/InstantPaymentComponent.swift @@ -56,14 +56,11 @@ public final class InstantPaymentComponent: PaymentComponent { /// Generate the payment details and invoke PaymentsComponentDelegate method. public func initiatePayment() { - sendTelemetryEvent() + // we can attempt to fetch the checkoutAttempId but it won't be ready for the payment submit(data: paymentData) } } -@_spi(AdyenInternal) -extension InstantPaymentComponent: TrackableComponent {} - /// Describes a payment details that contains nothing but the payment method type name. public struct InstantPaymentDetails: PaymentMethodDetails { diff --git a/Adyen/Core/Components/StoredPaymentMethodComponent.swift b/Adyen/Core/Components/StoredPaymentMethodComponent.swift index 8f0c8d24ee..6148553d0b 100644 --- a/Adyen/Core/Components/StoredPaymentMethodComponent.swift +++ b/Adyen/Core/Components/StoredPaymentMethodComponent.swift @@ -47,7 +47,7 @@ public final class StoredPaymentMethodComponent: PaymentComponent, flavor: _isDropIn ? .dropin : .components, context: context.apiContext ) - sendTelemetryEvent() + fetchCheckoutAttemptId() let localizationParameters = configuration.localizationParameters let displayInformation = storedPaymentMethod.displayInformation(using: localizationParameters) diff --git a/Adyen/Core/Core Protocols/PaymentComponent.swift b/Adyen/Core/Core Protocols/PaymentComponent.swift index fa3e570a81..218fe3c68a 100644 --- a/Adyen/Core/Core Protocols/PaymentComponent.swift +++ b/Adyen/Core/Core Protocols/PaymentComponent.swift @@ -31,8 +31,6 @@ extension PaymentComponent { /// - component: The component from which the payment originates. public func submit(data: PaymentComponentData, component: PaymentComponent? = nil) { let component = component ?? self - /// try to fetch the fetchCheckoutAttemptId to get cached if its not already cached - component.context.analyticsProvider.fetchAndCacheCheckoutAttemptIdIfNeeded() let updatedData = data.replacing(checkoutAttemptId: component.context.analyticsProvider.checkoutAttemptId) diff --git a/Adyen/Core/Core Protocols/PresentableComponent.swift b/Adyen/Core/Core Protocols/PresentableComponent.swift index 510f0b23dd..bad7955221 100644 --- a/Adyen/Core/Core Protocols/PresentableComponent.swift +++ b/Adyen/Core/Core Protocols/PresentableComponent.swift @@ -62,15 +62,26 @@ public extension PresentableComponent { @_spi(AdyenInternal) public protocol TrackableComponent: Component { - - func sendTelemetryEvent() + + func fetchCheckoutAttemptId() } @_spi(AdyenInternal) extension TrackableComponent where Self: PaymentMethodAware { - - public func sendTelemetryEvent() { + + public func fetchCheckoutAttemptId() { let flavor: TelemetryFlavor = _isDropIn ? .dropInComponent : .components(type: paymentMethod.type) - context.analyticsProvider.sendTelemetryEvent(flavor: flavor) + let amount = context.payment?.amount + let additionalFields = AdditionalAnalyticsFields(amount: amount, sessionId: AdyenAnalytics.sessionId) + context.analyticsProvider.fetchCheckoutAttemptId(with: flavor, + additionalFields: additionalFields) + } +} + +@_spi(AdyenInternal) +extension TrackableComponent where Self: ViewControllerDelegate { + + public func viewWillAppear(viewController: UIViewController) { + fetchCheckoutAttemptId() } } diff --git a/Adyen/UI/View Controllers/SearchViewController/SearchViewController.swift b/Adyen/UI/View Controllers/SearchViewController/SearchViewController.swift index 3ba71da75e..e77fccd83a 100644 --- a/Adyen/UI/View Controllers/SearchViewController/SearchViewController.swift +++ b/Adyen/UI/View Controllers/SearchViewController/SearchViewController.swift @@ -26,6 +26,9 @@ public class SearchViewController: UIViewController, AdyenObserver { internal let viewModel: ViewModel internal let emptyView: SearchResultsEmptyView + /// Delegate to handle different viewController events. + public weak var delegate: ViewControllerDelegate? + public lazy var resultsListViewController = ListViewController(style: viewModel.style) /// Initializes the search view controller. @@ -71,6 +74,8 @@ public class SearchViewController: UIViewController, AdyenObserver { view.addSubview(loadingView) + delegate?.viewDidLoad(viewController: self) + emptyView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(dismissKeyboardTapped))) emptyView.translatesAutoresizingMaskIntoConstraints = false view.addSubview(emptyView) @@ -101,6 +106,8 @@ public class SearchViewController: UIViewController, AdyenObserver { override public func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) + delegate?.viewWillAppear(viewController: self) + if viewModel.shouldFocusSearchBarOnAppearance { DispatchQueue.main.async { // Fix animation glitch on iOS 17 self.searchBar.becomeFirstResponder() @@ -108,6 +115,11 @@ public class SearchViewController: UIViewController, AdyenObserver { } } + override open func viewDidAppear(_ animated: Bool) { + super.viewDidAppear(animated) + delegate?.viewDidAppear(viewController: self) + } + private func setupConstraints() { NSLayoutConstraint.activate([ diff --git a/AdyenCard/Components/Card/CardComponentExtensions.swift b/AdyenCard/Components/Card/CardComponentExtensions.swift index 546cec01a6..a32f8e1567 100644 --- a/AdyenCard/Components/Card/CardComponentExtensions.swift +++ b/AdyenCard/Components/Card/CardComponentExtensions.swift @@ -72,10 +72,6 @@ extension CardComponent: ViewControllerDelegate { // just cache the public key value fetchCardPublicKey(notifyingDelegateOnFailure: false) } - - public func viewWillAppear(viewController: UIViewController) { - sendTelemetryEvent() - } } extension KCPDetails { diff --git a/AdyenCard/Components/GiftCardComponent/GiftCardComponent+Extensions.swift b/AdyenCard/Components/GiftCardComponent/GiftCardComponent+Extensions.swift index 3a4d475409..09f0d266e7 100644 --- a/AdyenCard/Components/GiftCardComponent/GiftCardComponent+Extensions.swift +++ b/AdyenCard/Components/GiftCardComponent/GiftCardComponent+Extensions.swift @@ -20,11 +20,6 @@ extension GiftCardComponent: ViewControllerDelegate { // just cache the public key value fetchCardPublicKey(notifyingDelegateOnFailure: false) } - - /// :nodoc: - public func viewWillAppear(viewController: UIViewController) { - sendTelemetryEvent() - } } extension GiftCardComponent { diff --git a/AdyenCard/Components/Stored Card/StoredCardComponent.swift b/AdyenCard/Components/Stored Card/StoredCardComponent.swift index 2774f0ffe5..19c39075ad 100644 --- a/AdyenCard/Components/Stored Card/StoredCardComponent.swift +++ b/AdyenCard/Components/Stored Card/StoredCardComponent.swift @@ -42,7 +42,7 @@ internal final class StoredCardComponent: PaymentComponent, PaymentAware, Presen flavor: _isDropIn ? .dropin : .components, context: context.apiContext ) - sendTelemetryEvent() + fetchCheckoutAttemptId() let manager = StoredCardAlertManager(paymentMethod: storedCardPaymentMethod, context: context, diff --git a/AdyenCashAppPay/CashAppPayComponent.swift b/AdyenCashAppPay/CashAppPayComponent.swift index 9b17fa5d58..960a827a2c 100644 --- a/AdyenCashAppPay/CashAppPayComponent.swift +++ b/AdyenCashAppPay/CashAppPayComponent.swift @@ -253,9 +253,4 @@ extension CashAppPayComponent: TrackableComponent {} @available(iOS 13.0, *) @_spi(AdyenInternal) -extension CashAppPayComponent: ViewControllerDelegate { - - public func viewWillAppear(viewController: UIViewController) { - sendTelemetryEvent() - } -} +extension CashAppPayComponent: ViewControllerDelegate {} diff --git a/AdyenComponents/ACH Direct Debit/ACHDirectDebitComponent.swift b/AdyenComponents/ACH Direct Debit/ACHDirectDebitComponent.swift index 2ae274f025..2350283b00 100644 --- a/AdyenComponents/ACH Direct Debit/ACHDirectDebitComponent.swift +++ b/AdyenComponents/ACH Direct Debit/ACHDirectDebitComponent.swift @@ -291,11 +291,6 @@ extension ACHDirectDebitComponent: ViewControllerDelegate { // just cache the public key value fetchCardPublicKey(notifyingDelegateOnFailure: false) } - - /// :nodoc: - public func viewWillAppear(viewController: UIViewController) { - sendTelemetryEvent() - } } /// Describes any configuration for the ACH Direct Debit component. diff --git a/AdyenComponents/Apple Pay/ApplePayComponent.swift b/AdyenComponents/Apple Pay/ApplePayComponent.swift index d583f9ee37..875bb4e2d0 100644 --- a/AdyenComponents/Apple Pay/ApplePayComponent.swift +++ b/AdyenComponents/Apple Pay/ApplePayComponent.swift @@ -130,12 +130,4 @@ extension ApplePayComponent { extension ApplePayComponent: TrackableComponent {} @_spi(AdyenInternal) -extension ApplePayComponent: ViewControllerDelegate { - public func viewDidLoad(viewController: UIViewController) { /* Empty implementation */ } - - public func viewDidAppear(viewController: UIViewController) { /* Empty implementation */ } - - public func viewWillAppear(viewController: UIViewController) { - sendTelemetryEvent() - } -} +extension ApplePayComponent: ViewControllerDelegate {} diff --git a/AdyenComponents/BACS Direct Debit/BACSDirectDebitComponent.swift b/AdyenComponents/BACS Direct Debit/BACSDirectDebitComponent.swift index 6ebaccbf5f..a92433719a 100644 --- a/AdyenComponents/BACS Direct Debit/BACSDirectDebitComponent.swift +++ b/AdyenComponents/BACS Direct Debit/BACSDirectDebitComponent.swift @@ -70,8 +70,7 @@ public final class BACSDirectDebitComponent: PaymentComponent, PaymentAware, Pre style: configuration.style) let tracker = BACSDirectDebitComponentTracker(paymentMethod: bacsPaymentMethod, - apiContext: context.apiContext, - telemetryTracker: context.analyticsProvider, + context: context, isDropIn: _isDropIn) let itemsFactory = BACSItemsFactory(styleProvider: configuration.style, localizationParameters: configuration.localizationParameters, diff --git a/AdyenComponents/BACS Direct Debit/Scenes/Input/BACSInputPresenter.swift b/AdyenComponents/BACS Direct Debit/Scenes/Input/BACSInputPresenter.swift index f15425faf1..08e0cead3e 100644 --- a/AdyenComponents/BACS Direct Debit/Scenes/Input/BACSInputPresenter.swift +++ b/AdyenComponents/BACS Direct Debit/Scenes/Input/BACSInputPresenter.swift @@ -56,7 +56,7 @@ internal class BACSInputPresenter: BACSInputPresenterProtocol { // MARK: - BACSInputPresenterProtocol internal func viewDidLoad() { - tracker.sendTelemetryEvent() + tracker.fetchCheckoutAttemptId() createItems() setupView() } diff --git a/AdyenComponents/BACS Direct Debit/Trackers/BACSDirectDebitComponentTracker.swift b/AdyenComponents/BACS Direct Debit/Trackers/BACSDirectDebitComponentTracker.swift index e9af945b1b..e348f18474 100644 --- a/AdyenComponents/BACS Direct Debit/Trackers/BACSDirectDebitComponentTracker.swift +++ b/AdyenComponents/BACS Direct Debit/Trackers/BACSDirectDebitComponentTracker.swift @@ -8,7 +8,7 @@ import Foundation internal protocol BACSDirectDebitComponentTrackerProtocol: AnyObject { - func sendTelemetryEvent() + func fetchCheckoutAttemptId() } internal class BACSDirectDebitComponentTracker: BACSDirectDebitComponentTrackerProtocol { @@ -16,27 +16,27 @@ internal class BACSDirectDebitComponentTracker: BACSDirectDebitComponentTrackerP // MARK: - Properties private let paymentMethod: BACSDirectDebitPaymentMethod - private let apiContext: APIContext - private let telemetryTracker: TelemetryTrackerProtocol + private let context: AdyenContext private let isDropIn: Bool // MARK: - Initializers internal init(paymentMethod: BACSDirectDebitPaymentMethod, - apiContext: APIContext, - telemetryTracker: TelemetryTrackerProtocol, + context: AdyenContext, isDropIn: Bool) { self.paymentMethod = paymentMethod - self.apiContext = apiContext - self.telemetryTracker = telemetryTracker + self.context = context self.isDropIn = isDropIn } // MARK: - BACSDirectDebitComponentTrackerProtocol - internal func sendTelemetryEvent() { + internal func fetchCheckoutAttemptId() { let flavor: TelemetryFlavor = isDropIn ? .dropInComponent : .components(type: paymentMethod.type) - telemetryTracker.sendTelemetryEvent(flavor: flavor) + let amount = context.payment?.amount + let additionalFields = AdditionalAnalyticsFields(amount: amount, sessionId: AdyenAnalytics.sessionId) + context.analyticsProvider.fetchCheckoutAttemptId(with: flavor, + additionalFields: additionalFields) } } diff --git a/AdyenComponents/BLIK/BLIKComponent.swift b/AdyenComponents/BLIK/BLIKComponent.swift index c943415638..b6f954db2f 100644 --- a/AdyenComponents/BLIK/BLIKComponent.swift +++ b/AdyenComponents/BLIK/BLIKComponent.swift @@ -120,10 +120,4 @@ public final class BLIKComponent: PaymentComponent, PresentableComponent, Paymen extension BLIKComponent: TrackableComponent {} @_spi(AdyenInternal) -extension BLIKComponent: ViewControllerDelegate { - // MARK: - ViewControllerDelegate - - public func viewWillAppear(viewController: UIViewController) { - sendTelemetryEvent() - } -} +extension BLIKComponent: ViewControllerDelegate {} diff --git a/AdyenComponents/Boleto/BoletoComponent.swift b/AdyenComponents/Boleto/BoletoComponent.swift index 0377cb351e..abe53ce21c 100644 --- a/AdyenComponents/Boleto/BoletoComponent.swift +++ b/AdyenComponents/Boleto/BoletoComponent.swift @@ -188,7 +188,7 @@ extension BoletoComponent: ViewControllerDelegate { public func viewDidAppear(viewController: UIViewController) {} public func viewWillAppear(viewController: UIViewController) { - sendTelemetryEvent() + fetchCheckoutAttemptId() prefillFields(for: formComponent) } } diff --git a/AdyenComponents/Issuer List/IssuerListComponent.swift b/AdyenComponents/Issuer List/IssuerListComponent.swift index 1392c4eb0c..b7ac725e93 100644 --- a/AdyenComponents/Issuer List/IssuerListComponent.swift +++ b/AdyenComponents/Issuer List/IssuerListComponent.swift @@ -64,12 +64,15 @@ public final class IssuerListComponent: PaymentComponent, PaymentAware, Presenta handler(self.listItems(for: searchText)) } - return SearchViewController( + let searchViewController = SearchViewController( viewModel: viewModel, emptyView: IssuerListEmptyView( localizationParameters: configuration.localizationParameters ) ) + searchViewController.delegate = self + + return searchViewController }() public func stopLoading() { @@ -129,12 +132,7 @@ public final class IssuerListComponent: PaymentComponent, PaymentAware, Presenta } @_spi(AdyenInternal) -extension IssuerListComponent: ViewControllerDelegate { - - public func viewWillAppear(viewController: UIViewController) { - sendTelemetryEvent() - } -} +extension IssuerListComponent: ViewControllerDelegate {} @_spi(AdyenInternal) extension IssuerListComponent: TrackableComponent {} diff --git a/AdyenComponents/SEPA Direct Debit/SEPADirectDebitComponent.swift b/AdyenComponents/SEPA Direct Debit/SEPADirectDebitComponent.swift index 7a6b3ffff6..23f77c95f5 100644 --- a/AdyenComponents/SEPA Direct Debit/SEPADirectDebitComponent.swift +++ b/AdyenComponents/SEPA Direct Debit/SEPADirectDebitComponent.swift @@ -140,9 +140,4 @@ public final class SEPADirectDebitComponent: PaymentComponent, PaymentAware, Pre extension SEPADirectDebitComponent: TrackableComponent {} @_spi(AdyenInternal) -extension SEPADirectDebitComponent: ViewControllerDelegate { - - public func viewWillAppear(viewController: UIViewController) { - sendTelemetryEvent() - } -} +extension SEPADirectDebitComponent: ViewControllerDelegate {} diff --git a/AdyenDropIn/Components/PaymentMethodListComponent.swift b/AdyenDropIn/Components/PaymentMethodListComponent.swift index 81a803b50b..1e5c5a7800 100644 --- a/AdyenDropIn/Components/PaymentMethodListComponent.swift +++ b/AdyenDropIn/Components/PaymentMethodListComponent.swift @@ -163,12 +163,6 @@ internal final class PaymentMethodListComponent: ComponentLoader, PresentableCom internal func stopLoading() { listViewController.stopLoading() } - - // MARK: - Private - - private func sendTelemetryEvent() { - context.analyticsProvider.sendTelemetryEvent(flavor: .dropIn(paymentMethods: [])) - } } extension PaymentMethodListComponent: ViewControllerDelegate { diff --git a/AdyenDropIn/Components/PreselectedPaymentMethodComponent.swift b/AdyenDropIn/Components/PreselectedPaymentMethodComponent.swift index 5f39ca147d..289633bce0 100644 --- a/AdyenDropIn/Components/PreselectedPaymentMethodComponent.swift +++ b/AdyenDropIn/Components/PreselectedPaymentMethodComponent.swift @@ -20,9 +20,10 @@ internal protocol PreselectedPaymentMethodComponentDelegate: AnyObject { /// A component that presents a single preselected payment method and option to open more payment methods. internal final class PreselectedPaymentMethodComponent: ComponentLoader, - PresentableComponent, - Localizable, - Cancellable { + PresentableComponent, + PaymentMethodAware, + Localizable, + Cancellable { private let title: String private let defaultComponent: PaymentComponent @@ -169,3 +170,6 @@ internal final class PreselectedPaymentMethodComponent: ComponentLoader, } extension PreselectedPaymentMethodComponent: ViewControllerDelegate {} + +@_spi(AdyenInternal) +extension PreselectedPaymentMethodComponent: TrackableComponent {} diff --git a/AdyenDropIn/DropInComponentExtensions.swift b/AdyenDropIn/DropInComponentExtensions.swift index cd4f64cbd7..58f9f066f7 100644 --- a/AdyenDropIn/DropInComponentExtensions.swift +++ b/AdyenDropIn/DropInComponentExtensions.swift @@ -22,7 +22,10 @@ extension DropInComponent: PaymentMethodListComponentDelegate { internal func didLoad(_ paymentMethodListComponent: PaymentMethodListComponent) { let paymentMethodTypes = paymentMethods.regular.map(\.type.rawValue) - context.analyticsProvider.sendTelemetryEvent(flavor: .dropIn(paymentMethods: paymentMethodTypes)) + let flavor = TelemetryFlavor.dropIn(paymentMethods: paymentMethodTypes) + let amount = context.payment?.amount + let additionalFields = AdditionalAnalyticsFields(amount: amount, sessionId: AdyenAnalytics.sessionId) + context.analyticsProvider.fetchCheckoutAttemptId(with: flavor, additionalFields: additionalFields) } internal func didSelect(_ component: PaymentComponent, @@ -51,8 +54,6 @@ extension DropInComponent: PaymentComponentDelegate { public func didSubmit(_ data: PaymentComponentData, from component: PaymentComponent) { paymentInProgress = true - /// try to fetch the fetchCheckoutAttemptId to get cached if its not already cached - component.context.analyticsProvider.fetchAndCacheCheckoutAttemptIdIfNeeded() let updatedData = data.replacing(checkoutAttemptId: component.context.analyticsProvider.checkoutAttemptId) diff --git a/AdyenSession/AdyenSession.swift b/AdyenSession/AdyenSession.swift index 0c4c0b420a..6915dbfd8c 100644 --- a/AdyenSession/AdyenSession.swift +++ b/AdyenSession/AdyenSession.swift @@ -119,6 +119,8 @@ public final class AdyenSession { sessionContext: sessionContext) session.delegate = delegate session.presentationDelegate = presentationDelegate + // Unfortunately needed by telemetry and this is the only way atm. + AdyenAnalytics.sessionId = sessionContext.identifier completion(.success(session)) case let .failure(error): completion(.failure(error)) diff --git a/Tests/Adyen Tests/Analytics/AnalyticsProviderMock.swift b/Tests/Adyen Tests/Analytics/AnalyticsProviderMock.swift index 3e8a4664d3..2e34223395 100644 --- a/Tests/Adyen Tests/Analytics/AnalyticsProviderMock.swift +++ b/Tests/Adyen Tests/Analytics/AnalyticsProviderMock.swift @@ -11,29 +11,19 @@ import Foundation class AnalyticsProviderMock: AnalyticsProviderProtocol { - var additionalFields: (() -> AdditionalAnalyticsFields)? - var checkoutAttemptId: String? { underlyingCheckoutAttemptId } + var checkoutAttemptId: String? // MARK: - checkoutAttemptId - - func fetchCheckoutAttemptId(completion: @escaping (String?) -> Void) { - completion(underlyingCheckoutAttemptId) - } - func fetchAndCacheCheckoutAttemptIdIfNeeded() { - fetchCheckoutAttemptId(completion: { _ in }) + func fetchCheckoutAttemptId(with flavor: TelemetryFlavor, additionalFields: AdditionalAnalyticsFields?) { + initialTelemetryEventCallsCount += 1 + checkoutAttemptId = _checkoutAttemptId } - var underlyingCheckoutAttemptId: String? - - // MARK: - sendTelemetryEvent - - var sendTelemetryEventCallsCount = 0 - var sendTelemetryEventCalled: Bool { - sendTelemetryEventCallsCount > 0 - } + var _checkoutAttemptId: String? - func sendTelemetryEvent(flavor: TelemetryFlavor) { - sendTelemetryEventCallsCount += 1 + var initialTelemetryEventCallsCount = 0 + var initialTelemetryEventCalled: Bool { + initialTelemetryEventCallsCount > 0 } } diff --git a/Tests/Adyen Tests/Analytics/AnalyticsProviderTests.swift b/Tests/Adyen Tests/Analytics/AnalyticsProviderTests.swift index 7d8465ac3e..88831d8f6d 100644 --- a/Tests/Adyen Tests/Analytics/AnalyticsProviderTests.swift +++ b/Tests/Adyen Tests/Analytics/AnalyticsProviderTests.swift @@ -41,25 +41,25 @@ class AnalyticsProviderTests: XCTestCase { // Given var analyticsConfiguration = AnalyticsConfiguration() analyticsConfiguration.isEnabled = true - sut = AnalyticsProvider(apiClient: apiClient, configuration: analyticsConfiguration) - let expectedCheckoutAttemptId = checkoutAttemptIdMockValue let checkoutAttemptIdResponse = CheckoutAttemptIdResponse(identifier: expectedCheckoutAttemptId) let checkoutAttemptIdResult: Result = .success(checkoutAttemptIdResponse) apiClient.mockedResults = [checkoutAttemptIdResult] - + let fetchCheckoutAttemptIdExpection = expectation(description: "checkoutAttemptId completion") + + sut = AnalyticsProvider(apiClient: apiClient, configuration: analyticsConfiguration) // When - sut.fetchCheckoutAttemptId { receivedCheckoutAttemptId in - - // Then - XCTAssertNotNil(receivedCheckoutAttemptId, "The checkoutAttemptId is nil.") - XCTAssertEqual(expectedCheckoutAttemptId, receivedCheckoutAttemptId, "The received checkoutAttemptId is not the expected one.") - fetchCheckoutAttemptIdExpection.fulfill() - } - + sut.fetchCheckoutAttemptId(with: .components(type: .achDirectDebit), additionalFields: nil) + fetchCheckoutAttemptIdExpection.fulfill() + + wait(for: .milliseconds(200)) + + XCTAssertNotNil(sut.checkoutAttemptId, "The checkoutAttemptId is nil.") + XCTAssertEqual(expectedCheckoutAttemptId, sut.checkoutAttemptId, "The received checkoutAttemptId is not the expected one.") + waitForExpectations(timeout: 1) } @@ -69,40 +69,36 @@ class AnalyticsProviderTests: XCTestCase { analyticsConfiguration.isEnabled = false sut = AnalyticsProvider(apiClient: apiClient, configuration: analyticsConfiguration) - let fetchCheckoutAttemptIdExpection = expectation(description: "checkoutAttemptId completion") - // When - sut.fetchCheckoutAttemptId { receivedCheckoutAttemptId in - XCTAssertEqual(self.sut.checkoutAttemptId, "do-not-track") - fetchCheckoutAttemptIdExpection.fulfill() - } - - waitForExpectations(timeout: 1) + sut.fetchCheckoutAttemptId(with: .components(type: .affirm), additionalFields: nil) + XCTAssertEqual(sut.checkoutAttemptId, "do-not-track") } func testFetchCheckoutAttemptIdWhenRequestSucceedShouldCallCompletionWithNonNilValue() throws { // Given var analyticsConfiguration = AnalyticsConfiguration() analyticsConfiguration.isEnabled = true - sut = AnalyticsProvider(apiClient: apiClient, configuration: analyticsConfiguration) let expectedCheckoutAttemptId = checkoutAttemptIdMockValue let checkoutAttemptIdResponse = CheckoutAttemptIdResponse(identifier: expectedCheckoutAttemptId) let checkoutAttemptIdResult: Result = .success(checkoutAttemptIdResponse) apiClient.mockedResults = [checkoutAttemptIdResult] - + let fetchCheckoutAttemptIdExpection = expectation(description: "checkoutAttemptId completion") + + sut = AnalyticsProvider(apiClient: apiClient, configuration: analyticsConfiguration) // When - sut.fetchCheckoutAttemptId { receivedCheckoutAttemptId in - - // Then - XCTAssertNotNil(receivedCheckoutAttemptId, "The checkoutAttemptId is nil.") - XCTAssertEqual(expectedCheckoutAttemptId, receivedCheckoutAttemptId, "The received checkoutAttemptId is not the expected one.") - fetchCheckoutAttemptIdExpection.fulfill() - } - + sut.fetchCheckoutAttemptId(with: .components(type: .achDirectDebit), additionalFields: nil) + fetchCheckoutAttemptIdExpection.fulfill() + + wait(for: .milliseconds(200)) + + // Then + XCTAssertNotNil(sut.checkoutAttemptId, "The checkoutAttemptId is nil.") + XCTAssertEqual(expectedCheckoutAttemptId, sut.checkoutAttemptId, "The received checkoutAttemptId is not the expected one.") + waitForExpectations(timeout: 1) } @@ -110,43 +106,44 @@ class AnalyticsProviderTests: XCTestCase { // Given var analyticsConfiguration = AnalyticsConfiguration() analyticsConfiguration.isEnabled = true - sut = AnalyticsProvider(apiClient: apiClient, configuration: analyticsConfiguration) let error = NSError(domain: "", code: 500, userInfo: [NSLocalizedDescriptionKey: "Internal Server Error"]) let checkoutAttemptIdResult: Result = .failure(error) apiClient.mockedResults = [checkoutAttemptIdResult] - - let fetchCheckoutAttemptIdExpection = expectation(description: "checkoutAttemptId completion") + + sut = AnalyticsProvider(apiClient: apiClient, configuration: analyticsConfiguration) // When - sut.fetchCheckoutAttemptId { receivedCheckoutAttemptId in - - // Then - XCTAssertNil(receivedCheckoutAttemptId, "The checkoutAttemptId is not nil.") - fetchCheckoutAttemptIdExpection.fulfill() - } - - waitForExpectations(timeout: 1) + sut.fetchCheckoutAttemptId(with: .dropInComponent, additionalFields: nil) + // Then + XCTAssertNil(sut.checkoutAttemptId, "The checkoutAttemptId is not nil.") } func testFetchCheckoutAttemptIdWhenAnalyticsIsEnabledShouldSetCheckoutAttemptIdProperty() throws { // Given var analyticsConfiguration = AnalyticsConfiguration() analyticsConfiguration.isEnabled = true - sut = AnalyticsProvider(apiClient: apiClient, configuration: analyticsConfiguration) let expectedCheckoutAttemptId = checkoutAttemptIdMockValue let checkoutAttemptIdResponse = CheckoutAttemptIdResponse(identifier: expectedCheckoutAttemptId) let checkoutAttemptIdResult: Result = .success(checkoutAttemptIdResponse) apiClient.mockedResults = [checkoutAttemptIdResult] + + let fetchCheckoutAttemptIdExpection = expectation(description: "checkoutAttemptId completion") + + sut = AnalyticsProvider(apiClient: apiClient, configuration: analyticsConfiguration) // When - sut.fetchCheckoutAttemptId { _ in - - // Then - XCTAssertEqual(expectedCheckoutAttemptId, self.sut.checkoutAttemptId) - } + sut.fetchCheckoutAttemptId(with: .components(type: .atome), additionalFields: nil) + fetchCheckoutAttemptIdExpection.fulfill() + + wait(for: .milliseconds(200)) + + // Then + XCTAssertEqual(expectedCheckoutAttemptId, sut.checkoutAttemptId) + + waitForExpectations(timeout: 1) } func testFetchCheckoutAttemptIdWhenAnalyticsIsDisabledShouldNotSetCheckoutAttemptIdProperty() throws { @@ -160,11 +157,9 @@ class AnalyticsProviderTests: XCTestCase { apiClient.mockedResults = [checkoutAttemptIdResult] // When - sut.fetchCheckoutAttemptId { _ in - - // Then - XCTAssertEqual(self.sut.checkoutAttemptId, "do-not-track") - } + sut.fetchCheckoutAttemptId(with: .components(type: .affirm), additionalFields: nil) + // Then + XCTAssertEqual(sut.checkoutAttemptId, "do-not-track") } func testAdditionalFields() throws { @@ -178,13 +173,11 @@ class AnalyticsProviderTests: XCTestCase { let apiClient = APIClientMock() apiClient.mockedResults = [ - .success(CheckoutAttemptIdResponse(identifier: checkoutAttemptId)), - .success(TelemetryResponse()) + .success(CheckoutAttemptIdResponse(identifier: checkoutAttemptId)) ] apiClient.onExecute = { request in - if let telemetryRequest = request as? TelemetryRequest { - XCTAssertEqual(telemetryRequest.amount, amount) - XCTAssertEqual(telemetryRequest.checkoutAttemptId, checkoutAttemptId) + if let checkoutAttemptIdRequest = request as? CheckoutAttemptIdRequest { + XCTAssertEqual(checkoutAttemptIdRequest.amount, amount) telemetryExpectation.fulfill() } } @@ -194,13 +187,9 @@ class AnalyticsProviderTests: XCTestCase { configuration: AnalyticsConfiguration() ) - analyticsProvider.additionalFields = { - .init(amount: amount) - } - // When - - analyticsProvider.sendTelemetryEvent(flavor: .components(type: .achDirectDebit)) + let additionalFields = AdditionalAnalyticsFields(amount: amount) + analyticsProvider.fetchCheckoutAttemptId(with: .components(type: .achDirectDebit), additionalFields: additionalFields) wait(for: [telemetryExpectation], timeout: 1) } diff --git a/Tests/Adyen Tests/Analytics/TelemetryTrackerTests.swift b/Tests/Adyen Tests/Analytics/TelemetryTrackerTests.swift index 12581c44a2..7db22e2a59 100644 --- a/Tests/Adyen Tests/Analytics/TelemetryTrackerTests.swift +++ b/Tests/Adyen Tests/Analytics/TelemetryTrackerTests.swift @@ -13,11 +13,14 @@ import XCTest class TelemetryTrackerTests: XCTestCase { var apiClient: APIClientMock! - var sut: TelemetryTrackerProtocol! + var sut: InitialTelemetryProtocol! override func setUpWithError() throws { try super.setUpWithError() apiClient = APIClientMock() + let checkoutAttemptIdResponse = CheckoutAttemptIdResponse(identifier: "checkoutAttempId1") + let checkoutAttemptIdResult: Result = .success(checkoutAttemptIdResponse) + apiClient.mockedResults = [checkoutAttemptIdResult] sut = AnalyticsProvider(apiClient: apiClient, configuration: .init()) } @@ -26,6 +29,10 @@ class TelemetryTrackerTests: XCTestCase { sut = nil try super.tearDownWithError() } + + private func sendInitialTelemetry(flavor: TelemetryFlavor = .components(type: .achDirectDebit)) { + sut.fetchCheckoutAttemptId(with: flavor, additionalFields: nil) + } func testSendTelemetryEventGivenAnalyticsIsDisabledAndTelemetryIsEnabledShouldNotSendAnyRequest() throws { // Given @@ -37,7 +44,7 @@ class TelemetryTrackerTests: XCTestCase { let expectedRequestCalls = 0 // When - sut.sendTelemetryEvent(flavor: .components(type: .affirm)) + sendInitialTelemetry() // Then XCTAssertEqual(expectedRequestCalls, apiClient.counter, "One or more telemetry requests were sent.") @@ -52,7 +59,7 @@ class TelemetryTrackerTests: XCTestCase { let expectedRequestCalls = 0 // When - sut.sendTelemetryEvent(flavor: .components(type: .affirm)) + sendInitialTelemetry() // Then XCTAssertEqual(expectedRequestCalls, apiClient.counter, "One or more telemetry requests were sent.") @@ -68,7 +75,7 @@ class TelemetryTrackerTests: XCTestCase { let expectedRequestCalls = 0 // When - sut.sendTelemetryEvent(flavor: flavor) + sendInitialTelemetry(flavor: flavor) // Then XCTAssertEqual(expectedRequestCalls, apiClient.counter, "One or more telemetry requests were sent.") @@ -81,14 +88,13 @@ class TelemetryTrackerTests: XCTestCase { sut = AnalyticsProvider(apiClient: apiClient, configuration: analyticsConfiguration) let flavor: TelemetryFlavor = .components(type: .affirm) - let expectedRequestCalls = 2 + let expectedRequestCalls = 1 let checkoutAttemptIdResult: Result = .success(checkoutAttemptIdResponse) - let telemetryResult: Result = .success(telemetryResponse) - apiClient.mockedResults = [checkoutAttemptIdResult, telemetryResult] + apiClient.mockedResults = [checkoutAttemptIdResult] // When - sut.sendTelemetryEvent(flavor: flavor) + sendInitialTelemetry(flavor: flavor) // Then wait(for: .milliseconds(1)) @@ -102,14 +108,13 @@ class TelemetryTrackerTests: XCTestCase { sut = AnalyticsProvider(apiClient: apiClient, configuration: analyticsConfiguration) let flavor: TelemetryFlavor = .dropIn(paymentMethods: ["scheme", "paypal", "affirm"]) - let expectedRequestCalls = 2 + let expectedRequestCalls = 1 let checkoutAttemptIdResult: Result = .success(checkoutAttemptIdResponse) - let telemetryResult: Result = .success(telemetryResponse) - apiClient.mockedResults = [checkoutAttemptIdResult, telemetryResult] + apiClient.mockedResults = [checkoutAttemptIdResult] // When - sut.sendTelemetryEvent(flavor: flavor) + sendInitialTelemetry(flavor: flavor) // Then wait(for: .milliseconds(1)) diff --git a/Tests/Adyen Tests/Core/AdyenContextTests.swift b/Tests/Adyen Tests/Core/AdyenContextTests.swift index 905bc1852b..7284940398 100644 --- a/Tests/Adyen Tests/Core/AdyenContextTests.swift +++ b/Tests/Adyen Tests/Core/AdyenContextTests.swift @@ -21,10 +21,10 @@ class AdyenContextTests: XCTestCase { payment: .init(amount: oneEUR, countryCode: "NL") ) - XCTAssertEqual(context.analyticsProvider.additionalFields?().amount, oneEUR) +// XCTAssertEqual(context.analyticsProvider.additionalFields?().amount, oneEUR) context.update(payment: Payment(amount: twoEUR, countryCode: "NL")) - XCTAssertEqual(context.analyticsProvider.additionalFields?().amount, twoEUR) +// XCTAssertEqual(context.analyticsProvider.additionalFields?().amount, twoEUR) } } diff --git a/Tests/Card Tests/BCMCComponentTests.swift b/Tests/Card Tests/BCMCComponentTests.swift index 9f0f3baffb..f9f3ad9ae1 100644 --- a/Tests/Card Tests/BCMCComponentTests.swift +++ b/Tests/Card Tests/BCMCComponentTests.swift @@ -532,7 +532,7 @@ class BCMCComponentTests: XCTestCase { sut.cardViewController.viewWillAppear(true) // Then - XCTAssertEqual(analyticsProviderMock.sendTelemetryEventCallsCount, 1) + XCTAssertEqual(analyticsProviderMock.initialTelemetryEventCallsCount, 1) } func fillCard(on view: UIView, with card: Card, simulateKeyStrokes: Bool = false) { diff --git a/Tests/Card Tests/CardComponentTests.swift b/Tests/Card Tests/CardComponentTests.swift index cedaf842b0..2ea5a43daa 100644 --- a/Tests/Card Tests/CardComponentTests.swift +++ b/Tests/Card Tests/CardComponentTests.swift @@ -1865,7 +1865,7 @@ class CardComponentTests: XCTestCase { sut.cardViewController.viewWillAppear(false) // Then - XCTAssertEqual(analyticsProviderMock.sendTelemetryEventCallsCount, 1) + XCTAssertEqual(analyticsProviderMock.initialTelemetryEventCallsCount, 1) } diff --git a/Tests/Card Tests/StoredCardComponentTests.swift b/Tests/Card Tests/StoredCardComponentTests.swift index 00c50f2c3f..c80506c58a 100644 --- a/Tests/Card Tests/StoredCardComponentTests.swift +++ b/Tests/Card Tests/StoredCardComponentTests.swift @@ -266,7 +266,7 @@ class StoredCardComponentTests: XCTestCase { sut.viewController.viewDidLoad() // Then - XCTAssertEqual(analyticsProviderMock.sendTelemetryEventCallsCount, 1) + XCTAssertEqual(analyticsProviderMock.initialTelemetryEventCallsCount, 1) } // MARK: - Private diff --git a/Tests/Card Tests/StoredPaymentMethodComponentTests.swift b/Tests/Card Tests/StoredPaymentMethodComponentTests.swift index b43cde5229..64af10543c 100644 --- a/Tests/Card Tests/StoredPaymentMethodComponentTests.swift +++ b/Tests/Card Tests/StoredPaymentMethodComponentTests.swift @@ -147,6 +147,6 @@ class StoredPaymentMethodComponentTests: XCTestCase { sut.viewController.viewDidLoad() // Then - XCTAssertEqual(analyticsProviderMock.sendTelemetryEventCallsCount, 1) + XCTAssertEqual(analyticsProviderMock.initialTelemetryEventCallsCount, 1) } } diff --git a/Tests/Components Tests/ACH Direct Debit/ACHDirectDebitComponentTests.swift b/Tests/Components Tests/ACH Direct Debit/ACHDirectDebitComponentTests.swift index b27f7181cf..47afa73e5b 100644 --- a/Tests/Components Tests/ACH Direct Debit/ACHDirectDebitComponentTests.swift +++ b/Tests/Components Tests/ACH Direct Debit/ACHDirectDebitComponentTests.swift @@ -304,6 +304,6 @@ class ACHDirectDebitComponentTests: XCTestCase { sut.viewWillAppear(viewController: sut.viewController) // Then - XCTAssertEqual(analyticsProviderMock.sendTelemetryEventCallsCount, 1) + XCTAssertEqual(analyticsProviderMock.initialTelemetryEventCallsCount, 1) } } diff --git a/Tests/Components Tests/Affirm/AffirmComponentTests.swift b/Tests/Components Tests/Affirm/AffirmComponentTests.swift index afa5c98671..606db936f1 100644 --- a/Tests/Components Tests/Affirm/AffirmComponentTests.swift +++ b/Tests/Components Tests/Affirm/AffirmComponentTests.swift @@ -318,7 +318,7 @@ class AffirmComponentTests: XCTestCase { sut.viewWillAppear(viewController: mockViewController) // Then - XCTAssertEqual(analyticsProviderMock.sendTelemetryEventCallsCount, 1) + XCTAssertEqual(analyticsProviderMock.initialTelemetryEventCallsCount, 1) } // MARK: - Private diff --git a/Tests/Components Tests/Apple Pay/ApplePayComponentTests.swift b/Tests/Components Tests/Apple Pay/ApplePayComponentTests.swift index 995e07768a..5f963a44ee 100644 --- a/Tests/Components Tests/Apple Pay/ApplePayComponentTests.swift +++ b/Tests/Components Tests/Apple Pay/ApplePayComponentTests.swift @@ -397,7 +397,7 @@ class ApplePayComponentTest: XCTestCase { sut.viewWillAppear(viewController: mockViewController) // Then - XCTAssertEqual(analyticsProviderMock.sendTelemetryEventCallsCount, 1) + XCTAssertEqual(analyticsProviderMock.initialTelemetryEventCallsCount, 1) } private func getRandomContactFieldSet() -> Set { diff --git a/Tests/Components Tests/Apple Pay/PreApplePayComponentTests.swift b/Tests/Components Tests/Apple Pay/PreApplePayComponentTests.swift index 0f64fcbb76..e60865e9ae 100644 --- a/Tests/Components Tests/Apple Pay/PreApplePayComponentTests.swift +++ b/Tests/Components Tests/Apple Pay/PreApplePayComponentTests.swift @@ -120,7 +120,7 @@ class PreApplePayComponentTests: XCTestCase { func testSubmitWithAnalyticsEnabledShouldSetCheckoutAttemptIdInPaymentComponentData() throws { // Given let expectedCheckoutAttemptId = "d06da733-ec41-4739-a532-5e8deab1262e16547639430681e1b021221a98c4bf13f7366b30fec4b376cc8450067ff98998682dd24fc9bda" - analyticsProviderMock.underlyingCheckoutAttemptId = expectedCheckoutAttemptId + analyticsProviderMock._checkoutAttemptId = expectedCheckoutAttemptId let paymentMethodDetails = ApplePayDetails(paymentMethod: paymentMethod, token: "test_token", network: "test_network", @@ -143,7 +143,7 @@ class PreApplePayComponentTests: XCTestCase { func testSubmitWithAnalyticsDisabledShouldNotSetCheckoutAttemptIdInPaymentComponentData() throws { // Given - analyticsProviderMock.underlyingCheckoutAttemptId = nil + analyticsProviderMock._checkoutAttemptId = nil let paymentMethodDetails = ApplePayDetails(paymentMethod: paymentMethod, token: "test_token", network: "test_network", diff --git a/Tests/Components Tests/Atome/AtomeComponentTests.swift b/Tests/Components Tests/Atome/AtomeComponentTests.swift index cacbdf1df6..6876a9607c 100644 --- a/Tests/Components Tests/Atome/AtomeComponentTests.swift +++ b/Tests/Components Tests/Atome/AtomeComponentTests.swift @@ -91,7 +91,7 @@ class AtomeComponentTests: XCTestCase { sut.viewWillAppear(viewController: mockViewController) // Then - XCTAssertEqual(analyticsProviderMock.sendTelemetryEventCallsCount, 1) + XCTAssertEqual(analyticsProviderMock.initialTelemetryEventCallsCount, 1) } } diff --git a/Tests/Components Tests/BACS Direct Debit/Mocks/BACSDirectDebitComponentTrackerProtocolMock.swift b/Tests/Components Tests/BACS Direct Debit/Mocks/BACSDirectDebitComponentTrackerProtocolMock.swift index c52d7845b0..4fb1097c12 100644 --- a/Tests/Components Tests/BACS Direct Debit/Mocks/BACSDirectDebitComponentTrackerProtocolMock.swift +++ b/Tests/Components Tests/BACS Direct Debit/Mocks/BACSDirectDebitComponentTrackerProtocolMock.swift @@ -14,12 +14,9 @@ class BACSDirectDebitComponentTrackerProtocolMock: BACSDirectDebitComponentTrack // MARK: - sendEvent - var sendTelemetryEventCallsCount = 0 - var sendTelemetryEventCalled: Bool { - sendTelemetryEventCallsCount > 0 - } - - func sendTelemetryEvent() { - sendTelemetryEventCallsCount += 1 + var initialTelemetryEventCallsCount = 0 + + func fetchCheckoutAttemptId() { + initialTelemetryEventCallsCount += 1 } } diff --git a/Tests/Components Tests/BACS Direct Debit/Scenes/Input/BACSInputPresenterTests.swift b/Tests/Components Tests/BACS Direct Debit/Scenes/Input/BACSInputPresenterTests.swift index d118ca1dd4..014eb6deed 100644 --- a/Tests/Components Tests/BACS Direct Debit/Scenes/Input/BACSInputPresenterTests.swift +++ b/Tests/Components Tests/BACS Direct Debit/Scenes/Input/BACSInputPresenterTests.swift @@ -64,7 +64,7 @@ class BACSInputPresenterTests: XCTestCase { sut.viewDidLoad() // Then - XCTAssertEqual(tracker.sendTelemetryEventCallsCount, 1) + XCTAssertEqual(tracker.initialTelemetryEventCallsCount, 1) } func testContinuePaymentWhenButtonTappedShouldDisplayValidationOnView() throws { diff --git a/Tests/Components Tests/BACS Direct Debit/Trackers/BACSDirectDebitComponentTrackerTests.swift b/Tests/Components Tests/BACS Direct Debit/Trackers/BACSDirectDebitComponentTrackerTests.swift index ba07d73c35..4b168da402 100644 --- a/Tests/Components Tests/BACS Direct Debit/Trackers/BACSDirectDebitComponentTrackerTests.swift +++ b/Tests/Components Tests/BACS Direct Debit/Trackers/BACSDirectDebitComponentTrackerTests.swift @@ -18,9 +18,9 @@ class BACSDirectDebitComponentTrackerTests: XCTestCase { apiContext = Dummy.apiContext analyticsProvider = AnalyticsProviderMock() + let adyenContext = AdyenContext(apiContext: apiContext, payment: Dummy.payment, analyticsProvider: analyticsProvider) sut = BACSDirectDebitComponentTracker(paymentMethod: paymentMethod, - apiContext: apiContext, - telemetryTracker: analyticsProvider, + context: adyenContext, isDropIn: false) } @@ -33,9 +33,9 @@ class BACSDirectDebitComponentTrackerTests: XCTestCase { func testSendTelemetryEventShouldCallAnalyticsProviderSendTelemetryEvent() throws { // When - sut.sendTelemetryEvent() + sut.fetchCheckoutAttemptId() // Then - XCTAssertEqual(analyticsProvider.sendTelemetryEventCallsCount, 1) + XCTAssertEqual(analyticsProvider.initialTelemetryEventCallsCount, 1) } } diff --git a/Tests/Components Tests/BLIK Component/BLIKComponentTests.swift b/Tests/Components Tests/BLIK Component/BLIKComponentTests.swift index 06288d9655..b2c69222fa 100644 --- a/Tests/Components Tests/BLIK Component/BLIKComponentTests.swift +++ b/Tests/Components Tests/BLIK Component/BLIKComponentTests.swift @@ -85,6 +85,6 @@ class BLIKComponentTests: XCTestCase { sut.viewWillAppear(viewController: sut.viewController) // Then - XCTAssertEqual(analyticsProviderMock.sendTelemetryEventCallsCount, 1) + XCTAssertEqual(analyticsProviderMock.initialTelemetryEventCallsCount, 1) } } diff --git a/Tests/Components Tests/Boleto/BoletoComponentTests.swift b/Tests/Components Tests/Boleto/BoletoComponentTests.swift index 3b70a852d4..c1f730f6b6 100644 --- a/Tests/Components Tests/Boleto/BoletoComponentTests.swift +++ b/Tests/Components Tests/Boleto/BoletoComponentTests.swift @@ -188,6 +188,6 @@ class BoletoComponentTests: XCTestCase { component.viewWillAppear(viewController: component.viewController) // Then - XCTAssertEqual(analyticsProviderMock.sendTelemetryEventCallsCount, 1) + XCTAssertEqual(analyticsProviderMock.initialTelemetryEventCallsCount, 1) } } diff --git a/Tests/Components Tests/Cash App Pay/CashAppPayComponentTests.swift b/Tests/Components Tests/Cash App Pay/CashAppPayComponentTests.swift index f57414afec..b5670f9fd8 100644 --- a/Tests/Components Tests/Cash App Pay/CashAppPayComponentTests.swift +++ b/Tests/Components Tests/Cash App Pay/CashAppPayComponentTests.swift @@ -148,7 +148,7 @@ import XCTest sut.viewWillAppear(viewController: sut.viewController) // Then - XCTAssertEqual(analyticsProviderMock.sendTelemetryEventCallsCount, 1) + XCTAssertEqual(analyticsProviderMock.initialTelemetryEventCallsCount, 1) } func testComponent_ShouldPaymentMethodTypeBeCashAppPay() throws { diff --git a/Tests/Components Tests/Doku/DokuComponentTests.swift b/Tests/Components Tests/Doku/DokuComponentTests.swift index fe52a56508..77fdc59f5e 100644 --- a/Tests/Components Tests/Doku/DokuComponentTests.swift +++ b/Tests/Components Tests/Doku/DokuComponentTests.swift @@ -163,7 +163,7 @@ class DokuComponentTests: XCTestCase { sut.viewWillAppear(viewController: sut.viewController) // Then - XCTAssertEqual(analyticsProviderMock.sendTelemetryEventCallsCount, 1) + XCTAssertEqual(analyticsProviderMock.initialTelemetryEventCallsCount, 1) } // MARK: - Private diff --git a/Tests/Components Tests/Gift Card/GiftCardComponentTests.swift b/Tests/Components Tests/Gift Card/GiftCardComponentTests.swift index d5f368e0f3..d9952a0922 100644 --- a/Tests/Components Tests/Gift Card/GiftCardComponentTests.swift +++ b/Tests/Components Tests/Gift Card/GiftCardComponentTests.swift @@ -575,7 +575,7 @@ class GiftCardComponentTests: XCTestCase { sut.viewWillAppear(viewController: mockViewController) // Then - XCTAssertEqual(analyticsProviderMock.sendTelemetryEventCallsCount, 1) + XCTAssertEqual(analyticsProviderMock.initialTelemetryEventCallsCount, 1) } func testGiftCardHidingSecurityCodeItemView() throws { diff --git a/Tests/Components Tests/Instant Payment/InstantPaymentComponentTests.swift b/Tests/Components Tests/Instant Payment/InstantPaymentComponentTests.swift index 545979b638..153adfa666 100644 --- a/Tests/Components Tests/Instant Payment/InstantPaymentComponentTests.swift +++ b/Tests/Components Tests/Instant Payment/InstantPaymentComponentTests.swift @@ -57,21 +57,6 @@ class InstantPaymentComponentTests: XCTestCase { waitForExpectations(timeout: 2, handler: nil) } - func testInitiatePaymentShouldSendTelemetryEvent() throws { - // Given - let analyticsProviderMock = AnalyticsProviderMock() - let context = Dummy.context(with: analyticsProviderMock) - sut = InstantPaymentComponent(paymentMethod: paymentMethod, - context: context, - paymentData: paymentComponentData) - - // When - sut.initiatePayment() - - // Then - XCTAssertEqual(analyticsProviderMock.sendTelemetryEventCallsCount, 1) - } - // MARK: - Private private var paymentComponentData: PaymentComponentData { diff --git a/Tests/Components Tests/IssuerList/IssuerListComponentTests.swift b/Tests/Components Tests/IssuerList/IssuerListComponentTests.swift index 5d3dbd4241..23b6b56e3c 100644 --- a/Tests/Components Tests/IssuerList/IssuerListComponentTests.swift +++ b/Tests/Components Tests/IssuerList/IssuerListComponentTests.swift @@ -67,6 +67,6 @@ class IssuerListComponentTests: XCTestCase { sut.viewWillAppear(viewController: mockViewController) // Then - XCTAssertEqual(analyticsProviderMock.sendTelemetryEventCallsCount, 1) + XCTAssertEqual(analyticsProviderMock.initialTelemetryEventCallsCount, 1) } } diff --git a/Tests/Components Tests/MB Way/MBWayComponentTests.swift b/Tests/Components Tests/MB Way/MBWayComponentTests.swift index 793a1d7708..07a2c59803 100644 --- a/Tests/Components Tests/MB Way/MBWayComponentTests.swift +++ b/Tests/Components Tests/MB Way/MBWayComponentTests.swift @@ -126,7 +126,7 @@ class MBWayComponentTests: XCTestCase { sut.viewWillAppear(viewController: sut.viewController) // Then - XCTAssertEqual(analyticsProviderMock.sendTelemetryEventCallsCount, 1) + XCTAssertEqual(analyticsProviderMock.initialTelemetryEventCallsCount, 1) } // MARK: - Private diff --git a/Tests/Components Tests/PaymentComponent/PaymentComponentSubjectTests.swift b/Tests/Components Tests/PaymentComponent/PaymentComponentSubjectTests.swift index 5126d8b290..899cb52482 100644 --- a/Tests/Components Tests/PaymentComponent/PaymentComponentSubjectTests.swift +++ b/Tests/Components Tests/PaymentComponent/PaymentComponentSubjectTests.swift @@ -43,7 +43,7 @@ class PaymentComponentSubjectTests: XCTestCase { func testSubmitWithAnalyticsEnabledShouldSetCheckoutAttemptIdInPaymentComponentData() throws { // Given let expectedCheckoutAttemptId = "d06da733-ec41-4739-a532-5e8deab1262e16547639430681e1b021221a98c4bf13f7366b30fec4b376cc8450067ff98998682dd24fc9bda" - analyticsProviderMock.underlyingCheckoutAttemptId = expectedCheckoutAttemptId + analyticsProviderMock._checkoutAttemptId = expectedCheckoutAttemptId let paymentMethodDetails = MBWayDetails(paymentMethod: paymentMethod, telephoneNumber: "0284294824") let paymentComponentData = PaymentComponentData(paymentMethodDetails: paymentMethodDetails, amount: nil, order: nil) @@ -59,7 +59,7 @@ class PaymentComponentSubjectTests: XCTestCase { func testSubmitWithAnalyticsDisabledShouldNotSetCheckoutAttemptIdInPaymentComponentData() throws { // Given - analyticsProviderMock.underlyingCheckoutAttemptId = nil + analyticsProviderMock._checkoutAttemptId = nil let paymentMethodDetails = MBWayDetails(paymentMethod: paymentMethod, telephoneNumber: "0284294824") let paymentComponentData = PaymentComponentData(paymentMethodDetails: paymentMethodDetails, amount: nil, order: nil) diff --git a/Tests/Components Tests/Qiwi Wallet/QiwiWalletComponentTests.swift b/Tests/Components Tests/Qiwi Wallet/QiwiWalletComponentTests.swift index a43234a805..c1cac70a1c 100644 --- a/Tests/Components Tests/Qiwi Wallet/QiwiWalletComponentTests.swift +++ b/Tests/Components Tests/Qiwi Wallet/QiwiWalletComponentTests.swift @@ -196,6 +196,6 @@ class QiwiWalletComponentTests: XCTestCase { sut.viewWillAppear(viewController: sut.viewController) // Then - XCTAssertEqual(analyticsProviderMock.sendTelemetryEventCallsCount, 1) + XCTAssertEqual(analyticsProviderMock.initialTelemetryEventCallsCount, 1) } } diff --git a/Tests/Components Tests/SEPA Tests/SEPADirectDebitComponentTests.swift b/Tests/Components Tests/SEPA Tests/SEPADirectDebitComponentTests.swift index bb4e969897..e8fefe34d4 100644 --- a/Tests/Components Tests/SEPA Tests/SEPADirectDebitComponentTests.swift +++ b/Tests/Components Tests/SEPA Tests/SEPADirectDebitComponentTests.swift @@ -251,6 +251,6 @@ class SEPADirectDebitComponentTests: XCTestCase { sut.viewWillAppear(viewController: mockViewController) // Then - XCTAssertEqual(analyticsProviderMock.sendTelemetryEventCallsCount, 1) + XCTAssertEqual(analyticsProviderMock.initialTelemetryEventCallsCount, 1) } } diff --git a/Tests/Session Tests/SessionTests.swift b/Tests/Session Tests/SessionTests.swift index 4ea4509fa0..33d15170b4 100644 --- a/Tests/Session Tests/SessionTests.swift +++ b/Tests/Session Tests/SessionTests.swift @@ -21,7 +21,7 @@ class SessionTests: XCTestCase { override func setUpWithError() throws { try super.setUpWithError() analyticsProviderMock = AnalyticsProviderMock() - analyticsProviderMock.underlyingCheckoutAttemptId = "d06da733-ec41-4739-a532-5e8deab1262e16547639430681e1b021221a98c4bf13f7366b30fec4b376cc8450067ff98998682dd24fc9bda" + analyticsProviderMock._checkoutAttemptId = "d06da733-ec41-4739-a532-5e8deab1262e16547639430681e1b021221a98c4bf13f7366b30fec4b376cc8450067ff98998682dd24fc9bda" context = Dummy.context(with: analyticsProviderMock) } @@ -70,6 +70,7 @@ class SessionTests: XCTestCase { XCTAssertEqual(session.sessionContext.paymentMethods, expectedPaymentMethods) XCTAssertEqual(session.sessionContext.amount, .init(value: 220, currencyCode: "USD")) XCTAssertFalse(session.sessionContext.configuration.enableStoreDetails) + XCTAssertEqual(AdyenAnalytics.sessionId, "session_id") } expectation.fulfill() } @@ -107,7 +108,7 @@ class SessionTests: XCTestCase { func testDidSubmitWithCheckoutAttemptIdNonNilShouldIncludeCheckoutAttemptIdInPaymentComponentData() throws { // Given - let expectedCheckoutAttemptId = try XCTUnwrap(analyticsProviderMock.underlyingCheckoutAttemptId) + let expectedCheckoutAttemptId = try XCTUnwrap(analyticsProviderMock._checkoutAttemptId) let sessionAdvancedHandlerMock = SessionAdvancedHandlerMock() let sessionDelegateMock = SessionDelegateMock() @@ -135,7 +136,7 @@ class SessionTests: XCTestCase { func testDidSubmitWithCheckoutAttemptIdNilShouldNotIncludeCheckoutAttemptIdInPaymentComponentData() throws { // Given - analyticsProviderMock.underlyingCheckoutAttemptId = nil + analyticsProviderMock._checkoutAttemptId = nil let sessionAdvancedHandlerMock = SessionAdvancedHandlerMock() let sessionDelegateMock = SessionDelegateMock() From 3808979747f0973328a2b0ccbf6056bca36e6a58 Mon Sep 17 00:00:00 2001 From: erenbesel Date: Thu, 21 Dec 2023 15:07:50 +0100 Subject: [PATCH 03/31] chore: remove old telemetry request file --- Adyen.xcodeproj/project.pbxproj | 4 - .../Analytics/Requests/TelemetryRequest.swift | 80 ------------------- .../Analytics/AnalyticsProviderTests.swift | 17 ++-- 3 files changed, 6 insertions(+), 95 deletions(-) delete mode 100644 Adyen/Analytics/Requests/TelemetryRequest.swift diff --git a/Adyen.xcodeproj/project.pbxproj b/Adyen.xcodeproj/project.pbxproj index e6ccdc8e57..554bd4d76c 100644 --- a/Adyen.xcodeproj/project.pbxproj +++ b/Adyen.xcodeproj/project.pbxproj @@ -305,7 +305,6 @@ C9454C37276A340B0086C218 /* BACSDirectDebitPresentationDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9454C35276A33A00086C218 /* BACSDirectDebitPresentationDelegate.swift */; }; C9454C38276A34150086C218 /* BACSDirectDebitPresentationDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9454C35276A33A00086C218 /* BACSDirectDebitPresentationDelegate.swift */; }; C94632BE27BA6985003DD81F /* AnalyticsProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = C94632BD27BA6985003DD81F /* AnalyticsProvider.swift */; }; - C94632C227BAA81F003DD81F /* TelemetryRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = C94632C127BAA81F003DD81F /* TelemetryRequest.swift */; }; C95903DE275A48D000E7D3BC /* BACSDirectDebitComponentTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C95903DD275A48D000E7D3BC /* BACSDirectDebitComponentTests.swift */; }; C96688BF26A6FC1C00DC7297 /* AffirmComponentTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C96688BE26A6FC1C00DC7297 /* AffirmComponentTests.swift */; }; C96E07A3283B92E300345732 /* BACSDirectDebitComponentTrackerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C96E07A1283B92D500345732 /* BACSDirectDebitComponentTrackerTests.swift */; }; @@ -1542,7 +1541,6 @@ C93B01B82760B06300D311A1 /* BACSConfirmationPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BACSConfirmationPresenter.swift; sourceTree = ""; }; C9454C35276A33A00086C218 /* BACSDirectDebitPresentationDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BACSDirectDebitPresentationDelegate.swift; sourceTree = ""; }; C94632BD27BA6985003DD81F /* AnalyticsProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnalyticsProvider.swift; sourceTree = ""; }; - C94632C127BAA81F003DD81F /* TelemetryRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TelemetryRequest.swift; sourceTree = ""; }; C95903DD275A48D000E7D3BC /* BACSDirectDebitComponentTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BACSDirectDebitComponentTests.swift; sourceTree = ""; }; C96688BE26A6FC1C00DC7297 /* AffirmComponentTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AffirmComponentTests.swift; sourceTree = ""; }; C96E07A1283B92D500345732 /* BACSDirectDebitComponentTrackerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BACSDirectDebitComponentTrackerTests.swift; sourceTree = ""; }; @@ -3111,7 +3109,6 @@ C9CA0B68282E7E4A00C4E9C2 /* Requests */ = { isa = PBXGroup; children = ( - C94632C127BAA81F003DD81F /* TelemetryRequest.swift */, C9BAE20E27BEA68D002F5728 /* CheckoutAttemptIdRequest.swift */, A0DB48652AFD020400348C83 /* AdyenAnalyticsRequest.swift */, ); @@ -6571,7 +6568,6 @@ F9354BED23A7C34D00A6760B /* ButtonStyle.swift in Sources */, F9B8C50C23FE962D00C4D0FB /* FormPhoneNumberItem.swift in Sources */, E2C0E0BC220B2976008616F6 /* FormItemView.swift in Sources */, - C94632C227BAA81F003DD81F /* TelemetryRequest.swift in Sources */, E7763A1125F02BD20046371E /* GiftCardPaymentMethod.swift in Sources */, E788A4FB2658034400089448 /* ShopperInformation.swift in Sources */, E7085B172628B29600D0153B /* PhoneExtensionInputControl.swift in Sources */, diff --git a/Adyen/Analytics/Requests/TelemetryRequest.swift b/Adyen/Analytics/Requests/TelemetryRequest.swift deleted file mode 100644 index 0d9cfa4c9b..0000000000 --- a/Adyen/Analytics/Requests/TelemetryRequest.swift +++ /dev/null @@ -1,80 +0,0 @@ -// -// Copyright (c) 2023 Adyen N.V. -// -// This file is open source and available under the MIT license. See the LICENSE file for more info. -// - -import AdyenNetworking -import Foundation - -internal struct TelemetryResponse: Response { /* Empty response */ } - -internal struct TelemetryRequest: APIRequest { - - internal typealias ResponseType = TelemetryResponse - - internal let path: String = "checkoutshopper/v2/analytics/log" - - internal var counter: UInt = 0 - - internal let headers: [String: String] = [:] - - internal let queryParameters: [URLQueryItem] = [] - - internal let method: HTTPMethod = .post - - internal private(set) var version: String - internal private(set) var platform: String - - private let channel: String - private let locale: String - private let flavor: String - private let userAgent: String? - private var deviceBrand: String - private let systemVersion: String - private let referrer: String - private let screenWidth: Int - private let containerWidth: Int? - private let paymentMethods: [String] - private let component: String - internal let amount: Amount? - internal let checkoutAttemptId: String? - - // MARK: - Initializers - - internal init(data: TelemetryData, checkoutAttemptId: String?) { - self.version = data.version - self.channel = data.channel - self.locale = data.locale - self.flavor = data.flavor - self.userAgent = data.userAgent - self.deviceBrand = data.deviceBrand - self.systemVersion = data.systemVersion - self.referrer = data.referrer - self.screenWidth = data.screenWidth - self.containerWidth = data.containerWidth - self.paymentMethods = data.paymentMethods - self.component = data.component - self.amount = data.amount - self.platform = data.platform - self.checkoutAttemptId = checkoutAttemptId - } - - internal enum CodingKeys: CodingKey { - case version - case channel - case locale - case flavor - case userAgent - case deviceBrand - case systemVersion - case referrer - case screenWidth - case containerWidth - case paymentMethods - case component - case checkoutAttemptId - case amount - case platform - } -} diff --git a/Tests/Adyen Tests/Analytics/AnalyticsProviderTests.swift b/Tests/Adyen Tests/Analytics/AnalyticsProviderTests.swift index c1ed1d2cfa..1498a9b105 100644 --- a/Tests/Adyen Tests/Analytics/AnalyticsProviderTests.swift +++ b/Tests/Adyen Tests/Analytics/AnalyticsProviderTests.swift @@ -165,14 +165,12 @@ class AnalyticsProviderTests: XCTestCase { let apiClient = APIClientMock() apiClient.mockedResults = [ .success(CheckoutAttemptIdResponse(identifier: checkoutAttemptId)), - .success(TelemetryResponse()) ] apiClient.onExecute = { request in - if let telemetryRequest = request as? TelemetryRequest { - XCTAssertNil(telemetryRequest.amount) - XCTAssertEqual(telemetryRequest.checkoutAttemptId, checkoutAttemptId) - XCTAssertEqual(telemetryRequest.version, adyenSdkVersion) - XCTAssertEqual(telemetryRequest.platform, "ios") + if let checkoutAttemptIdRequest = request as? CheckoutAttemptIdRequest { + XCTAssertNil(checkoutAttemptIdRequest.amount) + XCTAssertEqual(checkoutAttemptIdRequest.version, adyenSdkVersion) + XCTAssertEqual(checkoutAttemptIdRequest.platform, "ios") telemetryExpectation.fulfill() } } @@ -232,10 +230,7 @@ class AnalyticsProviderTests: XCTestCase { additionalFields: AdditionalAnalyticsFields(amount: .init(value: 1, currencyCode: "EUR")), context: TelemetryContext(version: "version", platform: .flutter)) - let request = TelemetryRequest( - data: telemetryData, - checkoutAttemptId: checkoutAttemptIdMockValue - ) + let request = CheckoutAttemptIdRequest(data: telemetryData) let encodedRequest = try JSONEncoder().encode(request) let decodedRequest = try XCTUnwrap(JSONSerialization.jsonObject(with: encodedRequest) as? [String: Any]) @@ -251,11 +246,11 @@ class AnalyticsProviderTests: XCTestCase { "screenWidth": telemetryData.screenWidth, "referrer": telemetryData.referrer, "deviceBrand": telemetryData.deviceBrand, + "deviceModel": telemetryData.deviceModel, "amount": [ "currency": "EUR", "value": 1 ] as [String: Any], - "checkoutAttemptId": checkoutAttemptIdMockValue, "version": "version" ] as [String: Any] From bbed373278707088d34ab39ee3a7541b54e7112e Mon Sep 17 00:00:00 2001 From: erenbesel Date: Thu, 21 Dec 2023 15:18:57 +0100 Subject: [PATCH 04/31] chore: fix spell check --- Adyen/Core/Components/InstantPaymentComponent.swift | 2 +- spell-check-word-allow-list.yaml | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Adyen/Core/Components/InstantPaymentComponent.swift b/Adyen/Core/Components/InstantPaymentComponent.swift index b90e7a88c8..c7201d7af8 100644 --- a/Adyen/Core/Components/InstantPaymentComponent.swift +++ b/Adyen/Core/Components/InstantPaymentComponent.swift @@ -56,7 +56,7 @@ public final class InstantPaymentComponent: PaymentComponent { /// Generate the payment details and invoke PaymentsComponentDelegate method. public func initiatePayment() { - // we can attempt to fetch the checkoutAttempId but it won't be ready for the payment + // we can attempt to fetch the checkoutAttemptId but it won't be ready for the payment submit(data: paymentData) } } diff --git a/spell-check-word-allow-list.yaml b/spell-check-word-allow-list.yaml index acd549e0cd..e673ba9288 100644 --- a/spell-check-word-allow-list.yaml +++ b/spell-check-word-allow-list.yaml @@ -191,3 +191,4 @@ whiteList: - mapkit - bizum - alipay + - checkoutanalytics From eea7f3c5504b2c25bf44ed07bb6104a6b52cbaf5 Mon Sep 17 00:00:00 2001 From: erenbesel Date: Thu, 21 Dec 2023 15:34:59 +0100 Subject: [PATCH 05/31] chore: remove deleted class usage in test From 0feba74d225edec2ae83a550ac50311f104e5a1c Mon Sep 17 00:00:00 2001 From: erenbesel Date: Thu, 21 Dec 2023 15:35:21 +0100 Subject: [PATCH 06/31] chore: remove deleted class usage in test --- Tests/Adyen Tests/Analytics/TelemetryTrackerTests.swift | 2 -- 1 file changed, 2 deletions(-) diff --git a/Tests/Adyen Tests/Analytics/TelemetryTrackerTests.swift b/Tests/Adyen Tests/Analytics/TelemetryTrackerTests.swift index 7db22e2a59..09d22b648c 100644 --- a/Tests/Adyen Tests/Analytics/TelemetryTrackerTests.swift +++ b/Tests/Adyen Tests/Analytics/TelemetryTrackerTests.swift @@ -126,6 +126,4 @@ class TelemetryTrackerTests: XCTestCase { private var checkoutAttemptIdResponse: CheckoutAttemptIdResponse { .init(identifier: "cb3eef98-978e-4f6f-b299-937a4450be1f1648546838056be73d8f38ee8bcc3a65ec14e41b037a59f255dcd9e83afe8c06bd3e7abcad993") } - - private let telemetryResponse = TelemetryResponse() } From 842fb793f6748736abc653f1a0e8c3f9e7443e5a Mon Sep 17 00:00:00 2001 From: erenbesel Date: Tue, 23 Jan 2024 15:15:48 +0100 Subject: [PATCH 07/31] chore: update review comments --- Adyen.xcodeproj/project.pbxproj | 8 ++++---- .../AnalyticsProvider/AnalyticsProvider.swift | 20 ++++++++----------- Adyen/Analytics/Models/AdyenAnalytics.swift | 5 +++++ ...csEvent.swift => AdyenAnalyticsInfo.swift} | 8 ++++---- .../Requests/AdyenAnalyticsRequest.swift | 4 ++-- .../Components/InstantPaymentComponent.swift | 3 ++- .../Core Protocols/PresentableComponent.swift | 2 +- .../BACSDirectDebitComponentTracker.swift | 2 +- AdyenDropIn/DropInComponentExtensions.swift | 2 +- AdyenSession/AdyenSession.swift | 1 - .../Analytics/AnalyticsProviderMock.swift | 2 +- .../Analytics/AnalyticsProviderTests.swift | 16 +++++++-------- .../Analytics/TelemetryTrackerTests.swift | 7 +++++-- .../Adyen Tests/Core/AdyenContextTests.swift | 6 ++---- 14 files changed, 44 insertions(+), 42 deletions(-) rename Adyen/Analytics/Models/{AdyenAnalyticsEvent.swift => AdyenAnalyticsInfo.swift} (77%) diff --git a/Adyen.xcodeproj/project.pbxproj b/Adyen.xcodeproj/project.pbxproj index 713ef63829..dc50e54c96 100644 --- a/Adyen.xcodeproj/project.pbxproj +++ b/Adyen.xcodeproj/project.pbxproj @@ -282,7 +282,7 @@ A0D48FB827109B0200C0B82C /* ArrayHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0D48FB727109B0200C0B82C /* ArrayHelpers.swift */; }; A0DB48662AFD020400348C83 /* AdyenAnalyticsRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0DB48652AFD020400348C83 /* AdyenAnalyticsRequest.swift */; }; A0DB48682AFD068400348C83 /* AdyenAnalytics.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0DB48672AFD068400348C83 /* AdyenAnalytics.swift */; }; - A0DB486A2AFD0BDC00348C83 /* AdyenAnalyticsEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0DB48692AFD0BDC00348C83 /* AdyenAnalyticsEvent.swift */; }; + A0DB486A2AFD0BDC00348C83 /* AdyenAnalyticsInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0DB48692AFD0BDC00348C83 /* AdyenAnalyticsInfo.swift */; }; A0DB486C2AFD0BEE00348C83 /* AdyenAnalyticsLog.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0DB486B2AFD0BEE00348C83 /* AdyenAnalyticsLog.swift */; }; A0DB486E2AFD0BFC00348C83 /* AdyenAnalyticsError.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0DB486D2AFD0BFC00348C83 /* AdyenAnalyticsError.swift */; }; A0DDA6A72A6162F500EBD6AF /* AdyenSessionResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0DDA6A62A6162F500EBD6AF /* AdyenSessionResult.swift */; }; @@ -1521,7 +1521,7 @@ A0D48FB727109B0200C0B82C /* ArrayHelpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArrayHelpers.swift; sourceTree = ""; }; A0DB48652AFD020400348C83 /* AdyenAnalyticsRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdyenAnalyticsRequest.swift; sourceTree = ""; }; A0DB48672AFD068400348C83 /* AdyenAnalytics.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdyenAnalytics.swift; sourceTree = ""; }; - A0DB48692AFD0BDC00348C83 /* AdyenAnalyticsEvent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdyenAnalyticsEvent.swift; sourceTree = ""; }; + A0DB48692AFD0BDC00348C83 /* AdyenAnalyticsInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdyenAnalyticsInfo.swift; sourceTree = ""; }; A0DB486B2AFD0BEE00348C83 /* AdyenAnalyticsLog.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdyenAnalyticsLog.swift; sourceTree = ""; }; A0DB486D2AFD0BFC00348C83 /* AdyenAnalyticsError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdyenAnalyticsError.swift; sourceTree = ""; }; A0DDA6A62A6162F500EBD6AF /* AdyenSessionResult.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdyenSessionResult.swift; sourceTree = ""; }; @@ -3130,7 +3130,7 @@ children = ( C9B6683627C8D7FB006950B9 /* TelemetryData.swift */, A0DB48672AFD068400348C83 /* AdyenAnalytics.swift */, - A0DB48692AFD0BDC00348C83 /* AdyenAnalyticsEvent.swift */, + A0DB48692AFD0BDC00348C83 /* AdyenAnalyticsInfo.swift */, A0DB486B2AFD0BEE00348C83 /* AdyenAnalyticsLog.swift */, A0DB486D2AFD0BFC00348C83 /* AdyenAnalyticsError.swift */, ); @@ -6662,7 +6662,7 @@ E2C0E096220B04F0008616F6 /* FormViewController.swift in Sources */, F9FE25D62626CD49001874BB /* ReadyToSubmitPaymentComponentDelegate.swift in Sources */, F99D4556262717A500880D72 /* FormErrorItemView.swift in Sources */, - A0DB486A2AFD0BDC00348C83 /* AdyenAnalyticsEvent.swift in Sources */, + A0DB486A2AFD0BDC00348C83 /* AdyenAnalyticsInfo.swift in Sources */, F96286BD256BDEB000043FE3 /* CoreBundleExtension.swift in Sources */, E7085D7D262EEF6200D0153B /* AllRegions.swift in Sources */, F919DF9124E682480027976E /* ClientKeyResponse.swift in Sources */, diff --git a/Adyen/Analytics/AnalyticsProvider/AnalyticsProvider.swift b/Adyen/Analytics/AnalyticsProvider/AnalyticsProvider.swift index f276693938..9ca4638e0a 100644 --- a/Adyen/Analytics/AnalyticsProvider/AnalyticsProvider.swift +++ b/Adyen/Analytics/AnalyticsProvider/AnalyticsProvider.swift @@ -42,14 +42,10 @@ public struct AdditionalAnalyticsFields { } @_spi(AdyenInternal) -public protocol InitialTelemetryProtocol { +public protocol AnalyticsProviderProtocol { /// Sends the initial data and retrieves the checkout attempt id as a response. - func fetchCheckoutAttemptId(with flavor: TelemetryFlavor, additionalFields: AdditionalAnalyticsFields?) -} - -@_spi(AdyenInternal) -public protocol AnalyticsProviderProtocol: InitialTelemetryProtocol { + func sendInitialAnalytics(with flavor: TelemetryFlavor, additionalFields: AdditionalAnalyticsFields?) var checkoutAttemptId: String? { get } } @@ -65,7 +61,7 @@ internal final class AnalyticsProvider: AnalyticsProviderProtocol { private var batchTimer: Timer? - private var events: [AdyenAnalytics.Event] = [] + private var infos: [AdyenAnalytics.Info] = [] private var logs: [AdyenAnalytics.Log] = [] private var errors: [AdyenAnalytics.Error] = [] @@ -82,7 +78,7 @@ internal final class AnalyticsProvider: AnalyticsProviderProtocol { // MARK: - Internal - internal func fetchCheckoutAttemptId(with flavor: TelemetryFlavor, additionalFields: AdditionalAnalyticsFields?) { + internal func sendInitialAnalytics(with flavor: TelemetryFlavor, additionalFields: AdditionalAnalyticsFields?) { guard configuration.isEnabled, configuration.isTelemetryEnabled else { checkoutAttemptId = "do-not-track" return @@ -105,8 +101,8 @@ internal final class AnalyticsProvider: AnalyticsProviderProtocol { } } - internal func send(event: AdyenAnalytics.Event) { - events.append(event) + internal func send(info: AdyenAnalytics.Info) { + infos.append(info) } internal func send(log: AdyenAnalytics.Log) { @@ -129,7 +125,7 @@ internal final class AnalyticsProvider: AnalyticsProviderProtocol { let checkoutAttemptId else { return } var request = AdyenAnalyticsRequest(checkoutAttemptId: checkoutAttemptId) - request.events = events + request.infos = infos request.logs = logs request.errors = errors @@ -140,7 +136,7 @@ internal final class AnalyticsProvider: AnalyticsProviderProtocol { } private func clearAll() { - events = [] + infos = [] logs = [] errors = [] } diff --git a/Adyen/Analytics/Models/AdyenAnalytics.swift b/Adyen/Analytics/Models/AdyenAnalytics.swift index dc57c9bc46..1684075aab 100644 --- a/Adyen/Analytics/Models/AdyenAnalytics.swift +++ b/Adyen/Analytics/Models/AdyenAnalytics.swift @@ -27,3 +27,8 @@ public final class AdyenAnalytics { internal protocol AdyenAnalyticsCommonFields: Encodable { var commonFields: AdyenAnalytics.CommonFields { get } } + +//@_spi(AdyenInternal) +//public protocol AdyenAnalyticEvent { +// var commonFields: AdyenAnalytics.CommonFields { get } +//} diff --git a/Adyen/Analytics/Models/AdyenAnalyticsEvent.swift b/Adyen/Analytics/Models/AdyenAnalyticsInfo.swift similarity index 77% rename from Adyen/Analytics/Models/AdyenAnalyticsEvent.swift rename to Adyen/Analytics/Models/AdyenAnalyticsInfo.swift index 293f6f36c4..b0f2589c5e 100644 --- a/Adyen/Analytics/Models/AdyenAnalyticsEvent.swift +++ b/Adyen/Analytics/Models/AdyenAnalyticsInfo.swift @@ -8,13 +8,13 @@ import Foundation extension AdyenAnalytics { - /// Represents an event in the analytics scheme that can occur + /// Represents an info event in the analytics scheme that can occur /// many times during the checkout flow, such as input field focus/unfocus etc. - internal struct Event: AdyenAnalyticsCommonFields { + internal struct Info: AdyenAnalyticsCommonFields { internal var commonFields: AdyenAnalytics.CommonFields - internal var type: EventType + internal var type: InfoType internal var target: String @@ -27,7 +27,7 @@ extension AdyenAnalytics { internal var validationErrorMessage: String } - internal enum EventType: String, Encodable { + internal enum InfoType: String, Encodable { case selected = "Selected" case focus = "Focus" case unfocus = "Unfocus" diff --git a/Adyen/Analytics/Requests/AdyenAnalyticsRequest.swift b/Adyen/Analytics/Requests/AdyenAnalyticsRequest.swift index ffd5e0c06e..b6354c4554 100644 --- a/Adyen/Analytics/Requests/AdyenAnalyticsRequest.swift +++ b/Adyen/Analytics/Requests/AdyenAnalyticsRequest.swift @@ -25,7 +25,7 @@ internal struct AdyenAnalyticsRequest: APIRequest { internal var channel: String = "iOS" - internal var events: [AdyenAnalytics.Event] = [] + internal var infos: [AdyenAnalytics.Info] = [] internal var logs: [AdyenAnalytics.Log] = [] @@ -37,7 +37,7 @@ internal struct AdyenAnalyticsRequest: APIRequest { private enum CodingKeys: String, CodingKey { case channel - case events + case infos = "info" case logs case errors diff --git a/Adyen/Core/Components/InstantPaymentComponent.swift b/Adyen/Core/Components/InstantPaymentComponent.swift index c7201d7af8..0865f3ebe2 100644 --- a/Adyen/Core/Components/InstantPaymentComponent.swift +++ b/Adyen/Core/Components/InstantPaymentComponent.swift @@ -56,7 +56,8 @@ public final class InstantPaymentComponent: PaymentComponent { /// Generate the payment details and invoke PaymentsComponentDelegate method. public func initiatePayment() { - // we can attempt to fetch the checkoutAttemptId but it won't be ready for the payment + // We are not attempting to fetch the checkoutAttemptId as it won't be ready for the payment + // and we don't want to block it for an analytics call. submit(data: paymentData) } } diff --git a/Adyen/Core/Core Protocols/PresentableComponent.swift b/Adyen/Core/Core Protocols/PresentableComponent.swift index bad7955221..02af4f94c7 100644 --- a/Adyen/Core/Core Protocols/PresentableComponent.swift +++ b/Adyen/Core/Core Protocols/PresentableComponent.swift @@ -73,7 +73,7 @@ extension TrackableComponent where Self: PaymentMethodAware { let flavor: TelemetryFlavor = _isDropIn ? .dropInComponent : .components(type: paymentMethod.type) let amount = context.payment?.amount let additionalFields = AdditionalAnalyticsFields(amount: amount, sessionId: AdyenAnalytics.sessionId) - context.analyticsProvider.fetchCheckoutAttemptId(with: flavor, + context.analyticsProvider.sendInitialAnalytics(with: flavor, additionalFields: additionalFields) } } diff --git a/AdyenComponents/BACS Direct Debit/Trackers/BACSDirectDebitComponentTracker.swift b/AdyenComponents/BACS Direct Debit/Trackers/BACSDirectDebitComponentTracker.swift index e348f18474..2de7b4b0ef 100644 --- a/AdyenComponents/BACS Direct Debit/Trackers/BACSDirectDebitComponentTracker.swift +++ b/AdyenComponents/BACS Direct Debit/Trackers/BACSDirectDebitComponentTracker.swift @@ -35,7 +35,7 @@ internal class BACSDirectDebitComponentTracker: BACSDirectDebitComponentTrackerP let flavor: TelemetryFlavor = isDropIn ? .dropInComponent : .components(type: paymentMethod.type) let amount = context.payment?.amount let additionalFields = AdditionalAnalyticsFields(amount: amount, sessionId: AdyenAnalytics.sessionId) - context.analyticsProvider.fetchCheckoutAttemptId(with: flavor, + context.analyticsProvider.sendInitialAnalytics(with: flavor, additionalFields: additionalFields) } diff --git a/AdyenDropIn/DropInComponentExtensions.swift b/AdyenDropIn/DropInComponentExtensions.swift index 58f9f066f7..fe39800394 100644 --- a/AdyenDropIn/DropInComponentExtensions.swift +++ b/AdyenDropIn/DropInComponentExtensions.swift @@ -25,7 +25,7 @@ extension DropInComponent: PaymentMethodListComponentDelegate { let flavor = TelemetryFlavor.dropIn(paymentMethods: paymentMethodTypes) let amount = context.payment?.amount let additionalFields = AdditionalAnalyticsFields(amount: amount, sessionId: AdyenAnalytics.sessionId) - context.analyticsProvider.fetchCheckoutAttemptId(with: flavor, additionalFields: additionalFields) + context.analyticsProvider.sendInitialAnalytics(with: flavor, additionalFields: additionalFields) } internal func didSelect(_ component: PaymentComponent, diff --git a/AdyenSession/AdyenSession.swift b/AdyenSession/AdyenSession.swift index 6915dbfd8c..02effb1e0d 100644 --- a/AdyenSession/AdyenSession.swift +++ b/AdyenSession/AdyenSession.swift @@ -119,7 +119,6 @@ public final class AdyenSession { sessionContext: sessionContext) session.delegate = delegate session.presentationDelegate = presentationDelegate - // Unfortunately needed by telemetry and this is the only way atm. AdyenAnalytics.sessionId = sessionContext.identifier completion(.success(session)) case let .failure(error): diff --git a/Tests/Adyen Tests/Analytics/AnalyticsProviderMock.swift b/Tests/Adyen Tests/Analytics/AnalyticsProviderMock.swift index 2e34223395..bfb0fc20ea 100644 --- a/Tests/Adyen Tests/Analytics/AnalyticsProviderMock.swift +++ b/Tests/Adyen Tests/Analytics/AnalyticsProviderMock.swift @@ -15,7 +15,7 @@ class AnalyticsProviderMock: AnalyticsProviderProtocol { // MARK: - checkoutAttemptId - func fetchCheckoutAttemptId(with flavor: TelemetryFlavor, additionalFields: AdditionalAnalyticsFields?) { + func sendInitialAnalytics(with flavor: TelemetryFlavor, additionalFields: AdditionalAnalyticsFields?) { initialTelemetryEventCallsCount += 1 checkoutAttemptId = _checkoutAttemptId } diff --git a/Tests/Adyen Tests/Analytics/AnalyticsProviderTests.swift b/Tests/Adyen Tests/Analytics/AnalyticsProviderTests.swift index 1ed3e6474c..d2bf83b064 100644 --- a/Tests/Adyen Tests/Analytics/AnalyticsProviderTests.swift +++ b/Tests/Adyen Tests/Analytics/AnalyticsProviderTests.swift @@ -39,7 +39,7 @@ class AnalyticsProviderTests: XCTestCase { let fetchCheckoutAttemptIdExpection = expectation(description: "checkoutAttemptId completion") // When - sut.fetchCheckoutAttemptId(with: .components(type: .achDirectDebit), additionalFields: nil) + sut.sendInitialAnalytics(with: .components(type: .achDirectDebit), additionalFields: nil) fetchCheckoutAttemptIdExpection.fulfill() wait(for: .milliseconds(200)) @@ -58,7 +58,7 @@ class AnalyticsProviderTests: XCTestCase { let sut = AnalyticsProvider(apiClient: apiClient, configuration: analyticsConfiguration) // When - sut.fetchCheckoutAttemptId(with: .components(type: .affirm), additionalFields: nil) + sut.sendInitialAnalytics(with: .components(type: .affirm), additionalFields: nil) XCTAssertEqual(sut.checkoutAttemptId, "do-not-track") } @@ -79,7 +79,7 @@ class AnalyticsProviderTests: XCTestCase { let fetchCheckoutAttemptIdExpection = expectation(description: "checkoutAttemptId completion") // When - sut.fetchCheckoutAttemptId(with: .components(type: .achDirectDebit), additionalFields: nil) + sut.sendInitialAnalytics(with: .components(type: .achDirectDebit), additionalFields: nil) fetchCheckoutAttemptIdExpection.fulfill() wait(for: .milliseconds(200)) @@ -104,7 +104,7 @@ class AnalyticsProviderTests: XCTestCase { apiClient.mockedResults = [checkoutAttemptIdResult] // When - sut.fetchCheckoutAttemptId(with: .dropInComponent, additionalFields: nil) + sut.sendInitialAnalytics(with: .dropInComponent, additionalFields: nil) // Then XCTAssertNil(sut.checkoutAttemptId, "The checkoutAttemptId is not nil.") } @@ -126,7 +126,7 @@ class AnalyticsProviderTests: XCTestCase { let fetchCheckoutAttemptIdExpection = expectation(description: "checkoutAttemptId completion") // When - sut.fetchCheckoutAttemptId(with: .components(type: .atome), additionalFields: nil) + sut.sendInitialAnalytics(with: .components(type: .atome), additionalFields: nil) fetchCheckoutAttemptIdExpection.fulfill() wait(for: .milliseconds(200)) @@ -150,7 +150,7 @@ class AnalyticsProviderTests: XCTestCase { apiClient.mockedResults = [checkoutAttemptIdResult] // When - sut.fetchCheckoutAttemptId(with: .components(type: .affirm), additionalFields: nil) + sut.sendInitialAnalytics(with: .components(type: .affirm), additionalFields: nil) // Then XCTAssertEqual(sut.checkoutAttemptId, "do-not-track") } @@ -182,7 +182,7 @@ class AnalyticsProviderTests: XCTestCase { // When - analyticsProvider.fetchCheckoutAttemptId(with: .components(type: .achDirectDebit), additionalFields: nil) + analyticsProvider.sendInitialAnalytics(with: .components(type: .achDirectDebit), additionalFields: nil) wait(for: [telemetryExpectation], timeout: 10) } @@ -219,7 +219,7 @@ class AnalyticsProviderTests: XCTestCase { // When let additionalFields = AdditionalAnalyticsFields(amount: amount) - analyticsProvider.fetchCheckoutAttemptId(with: .components(type: .achDirectDebit), additionalFields: additionalFields) + analyticsProvider.sendInitialAnalytics(with: .components(type: .achDirectDebit), additionalFields: additionalFields) wait(for: [telemetryExpectation], timeout: 10) } diff --git a/Tests/Adyen Tests/Analytics/TelemetryTrackerTests.swift b/Tests/Adyen Tests/Analytics/TelemetryTrackerTests.swift index 09d22b648c..5e6fcc7f5a 100644 --- a/Tests/Adyen Tests/Analytics/TelemetryTrackerTests.swift +++ b/Tests/Adyen Tests/Analytics/TelemetryTrackerTests.swift @@ -13,7 +13,7 @@ import XCTest class TelemetryTrackerTests: XCTestCase { var apiClient: APIClientMock! - var sut: InitialTelemetryProtocol! + var sut: AnalyticsProviderProtocol! override func setUpWithError() throws { try super.setUpWithError() @@ -31,7 +31,7 @@ class TelemetryTrackerTests: XCTestCase { } private func sendInitialTelemetry(flavor: TelemetryFlavor = .components(type: .achDirectDebit)) { - sut.fetchCheckoutAttemptId(with: flavor, additionalFields: nil) + sut.sendInitialAnalytics(with: flavor, additionalFields: nil) } func testSendTelemetryEventGivenAnalyticsIsDisabledAndTelemetryIsEnabledShouldNotSendAnyRequest() throws { @@ -63,6 +63,7 @@ class TelemetryTrackerTests: XCTestCase { // Then XCTAssertEqual(expectedRequestCalls, apiClient.counter, "One or more telemetry requests were sent.") + XCTAssertEqual(sut.checkoutAttemptId, "do-not-track") } func testSendTelemetryEventGivenTelemetryIsEnabledAndFlavorIsDropInComponentShouldNotSendAnyRequest() throws { @@ -79,6 +80,7 @@ class TelemetryTrackerTests: XCTestCase { // Then XCTAssertEqual(expectedRequestCalls, apiClient.counter, "One or more telemetry requests were sent.") + XCTAssertNil(sut.checkoutAttemptId) } func testSendTelemetryEventGivenTelemetryIsEnabledAndFlavorIsComponentsShouldSendTelemetryRequest() throws { @@ -99,6 +101,7 @@ class TelemetryTrackerTests: XCTestCase { // Then wait(for: .milliseconds(1)) XCTAssertEqual(expectedRequestCalls, apiClient.counter, "Invalid request number made.") + XCTAssertEqual(sut.checkoutAttemptId, "cb3eef98-978e-4f6f-b299-937a4450be1f1648546838056be73d8f38ee8bcc3a65ec14e41b037a59f255dcd9e83afe8c06bd3e7abcad993") } func testSendTelemetryEventGivenTelemetryIsEnabledAndFlavorIsDropInShouldSendTelemetryRequest() throws { diff --git a/Tests/Adyen Tests/Core/AdyenContextTests.swift b/Tests/Adyen Tests/Core/AdyenContextTests.swift index 7284940398..915d7a5cdb 100644 --- a/Tests/Adyen Tests/Core/AdyenContextTests.swift +++ b/Tests/Adyen Tests/Core/AdyenContextTests.swift @@ -21,10 +21,8 @@ class AdyenContextTests: XCTestCase { payment: .init(amount: oneEUR, countryCode: "NL") ) -// XCTAssertEqual(context.analyticsProvider.additionalFields?().amount, oneEUR) - + XCTAssertEqual(context.payment?.amount, oneEUR) context.update(payment: Payment(amount: twoEUR, countryCode: "NL")) - -// XCTAssertEqual(context.analyticsProvider.additionalFields?().amount, twoEUR) + XCTAssertEqual(context.payment?.amount, twoEUR) } } From d8f53255c38a1558fd1fafe1541d532c9197310e Mon Sep 17 00:00:00 2001 From: erenbesel Date: Thu, 25 Jan 2024 10:27:15 +0100 Subject: [PATCH 08/31] chore: review updates --- Adyen.xcodeproj/project.pbxproj | 8 ++--- Adyen/Analytics/Models/AdyenAnalytics.swift | 5 ---- ...AbstractPersonalInformationComponent.swift | 2 +- .../StoredPaymentMethodComponent.swift | 2 +- .../Core Protocols/PresentableComponent.swift | 6 ++-- .../UI/{Dimentions.swift => Dimensions.swift} | 0 .../Stored Card/StoredCardComponent.swift | 2 +- .../Scenes/Input/BACSInputPresenter.swift | 2 +- .../BACSDirectDebitComponentTracker.swift | 4 +-- AdyenComponents/Boleto/BoletoComponent.swift | 2 +- .../Analytics/AnalyticsProviderTests.swift | 29 ++----------------- .../Analytics/TelemetryTrackerTests.swift | 12 ++++---- ...ectDebitComponentTrackerProtocolMock.swift | 2 +- ...BACSDirectDebitComponentTrackerTests.swift | 2 +- 14 files changed, 25 insertions(+), 53 deletions(-) rename Adyen/UI/{Dimentions.swift => Dimensions.swift} (100%) diff --git a/Adyen.xcodeproj/project.pbxproj b/Adyen.xcodeproj/project.pbxproj index dc50e54c96..5a7f9097ed 100644 --- a/Adyen.xcodeproj/project.pbxproj +++ b/Adyen.xcodeproj/project.pbxproj @@ -435,7 +435,7 @@ E72375DD27AABF450020DCF9 /* AdyenWeChatPayInternal in Frameworks */ = {isa = PBXBuildFile; productRef = E72375DC27AABF450020DCF9 /* AdyenWeChatPayInternal */; }; E72521EE25517EB100533E35 /* BLIKComponentTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E72521ED25517EB100533E35 /* BLIKComponentTests.swift */; }; E7275BF9255012F600907CF9 /* FormLabelItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = E7275BF8255012F600907CF9 /* FormLabelItem.swift */; }; - E72D9BAA26A6E66800FBDA48 /* Dimentions.swift in Sources */ = {isa = PBXBuildFile; fileRef = E72D9BA926A6E66800FBDA48 /* Dimentions.swift */; }; + E72D9BAA26A6E66800FBDA48 /* Dimensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = E72D9BA926A6E66800FBDA48 /* Dimensions.swift */; }; E72DA33F23E19DE300707638 /* PreselectedPaymentMethodComponent.swift in Sources */ = {isa = PBXBuildFile; fileRef = E72DA33C23E19DE300707638 /* PreselectedPaymentMethodComponent.swift */; }; E72DA34123E1BE5300707638 /* DropInNavigationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E72DA34023E1BE5300707638 /* DropInNavigationController.swift */; }; E7388D8523DB1F9A008E62B8 /* DimmingPresentationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E7388D8423DB1F9A008E62B8 /* DimmingPresentationController.swift */; }; @@ -1699,7 +1699,7 @@ E71E8F3D257921D10054B03D /* StoredBLIKPaymentMethod.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StoredBLIKPaymentMethod.swift; sourceTree = ""; }; E72521ED25517EB100533E35 /* BLIKComponentTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BLIKComponentTests.swift; sourceTree = ""; }; E7275BF8255012F600907CF9 /* FormLabelItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FormLabelItem.swift; sourceTree = ""; }; - E72D9BA926A6E66800FBDA48 /* Dimentions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Dimentions.swift; sourceTree = ""; }; + E72D9BA926A6E66800FBDA48 /* Dimensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Dimensions.swift; sourceTree = ""; }; E72DA33C23E19DE300707638 /* PreselectedPaymentMethodComponent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PreselectedPaymentMethodComponent.swift; sourceTree = ""; }; E72DA34023E1BE5300707638 /* DropInNavigationController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DropInNavigationController.swift; sourceTree = ""; }; E736497E25277B6500AB76AE /* StringExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StringExtension.swift; sourceTree = ""; }; @@ -3540,7 +3540,7 @@ E28098B9220DB9E70087928F /* List */, E2C0E0BF220D7E53008616F6 /* Views */, F9175F7625948EDF00D653BE /* View Controllers */, - E72D9BA926A6E66800FBDA48 /* Dimentions.swift */, + E72D9BA926A6E66800FBDA48 /* Dimensions.swift */, ); path = UI; sourceTree = ""; @@ -6478,7 +6478,7 @@ F96F44DD23BE487500871C1F /* LocalizationParameters.swift in Sources */, E7085A8D2627132B00D0153B /* PostalAddress.swift in Sources */, F9589D272601F19E00E4113F /* EmailFormItemInjector.swift in Sources */, - E72D9BAA26A6E66800FBDA48 /* Dimentions.swift in Sources */, + E72D9BAA26A6E66800FBDA48 /* Dimensions.swift in Sources */, F9620DB323C75C19005209FC /* PaymentComponentBuilder.swift in Sources */, F96757BF27CF690600A16FB6 /* PartialPaymentError.swift in Sources */, E7085B122628B29600D0153B /* BasePickerInputControl.swift in Sources */, diff --git a/Adyen/Analytics/Models/AdyenAnalytics.swift b/Adyen/Analytics/Models/AdyenAnalytics.swift index 1684075aab..dc57c9bc46 100644 --- a/Adyen/Analytics/Models/AdyenAnalytics.swift +++ b/Adyen/Analytics/Models/AdyenAnalytics.swift @@ -27,8 +27,3 @@ public final class AdyenAnalytics { internal protocol AdyenAnalyticsCommonFields: Encodable { var commonFields: AdyenAnalytics.CommonFields { get } } - -//@_spi(AdyenInternal) -//public protocol AdyenAnalyticEvent { -// var commonFields: AdyenAnalytics.CommonFields { get } -//} diff --git a/Adyen/Core/Components/AbstractPersonalInformationComponent/AbstractPersonalInformationComponent.swift b/Adyen/Core/Components/AbstractPersonalInformationComponent/AbstractPersonalInformationComponent.swift index 2955caaa15..ab94070530 100644 --- a/Adyen/Core/Components/AbstractPersonalInformationComponent/AbstractPersonalInformationComponent.swift +++ b/Adyen/Core/Components/AbstractPersonalInformationComponent/AbstractPersonalInformationComponent.swift @@ -258,7 +258,7 @@ extension AbstractPersonalInformationComponent: ViewControllerDelegate { // MARK: - ViewControllerDelegate public func viewWillAppear(viewController: UIViewController) { - fetchCheckoutAttemptId() + sendInitialAnalytics() populateFields() } } diff --git a/Adyen/Core/Components/StoredPaymentMethodComponent.swift b/Adyen/Core/Components/StoredPaymentMethodComponent.swift index 6148553d0b..e879714f99 100644 --- a/Adyen/Core/Components/StoredPaymentMethodComponent.swift +++ b/Adyen/Core/Components/StoredPaymentMethodComponent.swift @@ -47,7 +47,7 @@ public final class StoredPaymentMethodComponent: PaymentComponent, flavor: _isDropIn ? .dropin : .components, context: context.apiContext ) - fetchCheckoutAttemptId() + sendInitialAnalytics() let localizationParameters = configuration.localizationParameters let displayInformation = storedPaymentMethod.displayInformation(using: localizationParameters) diff --git a/Adyen/Core/Core Protocols/PresentableComponent.swift b/Adyen/Core/Core Protocols/PresentableComponent.swift index 02af4f94c7..96b6b9b9f8 100644 --- a/Adyen/Core/Core Protocols/PresentableComponent.swift +++ b/Adyen/Core/Core Protocols/PresentableComponent.swift @@ -63,13 +63,13 @@ public extension PresentableComponent { @_spi(AdyenInternal) public protocol TrackableComponent: Component { - func fetchCheckoutAttemptId() + func sendInitialAnalytics() } @_spi(AdyenInternal) extension TrackableComponent where Self: PaymentMethodAware { - public func fetchCheckoutAttemptId() { + public func sendInitialAnalytics() { let flavor: TelemetryFlavor = _isDropIn ? .dropInComponent : .components(type: paymentMethod.type) let amount = context.payment?.amount let additionalFields = AdditionalAnalyticsFields(amount: amount, sessionId: AdyenAnalytics.sessionId) @@ -82,6 +82,6 @@ extension TrackableComponent where Self: PaymentMethodAware { extension TrackableComponent where Self: ViewControllerDelegate { public func viewWillAppear(viewController: UIViewController) { - fetchCheckoutAttemptId() + sendInitialAnalytics() } } diff --git a/Adyen/UI/Dimentions.swift b/Adyen/UI/Dimensions.swift similarity index 100% rename from Adyen/UI/Dimentions.swift rename to Adyen/UI/Dimensions.swift diff --git a/AdyenCard/Components/Stored Card/StoredCardComponent.swift b/AdyenCard/Components/Stored Card/StoredCardComponent.swift index 19c39075ad..84828a9d5b 100644 --- a/AdyenCard/Components/Stored Card/StoredCardComponent.swift +++ b/AdyenCard/Components/Stored Card/StoredCardComponent.swift @@ -42,7 +42,7 @@ internal final class StoredCardComponent: PaymentComponent, PaymentAware, Presen flavor: _isDropIn ? .dropin : .components, context: context.apiContext ) - fetchCheckoutAttemptId() + sendInitialAnalytics() let manager = StoredCardAlertManager(paymentMethod: storedCardPaymentMethod, context: context, diff --git a/AdyenComponents/BACS Direct Debit/Scenes/Input/BACSInputPresenter.swift b/AdyenComponents/BACS Direct Debit/Scenes/Input/BACSInputPresenter.swift index 08e0cead3e..01ce7afcd1 100644 --- a/AdyenComponents/BACS Direct Debit/Scenes/Input/BACSInputPresenter.swift +++ b/AdyenComponents/BACS Direct Debit/Scenes/Input/BACSInputPresenter.swift @@ -56,7 +56,7 @@ internal class BACSInputPresenter: BACSInputPresenterProtocol { // MARK: - BACSInputPresenterProtocol internal func viewDidLoad() { - tracker.fetchCheckoutAttemptId() + tracker.sendInitialAnalytics() createItems() setupView() } diff --git a/AdyenComponents/BACS Direct Debit/Trackers/BACSDirectDebitComponentTracker.swift b/AdyenComponents/BACS Direct Debit/Trackers/BACSDirectDebitComponentTracker.swift index 2de7b4b0ef..c725362eb6 100644 --- a/AdyenComponents/BACS Direct Debit/Trackers/BACSDirectDebitComponentTracker.swift +++ b/AdyenComponents/BACS Direct Debit/Trackers/BACSDirectDebitComponentTracker.swift @@ -8,7 +8,7 @@ import Foundation internal protocol BACSDirectDebitComponentTrackerProtocol: AnyObject { - func fetchCheckoutAttemptId() + func sendInitialAnalytics() } internal class BACSDirectDebitComponentTracker: BACSDirectDebitComponentTrackerProtocol { @@ -31,7 +31,7 @@ internal class BACSDirectDebitComponentTracker: BACSDirectDebitComponentTrackerP // MARK: - BACSDirectDebitComponentTrackerProtocol - internal func fetchCheckoutAttemptId() { + internal func sendInitialAnalytics() { let flavor: TelemetryFlavor = isDropIn ? .dropInComponent : .components(type: paymentMethod.type) let amount = context.payment?.amount let additionalFields = AdditionalAnalyticsFields(amount: amount, sessionId: AdyenAnalytics.sessionId) diff --git a/AdyenComponents/Boleto/BoletoComponent.swift b/AdyenComponents/Boleto/BoletoComponent.swift index abe53ce21c..bf113ac175 100644 --- a/AdyenComponents/Boleto/BoletoComponent.swift +++ b/AdyenComponents/Boleto/BoletoComponent.swift @@ -188,7 +188,7 @@ extension BoletoComponent: ViewControllerDelegate { public func viewDidAppear(viewController: UIViewController) {} public func viewWillAppear(viewController: UIViewController) { - fetchCheckoutAttemptId() + sendInitialAnalytics() prefillFields(for: formComponent) } } diff --git a/Tests/Adyen Tests/Analytics/AnalyticsProviderTests.swift b/Tests/Adyen Tests/Analytics/AnalyticsProviderTests.swift index d2bf83b064..c6779f2268 100644 --- a/Tests/Adyen Tests/Analytics/AnalyticsProviderTests.swift +++ b/Tests/Adyen Tests/Analytics/AnalyticsProviderTests.swift @@ -35,19 +35,11 @@ class AnalyticsProviderTests: XCTestCase { let checkoutAttemptIdResponse = CheckoutAttemptIdResponse(identifier: expectedCheckoutAttemptId) let checkoutAttemptIdResult: Result = .success(checkoutAttemptIdResponse) apiClient.mockedResults = [checkoutAttemptIdResult] - - let fetchCheckoutAttemptIdExpection = expectation(description: "checkoutAttemptId completion") // When sut.sendInitialAnalytics(with: .components(type: .achDirectDebit), additionalFields: nil) - fetchCheckoutAttemptIdExpection.fulfill() - - wait(for: .milliseconds(200)) - - XCTAssertNotNil(sut.checkoutAttemptId, "The checkoutAttemptId is nil.") - XCTAssertEqual(expectedCheckoutAttemptId, sut.checkoutAttemptId, "The received checkoutAttemptId is not the expected one.") - waitForExpectations(timeout: 10) + wait(until: sut, at: \.checkoutAttemptId, is: expectedCheckoutAttemptId) } func testFetchCheckoutAttemptIdWhenAnalyticsIsDisabledShouldNotTriggerCheckoutAttemptIdRequest() throws { @@ -75,20 +67,12 @@ class AnalyticsProviderTests: XCTestCase { let checkoutAttemptIdResponse = CheckoutAttemptIdResponse(identifier: expectedCheckoutAttemptId) let checkoutAttemptIdResult: Result = .success(checkoutAttemptIdResponse) apiClient.mockedResults = [checkoutAttemptIdResult] - - let fetchCheckoutAttemptIdExpection = expectation(description: "checkoutAttemptId completion") // When sut.sendInitialAnalytics(with: .components(type: .achDirectDebit), additionalFields: nil) - fetchCheckoutAttemptIdExpection.fulfill() - - wait(for: .milliseconds(200)) // Then - XCTAssertNotNil(sut.checkoutAttemptId, "The checkoutAttemptId is nil.") - XCTAssertEqual(expectedCheckoutAttemptId, sut.checkoutAttemptId, "The received checkoutAttemptId is not the expected one.") - - waitForExpectations(timeout: 10) + wait(until: sut, at: \.checkoutAttemptId, is: expectedCheckoutAttemptId) } func testFetchCheckoutAttemptIdWhenAnalyticsIsEnabledGivenFailureShouldCallCompletionWithNilValue() throws { @@ -122,19 +106,12 @@ class AnalyticsProviderTests: XCTestCase { let checkoutAttemptIdResponse = CheckoutAttemptIdResponse(identifier: expectedCheckoutAttemptId) let checkoutAttemptIdResult: Result = .success(checkoutAttemptIdResponse) apiClient.mockedResults = [checkoutAttemptIdResult] - - let fetchCheckoutAttemptIdExpection = expectation(description: "checkoutAttemptId completion") // When sut.sendInitialAnalytics(with: .components(type: .atome), additionalFields: nil) - fetchCheckoutAttemptIdExpection.fulfill() - - wait(for: .milliseconds(200)) // Then - XCTAssertEqual(expectedCheckoutAttemptId, sut.checkoutAttemptId) - - waitForExpectations(timeout: 1) + wait(until: sut, at: \.checkoutAttemptId, is: expectedCheckoutAttemptId) } func testFetchCheckoutAttemptIdWhenAnalyticsIsDisabledShouldNotSetCheckoutAttemptIdProperty() throws { diff --git a/Tests/Adyen Tests/Analytics/TelemetryTrackerTests.swift b/Tests/Adyen Tests/Analytics/TelemetryTrackerTests.swift index 5e6fcc7f5a..a056d8ce36 100644 --- a/Tests/Adyen Tests/Analytics/TelemetryTrackerTests.swift +++ b/Tests/Adyen Tests/Analytics/TelemetryTrackerTests.swift @@ -30,7 +30,7 @@ class TelemetryTrackerTests: XCTestCase { try super.tearDownWithError() } - private func sendInitialTelemetry(flavor: TelemetryFlavor = .components(type: .achDirectDebit)) { + private func sendInitialAnalytics(flavor: TelemetryFlavor = .components(type: .achDirectDebit)) { sut.sendInitialAnalytics(with: flavor, additionalFields: nil) } @@ -44,7 +44,7 @@ class TelemetryTrackerTests: XCTestCase { let expectedRequestCalls = 0 // When - sendInitialTelemetry() + sendInitialAnalytics() // Then XCTAssertEqual(expectedRequestCalls, apiClient.counter, "One or more telemetry requests were sent.") @@ -59,7 +59,7 @@ class TelemetryTrackerTests: XCTestCase { let expectedRequestCalls = 0 // When - sendInitialTelemetry() + sendInitialAnalytics() // Then XCTAssertEqual(expectedRequestCalls, apiClient.counter, "One or more telemetry requests were sent.") @@ -76,7 +76,7 @@ class TelemetryTrackerTests: XCTestCase { let expectedRequestCalls = 0 // When - sendInitialTelemetry(flavor: flavor) + sendInitialAnalytics(flavor: flavor) // Then XCTAssertEqual(expectedRequestCalls, apiClient.counter, "One or more telemetry requests were sent.") @@ -96,7 +96,7 @@ class TelemetryTrackerTests: XCTestCase { apiClient.mockedResults = [checkoutAttemptIdResult] // When - sendInitialTelemetry(flavor: flavor) + sendInitialAnalytics(flavor: flavor) // Then wait(for: .milliseconds(1)) @@ -117,7 +117,7 @@ class TelemetryTrackerTests: XCTestCase { apiClient.mockedResults = [checkoutAttemptIdResult] // When - sendInitialTelemetry(flavor: flavor) + sendInitialAnalytics(flavor: flavor) // Then wait(for: .milliseconds(1)) diff --git a/Tests/Components Tests/BACS Direct Debit/Mocks/BACSDirectDebitComponentTrackerProtocolMock.swift b/Tests/Components Tests/BACS Direct Debit/Mocks/BACSDirectDebitComponentTrackerProtocolMock.swift index 4fb1097c12..14d611ee64 100644 --- a/Tests/Components Tests/BACS Direct Debit/Mocks/BACSDirectDebitComponentTrackerProtocolMock.swift +++ b/Tests/Components Tests/BACS Direct Debit/Mocks/BACSDirectDebitComponentTrackerProtocolMock.swift @@ -16,7 +16,7 @@ class BACSDirectDebitComponentTrackerProtocolMock: BACSDirectDebitComponentTrack var initialTelemetryEventCallsCount = 0 - func fetchCheckoutAttemptId() { + func sendInitialAnalytics() { initialTelemetryEventCallsCount += 1 } } diff --git a/Tests/Components Tests/BACS Direct Debit/Trackers/BACSDirectDebitComponentTrackerTests.swift b/Tests/Components Tests/BACS Direct Debit/Trackers/BACSDirectDebitComponentTrackerTests.swift index 4b168da402..38f7a3b9ef 100644 --- a/Tests/Components Tests/BACS Direct Debit/Trackers/BACSDirectDebitComponentTrackerTests.swift +++ b/Tests/Components Tests/BACS Direct Debit/Trackers/BACSDirectDebitComponentTrackerTests.swift @@ -33,7 +33,7 @@ class BACSDirectDebitComponentTrackerTests: XCTestCase { func testSendTelemetryEventShouldCallAnalyticsProviderSendTelemetryEvent() throws { // When - sut.fetchCheckoutAttemptId() + sut.sendInitialAnalytics() // Then XCTAssertEqual(analyticsProvider.initialTelemetryEventCallsCount, 1) From 30bc5d6f4e995ff6b768d7f45b036492950545b2 Mon Sep 17 00:00:00 2001 From: erenbesel Date: Fri, 2 Feb 2024 17:09:02 +0100 Subject: [PATCH 09/31] chore: add new environment for analytics --- Adyen.xcodeproj/project.pbxproj | 28 +++++---- .../AnalyticsProvider/AnalyticsProvider.swift | 10 ++-- ...tryTracker.swift => TelemetryFlavor.swift} | 0 ...csRequest.swift => AnalyticsRequest.swift} | 8 +-- ...st.swift => InitialAnalyticsRequest.swift} | 8 +-- .../Core/APIClient/AnalyticsEnvironment.swift | 60 +++++++++++++++++++ Adyen/Core/APIClient/Environment.swift | 3 + Adyen/Core/AdyenContext/AdyenContext.swift | 18 ++++-- .../Core Protocols/PaymentComponent.swift | 2 +- .../Core Protocols/PresentableComponent.swift | 22 +++---- .../BACSDirectDebitComponentTracker.swift | 4 +- AdyenDropIn/DropInComponentExtensions.swift | 4 +- .../Analytics/AnalyticsProviderTests.swift | 38 ++++++------ .../Analytics/TelemetryTrackerTests.swift | 4 +- .../Adyen Tests/Core/AdyenContextTests.swift | 35 +++++++++++ 15 files changed, 177 insertions(+), 67 deletions(-) rename Adyen/Analytics/AnalyticsProvider/{TelemetryTracker.swift => TelemetryFlavor.swift} (100%) rename Adyen/Analytics/Requests/{AdyenAnalyticsRequest.swift => AnalyticsRequest.swift} (76%) rename Adyen/Analytics/Requests/{CheckoutAttemptIdRequest.swift => InitialAnalyticsRequest.swift} (90%) create mode 100644 Adyen/Core/APIClient/AnalyticsEnvironment.swift diff --git a/Adyen.xcodeproj/project.pbxproj b/Adyen.xcodeproj/project.pbxproj index b26903360b..5d0bbf488a 100644 --- a/Adyen.xcodeproj/project.pbxproj +++ b/Adyen.xcodeproj/project.pbxproj @@ -258,6 +258,7 @@ A04E60CD27DFA2BD0051C72C /* SessionAPIClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = A04E60CC27DFA2BD0051C72C /* SessionAPIClient.swift */; }; A04E60D527EDDF4F0051C72C /* AdyenSessionDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = A04E60D427EDDF4F0051C72C /* AdyenSessionDelegate.swift */; }; A04E60DB27F30D900051C72C /* SessionDelegateMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = A04E60DA27F30D900051C72C /* SessionDelegateMock.swift */; }; + A04EA85E2B69509500723F39 /* AnalyticsEnvironment.swift in Sources */ = {isa = PBXBuildFile; fileRef = A04EA85D2B69509500723F39 /* AnalyticsEnvironment.swift */; }; A04F8C2229E5950100F3F62B /* AdyenCashAppPay.docc in Sources */ = {isa = PBXBuildFile; fileRef = A04F8C2129E5950100F3F62B /* AdyenCashAppPay.docc */; }; A04F8C2329E5950100F3F62B /* AdyenCashAppPay.h in Headers */ = {isa = PBXBuildFile; fileRef = A04F8C2029E5950100F3F62B /* AdyenCashAppPay.h */; settings = {ATTRIBUTES = (Public, ); }; }; A04F8C2B29E5957B00F3F62B /* Adyen.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E2C0E03322097917008616F6 /* Adyen.framework */; }; @@ -282,7 +283,7 @@ A0BC64E628F062E400CED2A1 /* AdyenSessionAware.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0BC64E528F062E400CED2A1 /* AdyenSessionAware.swift */; }; A0C9B59B288AE34600D6BDAB /* InstallmentOptions.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0F41E5526CBCA6E0089AD6C /* InstallmentOptions.swift */; }; A0D48FB827109B0200C0B82C /* ArrayHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0D48FB727109B0200C0B82C /* ArrayHelpers.swift */; }; - A0DB48662AFD020400348C83 /* AdyenAnalyticsRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0DB48652AFD020400348C83 /* AdyenAnalyticsRequest.swift */; }; + A0DB48662AFD020400348C83 /* AnalyticsRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0DB48652AFD020400348C83 /* AnalyticsRequest.swift */; }; A0DB48682AFD068400348C83 /* AdyenAnalytics.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0DB48672AFD068400348C83 /* AdyenAnalytics.swift */; }; A0DB486A2AFD0BDC00348C83 /* AdyenAnalyticsInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0DB48692AFD0BDC00348C83 /* AdyenAnalyticsInfo.swift */; }; A0DB486C2AFD0BEE00348C83 /* AdyenAnalyticsLog.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0DB486B2AFD0BEE00348C83 /* AdyenAnalyticsLog.swift */; }; @@ -323,10 +324,10 @@ C98125502851E9E4006D1374 /* PaymentComponentSubjectTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C981254F2851E9E4006D1374 /* PaymentComponentSubjectTests.swift */; }; C982FFD826946F0800AED849 /* AffirmComponent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C982FFD726946F0800AED849 /* AffirmComponent.swift */; }; C982FFDC2694792F00AED849 /* AffirmPaymentMethod.swift in Sources */ = {isa = PBXBuildFile; fileRef = C982FFDB2694792F00AED849 /* AffirmPaymentMethod.swift */; }; - C9B6683527C7CB7A006950B9 /* TelemetryTracker.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9B6683427C7CB7A006950B9 /* TelemetryTracker.swift */; }; + C9B6683527C7CB7A006950B9 /* TelemetryFlavor.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9B6683427C7CB7A006950B9 /* TelemetryFlavor.swift */; }; C9B6683727C8D7FB006950B9 /* TelemetryData.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9B6683627C8D7FB006950B9 /* TelemetryData.swift */; }; C9B6683927C903FE006950B9 /* AdyenContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9B6683827C903FE006950B9 /* AdyenContext.swift */; }; - C9BAE20F27BEA68D002F5728 /* CheckoutAttemptIdRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9BAE20E27BEA68D002F5728 /* CheckoutAttemptIdRequest.swift */; }; + C9BAE20F27BEA68D002F5728 /* InitialAnalyticsRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9BAE20E27BEA68D002F5728 /* InitialAnalyticsRequest.swift */; }; C9BB460427622D9B00E6730B /* BACSConfirmationViewProtocolMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9BB460327622D9B00E6730B /* BACSConfirmationViewProtocolMock.swift */; }; C9BB460627622E9600E6730B /* BACSConfirmationPresenterProtocolMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9BB460527622E9600E6730B /* BACSConfirmationPresenterProtocolMock.swift */; }; C9BB460927622F4100E6730B /* BACSConfirmationPresenterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9BB460827622F4100E6730B /* BACSConfirmationPresenterTests.swift */; }; @@ -1503,6 +1504,7 @@ A04E60D227E0E6280051C72C /* XCTestCase+Result.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "XCTestCase+Result.swift"; sourceTree = ""; }; A04E60D427EDDF4F0051C72C /* AdyenSessionDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdyenSessionDelegate.swift; sourceTree = ""; }; A04E60DA27F30D900051C72C /* SessionDelegateMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionDelegateMock.swift; sourceTree = ""; }; + A04EA85D2B69509500723F39 /* AnalyticsEnvironment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnalyticsEnvironment.swift; sourceTree = ""; }; A04F8C1E29E5950100F3F62B /* AdyenCashAppPay.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = AdyenCashAppPay.framework; sourceTree = BUILT_PRODUCTS_DIR; }; A04F8C2029E5950100F3F62B /* AdyenCashAppPay.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AdyenCashAppPay.h; sourceTree = ""; }; A04F8C2129E5950100F3F62B /* AdyenCashAppPay.docc */ = {isa = PBXFileReference; lastKnownFileType = folder.documentationcatalog; path = AdyenCashAppPay.docc; sourceTree = ""; }; @@ -1523,7 +1525,7 @@ A0B180302A2DE445003C608E /* MealVoucherDetails.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MealVoucherDetails.swift; sourceTree = ""; }; A0BC64E528F062E400CED2A1 /* AdyenSessionAware.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdyenSessionAware.swift; sourceTree = ""; }; A0D48FB727109B0200C0B82C /* ArrayHelpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArrayHelpers.swift; sourceTree = ""; }; - A0DB48652AFD020400348C83 /* AdyenAnalyticsRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdyenAnalyticsRequest.swift; sourceTree = ""; }; + A0DB48652AFD020400348C83 /* AnalyticsRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnalyticsRequest.swift; sourceTree = ""; }; A0DB48672AFD068400348C83 /* AdyenAnalytics.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdyenAnalytics.swift; sourceTree = ""; }; A0DB48692AFD0BDC00348C83 /* AdyenAnalyticsInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdyenAnalyticsInfo.swift; sourceTree = ""; }; A0DB486B2AFD0BEE00348C83 /* AdyenAnalyticsLog.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdyenAnalyticsLog.swift; sourceTree = ""; }; @@ -1563,10 +1565,10 @@ C981254F2851E9E4006D1374 /* PaymentComponentSubjectTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PaymentComponentSubjectTests.swift; sourceTree = ""; }; C982FFD726946F0800AED849 /* AffirmComponent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AffirmComponent.swift; sourceTree = ""; }; C982FFDB2694792F00AED849 /* AffirmPaymentMethod.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AffirmPaymentMethod.swift; sourceTree = ""; }; - C9B6683427C7CB7A006950B9 /* TelemetryTracker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TelemetryTracker.swift; sourceTree = ""; }; + C9B6683427C7CB7A006950B9 /* TelemetryFlavor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TelemetryFlavor.swift; sourceTree = ""; }; C9B6683627C8D7FB006950B9 /* TelemetryData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TelemetryData.swift; sourceTree = ""; }; C9B6683827C903FE006950B9 /* AdyenContext.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdyenContext.swift; sourceTree = ""; }; - C9BAE20E27BEA68D002F5728 /* CheckoutAttemptIdRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CheckoutAttemptIdRequest.swift; sourceTree = ""; }; + C9BAE20E27BEA68D002F5728 /* InitialAnalyticsRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InitialAnalyticsRequest.swift; sourceTree = ""; }; C9BB460327622D9B00E6730B /* BACSConfirmationViewProtocolMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BACSConfirmationViewProtocolMock.swift; sourceTree = ""; }; C9BB460527622E9600E6730B /* BACSConfirmationPresenterProtocolMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BACSConfirmationPresenterProtocolMock.swift; sourceTree = ""; }; C9BB460827622F4100E6730B /* BACSConfirmationPresenterTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BACSConfirmationPresenterTests.swift; sourceTree = ""; }; @@ -3020,7 +3022,7 @@ isa = PBXGroup; children = ( C94632BD27BA6985003DD81F /* AnalyticsProvider.swift */, - C9B6683427C7CB7A006950B9 /* TelemetryTracker.swift */, + C9B6683427C7CB7A006950B9 /* TelemetryFlavor.swift */, ); path = AnalyticsProvider; sourceTree = ""; @@ -3123,8 +3125,8 @@ C9CA0B68282E7E4A00C4E9C2 /* Requests */ = { isa = PBXGroup; children = ( - C9BAE20E27BEA68D002F5728 /* CheckoutAttemptIdRequest.swift */, - A0DB48652AFD020400348C83 /* AdyenAnalyticsRequest.swift */, + C9BAE20E27BEA68D002F5728 /* InitialAnalyticsRequest.swift */, + A0DB48652AFD020400348C83 /* AnalyticsRequest.swift */, ); path = Requests; sourceTree = ""; @@ -4854,6 +4856,7 @@ E7B6280724ED65D2000CEC6E /* Requests */, E90933FE228AFC6600C9F04B /* Environment.swift */, 5A4702172664E9440023F264 /* APIContext.swift */, + A04EA85D2B69509500723F39 /* AnalyticsEnvironment.swift */, ); path = APIClient; sourceTree = ""; @@ -6518,7 +6521,7 @@ F9A6C41D26550B7100D8CD3E /* AlreadyPaidPaymentComponent.swift in Sources */, F9D644E024D2E4210059CBE3 /* EmailValidator.swift in Sources */, F9639B3324DD96990073F38A /* PaymentStatusRequest.swift in Sources */, - A0DB48662AFD020400348C83 /* AdyenAnalyticsRequest.swift in Sources */, + A0DB48662AFD020400348C83 /* AnalyticsRequest.swift in Sources */, 5AD40E75262F04440090E01C /* UIProgressViewHelpers.swift in Sources */, F91664F023E41D7300C10738 /* AnyEncodable.swift in Sources */, E7D531192446F525000046B4 /* FormSeparatorItemView.swift in Sources */, @@ -6532,8 +6535,9 @@ E28098B3220DA7980087928F /* Component.swift in Sources */, F95B6D8E25231715002C9062 /* RegularExpressionValidator.swift in Sources */, 002B93082951F120000B93F4 /* FormSegmentedControlItem.swift in Sources */, - C9B6683527C7CB7A006950B9 /* TelemetryTracker.swift in Sources */, - C9BAE20F27BEA68D002F5728 /* CheckoutAttemptIdRequest.swift in Sources */, + A04EA85E2B69509500723F39 /* AnalyticsEnvironment.swift in Sources */, + C9B6683527C7CB7A006950B9 /* TelemetryFlavor.swift in Sources */, + C9BAE20F27BEA68D002F5728 /* InitialAnalyticsRequest.swift in Sources */, F926D52023F4217A00D058D3 /* DeviceDependent.swift in Sources */, F9A6C4BB2657AFF600D8CD3E /* FormSpacerItem.swift in Sources */, 00346FC429895B6A00F7DA94 /* ModalToolbar.swift in Sources */, diff --git a/Adyen/Analytics/AnalyticsProvider/AnalyticsProvider.swift b/Adyen/Analytics/AnalyticsProvider/AnalyticsProvider.swift index 9ca4638e0a..6644c5f27a 100644 --- a/Adyen/Analytics/AnalyticsProvider/AnalyticsProvider.swift +++ b/Adyen/Analytics/AnalyticsProvider/AnalyticsProvider.swift @@ -57,7 +57,7 @@ internal final class AnalyticsProvider: AnalyticsProviderProtocol { internal let apiClient: APIClientProtocol internal let configuration: AnalyticsConfiguration internal private(set) var checkoutAttemptId: String? - private let uniqueAssetAPIClient: UniqueAssetAPIClient + private let uniqueAssetAPIClient: UniqueAssetAPIClient private var batchTimer: Timer? @@ -73,7 +73,7 @@ internal final class AnalyticsProvider: AnalyticsProviderProtocol { ) { self.apiClient = apiClient self.configuration = configuration - self.uniqueAssetAPIClient = UniqueAssetAPIClient(apiClient: apiClient) + self.uniqueAssetAPIClient = UniqueAssetAPIClient(apiClient: apiClient) } // MARK: - Internal @@ -89,9 +89,9 @@ internal final class AnalyticsProvider: AnalyticsProviderProtocol { additionalFields: additionalFields, context: configuration.context) - let checkoutAttemptIdRequest = CheckoutAttemptIdRequest(data: telemetryData) + let initialAnalyticsRequest = InitialAnalyticsRequest(data: telemetryData) - uniqueAssetAPIClient.perform(checkoutAttemptIdRequest) { [weak self] result in + uniqueAssetAPIClient.perform(initialAnalyticsRequest) { [weak self] result in switch result { case let .success(response): self?.checkoutAttemptId = response.identifier @@ -123,7 +123,7 @@ internal final class AnalyticsProvider: AnalyticsProviderProtocol { @objc private func sendAll() { guard configuration.isEnabled, let checkoutAttemptId else { return } - var request = AdyenAnalyticsRequest(checkoutAttemptId: checkoutAttemptId) + var request = AnalyticsRequest(checkoutAttemptId: checkoutAttemptId) request.infos = infos request.logs = logs diff --git a/Adyen/Analytics/AnalyticsProvider/TelemetryTracker.swift b/Adyen/Analytics/AnalyticsProvider/TelemetryFlavor.swift similarity index 100% rename from Adyen/Analytics/AnalyticsProvider/TelemetryTracker.swift rename to Adyen/Analytics/AnalyticsProvider/TelemetryFlavor.swift diff --git a/Adyen/Analytics/Requests/AdyenAnalyticsRequest.swift b/Adyen/Analytics/Requests/AnalyticsRequest.swift similarity index 76% rename from Adyen/Analytics/Requests/AdyenAnalyticsRequest.swift rename to Adyen/Analytics/Requests/AnalyticsRequest.swift index b6354c4554..7dc88d502c 100644 --- a/Adyen/Analytics/Requests/AdyenAnalyticsRequest.swift +++ b/Adyen/Analytics/Requests/AnalyticsRequest.swift @@ -7,11 +7,11 @@ import AdyenNetworking import Foundation -internal struct AdyenAnalyticsResponse: Response { /* Empty response */ } +internal struct AnalyticsResponse: Response { /* Empty response */ } -internal struct AdyenAnalyticsRequest: APIRequest { +internal struct AnalyticsRequest: APIRequest { - internal typealias ResponseType = AdyenAnalyticsResponse + internal typealias ResponseType = AnalyticsResponse internal let path: String @@ -32,7 +32,7 @@ internal struct AdyenAnalyticsRequest: APIRequest { internal var errors: [AdyenAnalytics.Error] = [] internal init(checkoutAttemptId: String) { - self.path = "/checkoutanalytics/v3/analytics/\(checkoutAttemptId)" + self.path = "checkoutanalytics/v3/analytics/\(checkoutAttemptId)" } private enum CodingKeys: String, CodingKey { diff --git a/Adyen/Analytics/Requests/CheckoutAttemptIdRequest.swift b/Adyen/Analytics/Requests/InitialAnalyticsRequest.swift similarity index 90% rename from Adyen/Analytics/Requests/CheckoutAttemptIdRequest.swift rename to Adyen/Analytics/Requests/InitialAnalyticsRequest.swift index ed7963776d..b2f556d1cf 100644 --- a/Adyen/Analytics/Requests/CheckoutAttemptIdRequest.swift +++ b/Adyen/Analytics/Requests/InitialAnalyticsRequest.swift @@ -7,7 +7,7 @@ import AdyenNetworking import Foundation -internal struct CheckoutAttemptIdResponse: Response { +internal struct InitialAnalyticsResponse: Response { // MARK: - Properties @@ -18,11 +18,11 @@ internal struct CheckoutAttemptIdResponse: Response { } } -internal struct CheckoutAttemptIdRequest: APIRequest { +internal struct InitialAnalyticsRequest: APIRequest { - internal typealias ResponseType = CheckoutAttemptIdResponse + internal typealias ResponseType = InitialAnalyticsResponse - internal let path: String = "/checkoutanalytics/v3/analytics" + internal let path: String = "checkoutanalytics/v3/analytics" internal var counter: UInt = 0 diff --git a/Adyen/Core/APIClient/AnalyticsEnvironment.swift b/Adyen/Core/APIClient/AnalyticsEnvironment.swift new file mode 100644 index 0000000000..60692d0c96 --- /dev/null +++ b/Adyen/Core/APIClient/AnalyticsEnvironment.swift @@ -0,0 +1,60 @@ +// +// Copyright (c) 2024 Adyen N.V. +// +// This file is open source and available under the MIT license. See the LICENSE file for more info. +// + +import AdyenNetworking +import Foundation + +/// Enum that defines the analytics environment URLs.. +@_spi(AdyenInternal) +public enum AnalyticsEnvironment: String, AnyAPIEnvironment { + + case test = "https://checkoutanalytics-test.adyen.com/" + + case liveEurope = "https://checkoutanalytics-live.adyen.com/" + + case liveAustralia = "https://checkoutanalytics-live-au.adyen.com/" + + case liveUnitedStates = "https://checkoutanalytics-live-us.adyen.com/" + + case liveApse = "https://checkoutanalytics-live-apse.adyen.com/" + + case liveIndia = "https://checkoutanalytics-live-in.adyen.com/" + + @_spi(AdyenInternal) + case beta = "https://beta.adyen.com/checkoutanalytics/v3/analytics/" + + @_spi(AdyenInternal) + case local = "http://localhost:8080/" + + public var baseURL: URL { URL(string: rawValue)! } + +} + +extension Environment { + + internal func toAnalyticsEnvironment() -> AnalyticsEnvironment { + switch self { + case .beta: + return .beta + case .test: + return .test + case .liveApse: + return .liveApse + case .liveIndia: + return .liveIndia + case .liveEurope: + return .liveEurope + case .liveAustralia: + return .liveAustralia + case .liveUnitedStates: + return .liveUnitedStates + case .local: + return .local + default: + return .test + } + } +} diff --git a/Adyen/Core/APIClient/Environment.swift b/Adyen/Core/APIClient/Environment.swift index 96ecd904e8..4e3f8d349e 100644 --- a/Adyen/Core/APIClient/Environment.swift +++ b/Adyen/Core/APIClient/Environment.swift @@ -59,3 +59,6 @@ public struct Environment: AnyAPIEnvironment { } } + +@_spi(AdyenInternal) +extension Environment: Equatable {} diff --git a/Adyen/Core/AdyenContext/AdyenContext.swift b/Adyen/Core/AdyenContext/AdyenContext.swift index f6d160f66d..eaccefbdcc 100644 --- a/Adyen/Core/AdyenContext/AdyenContext.swift +++ b/Adyen/Core/AdyenContext/AdyenContext.swift @@ -19,7 +19,7 @@ public final class AdyenContext: PaymentAware { public private(set) var payment: Payment? @_spi(AdyenInternal) - public let analyticsProvider: AnalyticsProviderProtocol + public let analyticsProvider: AnalyticsProviderProtocol? // MARK: - Initializers @@ -30,10 +30,16 @@ public final class AdyenContext: PaymentAware { /// - payment: The payment information. public convenience init(apiContext: APIContext, payment: Payment?, analyticsConfiguration: AnalyticsConfiguration = .init()) { - let analyticsProvider = AnalyticsProvider( - apiClient: APIClient(apiContext: apiContext), - configuration: analyticsConfiguration - ) + var analyticsProvider: AnalyticsProviderProtocol? + if let analyticsEnvironment = (apiContext.environment as? Environment)?.toAnalyticsEnvironment(), + let analyticsApiContext = try? APIContext(environment: analyticsEnvironment, + clientKey: apiContext.clientKey) { + + analyticsProvider = AnalyticsProvider( + apiClient: APIClient(apiContext: analyticsApiContext), + configuration: analyticsConfiguration + ) + } self.init( apiContext: apiContext, @@ -45,7 +51,7 @@ public final class AdyenContext: PaymentAware { /// Internal init for testing only internal init(apiContext: APIContext, payment: Payment?, - analyticsProvider: AnalyticsProviderProtocol) { + analyticsProvider: AnalyticsProviderProtocol?) { self.apiContext = apiContext self.analyticsProvider = analyticsProvider self.payment = payment diff --git a/Adyen/Core/Core Protocols/PaymentComponent.swift b/Adyen/Core/Core Protocols/PaymentComponent.swift index 218fe3c68a..03f179fb44 100644 --- a/Adyen/Core/Core Protocols/PaymentComponent.swift +++ b/Adyen/Core/Core Protocols/PaymentComponent.swift @@ -32,7 +32,7 @@ extension PaymentComponent { public func submit(data: PaymentComponentData, component: PaymentComponent? = nil) { let component = component ?? self - let updatedData = data.replacing(checkoutAttemptId: component.context.analyticsProvider.checkoutAttemptId) + let updatedData = data.replacing(checkoutAttemptId: component.context.analyticsProvider?.checkoutAttemptId) guard updatedData.browserInfo == nil else { delegate?.didSubmit(updatedData, from: component) diff --git a/Adyen/Core/Core Protocols/PresentableComponent.swift b/Adyen/Core/Core Protocols/PresentableComponent.swift index 96b6b9b9f8..c0747d51c6 100644 --- a/Adyen/Core/Core Protocols/PresentableComponent.swift +++ b/Adyen/Core/Core Protocols/PresentableComponent.swift @@ -67,21 +67,23 @@ public protocol TrackableComponent: Component { } @_spi(AdyenInternal) -extension TrackableComponent where Self: PaymentMethodAware { +extension TrackableComponent where Self: ViewControllerDelegate { - public func sendInitialAnalytics() { - let flavor: TelemetryFlavor = _isDropIn ? .dropInComponent : .components(type: paymentMethod.type) - let amount = context.payment?.amount - let additionalFields = AdditionalAnalyticsFields(amount: amount, sessionId: AdyenAnalytics.sessionId) - context.analyticsProvider.sendInitialAnalytics(with: flavor, - additionalFields: additionalFields) + public func viewWillAppear(viewController: UIViewController) { + // initial call is not needed again if inside dropIn +// guard !_isDropIn else { return } + sendInitialAnalytics() } } @_spi(AdyenInternal) -extension TrackableComponent where Self: ViewControllerDelegate { +extension TrackableComponent where Self: PaymentMethodAware { - public func viewWillAppear(viewController: UIViewController) { - sendInitialAnalytics() + public func sendInitialAnalytics() { + let flavor: TelemetryFlavor = .components(type: paymentMethod.type) + let amount = context.payment?.amount + let additionalFields = AdditionalAnalyticsFields(amount: amount, sessionId: AdyenAnalytics.sessionId) + context.analyticsProvider?.sendInitialAnalytics(with: flavor, + additionalFields: additionalFields) } } diff --git a/AdyenComponents/BACS Direct Debit/Trackers/BACSDirectDebitComponentTracker.swift b/AdyenComponents/BACS Direct Debit/Trackers/BACSDirectDebitComponentTracker.swift index c725362eb6..2cb168a87e 100644 --- a/AdyenComponents/BACS Direct Debit/Trackers/BACSDirectDebitComponentTracker.swift +++ b/AdyenComponents/BACS Direct Debit/Trackers/BACSDirectDebitComponentTracker.swift @@ -32,10 +32,10 @@ internal class BACSDirectDebitComponentTracker: BACSDirectDebitComponentTrackerP // MARK: - BACSDirectDebitComponentTrackerProtocol internal func sendInitialAnalytics() { - let flavor: TelemetryFlavor = isDropIn ? .dropInComponent : .components(type: paymentMethod.type) + let flavor: TelemetryFlavor = .components(type: paymentMethod.type) let amount = context.payment?.amount let additionalFields = AdditionalAnalyticsFields(amount: amount, sessionId: AdyenAnalytics.sessionId) - context.analyticsProvider.sendInitialAnalytics(with: flavor, + context.analyticsProvider?.sendInitialAnalytics(with: flavor, additionalFields: additionalFields) } diff --git a/AdyenDropIn/DropInComponentExtensions.swift b/AdyenDropIn/DropInComponentExtensions.swift index fe39800394..eb93b7d015 100644 --- a/AdyenDropIn/DropInComponentExtensions.swift +++ b/AdyenDropIn/DropInComponentExtensions.swift @@ -25,7 +25,7 @@ extension DropInComponent: PaymentMethodListComponentDelegate { let flavor = TelemetryFlavor.dropIn(paymentMethods: paymentMethodTypes) let amount = context.payment?.amount let additionalFields = AdditionalAnalyticsFields(amount: amount, sessionId: AdyenAnalytics.sessionId) - context.analyticsProvider.sendInitialAnalytics(with: flavor, additionalFields: additionalFields) + context.analyticsProvider?.sendInitialAnalytics(with: flavor, additionalFields: additionalFields) } internal func didSelect(_ component: PaymentComponent, @@ -55,7 +55,7 @@ extension DropInComponent: PaymentComponentDelegate { public func didSubmit(_ data: PaymentComponentData, from component: PaymentComponent) { paymentInProgress = true - let updatedData = data.replacing(checkoutAttemptId: component.context.analyticsProvider.checkoutAttemptId) + let updatedData = data.replacing(checkoutAttemptId: component.context.analyticsProvider?.checkoutAttemptId) guard updatedData.browserInfo == nil else { self.delegate?.didSubmit(updatedData, from: component, in: self) diff --git a/Tests/Adyen Tests/Analytics/AnalyticsProviderTests.swift b/Tests/Adyen Tests/Analytics/AnalyticsProviderTests.swift index c6779f2268..38211e1dbe 100644 --- a/Tests/Adyen Tests/Analytics/AnalyticsProviderTests.swift +++ b/Tests/Adyen Tests/Analytics/AnalyticsProviderTests.swift @@ -32,8 +32,8 @@ class AnalyticsProviderTests: XCTestCase { let expectedCheckoutAttemptId = checkoutAttemptIdMockValue - let checkoutAttemptIdResponse = CheckoutAttemptIdResponse(identifier: expectedCheckoutAttemptId) - let checkoutAttemptIdResult: Result = .success(checkoutAttemptIdResponse) + let initialAnalyticsResponse = InitialAnalyticsResponse(identifier: expectedCheckoutAttemptId) + let checkoutAttemptIdResult: Result = .success(initialAnalyticsResponse) apiClient.mockedResults = [checkoutAttemptIdResult] // When @@ -64,8 +64,8 @@ class AnalyticsProviderTests: XCTestCase { let expectedCheckoutAttemptId = checkoutAttemptIdMockValue - let checkoutAttemptIdResponse = CheckoutAttemptIdResponse(identifier: expectedCheckoutAttemptId) - let checkoutAttemptIdResult: Result = .success(checkoutAttemptIdResponse) + let initialAnalyticsResponse = InitialAnalyticsResponse(identifier: expectedCheckoutAttemptId) + let checkoutAttemptIdResult: Result = .success(initialAnalyticsResponse) apiClient.mockedResults = [checkoutAttemptIdResult] // When @@ -103,8 +103,8 @@ class AnalyticsProviderTests: XCTestCase { let expectedCheckoutAttemptId = checkoutAttemptIdMockValue - let checkoutAttemptIdResponse = CheckoutAttemptIdResponse(identifier: expectedCheckoutAttemptId) - let checkoutAttemptIdResult: Result = .success(checkoutAttemptIdResponse) + let initialAnalyticsResponse = InitialAnalyticsResponse(identifier: expectedCheckoutAttemptId) + let checkoutAttemptIdResult: Result = .success(initialAnalyticsResponse) apiClient.mockedResults = [checkoutAttemptIdResult] // When @@ -122,8 +122,8 @@ class AnalyticsProviderTests: XCTestCase { let apiClient = APIClientMock() let sut = AnalyticsProvider(apiClient: apiClient, configuration: analyticsConfiguration) - let checkoutAttemptIdResponse = CheckoutAttemptIdResponse(identifier: checkoutAttemptIdMockValue) - let checkoutAttemptIdResult: Result = .success(checkoutAttemptIdResponse) + let initialAnalyticsResponse = InitialAnalyticsResponse(identifier: checkoutAttemptIdMockValue) + let checkoutAttemptIdResult: Result = .success(initialAnalyticsResponse) apiClient.mockedResults = [checkoutAttemptIdResult] // When @@ -141,13 +141,13 @@ class AnalyticsProviderTests: XCTestCase { let apiClient = APIClientMock() apiClient.mockedResults = [ - .success(CheckoutAttemptIdResponse(identifier: checkoutAttemptId)), + .success(InitialAnalyticsResponse(identifier: checkoutAttemptId)), ] apiClient.onExecute = { request in - if let checkoutAttemptIdRequest = request as? CheckoutAttemptIdRequest { - XCTAssertNil(checkoutAttemptIdRequest.amount) - XCTAssertEqual(checkoutAttemptIdRequest.version, adyenSdkVersion) - XCTAssertEqual(checkoutAttemptIdRequest.platform, "ios") + if let initialAnalyticsdRequest = request as? InitialAnalyticsRequest { + XCTAssertNil(initialAnalyticsdRequest.amount) + XCTAssertEqual(initialAnalyticsdRequest.version, adyenSdkVersion) + XCTAssertEqual(initialAnalyticsdRequest.platform, "ios") telemetryExpectation.fulfill() } } @@ -175,13 +175,13 @@ class AnalyticsProviderTests: XCTestCase { let apiClient = APIClientMock() apiClient.mockedResults = [ - .success(CheckoutAttemptIdResponse(identifier: checkoutAttemptId)) + .success(InitialAnalyticsResponse(identifier: checkoutAttemptId)) ] apiClient.onExecute = { request in - if let checkoutAttemptIdRequest = request as? CheckoutAttemptIdRequest { - XCTAssertEqual(checkoutAttemptIdRequest.amount, amount) - XCTAssertEqual(checkoutAttemptIdRequest.version, "version") - XCTAssertEqual(checkoutAttemptIdRequest.platform, "react-native") + if let initialAnalyticsdRequest = request as? InitialAnalyticsRequest { + XCTAssertEqual(initialAnalyticsdRequest.amount, amount) + XCTAssertEqual(initialAnalyticsdRequest.version, "version") + XCTAssertEqual(initialAnalyticsdRequest.platform, "react-native") telemetryExpectation.fulfill() } } @@ -207,7 +207,7 @@ class AnalyticsProviderTests: XCTestCase { additionalFields: AdditionalAnalyticsFields(amount: .init(value: 1, currencyCode: "EUR")), context: TelemetryContext(version: "version", platform: .flutter)) - let request = CheckoutAttemptIdRequest(data: telemetryData) + let request = InitialAnalyticsRequest(data: telemetryData) let encodedRequest = try JSONEncoder().encode(request) let decodedRequest = try XCTUnwrap(JSONSerialization.jsonObject(with: encodedRequest) as? [String: Any]) diff --git a/Tests/Adyen Tests/Analytics/TelemetryTrackerTests.swift b/Tests/Adyen Tests/Analytics/TelemetryTrackerTests.swift index a056d8ce36..f6dce00702 100644 --- a/Tests/Adyen Tests/Analytics/TelemetryTrackerTests.swift +++ b/Tests/Adyen Tests/Analytics/TelemetryTrackerTests.swift @@ -18,7 +18,7 @@ class TelemetryTrackerTests: XCTestCase { override func setUpWithError() throws { try super.setUpWithError() apiClient = APIClientMock() - let checkoutAttemptIdResponse = CheckoutAttemptIdResponse(identifier: "checkoutAttempId1") + let checkoutAttemptIdResponse = InitialAnalyticsResponse(identifier: "checkoutAttempId1") let checkoutAttemptIdResult: Result = .success(checkoutAttemptIdResponse) apiClient.mockedResults = [checkoutAttemptIdResult] sut = AnalyticsProvider(apiClient: apiClient, configuration: .init()) @@ -126,7 +126,7 @@ class TelemetryTrackerTests: XCTestCase { // MARK: - Private - private var checkoutAttemptIdResponse: CheckoutAttemptIdResponse { + private var checkoutAttemptIdResponse: InitialAnalyticsResponse { .init(identifier: "cb3eef98-978e-4f6f-b299-937a4450be1f1648546838056be73d8f38ee8bcc3a65ec14e41b037a59f255dcd9e83afe8c06bd3e7abcad993") } } diff --git a/Tests/Adyen Tests/Core/AdyenContextTests.swift b/Tests/Adyen Tests/Core/AdyenContextTests.swift index 915d7a5cdb..7cdfad7dbb 100644 --- a/Tests/Adyen Tests/Core/AdyenContextTests.swift +++ b/Tests/Adyen Tests/Core/AdyenContextTests.swift @@ -6,6 +6,7 @@ @testable @_spi(AdyenInternal) import Adyen @testable import AdyenEncryption +@testable import AdyenNetworking import XCTest class AdyenContextTests: XCTestCase { @@ -25,4 +26,38 @@ class AdyenContextTests: XCTestCase { context.update(payment: Payment(amount: twoEUR, countryCode: "NL")) XCTAssertEqual(context.payment?.amount, twoEUR) } + + func testPublicInit() { + let context = AdyenContext(apiContext: Dummy.apiContext, payment: Dummy.payment) + + XCTAssertEqual(context.payment?.amount, Dummy.payment.amount) + XCTAssertEqual(context.apiContext.clientKey, Dummy.apiContext.clientKey) + } + + func testInternalInit() { + let context = AdyenContext(apiContext: Dummy.apiContext, payment: Dummy.payment, analyticsProvider: AnalyticsProviderMock()) + + XCTAssertEqual(context.payment?.amount, Dummy.payment.amount) + XCTAssertEqual(context.apiContext.clientKey, Dummy.apiContext.clientKey) + XCTAssertNotNil(context.analyticsProvider) + } + + func testInitWithRegularEnvironmentShouldHaveAnalyticsProvider() { + let context = AdyenContext(apiContext: Dummy.apiContext, payment: Dummy.payment) + + XCTAssertNotNil(context.analyticsProvider) + } + + func testInitWithDifferentEnvironmentShouldNotHaveAnalyticsProvider() { + let apiContext = try! APIContext(environment: TestEnvironment.test, clientKey: "local_DUMMYKEYFORTESTING") + + let context = AdyenContext(apiContext: apiContext, payment: Dummy.payment) + XCTAssertNil(context.analyticsProvider) + } +} + +enum TestEnvironment: AnyAPIEnvironment { + case test + + var baseURL: URL { URL(string: "test")! } } From da8fe5373d3bc8d5f3fdadcb855b3142c38664bb Mon Sep 17 00:00:00 2001 From: erenbesel Date: Mon, 5 Feb 2024 15:01:26 +0100 Subject: [PATCH 10/31] chore: dont send inital call if dropin --- Adyen/Core/Core Protocols/PresentableComponent.swift | 4 ++-- .../Trackers/BACSDirectDebitComponentTracker.swift | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Adyen/Core/Core Protocols/PresentableComponent.swift b/Adyen/Core/Core Protocols/PresentableComponent.swift index c0747d51c6..c3478c607c 100644 --- a/Adyen/Core/Core Protocols/PresentableComponent.swift +++ b/Adyen/Core/Core Protocols/PresentableComponent.swift @@ -70,8 +70,6 @@ public protocol TrackableComponent: Component { extension TrackableComponent where Self: ViewControllerDelegate { public func viewWillAppear(viewController: UIViewController) { - // initial call is not needed again if inside dropIn -// guard !_isDropIn else { return } sendInitialAnalytics() } } @@ -80,6 +78,8 @@ extension TrackableComponent where Self: ViewControllerDelegate { extension TrackableComponent where Self: PaymentMethodAware { public func sendInitialAnalytics() { + // initial call is not needed again if inside dropIn + guard !_isDropIn else { return } let flavor: TelemetryFlavor = .components(type: paymentMethod.type) let amount = context.payment?.amount let additionalFields = AdditionalAnalyticsFields(amount: amount, sessionId: AdyenAnalytics.sessionId) diff --git a/AdyenComponents/BACS Direct Debit/Trackers/BACSDirectDebitComponentTracker.swift b/AdyenComponents/BACS Direct Debit/Trackers/BACSDirectDebitComponentTracker.swift index 2cb168a87e..78ff9fd423 100644 --- a/AdyenComponents/BACS Direct Debit/Trackers/BACSDirectDebitComponentTracker.swift +++ b/AdyenComponents/BACS Direct Debit/Trackers/BACSDirectDebitComponentTracker.swift @@ -32,6 +32,8 @@ internal class BACSDirectDebitComponentTracker: BACSDirectDebitComponentTrackerP // MARK: - BACSDirectDebitComponentTrackerProtocol internal func sendInitialAnalytics() { + // initial call is not needed again if inside dropIn + guard !isDropIn else { return } let flavor: TelemetryFlavor = .components(type: paymentMethod.type) let amount = context.payment?.amount let additionalFields = AdditionalAnalyticsFields(amount: amount, sessionId: AdyenAnalytics.sessionId) From 147b20fb4e15c44d5f21fa901e6f5d28bef69fd2 Mon Sep 17 00:00:00 2001 From: erenbesel Date: Tue, 6 Feb 2024 16:54:30 +0100 Subject: [PATCH 11/31] chore: adding component load event --- Adyen.xcodeproj/project.pbxproj | 24 ++++++------ .../AnalyticsProvider/AnalyticsProvider.swift | 25 +++++++----- Adyen/Analytics/Models/AdyenAnalytics.swift | 30 +++++++------- .../Models/AdyenAnalyticsError.swift | 32 --------------- .../Analytics/Models/AdyenAnalyticsInfo.swift | 35 ----------------- .../Analytics/Models/AdyenAnalyticsLog.swift | 39 ------------------- .../Models/AnalyticsEventError.swift | 30 ++++++++++++++ .../Analytics/Models/AnalyticsEventInfo.swift | 34 ++++++++++++++++ .../Analytics/Models/AnalyticsEventLog.swift | 39 +++++++++++++++++++ .../Analytics/Requests/AnalyticsRequest.swift | 6 +-- .../Requests/InitialAnalyticsRequest.swift | 4 +- .../Core Protocols/PresentableComponent.swift | 12 +++++- .../BACSDirectDebitComponentTracker.swift | 2 +- AdyenDropIn/DropInComponentExtensions.swift | 2 +- AdyenSession/AdyenSession.swift | 2 +- .../Analytics/AnalyticsProviderTests.swift | 12 +++--- .../Analytics/TelemetryTrackerTests.swift | 4 +- Tests/Session Tests/SessionTests.swift | 2 +- 18 files changed, 176 insertions(+), 158 deletions(-) delete mode 100644 Adyen/Analytics/Models/AdyenAnalyticsError.swift delete mode 100644 Adyen/Analytics/Models/AdyenAnalyticsInfo.swift delete mode 100644 Adyen/Analytics/Models/AdyenAnalyticsLog.swift create mode 100644 Adyen/Analytics/Models/AnalyticsEventError.swift create mode 100644 Adyen/Analytics/Models/AnalyticsEventInfo.swift create mode 100644 Adyen/Analytics/Models/AnalyticsEventLog.swift diff --git a/Adyen.xcodeproj/project.pbxproj b/Adyen.xcodeproj/project.pbxproj index 5d0bbf488a..a953fffcff 100644 --- a/Adyen.xcodeproj/project.pbxproj +++ b/Adyen.xcodeproj/project.pbxproj @@ -285,9 +285,9 @@ A0D48FB827109B0200C0B82C /* ArrayHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0D48FB727109B0200C0B82C /* ArrayHelpers.swift */; }; A0DB48662AFD020400348C83 /* AnalyticsRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0DB48652AFD020400348C83 /* AnalyticsRequest.swift */; }; A0DB48682AFD068400348C83 /* AdyenAnalytics.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0DB48672AFD068400348C83 /* AdyenAnalytics.swift */; }; - A0DB486A2AFD0BDC00348C83 /* AdyenAnalyticsInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0DB48692AFD0BDC00348C83 /* AdyenAnalyticsInfo.swift */; }; - A0DB486C2AFD0BEE00348C83 /* AdyenAnalyticsLog.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0DB486B2AFD0BEE00348C83 /* AdyenAnalyticsLog.swift */; }; - A0DB486E2AFD0BFC00348C83 /* AdyenAnalyticsError.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0DB486D2AFD0BFC00348C83 /* AdyenAnalyticsError.swift */; }; + A0DB486A2AFD0BDC00348C83 /* AnalyticsEventInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0DB48692AFD0BDC00348C83 /* AnalyticsEventInfo.swift */; }; + A0DB486C2AFD0BEE00348C83 /* AnalyticsEventLog.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0DB486B2AFD0BEE00348C83 /* AnalyticsEventLog.swift */; }; + A0DB486E2AFD0BFC00348C83 /* AnalyticsEventError.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0DB486D2AFD0BFC00348C83 /* AnalyticsEventError.swift */; }; A0DDA6A72A6162F500EBD6AF /* AdyenSessionResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0DDA6A62A6162F500EBD6AF /* AdyenSessionResult.swift */; }; A0DE8F6D26CEA04500F2F1E8 /* Installments.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0DE8F6C26CEA04500F2F1E8 /* Installments.swift */; }; A0F41EAC26CD4AA50089AD6C /* FormCardInstallmentsItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0F41EAB26CD4AA50089AD6C /* FormCardInstallmentsItem.swift */; }; @@ -1527,9 +1527,9 @@ A0D48FB727109B0200C0B82C /* ArrayHelpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArrayHelpers.swift; sourceTree = ""; }; A0DB48652AFD020400348C83 /* AnalyticsRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnalyticsRequest.swift; sourceTree = ""; }; A0DB48672AFD068400348C83 /* AdyenAnalytics.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdyenAnalytics.swift; sourceTree = ""; }; - A0DB48692AFD0BDC00348C83 /* AdyenAnalyticsInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdyenAnalyticsInfo.swift; sourceTree = ""; }; - A0DB486B2AFD0BEE00348C83 /* AdyenAnalyticsLog.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdyenAnalyticsLog.swift; sourceTree = ""; }; - A0DB486D2AFD0BFC00348C83 /* AdyenAnalyticsError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdyenAnalyticsError.swift; sourceTree = ""; }; + A0DB48692AFD0BDC00348C83 /* AnalyticsEventInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnalyticsEventInfo.swift; sourceTree = ""; }; + A0DB486B2AFD0BEE00348C83 /* AnalyticsEventLog.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnalyticsEventLog.swift; sourceTree = ""; }; + A0DB486D2AFD0BFC00348C83 /* AnalyticsEventError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnalyticsEventError.swift; sourceTree = ""; }; A0DDA6A62A6162F500EBD6AF /* AdyenSessionResult.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdyenSessionResult.swift; sourceTree = ""; }; A0DE8F6C26CEA04500F2F1E8 /* Installments.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Installments.swift; sourceTree = ""; }; A0F41E5526CBCA6E0089AD6C /* InstallmentOptions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InstallmentOptions.swift; sourceTree = ""; }; @@ -3136,9 +3136,9 @@ children = ( C9B6683627C8D7FB006950B9 /* TelemetryData.swift */, A0DB48672AFD068400348C83 /* AdyenAnalytics.swift */, - A0DB48692AFD0BDC00348C83 /* AdyenAnalyticsInfo.swift */, - A0DB486B2AFD0BEE00348C83 /* AdyenAnalyticsLog.swift */, - A0DB486D2AFD0BFC00348C83 /* AdyenAnalyticsError.swift */, + A0DB48692AFD0BDC00348C83 /* AnalyticsEventInfo.swift */, + A0DB486B2AFD0BEE00348C83 /* AnalyticsEventLog.swift */, + A0DB486D2AFD0BFC00348C83 /* AnalyticsEventError.swift */, ); path = Models; sourceTree = ""; @@ -6578,7 +6578,7 @@ E224088D22B0FD220058923E /* StoredPayPalPaymentMethod.swift in Sources */, F99D2F0A266136A700BB5B2F /* AppleWalletPassResponse.swift in Sources */, F9639B3524DD97A30073F38A /* PaymentStatusResponse.swift in Sources */, - A0DB486E2AFD0BFC00348C83 /* AdyenAnalyticsError.swift in Sources */, + A0DB486E2AFD0BFC00348C83 /* AnalyticsEventError.swift in Sources */, F9BA21C2246E82EE00D36A63 /* SizeUtilities.swift in Sources */, F97C829225BB156600D7F85C /* AbstractPersonalInformationComponent+Extensions.swift in Sources */, 81BA08372A49C93100308160 /* FormSelectableValueItemView.swift in Sources */, @@ -6652,7 +6652,7 @@ F9D5752A237C6084009C18B5 /* StoredBCMCPaymentMethod.swift in Sources */, E2289B3C23D0BBB1002844BF /* ListSectionHeaderStyle.swift in Sources */, E715A7342A1B96890047B87A /* UIApplicationHelpers.swift in Sources */, - A0DB486C2AFD0BEE00348C83 /* AdyenAnalyticsLog.swift in Sources */, + A0DB486C2AFD0BEE00348C83 /* AnalyticsEventLog.swift in Sources */, F926D53723F6A35700D058D3 /* NumericFormatter.swift in Sources */, A026C85127C4FE4700E6C34A /* BasicComponentConfiguration.swift in Sources */, E7085B162628B29600D0153B /* FormPhoneExtensionPickerItemView.swift in Sources */, @@ -6673,7 +6673,7 @@ E2C0E096220B04F0008616F6 /* FormViewController.swift in Sources */, F9FE25D62626CD49001874BB /* ReadyToSubmitPaymentComponentDelegate.swift in Sources */, F99D4556262717A500880D72 /* FormErrorItemView.swift in Sources */, - A0DB486A2AFD0BDC00348C83 /* AdyenAnalyticsInfo.swift in Sources */, + A0DB486A2AFD0BDC00348C83 /* AnalyticsEventInfo.swift in Sources */, F96286BD256BDEB000043FE3 /* CoreBundleExtension.swift in Sources */, E7085D7D262EEF6200D0153B /* AllRegions.swift in Sources */, F919DF9124E682480027976E /* ClientKeyResponse.swift in Sources */, diff --git a/Adyen/Analytics/AnalyticsProvider/AnalyticsProvider.swift b/Adyen/Analytics/AnalyticsProvider/AnalyticsProvider.swift index 6644c5f27a..5a044f2935 100644 --- a/Adyen/Analytics/AnalyticsProvider/AnalyticsProvider.swift +++ b/Adyen/Analytics/AnalyticsProvider/AnalyticsProvider.swift @@ -48,6 +48,15 @@ public protocol AnalyticsProviderProtocol { func sendInitialAnalytics(with flavor: TelemetryFlavor, additionalFields: AdditionalAnalyticsFields?) var checkoutAttemptId: String? { get } + + /// Sends an info event to Checkout Anayltics + func send(info: AnalyticsEventInfo) + + /// Sends a log event to Checkout Anayltics + func send(log: AnalyticsEventLog) + + /// Sends an error event to Checkout Anayltics + func send(error: AnalyticsEventError) } internal final class AnalyticsProvider: AnalyticsProviderProtocol { @@ -59,11 +68,9 @@ internal final class AnalyticsProvider: AnalyticsProviderProtocol { internal private(set) var checkoutAttemptId: String? private let uniqueAssetAPIClient: UniqueAssetAPIClient - private var batchTimer: Timer? - - private var infos: [AdyenAnalytics.Info] = [] - private var logs: [AdyenAnalytics.Log] = [] - private var errors: [AdyenAnalytics.Error] = [] + private var infos: [AnalyticsEventInfo] = [] + private var logs: [AnalyticsEventLog] = [] + private var errors: [AnalyticsEventError] = [] // MARK: - Initializers @@ -94,22 +101,22 @@ internal final class AnalyticsProvider: AnalyticsProviderProtocol { uniqueAssetAPIClient.perform(initialAnalyticsRequest) { [weak self] result in switch result { case let .success(response): - self?.checkoutAttemptId = response.identifier + self?.checkoutAttemptId = response.checkoutAttemptId case .failure: self?.checkoutAttemptId = nil } } } - internal func send(info: AdyenAnalytics.Info) { + internal func send(info: AnalyticsEventInfo) { infos.append(info) } - internal func send(log: AdyenAnalytics.Log) { + internal func send(log: AnalyticsEventLog) { logs.append(log) } - internal func send(error: AdyenAnalytics.Error) { + internal func send(error: AnalyticsEventError) { errors.append(error) sendAll() } diff --git a/Adyen/Analytics/Models/AdyenAnalytics.swift b/Adyen/Analytics/Models/AdyenAnalytics.swift index dc57c9bc46..d031d9785f 100644 --- a/Adyen/Analytics/Models/AdyenAnalytics.swift +++ b/Adyen/Analytics/Models/AdyenAnalytics.swift @@ -7,23 +7,27 @@ import Foundation @_spi(AdyenInternal) -public final class AdyenAnalytics { +/// Used as a singleton to update the sessionId +public final class AnalyticsForSession { - @_spi(AdyenInternal) /// Needed to be able to determine if using session public static var sessionId: String? - - internal struct CommonFields: Encodable { - - internal var timestamp = ISO8601DateFormatter().string(from: Date()) - - internal var component: String - - internal var metadata: [String: String] = [:] - } + private init() { /* Private empty init */ } +} + +@_spi(AdyenInternal) +/// A protocol that defines the events that can occur under Checkout Analytics. +public protocol AnalyticsEvent: Encodable { + var timestamp: TimeInterval { get } + + var component: String { get } } -internal protocol AdyenAnalyticsCommonFields: Encodable { - var commonFields: AdyenAnalytics.CommonFields { get } +@_spi(AdyenInternal) +public extension AnalyticsEvent { + + var timestamp: TimeInterval { + Date().timeIntervalSince1970 + } } diff --git a/Adyen/Analytics/Models/AdyenAnalyticsError.swift b/Adyen/Analytics/Models/AdyenAnalyticsError.swift deleted file mode 100644 index 20c85e6b82..0000000000 --- a/Adyen/Analytics/Models/AdyenAnalyticsError.swift +++ /dev/null @@ -1,32 +0,0 @@ -// -// Copyright (c) 2023 Adyen N.V. -// -// This file is open source and available under the MIT license. See the LICENSE file for more info. -// - -import Foundation - -extension AdyenAnalytics { - - /// Represents an error in the analytics scheme that indicates the flow was interrupted due to an error in the SDK. - internal struct Error: AdyenAnalyticsCommonFields { - - internal var commonFields: AdyenAnalytics.CommonFields - - internal var type: ErrorType - - internal var code: String - - internal var message: String - } - - internal enum ErrorType: String, Encodable { - case network = "Network" - case implementation = "Implementation" - case `internal` = "Internal" - case api = "ApiError" - case sdk = "SdkError" - case thirdParty = "ThirdParty" - case generic = "Generic" - } -} diff --git a/Adyen/Analytics/Models/AdyenAnalyticsInfo.swift b/Adyen/Analytics/Models/AdyenAnalyticsInfo.swift deleted file mode 100644 index b0f2589c5e..0000000000 --- a/Adyen/Analytics/Models/AdyenAnalyticsInfo.swift +++ /dev/null @@ -1,35 +0,0 @@ -// -// Copyright (c) 2023 Adyen N.V. -// -// This file is open source and available under the MIT license. See the LICENSE file for more info. -// - -import Foundation - -extension AdyenAnalytics { - - /// Represents an info event in the analytics scheme that can occur - /// many times during the checkout flow, such as input field focus/unfocus etc. - internal struct Info: AdyenAnalyticsCommonFields { - - internal var commonFields: AdyenAnalytics.CommonFields - - internal var type: InfoType - - internal var target: String - - internal var isStoredPaymentMethod: Bool - - internal var brand: String - - internal var validationErrorCode: String - - internal var validationErrorMessage: String - } - - internal enum InfoType: String, Encodable { - case selected = "Selected" - case focus = "Focus" - case unfocus = "Unfocus" - } -} diff --git a/Adyen/Analytics/Models/AdyenAnalyticsLog.swift b/Adyen/Analytics/Models/AdyenAnalyticsLog.swift deleted file mode 100644 index f2aae21013..0000000000 --- a/Adyen/Analytics/Models/AdyenAnalyticsLog.swift +++ /dev/null @@ -1,39 +0,0 @@ -// -// Copyright (c) 2023 Adyen N.V. -// -// This file is open source and available under the MIT license. See the LICENSE file for more info. -// - -import Foundation - -extension AdyenAnalytics { - - /// A log in the analytics scheme represents important checkpoints such as the pay button press, 3ds challenge etc. - internal struct Log: AdyenAnalyticsCommonFields { - - internal var commonFields: AdyenAnalytics.CommonFields - - internal var type: LogType - - internal var subType: LogSubType - - internal var target: String - - internal var message: String - } - - internal enum LogType: String, Encodable { - case action = "Action" - case submit = "Submit" - } - - internal enum LogSubType: String, Encodable { - case threeDS2 = "ThreeDS2" - case redirect = "Redirect" - case voucher = "Voucher" - case await = "Await" - case qrCode = "QrCode" - case bankTransfer = "BankTransfer" - case sdk = "Sdk" - } -} diff --git a/Adyen/Analytics/Models/AnalyticsEventError.swift b/Adyen/Analytics/Models/AnalyticsEventError.swift new file mode 100644 index 0000000000..353d20459c --- /dev/null +++ b/Adyen/Analytics/Models/AnalyticsEventError.swift @@ -0,0 +1,30 @@ +// +// Copyright (c) 2023 Adyen N.V. +// +// This file is open source and available under the MIT license. See the LICENSE file for more info. +// + +import Foundation + +@_spi(AdyenInternal) +/// Represents an error in the analytics scheme that indicates the flow was interrupted due to an error in the SDK. +public struct AnalyticsEventError: AnalyticsEvent { + + public var component: String + + public var type: ErrorType + + public var code: String? + + public var message: String? + + public enum ErrorType: String, Encodable { + case network = "Network" + case implementation = "Implementation" + case `internal` = "Internal" + case api = "ApiError" + case sdk = "SdkError" + case thirdParty = "ThirdParty" + case generic = "Generic" + } +} diff --git a/Adyen/Analytics/Models/AnalyticsEventInfo.swift b/Adyen/Analytics/Models/AnalyticsEventInfo.swift new file mode 100644 index 0000000000..2a006bc8c2 --- /dev/null +++ b/Adyen/Analytics/Models/AnalyticsEventInfo.swift @@ -0,0 +1,34 @@ +// +// Copyright (c) 2023 Adyen N.V. +// +// This file is open source and available under the MIT license. See the LICENSE file for more info. +// + +import Foundation + +@_spi(AdyenInternal) +/// Represents an info event in the analytics scheme that can occur +/// many times during the checkout flow, such as input field focus/unfocus etc. +public struct AnalyticsEventInfo: AnalyticsEvent { + public var component: String + + public var type: InfoType + + public var target: String? + + public var isStoredPaymentMethod: Bool? + + public var brand: String? + + public var validationErrorCode: String? + + public var validationErrorMessage: String? + + public enum InfoType: String, Encodable { + case selected = "Selected" + case focus = "Focus" + case unfocus = "Unfocus" + case validationError = "ValidationError" + case rendered = "Rendered" + } +} diff --git a/Adyen/Analytics/Models/AnalyticsEventLog.swift b/Adyen/Analytics/Models/AnalyticsEventLog.swift new file mode 100644 index 0000000000..a0e3ee1a45 --- /dev/null +++ b/Adyen/Analytics/Models/AnalyticsEventLog.swift @@ -0,0 +1,39 @@ +// +// Copyright (c) 2023 Adyen N.V. +// +// This file is open source and available under the MIT license. See the LICENSE file for more info. +// + +import Foundation + +@_spi(AdyenInternal) +/// A log in the analytics scheme represents important checkpoints such as the pay button press, 3ds challenge etc. +public struct AnalyticsEventLog: AnalyticsEvent { + + public var component: String + + public var type: LogType + + public var subType: LogSubType + + public var target: String + + public var message: String? + + public enum LogType: String, Encodable { + case action = "Action" + case submit = "Submit" + case redirect = "Redirect" + case threeDS2 = "ThreeDS2" + } + + public enum LogSubType: String, Encodable { + case threeDS2 = "ThreeDS2" + case redirect = "Redirect" + case voucher = "Voucher" + case await = "Await" + case qrCode = "QrCode" + case bankTransfer = "BankTransfer" + case sdk = "Sdk" + } +} diff --git a/Adyen/Analytics/Requests/AnalyticsRequest.swift b/Adyen/Analytics/Requests/AnalyticsRequest.swift index 7dc88d502c..812f3fcaea 100644 --- a/Adyen/Analytics/Requests/AnalyticsRequest.swift +++ b/Adyen/Analytics/Requests/AnalyticsRequest.swift @@ -25,11 +25,11 @@ internal struct AnalyticsRequest: APIRequest { internal var channel: String = "iOS" - internal var infos: [AdyenAnalytics.Info] = [] + internal var infos: [AnalyticsEventInfo] = [] - internal var logs: [AdyenAnalytics.Log] = [] + internal var logs: [AnalyticsEventLog] = [] - internal var errors: [AdyenAnalytics.Error] = [] + internal var errors: [AnalyticsEventError] = [] internal init(checkoutAttemptId: String) { self.path = "checkoutanalytics/v3/analytics/\(checkoutAttemptId)" diff --git a/Adyen/Analytics/Requests/InitialAnalyticsRequest.swift b/Adyen/Analytics/Requests/InitialAnalyticsRequest.swift index b2f556d1cf..991e671377 100644 --- a/Adyen/Analytics/Requests/InitialAnalyticsRequest.swift +++ b/Adyen/Analytics/Requests/InitialAnalyticsRequest.swift @@ -11,10 +11,10 @@ internal struct InitialAnalyticsResponse: Response { // MARK: - Properties - internal let identifier: String + internal let checkoutAttemptId: String internal enum CodingKeys: String, CodingKey { - case identifier = "checkoutAttemptId" + case checkoutAttemptId } } diff --git a/Adyen/Core/Core Protocols/PresentableComponent.swift b/Adyen/Core/Core Protocols/PresentableComponent.swift index c3478c607c..22eb4c46d0 100644 --- a/Adyen/Core/Core Protocols/PresentableComponent.swift +++ b/Adyen/Core/Core Protocols/PresentableComponent.swift @@ -63,7 +63,11 @@ public extension PresentableComponent { @_spi(AdyenInternal) public protocol TrackableComponent: Component { + /// Sends the initial data and retireves the checkout attempt id func sendInitialAnalytics() + + /// Sent when the component is first displayed on the screen. + func sendComponentDidLoadEvent() } @_spi(AdyenInternal) @@ -71,6 +75,7 @@ extension TrackableComponent where Self: ViewControllerDelegate { public func viewWillAppear(viewController: UIViewController) { sendInitialAnalytics() + sendComponentDidLoadEvent() } } @@ -82,8 +87,13 @@ extension TrackableComponent where Self: PaymentMethodAware { guard !_isDropIn else { return } let flavor: TelemetryFlavor = .components(type: paymentMethod.type) let amount = context.payment?.amount - let additionalFields = AdditionalAnalyticsFields(amount: amount, sessionId: AdyenAnalytics.sessionId) + let additionalFields = AdditionalAnalyticsFields(amount: amount, sessionId: AnalyticsForSession.sessionId) context.analyticsProvider?.sendInitialAnalytics(with: flavor, additionalFields: additionalFields) } + + public func sendComponentDidLoadEvent() { + let info = AnalyticsEventInfo(component: paymentMethod.type.rawValue, type: .rendered) + context.analyticsProvider?.send(info: info) + } } diff --git a/AdyenComponents/BACS Direct Debit/Trackers/BACSDirectDebitComponentTracker.swift b/AdyenComponents/BACS Direct Debit/Trackers/BACSDirectDebitComponentTracker.swift index 78ff9fd423..b84b0b67b6 100644 --- a/AdyenComponents/BACS Direct Debit/Trackers/BACSDirectDebitComponentTracker.swift +++ b/AdyenComponents/BACS Direct Debit/Trackers/BACSDirectDebitComponentTracker.swift @@ -36,7 +36,7 @@ internal class BACSDirectDebitComponentTracker: BACSDirectDebitComponentTrackerP guard !isDropIn else { return } let flavor: TelemetryFlavor = .components(type: paymentMethod.type) let amount = context.payment?.amount - let additionalFields = AdditionalAnalyticsFields(amount: amount, sessionId: AdyenAnalytics.sessionId) + let additionalFields = AdditionalAnalyticsFields(amount: amount, sessionId: AnalyticsForSession.sessionId) context.analyticsProvider?.sendInitialAnalytics(with: flavor, additionalFields: additionalFields) } diff --git a/AdyenDropIn/DropInComponentExtensions.swift b/AdyenDropIn/DropInComponentExtensions.swift index eb93b7d015..97b7af43d1 100644 --- a/AdyenDropIn/DropInComponentExtensions.swift +++ b/AdyenDropIn/DropInComponentExtensions.swift @@ -24,7 +24,7 @@ extension DropInComponent: PaymentMethodListComponentDelegate { let paymentMethodTypes = paymentMethods.regular.map(\.type.rawValue) let flavor = TelemetryFlavor.dropIn(paymentMethods: paymentMethodTypes) let amount = context.payment?.amount - let additionalFields = AdditionalAnalyticsFields(amount: amount, sessionId: AdyenAnalytics.sessionId) + let additionalFields = AdditionalAnalyticsFields(amount: amount, sessionId: AnalyticsForSession.sessionId) context.analyticsProvider?.sendInitialAnalytics(with: flavor, additionalFields: additionalFields) } diff --git a/AdyenSession/AdyenSession.swift b/AdyenSession/AdyenSession.swift index 02effb1e0d..107365740a 100644 --- a/AdyenSession/AdyenSession.swift +++ b/AdyenSession/AdyenSession.swift @@ -119,7 +119,7 @@ public final class AdyenSession { sessionContext: sessionContext) session.delegate = delegate session.presentationDelegate = presentationDelegate - AdyenAnalytics.sessionId = sessionContext.identifier + AnalyticsForSession.sessionId = sessionContext.identifier completion(.success(session)) case let .failure(error): completion(.failure(error)) diff --git a/Tests/Adyen Tests/Analytics/AnalyticsProviderTests.swift b/Tests/Adyen Tests/Analytics/AnalyticsProviderTests.swift index 38211e1dbe..baa7e5f1da 100644 --- a/Tests/Adyen Tests/Analytics/AnalyticsProviderTests.swift +++ b/Tests/Adyen Tests/Analytics/AnalyticsProviderTests.swift @@ -32,7 +32,7 @@ class AnalyticsProviderTests: XCTestCase { let expectedCheckoutAttemptId = checkoutAttemptIdMockValue - let initialAnalyticsResponse = InitialAnalyticsResponse(identifier: expectedCheckoutAttemptId) + let initialAnalyticsResponse = InitialAnalyticsResponse(checkoutAttemptId: expectedCheckoutAttemptId) let checkoutAttemptIdResult: Result = .success(initialAnalyticsResponse) apiClient.mockedResults = [checkoutAttemptIdResult] @@ -64,7 +64,7 @@ class AnalyticsProviderTests: XCTestCase { let expectedCheckoutAttemptId = checkoutAttemptIdMockValue - let initialAnalyticsResponse = InitialAnalyticsResponse(identifier: expectedCheckoutAttemptId) + let initialAnalyticsResponse = InitialAnalyticsResponse(checkoutAttemptId: expectedCheckoutAttemptId) let checkoutAttemptIdResult: Result = .success(initialAnalyticsResponse) apiClient.mockedResults = [checkoutAttemptIdResult] @@ -103,7 +103,7 @@ class AnalyticsProviderTests: XCTestCase { let expectedCheckoutAttemptId = checkoutAttemptIdMockValue - let initialAnalyticsResponse = InitialAnalyticsResponse(identifier: expectedCheckoutAttemptId) + let initialAnalyticsResponse = InitialAnalyticsResponse(checkoutAttemptId: expectedCheckoutAttemptId) let checkoutAttemptIdResult: Result = .success(initialAnalyticsResponse) apiClient.mockedResults = [checkoutAttemptIdResult] @@ -122,7 +122,7 @@ class AnalyticsProviderTests: XCTestCase { let apiClient = APIClientMock() let sut = AnalyticsProvider(apiClient: apiClient, configuration: analyticsConfiguration) - let initialAnalyticsResponse = InitialAnalyticsResponse(identifier: checkoutAttemptIdMockValue) + let initialAnalyticsResponse = InitialAnalyticsResponse(checkoutAttemptId: checkoutAttemptIdMockValue) let checkoutAttemptIdResult: Result = .success(initialAnalyticsResponse) apiClient.mockedResults = [checkoutAttemptIdResult] @@ -141,7 +141,7 @@ class AnalyticsProviderTests: XCTestCase { let apiClient = APIClientMock() apiClient.mockedResults = [ - .success(InitialAnalyticsResponse(identifier: checkoutAttemptId)), + .success(InitialAnalyticsResponse(checkoutAttemptId: checkoutAttemptId)), ] apiClient.onExecute = { request in if let initialAnalyticsdRequest = request as? InitialAnalyticsRequest { @@ -175,7 +175,7 @@ class AnalyticsProviderTests: XCTestCase { let apiClient = APIClientMock() apiClient.mockedResults = [ - .success(InitialAnalyticsResponse(identifier: checkoutAttemptId)) + .success(InitialAnalyticsResponse(checkoutAttemptId: checkoutAttemptId)) ] apiClient.onExecute = { request in if let initialAnalyticsdRequest = request as? InitialAnalyticsRequest { diff --git a/Tests/Adyen Tests/Analytics/TelemetryTrackerTests.swift b/Tests/Adyen Tests/Analytics/TelemetryTrackerTests.swift index f6dce00702..c2c0db0737 100644 --- a/Tests/Adyen Tests/Analytics/TelemetryTrackerTests.swift +++ b/Tests/Adyen Tests/Analytics/TelemetryTrackerTests.swift @@ -18,7 +18,7 @@ class TelemetryTrackerTests: XCTestCase { override func setUpWithError() throws { try super.setUpWithError() apiClient = APIClientMock() - let checkoutAttemptIdResponse = InitialAnalyticsResponse(identifier: "checkoutAttempId1") + let checkoutAttemptIdResponse = InitialAnalyticsResponse(checkoutAttemptId: "checkoutAttempId1") let checkoutAttemptIdResult: Result = .success(checkoutAttemptIdResponse) apiClient.mockedResults = [checkoutAttemptIdResult] sut = AnalyticsProvider(apiClient: apiClient, configuration: .init()) @@ -127,6 +127,6 @@ class TelemetryTrackerTests: XCTestCase { // MARK: - Private private var checkoutAttemptIdResponse: InitialAnalyticsResponse { - .init(identifier: "cb3eef98-978e-4f6f-b299-937a4450be1f1648546838056be73d8f38ee8bcc3a65ec14e41b037a59f255dcd9e83afe8c06bd3e7abcad993") + .init(checkoutAttemptId: "cb3eef98-978e-4f6f-b299-937a4450be1f1648546838056be73d8f38ee8bcc3a65ec14e41b037a59f255dcd9e83afe8c06bd3e7abcad993") } } diff --git a/Tests/Session Tests/SessionTests.swift b/Tests/Session Tests/SessionTests.swift index 53ad59adad..ed2b9e3884 100644 --- a/Tests/Session Tests/SessionTests.swift +++ b/Tests/Session Tests/SessionTests.swift @@ -70,7 +70,7 @@ class SessionTests: XCTestCase { XCTAssertEqual(session.sessionContext.paymentMethods, expectedPaymentMethods) XCTAssertEqual(session.sessionContext.amount, .init(value: 220, currencyCode: "USD")) XCTAssertFalse(session.sessionContext.configuration.enableStoreDetails) - XCTAssertEqual(AdyenAnalytics.sessionId, "session_id") + XCTAssertEqual(AnalyticsForSession.sessionId, "session_id") } expectation.fulfill() } From 5f2ee30858d9908f21d64ba1a31bae125a5726cc Mon Sep 17 00:00:00 2001 From: erenbesel Date: Wed, 7 Feb 2024 13:17:35 +0100 Subject: [PATCH 12/31] chore: call initial analytisc on didLoad instead of willAppear --- .../AbstractPersonalInformationComponent.swift | 5 ++++- .../Core/Core Protocols/PresentableComponent.swift | 2 +- .../Components/Card/CardComponentExtensions.swift | 1 + AdyenComponents/Boleto/BoletoComponent.swift | 13 ++----------- 4 files changed, 8 insertions(+), 13 deletions(-) diff --git a/Adyen/Core/Components/AbstractPersonalInformationComponent/AbstractPersonalInformationComponent.swift b/Adyen/Core/Components/AbstractPersonalInformationComponent/AbstractPersonalInformationComponent.swift index b4b4d57293..a741bb5665 100644 --- a/Adyen/Core/Components/AbstractPersonalInformationComponent/AbstractPersonalInformationComponent.swift +++ b/Adyen/Core/Components/AbstractPersonalInformationComponent/AbstractPersonalInformationComponent.swift @@ -262,7 +262,10 @@ extension AbstractPersonalInformationComponent: ViewControllerDelegate { // MARK: - ViewControllerDelegate public func viewWillAppear(viewController: UIViewController) { - sendInitialAnalytics() populateFields() } + + public func viewDidLoad(viewController: UIViewController) { + sendInitialAnalytics() + } } diff --git a/Adyen/Core/Core Protocols/PresentableComponent.swift b/Adyen/Core/Core Protocols/PresentableComponent.swift index c3478c607c..9b95fa52de 100644 --- a/Adyen/Core/Core Protocols/PresentableComponent.swift +++ b/Adyen/Core/Core Protocols/PresentableComponent.swift @@ -69,7 +69,7 @@ public protocol TrackableComponent: Component { @_spi(AdyenInternal) extension TrackableComponent where Self: ViewControllerDelegate { - public func viewWillAppear(viewController: UIViewController) { + public func viewDidLoad(viewController: UIViewController) { sendInitialAnalytics() } } diff --git a/AdyenCard/Components/Card/CardComponentExtensions.swift b/AdyenCard/Components/Card/CardComponentExtensions.swift index a32f8e1567..c4bd0a6897 100644 --- a/AdyenCard/Components/Card/CardComponentExtensions.swift +++ b/AdyenCard/Components/Card/CardComponentExtensions.swift @@ -69,6 +69,7 @@ extension CardComponent: ViewControllerDelegate { Analytics.sendEvent(component: paymentMethod.type.rawValue, flavor: _isDropIn ? .dropin : .components, context: context.apiContext) + sendInitialAnalytics() // just cache the public key value fetchCardPublicKey(notifyingDelegateOnFailure: false) } diff --git a/AdyenComponents/Boleto/BoletoComponent.swift b/AdyenComponents/Boleto/BoletoComponent.swift index f11ea14bdb..e7ee4be5ab 100644 --- a/AdyenComponents/Boleto/BoletoComponent.swift +++ b/AdyenComponents/Boleto/BoletoComponent.swift @@ -90,6 +90,7 @@ public final class BoletoComponent: PaymentComponent, } (component.viewController as? SecuredViewController)?.delegate = self component.delegate = self + component._isDropIn = _isDropIn return component }() @@ -170,17 +171,7 @@ public final class BoletoComponent: PaymentComponent, extension BoletoComponent: TrackableComponent {} @_spi(AdyenInternal) -extension BoletoComponent: ViewControllerDelegate { - - public func viewDidLoad(viewController: UIViewController) {} - - public func viewDidAppear(viewController: UIViewController) {} - - public func viewWillAppear(viewController: UIViewController) { - sendInitialAnalytics() - prefillFields(for: formComponent) - } -} +extension BoletoComponent: ViewControllerDelegate {} @_spi(AdyenInternal) extension BoletoComponent: PaymentComponentDelegate { From d8c1f163e66fd22d4c4d168868151ff08e33e8d4 Mon Sep 17 00:00:00 2001 From: erenbesel Date: Wed, 7 Feb 2024 13:40:28 +0100 Subject: [PATCH 13/31] chore: fix tests --- .../GiftCardComponent/GiftCardComponent+Extensions.swift | 1 + Tests/Card Tests/BCMCComponentTests.swift | 4 ++-- Tests/Card Tests/CardComponentTests.swift | 4 ++-- .../ACH Direct Debit/ACHDirectDebitComponentTests.swift | 4 ++-- Tests/Components Tests/Affirm/AffirmComponentTests.swift | 4 ++-- Tests/Components Tests/Apple Pay/ApplePayComponentTests.swift | 4 ++-- Tests/Components Tests/Atome/AtomeComponentTests.swift | 4 ++-- .../Components Tests/BLIK Component/BLIKComponentTests.swift | 4 ++-- Tests/Components Tests/Boleto/BoletoComponentTests.swift | 4 ++-- .../Cash App Pay/CashAppPayComponentTests.swift | 4 ++-- Tests/Components Tests/Doku/DokuComponentTests.swift | 4 ++-- Tests/Components Tests/Gift Card/GiftCardComponentTests.swift | 4 ++-- .../IssuerList/IssuerListComponentTests.swift | 4 ++-- Tests/Components Tests/MB Way/MBWayComponentTests.swift | 4 ++-- .../Qiwi Wallet/QiwiWalletComponentTests.swift | 4 ++-- .../SEPA Tests/SEPADirectDebitComponentTests.swift | 4 ++-- 16 files changed, 31 insertions(+), 30 deletions(-) diff --git a/AdyenCard/Components/GiftCardComponent/GiftCardComponent+Extensions.swift b/AdyenCard/Components/GiftCardComponent/GiftCardComponent+Extensions.swift index 09f0d266e7..7f8b9bc393 100644 --- a/AdyenCard/Components/GiftCardComponent/GiftCardComponent+Extensions.swift +++ b/AdyenCard/Components/GiftCardComponent/GiftCardComponent+Extensions.swift @@ -17,6 +17,7 @@ extension GiftCardComponent: ViewControllerDelegate { Analytics.sendEvent(component: paymentMethod.type.rawValue, flavor: _isDropIn ? .dropin : .components, context: context.apiContext) + sendInitialAnalytics() // just cache the public key value fetchCardPublicKey(notifyingDelegateOnFailure: false) } diff --git a/Tests/Card Tests/BCMCComponentTests.swift b/Tests/Card Tests/BCMCComponentTests.swift index 86e9bc765c..ed23bff60b 100644 --- a/Tests/Card Tests/BCMCComponentTests.swift +++ b/Tests/Card Tests/BCMCComponentTests.swift @@ -513,7 +513,7 @@ class BCMCComponentTests: XCTestCase { XCTAssertEqual(sut.viewController.title, cardPaymentMethod.name) } - func testViewWillAppearShouldSendTelemetryEvent() throws { + func testViewDidLoadShouldSendInitialCall() throws { // Given let analyticsProviderMock = AnalyticsProviderMock() let context = Dummy.context(with: analyticsProviderMock) @@ -526,7 +526,7 @@ class BCMCComponentTests: XCTestCase { context: context) // When - sut.cardViewController.viewWillAppear(true) + sut.cardViewController.viewDidLoad() // Then XCTAssertEqual(analyticsProviderMock.initialTelemetryEventCallsCount, 1) diff --git a/Tests/Card Tests/CardComponentTests.swift b/Tests/Card Tests/CardComponentTests.swift index c8936544e7..4a6944165e 100644 --- a/Tests/Card Tests/CardComponentTests.swift +++ b/Tests/Card Tests/CardComponentTests.swift @@ -1960,7 +1960,7 @@ class CardComponentTests: XCTestCase { waitForExpectations(timeout: 10, handler: nil) } - func testViewWillAppearShouldSendTelemetryEvent() throws { + func testViewDidLoadShouldSendInitialCall() throws { // Given let analyticsProviderMock = AnalyticsProviderMock() let context = Dummy.context(with: analyticsProviderMock) @@ -1969,7 +1969,7 @@ class CardComponentTests: XCTestCase { configuration: CardComponent.Configuration()) // When - sut.cardViewController.viewWillAppear(false) + sut.cardViewController.viewDidLoad() // Then XCTAssertEqual(analyticsProviderMock.initialTelemetryEventCallsCount, 1) diff --git a/Tests/Components Tests/ACH Direct Debit/ACHDirectDebitComponentTests.swift b/Tests/Components Tests/ACH Direct Debit/ACHDirectDebitComponentTests.swift index 8b6044e970..934a9a3702 100644 --- a/Tests/Components Tests/ACH Direct Debit/ACHDirectDebitComponentTests.swift +++ b/Tests/Components Tests/ACH Direct Debit/ACHDirectDebitComponentTests.swift @@ -284,7 +284,7 @@ class ACHDirectDebitComponentTests: XCTestCase { wait(for: [expectation], timeout: 100) } - func testViewWillAppearShouldSendTelemetryEvent() throws { + func testViewDidLoadShouldSendInitialCall() throws { // Given let analyticsProviderMock = AnalyticsProviderMock() @@ -298,7 +298,7 @@ class ACHDirectDebitComponentTests: XCTestCase { publicKeyProvider: PublicKeyProviderMock()) // When - sut.viewWillAppear(viewController: sut.viewController) + sut.viewDidLoad(viewController: sut.viewController) // Then XCTAssertEqual(analyticsProviderMock.initialTelemetryEventCallsCount, 1) diff --git a/Tests/Components Tests/Affirm/AffirmComponentTests.swift b/Tests/Components Tests/Affirm/AffirmComponentTests.swift index 3c598adb2b..20cbdd65c4 100644 --- a/Tests/Components Tests/Affirm/AffirmComponentTests.swift +++ b/Tests/Components Tests/Affirm/AffirmComponentTests.swift @@ -308,7 +308,7 @@ class AffirmComponentTests: XCTestCase { XCTAssertNil(deliveryAddressView.item.value) } - func testViewWillAppear_shouldSendTelemetryEvent() throws { + func testViewDidLoadShouldSendInitialCall() throws { // Given let analyticsProviderMock = AnalyticsProviderMock() let context = Dummy.context(with: analyticsProviderMock) @@ -316,7 +316,7 @@ class AffirmComponentTests: XCTestCase { let mockViewController = UIViewController() // When - sut.viewWillAppear(viewController: mockViewController) + sut.viewDidLoad(viewController: mockViewController) // Then XCTAssertEqual(analyticsProviderMock.initialTelemetryEventCallsCount, 1) diff --git a/Tests/Components Tests/Apple Pay/ApplePayComponentTests.swift b/Tests/Components Tests/Apple Pay/ApplePayComponentTests.swift index d9e7c115c7..ba3021d3c2 100644 --- a/Tests/Components Tests/Apple Pay/ApplePayComponentTests.swift +++ b/Tests/Components Tests/Apple Pay/ApplePayComponentTests.swift @@ -381,7 +381,7 @@ class ApplePayComponentTest: XCTestCase { XCTAssertTrue(compareCollections(supportedNetworks, [.masterCard, .elo])) } - func testViewWillAppearShouldSendTelemetryEvent() throws { + func testViewDidLoadShouldSendInitialCall() throws { // Given let analyticsProviderMock = AnalyticsProviderMock() let context = Dummy.context(with: analyticsProviderMock) @@ -394,7 +394,7 @@ class ApplePayComponentTest: XCTestCase { configuration: configuration) // When - sut.viewWillAppear(viewController: mockViewController) + sut.viewDidLoad(viewController: mockViewController) // Then XCTAssertEqual(analyticsProviderMock.initialTelemetryEventCallsCount, 1) diff --git a/Tests/Components Tests/Atome/AtomeComponentTests.swift b/Tests/Components Tests/Atome/AtomeComponentTests.swift index 6876a9607c..5f4e458c9c 100644 --- a/Tests/Components Tests/Atome/AtomeComponentTests.swift +++ b/Tests/Components Tests/Atome/AtomeComponentTests.swift @@ -79,7 +79,7 @@ class AtomeComponentTests: XCTestCase { XCTAssertFalse(phoneExtensions.isEmpty) } - func testViewWillAppearShouldSendTelemetryEvent() throws { + func testViewDidLoadShouldSendInitialCall() throws { // Given let analyticsProviderMock = AnalyticsProviderMock() let context = Dummy.context(with: analyticsProviderMock) @@ -88,7 +88,7 @@ class AtomeComponentTests: XCTestCase { let mockViewController = UIViewController() // When - sut.viewWillAppear(viewController: mockViewController) + sut.viewDidLoad(viewController: mockViewController) // Then XCTAssertEqual(analyticsProviderMock.initialTelemetryEventCallsCount, 1) diff --git a/Tests/Components Tests/BLIK Component/BLIKComponentTests.swift b/Tests/Components Tests/BLIK Component/BLIKComponentTests.swift index b2c69222fa..659d840131 100644 --- a/Tests/Components Tests/BLIK Component/BLIKComponentTests.swift +++ b/Tests/Components Tests/BLIK Component/BLIKComponentTests.swift @@ -77,12 +77,12 @@ class BLIKComponentTests: XCTestCase { XCTAssertEqual(sut.requiresModalPresentation, true) } - func testViewWillAppearShouldSendTelemetryEvent() throws { + func testViewDidLoadShouldSendInitialCall() throws { // When let analyticsProviderMock = AnalyticsProviderMock() let context = Dummy.context(with: analyticsProviderMock) sut = BLIKComponent(paymentMethod: method, context: context) - sut.viewWillAppear(viewController: sut.viewController) + sut.viewDidLoad(viewController: sut.viewController) // Then XCTAssertEqual(analyticsProviderMock.initialTelemetryEventCallsCount, 1) diff --git a/Tests/Components Tests/Boleto/BoletoComponentTests.swift b/Tests/Components Tests/Boleto/BoletoComponentTests.swift index f84f127a95..ca47574da0 100644 --- a/Tests/Components Tests/Boleto/BoletoComponentTests.swift +++ b/Tests/Components Tests/Boleto/BoletoComponentTests.swift @@ -123,7 +123,7 @@ class BoletoComponentTests: XCTestCase { XCTAssertFalse(emailItem.isHidden) } - func testViewWillAppearShouldSendTelemetryEvent() throws { + func testViewDidLoadShouldSendInitialCall() throws { // Given let analyticsProviderMock = AnalyticsProviderMock() let context = Dummy.context(with: analyticsProviderMock) @@ -135,7 +135,7 @@ class BoletoComponentTests: XCTestCase { ) // When - component.viewWillAppear(viewController: component.viewController) + component.viewDidLoad(viewController: component.viewController) // Then XCTAssertEqual(analyticsProviderMock.initialTelemetryEventCallsCount, 1) diff --git a/Tests/Components Tests/Cash App Pay/CashAppPayComponentTests.swift b/Tests/Components Tests/Cash App Pay/CashAppPayComponentTests.swift index b5670f9fd8..4d10489338 100644 --- a/Tests/Components Tests/Cash App Pay/CashAppPayComponentTests.swift +++ b/Tests/Components Tests/Cash App Pay/CashAppPayComponentTests.swift @@ -134,7 +134,7 @@ import XCTest XCTAssertFalse(sut.cashAppPayButton.showsActivityIndicator) } - func testViewWillAppearShouldSendTelemetryEvent() throws { + func testViewDidLoadShouldSendInitialCall() throws { // Given let analyticsProviderMock = AnalyticsProviderMock() @@ -145,7 +145,7 @@ import XCTest let sut = CashAppPayComponent(paymentMethod: paymentMethod, context: context, configuration: config) // When - sut.viewWillAppear(viewController: sut.viewController) + sut.viewDidLoad(viewController: sut.viewController) // Then XCTAssertEqual(analyticsProviderMock.initialTelemetryEventCallsCount, 1) diff --git a/Tests/Components Tests/Doku/DokuComponentTests.swift b/Tests/Components Tests/Doku/DokuComponentTests.swift index 7776d2b8b1..03343c9a83 100644 --- a/Tests/Components Tests/Doku/DokuComponentTests.swift +++ b/Tests/Components Tests/Doku/DokuComponentTests.swift @@ -151,7 +151,7 @@ class DokuComponentTests: XCTestCase { XCTAssertTrue(email.isEmpty) } - func testViewWillAppearShouldSendTelemetryEvent() throws { + func testViewDidLoadShouldSendInitialCall() throws { // Given let analyticsProviderMock = AnalyticsProviderMock() let context = Dummy.context(with: analyticsProviderMock) @@ -160,7 +160,7 @@ class DokuComponentTests: XCTestCase { configuration: DokuComponent.Configuration()) // When - sut.viewWillAppear(viewController: sut.viewController) + sut.viewDidLoad(viewController: sut.viewController) // Then XCTAssertEqual(analyticsProviderMock.initialTelemetryEventCallsCount, 1) diff --git a/Tests/Components Tests/Gift Card/GiftCardComponentTests.swift b/Tests/Components Tests/Gift Card/GiftCardComponentTests.swift index e70529e0a2..4125cd6840 100644 --- a/Tests/Components Tests/Gift Card/GiftCardComponentTests.swift +++ b/Tests/Components Tests/Gift Card/GiftCardComponentTests.swift @@ -559,7 +559,7 @@ class GiftCardComponentTests: XCTestCase { waitForExpectations(timeout: 10, handler: nil) } - func testViewWillAppearShouldSendTelemetryEvent() throws { + func testViewDidLoadShouldSendInitialCall() throws { // Given let analyticsProviderMock = AnalyticsProviderMock() let context = Dummy.context(with: analyticsProviderMock) @@ -572,7 +572,7 @@ class GiftCardComponentTests: XCTestCase { let mockViewController = UIViewController() // When - sut.viewWillAppear(viewController: mockViewController) + sut.viewDidLoad(viewController: mockViewController) // Then XCTAssertEqual(analyticsProviderMock.initialTelemetryEventCallsCount, 1) diff --git a/Tests/Components Tests/IssuerList/IssuerListComponentTests.swift b/Tests/Components Tests/IssuerList/IssuerListComponentTests.swift index b7b31b790c..bafc0ef326 100644 --- a/Tests/Components Tests/IssuerList/IssuerListComponentTests.swift +++ b/Tests/Components Tests/IssuerList/IssuerListComponentTests.swift @@ -55,7 +55,7 @@ class IssuerListComponentTests: XCTestCase { waitForExpectations(timeout: 10) } - func testViewWillAppearShouldSendTelemetryEvent() throws { + func testViewDidLoadShouldSendInitialCall() throws { // Given let analyticsProviderMock = AnalyticsProviderMock() let context = Dummy.context(with: analyticsProviderMock) @@ -64,7 +64,7 @@ class IssuerListComponentTests: XCTestCase { let mockViewController = UIViewController() // When - sut.viewWillAppear(viewController: mockViewController) + sut.viewDidLoad(viewController: mockViewController) // Then XCTAssertEqual(analyticsProviderMock.initialTelemetryEventCallsCount, 1) diff --git a/Tests/Components Tests/MB Way/MBWayComponentTests.swift b/Tests/Components Tests/MB Way/MBWayComponentTests.swift index 481b96ea0f..68c6b1596c 100644 --- a/Tests/Components Tests/MB Way/MBWayComponentTests.swift +++ b/Tests/Components Tests/MB Way/MBWayComponentTests.swift @@ -114,7 +114,7 @@ class MBWayComponentTests: XCTestCase { XCTAssertTrue(phoneNumber.isEmpty) } - func testViewWillAppearShouldSendTelemetryEvent() throws { + func testViewDidLoadShouldSendInitialCall() throws { // Given let analyticsProviderMock = AnalyticsProviderMock() let context = Dummy.context(with: analyticsProviderMock) @@ -123,7 +123,7 @@ class MBWayComponentTests: XCTestCase { configuration: MBWayComponent.Configuration()) // When - sut.viewWillAppear(viewController: sut.viewController) + sut.viewDidLoad(viewController: sut.viewController) // Then XCTAssertEqual(analyticsProviderMock.initialTelemetryEventCallsCount, 1) diff --git a/Tests/Components Tests/Qiwi Wallet/QiwiWalletComponentTests.swift b/Tests/Components Tests/Qiwi Wallet/QiwiWalletComponentTests.swift index c1cac70a1c..307b5573d5 100644 --- a/Tests/Components Tests/Qiwi Wallet/QiwiWalletComponentTests.swift +++ b/Tests/Components Tests/Qiwi Wallet/QiwiWalletComponentTests.swift @@ -182,7 +182,7 @@ class QiwiWalletComponentTests: XCTestCase { } - func testViewWillAppearShouldSendTelemetryEvent() throws { + func testViewDidLoadShouldSendInitialCall() throws { // Given let analyticsProviderMock = AnalyticsProviderMock() let context = Dummy.context(with: analyticsProviderMock) @@ -193,7 +193,7 @@ class QiwiWalletComponentTests: XCTestCase { configuration: QiwiWalletComponent.Configuration()) // When - sut.viewWillAppear(viewController: sut.viewController) + sut.viewDidLoad(viewController: sut.viewController) // Then XCTAssertEqual(analyticsProviderMock.initialTelemetryEventCallsCount, 1) diff --git a/Tests/Components Tests/SEPA Tests/SEPADirectDebitComponentTests.swift b/Tests/Components Tests/SEPA Tests/SEPADirectDebitComponentTests.swift index e3c7b2b04d..f9bef7360c 100644 --- a/Tests/Components Tests/SEPA Tests/SEPADirectDebitComponentTests.swift +++ b/Tests/Components Tests/SEPA Tests/SEPADirectDebitComponentTests.swift @@ -240,7 +240,7 @@ class SEPADirectDebitComponentTests: XCTestCase { wait(for: [expectation], timeout: 5) } - func testViewWillAppearShouldSendTelemetryEvent() throws { + func testViewDidLoadShouldSendInitialCall() throws { // Given let analyticsProviderMock = AnalyticsProviderMock() let context = Dummy.context(with: analyticsProviderMock) @@ -250,7 +250,7 @@ class SEPADirectDebitComponentTests: XCTestCase { context: context) // When - sut.viewWillAppear(viewController: mockViewController) + sut.viewDidLoad(viewController: mockViewController) // Then XCTAssertEqual(analyticsProviderMock.initialTelemetryEventCallsCount, 1) From 40733c3561c4b97796b3ed37a2dc47cdf027aab9 Mon Sep 17 00:00:00 2001 From: erenbesel Date: Wed, 7 Feb 2024 14:24:47 +0100 Subject: [PATCH 14/31] chore: remove usage of old analytics where new one is used --- Adyen/Core/Components/StoredPaymentMethodComponent.swift | 5 ----- AdyenCard/Components/Card/CardComponentExtensions.swift | 3 --- .../GiftCardComponent/GiftCardComponent+Extensions.swift | 3 --- AdyenCard/Components/Stored Card/StoredCardComponent.swift | 5 ----- .../ACH Direct Debit/ACHDirectDebitComponent.swift | 4 +--- AdyenComponents/Boleto/BoletoComponent.swift | 7 ++++++- Tests/Card Tests/BCMCComponentTests.swift | 2 +- Tests/Card Tests/CardComponentTests.swift | 2 +- Tests/Components Tests/Boleto/BoletoComponentTests.swift | 4 ++-- 9 files changed, 11 insertions(+), 24 deletions(-) diff --git a/Adyen/Core/Components/StoredPaymentMethodComponent.swift b/Adyen/Core/Components/StoredPaymentMethodComponent.swift index e879714f99..d7a470b8f2 100644 --- a/Adyen/Core/Components/StoredPaymentMethodComponent.swift +++ b/Adyen/Core/Components/StoredPaymentMethodComponent.swift @@ -42,11 +42,6 @@ public final class StoredPaymentMethodComponent: PaymentComponent, // MARK: - PresentableComponent public lazy var viewController: UIViewController = { - Analytics.sendEvent( - component: storedPaymentMethod.type.rawValue, - flavor: _isDropIn ? .dropin : .components, - context: context.apiContext - ) sendInitialAnalytics() let localizationParameters = configuration.localizationParameters diff --git a/AdyenCard/Components/Card/CardComponentExtensions.swift b/AdyenCard/Components/Card/CardComponentExtensions.swift index c4bd0a6897..96e7e2f536 100644 --- a/AdyenCard/Components/Card/CardComponentExtensions.swift +++ b/AdyenCard/Components/Card/CardComponentExtensions.swift @@ -66,9 +66,6 @@ extension CardComponent: TrackableComponent {} extension CardComponent: ViewControllerDelegate { public func viewDidLoad(viewController: UIViewController) { - Analytics.sendEvent(component: paymentMethod.type.rawValue, - flavor: _isDropIn ? .dropin : .components, - context: context.apiContext) sendInitialAnalytics() // just cache the public key value fetchCardPublicKey(notifyingDelegateOnFailure: false) diff --git a/AdyenCard/Components/GiftCardComponent/GiftCardComponent+Extensions.swift b/AdyenCard/Components/GiftCardComponent/GiftCardComponent+Extensions.swift index 7f8b9bc393..cd01c2d0f2 100644 --- a/AdyenCard/Components/GiftCardComponent/GiftCardComponent+Extensions.swift +++ b/AdyenCard/Components/GiftCardComponent/GiftCardComponent+Extensions.swift @@ -14,9 +14,6 @@ extension GiftCardComponent: TrackableComponent {} extension GiftCardComponent: ViewControllerDelegate { public func viewDidLoad(viewController: UIViewController) { - Analytics.sendEvent(component: paymentMethod.type.rawValue, - flavor: _isDropIn ? .dropin : .components, - context: context.apiContext) sendInitialAnalytics() // just cache the public key value fetchCardPublicKey(notifyingDelegateOnFailure: false) diff --git a/AdyenCard/Components/Stored Card/StoredCardComponent.swift b/AdyenCard/Components/Stored Card/StoredCardComponent.swift index 84828a9d5b..02b741dc74 100644 --- a/AdyenCard/Components/Stored Card/StoredCardComponent.swift +++ b/AdyenCard/Components/Stored Card/StoredCardComponent.swift @@ -37,11 +37,6 @@ internal final class StoredCardComponent: PaymentComponent, PaymentAware, Presen } internal lazy var storedCardAlertManager: StoredCardAlertManager = { - Analytics.sendEvent( - component: paymentMethod.type.rawValue, - flavor: _isDropIn ? .dropin : .components, - context: context.apiContext - ) sendInitialAnalytics() let manager = StoredCardAlertManager(paymentMethod: storedCardPaymentMethod, diff --git a/AdyenComponents/ACH Direct Debit/ACHDirectDebitComponent.swift b/AdyenComponents/ACH Direct Debit/ACHDirectDebitComponent.swift index 174b5c1d15..a6f6e825e6 100644 --- a/AdyenComponents/ACH Direct Debit/ACHDirectDebitComponent.swift +++ b/AdyenComponents/ACH Direct Debit/ACHDirectDebitComponent.swift @@ -288,9 +288,7 @@ extension ACHDirectDebitComponent: TrackableComponent {} extension ACHDirectDebitComponent: ViewControllerDelegate { public func viewDidLoad(viewController: UIViewController) { - Analytics.sendEvent(component: paymentMethod.type.rawValue, - flavor: _isDropIn ? .dropin : .components, - context: context.apiContext) + sendInitialAnalytics() // just cache the public key value fetchCardPublicKey(notifyingDelegateOnFailure: false) } diff --git a/AdyenComponents/Boleto/BoletoComponent.swift b/AdyenComponents/Boleto/BoletoComponent.swift index e7ee4be5ab..741b490b23 100644 --- a/AdyenComponents/Boleto/BoletoComponent.swift +++ b/AdyenComponents/Boleto/BoletoComponent.swift @@ -171,7 +171,12 @@ public final class BoletoComponent: PaymentComponent, extension BoletoComponent: TrackableComponent {} @_spi(AdyenInternal) -extension BoletoComponent: ViewControllerDelegate {} +extension BoletoComponent: ViewControllerDelegate { + + public func viewWillAppear(viewController: UIViewController) { + prefillFields(for: formComponent) + } +} @_spi(AdyenInternal) extension BoletoComponent: PaymentComponentDelegate { diff --git a/Tests/Card Tests/BCMCComponentTests.swift b/Tests/Card Tests/BCMCComponentTests.swift index ed23bff60b..c533971905 100644 --- a/Tests/Card Tests/BCMCComponentTests.swift +++ b/Tests/Card Tests/BCMCComponentTests.swift @@ -526,7 +526,7 @@ class BCMCComponentTests: XCTestCase { context: context) // When - sut.cardViewController.viewDidLoad() + sut.viewDidLoad(viewController: sut.cardViewController) // Then XCTAssertEqual(analyticsProviderMock.initialTelemetryEventCallsCount, 1) diff --git a/Tests/Card Tests/CardComponentTests.swift b/Tests/Card Tests/CardComponentTests.swift index 4a6944165e..51e51f5831 100644 --- a/Tests/Card Tests/CardComponentTests.swift +++ b/Tests/Card Tests/CardComponentTests.swift @@ -1969,7 +1969,7 @@ class CardComponentTests: XCTestCase { configuration: CardComponent.Configuration()) // When - sut.cardViewController.viewDidLoad() + sut.viewDidLoad(viewController: sut.cardViewController) // Then XCTAssertEqual(analyticsProviderMock.initialTelemetryEventCallsCount, 1) diff --git a/Tests/Components Tests/Boleto/BoletoComponentTests.swift b/Tests/Components Tests/Boleto/BoletoComponentTests.swift index ca47574da0..1265306c1d 100644 --- a/Tests/Components Tests/Boleto/BoletoComponentTests.swift +++ b/Tests/Components Tests/Boleto/BoletoComponentTests.swift @@ -28,14 +28,14 @@ class BoletoComponentTests: XCTestCase { let viewController = component.viewController - setupRootViewController(viewController) - let firstNameField: UITextField = try XCTUnwrap(viewController.view.findView(by: "firstNameItem.textField")) let lastNameField: UITextField = try XCTUnwrap(viewController.view.findView(by: "lastNameItem.textField")) let socialSecurityNumberField: UITextField = try XCTUnwrap(viewController.view.findView(by: "socialSecurityNumberItem.textField")) let emailField: UITextField = try XCTUnwrap(viewController.view.findView(by: "emailItem.textField")) let addressField: FormAddressPickerItemView = try XCTUnwrap(viewController.view.findView(by: "addressItem")) + setupRootViewController(viewController) + XCTAssertEqual(firstNameField.text, prefilledInformation.shopperName?.firstName) XCTAssertEqual(lastNameField.text, prefilledInformation.shopperName?.lastName) let formattedSocialSecurityNumber = brazilSocialSecurityNumberFormatter.formattedValue(for: prefilledInformation.socialSecurityNumber!) From 45a64c339bdb7dc45de61b0319ae394cb0a6ca0c Mon Sep 17 00:00:00 2001 From: erenbesel Date: Wed, 7 Feb 2024 16:49:53 +0100 Subject: [PATCH 15/31] chore: remove unused code and rename analytic events --- .../AnalyticsProvider/AnalyticsProvider.swift | 53 ------------------- .../Core Protocols/PresentableComponent.swift | 9 ---- 2 files changed, 62 deletions(-) diff --git a/Adyen/Analytics/AnalyticsProvider/AnalyticsProvider.swift b/Adyen/Analytics/AnalyticsProvider/AnalyticsProvider.swift index 5a044f2935..2674c0bc9f 100644 --- a/Adyen/Analytics/AnalyticsProvider/AnalyticsProvider.swift +++ b/Adyen/Analytics/AnalyticsProvider/AnalyticsProvider.swift @@ -48,15 +48,6 @@ public protocol AnalyticsProviderProtocol { func sendInitialAnalytics(with flavor: TelemetryFlavor, additionalFields: AdditionalAnalyticsFields?) var checkoutAttemptId: String? { get } - - /// Sends an info event to Checkout Anayltics - func send(info: AnalyticsEventInfo) - - /// Sends a log event to Checkout Anayltics - func send(log: AnalyticsEventLog) - - /// Sends an error event to Checkout Anayltics - func send(error: AnalyticsEventError) } internal final class AnalyticsProvider: AnalyticsProviderProtocol { @@ -67,10 +58,6 @@ internal final class AnalyticsProvider: AnalyticsProviderProtocol { internal let configuration: AnalyticsConfiguration internal private(set) var checkoutAttemptId: String? private let uniqueAssetAPIClient: UniqueAssetAPIClient - - private var infos: [AnalyticsEventInfo] = [] - private var logs: [AnalyticsEventLog] = [] - private var errors: [AnalyticsEventError] = [] // MARK: - Initializers @@ -107,44 +94,4 @@ internal final class AnalyticsProvider: AnalyticsProviderProtocol { } } } - - internal func send(info: AnalyticsEventInfo) { - infos.append(info) - } - - internal func send(log: AnalyticsEventLog) { - logs.append(log) - } - - internal func send(error: AnalyticsEventError) { - errors.append(error) - sendAll() - } - - private func setupTimer() { - let timer = Timer(timeInterval: 10, target: self, selector: #selector(sendAll), userInfo: nil, repeats: true) - timer.tolerance = 1 - RunLoop.current.add(timer, forMode: .common) - } - - @objc private func sendAll() { - guard configuration.isEnabled, - let checkoutAttemptId else { return } - var request = AnalyticsRequest(checkoutAttemptId: checkoutAttemptId) - - request.infos = infos - request.logs = logs - request.errors = errors - - apiClient.perform(request) { [weak self] _ in - guard let self else { return } - self.clearAll() - } - } - - private func clearAll() { - infos = [] - logs = [] - errors = [] - } } diff --git a/Adyen/Core/Core Protocols/PresentableComponent.swift b/Adyen/Core/Core Protocols/PresentableComponent.swift index 644c057312..6aa6977b5c 100644 --- a/Adyen/Core/Core Protocols/PresentableComponent.swift +++ b/Adyen/Core/Core Protocols/PresentableComponent.swift @@ -65,9 +65,6 @@ public protocol TrackableComponent: Component { /// Sends the initial data and retireves the checkout attempt id func sendInitialAnalytics() - - /// Sent when the component is first displayed on the screen. - func sendComponentDidLoadEvent() } @_spi(AdyenInternal) @@ -75,7 +72,6 @@ extension TrackableComponent where Self: ViewControllerDelegate { public func viewDidLoad(viewController: UIViewController) { sendInitialAnalytics() - sendComponentDidLoadEvent() } } @@ -91,9 +87,4 @@ extension TrackableComponent where Self: PaymentMethodAware { context.analyticsProvider?.sendInitialAnalytics(with: flavor, additionalFields: additionalFields) } - - public func sendComponentDidLoadEvent() { - let info = AnalyticsEventInfo(component: paymentMethod.type.rawValue, type: .rendered) - context.analyticsProvider?.send(info: info) - } } From 3da79b7d456f8a848479fddeeb272f5faf561794 Mon Sep 17 00:00:00 2001 From: erenbesel Date: Thu, 8 Feb 2024 10:48:23 +0100 Subject: [PATCH 16/31] chore: split initial analytics call --- Adyen/Analytics/AnalyticsProvider/AnalyticsProvider.swift | 6 +++++- Adyen/Core/Core Protocols/PresentableComponent.swift | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/Adyen/Analytics/AnalyticsProvider/AnalyticsProvider.swift b/Adyen/Analytics/AnalyticsProvider/AnalyticsProvider.swift index 2674c0bc9f..4095aae6c1 100644 --- a/Adyen/Analytics/AnalyticsProvider/AnalyticsProvider.swift +++ b/Adyen/Analytics/AnalyticsProvider/AnalyticsProvider.swift @@ -83,7 +83,11 @@ internal final class AnalyticsProvider: AnalyticsProviderProtocol { additionalFields: additionalFields, context: configuration.context) - let initialAnalyticsRequest = InitialAnalyticsRequest(data: telemetryData) + fetchCheckoutAttemptId(with: telemetryData) + } + + private func fetchCheckoutAttemptId(with initialAnalyticsData: TelemetryData) { + let initialAnalyticsRequest = InitialAnalyticsRequest(data: initialAnalyticsData) uniqueAssetAPIClient.perform(initialAnalyticsRequest) { [weak self] result in switch result { diff --git a/Adyen/Core/Core Protocols/PresentableComponent.swift b/Adyen/Core/Core Protocols/PresentableComponent.swift index 6aa6977b5c..7dab05e4b8 100644 --- a/Adyen/Core/Core Protocols/PresentableComponent.swift +++ b/Adyen/Core/Core Protocols/PresentableComponent.swift @@ -63,7 +63,7 @@ public extension PresentableComponent { @_spi(AdyenInternal) public protocol TrackableComponent: Component { - /// Sends the initial data and retireves the checkout attempt id + /// Sends the initial data and retrieves the checkout attempt id func sendInitialAnalytics() } From 87a69e26693e496f4dc768a9052b952ff3e982ea Mon Sep 17 00:00:00 2001 From: erenbesel Date: Thu, 8 Feb 2024 13:49:32 +0100 Subject: [PATCH 17/31] chore: replace telemetry keyword with analytics --- Adyen.xcodeproj/project.pbxproj | 32 +++++++------- ...etryFlavor.swift => AnalyticsFlavor.swift} | 4 +- .../AnalyticsProvider/AnalyticsProvider.swift | 21 ++++----- ...elemetryData.swift => AnalyticsData.swift} | 10 ++--- .../Analytics/Models/AnalyticsEventInfo.swift | 2 +- .../Requests/InitialAnalyticsRequest.swift | 2 +- .../Core Protocols/PresentableComponent.swift | 2 +- .../BACSDirectDebitComponentTracker.swift | 2 +- AdyenDropIn/DropInComponentExtensions.swift | 2 +- ...rTests.swift => AnalyticsEventTests.swift} | 43 ++++++------------- ...Tests.swift => AnalyticsFlavorTests.swift} | 12 +++--- .../Analytics/AnalyticsProviderMock.swift | 10 ++--- .../Analytics/AnalyticsProviderTests.swift | 40 ++++++++--------- Tests/Card Tests/BCMCComponentTests.swift | 2 +- Tests/Card Tests/CardComponentTests.swift | 2 +- .../Card Tests/StoredCardComponentTests.swift | 4 +- .../StoredPaymentMethodComponentTests.swift | 4 +- .../ACHDirectDebitComponentTests.swift | 2 +- .../Affirm/AffirmComponentTests.swift | 2 +- .../Apple Pay/ApplePayComponentTests.swift | 2 +- .../Atome/AtomeComponentTests.swift | 2 +- ...ectDebitComponentTrackerProtocolMock.swift | 4 +- .../Input/BACSInputPresenterTests.swift | 2 +- ...BACSDirectDebitComponentTrackerTests.swift | 4 +- .../BLIK Component/BLIKComponentTests.swift | 2 +- .../Boleto/BoletoComponentTests.swift | 2 +- .../CashAppPayComponentTests.swift | 2 +- .../Doku/DokuComponentTests.swift | 2 +- .../Gift Card/GiftCardComponentTests.swift | 2 +- .../IssuerList/IssuerListComponentTests.swift | 2 +- .../MB Way/MBWayComponentTests.swift | 2 +- .../QiwiWalletComponentTests.swift | 2 +- .../SEPADirectDebitComponentTests.swift | 2 +- 33 files changed, 104 insertions(+), 126 deletions(-) rename Adyen/Analytics/AnalyticsProvider/{TelemetryFlavor.swift => AnalyticsFlavor.swift} (88%) rename Adyen/Analytics/Models/{TelemetryData.swift => AnalyticsData.swift} (93%) rename Tests/Adyen Tests/Analytics/{TelemetryTrackerTests.swift => AnalyticsEventTests.swift} (68%) rename Tests/Adyen Tests/Analytics/{TelemetryFlavorTests.swift => AnalyticsFlavorTests.swift} (76%) diff --git a/Adyen.xcodeproj/project.pbxproj b/Adyen.xcodeproj/project.pbxproj index a953fffcff..f0da73cbe9 100644 --- a/Adyen.xcodeproj/project.pbxproj +++ b/Adyen.xcodeproj/project.pbxproj @@ -317,15 +317,15 @@ C96688BF26A6FC1C00DC7297 /* AffirmComponentTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C96688BE26A6FC1C00DC7297 /* AffirmComponentTests.swift */; }; C96E07A3283B92E300345732 /* BACSDirectDebitComponentTrackerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C96E07A1283B92D500345732 /* BACSDirectDebitComponentTrackerTests.swift */; }; C978F5EF2732CD6A00F59B3C /* FormCardSecurityCodeItemViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C978F5EE2732CD6A00F59B3C /* FormCardSecurityCodeItemViewTests.swift */; }; - C97C16AA28059A5A00534419 /* TelemetryTrackerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C97C16A928059A5A00534419 /* TelemetryTrackerTests.swift */; }; - C97C16AC280702B200534419 /* TelemetryFlavorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C97C16AB280702B200534419 /* TelemetryFlavorTests.swift */; }; + C97C16AA28059A5A00534419 /* AnalyticsEventTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C97C16A928059A5A00534419 /* AnalyticsEventTests.swift */; }; + C97C16AC280702B200534419 /* AnalyticsFlavorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C97C16AB280702B200534419 /* AnalyticsFlavorTests.swift */; }; C97C16AD2807076400534419 /* AnalyticsProviderMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9C0005B280468E100CE2EEC /* AnalyticsProviderMock.swift */; }; C981254E2851E9AF006D1374 /* PaymentComponentSubject.swift in Sources */ = {isa = PBXBuildFile; fileRef = C981254C2851E903006D1374 /* PaymentComponentSubject.swift */; }; C98125502851E9E4006D1374 /* PaymentComponentSubjectTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C981254F2851E9E4006D1374 /* PaymentComponentSubjectTests.swift */; }; C982FFD826946F0800AED849 /* AffirmComponent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C982FFD726946F0800AED849 /* AffirmComponent.swift */; }; C982FFDC2694792F00AED849 /* AffirmPaymentMethod.swift in Sources */ = {isa = PBXBuildFile; fileRef = C982FFDB2694792F00AED849 /* AffirmPaymentMethod.swift */; }; - C9B6683527C7CB7A006950B9 /* TelemetryFlavor.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9B6683427C7CB7A006950B9 /* TelemetryFlavor.swift */; }; - C9B6683727C8D7FB006950B9 /* TelemetryData.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9B6683627C8D7FB006950B9 /* TelemetryData.swift */; }; + C9B6683527C7CB7A006950B9 /* AnalyticsFlavor.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9B6683427C7CB7A006950B9 /* AnalyticsFlavor.swift */; }; + C9B6683727C8D7FB006950B9 /* AnalyticsData.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9B6683627C8D7FB006950B9 /* AnalyticsData.swift */; }; C9B6683927C903FE006950B9 /* AdyenContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9B6683827C903FE006950B9 /* AdyenContext.swift */; }; C9BAE20F27BEA68D002F5728 /* InitialAnalyticsRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9BAE20E27BEA68D002F5728 /* InitialAnalyticsRequest.swift */; }; C9BB460427622D9B00E6730B /* BACSConfirmationViewProtocolMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9BB460327622D9B00E6730B /* BACSConfirmationViewProtocolMock.swift */; }; @@ -1559,14 +1559,14 @@ C96688BE26A6FC1C00DC7297 /* AffirmComponentTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AffirmComponentTests.swift; sourceTree = ""; }; C96E07A1283B92D500345732 /* BACSDirectDebitComponentTrackerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BACSDirectDebitComponentTrackerTests.swift; sourceTree = ""; }; C978F5EE2732CD6A00F59B3C /* FormCardSecurityCodeItemViewTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FormCardSecurityCodeItemViewTests.swift; sourceTree = ""; }; - C97C16A928059A5A00534419 /* TelemetryTrackerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TelemetryTrackerTests.swift; sourceTree = ""; }; - C97C16AB280702B200534419 /* TelemetryFlavorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TelemetryFlavorTests.swift; sourceTree = ""; }; + C97C16A928059A5A00534419 /* AnalyticsEventTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnalyticsEventTests.swift; sourceTree = ""; }; + C97C16AB280702B200534419 /* AnalyticsFlavorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnalyticsFlavorTests.swift; sourceTree = ""; }; C981254C2851E903006D1374 /* PaymentComponentSubject.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PaymentComponentSubject.swift; sourceTree = ""; }; C981254F2851E9E4006D1374 /* PaymentComponentSubjectTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PaymentComponentSubjectTests.swift; sourceTree = ""; }; C982FFD726946F0800AED849 /* AffirmComponent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AffirmComponent.swift; sourceTree = ""; }; C982FFDB2694792F00AED849 /* AffirmPaymentMethod.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AffirmPaymentMethod.swift; sourceTree = ""; }; - C9B6683427C7CB7A006950B9 /* TelemetryFlavor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TelemetryFlavor.swift; sourceTree = ""; }; - C9B6683627C8D7FB006950B9 /* TelemetryData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TelemetryData.swift; sourceTree = ""; }; + C9B6683427C7CB7A006950B9 /* AnalyticsFlavor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnalyticsFlavor.swift; sourceTree = ""; }; + C9B6683627C8D7FB006950B9 /* AnalyticsData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnalyticsData.swift; sourceTree = ""; }; C9B6683827C903FE006950B9 /* AdyenContext.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdyenContext.swift; sourceTree = ""; }; C9BAE20E27BEA68D002F5728 /* InitialAnalyticsRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InitialAnalyticsRequest.swift; sourceTree = ""; }; C9BB460327622D9B00E6730B /* BACSConfirmationViewProtocolMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BACSConfirmationViewProtocolMock.swift; sourceTree = ""; }; @@ -3022,7 +3022,7 @@ isa = PBXGroup; children = ( C94632BD27BA6985003DD81F /* AnalyticsProvider.swift */, - C9B6683427C7CB7A006950B9 /* TelemetryFlavor.swift */, + C9B6683427C7CB7A006950B9 /* AnalyticsFlavor.swift */, ); path = AnalyticsProvider; sourceTree = ""; @@ -3116,8 +3116,8 @@ children = ( C9C0005B280468E100CE2EEC /* AnalyticsProviderMock.swift */, C9C0005D280474DF00CE2EEC /* AnalyticsProviderTests.swift */, - C97C16A928059A5A00534419 /* TelemetryTrackerTests.swift */, - C97C16AB280702B200534419 /* TelemetryFlavorTests.swift */, + C97C16A928059A5A00534419 /* AnalyticsEventTests.swift */, + C97C16AB280702B200534419 /* AnalyticsFlavorTests.swift */, ); path = Analytics; sourceTree = ""; @@ -3134,7 +3134,7 @@ C9CA0B69282E7E5D00C4E9C2 /* Models */ = { isa = PBXGroup; children = ( - C9B6683627C8D7FB006950B9 /* TelemetryData.swift */, + C9B6683627C8D7FB006950B9 /* AnalyticsData.swift */, A0DB48672AFD068400348C83 /* AdyenAnalytics.swift */, A0DB48692AFD0BDC00348C83 /* AnalyticsEventInfo.swift */, A0DB486B2AFD0BEE00348C83 /* AnalyticsEventLog.swift */, @@ -6536,7 +6536,7 @@ F95B6D8E25231715002C9062 /* RegularExpressionValidator.swift in Sources */, 002B93082951F120000B93F4 /* FormSegmentedControlItem.swift in Sources */, A04EA85E2B69509500723F39 /* AnalyticsEnvironment.swift in Sources */, - C9B6683527C7CB7A006950B9 /* TelemetryFlavor.swift in Sources */, + C9B6683527C7CB7A006950B9 /* AnalyticsFlavor.swift in Sources */, C9BAE20F27BEA68D002F5728 /* InitialAnalyticsRequest.swift in Sources */, F926D52023F4217A00D058D3 /* DeviceDependent.swift in Sources */, F9A6C4BB2657AFF600D8CD3E /* FormSpacerItem.swift in Sources */, @@ -6680,7 +6680,7 @@ F97C81AF25BAC8E600D7F85C /* AbstractPersonalInformationComponent.swift in Sources */, F97842D726C2758E00677458 /* InstantPaymentMethod.swift in Sources */, F97CCD3C24360A4000BC560A /* BundleHelpers.swift in Sources */, - C9B6683727C8D7FB006950B9 /* TelemetryData.swift in Sources */, + C9B6683727C8D7FB006950B9 /* AnalyticsData.swift in Sources */, E788A4EF2658030100089448 /* DisplayInformation.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -6710,7 +6710,7 @@ E9E3DAB2221D79C800697074 /* CardNumberFormatterTests.swift in Sources */, F9EDB796239663F800CFB3C9 /* PaymentComponentMock.swift in Sources */, F9B9F625295485A2008C2E49 /* ThreeDSResultExtension.swift in Sources */, - C97C16AA28059A5A00534419 /* TelemetryTrackerTests.swift in Sources */, + C97C16AA28059A5A00534419 /* AnalyticsEventTests.swift in Sources */, E7D189B025D31936006AD3B7 /* DropInActionTests.swift in Sources */, C95903DE275A48D000E7D3BC /* BACSDirectDebitComponentTests.swift in Sources */, 81825CBB2AC59C4000F91912 /* UIViewController+Search.swift in Sources */, @@ -6777,7 +6777,7 @@ E74D918325AF3FE600743B0C /* CardBrandProviderTests.swift in Sources */, 813BF1122B2365400096940E /* XCTestCase+FirstResponder.swift in Sources */, E773EA3C2523432B00119499 /* CardTypeProviderMock.swift in Sources */, - C97C16AC280702B200534419 /* TelemetryFlavorTests.swift in Sources */, + C97C16AC280702B200534419 /* AnalyticsFlavorTests.swift in Sources */, E9E3DB062226B3B200697074 /* AdyenCoderTests.swift in Sources */, F99D4603262D647400880D72 /* AddressViewModelTests.swift in Sources */, E9E3DABE221EA47800697074 /* StringExtensionsTests.swift in Sources */, diff --git a/Adyen/Analytics/AnalyticsProvider/TelemetryFlavor.swift b/Adyen/Analytics/AnalyticsProvider/AnalyticsFlavor.swift similarity index 88% rename from Adyen/Analytics/AnalyticsProvider/TelemetryFlavor.swift rename to Adyen/Analytics/AnalyticsProvider/AnalyticsFlavor.swift index 4c569f5ac5..6d3582fe8b 100644 --- a/Adyen/Analytics/AnalyticsProvider/TelemetryFlavor.swift +++ b/Adyen/Analytics/AnalyticsProvider/AnalyticsFlavor.swift @@ -7,12 +7,12 @@ import Foundation @_spi(AdyenInternal) -public enum TelemetryFlavor { +public enum AnalyticsFlavor { case components(type: PaymentMethodType) case dropIn(type: String = "dropin", paymentMethods: [String]) // The `dropInComponent` type describes a component within the drop-in component. - // In telemetry, we need to distinguish when a component is used from the drop-in + // In analytics, we need to distinguish when a component is used from the drop-in // and when it's used as standalone. case dropInComponent diff --git a/Adyen/Analytics/AnalyticsProvider/AnalyticsProvider.swift b/Adyen/Analytics/AnalyticsProvider/AnalyticsProvider.swift index 4095aae6c1..d20d9b6127 100644 --- a/Adyen/Analytics/AnalyticsProvider/AnalyticsProvider.swift +++ b/Adyen/Analytics/AnalyticsProvider/AnalyticsProvider.swift @@ -14,12 +14,9 @@ public struct AnalyticsConfiguration { /// A Boolean value that determines whether analytics is enabled. public var isEnabled = true - - @_spi(AdyenInternal) - public var isTelemetryEnabled = true @_spi(AdyenInternal) - public var context: TelemetryContext = .init() + public var context: AnalyticsContext = .init() // MARK: - Initializers @@ -28,14 +25,14 @@ public struct AnalyticsConfiguration { } @_spi(AdyenInternal) -/// Additional fields to be provided with a ``TelemetryRequest`` +/// Additional fields to be provided with an ``InitialAnalyticsRequest`` public struct AdditionalAnalyticsFields { /// The amount of the payment public let amount: Amount? public let sessionId: String? - public init(amount: Amount? = nil, sessionId: String? = nil) { + public init(amount: Amount?, sessionId: String?) { self.amount = amount self.sessionId = sessionId } @@ -45,7 +42,7 @@ public struct AdditionalAnalyticsFields { public protocol AnalyticsProviderProtocol { /// Sends the initial data and retrieves the checkout attempt id as a response. - func sendInitialAnalytics(with flavor: TelemetryFlavor, additionalFields: AdditionalAnalyticsFields?) + func sendInitialAnalytics(with flavor: AnalyticsFlavor, additionalFields: AdditionalAnalyticsFields?) var checkoutAttemptId: String? { get } } @@ -72,21 +69,21 @@ internal final class AnalyticsProvider: AnalyticsProviderProtocol { // MARK: - Internal - internal func sendInitialAnalytics(with flavor: TelemetryFlavor, additionalFields: AdditionalAnalyticsFields?) { - guard configuration.isEnabled, configuration.isTelemetryEnabled else { + internal func sendInitialAnalytics(with flavor: AnalyticsFlavor, additionalFields: AdditionalAnalyticsFields?) { + guard configuration.isEnabled else { checkoutAttemptId = "do-not-track" return } if case .dropInComponent = flavor { return } - let telemetryData = TelemetryData(flavor: flavor, + let analyticsData = AnalyticsData(flavor: flavor, additionalFields: additionalFields, context: configuration.context) - fetchCheckoutAttemptId(with: telemetryData) + fetchCheckoutAttemptId(with: analyticsData) } - private func fetchCheckoutAttemptId(with initialAnalyticsData: TelemetryData) { + private func fetchCheckoutAttemptId(with initialAnalyticsData: AnalyticsData) { let initialAnalyticsRequest = InitialAnalyticsRequest(data: initialAnalyticsData) uniqueAssetAPIClient.perform(initialAnalyticsRequest) { [weak self] result in diff --git a/Adyen/Analytics/Models/TelemetryData.swift b/Adyen/Analytics/Models/AnalyticsData.swift similarity index 93% rename from Adyen/Analytics/Models/TelemetryData.swift rename to Adyen/Analytics/Models/AnalyticsData.swift index 8cedc89f6e..dcb6845b58 100644 --- a/Adyen/Analytics/Models/TelemetryData.swift +++ b/Adyen/Analytics/Models/AnalyticsData.swift @@ -11,7 +11,7 @@ import UIKit /// /// Used to e.g. override the version + platform from within the Flutter SDK @_spi(AdyenInternal) -public struct TelemetryContext { +public struct AnalyticsContext { internal let version: String internal let platform: Platform @@ -26,7 +26,7 @@ public struct TelemetryContext { } @_spi(AdyenInternal) -public extension TelemetryContext { +public extension AnalyticsContext { enum Platform: String { case iOS = "ios" @@ -35,7 +35,7 @@ public extension TelemetryContext { } } -internal struct TelemetryData: Encodable { +internal struct AnalyticsData: Encodable { // MARK: - Properties @@ -89,9 +89,9 @@ internal struct TelemetryData: Encodable { // MARK: - Initializers - internal init(flavor: TelemetryFlavor, + internal init(flavor: AnalyticsFlavor, additionalFields: AdditionalAnalyticsFields?, - context: TelemetryContext) { + context: AnalyticsContext) { self.flavor = flavor.value self.amount = additionalFields?.amount self.sessionId = additionalFields?.sessionId diff --git a/Adyen/Analytics/Models/AnalyticsEventInfo.swift b/Adyen/Analytics/Models/AnalyticsEventInfo.swift index 2a006bc8c2..32f3d827a0 100644 --- a/Adyen/Analytics/Models/AnalyticsEventInfo.swift +++ b/Adyen/Analytics/Models/AnalyticsEventInfo.swift @@ -8,7 +8,7 @@ import Foundation @_spi(AdyenInternal) /// Represents an info event in the analytics scheme that can occur -/// many times during the checkout flow, such as input field focus/unfocus etc. +/// multiple times during the checkout flow, such as input field focus/unfocus etc. public struct AnalyticsEventInfo: AnalyticsEvent { public var component: String diff --git a/Adyen/Analytics/Requests/InitialAnalyticsRequest.swift b/Adyen/Analytics/Requests/InitialAnalyticsRequest.swift index 991e671377..37ae06ecf9 100644 --- a/Adyen/Analytics/Requests/InitialAnalyticsRequest.swift +++ b/Adyen/Analytics/Requests/InitialAnalyticsRequest.swift @@ -52,7 +52,7 @@ internal struct InitialAnalyticsRequest: APIRequest { // MARK: - Initializers - internal init(data: TelemetryData) { + internal init(data: AnalyticsData) { self.version = data.version self.platform = data.platform self.channel = data.channel diff --git a/Adyen/Core/Core Protocols/PresentableComponent.swift b/Adyen/Core/Core Protocols/PresentableComponent.swift index 7dab05e4b8..15b89eb4b0 100644 --- a/Adyen/Core/Core Protocols/PresentableComponent.swift +++ b/Adyen/Core/Core Protocols/PresentableComponent.swift @@ -81,7 +81,7 @@ extension TrackableComponent where Self: PaymentMethodAware { public func sendInitialAnalytics() { // initial call is not needed again if inside dropIn guard !_isDropIn else { return } - let flavor: TelemetryFlavor = .components(type: paymentMethod.type) + let flavor: AnalyticsFlavor = .components(type: paymentMethod.type) let amount = context.payment?.amount let additionalFields = AdditionalAnalyticsFields(amount: amount, sessionId: AnalyticsForSession.sessionId) context.analyticsProvider?.sendInitialAnalytics(with: flavor, diff --git a/AdyenComponents/BACS Direct Debit/Trackers/BACSDirectDebitComponentTracker.swift b/AdyenComponents/BACS Direct Debit/Trackers/BACSDirectDebitComponentTracker.swift index b84b0b67b6..cf44cc27a1 100644 --- a/AdyenComponents/BACS Direct Debit/Trackers/BACSDirectDebitComponentTracker.swift +++ b/AdyenComponents/BACS Direct Debit/Trackers/BACSDirectDebitComponentTracker.swift @@ -34,7 +34,7 @@ internal class BACSDirectDebitComponentTracker: BACSDirectDebitComponentTrackerP internal func sendInitialAnalytics() { // initial call is not needed again if inside dropIn guard !isDropIn else { return } - let flavor: TelemetryFlavor = .components(type: paymentMethod.type) + let flavor: AnalyticsFlavor = .components(type: paymentMethod.type) let amount = context.payment?.amount let additionalFields = AdditionalAnalyticsFields(amount: amount, sessionId: AnalyticsForSession.sessionId) context.analyticsProvider?.sendInitialAnalytics(with: flavor, diff --git a/AdyenDropIn/DropInComponentExtensions.swift b/AdyenDropIn/DropInComponentExtensions.swift index 97b7af43d1..7879b24edb 100644 --- a/AdyenDropIn/DropInComponentExtensions.swift +++ b/AdyenDropIn/DropInComponentExtensions.swift @@ -22,7 +22,7 @@ extension DropInComponent: PaymentMethodListComponentDelegate { internal func didLoad(_ paymentMethodListComponent: PaymentMethodListComponent) { let paymentMethodTypes = paymentMethods.regular.map(\.type.rawValue) - let flavor = TelemetryFlavor.dropIn(paymentMethods: paymentMethodTypes) + let flavor = AnalyticsFlavor.dropIn(paymentMethods: paymentMethodTypes) let amount = context.payment?.amount let additionalFields = AdditionalAnalyticsFields(amount: amount, sessionId: AnalyticsForSession.sessionId) context.analyticsProvider?.sendInitialAnalytics(with: flavor, additionalFields: additionalFields) diff --git a/Tests/Adyen Tests/Analytics/TelemetryTrackerTests.swift b/Tests/Adyen Tests/Analytics/AnalyticsEventTests.swift similarity index 68% rename from Tests/Adyen Tests/Analytics/TelemetryTrackerTests.swift rename to Tests/Adyen Tests/Analytics/AnalyticsEventTests.swift index c2c0db0737..6829e32097 100644 --- a/Tests/Adyen Tests/Analytics/TelemetryTrackerTests.swift +++ b/Tests/Adyen Tests/Analytics/AnalyticsEventTests.swift @@ -1,5 +1,5 @@ // -// TelemetryTrackerTests.swift +// AnalyticsEventTests.swift // AdyenUIKitTests // // Created by Naufal Aros on 4/12/22. @@ -10,7 +10,7 @@ import XCTest @_spi(AdyenInternal) @testable import Adyen @testable import AdyenNetworking -class TelemetryTrackerTests: XCTestCase { +class AnalyticsEventTests: XCTestCase { var apiClient: APIClientMock! var sut: AnalyticsProviderProtocol! @@ -30,15 +30,14 @@ class TelemetryTrackerTests: XCTestCase { try super.tearDownWithError() } - private func sendInitialAnalytics(flavor: TelemetryFlavor = .components(type: .achDirectDebit)) { + private func sendInitialAnalytics(flavor: AnalyticsFlavor = .components(type: .achDirectDebit)) { sut.sendInitialAnalytics(with: flavor, additionalFields: nil) } - func testSendTelemetryEventGivenAnalyticsIsDisabledAndTelemetryIsEnabledShouldNotSendAnyRequest() throws { + func testSendInitialEventGivenAnalyticsIsDisabledShouldNotSendAnyRequest() throws { // Given var analyticsConfiguration = AnalyticsConfiguration() analyticsConfiguration.isEnabled = false - analyticsConfiguration.isTelemetryEnabled = true sut = AnalyticsProvider(apiClient: apiClient, configuration: analyticsConfiguration) let expectedRequestCalls = 0 @@ -47,49 +46,32 @@ class TelemetryTrackerTests: XCTestCase { sendInitialAnalytics() // Then - XCTAssertEqual(expectedRequestCalls, apiClient.counter, "One or more telemetry requests were sent.") - } - - func testSendTelemetryEventGivenTelemetryIsDisabledShouldNotSendAnyRequest() throws { - // Given - var analyticsConfiguration = AnalyticsConfiguration() - analyticsConfiguration.isTelemetryEnabled = false - sut = AnalyticsProvider(apiClient: apiClient, configuration: analyticsConfiguration) - - let expectedRequestCalls = 0 - - // When - sendInitialAnalytics() - - // Then - XCTAssertEqual(expectedRequestCalls, apiClient.counter, "One or more telemetry requests were sent.") + XCTAssertEqual(expectedRequestCalls, apiClient.counter, "One or more analytics requests were sent.") XCTAssertEqual(sut.checkoutAttemptId, "do-not-track") } - func testSendTelemetryEventGivenTelemetryIsEnabledAndFlavorIsDropInComponentShouldNotSendAnyRequest() throws { + func testSendInitialEventGivenEnabledAndFlavorIsDropInComponentShouldNotSendAnyRequest() throws { // Given var analyticsConfiguration = AnalyticsConfiguration() - analyticsConfiguration.isTelemetryEnabled = true sut = AnalyticsProvider(apiClient: apiClient, configuration: analyticsConfiguration) - let flavor: TelemetryFlavor = .dropInComponent + let flavor: AnalyticsFlavor = .dropInComponent let expectedRequestCalls = 0 // When sendInitialAnalytics(flavor: flavor) // Then - XCTAssertEqual(expectedRequestCalls, apiClient.counter, "One or more telemetry requests were sent.") + XCTAssertEqual(expectedRequestCalls, apiClient.counter, "One or more analytics requests were sent.") XCTAssertNil(sut.checkoutAttemptId) } - func testSendTelemetryEventGivenTelemetryIsEnabledAndFlavorIsComponentsShouldSendTelemetryRequest() throws { + func testSendInitialEventGivenEnabledAndFlavorIsComponentsShouldSendInitialRequest() throws { // Given var analyticsConfiguration = AnalyticsConfiguration() - analyticsConfiguration.isTelemetryEnabled = true sut = AnalyticsProvider(apiClient: apiClient, configuration: analyticsConfiguration) - let flavor: TelemetryFlavor = .components(type: .affirm) + let flavor: AnalyticsFlavor = .components(type: .affirm) let expectedRequestCalls = 1 let checkoutAttemptIdResult: Result = .success(checkoutAttemptIdResponse) @@ -104,13 +86,12 @@ class TelemetryTrackerTests: XCTestCase { XCTAssertEqual(sut.checkoutAttemptId, "cb3eef98-978e-4f6f-b299-937a4450be1f1648546838056be73d8f38ee8bcc3a65ec14e41b037a59f255dcd9e83afe8c06bd3e7abcad993") } - func testSendTelemetryEventGivenTelemetryIsEnabledAndFlavorIsDropInShouldSendTelemetryRequest() throws { + func testSendInitialEventGivenEnabledAndFlavorIsDropInShouldSendInitialRequest() throws { // Given var analyticsConfiguration = AnalyticsConfiguration() - analyticsConfiguration.isTelemetryEnabled = true sut = AnalyticsProvider(apiClient: apiClient, configuration: analyticsConfiguration) - let flavor: TelemetryFlavor = .dropIn(paymentMethods: ["scheme", "paypal", "affirm"]) + let flavor: AnalyticsFlavor = .dropIn(paymentMethods: ["scheme", "paypal", "affirm"]) let expectedRequestCalls = 1 let checkoutAttemptIdResult: Result = .success(checkoutAttemptIdResponse) diff --git a/Tests/Adyen Tests/Analytics/TelemetryFlavorTests.swift b/Tests/Adyen Tests/Analytics/AnalyticsFlavorTests.swift similarity index 76% rename from Tests/Adyen Tests/Analytics/TelemetryFlavorTests.swift rename to Tests/Adyen Tests/Analytics/AnalyticsFlavorTests.swift index 3e079fbc38..8ec0dbb670 100644 --- a/Tests/Adyen Tests/Analytics/TelemetryFlavorTests.swift +++ b/Tests/Adyen Tests/Analytics/AnalyticsFlavorTests.swift @@ -1,5 +1,5 @@ // -// TelemetryFlavorTests.swift +// AnalyticsFlavorTests.swift // AdyenUIKitTests // // Created by Naufal Aros on 4/13/22. @@ -9,16 +9,16 @@ import XCTest @_spi(AdyenInternal) @testable import Adyen -class TelemetryFlavorTests: XCTestCase { +class AnalyticsFlavorTests: XCTestCase { - var sut: TelemetryFlavor! + var sut: AnalyticsFlavor! override func tearDownWithError() throws { sut = nil try super.tearDownWithError() } - func testTelemetryFlavorValueWhenFlavorIsComponentsMatchesFlavorType() throws { + func testAnalyticsFlavorValueWhenFlavorIsComponentsMatchesFlavorType() throws { // Given let expectedFlavorValue = "components" @@ -29,7 +29,7 @@ class TelemetryFlavorTests: XCTestCase { XCTAssertEqual(expectedFlavorValue, sut.value) } - func testTelemetryFlavorValueWhenFlavorIsDropInMatchesFlavorType() throws { + func testAnalyticsFlavorValueWhenFlavorIsDropInMatchesFlavorType() throws { // Given let expectedFlavorValue = "dropin" @@ -40,7 +40,7 @@ class TelemetryFlavorTests: XCTestCase { XCTAssertEqual(expectedFlavorValue, sut.value) } - func testTelemetryFlavorValueWhenFlavorIsDropInComponentMatchesFlavorType() throws { + func testAnalyticsFlavorValueWhenFlavorIsDropInComponentMatchesFlavorType() throws { // Given let expectedFlavorValue = "dropInComponent" diff --git a/Tests/Adyen Tests/Analytics/AnalyticsProviderMock.swift b/Tests/Adyen Tests/Analytics/AnalyticsProviderMock.swift index bfb0fc20ea..11009fa78d 100644 --- a/Tests/Adyen Tests/Analytics/AnalyticsProviderMock.swift +++ b/Tests/Adyen Tests/Analytics/AnalyticsProviderMock.swift @@ -15,15 +15,15 @@ class AnalyticsProviderMock: AnalyticsProviderProtocol { // MARK: - checkoutAttemptId - func sendInitialAnalytics(with flavor: TelemetryFlavor, additionalFields: AdditionalAnalyticsFields?) { - initialTelemetryEventCallsCount += 1 + func sendInitialAnalytics(with flavor: AnalyticsFlavor, additionalFields: AdditionalAnalyticsFields?) { + initialEventCallsCount += 1 checkoutAttemptId = _checkoutAttemptId } var _checkoutAttemptId: String? - var initialTelemetryEventCallsCount = 0 - var initialTelemetryEventCalled: Bool { - initialTelemetryEventCallsCount > 0 + var initialEventCallsCount = 0 + var initialEventCalled: Bool { + initialEventCallsCount > 0 } } diff --git a/Tests/Adyen Tests/Analytics/AnalyticsProviderTests.swift b/Tests/Adyen Tests/Analytics/AnalyticsProviderTests.swift index baa7e5f1da..478a1dc695 100644 --- a/Tests/Adyen Tests/Analytics/AnalyticsProviderTests.swift +++ b/Tests/Adyen Tests/Analytics/AnalyticsProviderTests.swift @@ -19,7 +19,6 @@ class AnalyticsProviderTests: XCTestCase { // Then XCTAssertTrue(sut.configuration.isEnabled) - XCTAssertTrue(sut.configuration.isTelemetryEnabled) } func testFetchCheckoutAttemptIdWhenAnalyticsIsEnabledShouldTriggerRequest() throws { @@ -132,12 +131,12 @@ class AnalyticsProviderTests: XCTestCase { XCTAssertEqual(sut.checkoutAttemptId, "do-not-track") } - func testTelemetryRequest() throws { + func testInitialRequest() throws { // Given let checkoutAttemptId = checkoutAttemptIdMockValue - let telemetryExpectation = expectation(description: "Telemetry request is triggered") + let analyticsExpectation = expectation(description: "Initial request is triggered") let apiClient = APIClientMock() apiClient.mockedResults = [ @@ -148,7 +147,7 @@ class AnalyticsProviderTests: XCTestCase { XCTAssertNil(initialAnalyticsdRequest.amount) XCTAssertEqual(initialAnalyticsdRequest.version, adyenSdkVersion) XCTAssertEqual(initialAnalyticsdRequest.platform, "ios") - telemetryExpectation.fulfill() + analyticsExpectation.fulfill() } } @@ -161,7 +160,7 @@ class AnalyticsProviderTests: XCTestCase { analyticsProvider.sendInitialAnalytics(with: .components(type: .achDirectDebit), additionalFields: nil) - wait(for: [telemetryExpectation], timeout: 10) + wait(for: [analyticsExpectation], timeout: 10) } func testAdditionalFields() throws { @@ -171,7 +170,7 @@ class AnalyticsProviderTests: XCTestCase { let amount = Amount(value: 1, currencyCode: "EUR") let checkoutAttemptId = checkoutAttemptIdMockValue - let telemetryExpectation = expectation(description: "Telemetry request is triggered") + let analyticsExpectation = expectation(description: "Initial request is triggered") let apiClient = APIClientMock() apiClient.mockedResults = [ @@ -182,7 +181,7 @@ class AnalyticsProviderTests: XCTestCase { XCTAssertEqual(initialAnalyticsdRequest.amount, amount) XCTAssertEqual(initialAnalyticsdRequest.version, "version") XCTAssertEqual(initialAnalyticsdRequest.platform, "react-native") - telemetryExpectation.fulfill() + analyticsExpectation.fulfill() } } @@ -195,39 +194,40 @@ class AnalyticsProviderTests: XCTestCase { ) // When - let additionalFields = AdditionalAnalyticsFields(amount: amount) + let additionalFields = AdditionalAnalyticsFields(amount: amount, sessionId: nil) analyticsProvider.sendInitialAnalytics(with: .components(type: .achDirectDebit), additionalFields: additionalFields) - wait(for: [telemetryExpectation], timeout: 10) + wait(for: [analyticsExpectation], timeout: 10) } - func testTelemetryRequestEncoding() throws { + func testInitialRequestEncoding() throws { - let telemetryData = TelemetryData(flavor: .dropInComponent, - additionalFields: AdditionalAnalyticsFields(amount: .init(value: 1, currencyCode: "EUR")), - context: TelemetryContext(version: "version", platform: .flutter)) + let analyticsData = AnalyticsData(flavor: .dropInComponent, + additionalFields: AdditionalAnalyticsFields(amount: .init(value: 1, currencyCode: "EUR"), sessionId: "test_session_id"), + context: AnalyticsContext(version: "version", platform: .flutter)) - let request = InitialAnalyticsRequest(data: telemetryData) + let request = InitialAnalyticsRequest(data: analyticsData) let encodedRequest = try JSONEncoder().encode(request) let decodedRequest = try XCTUnwrap(JSONSerialization.jsonObject(with: encodedRequest) as? [String: Any]) let expectedDecodedRequest = [ "locale": "en_US", - "paymentMethods": telemetryData.paymentMethods, + "paymentMethods": analyticsData.paymentMethods, "platform": "flutter", "component": "", "flavor": "dropInComponent", "channel": "iOS", - "systemVersion": telemetryData.systemVersion, - "screenWidth": telemetryData.screenWidth, - "referrer": telemetryData.referrer, - "deviceBrand": telemetryData.deviceBrand, - "deviceModel": telemetryData.deviceModel, + "systemVersion": analyticsData.systemVersion, + "screenWidth": analyticsData.screenWidth, + "referrer": analyticsData.referrer, + "deviceBrand": analyticsData.deviceBrand, + "deviceModel": analyticsData.deviceModel, "amount": [ "currency": "EUR", "value": 1 ] as [String: Any], + "sessionId": "test_session_id", "version": "version" ] as [String: Any] diff --git a/Tests/Card Tests/BCMCComponentTests.swift b/Tests/Card Tests/BCMCComponentTests.swift index c533971905..39d3572dd5 100644 --- a/Tests/Card Tests/BCMCComponentTests.swift +++ b/Tests/Card Tests/BCMCComponentTests.swift @@ -529,7 +529,7 @@ class BCMCComponentTests: XCTestCase { sut.viewDidLoad(viewController: sut.cardViewController) // Then - XCTAssertEqual(analyticsProviderMock.initialTelemetryEventCallsCount, 1) + XCTAssertEqual(analyticsProviderMock.initialEventCallsCount, 1) } func fillCard(on view: UIView, with card: Card, simulateKeyStrokes: Bool = false) { diff --git a/Tests/Card Tests/CardComponentTests.swift b/Tests/Card Tests/CardComponentTests.swift index 51e51f5831..776900d7ae 100644 --- a/Tests/Card Tests/CardComponentTests.swift +++ b/Tests/Card Tests/CardComponentTests.swift @@ -1972,7 +1972,7 @@ class CardComponentTests: XCTestCase { sut.viewDidLoad(viewController: sut.cardViewController) // Then - XCTAssertEqual(analyticsProviderMock.initialTelemetryEventCallsCount, 1) + XCTAssertEqual(analyticsProviderMock.initialEventCallsCount, 1) } diff --git a/Tests/Card Tests/StoredCardComponentTests.swift b/Tests/Card Tests/StoredCardComponentTests.swift index eb20a09973..84fd5fc3a3 100644 --- a/Tests/Card Tests/StoredCardComponentTests.swift +++ b/Tests/Card Tests/StoredCardComponentTests.swift @@ -225,7 +225,7 @@ class StoredCardComponentTests: XCTestCase { alertController.dismiss(animated: false, completion: nil) } - func testViewDidLoadShouldSendTelemetryEvent() throws { + func testViewDidLoadShouldSendInitialEvent() throws { // Given let analyticsProviderMock = AnalyticsProviderMock() let context = Dummy.context(with: analyticsProviderMock) @@ -237,7 +237,7 @@ class StoredCardComponentTests: XCTestCase { sut.viewController.viewDidLoad() // Then - XCTAssertEqual(analyticsProviderMock.initialTelemetryEventCallsCount, 1) + XCTAssertEqual(analyticsProviderMock.initialEventCallsCount, 1) } // MARK: - Private diff --git a/Tests/Card Tests/StoredPaymentMethodComponentTests.swift b/Tests/Card Tests/StoredPaymentMethodComponentTests.swift index 64af10543c..b8c11b100a 100644 --- a/Tests/Card Tests/StoredPaymentMethodComponentTests.swift +++ b/Tests/Card Tests/StoredPaymentMethodComponentTests.swift @@ -135,7 +135,7 @@ class StoredPaymentMethodComponentTests: XCTestCase { XCTAssertEqual(viewController?.title, localizedString(.dropInStoredTitle, nil, paymentMethod.name)) } - func testViewDidLoadShouldSendTelemetryEvent() throws { + func testViewDidLoadShouldSendInitialEvent() throws { // Given let analyticsProviderMock = AnalyticsProviderMock() let context = Dummy.context(with: analyticsProviderMock) @@ -147,6 +147,6 @@ class StoredPaymentMethodComponentTests: XCTestCase { sut.viewController.viewDidLoad() // Then - XCTAssertEqual(analyticsProviderMock.initialTelemetryEventCallsCount, 1) + XCTAssertEqual(analyticsProviderMock.initialEventCallsCount, 1) } } diff --git a/Tests/Components Tests/ACH Direct Debit/ACHDirectDebitComponentTests.swift b/Tests/Components Tests/ACH Direct Debit/ACHDirectDebitComponentTests.swift index 934a9a3702..486f949584 100644 --- a/Tests/Components Tests/ACH Direct Debit/ACHDirectDebitComponentTests.swift +++ b/Tests/Components Tests/ACH Direct Debit/ACHDirectDebitComponentTests.swift @@ -301,6 +301,6 @@ class ACHDirectDebitComponentTests: XCTestCase { sut.viewDidLoad(viewController: sut.viewController) // Then - XCTAssertEqual(analyticsProviderMock.initialTelemetryEventCallsCount, 1) + XCTAssertEqual(analyticsProviderMock.initialEventCallsCount, 1) } } diff --git a/Tests/Components Tests/Affirm/AffirmComponentTests.swift b/Tests/Components Tests/Affirm/AffirmComponentTests.swift index 20cbdd65c4..781b22bb12 100644 --- a/Tests/Components Tests/Affirm/AffirmComponentTests.swift +++ b/Tests/Components Tests/Affirm/AffirmComponentTests.swift @@ -319,7 +319,7 @@ class AffirmComponentTests: XCTestCase { sut.viewDidLoad(viewController: mockViewController) // Then - XCTAssertEqual(analyticsProviderMock.initialTelemetryEventCallsCount, 1) + XCTAssertEqual(analyticsProviderMock.initialEventCallsCount, 1) } // MARK: - Private diff --git a/Tests/Components Tests/Apple Pay/ApplePayComponentTests.swift b/Tests/Components Tests/Apple Pay/ApplePayComponentTests.swift index ba3021d3c2..337f3e57a5 100644 --- a/Tests/Components Tests/Apple Pay/ApplePayComponentTests.swift +++ b/Tests/Components Tests/Apple Pay/ApplePayComponentTests.swift @@ -397,7 +397,7 @@ class ApplePayComponentTest: XCTestCase { sut.viewDidLoad(viewController: mockViewController) // Then - XCTAssertEqual(analyticsProviderMock.initialTelemetryEventCallsCount, 1) + XCTAssertEqual(analyticsProviderMock.initialEventCallsCount, 1) } private func getRandomContactFieldSet() -> Set { diff --git a/Tests/Components Tests/Atome/AtomeComponentTests.swift b/Tests/Components Tests/Atome/AtomeComponentTests.swift index 5f4e458c9c..71b42433a4 100644 --- a/Tests/Components Tests/Atome/AtomeComponentTests.swift +++ b/Tests/Components Tests/Atome/AtomeComponentTests.swift @@ -91,7 +91,7 @@ class AtomeComponentTests: XCTestCase { sut.viewDidLoad(viewController: mockViewController) // Then - XCTAssertEqual(analyticsProviderMock.initialTelemetryEventCallsCount, 1) + XCTAssertEqual(analyticsProviderMock.initialEventCallsCount, 1) } } diff --git a/Tests/Components Tests/BACS Direct Debit/Mocks/BACSDirectDebitComponentTrackerProtocolMock.swift b/Tests/Components Tests/BACS Direct Debit/Mocks/BACSDirectDebitComponentTrackerProtocolMock.swift index 14d611ee64..7d233b4e2a 100644 --- a/Tests/Components Tests/BACS Direct Debit/Mocks/BACSDirectDebitComponentTrackerProtocolMock.swift +++ b/Tests/Components Tests/BACS Direct Debit/Mocks/BACSDirectDebitComponentTrackerProtocolMock.swift @@ -14,9 +14,9 @@ class BACSDirectDebitComponentTrackerProtocolMock: BACSDirectDebitComponentTrack // MARK: - sendEvent - var initialTelemetryEventCallsCount = 0 + var initialEventCallsCount = 0 func sendInitialAnalytics() { - initialTelemetryEventCallsCount += 1 + initialEventCallsCount += 1 } } diff --git a/Tests/Components Tests/BACS Direct Debit/Scenes/Input/BACSInputPresenterTests.swift b/Tests/Components Tests/BACS Direct Debit/Scenes/Input/BACSInputPresenterTests.swift index 014eb6deed..65975cc92c 100644 --- a/Tests/Components Tests/BACS Direct Debit/Scenes/Input/BACSInputPresenterTests.swift +++ b/Tests/Components Tests/BACS Direct Debit/Scenes/Input/BACSInputPresenterTests.swift @@ -64,7 +64,7 @@ class BACSInputPresenterTests: XCTestCase { sut.viewDidLoad() // Then - XCTAssertEqual(tracker.initialTelemetryEventCallsCount, 1) + XCTAssertEqual(tracker.initialEventCallsCount, 1) } func testContinuePaymentWhenButtonTappedShouldDisplayValidationOnView() throws { diff --git a/Tests/Components Tests/BACS Direct Debit/Trackers/BACSDirectDebitComponentTrackerTests.swift b/Tests/Components Tests/BACS Direct Debit/Trackers/BACSDirectDebitComponentTrackerTests.swift index 38f7a3b9ef..67e86c95eb 100644 --- a/Tests/Components Tests/BACS Direct Debit/Trackers/BACSDirectDebitComponentTrackerTests.swift +++ b/Tests/Components Tests/BACS Direct Debit/Trackers/BACSDirectDebitComponentTrackerTests.swift @@ -31,11 +31,11 @@ class BACSDirectDebitComponentTrackerTests: XCTestCase { try super.tearDownWithError() } - func testSendTelemetryEventShouldCallAnalyticsProviderSendTelemetryEvent() throws { + func testSendInitialEventShouldCallAnalyticsProviderSendInitialEvent() throws { // When sut.sendInitialAnalytics() // Then - XCTAssertEqual(analyticsProvider.initialTelemetryEventCallsCount, 1) + XCTAssertEqual(analyticsProvider.initialEventCallsCount, 1) } } diff --git a/Tests/Components Tests/BLIK Component/BLIKComponentTests.swift b/Tests/Components Tests/BLIK Component/BLIKComponentTests.swift index 659d840131..bf35e6d64b 100644 --- a/Tests/Components Tests/BLIK Component/BLIKComponentTests.swift +++ b/Tests/Components Tests/BLIK Component/BLIKComponentTests.swift @@ -85,6 +85,6 @@ class BLIKComponentTests: XCTestCase { sut.viewDidLoad(viewController: sut.viewController) // Then - XCTAssertEqual(analyticsProviderMock.initialTelemetryEventCallsCount, 1) + XCTAssertEqual(analyticsProviderMock.initialEventCallsCount, 1) } } diff --git a/Tests/Components Tests/Boleto/BoletoComponentTests.swift b/Tests/Components Tests/Boleto/BoletoComponentTests.swift index 1265306c1d..70c859622c 100644 --- a/Tests/Components Tests/Boleto/BoletoComponentTests.swift +++ b/Tests/Components Tests/Boleto/BoletoComponentTests.swift @@ -138,6 +138,6 @@ class BoletoComponentTests: XCTestCase { component.viewDidLoad(viewController: component.viewController) // Then - XCTAssertEqual(analyticsProviderMock.initialTelemetryEventCallsCount, 1) + XCTAssertEqual(analyticsProviderMock.initialEventCallsCount, 1) } } diff --git a/Tests/Components Tests/Cash App Pay/CashAppPayComponentTests.swift b/Tests/Components Tests/Cash App Pay/CashAppPayComponentTests.swift index 4d10489338..cf640930ff 100644 --- a/Tests/Components Tests/Cash App Pay/CashAppPayComponentTests.swift +++ b/Tests/Components Tests/Cash App Pay/CashAppPayComponentTests.swift @@ -148,7 +148,7 @@ import XCTest sut.viewDidLoad(viewController: sut.viewController) // Then - XCTAssertEqual(analyticsProviderMock.initialTelemetryEventCallsCount, 1) + XCTAssertEqual(analyticsProviderMock.initialEventCallsCount, 1) } func testComponent_ShouldPaymentMethodTypeBeCashAppPay() throws { diff --git a/Tests/Components Tests/Doku/DokuComponentTests.swift b/Tests/Components Tests/Doku/DokuComponentTests.swift index 03343c9a83..5f2b79af9e 100644 --- a/Tests/Components Tests/Doku/DokuComponentTests.swift +++ b/Tests/Components Tests/Doku/DokuComponentTests.swift @@ -163,7 +163,7 @@ class DokuComponentTests: XCTestCase { sut.viewDidLoad(viewController: sut.viewController) // Then - XCTAssertEqual(analyticsProviderMock.initialTelemetryEventCallsCount, 1) + XCTAssertEqual(analyticsProviderMock.initialEventCallsCount, 1) } // MARK: - Private diff --git a/Tests/Components Tests/Gift Card/GiftCardComponentTests.swift b/Tests/Components Tests/Gift Card/GiftCardComponentTests.swift index 4125cd6840..d0fda93772 100644 --- a/Tests/Components Tests/Gift Card/GiftCardComponentTests.swift +++ b/Tests/Components Tests/Gift Card/GiftCardComponentTests.swift @@ -575,7 +575,7 @@ class GiftCardComponentTests: XCTestCase { sut.viewDidLoad(viewController: mockViewController) // Then - XCTAssertEqual(analyticsProviderMock.initialTelemetryEventCallsCount, 1) + XCTAssertEqual(analyticsProviderMock.initialEventCallsCount, 1) } func testGiftCardHidingSecurityCodeItemView() throws { diff --git a/Tests/Components Tests/IssuerList/IssuerListComponentTests.swift b/Tests/Components Tests/IssuerList/IssuerListComponentTests.swift index bafc0ef326..aedf5fb191 100644 --- a/Tests/Components Tests/IssuerList/IssuerListComponentTests.swift +++ b/Tests/Components Tests/IssuerList/IssuerListComponentTests.swift @@ -67,6 +67,6 @@ class IssuerListComponentTests: XCTestCase { sut.viewDidLoad(viewController: mockViewController) // Then - XCTAssertEqual(analyticsProviderMock.initialTelemetryEventCallsCount, 1) + XCTAssertEqual(analyticsProviderMock.initialEventCallsCount, 1) } } diff --git a/Tests/Components Tests/MB Way/MBWayComponentTests.swift b/Tests/Components Tests/MB Way/MBWayComponentTests.swift index 68c6b1596c..99db85e08b 100644 --- a/Tests/Components Tests/MB Way/MBWayComponentTests.swift +++ b/Tests/Components Tests/MB Way/MBWayComponentTests.swift @@ -126,7 +126,7 @@ class MBWayComponentTests: XCTestCase { sut.viewDidLoad(viewController: sut.viewController) // Then - XCTAssertEqual(analyticsProviderMock.initialTelemetryEventCallsCount, 1) + XCTAssertEqual(analyticsProviderMock.initialEventCallsCount, 1) } // MARK: - Private diff --git a/Tests/Components Tests/Qiwi Wallet/QiwiWalletComponentTests.swift b/Tests/Components Tests/Qiwi Wallet/QiwiWalletComponentTests.swift index 307b5573d5..faef470bf1 100644 --- a/Tests/Components Tests/Qiwi Wallet/QiwiWalletComponentTests.swift +++ b/Tests/Components Tests/Qiwi Wallet/QiwiWalletComponentTests.swift @@ -196,6 +196,6 @@ class QiwiWalletComponentTests: XCTestCase { sut.viewDidLoad(viewController: sut.viewController) // Then - XCTAssertEqual(analyticsProviderMock.initialTelemetryEventCallsCount, 1) + XCTAssertEqual(analyticsProviderMock.initialEventCallsCount, 1) } } diff --git a/Tests/Components Tests/SEPA Tests/SEPADirectDebitComponentTests.swift b/Tests/Components Tests/SEPA Tests/SEPADirectDebitComponentTests.swift index f9bef7360c..281238b7b2 100644 --- a/Tests/Components Tests/SEPA Tests/SEPADirectDebitComponentTests.swift +++ b/Tests/Components Tests/SEPA Tests/SEPADirectDebitComponentTests.swift @@ -253,6 +253,6 @@ class SEPADirectDebitComponentTests: XCTestCase { sut.viewDidLoad(viewController: mockViewController) // Then - XCTAssertEqual(analyticsProviderMock.initialTelemetryEventCallsCount, 1) + XCTAssertEqual(analyticsProviderMock.initialEventCallsCount, 1) } } From 7e1a7f3c4ecb685284eb9f358c30c8a2f6edd9e9 Mon Sep 17 00:00:00 2001 From: erenbesel Date: Thu, 8 Feb 2024 14:21:57 +0100 Subject: [PATCH 18/31] chore: remove unused analytics flavor --- .../AnalyticsProvider/AnalyticsFlavor.swift | 7 ------- .../AnalyticsProvider/AnalyticsProvider.swift | 1 - .../Analytics/AnalyticsEventTests.swift | 20 ++----------------- .../Analytics/AnalyticsFlavorTests.swift | 11 ---------- .../Analytics/AnalyticsProviderTests.swift | 8 ++++---- 5 files changed, 6 insertions(+), 41 deletions(-) diff --git a/Adyen/Analytics/AnalyticsProvider/AnalyticsFlavor.swift b/Adyen/Analytics/AnalyticsProvider/AnalyticsFlavor.swift index 6d3582fe8b..15a65ce8e4 100644 --- a/Adyen/Analytics/AnalyticsProvider/AnalyticsFlavor.swift +++ b/Adyen/Analytics/AnalyticsProvider/AnalyticsFlavor.swift @@ -11,19 +11,12 @@ public enum AnalyticsFlavor { case components(type: PaymentMethodType) case dropIn(type: String = "dropin", paymentMethods: [String]) - // The `dropInComponent` type describes a component within the drop-in component. - // In analytics, we need to distinguish when a component is used from the drop-in - // and when it's used as standalone. - case dropInComponent - public var value: String { switch self { case .components: return "components" case .dropIn: return "dropin" - case .dropInComponent: - return "dropInComponent" } } } diff --git a/Adyen/Analytics/AnalyticsProvider/AnalyticsProvider.swift b/Adyen/Analytics/AnalyticsProvider/AnalyticsProvider.swift index d20d9b6127..bfd62b860d 100644 --- a/Adyen/Analytics/AnalyticsProvider/AnalyticsProvider.swift +++ b/Adyen/Analytics/AnalyticsProvider/AnalyticsProvider.swift @@ -74,7 +74,6 @@ internal final class AnalyticsProvider: AnalyticsProviderProtocol { checkoutAttemptId = "do-not-track" return } - if case .dropInComponent = flavor { return } let analyticsData = AnalyticsData(flavor: flavor, additionalFields: additionalFields, diff --git a/Tests/Adyen Tests/Analytics/AnalyticsEventTests.swift b/Tests/Adyen Tests/Analytics/AnalyticsEventTests.swift index 6829e32097..5b79e7d8a6 100644 --- a/Tests/Adyen Tests/Analytics/AnalyticsEventTests.swift +++ b/Tests/Adyen Tests/Analytics/AnalyticsEventTests.swift @@ -50,25 +50,9 @@ class AnalyticsEventTests: XCTestCase { XCTAssertEqual(sut.checkoutAttemptId, "do-not-track") } - func testSendInitialEventGivenEnabledAndFlavorIsDropInComponentShouldNotSendAnyRequest() throws { - // Given - var analyticsConfiguration = AnalyticsConfiguration() - sut = AnalyticsProvider(apiClient: apiClient, configuration: analyticsConfiguration) - - let flavor: AnalyticsFlavor = .dropInComponent - let expectedRequestCalls = 0 - - // When - sendInitialAnalytics(flavor: flavor) - - // Then - XCTAssertEqual(expectedRequestCalls, apiClient.counter, "One or more analytics requests were sent.") - XCTAssertNil(sut.checkoutAttemptId) - } - func testSendInitialEventGivenEnabledAndFlavorIsComponentsShouldSendInitialRequest() throws { // Given - var analyticsConfiguration = AnalyticsConfiguration() + let analyticsConfiguration = AnalyticsConfiguration() sut = AnalyticsProvider(apiClient: apiClient, configuration: analyticsConfiguration) let flavor: AnalyticsFlavor = .components(type: .affirm) @@ -88,7 +72,7 @@ class AnalyticsEventTests: XCTestCase { func testSendInitialEventGivenEnabledAndFlavorIsDropInShouldSendInitialRequest() throws { // Given - var analyticsConfiguration = AnalyticsConfiguration() + let analyticsConfiguration = AnalyticsConfiguration() sut = AnalyticsProvider(apiClient: apiClient, configuration: analyticsConfiguration) let flavor: AnalyticsFlavor = .dropIn(paymentMethods: ["scheme", "paypal", "affirm"]) diff --git a/Tests/Adyen Tests/Analytics/AnalyticsFlavorTests.swift b/Tests/Adyen Tests/Analytics/AnalyticsFlavorTests.swift index 8ec0dbb670..96d0086a9c 100644 --- a/Tests/Adyen Tests/Analytics/AnalyticsFlavorTests.swift +++ b/Tests/Adyen Tests/Analytics/AnalyticsFlavorTests.swift @@ -39,15 +39,4 @@ class AnalyticsFlavorTests: XCTestCase { // Then XCTAssertEqual(expectedFlavorValue, sut.value) } - - func testAnalyticsFlavorValueWhenFlavorIsDropInComponentMatchesFlavorType() throws { - // Given - let expectedFlavorValue = "dropInComponent" - - // When - sut = .dropInComponent - - // Then - XCTAssertEqual(expectedFlavorValue, sut.value) - } } diff --git a/Tests/Adyen Tests/Analytics/AnalyticsProviderTests.swift b/Tests/Adyen Tests/Analytics/AnalyticsProviderTests.swift index 478a1dc695..21ba4a2d5e 100644 --- a/Tests/Adyen Tests/Analytics/AnalyticsProviderTests.swift +++ b/Tests/Adyen Tests/Analytics/AnalyticsProviderTests.swift @@ -87,7 +87,7 @@ class AnalyticsProviderTests: XCTestCase { apiClient.mockedResults = [checkoutAttemptIdResult] // When - sut.sendInitialAnalytics(with: .dropInComponent, additionalFields: nil) + sut.sendInitialAnalytics(with: .components(type: .atome), additionalFields: nil) // Then XCTAssertNil(sut.checkoutAttemptId, "The checkoutAttemptId is not nil.") } @@ -202,7 +202,7 @@ class AnalyticsProviderTests: XCTestCase { func testInitialRequestEncoding() throws { - let analyticsData = AnalyticsData(flavor: .dropInComponent, + let analyticsData = AnalyticsData(flavor: .components(type: .achDirectDebit), additionalFields: AdditionalAnalyticsFields(amount: .init(value: 1, currencyCode: "EUR"), sessionId: "test_session_id"), context: AnalyticsContext(version: "version", platform: .flutter)) @@ -215,8 +215,8 @@ class AnalyticsProviderTests: XCTestCase { "locale": "en_US", "paymentMethods": analyticsData.paymentMethods, "platform": "flutter", - "component": "", - "flavor": "dropInComponent", + "component": "ach", + "flavor": "components", "channel": "iOS", "systemVersion": analyticsData.systemVersion, "screenWidth": analyticsData.screenWidth, From 63016fdaebcce42e664feb3212e1552a274e8723 Mon Sep 17 00:00:00 2001 From: erenbesel Date: Fri, 9 Feb 2024 11:31:20 +0100 Subject: [PATCH 19/31] chore: update review comments --- .../AnalyticsProvider/AnalyticsProvider.swift | 22 +++++++++---------- Adyen/Analytics/Models/AnalyticsData.swift | 2 -- 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/Adyen/Analytics/AnalyticsProvider/AnalyticsProvider.swift b/Adyen/Analytics/AnalyticsProvider/AnalyticsProvider.swift index bfd62b860d..5610de9722 100644 --- a/Adyen/Analytics/AnalyticsProvider/AnalyticsProvider.swift +++ b/Adyen/Analytics/AnalyticsProvider/AnalyticsProvider.swift @@ -79,19 +79,19 @@ internal final class AnalyticsProvider: AnalyticsProviderProtocol { additionalFields: additionalFields, context: configuration.context) - fetchCheckoutAttemptId(with: analyticsData) - } - - private func fetchCheckoutAttemptId(with initialAnalyticsData: AnalyticsData) { - let initialAnalyticsRequest = InitialAnalyticsRequest(data: initialAnalyticsData) + let initialAnalyticsRequest = InitialAnalyticsRequest(data: analyticsData) uniqueAssetAPIClient.perform(initialAnalyticsRequest) { [weak self] result in - switch result { - case let .success(response): - self?.checkoutAttemptId = response.checkoutAttemptId - case .failure: - self?.checkoutAttemptId = nil - } + self?.saveCheckoutAttemptId(from: result) + } + } + + private func saveCheckoutAttemptId(from result: Result) { + switch result { + case let .success(response): + checkoutAttemptId = response.checkoutAttemptId + case .failure: + checkoutAttemptId = nil } } } diff --git a/Adyen/Analytics/Models/AnalyticsData.swift b/Adyen/Analytics/Models/AnalyticsData.swift index dcb6845b58..a5b04159e5 100644 --- a/Adyen/Analytics/Models/AnalyticsData.swift +++ b/Adyen/Analytics/Models/AnalyticsData.swift @@ -105,8 +105,6 @@ internal struct AnalyticsData: Encodable { self.component = type case let .components(type): self.component = type.rawValue - default: - self.component = "" } } } From ad4147d02658bf6772f434a0f2289451dd4d4816 Mon Sep 17 00:00:00 2001 From: erenbesel Date: Fri, 9 Feb 2024 15:53:04 +0100 Subject: [PATCH 20/31] chore: conform dropin to trackable component --- AdyenDropIn/DropInComponentExtensions.swift | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/AdyenDropIn/DropInComponentExtensions.swift b/AdyenDropIn/DropInComponentExtensions.swift index 7879b24edb..2a7a3aff05 100644 --- a/AdyenDropIn/DropInComponentExtensions.swift +++ b/AdyenDropIn/DropInComponentExtensions.swift @@ -21,11 +21,7 @@ import UIKit extension DropInComponent: PaymentMethodListComponentDelegate { internal func didLoad(_ paymentMethodListComponent: PaymentMethodListComponent) { - let paymentMethodTypes = paymentMethods.regular.map(\.type.rawValue) - let flavor = AnalyticsFlavor.dropIn(paymentMethods: paymentMethodTypes) - let amount = context.payment?.amount - let additionalFields = AdditionalAnalyticsFields(amount: amount, sessionId: AnalyticsForSession.sessionId) - context.analyticsProvider?.sendInitialAnalytics(with: flavor, additionalFields: additionalFields) + sendInitialAnalytics() } internal func didSelect(_ component: PaymentComponent, @@ -159,3 +155,15 @@ extension DropInComponent: ReadyToSubmitPaymentComponentDelegate { rootComponent = newRoot } } + +@_spi(AdyenInternal) +extension DropInComponent: TrackableComponent { + + public func sendInitialAnalytics() { + let paymentMethodTypes = paymentMethods.regular.map(\.type.rawValue) + let flavor = AnalyticsFlavor.dropIn(paymentMethods: paymentMethodTypes) + let amount = context.payment?.amount + let additionalFields = AdditionalAnalyticsFields(amount: amount, sessionId: AnalyticsForSession.sessionId) + context.analyticsProvider?.sendInitialAnalytics(with: flavor, additionalFields: additionalFields) + } +} From 663f10bf6a254601c27f2f77dd4e184b4594b6bb Mon Sep 17 00:00:00 2001 From: Andrii Mamchenko Date: Wed, 14 Feb 2024 20:19:22 +0100 Subject: [PATCH 21/31] Improve Apple Pay flow state naming This change makes state naming more precise as we might receive an error after submitting payment details to Apple so `submitted` fits and reads better and doesn't provoke any false assumptions. --- AdyenComponents/Apple Pay/ApplePayComponent.swift | 6 +++--- AdyenComponents/Apple Pay/ApplePayComponentExtensions.swift | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/AdyenComponents/Apple Pay/ApplePayComponent.swift b/AdyenComponents/Apple Pay/ApplePayComponent.swift index d583f9ee37..74fa5a796f 100644 --- a/AdyenComponents/Apple Pay/ApplePayComponent.swift +++ b/AdyenComponents/Apple Pay/ApplePayComponent.swift @@ -1,5 +1,5 @@ // -// Copyright (c) 2023 Adyen N.V. +// Copyright (c) 2024 Adyen N.V. // // This file is open source and available under the MIT license. See the LICENSE file for more info. // @@ -83,7 +83,7 @@ public class ApplePayComponent: NSObject, PresentableComponent, PaymentComponent } public func didFinalize(with success: Bool, completion: (() -> Void)?) { - if case let .paid(paymentAuthorizationCompletion) = state { + if case let .submitted(paymentAuthorizationCompletion) = state { state = .finalized(completion) paymentAuthorizationCompletion(success ? .success : .failure) } else { @@ -120,7 +120,7 @@ extension ApplePayComponent { internal enum State { case initial - case paid((PKPaymentAuthorizationStatus) -> Void) + case submitted((PKPaymentAuthorizationStatus) -> Void) case finalized((() -> Void)?) } diff --git a/AdyenComponents/Apple Pay/ApplePayComponentExtensions.swift b/AdyenComponents/Apple Pay/ApplePayComponentExtensions.swift index e518a66eac..931bde463d 100644 --- a/AdyenComponents/Apple Pay/ApplePayComponentExtensions.swift +++ b/AdyenComponents/Apple Pay/ApplePayComponentExtensions.swift @@ -1,5 +1,5 @@ // -// Copyright (c) 2022 Adyen N.V. +// Copyright (c) 2024 Adyen N.V. // // This file is open source and available under the MIT license. See the LICENSE file for more info. // @@ -29,7 +29,7 @@ extension ApplePayComponent: PKPaymentAuthorizationViewControllerDelegate { return } - state = .paid(completion) + state = .submitted(completion) let token = payment.token.paymentData.base64EncodedString() let network = payment.token.paymentMethod.network?.rawValue ?? "" let details = ApplePayDetails(paymentMethod: applePayPaymentMethod, From 0e8b35095ba9484843892d3212157bf8bedbe733 Mon Sep 17 00:00:00 2001 From: erenbesel Date: Mon, 19 Feb 2024 15:27:51 +0100 Subject: [PATCH 22/31] chore: Extend TrackableComponent default extension to dropin --- Adyen.xcodeproj/project.pbxproj | 4 ++ .../Core Protocols/PresentableComponent.swift | 29 ----------- .../Core Protocols/TrackableComponent.swift | 48 +++++++++++++++++++ AdyenDropIn/DropInComponentExtensions.swift | 8 +--- 4 files changed, 54 insertions(+), 35 deletions(-) create mode 100644 Adyen/Core/Core Protocols/TrackableComponent.swift diff --git a/Adyen.xcodeproj/project.pbxproj b/Adyen.xcodeproj/project.pbxproj index f0da73cbe9..ac6e16f664 100644 --- a/Adyen.xcodeproj/project.pbxproj +++ b/Adyen.xcodeproj/project.pbxproj @@ -279,6 +279,7 @@ A09ADA112807142600BF6802 /* SessionRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = A09ADA102807142600BF6802 /* SessionRequest.swift */; }; A09ADA122807142600BF6802 /* SessionRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = A09ADA102807142600BF6802 /* SessionRequest.swift */; }; A09C704327032870004C01AA /* FormCardLogosItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A09C704227032870004C01AA /* FormCardLogosItemView.swift */; }; + A09FB2EB2B8399B700270D51 /* TrackableComponent.swift in Sources */ = {isa = PBXBuildFile; fileRef = A09FB2EA2B8399B700270D51 /* TrackableComponent.swift */; }; A0B180312A2DE445003C608E /* MealVoucherDetails.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0B180302A2DE445003C608E /* MealVoucherDetails.swift */; }; A0BC64E628F062E400CED2A1 /* AdyenSessionAware.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0BC64E528F062E400CED2A1 /* AdyenSessionAware.swift */; }; A0C9B59B288AE34600D6BDAB /* InstallmentOptions.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0F41E5526CBCA6E0089AD6C /* InstallmentOptions.swift */; }; @@ -1522,6 +1523,7 @@ A07B2CF126A5D4FE0008185C /* BrazilSocialSecurityNumberFormatterTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BrazilSocialSecurityNumberFormatterTests.swift; sourceTree = ""; }; A09ADA102807142600BF6802 /* SessionRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionRequest.swift; sourceTree = ""; }; A09C704227032870004C01AA /* FormCardLogosItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FormCardLogosItemView.swift; sourceTree = ""; }; + A09FB2EA2B8399B700270D51 /* TrackableComponent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrackableComponent.swift; sourceTree = ""; }; A0B180302A2DE445003C608E /* MealVoucherDetails.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MealVoucherDetails.swift; sourceTree = ""; }; A0BC64E528F062E400CED2A1 /* AdyenSessionAware.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdyenSessionAware.swift; sourceTree = ""; }; A0D48FB727109B0200C0B82C /* ArrayHelpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArrayHelpers.swift; sourceTree = ""; }; @@ -4567,6 +4569,7 @@ E226F54A229803130013A463 /* DropInComponentDelegate.swift */, E7D418B0286E4C5900E9A7F4 /* PaymentAwareComponent.swift */, A0BC64E528F062E400CED2A1 /* AdyenSessionAware.swift */, + A09FB2EA2B8399B700270D51 /* TrackableComponent.swift */, ); path = "Core Protocols"; sourceTree = ""; @@ -6667,6 +6670,7 @@ C982FFDC2694792F00AED849 /* AffirmPaymentMethod.swift in Sources */, F9B798C923AB697100A2103C /* FormComponentStyle.swift in Sources */, E708591F261F1CB800D0153B /* FormVerticalStackItemView.swift in Sources */, + A09FB2EB2B8399B700270D51 /* TrackableComponent.swift in Sources */, E7275BF9255012F600907CF9 /* FormLabelItem.swift in Sources */, E2D12BEF221D560800EF682F /* FormValueItem.swift in Sources */, E76EC6882412581E009C6E2F /* FormTextInputItem.swift in Sources */, diff --git a/Adyen/Core/Core Protocols/PresentableComponent.swift b/Adyen/Core/Core Protocols/PresentableComponent.swift index 15b89eb4b0..b0cb2f6ea0 100644 --- a/Adyen/Core/Core Protocols/PresentableComponent.swift +++ b/Adyen/Core/Core Protocols/PresentableComponent.swift @@ -59,32 +59,3 @@ public extension PresentableComponent { var navBarType: NavigationBarType { .regular } } - -@_spi(AdyenInternal) -public protocol TrackableComponent: Component { - - /// Sends the initial data and retrieves the checkout attempt id - func sendInitialAnalytics() -} - -@_spi(AdyenInternal) -extension TrackableComponent where Self: ViewControllerDelegate { - - public func viewDidLoad(viewController: UIViewController) { - sendInitialAnalytics() - } -} - -@_spi(AdyenInternal) -extension TrackableComponent where Self: PaymentMethodAware { - - public func sendInitialAnalytics() { - // initial call is not needed again if inside dropIn - guard !_isDropIn else { return } - let flavor: AnalyticsFlavor = .components(type: paymentMethod.type) - let amount = context.payment?.amount - let additionalFields = AdditionalAnalyticsFields(amount: amount, sessionId: AnalyticsForSession.sessionId) - context.analyticsProvider?.sendInitialAnalytics(with: flavor, - additionalFields: additionalFields) - } -} diff --git a/Adyen/Core/Core Protocols/TrackableComponent.swift b/Adyen/Core/Core Protocols/TrackableComponent.swift new file mode 100644 index 0000000000..b2a4ef1af0 --- /dev/null +++ b/Adyen/Core/Core Protocols/TrackableComponent.swift @@ -0,0 +1,48 @@ +// +// Copyright (c) 2024 Adyen N.V. +// +// This file is open source and available under the MIT license. See the LICENSE file for more info. +// + +import Foundation + +/// A component that can send analytics events. +@_spi(AdyenInternal) +public protocol TrackableComponent: Component { + + /// Analytics flavor to determine the component / dropIn that initiates the events. + var analyticsFlavor: AnalyticsFlavor { get } + + /// Sends the initial data and retrieves the checkout attempt id + func sendInitialAnalytics() +} + +@_spi(AdyenInternal) +extension TrackableComponent where Self: ViewControllerDelegate { + + public func viewDidLoad(viewController: UIViewController) { + sendInitialAnalytics() + } +} + +// Generic extension to send events for all components and dropIn. +@_spi(AdyenInternal) +extension TrackableComponent { + + public func sendInitialAnalytics() { + // initial call is not needed again if inside dropIn + guard !_isDropIn else { return } + let amount = context.payment?.amount + let additionalFields = AdditionalAnalyticsFields(amount: amount, sessionId: AnalyticsForSession.sessionId) + context.analyticsProvider?.sendInitialAnalytics(with: analyticsFlavor, + additionalFields: additionalFields) + } +} + +@_spi(AdyenInternal) +extension TrackableComponent where Self: PaymentMethodAware { + + public var analyticsFlavor: AnalyticsFlavor { + .components(type: paymentMethod.type) + } +} diff --git a/AdyenDropIn/DropInComponentExtensions.swift b/AdyenDropIn/DropInComponentExtensions.swift index 2a7a3aff05..d5b9b7ad02 100644 --- a/AdyenDropIn/DropInComponentExtensions.swift +++ b/AdyenDropIn/DropInComponentExtensions.swift @@ -158,12 +158,8 @@ extension DropInComponent: ReadyToSubmitPaymentComponentDelegate { @_spi(AdyenInternal) extension DropInComponent: TrackableComponent { - - public func sendInitialAnalytics() { + public var analyticsFlavor: AnalyticsFlavor { let paymentMethodTypes = paymentMethods.regular.map(\.type.rawValue) - let flavor = AnalyticsFlavor.dropIn(paymentMethods: paymentMethodTypes) - let amount = context.payment?.amount - let additionalFields = AdditionalAnalyticsFields(amount: amount, sessionId: AnalyticsForSession.sessionId) - context.analyticsProvider?.sendInitialAnalytics(with: flavor, additionalFields: additionalFields) + return .dropIn(paymentMethods: paymentMethodTypes) } } From 470f2a35ea4f6205252bed2b62c80b6797a5d9fd Mon Sep 17 00:00:00 2001 From: erenbesel Date: Tue, 20 Feb 2024 10:26:38 +0100 Subject: [PATCH 23/31] chore: fix UIKit import --- Adyen/Core/Core Protocols/TrackableComponent.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/Adyen/Core/Core Protocols/TrackableComponent.swift b/Adyen/Core/Core Protocols/TrackableComponent.swift index b2a4ef1af0..35b31cd9f1 100644 --- a/Adyen/Core/Core Protocols/TrackableComponent.swift +++ b/Adyen/Core/Core Protocols/TrackableComponent.swift @@ -5,6 +5,7 @@ // import Foundation +import UIKit /// A component that can send analytics events. @_spi(AdyenInternal) From 45e1b26749831d7fb74391b32542734d3de0695c Mon Sep 17 00:00:00 2001 From: Alex Guretzki Date: Wed, 21 Feb 2024 13:59:56 +0100 Subject: [PATCH 24/31] Using custom sim for 16.4 compatibility testing --- .github/workflows/build.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 3d0bf91e2a..81142ca267 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -16,9 +16,11 @@ jobs: include: - version: '16.4' - displayname: 'iPhone 14' + runtime: 'iOS-16-4' + device: 'iPhone 14' + displayname: 'iPhone-14' os: 'macos-13-xl' - needs_custom_sim: false # Takes the shipped simulator that comes with Xcode 14 + needs_custom_sim: true - version: '15.0' runtime: 'iOS-15-0' From 06f17ad2bb50f438478b195fa87ea2706c67ea95 Mon Sep 17 00:00:00 2001 From: Alex Guretzki Date: Wed, 21 Feb 2024 14:05:11 +0100 Subject: [PATCH 25/31] Update build.yml --- .github/workflows/build.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 81142ca267..2d3950685f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -15,11 +15,11 @@ jobs: matrix: include: - - version: '16.4' - runtime: 'iOS-16-4' - device: 'iPhone 14' - displayname: 'iPhone-14' - os: 'macos-13-xl' + - version: '16.2' + runtime: 'iOS-16-2' + device: 'iPhone 13' + displayname: 'iPhone-13' + os: 'macos-12-xl' needs_custom_sim: true - version: '15.0' From 949193c9ac45976cc8a1d5d936fcdf15758b38a9 Mon Sep 17 00:00:00 2001 From: Alex Guretzki Date: Wed, 21 Feb 2024 14:14:05 +0100 Subject: [PATCH 26/31] Update build.yml --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2d3950685f..c3787c9631 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -19,7 +19,7 @@ jobs: runtime: 'iOS-16-2' device: 'iPhone 13' displayname: 'iPhone-13' - os: 'macos-12-xl' + os: 'macos-12' needs_custom_sim: true - version: '15.0' From cf1af461bf01987b7545aed044f3593c183c8691 Mon Sep 17 00:00:00 2001 From: Alex Guretzki Date: Wed, 21 Feb 2024 14:29:13 +0100 Subject: [PATCH 27/31] Update build.yml --- .github/workflows/build.yml | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index c3787c9631..c97e42a635 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -15,12 +15,12 @@ jobs: matrix: include: - - version: '16.2' - runtime: 'iOS-16-2' - device: 'iPhone 13' - displayname: 'iPhone-13' - os: 'macos-12' - needs_custom_sim: true + - version: '16.4' + runtime: 'iOS-16-4' + device: 'iPhone 14' + displayname: 'iPhone-14' + os: 'macos-13-xl' + needs_custom_sim: false # Takes the shipped simulator that comes with Xcode 14 - version: '15.0' runtime: 'iOS-15-0' @@ -53,10 +53,15 @@ jobs: run: | sudo mkdir -p /Library/Developer/CoreSimulator/Profiles/Runtimes - - name: Prepare ${{ matrix.version }} + - name: Download simulator if needed (${{ matrix.version }}) if: matrix.needs_custom_sim run: | xcversion simulators --install="iOS ${version}" + env: + version: ${{ matrix.version }} + + - name: Create simulator ${{ matrix.version }} + run: | xcrun simctl list devices ${version} xcrun simctl create ${displayname} "${device}" "com.apple.CoreSimulator.SimRuntime.${runtime}" env: From f1b6ff7b85ef1be9f6a3dbbbf0656bc5908b3676 Mon Sep 17 00:00:00 2001 From: Alex Guretzki Date: Wed, 21 Feb 2024 14:41:32 +0100 Subject: [PATCH 28/31] Update build.yml --- .github/workflows/build.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index c97e42a635..44f4ef643e 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -20,6 +20,7 @@ jobs: device: 'iPhone 14' displayname: 'iPhone-14' os: 'macos-13-xl' + xcode_version: '14.3' needs_custom_sim: false # Takes the shipped simulator that comes with Xcode 14 - version: '15.0' @@ -27,6 +28,7 @@ jobs: device: 'iPhone 13' displayname: 'iPhone-13' os: 'macos-12-xl' + xcode_version: '13.4.1' needs_custom_sim: true - version: '14.2' @@ -34,6 +36,7 @@ jobs: displayname: 'iPhone-12' runtime: 'iOS-14-2' os: 'macos-12-xl' + xcode_version: '13.4.1' needs_custom_sim: true - version: '13.7' @@ -41,6 +44,7 @@ jobs: device: 'iPhone 11' displayname: 'iPhone-11' os: 'macos-12-xl' + xcode_version: '13.4.1' needs_custom_sim: true steps: @@ -53,6 +57,12 @@ jobs: run: | sudo mkdir -p /Library/Developer/CoreSimulator/Profiles/Runtimes + - name: Select Xcode ${{ matrix.xcode_version}} + run: | + sudo xcode-select -s /Applications/Xcode_${xcode_version}.app/Contents/Developer + env: + xcode_version: ${{ matrix.xcode_version }} + - name: Download simulator if needed (${{ matrix.version }}) if: matrix.needs_custom_sim run: | From 3c00e276f14977c1ccda5a0bf12fafcee7d260ba Mon Sep 17 00:00:00 2001 From: Alex Guretzki Date: Wed, 21 Feb 2024 14:45:42 +0100 Subject: [PATCH 29/31] Update build.yml --- .github/workflows/build.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 44f4ef643e..88c5892093 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -59,6 +59,7 @@ jobs: - name: Select Xcode ${{ matrix.xcode_version}} run: | + ls /Applications/Xcode_*.app sudo xcode-select -s /Applications/Xcode_${xcode_version}.app/Contents/Developer env: xcode_version: ${{ matrix.xcode_version }} From 14ccd05330b1b7b72612adae619115a5cba446af Mon Sep 17 00:00:00 2001 From: Alex Guretzki Date: Thu, 22 Feb 2024 09:32:22 +0100 Subject: [PATCH 30/31] Update build.yml --- .github/workflows/build.yml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 88c5892093..fe16d2e02f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -28,7 +28,6 @@ jobs: device: 'iPhone 13' displayname: 'iPhone-13' os: 'macos-12-xl' - xcode_version: '13.4.1' needs_custom_sim: true - version: '14.2' @@ -36,7 +35,6 @@ jobs: displayname: 'iPhone-12' runtime: 'iOS-14-2' os: 'macos-12-xl' - xcode_version: '13.4.1' needs_custom_sim: true - version: '13.7' @@ -44,7 +42,6 @@ jobs: device: 'iPhone 11' displayname: 'iPhone-11' os: 'macos-12-xl' - xcode_version: '13.4.1' needs_custom_sim: true steps: @@ -57,7 +54,8 @@ jobs: run: | sudo mkdir -p /Library/Developer/CoreSimulator/Profiles/Runtimes - - name: Select Xcode ${{ matrix.xcode_version}} + - name: Select Xcode ${{ matrix.xcode_version }} + if: matrix.xcode_version != '' run: | ls /Applications/Xcode_*.app sudo xcode-select -s /Applications/Xcode_${xcode_version}.app/Contents/Developer From d9bffaf69346f30b868febb44635f8f9de9600a8 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 23 Feb 2024 11:55:55 +0000 Subject: [PATCH 31/31] chore(deps): update peter-evans/create-pull-request action to v6 --- .github/workflows/format_project.yml | 2 +- .github/workflows/regenerate-docs.yml | 2 +- .github/workflows/update-version.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/format_project.yml b/.github/workflows/format_project.yml index dfc27fea7d..4f3bd7c0b2 100644 --- a/.github/workflows/format_project.yml +++ b/.github/workflows/format_project.yml @@ -22,7 +22,7 @@ jobs: brew install swiftformat swiftformat . - name: Create Pull Request - uses: peter-evans/create-pull-request@v5 + uses: peter-evans/create-pull-request@v6 with: delete-branch: true branch: format-project-github-action diff --git a/.github/workflows/regenerate-docs.yml b/.github/workflows/regenerate-docs.yml index 7eddc79777..bf3870f4df 100644 --- a/.github/workflows/regenerate-docs.yml +++ b/.github/workflows/regenerate-docs.yml @@ -28,7 +28,7 @@ jobs: env: LATEST_VERSION: ${{ github.event.inputs.latestVersion }} - name: Create Pull Request - uses: peter-evans/create-pull-request@v5 + uses: peter-evans/create-pull-request@v6 with: delete-branch: true branch: update-docs-github-action diff --git a/.github/workflows/update-version.yml b/.github/workflows/update-version.yml index d39d8f52ef..6a1e049300 100644 --- a/.github/workflows/update-version.yml +++ b/.github/workflows/update-version.yml @@ -26,7 +26,7 @@ jobs: run: | Scripts/increment_version.sh ${{ github.event.inputs.newVersion }} - name: Create Pull Request - uses: peter-evans/create-pull-request@v5 + uses: peter-evans/create-pull-request@v6 with: delete-branch: true branch: update-version-github-action