From 7b3cca106525d4e2a10162fcbe54609aad57877f Mon Sep 17 00:00:00 2001 From: Alessandro Boron Date: Thu, 19 Sep 2024 19:02:10 +1000 Subject: [PATCH] Onboarding highlights pixels (#3365) Task/Issue URL: https://app.asana.com/0/1206329551987282/1208084960727012 **Description**: 1. Add pixels to Onboarding Highlights experiment. [Commit](https://github.com/duckduckgo/iOS/commit/e57c3fbd477fc3252d822fb165bd96da0062e9c7) 2. Remove previous onboarding experiment temporary pixels. [Commit](https://github.com/duckduckgo/iOS/commit/ccc4a0117f2c18608ff1e2ee2ba8afe99dca8734) --- Core/PixelEvent.swift | 12 ++ .../NewTabDaxDialogFactory.swift | 3 +- .../ContextualDaxDialogsFactory.swift | 3 +- .../OnboardingIntroViewModel.swift | 18 +- .../Pixels/OnboardingPixelReporter.swift | 35 +++- .../ContextualDaxDialogsFactoryTests.swift | 14 ++ ...alOnboardingNewTabDialogFactoryTests.swift | 21 ++- .../OnboardingIntroViewModelTests.swift | 156 +++++++++++++----- .../OnboardingPixelReporterMock.swift | 31 +++- .../OnboardingPixelReporterTests.swift | 130 ++++++++++----- 10 files changed, 324 insertions(+), 99 deletions(-) diff --git a/Core/PixelEvent.swift b/Core/PixelEvent.swift index b9a2cf6dae..2f67e300f1 100644 --- a/Core/PixelEvent.swift +++ b/Core/PixelEvent.swift @@ -144,6 +144,11 @@ extension Pixel { case onboardingIntroShownUnique case onboardingIntroComparisonChartShownUnique case onboardingIntroChooseBrowserCTAPressed + case onboardingIntroChooseAppIconImpressionUnique + case onboardingIntroChooseCustomAppIconColorCTAPressed + case onboardingIntroChooseAddressBarImpressionUnique + case onboardingIntroBottomAddressBarSelected + case onboardingContextualSearchOptionTappedUnique case onboardingContextualSearchCustomUnique case onboardingContextualSiteOptionTappedUnique @@ -164,6 +169,7 @@ extension Pixel { case daxDialogsFireEducationCancelledUnique case daxDialogsEndOfJourneyTabUnique case daxDialogsEndOfJourneyNewTabUnique + case daxDialogsEndOfJourneyDismissed case widgetsOnboardingCTAPressed case widgetsOnboardingDeclineOptionPressed @@ -953,6 +959,11 @@ extension Pixel.Event { case .onboardingIntroShownUnique: return "m_preonboarding_intro_shown_unique" case .onboardingIntroComparisonChartShownUnique: return "m_preonboarding_comparison_chart_shown_unique" case .onboardingIntroChooseBrowserCTAPressed: return "m_preonboarding_choose_browser_pressed" + case .onboardingIntroChooseAppIconImpressionUnique: return "m_preonboarding_choose_icon_impressions_unique" + case .onboardingIntroChooseCustomAppIconColorCTAPressed: return "m_preonboarding_icon_color_chosen" + case .onboardingIntroChooseAddressBarImpressionUnique: return "m_preonboarding_choose_address_bar_impressions_unique" + case .onboardingIntroBottomAddressBarSelected: return "m_preonboarding_bottom_address_bar_selected" + case .onboardingContextualSearchOptionTappedUnique: return "m_onboarding_search_option_tapped_unique" case .onboardingContextualSiteOptionTappedUnique: return "m_onboarding_visit_site_option_tapped_unique" case .onboardingContextualSecondSiteVisitUnique: return "m_second_sitevisit_unique" @@ -973,6 +984,7 @@ extension Pixel.Event { case .daxDialogsFireEducationCancelledUnique: return "m_dx_fe_ca_unique" case .daxDialogsEndOfJourneyTabUnique: return "m_dx_end_tab_unique" case .daxDialogsEndOfJourneyNewTabUnique: return "m_dx_end_new_tab_unique" + case .daxDialogsEndOfJourneyDismissed: return "m_dx_end_dialog_dismissed" case .widgetsOnboardingCTAPressed: return "m_o_w_a" case .widgetsOnboardingDeclineOptionPressed: return "m_o_w_d" diff --git a/DuckDuckGo/OnboardingExperiment/ContextualDaxDialogs/NewTabDaxDialogFactory.swift b/DuckDuckGo/OnboardingExperiment/ContextualDaxDialogs/NewTabDaxDialogFactory.swift index 7f6f068844..6d99fc21d9 100644 --- a/DuckDuckGo/OnboardingExperiment/ContextualDaxDialogs/NewTabDaxDialogFactory.swift +++ b/DuckDuckGo/OnboardingExperiment/ContextualDaxDialogs/NewTabDaxDialogFactory.swift @@ -102,7 +102,8 @@ final class NewTabDaxDialogFactory: NewTabDaxDialogProvider { let message = onboardingManager.isOnboardingHighlightsEnabled ? UserText.HighlightsOnboardingExperiment.ContextualOnboarding.onboardingFinalScreenMessage : UserText.DaxOnboardingExperiment.ContextualOnboarding.onboardingFinalScreenMessage return FadeInView { - OnboardingFinalDialog(message: message, highFiveAction: { + OnboardingFinalDialog(message: message, highFiveAction: { [weak self] in + self?.onboardingPixelReporter.trackEndOfJourneyDialogCTAAction() onDismiss() }) .onboardingDaxDialogStyle() diff --git a/DuckDuckGo/OnboardingExperiment/ContextualOnboarding/ContextualDaxDialogsFactory.swift b/DuckDuckGo/OnboardingExperiment/ContextualOnboarding/ContextualDaxDialogsFactory.swift index 04fa68f5df..2ca605f244 100644 --- a/DuckDuckGo/OnboardingExperiment/ContextualOnboarding/ContextualDaxDialogsFactory.swift +++ b/DuckDuckGo/OnboardingExperiment/ContextualOnboarding/ContextualDaxDialogsFactory.swift @@ -175,8 +175,9 @@ final class ExperimentContextualDaxDialogsFactory: ContextualDaxDialogsFactory { private func endOfJourneyDialog(delegate: ContextualOnboardingDelegate, pixelName: Pixel.Event) -> some View { let message = onboardingManager.isOnboardingHighlightsEnabled ? UserText.HighlightsOnboardingExperiment.ContextualOnboarding.onboardingFinalScreenMessage : UserText.DaxOnboardingExperiment.ContextualOnboarding.onboardingFinalScreenMessage - return OnboardingFinalDialog(message: message, highFiveAction: { [weak delegate] in + return OnboardingFinalDialog(message: message, highFiveAction: { [weak delegate, weak self] in delegate?.didTapDismissContextualOnboardingAction() + self?.contextualOnboardingPixelReporter.trackEndOfJourneyDialogCTAAction() }) .onFirstAppear { [weak self] in self?.contextualOnboardingLogic.setFinalOnboardingDialogSeen() diff --git a/DuckDuckGo/OnboardingExperiment/OnboardingIntro/OnboardingIntroViewModel.swift b/DuckDuckGo/OnboardingExperiment/OnboardingIntro/OnboardingIntroViewModel.swift index 419ea7daf1..af1622a3d0 100644 --- a/DuckDuckGo/OnboardingExperiment/OnboardingIntro/OnboardingIntroViewModel.swift +++ b/DuckDuckGo/OnboardingExperiment/OnboardingIntro/OnboardingIntroViewModel.swift @@ -34,17 +34,24 @@ final class OnboardingIntroViewModel: ObservableObject { private let onboardingManager: OnboardingHighlightsManaging private let isIpad: Bool private let urlOpener: URLOpener + private let appIconProvider: () -> AppIcon + private let addressBarPositionProvider: () -> AddressBarPosition init( pixelReporter: OnboardingIntroPixelReporting, onboardingManager: OnboardingHighlightsManaging = OnboardingManager(), isIpad: Bool = UIDevice.current.userInterfaceIdiom == .pad, - urlOpener: URLOpener = UIApplication.shared + urlOpener: URLOpener = UIApplication.shared, + appIconProvider: @escaping () -> AppIcon = { AppIconManager.shared.appIcon }, + addressBarPositionProvider: @escaping () -> AddressBarPosition = { AppUserDefaults().currentAddressBarPosition } ) { self.pixelReporter = pixelReporter self.onboardingManager = onboardingManager self.isIpad = isIpad self.urlOpener = urlOpener + self.appIconProvider = appIconProvider + self.addressBarPositionProvider = addressBarPositionProvider + introSteps = if onboardingManager.isOnboardingHighlightsEnabled { isIpad ? OnboardingIntroStep.highlightsIPadFlow : OnboardingIntroStep.highlightsIPhoneFlow } else { @@ -79,14 +86,22 @@ final class OnboardingIntroViewModel: ObservableObject { } func appIconPickerContinueAction() { + if appIconProvider() != .defaultAppIcon { + pixelReporter.trackChooseCustomAppIconColor() + } + if isIpad { onCompletingOnboardingIntro?() } else { state = makeViewState(for: .addressBarPositionSelection) + pixelReporter.trackAddressBarPositionSelectionImpression() } } func selectAddressBarPositionAction() { + if addressBarPositionProvider() == .bottom { + pixelReporter.trackChooseBottomAddressBarPosition() + } onCompletingOnboardingIntro?() } @@ -127,6 +142,7 @@ private extension OnboardingIntroViewModel { func handleSetDefaultBrowserAction() { if onboardingManager.isOnboardingHighlightsEnabled { state = makeViewState(for: .appIconSelection) + pixelReporter.trackChooseAppIconImpression() } else { onCompletingOnboardingIntro?() } diff --git a/DuckDuckGo/OnboardingExperiment/Pixels/OnboardingPixelReporter.swift b/DuckDuckGo/OnboardingExperiment/Pixels/OnboardingPixelReporter.swift index ce0cfa348d..1882e2c3e7 100644 --- a/DuckDuckGo/OnboardingExperiment/Pixels/OnboardingPixelReporter.swift +++ b/DuckDuckGo/OnboardingExperiment/Pixels/OnboardingPixelReporter.swift @@ -49,6 +49,10 @@ protocol OnboardingIntroImpressionReporting { protocol OnboardingIntroPixelReporting: OnboardingIntroImpressionReporting { func trackBrowserComparisonImpression() func trackChooseBrowserCTAAction() + func trackChooseAppIconImpression() + func trackChooseCustomAppIconColor() + func trackAddressBarPositionSelectionImpression() + func trackChooseBottomAddressBarPosition() } protocol OnboardingCustomInteractionPixelReporting { @@ -58,11 +62,12 @@ protocol OnboardingCustomInteractionPixelReporting { func trackPrivacyDashboardOpenedForFirstTime() } -protocol OnboardingScreenImpressionReporting { +protocol OnboardingDaxDialogsReporting { func trackScreenImpression(event: Pixel.Event) + func trackEndOfJourneyDialogCTAAction() } -typealias OnboardingPixelReporting = OnboardingIntroImpressionReporting & OnboardingIntroPixelReporting & OnboardingSearchSuggestionsPixelReporting & OnboardingSiteSuggestionsPixelReporting & OnboardingCustomInteractionPixelReporting & OnboardingScreenImpressionReporting +typealias OnboardingPixelReporting = OnboardingIntroImpressionReporting & OnboardingIntroPixelReporting & OnboardingSearchSuggestionsPixelReporting & OnboardingSiteSuggestionsPixelReporting & OnboardingCustomInteractionPixelReporting & OnboardingDaxDialogsReporting // MARK: - Implementation @@ -146,6 +151,22 @@ extension OnboardingPixelReporter: OnboardingIntroPixelReporting { fire(event: .onboardingIntroChooseBrowserCTAPressed, unique: false) } + func trackChooseAppIconImpression() { + fire(event: .onboardingIntroChooseAppIconImpressionUnique, unique: true, includedParameters: [.appVersion]) + } + + func trackChooseCustomAppIconColor() { + fire(event: .onboardingIntroChooseCustomAppIconColorCTAPressed, unique: false, includedParameters: [.appVersion]) + } + + func trackAddressBarPositionSelectionImpression() { + fire(event: .onboardingIntroChooseAddressBarImpressionUnique, unique: true, includedParameters: [.appVersion]) + } + + func trackChooseBottomAddressBarPosition() { + fire(event: .onboardingIntroBottomAddressBarSelected, unique: false, includedParameters: [.appVersion]) + } + } // MARK: - OnboardingPixelReporter + List @@ -153,7 +174,7 @@ extension OnboardingPixelReporter: OnboardingIntroPixelReporting { extension OnboardingPixelReporter: OnboardingSearchSuggestionsPixelReporting { func trackSearchSuggetionOptionTapped() { - fire(event: .onboardingContextualSearchOptionTappedUnique, unique: true) + // Left empty on purpose. These were temporary pixels in iOS. macOS will still use them. } } @@ -161,7 +182,7 @@ extension OnboardingPixelReporter: OnboardingSearchSuggestionsPixelReporting { extension OnboardingPixelReporter: OnboardingSiteSuggestionsPixelReporting { func trackSiteSuggetionOptionTapped() { - fire(event: .onboardingContextualSiteOptionTappedUnique, unique: true) + // Left empty on purpose. These were temporary pixels in iOS. macOS will still use them. } } @@ -199,12 +220,16 @@ extension OnboardingPixelReporter: OnboardingCustomInteractionPixelReporting { // MARK: - OnboardingPixelReporter + Screen Impression -extension OnboardingPixelReporter: OnboardingScreenImpressionReporting { +extension OnboardingPixelReporter: OnboardingDaxDialogsReporting { func trackScreenImpression(event: Pixel.Event) { fire(event: event, unique: true) } + func trackEndOfJourneyDialogCTAAction() { + fire(event: .daxDialogsEndOfJourneyDismissed, unique: false) + } + } struct EnqueuedPixel { diff --git a/DuckDuckGoTests/ContextualDaxDialogsFactoryTests.swift b/DuckDuckGoTests/ContextualDaxDialogsFactoryTests.swift index edafab97ab..cf4b1ba610 100644 --- a/DuckDuckGoTests/ContextualDaxDialogsFactoryTests.swift +++ b/DuckDuckGoTests/ContextualDaxDialogsFactoryTests.swift @@ -321,6 +321,20 @@ final class ContextualDaxDialogsFactoryTests: XCTestCase { XCTAssertTrue(pixelReporterMock.didCallTrackScreenImpressionCalled) XCTAssertEqual(pixelReporterMock.capturedScreenImpression, .onboardingContextualTryVisitSiteUnique) } + + func testWhenEndOfJourneyDialogCTAIsTappedThenExpectedPixelFires() throws { + // GIVEN + let spec = DaxDialogs.BrowsingSpec.final + let result = sut.makeView(for: spec, delegate: delegate, onSizeUpdate: {}) + let view = try XCTUnwrap(find(OnboardingFinalDialog.self, in: result)) + XCTAssertFalse(pixelReporterMock.didCallTrackEndOfJourneyDialogDismiss) + + // WHEN + view.highFiveAction() + + // THEN + XCTAssertTrue(pixelReporterMock.didCallTrackEndOfJourneyDialogDismiss) + } } extension ContextualDaxDialogsFactoryTests { diff --git a/DuckDuckGoTests/ContextualOnboardingNewTabDialogFactoryTests.swift b/DuckDuckGoTests/ContextualOnboardingNewTabDialogFactoryTests.swift index 5e1f62a30a..152b5523e4 100644 --- a/DuckDuckGoTests/ContextualOnboardingNewTabDialogFactoryTests.swift +++ b/DuckDuckGoTests/ContextualOnboardingNewTabDialogFactoryTests.swift @@ -124,7 +124,7 @@ class ContextualOnboardingNewTabDialogFactoryTests: XCTestCase { // MARK: - Pixels - func testWhenOnboardingTrySearchDialogAppearForTheFirstTime_ThenSendFireExpectedPixel() { + func testWhenOnboardingTrySearchDialogAppearForTheFirstTime_ThenFireExpectedPixel() { // GIVEN let spec = DaxDialogs.HomeScreenSpec.initial let pixelEvent = Pixel.Event.onboardingContextualTrySearchUnique @@ -132,7 +132,7 @@ class ContextualOnboardingNewTabDialogFactoryTests: XCTestCase { testDialogDefinedBy(spec: spec, firesEvent: pixelEvent) } - func testWhenOnboardingTryVisitSiteDialogAppearForTheFirstTime_ThenSendFireExpectedPixel() { + func testWhenOnboardingTryVisitSiteDialogAppearForTheFirstTime_ThenFireExpectedPixel() { // GIVEN let spec = DaxDialogs.HomeScreenSpec.subsequent let pixelEvent = Pixel.Event.onboardingContextualTryVisitSiteUnique @@ -140,7 +140,7 @@ class ContextualOnboardingNewTabDialogFactoryTests: XCTestCase { testDialogDefinedBy(spec: spec, firesEvent: pixelEvent) } - func testWhenOnboardingFinalDialogAppearForTheFirstTime_ThenSendFireExpectedPixel() { + func testWhenOnboardingFinalDialogAppearForTheFirstTime_ThenFireExpectedPixel() { // GIVEN let spec = DaxDialogs.HomeScreenSpec.final let pixelEvent = Pixel.Event.daxDialogsEndOfJourneyNewTabUnique @@ -148,6 +148,21 @@ class ContextualOnboardingNewTabDialogFactoryTests: XCTestCase { testDialogDefinedBy(spec: spec, firesEvent: pixelEvent) } + func testWhenOnboardingFinalDialogCTAIsTapped_ThenFireExpectedPixel() throws { + // GIVEN + let view = factory.createDaxDialog(for: DaxDialogs.HomeScreenSpec.final, onDismiss: {}) + let host = UIHostingController(rootView: view) + window.rootViewController = host + let finalDialog = try XCTUnwrap(find(OnboardingFinalDialog.self, in: host)) + XCTAssertFalse(pixelReporterMock.didCallTrackEndOfJourneyDialogDismiss) + + // WHEN + finalDialog.highFiveAction() + + // THEN + XCTAssertTrue(pixelReporterMock.didCallTrackEndOfJourneyDialogDismiss) + } + } private extension ContextualOnboardingNewTabDialogFactoryTests { diff --git a/DuckDuckGoTests/OnboardingIntroViewModelTests.swift b/DuckDuckGoTests/OnboardingIntroViewModelTests.swift index 520ded80cf..2c8ee42d50 100644 --- a/DuckDuckGoTests/OnboardingIntroViewModelTests.swift +++ b/DuckDuckGoTests/OnboardingIntroViewModelTests.swift @@ -37,7 +37,7 @@ final class OnboardingIntroViewModelTests: XCTestCase { func testWhenSubscribeToViewStateThenShouldSendLanding() { // GIVEN - let sut = OnboardingIntroViewModel(pixelReporter: OnboardingIntroPixelReporterMock(), onboardingManager: onboardingManager, urlOpener: MockURLOpener()) + let sut = OnboardingIntroViewModel(pixelReporter: OnboardingPixelReporterMock(), onboardingManager: onboardingManager, urlOpener: MockURLOpener()) // WHEN let result = sut.state @@ -48,7 +48,7 @@ final class OnboardingIntroViewModelTests: XCTestCase { func testWhenOnAppearIsCalledThenViewStateChangesToStartOnboardingDialog() { // GIVEN - let sut = OnboardingIntroViewModel(pixelReporter: OnboardingIntroPixelReporterMock(), onboardingManager: onboardingManager, urlOpener: MockURLOpener()) + let sut = OnboardingIntroViewModel(pixelReporter: OnboardingPixelReporterMock(), onboardingManager: onboardingManager, urlOpener: MockURLOpener()) XCTAssertEqual(sut.state, .landing) // WHEN @@ -60,7 +60,7 @@ final class OnboardingIntroViewModelTests: XCTestCase { func testWhenStartOnboardingActionIsCalledThenViewStateChangesToBrowsersComparisonDialog() { // GIVEN - let sut = OnboardingIntroViewModel(pixelReporter: OnboardingIntroPixelReporterMock(), onboardingManager: onboardingManager) + let sut = OnboardingIntroViewModel(pixelReporter: OnboardingPixelReporterMock(), onboardingManager: onboardingManager) XCTAssertEqual(sut.state, .landing) // WHEN @@ -73,7 +73,7 @@ final class OnboardingIntroViewModelTests: XCTestCase { func testWhenSetDefaultBrowserActionIsCalledThenURLOpenerOpensSettingsURL() { // GIVEN let urlOpenerMock = MockURLOpener() - let sut = OnboardingIntroViewModel(pixelReporter: OnboardingIntroPixelReporterMock(), onboardingManager: onboardingManager, urlOpener: urlOpenerMock) + let sut = OnboardingIntroViewModel(pixelReporter: OnboardingPixelReporterMock(), onboardingManager: onboardingManager, urlOpener: urlOpenerMock) XCTAssertFalse(urlOpenerMock.didCallOpenURL) XCTAssertNil(urlOpenerMock.capturedURL) @@ -88,7 +88,7 @@ final class OnboardingIntroViewModelTests: XCTestCase { func testWhenSetDefaultBrowserActionIsCalledThenOnCompletingOnboardingIntroIsCalled() { // GIVEN var didCallOnCompletingOnboardingIntro = false - let sut = OnboardingIntroViewModel(pixelReporter: OnboardingIntroPixelReporterMock(), onboardingManager: onboardingManager, urlOpener: MockURLOpener()) + let sut = OnboardingIntroViewModel(pixelReporter: OnboardingPixelReporterMock(), onboardingManager: onboardingManager, urlOpener: MockURLOpener()) sut.onCompletingOnboardingIntro = { didCallOnCompletingOnboardingIntro = true } @@ -104,7 +104,7 @@ final class OnboardingIntroViewModelTests: XCTestCase { func testWhenCancelSetDefaultBrowserActionIsCalledThenOnCompletingOnboardingIntroIsCalled() { // GIVEN var didCallOnCompletingOnboardingIntro = false - let sut = OnboardingIntroViewModel(pixelReporter: OnboardingIntroPixelReporterMock(), onboardingManager: onboardingManager, isIpad: false, urlOpener: MockURLOpener()) + let sut = OnboardingIntroViewModel(pixelReporter: OnboardingPixelReporterMock(), onboardingManager: onboardingManager, isIpad: false, urlOpener: MockURLOpener()) sut.onCompletingOnboardingIntro = { didCallOnCompletingOnboardingIntro = true } @@ -124,7 +124,7 @@ final class OnboardingIntroViewModelTests: XCTestCase { func testWhenSubscribeToViewStateAndIsHighlightsIphoneFlowThenShouldSendLanding() { // GIVEN onboardingManager.isOnboardingHighlightsEnabled = true - let sut = OnboardingIntroViewModel(pixelReporter: OnboardingIntroPixelReporterMock(), onboardingManager: onboardingManager, isIpad: false, urlOpener: MockURLOpener()) + let sut = OnboardingIntroViewModel(pixelReporter: OnboardingPixelReporterMock(), onboardingManager: onboardingManager, isIpad: false, urlOpener: MockURLOpener()) // WHEN let result = sut.state @@ -136,7 +136,7 @@ final class OnboardingIntroViewModelTests: XCTestCase { func testWhenOnAppearIsCalledAndAndIsHighlightsIphoneFlowThenViewStateChangesToStartOnboardingDialogAndProgressIsHidden() { // GIVEN onboardingManager.isOnboardingHighlightsEnabled = true - let sut = OnboardingIntroViewModel(pixelReporter: OnboardingIntroPixelReporterMock(), onboardingManager: onboardingManager, isIpad: false, urlOpener: MockURLOpener()) + let sut = OnboardingIntroViewModel(pixelReporter: OnboardingPixelReporterMock(), onboardingManager: onboardingManager, isIpad: false, urlOpener: MockURLOpener()) XCTAssertEqual(sut.state, .landing) // WHEN @@ -149,7 +149,7 @@ final class OnboardingIntroViewModelTests: XCTestCase { func testWhenStartOnboardingActionIsCalledAndIsHighlightsIphoneFlowThenViewStateChangesToBrowsersComparisonDialogAndProgressIs1Of3() { // GIVEN onboardingManager.isOnboardingHighlightsEnabled = true - let sut = OnboardingIntroViewModel(pixelReporter: OnboardingIntroPixelReporterMock(), onboardingManager: onboardingManager, isIpad: false) + let sut = OnboardingIntroViewModel(pixelReporter: OnboardingPixelReporterMock(), onboardingManager: onboardingManager, isIpad: false) XCTAssertEqual(sut.state, .landing) // WHEN @@ -162,7 +162,7 @@ final class OnboardingIntroViewModelTests: XCTestCase { func testWhenSetDefaultBrowserActionIsCalledAndIsHighlightsIphoneFlowThenViewStateChangesToChooseAppIconDialogAndProgressIs2Of3() { // GIVEN onboardingManager.isOnboardingHighlightsEnabled = true - let sut = OnboardingIntroViewModel(pixelReporter: OnboardingIntroPixelReporterMock(), onboardingManager: onboardingManager, isIpad: false, urlOpener: MockURLOpener()) + let sut = OnboardingIntroViewModel(pixelReporter: OnboardingPixelReporterMock(), onboardingManager: onboardingManager, isIpad: false, urlOpener: MockURLOpener()) XCTAssertEqual(sut.state, .landing) // WHEN @@ -175,7 +175,7 @@ final class OnboardingIntroViewModelTests: XCTestCase { func testWhenCancelSetDefaultBrowserActionIsCalledAndIsHighlightsIphoneFlowThenViewStateChangesToChooseAppIconDialogAndProgressIs2Of3() { // GIVEN onboardingManager.isOnboardingHighlightsEnabled = true - let sut = OnboardingIntroViewModel(pixelReporter: OnboardingIntroPixelReporterMock(), onboardingManager: onboardingManager, isIpad: false, urlOpener: MockURLOpener()) + let sut = OnboardingIntroViewModel(pixelReporter: OnboardingPixelReporterMock(), onboardingManager: onboardingManager, isIpad: false, urlOpener: MockURLOpener()) XCTAssertEqual(sut.state, .landing) // WHEN @@ -188,7 +188,7 @@ final class OnboardingIntroViewModelTests: XCTestCase { func testWhenAppIconPickerContinueActionIsCalledAndIsHighlightsIphoneFlowThenViewStateChangesToChooseAddressBarPositionDialogAndProgressIs3Of3() { // GIVEN onboardingManager.isOnboardingHighlightsEnabled = true - let sut = OnboardingIntroViewModel(pixelReporter: OnboardingIntroPixelReporterMock(), onboardingManager: onboardingManager, isIpad: false) + let sut = OnboardingIntroViewModel(pixelReporter: OnboardingPixelReporterMock(), onboardingManager: onboardingManager, isIpad: false) XCTAssertEqual(sut.state, .landing) // WHEN @@ -202,7 +202,7 @@ final class OnboardingIntroViewModelTests: XCTestCase { // GIVEN onboardingManager.isOnboardingHighlightsEnabled = true var didCallOnCompletingOnboardingIntro = false - let sut = OnboardingIntroViewModel(pixelReporter: OnboardingIntroPixelReporterMock(), onboardingManager: onboardingManager, isIpad: false, urlOpener: MockURLOpener()) + let sut = OnboardingIntroViewModel(pixelReporter: OnboardingPixelReporterMock(), onboardingManager: onboardingManager, isIpad: false, urlOpener: MockURLOpener()) sut.onCompletingOnboardingIntro = { didCallOnCompletingOnboardingIntro = true } @@ -220,7 +220,7 @@ final class OnboardingIntroViewModelTests: XCTestCase { func testWhenSubscribeToViewStateAndIsHighlightsIpadFlowThenShouldSendLanding() { // GIVEN onboardingManager.isOnboardingHighlightsEnabled = true - let sut = OnboardingIntroViewModel(pixelReporter: OnboardingIntroPixelReporterMock(), onboardingManager: onboardingManager, isIpad: true, urlOpener: MockURLOpener()) + let sut = OnboardingIntroViewModel(pixelReporter: OnboardingPixelReporterMock(), onboardingManager: onboardingManager, isIpad: true, urlOpener: MockURLOpener()) // WHEN let result = sut.state @@ -232,7 +232,7 @@ final class OnboardingIntroViewModelTests: XCTestCase { func testWhenOnAppearIsCalledAndAndIsHighlightsIpadFlowThenViewStateChangesToStartOnboardingDialogAndProgressIsHidden() { // GIVEN onboardingManager.isOnboardingHighlightsEnabled = true - let sut = OnboardingIntroViewModel(pixelReporter: OnboardingIntroPixelReporterMock(), onboardingManager: onboardingManager, isIpad: true, urlOpener: MockURLOpener()) + let sut = OnboardingIntroViewModel(pixelReporter: OnboardingPixelReporterMock(), onboardingManager: onboardingManager, isIpad: true, urlOpener: MockURLOpener()) XCTAssertEqual(sut.state, .landing) // WHEN @@ -245,7 +245,7 @@ final class OnboardingIntroViewModelTests: XCTestCase { func testWhenStartOnboardingActionIsCalledAndIsHighlightsIpadFlowThenViewStateChangesToBrowsersComparisonDialogAndProgressIs1Of3() { // GIVEN onboardingManager.isOnboardingHighlightsEnabled = true - let sut = OnboardingIntroViewModel(pixelReporter: OnboardingIntroPixelReporterMock(), onboardingManager: onboardingManager, isIpad: true) + let sut = OnboardingIntroViewModel(pixelReporter: OnboardingPixelReporterMock(), onboardingManager: onboardingManager, isIpad: true) XCTAssertEqual(sut.state, .landing) // WHEN @@ -258,7 +258,7 @@ final class OnboardingIntroViewModelTests: XCTestCase { func testWhenSetDefaultBrowserActionIsCalledAndIsHighlightsIpadFlowThenViewStateChangesToChooseAppIconDialogAndProgressIs2Of3() { // GIVEN onboardingManager.isOnboardingHighlightsEnabled = true - let sut = OnboardingIntroViewModel(pixelReporter: OnboardingIntroPixelReporterMock(), onboardingManager: onboardingManager, isIpad: true, urlOpener: MockURLOpener()) + let sut = OnboardingIntroViewModel(pixelReporter: OnboardingPixelReporterMock(), onboardingManager: onboardingManager, isIpad: true, urlOpener: MockURLOpener()) XCTAssertEqual(sut.state, .landing) // WHEN @@ -271,7 +271,7 @@ final class OnboardingIntroViewModelTests: XCTestCase { func testWhenCancelSetDefaultBrowserActionIsCalledAndIsHighlightsIpadFlowThenViewStateChangesToChooseAppIconDialogAndProgressIs2Of3() { // GIVEN onboardingManager.isOnboardingHighlightsEnabled = true - let sut = OnboardingIntroViewModel(pixelReporter: OnboardingIntroPixelReporterMock(), onboardingManager: onboardingManager, isIpad: true, urlOpener: MockURLOpener()) + let sut = OnboardingIntroViewModel(pixelReporter: OnboardingPixelReporterMock(), onboardingManager: onboardingManager, isIpad: true, urlOpener: MockURLOpener()) XCTAssertEqual(sut.state, .landing) // WHEN @@ -285,7 +285,7 @@ final class OnboardingIntroViewModelTests: XCTestCase { // GIVEN onboardingManager.isOnboardingHighlightsEnabled = true var didCallOnCompletingOnboardingIntro = false - let sut = OnboardingIntroViewModel(pixelReporter: OnboardingIntroPixelReporterMock(), onboardingManager: onboardingManager, isIpad: true, urlOpener: MockURLOpener()) + let sut = OnboardingIntroViewModel(pixelReporter: OnboardingPixelReporterMock(), onboardingManager: onboardingManager, isIpad: true, urlOpener: MockURLOpener()) sut.onCompletingOnboardingIntro = { didCallOnCompletingOnboardingIntro = true } @@ -302,7 +302,7 @@ final class OnboardingIntroViewModelTests: XCTestCase { func testWhenOnAppearIsCalledThenPixelReporterTrackOnboardingIntroImpression() { // GIVEN - let pixelReporterMock = OnboardingIntroPixelReporterMock() + let pixelReporterMock = OnboardingPixelReporterMock() let sut = OnboardingIntroViewModel(pixelReporter: pixelReporterMock, onboardingManager: onboardingManager, urlOpener: MockURLOpener()) XCTAssertFalse(pixelReporterMock.didCallTrackOnboardingIntroImpression) @@ -315,7 +315,7 @@ final class OnboardingIntroViewModelTests: XCTestCase { func testWhenStartOnboardingActionIsCalledThenPixelReporterTrackBrowserComparisonImpression() { // GIVEN - let pixelReporterMock = OnboardingIntroPixelReporterMock() + let pixelReporterMock = OnboardingPixelReporterMock() let sut = OnboardingIntroViewModel(pixelReporter: pixelReporterMock, onboardingManager: onboardingManager, urlOpener: MockURLOpener()) XCTAssertFalse(pixelReporterMock.didCallTrackBrowserComparisonImpression) @@ -328,7 +328,7 @@ final class OnboardingIntroViewModelTests: XCTestCase { func testWhenChooseBrowserIsCalledThenPixelReporterTrackChooseBrowserCTAAction() { // GIVEN - let pixelReporterMock = OnboardingIntroPixelReporterMock() + let pixelReporterMock = OnboardingPixelReporterMock() let sut = OnboardingIntroViewModel(pixelReporter: pixelReporterMock, onboardingManager: onboardingManager, urlOpener: MockURLOpener()) XCTAssertFalse(pixelReporterMock.didCallTrackChooseBrowserCTAAction) @@ -339,12 +339,98 @@ final class OnboardingIntroViewModelTests: XCTestCase { XCTAssertTrue(pixelReporterMock.didCallTrackChooseBrowserCTAAction) } + // MARK: - Pixel "Highlights" + + func testWhenStateChangesToChooseAppIconThenPixelReporterTrackAppIconImpression() { + // GIVEN + onboardingManager.isOnboardingHighlightsEnabled = true + let pixelReporterMock = OnboardingPixelReporterMock() + let sut = OnboardingIntroViewModel(pixelReporter: pixelReporterMock, onboardingManager: onboardingManager, urlOpener: MockURLOpener()) + XCTAssertFalse(pixelReporterMock.didCallTrackBrowserComparisonImpression) + + // WHEN + sut.setDefaultBrowserAction() + + // THEN + XCTAssertTrue(pixelReporterMock.didCallTrackChooseAppIconImpression) + } + + func testWhenAppIconPickerContinueActionIsCalledAndIconIsCustomColorThenPixelReporterTrackCustomAppIconColor() { + // GIVEN + onboardingManager.isOnboardingHighlightsEnabled = true + let pixelReporterMock = OnboardingPixelReporterMock() + let sut = OnboardingIntroViewModel(pixelReporter: pixelReporterMock, onboardingManager: onboardingManager, urlOpener: MockURLOpener(), appIconProvider: { .purple }) + XCTAssertFalse(pixelReporterMock.didCallTrackChooseCustomAppIconColor) + + // WHEN + sut.appIconPickerContinueAction() + + // THEN + XCTAssertTrue(pixelReporterMock.didCallTrackChooseCustomAppIconColor) + } + + func testWhenAppIconPickerContinueActionIsCalledAndIconIsDefaultColorThenPixelReporterDoNotTrackCustomAppIconColor() { + // GIVEN + onboardingManager.isOnboardingHighlightsEnabled = true + let pixelReporterMock = OnboardingPixelReporterMock() + let sut = OnboardingIntroViewModel(pixelReporter: pixelReporterMock, onboardingManager: onboardingManager, urlOpener: MockURLOpener(), appIconProvider: { .defaultAppIcon }) + XCTAssertFalse(pixelReporterMock.didCallTrackChooseCustomAppIconColor) + + // WHEN + sut.appIconPickerContinueAction() + + // THEN + XCTAssertFalse(pixelReporterMock.didCallTrackChooseCustomAppIconColor) + } + + func testWhenStateChangesToChooseAddressBarPositionThenPixelReporterTrackAddressBarSelectionImpression() { + // GIVEN + onboardingManager.isOnboardingHighlightsEnabled = true + let pixelReporterMock = OnboardingPixelReporterMock() + let sut = OnboardingIntroViewModel(pixelReporter: pixelReporterMock, onboardingManager: onboardingManager, isIpad: false, urlOpener: MockURLOpener()) + XCTAssertFalse(pixelReporterMock.didCallTrackAddressBarPositionSelectionImpression) + + // WHEN + sut.appIconPickerContinueAction() + + // THEN + XCTAssertTrue(pixelReporterMock.didCallTrackAddressBarPositionSelectionImpression) + } + + func testWhenSelectAddressBarPositionActionIsCalledAndAddressBarPositionIsBottomThenPixelReporterTrackChooseBottomAddressBarPosition() { + // GIVEN + onboardingManager.isOnboardingHighlightsEnabled = true + let pixelReporterMock = OnboardingPixelReporterMock() + let sut = OnboardingIntroViewModel(pixelReporter: pixelReporterMock, onboardingManager: onboardingManager, urlOpener: MockURLOpener(), addressBarPositionProvider: { .bottom }) + XCTAssertFalse(pixelReporterMock.didCallTrackChooseBottomAddressBarPosition) + + // WHEN + sut.selectAddressBarPositionAction() + + // THEN + XCTAssertTrue(pixelReporterMock.didCallTrackChooseBottomAddressBarPosition) + } + + func testWhenSelectAddressBarPositionActionIsCalledAndAddressBarPositionIsTopThenPixelReporterDoNotTrackChooseBottomAddressBarPosition() { + // GIVEN + onboardingManager.isOnboardingHighlightsEnabled = true + let pixelReporterMock = OnboardingPixelReporterMock() + let sut = OnboardingIntroViewModel(pixelReporter: pixelReporterMock, onboardingManager: onboardingManager, urlOpener: MockURLOpener(), addressBarPositionProvider: { .top }) + XCTAssertFalse(pixelReporterMock.didCallTrackChooseBottomAddressBarPosition) + + // WHEN + sut.selectAddressBarPositionAction() + + // THEN + XCTAssertFalse(pixelReporterMock.didCallTrackChooseBottomAddressBarPosition) + } + // MARK: - Copy func testWhenIsNotHighlightsThenIntroTitleIsCorrect() { // GIVEN onboardingManager.isOnboardingHighlightsEnabled = false - let sut = OnboardingIntroViewModel(pixelReporter: OnboardingIntroPixelReporterMock(), onboardingManager: onboardingManager, urlOpener: MockURLOpener()) + let sut = OnboardingIntroViewModel(pixelReporter: OnboardingPixelReporterMock(), onboardingManager: onboardingManager, urlOpener: MockURLOpener()) // WHEN let result = sut.copy.introTitle @@ -356,7 +442,7 @@ final class OnboardingIntroViewModelTests: XCTestCase { func testWhenIsHighlightsThenIntroTitleIsCorrect() { // GIVEN onboardingManager.isOnboardingHighlightsEnabled = true - let sut = OnboardingIntroViewModel(pixelReporter: OnboardingIntroPixelReporterMock(), onboardingManager: onboardingManager, urlOpener: MockURLOpener()) + let sut = OnboardingIntroViewModel(pixelReporter: OnboardingPixelReporterMock(), onboardingManager: onboardingManager, urlOpener: MockURLOpener()) // WHEN let result = sut.copy.introTitle @@ -368,7 +454,7 @@ final class OnboardingIntroViewModelTests: XCTestCase { func testWhenIsNotHighlightsThenBrowserComparisonTitleIsCorrect() { // GIVEN onboardingManager.isOnboardingHighlightsEnabled = false - let sut = OnboardingIntroViewModel(pixelReporter: OnboardingIntroPixelReporterMock(), onboardingManager: onboardingManager, urlOpener: MockURLOpener()) + let sut = OnboardingIntroViewModel(pixelReporter: OnboardingPixelReporterMock(), onboardingManager: onboardingManager, urlOpener: MockURLOpener()) // WHEN let result = sut.copy.browserComparisonTitle @@ -380,7 +466,7 @@ final class OnboardingIntroViewModelTests: XCTestCase { func testWhenIsHighlightsThenBrowserComparisonTitleIsCorrect() { // GIVEN onboardingManager.isOnboardingHighlightsEnabled = true - let sut = OnboardingIntroViewModel(pixelReporter: OnboardingIntroPixelReporterMock(), onboardingManager: onboardingManager, urlOpener: MockURLOpener()) + let sut = OnboardingIntroViewModel(pixelReporter: OnboardingPixelReporterMock(), onboardingManager: onboardingManager, urlOpener: MockURLOpener()) // WHEN let result = sut.copy.browserComparisonTitle @@ -390,21 +476,3 @@ final class OnboardingIntroViewModelTests: XCTestCase { } } - -private final class OnboardingIntroPixelReporterMock: OnboardingIntroPixelReporting { - private(set) var didCallTrackOnboardingIntroImpression = false - private(set) var didCallTrackBrowserComparisonImpression = false - private(set) var didCallTrackChooseBrowserCTAAction = false - - func trackOnboardingIntroImpression() { - didCallTrackOnboardingIntroImpression = true - } - - func trackBrowserComparisonImpression() { - didCallTrackBrowserComparisonImpression = true - } - - func trackChooseBrowserCTAAction() { - didCallTrackChooseBrowserCTAAction = true - } -} diff --git a/DuckDuckGoTests/OnboardingPixelReporterMock.swift b/DuckDuckGoTests/OnboardingPixelReporterMock.swift index 855d445fcb..4a4b20a4a5 100644 --- a/DuckDuckGoTests/OnboardingPixelReporterMock.swift +++ b/DuckDuckGoTests/OnboardingPixelReporterMock.swift @@ -22,11 +22,15 @@ import Core import Onboarding @testable import DuckDuckGo -final class OnboardingPixelReporterMock: OnboardingIntroPixelReporting, OnboardingSiteSuggestionsPixelReporting, OnboardingSearchSuggestionsPixelReporting, OnboardingCustomInteractionPixelReporting, OnboardingScreenImpressionReporting { +final class OnboardingPixelReporterMock: OnboardingIntroPixelReporting, OnboardingSiteSuggestionsPixelReporting, OnboardingSearchSuggestionsPixelReporting, OnboardingCustomInteractionPixelReporting, OnboardingDaxDialogsReporting { private(set) var didCallTrackOnboardingIntroImpression = false private(set) var didCallTrackBrowserComparisonImpression = false - private(set) var didCallChooseBrowserCTAAction = false + private(set) var didCallTrackChooseBrowserCTAAction = false + private(set) var didCallTrackChooseAppIconImpression = false + private(set) var didCallTrackChooseCustomAppIconColor = false + private(set) var didCallTrackAddressBarPositionSelectionImpression = false + private(set) var didCallTrackChooseBottomAddressBarPosition = false private(set) var didCallTrackSearchOptionTapped = false private(set) var didCallTrackSiteOptionTapped = false private(set) var didCallTrackCustomSearch = false @@ -40,6 +44,7 @@ final class OnboardingPixelReporterMock: OnboardingIntroPixelReporting, Onboardi private(set) var didCallTrackScreenImpressionCalled = false private(set) var capturedScreenImpression: Pixel.Event? private(set) var didCallTrackPrivacyDashboardOpenedForFirstTime = false + private(set) var didCallTrackEndOfJourneyDialogDismiss = false func trackOnboardingIntroImpression() { didCallTrackOnboardingIntroImpression = true @@ -50,7 +55,27 @@ final class OnboardingPixelReporterMock: OnboardingIntroPixelReporting, Onboardi } func trackChooseBrowserCTAAction() { - didCallChooseBrowserCTAAction = true + didCallTrackChooseBrowserCTAAction = true + } + + func trackChooseAppIconImpression() { + didCallTrackChooseAppIconImpression = true + } + + func trackChooseCustomAppIconColor() { + didCallTrackChooseCustomAppIconColor = true + } + + func trackAddressBarPositionSelectionImpression() { + didCallTrackAddressBarPositionSelectionImpression = true + } + + func trackChooseBottomAddressBarPosition() { + didCallTrackChooseBottomAddressBarPosition = true + } + + func trackEndOfJourneyDialogCTAAction() { + didCallTrackEndOfJourneyDialogDismiss = true } func trackSiteSuggetionOptionTapped() { diff --git a/DuckDuckGoTests/OnboardingPixelReporterTests.swift b/DuckDuckGoTests/OnboardingPixelReporterTests.swift index 09994eb9ce..f79808e3c9 100644 --- a/DuckDuckGoTests/OnboardingPixelReporterTests.swift +++ b/DuckDuckGoTests/OnboardingPixelReporterTests.swift @@ -107,46 +107,6 @@ final class OnboardingPixelReporterTests: XCTestCase { XCTAssertEqual(OnboardingPixelFireMock.capturedIncludeParameters, [.appVersion, .atb]) } - // MARK: - List - - func testWhenTrackSearchSuggestionOptionTappedThenSearchOptionTappedFires() { - // GIVEN - let expectedPixel = Pixel.Event.onboardingContextualSearchOptionTappedUnique - XCTAssertFalse(OnboardingUniquePixelFireMock.didCallFire) - XCTAssertNil(OnboardingUniquePixelFireMock.capturedPixelEvent) - XCTAssertEqual(OnboardingUniquePixelFireMock.capturedParams, [:]) - XCTAssertEqual(OnboardingUniquePixelFireMock.capturedIncludeParameters, []) - - // WHEN - sut.trackSearchSuggetionOptionTapped() - - // THEN - XCTAssertTrue(OnboardingUniquePixelFireMock.didCallFire) - XCTAssertEqual(OnboardingUniquePixelFireMock.capturedPixelEvent, expectedPixel) - XCTAssertEqual(expectedPixel.name, "m_onboarding_search_option_tapped_unique") - XCTAssertEqual(OnboardingUniquePixelFireMock.capturedParams, [:]) - XCTAssertEqual(OnboardingUniquePixelFireMock.capturedIncludeParameters, [.appVersion, .atb]) - } - - func testWhenTrackSiteSuggestionThenSiteOptionsTappedFires() { - // GIVEN - let expectedPixel = Pixel.Event.onboardingContextualSiteOptionTappedUnique - XCTAssertFalse(OnboardingUniquePixelFireMock.didCallFire) - XCTAssertNil(OnboardingUniquePixelFireMock.capturedPixelEvent) - XCTAssertEqual(OnboardingUniquePixelFireMock.capturedParams, [:]) - XCTAssertEqual(OnboardingUniquePixelFireMock.capturedIncludeParameters, []) - - // WHEN - sut.trackSiteSuggetionOptionTapped() - - // THEN - XCTAssertTrue(OnboardingUniquePixelFireMock.didCallFire) - XCTAssertEqual(OnboardingUniquePixelFireMock.capturedPixelEvent, expectedPixel) - XCTAssertEqual(expectedPixel.name, "m_onboarding_visit_site_option_tapped_unique") - XCTAssertEqual(OnboardingUniquePixelFireMock.capturedParams, [:]) - XCTAssertEqual(OnboardingUniquePixelFireMock.capturedIncludeParameters, [.appVersion, .atb]) - } - // MARK: - Custom Interactions func testWhenTrackCustomSearchIsCalledThenSearchCustomFires() { @@ -269,7 +229,7 @@ final class OnboardingPixelReporterTests: XCTestCase { XCTAssertEqual(OnboardingUniquePixelFireMock.capturedParams["daysSinceInstall"], "3") } - // MARK: - Screen Impressions + // MARK: - Dax Dialogs func testWhenTrackScreenImpressionIsCalledThenPixelFires() { // GIVEN @@ -288,6 +248,23 @@ final class OnboardingPixelReporterTests: XCTestCase { XCTAssertEqual(OnboardingUniquePixelFireMock.capturedIncludeParameters, [.appVersion, .atb]) } + func testWhentrackEndOfJourneyDialogCTAActionIsCalledThenDaxDialogsEndOfJourneyDismissedPixelFires() { + // GIVEN + let expectedPixel = Pixel.Event.daxDialogsEndOfJourneyDismissed + XCTAssertFalse(OnboardingPixelFireMock.didCallFire) + XCTAssertNil(OnboardingPixelFireMock.capturedPixelEvent) + XCTAssertEqual(OnboardingPixelFireMock.capturedIncludeParameters, []) + + // WHEN + sut.trackEndOfJourneyDialogCTAAction() + + // THEN + XCTAssertTrue(OnboardingPixelFireMock.didCallFire) + XCTAssertEqual(OnboardingPixelFireMock.capturedPixelEvent, expectedPixel) + XCTAssertEqual(expectedPixel.name, expectedPixel.name) + XCTAssertEqual(OnboardingPixelFireMock.capturedIncludeParameters, [.appVersion, .atb]) + } + // Enqueuing / Dequeuing Pixels func testWhenPixelIsFiredAndAndATBIsNotAvailableAndPixelNeedsATBThenEnqueuePixel() throws { @@ -353,4 +330,75 @@ final class OnboardingPixelReporterTests: XCTestCase { XCTAssertEqual(OnboardingUniquePixelFireMock.capturedPixelEventHistory[0], .onboardingIntroShownUnique) XCTAssertEqual(OnboardingUniquePixelFireMock.capturedPixelEventHistory[1], .onboardingIntroComparisonChartShownUnique) } + + // MARK: - Onboarding Intro Highglights Experiment + + func testWhenTrackChooseAppIconImpressionIsCalledThenOnboardingIntroChooseIconImpressionUniquePixelFires() { + // GIVEN + let expectedPixel = Pixel.Event.onboardingIntroChooseAppIconImpressionUnique + XCTAssertFalse(OnboardingUniquePixelFireMock.didCallFire) + XCTAssertNil(OnboardingUniquePixelFireMock.capturedPixelEvent) + XCTAssertEqual(OnboardingUniquePixelFireMock.capturedIncludeParameters, []) + + // WHEN + sut.trackChooseAppIconImpression() + + // THEN + XCTAssertTrue(OnboardingUniquePixelFireMock.didCallFire) + XCTAssertEqual(OnboardingUniquePixelFireMock.capturedPixelEvent, expectedPixel) + XCTAssertEqual(expectedPixel.name, expectedPixel.name) + XCTAssertEqual(OnboardingUniquePixelFireMock.capturedIncludeParameters, [.appVersion]) + } + + func testWhenTrackChooseNonDefaultAppIconIsCalledThenOnboardingIntroChooseCustomIconColorPixelFires() { + // GIVEN + let expectedPixel = Pixel.Event.onboardingIntroChooseCustomAppIconColorCTAPressed + XCTAssertFalse(OnboardingPixelFireMock.didCallFire) + XCTAssertNil(OnboardingPixelFireMock.capturedPixelEvent) + XCTAssertEqual(OnboardingPixelFireMock.capturedIncludeParameters, []) + + // WHEN + sut.trackChooseCustomAppIconColor() + + // THEN + XCTAssertTrue(OnboardingPixelFireMock.didCallFire) + XCTAssertEqual(OnboardingPixelFireMock.capturedPixelEvent, expectedPixel) + XCTAssertEqual(expectedPixel.name, expectedPixel.name) + XCTAssertEqual(OnboardingPixelFireMock.capturedIncludeParameters, [.appVersion]) + } + + func testWhenTrackAddressBarPositionSelectionImpressionIsCalledThenOnboardingIntroChooseAddressBarImpressionUniquePixelFires() { + // GIVEN + let expectedPixel = Pixel.Event.onboardingIntroChooseAddressBarImpressionUnique + XCTAssertFalse(OnboardingUniquePixelFireMock.didCallFire) + XCTAssertNil(OnboardingUniquePixelFireMock.capturedPixelEvent) + XCTAssertEqual(OnboardingUniquePixelFireMock.capturedIncludeParameters, []) + + // WHEN + sut.trackAddressBarPositionSelectionImpression() + + // THEN + XCTAssertTrue(OnboardingUniquePixelFireMock.didCallFire) + XCTAssertEqual(OnboardingUniquePixelFireMock.capturedPixelEvent, expectedPixel) + XCTAssertEqual(expectedPixel.name, expectedPixel.name) + XCTAssertEqual(OnboardingUniquePixelFireMock.capturedIncludeParameters, [.appVersion]) + } + + func testWhenTrackChooseBottomAddressBarPositionIsCalledThenOnboardingIntroBottomAddressBarSelectedFires() { + // GIVEN + let expectedPixel = Pixel.Event.onboardingIntroBottomAddressBarSelected + XCTAssertFalse(OnboardingPixelFireMock.didCallFire) + XCTAssertNil(OnboardingPixelFireMock.capturedPixelEvent) + XCTAssertEqual(OnboardingPixelFireMock.capturedIncludeParameters, []) + + // WHEN + sut.trackChooseBottomAddressBarPosition() + + // THEN + XCTAssertTrue(OnboardingPixelFireMock.didCallFire) + XCTAssertEqual(OnboardingPixelFireMock.capturedPixelEvent, expectedPixel) + XCTAssertEqual(expectedPixel.name, expectedPixel.name) + XCTAssertEqual(OnboardingPixelFireMock.capturedIncludeParameters, [.appVersion]) + } + }