From 198c466a862389578f73a9e32c37469a739002c6 Mon Sep 17 00:00:00 2001 From: Mauro Pereira Date: Fri, 7 Aug 2026 20:45:07 +0100 Subject: [PATCH] fix(domains): prevent duplicate navigation --- .../DomainDetailsWebViewControllerTests.swift | 52 ++++++++++++++++++- .../DomainDetailsWebViewController.swift | 34 ++---------- 2 files changed, 54 insertions(+), 32 deletions(-) diff --git a/Tests/KeystoneTests/Tests/Features/Domains/DomainDetailsWebViewControllerTests.swift b/Tests/KeystoneTests/Tests/Features/Domains/DomainDetailsWebViewControllerTests.swift index cdbd6fc1bd24..c946663a6d27 100644 --- a/Tests/KeystoneTests/Tests/Features/Domains/DomainDetailsWebViewControllerTests.swift +++ b/Tests/KeystoneTests/Tests/Features/Domains/DomainDetailsWebViewControllerTests.swift @@ -1,4 +1,5 @@ import XCTest +import Testing @testable import WordPress @@ -54,7 +55,56 @@ final class DomainDetailsWebViewControllerTests: XCTestCase { siteSlug: String = Constants.siteSlug, viewSlug: String = Constants.viewSlug ) throws -> String { - let url = "\(Constants.domainManagementBase)/\(domain)/\(viewSlug)/\(siteSlug)".addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) + let url = "\(Constants.domainManagementBase)/\(domain)/\(viewSlug)/\(siteSlug)" + .addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) return try XCTUnwrap(url) } } + +@MainActor +struct DomainDetailsNavigationTests { + + @Test func navigationPolicyDistinguishesRedirectsFromLinks() throws { + let controller = DomainDetailsWebViewController( + domain: "example.com", + siteSlug: "example.wordpress.com", + type: .mapped + ) + let redirectURL = try #require( + URL(string: "https://wordpress.com/domains/manage/all/example.com/edit/example.wordpress.com?redirected=1") + ) + var redirectRequest = URLRequest(url: redirectURL) + redirectRequest.mainDocumentURL = redirectURL + let externalURLHandler = ExternalURLHandlerSpy() + + let redirectPolicy = controller.linkBehavior.handle( + request: redirectRequest, + with: .other, + externalURLHandler: externalURLHandler + ) + + #expect(redirectPolicy == .allow) + #expect(externalURLHandler.openedURL == nil) + + let linkURL = try #require(URL(string: "https://wordpress.com/support")) + var linkRequest = URLRequest(url: linkURL) + linkRequest.mainDocumentURL = linkURL + + let linkPolicy = controller.linkBehavior.handle( + request: linkRequest, + with: .linkActivated, + externalURLHandler: externalURLHandler + ) + + #expect(linkPolicy == .cancel) + #expect(externalURLHandler.openedURL == linkURL) + } +} + +private final class ExternalURLHandlerSpy: ExternalURLHandler { + private(set) var openedURL: URL? + + func open(_ url: URL) { + openedURL = url + } +} diff --git a/WordPress/Classes/ViewRelated/Me/Domain Details/DomainDetailsWebViewController.swift b/WordPress/Classes/ViewRelated/Me/Domain Details/DomainDetailsWebViewController.swift index ced618d3f2e6..c42c24840e76 100644 --- a/WordPress/Classes/ViewRelated/Me/Domain Details/DomainDetailsWebViewController.swift +++ b/WordPress/Classes/ViewRelated/Me/Domain Details/DomainDetailsWebViewController.swift @@ -13,21 +13,17 @@ final class DomainDetailsWebViewController: WebKitViewController { static let manageAllDomainsPath = "\(domainsPath)/manage/all" } - // MARK: - Properties - - private let domain: String - - private var observation: NSKeyValueObservation? - // MARK: - Init init(domain: String, siteSlug: String, type: DomainType, analyticsSource: String? = nil) { - self.domain = domain let url = Self.wpcomDetailsURL(domain: domain, siteSlug: siteSlug, type: type) let configuration = WebViewControllerConfiguration(url: url) configuration.customTitle = domain configuration.analyticsSource = analyticsSource configuration.secureInteraction = true + if let url { + configuration.linkBehavior = .urlOnly(url) + } configuration.authenticateWithDefaultAccount() super.init(configuration: configuration) } @@ -40,25 +36,9 @@ final class DomainDetailsWebViewController: WebKitViewController { override func viewDidLoad() { super.viewDidLoad() - self.observeURL() self.trackWebViewShownEvent(url: url) } - // MARK: - Handling URL Changes - - private func observeURL() { - self.observation = webView.observe(\.url) { [weak self] webView, _ in - guard let self, let url = webView.url else { - return - } - if !self.shouldAllowNavigation(for: url) { - // Open URL in device browser then go back to Domain Management page. - self.open(url) - self.goBack() - } - } - } - // MARK: - Navigation override func goBack() { @@ -84,14 +64,6 @@ final class DomainDetailsWebViewController: WebKitViewController { WPAnalytics.track(.allDomainsDomainDetailsWebViewShown, properties: properties) } - private func shouldAllowNavigation(for url: URL) -> Bool { - return url.absoluteString == self.url?.absoluteString - } - - private func open(_ url: URL) { - UIApplication.shared.open(url) - } - private static func wpcomDetailsURL(domain: String, siteSlug: String, type: DomainType) -> URL? { let viewSlug = { switch type {