From cb1122b4d074143da2599db138354a940731e395 Mon Sep 17 00:00:00 2001 From: Christopher Brind Date: Mon, 28 Oct 2024 10:58:46 +0000 Subject: [PATCH] fire pixels when showing the error screen (#3462) Task/Issue URL: https://app.asana.com/0/392891325557410/1208511720659950/f Tech Design URL: CC: **Description**: Fires a pixel when the error screen is shown. **Steps to test this PR**: 1. Open a tab, and use activity monitor to kill that process. The "webpage has crashed" error screen should appear and the pixel should be fired. 2. Open a nonsense url like https://nonsense.url - The 'unable to load' page should appear and the pixel should be displayed 3. Switch between other tabs and the error pages and pixels should be fired when the user switches tabs. **Definition of Done**: * [ ] Does this PR satisfy our [Definition of Done](https://app.asana.com/0/1202500774821704/1207634633537039/f)? --- ###### Internal references: [Pull Request Review Checklist](https://app.asana.com/0/1202500774821704/1203764234894239/f) [Software Engineering Expectations](https://app.asana.com/0/59792373528535/199064865822552) [Technical Design Template](https://app.asana.com/0/59792373528535/184709971311943) [Pull Request Documentation](https://app.asana.com/0/1202500774821704/1204012835277482/f) --- DuckDuckGo/Statistics/GeneralPixel.swift | 10 +++++++ DuckDuckGo/Tab/Model/Tab.swift | 2 ++ .../ViewModel/TabCollectionViewModel.swift | 27 +++++++++++++++++++ 3 files changed, 39 insertions(+) diff --git a/DuckDuckGo/Statistics/GeneralPixel.swift b/DuckDuckGo/Statistics/GeneralPixel.swift index 0728b09ff9..416c3dfec3 100644 --- a/DuckDuckGo/Statistics/GeneralPixel.swift +++ b/DuckDuckGo/Statistics/GeneralPixel.swift @@ -328,6 +328,7 @@ enum GeneralPixel: PixelKitEventV2 { case adAttributionLogicWrongVendorOnFailedCompilation case webKitDidTerminate + case userViewedWebKitTerminationErrorPage case removedInvalidBookmarkManagedObjects @@ -424,6 +425,10 @@ enum GeneralPixel: PixelKitEventV2 { case compilationFailed + // MARK: error page shown + case errorPageShownOther + case errorPageShownWebkitTermination + var name: String { switch self { @@ -916,6 +921,8 @@ enum GeneralPixel: PixelKitEventV2 { case .webKitDidTerminate: return "webkit_did_terminate" + case .userViewedWebKitTerminationErrorPage: + return "webkit-termination-error-page-viewed" case .removedInvalidBookmarkManagedObjects: return "removed_invalid_bookmark_managed_objects" @@ -1037,6 +1044,9 @@ enum GeneralPixel: PixelKitEventV2 { case .bookmarksSortByName: return "m_mac_sort_bookmarks_by_name" case .bookmarksSearchExecuted: return "m_mac_search_bookmarks_executed" case .bookmarksSearchResultClicked: return "m_mac_search_result_clicked" + + case .errorPageShownOther: return "m_mac_errorpageshown_other" + case .errorPageShownWebkitTermination: return "m_mac_errorpageshown_webkittermination" } } diff --git a/DuckDuckGo/Tab/Model/Tab.swift b/DuckDuckGo/Tab/Model/Tab.swift index f69e9cfe00..4f3867b84e 100644 --- a/DuckDuckGo/Tab/Model/Tab.swift +++ b/DuckDuckGo/Tab/Model/Tab.swift @@ -1259,6 +1259,8 @@ extension Tab/*: NavigationResponder*/ { // to be moved to Tab+Navigation.swift @MainActor func webContentProcessDidTerminate(with reason: WKProcessTerminationReason?) { + guard (error?.code.rawValue ?? WKError.Code.unknown.rawValue) != WKError.Code.webContentProcessTerminated.rawValue else { return } + let error = WKError(.webContentProcessTerminated, userInfo: [ WKProcessTerminationReason.userInfoKey: reason?.rawValue ?? -1, NSLocalizedDescriptionKey: UserText.webProcessCrashPageMessage diff --git a/DuckDuckGo/TabBar/ViewModel/TabCollectionViewModel.swift b/DuckDuckGo/TabBar/ViewModel/TabCollectionViewModel.swift index 59090bb527..20a250e726 100644 --- a/DuckDuckGo/TabBar/ViewModel/TabCollectionViewModel.swift +++ b/DuckDuckGo/TabBar/ViewModel/TabCollectionViewModel.swift @@ -130,6 +130,7 @@ final class TabCollectionViewModel: NSObject { subscribeToTabs() subscribeToPinnedTabsManager() + subscribeToSelectedTab() if tabCollection.tabs.isEmpty { appendNewTab(with: homePage) @@ -153,6 +154,32 @@ final class TabCollectionViewModel: NSObject { burnerMode: burnerMode) } + var selectedTabCancellable: AnyCancellable? + private func subscribeToSelectedTab() { + selectedTabCancellable = $selectedTabViewModel + .compactMap { $0 } + .sink { [weak self] model in + self?.subscribeToTabError(model) + } + } + + var selectedTabErrorCancellable: AnyCancellable? + private func subscribeToTabError(_ model: TabViewModel) { + selectedTabErrorCancellable = model.tab.$error + .compactMap { $0 } + .sink { [weak self] error in + self?.fireErrorPageShownPixel(error) + } + } + + private func fireErrorPageShownPixel(_ error: WKError) { + if error.code == WKError.Code.webContentProcessTerminated { + PixelKit.fire(GeneralPixel.errorPageShownWebkitTermination) + } else { + PixelKit.fire(GeneralPixel.errorPageShownOther) + } + } + func setUpLazyLoadingIfNeeded() { guard !isTabLazyLoadingRequested else { Logger.tabLazyLoading.debug("Lazy loading already requested in this session, skipping.")