diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj index 1cb1a302b6..7f986cc5b6 100644 --- a/DuckDuckGo.xcodeproj/project.pbxproj +++ b/DuckDuckGo.xcodeproj/project.pbxproj @@ -743,6 +743,8 @@ 9F254AD92CF605310063B308 /* MockSSLErrorPageNavigationHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F254AD72CF605310063B308 /* MockSSLErrorPageNavigationHandler.swift */; }; 9F254ADB2CF6120E0063B308 /* MockSpecialErrorPageNavigationDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F254ADA2CF6120E0063B308 /* MockSpecialErrorPageNavigationDelegate.swift */; }; 9F254ADC2CF6120E0063B308 /* MockSpecialErrorPageNavigationDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F254ADA2CF6120E0063B308 /* MockSpecialErrorPageNavigationDelegate.swift */; }; + 9F254ADE2CF636CF0063B308 /* DummyWKNavigation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F254ADD2CF636CF0063B308 /* DummyWKNavigation.swift */; }; + 9F254ADF2CF636CF0063B308 /* DummyWKNavigation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F254ADD2CF636CF0063B308 /* DummyWKNavigation.swift */; }; 9F46BEF82CD8D7490092E0EF /* OnboardingView+AddToDockContent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F46BEF72CD8D7490092E0EF /* OnboardingView+AddToDockContent.swift */; }; 9F4CC5152C47AD08006A96EB /* ContextualOnboardingPresenterMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F4CC5142C47AD08006A96EB /* ContextualOnboardingPresenterMock.swift */; }; 9F4CC5172C48B8D4006A96EB /* TabViewControllerDaxDialogTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F4CC5162C48B8D4006A96EB /* TabViewControllerDaxDialogTests.swift */; }; @@ -2572,6 +2574,7 @@ 9F254AD42CF5E5B10063B308 /* DummyMaliciousSiteProtectionNavigationHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DummyMaliciousSiteProtectionNavigationHandler.swift; sourceTree = ""; }; 9F254AD72CF605310063B308 /* MockSSLErrorPageNavigationHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockSSLErrorPageNavigationHandler.swift; sourceTree = ""; }; 9F254ADA2CF6120E0063B308 /* MockSpecialErrorPageNavigationDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockSpecialErrorPageNavigationDelegate.swift; sourceTree = ""; }; + 9F254ADD2CF636CF0063B308 /* DummyWKNavigation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DummyWKNavigation.swift; sourceTree = ""; }; 9F46BEF72CD8D7490092E0EF /* OnboardingView+AddToDockContent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "OnboardingView+AddToDockContent.swift"; sourceTree = ""; }; 9F4CC5142C47AD08006A96EB /* ContextualOnboardingPresenterMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContextualOnboardingPresenterMock.swift; sourceTree = ""; }; 9F4CC5162C48B8D4006A96EB /* TabViewControllerDaxDialogTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabViewControllerDaxDialogTests.swift; sourceTree = ""; }; @@ -4910,6 +4913,7 @@ 9F254AD42CF5E5B10063B308 /* DummyMaliciousSiteProtectionNavigationHandler.swift */, 9F254AD72CF605310063B308 /* MockSSLErrorPageNavigationHandler.swift */, 9F254ADA2CF6120E0063B308 /* MockSpecialErrorPageNavigationDelegate.swift */, + 9F254ADD2CF636CF0063B308 /* DummyWKNavigation.swift */, ); path = TestDoubles; sourceTree = ""; @@ -8191,6 +8195,7 @@ 85D2187224BF24F2004373D2 /* NotFoundCachingDownloaderTests.swift in Sources */, C1935A242C89CC6D001AD72D /* AutofillHeaderViewFactoryTests.swift in Sources */, C111B26927F579EF006558B1 /* BookmarkOrFolderTests.swift in Sources */, + 9F254ADF2CF636CF0063B308 /* DummyWKNavigation.swift in Sources */, 6F7BACD42CEE084B00F561D8 /* OmniBarEqualityCheckTests.swift in Sources */, 6F7FB8E72C66197E00867DA7 /* NewTabPageSectionsSettingsModelTests.swift in Sources */, 851CD674244D7E6000331B98 /* UserDefaultsExtension.swift in Sources */, @@ -8371,6 +8376,7 @@ 9F254AD62CF5E5B10063B308 /* DummyMaliciousSiteProtectionNavigationHandler.swift in Sources */, 85F21DB0210F5E32002631A6 /* AtbIntegrationTests.swift in Sources */, 9F254AD22CF5D3A80063B308 /* MockSpecialErrorWebView.swift in Sources */, + 9F254ADE2CF636CF0063B308 /* DummyWKNavigation.swift in Sources */, 8551912724746EDC0010FDD0 /* SnapshotHelper.swift in Sources */, 9F254ADB2CF6120E0063B308 /* MockSpecialErrorPageNavigationDelegate.swift in Sources */, 9F254ACC2CF5CDC60063B308 /* SpecialErrorPageNavigationHandlerTests.swift in Sources */, diff --git a/DuckDuckGo/SpecialErrorPage/SpecialErrorPageNavigationHandler.swift b/DuckDuckGo/SpecialErrorPage/SpecialErrorPageNavigationHandler.swift index 12390bd6b9..c842be7f40 100644 --- a/DuckDuckGo/SpecialErrorPage/SpecialErrorPageNavigationHandler.swift +++ b/DuckDuckGo/SpecialErrorPage/SpecialErrorPageNavigationHandler.swift @@ -81,7 +81,7 @@ extension SpecialErrorPageNavigationHandler: WebViewNavigationHandling { sslErrorPageNavigationHandler.handleServerTrustChallenge(challenge, completionHandler: completionHandler) } - func handleWebView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: NSError) { + func handleWebView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WebViewNavigation, withError error: NSError) { guard let (url, sslErrorType, specialErrorData) = sslErrorPageNavigationHandler.makeNewRequestURLAndSpecialErrorDataIfEnabled(error: error) else { return } failedURL = url sslErrorPageNavigationHandler.errorPageVisited(errorType: sslErrorType) @@ -90,7 +90,7 @@ extension SpecialErrorPageNavigationHandler: WebViewNavigationHandling { loadSpecialErrorPage(url: url) } - func handleWebView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { + func handleWebView(_ webView: WKWebView, didFinish navigation: WebViewNavigation) { userScript?.isEnabled = webView.url == failedURL if webView.url != failedURL { isSpecialErrorPageVisible = false diff --git a/DuckDuckGoTests/SpecialErrorPage/SSLErrorPageNavigationHandlerTests.swift b/DuckDuckGoTests/SpecialErrorPage/SSLErrorPageNavigationHandlerTests.swift index 6119e7e779..6b352cc47f 100644 --- a/DuckDuckGoTests/SpecialErrorPage/SSLErrorPageNavigationHandlerTests.swift +++ b/DuckDuckGoTests/SpecialErrorPage/SSLErrorPageNavigationHandlerTests.swift @@ -33,12 +33,10 @@ final class SSLSpecialErrorPageTests: XCTestCase { let featureFlagger = MockFeatureFlagger() featureFlagger.enabledFeatureFlags = [.sslCertificatesBypass] sut = SSLErrorPageNavigationHandler(urlCredentialCreator: MockCredentialCreator(), featureFlagger: featureFlagger) - WKNavigation.swizzleDealloc() } override func tearDown() async throws { try await super.tearDown() - await WKNavigation.restoreDealloc() sut = nil } diff --git a/DuckDuckGoTests/SpecialErrorPage/SpecialErrorPageNavigationHandlerIntegrationTests.swift b/DuckDuckGoTests/SpecialErrorPage/SpecialErrorPageNavigationHandlerIntegrationTests.swift index c969c3fcf6..9ef1c1bff9 100644 --- a/DuckDuckGoTests/SpecialErrorPage/SpecialErrorPageNavigationHandlerIntegrationTests.swift +++ b/DuckDuckGoTests/SpecialErrorPage/SpecialErrorPageNavigationHandlerIntegrationTests.swift @@ -38,14 +38,12 @@ final class SpecialErrorPageNavigationHandlerIntegrationTests { sslErrorPageNavigationHandler: sslErrorPageNavigationHandler, maliciousSiteProtectionNavigationHandler: DummyMaliciousSiteProtectionNavigationHandler() ) - WKNavigation.swizzleDealloc() } deinit { sslErrorPageNavigationHandler = nil sut = nil webView = nil - WKNavigation.restoreDealloc() } @MainActor @@ -68,7 +66,7 @@ final class SpecialErrorPageNavigationHandlerIntegrationTests { } // WHEN - sut.handleWebView(webView, didFailProvisionalNavigation: WKNavigation(), withError: error) + sut.handleWebView(webView, didFailProvisionalNavigation: DummyWKNavigation(), withError: error) // THEN let html = try #require(expectedHTML) @@ -102,7 +100,7 @@ final class SpecialErrorPageNavigationHandlerIntegrationTests { } // WHEN - sut.handleWebView(webView, didFailProvisionalNavigation: WKNavigation(), withError: error) + sut.handleWebView(webView, didFailProvisionalNavigation: DummyWKNavigation(), withError: error) // THEN let html = try #require(expectedHTML) @@ -136,7 +134,7 @@ final class SpecialErrorPageNavigationHandlerIntegrationTests { } // WHEN - sut.handleWebView(webView, didFailProvisionalNavigation: WKNavigation(), withError: error) + sut.handleWebView(webView, didFailProvisionalNavigation: DummyWKNavigation(), withError: error) // THEN let html = try #require(expectedHTML) @@ -170,7 +168,7 @@ final class SpecialErrorPageNavigationHandlerIntegrationTests { } // WHEN - sut.handleWebView(webView, didFailProvisionalNavigation: WKNavigation(), withError: error) + sut.handleWebView(webView, didFailProvisionalNavigation: DummyWKNavigation(), withError: error) // THEN let html = try #require(expectedHTML) @@ -195,7 +193,7 @@ final class SpecialErrorPageNavigationHandlerIntegrationTests { #expect(script.isEnabled == false) // WHEN - sut.handleWebView(webView, didFinish: WKNavigation()) + sut.handleWebView(webView, didFinish: DummyWKNavigation()) // THEN #expect(script.isEnabled == false) @@ -215,11 +213,11 @@ final class SpecialErrorPageNavigationHandlerIntegrationTests { sut.setUserScript(script) sut.attachWebView(webView) // Fail the request with a different URL. - sut.handleWebView(webView, didFailProvisionalNavigation: WKNavigation(), withError: error) + sut.handleWebView(webView, didFailProvisionalNavigation: DummyWKNavigation(), withError: error) #expect(script.isEnabled == false) // WHEN - sut.handleWebView(webView, didFinish: WKNavigation()) + sut.handleWebView(webView, didFinish: DummyWKNavigation()) // THEN #expect(script.isEnabled == false) @@ -234,7 +232,7 @@ final class SpecialErrorPageNavigationHandlerIntegrationTests { let script = SpecialErrorPageUserScript(localeStrings: "", languageCode: "") sut.setUserScript(script) sut.attachWebView(webView) - let navigation = WKNavigation() + let navigation = DummyWKNavigation() let error = NSError( domain: "test", code: NSURLErrorServerCertificateUntrusted, diff --git a/DuckDuckGoTests/SpecialErrorPage/SpecialErrorPageNavigationHandlerTests.swift b/DuckDuckGoTests/SpecialErrorPage/SpecialErrorPageNavigationHandlerTests.swift index 8d73ed43dc..e860c46726 100644 --- a/DuckDuckGoTests/SpecialErrorPage/SpecialErrorPageNavigationHandlerTests.swift +++ b/DuckDuckGoTests/SpecialErrorPage/SpecialErrorPageNavigationHandlerTests.swift @@ -38,14 +38,12 @@ final class SpecialErrorPageNavigationHandlerTests { sslErrorPageNavigationHandler: sslErrorPageNavigationHandler, maliciousSiteProtectionNavigationHandler: DummyMaliciousSiteProtectionNavigationHandler() ) - WKNavigation.swizzleDealloc() } deinit { sslErrorPageNavigationHandler = nil sut = nil webView = nil - WKNavigation.restoreDealloc() } @Test("Receive Challenge forward event to SSL Error Page Navigation Handler") @@ -65,7 +63,7 @@ final class SpecialErrorPageNavigationHandlerTests { @Test("Leave Site forward event to SSL Error Page Navigation Handler") func whenLeaveSite_AndSSLError_ThenCallLeaveSiteOnSSLErrorPageNavigationHandler() { // GIVEN - sut.handleWebView(webView, didFailProvisionalNavigation: WKNavigation(), withError: .genericSSL) + sut.handleWebView(webView, didFailProvisionalNavigation: DummyWKNavigation(), withError: .genericSSL) #expect(!sslErrorPageNavigationHandler.didCallLeaveSite) // WHEN @@ -115,7 +113,7 @@ final class SpecialErrorPageNavigationHandlerTests { @Test("Visit Site forward event to SSL Error Page Navigation Handler") func whenVisitSite_AndSSLError_ThenCallVisitSiteOnSSLErrorPageNavigationHandler() { // GIVEN - sut.handleWebView(webView, didFailProvisionalNavigation: WKNavigation(), withError: .genericSSL) + sut.handleWebView(webView, didFailProvisionalNavigation: DummyWKNavigation(), withError: .genericSSL) #expect(!sslErrorPageNavigationHandler.didCallVisitSite) // WHEN @@ -135,7 +133,7 @@ final class SpecialErrorPageNavigationHandlerTests { func whenVisitSite_ThenSetIsSpecialErrorPageVisibleToFalseAndReloadPage() { // GIVEN sut.attachWebView(webView) - sut.handleWebView(webView, didFailProvisionalNavigation: WKNavigation(), withError: .genericSSL) + sut.handleWebView(webView, didFailProvisionalNavigation: DummyWKNavigation(), withError: .genericSSL) #expect(sut.isSpecialErrorPageVisible) #expect(!webView.didCallReload) @@ -150,7 +148,7 @@ final class SpecialErrorPageNavigationHandlerTests { @Test("Advanced Info Presented forward event to SSL Error Page Navigation Handler") func whenAdvancedInfoPresented_AndSSLError_ThenCallAdvancedInfoPresentedOnSSLErrorPageNavigationHandler() { // GIVEN - sut.handleWebView(webView, didFailProvisionalNavigation: WKNavigation(), withError: .genericSSL) + sut.handleWebView(webView, didFailProvisionalNavigation: DummyWKNavigation(), withError: .genericSSL) #expect(!sslErrorPageNavigationHandler.didCalladvancedInfoPresented) // WHEN diff --git a/DuckDuckGoTests/SpecialErrorPage/TestDoubles/DummyWKNavigation.swift b/DuckDuckGoTests/SpecialErrorPage/TestDoubles/DummyWKNavigation.swift new file mode 100644 index 0000000000..c6ac52e0df --- /dev/null +++ b/DuckDuckGoTests/SpecialErrorPage/TestDoubles/DummyWKNavigation.swift @@ -0,0 +1,28 @@ +// +// MockWKNavigation.swift +// DuckDuckGo +// +// Copyright © 2024 DuckDuckGo. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import Foundation +@testable import DuckDuckGo + +// Used in tests. WKNavigation() crashes on deinit when initialising it manually. +// As workaround we used to Swizzle the implementation of deinit in tests. +// The problem with that approach is that when running different test suites it is possible that unrelated tests re-set the original implementation of deinit while other tests are running. +// This cause the app to crash as the original implementation is executed. +// Defining a protocol for WKNavigation and using mocks in tests fix the problem. +final class DummyWKNavigation: WebViewNavigation {}