Skip to content

Commit

Permalink
Fix Tab not closed for redrected download (#2715)
Browse files Browse the repository at this point in the history
  • Loading branch information
mallexxx authored Apr 30, 2024
1 parent e0f5c47 commit 632cb2e
Show file tree
Hide file tree
Showing 6 changed files with 177 additions and 8 deletions.
5 changes: 3 additions & 2 deletions DuckDuckGo/Tab/TabExtensions/DownloadsTabExtension.swift
Original file line number Diff line number Diff line change
Expand Up @@ -224,11 +224,12 @@ extension DownloadsTabExtension: NavigationResponder {
let task = downloadManager.add(download, fromBurnerWindow: self.isBurner, delegate: self, destination: .auto)

var isMainFrameNavigationActionWithNoHistory: Bool {
guard let navigationAction,
// get the first navigation action in the redirect series
guard let navigationAction = navigationAction?.redirectHistory?.first ?? navigationAction,
navigationAction.isForMainFrame,
navigationAction.isTargetingNewWindow,
// webView has no navigation history (downloaded navigationAction has started from an empty state)
(navigationAction.redirectHistory?.first ?? navigationAction).fromHistoryItemIdentity == nil
navigationAction.fromHistoryItemIdentity == nil
else { return false }
return true
}
Expand Down
2 changes: 1 addition & 1 deletion IntegrationTests/Common/TestsURLExtension.swift
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ extension URL {
let url = URL.testsServer
.appendingPathComponent("filename") // "http://localhost:8085/filename"
.appendingTestParameters(status: 301,
reason: "Moved"
reason: "Moved",
data: Data(),
headers: ["Location": "/redirect-location.html"])
Tab.setUrl(url)
Expand Down
127 changes: 127 additions & 0 deletions IntegrationTests/Downloads/DownloadsIntegrationTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,133 @@ class DownloadsIntegrationTests: XCTestCase {
}
}

@MainActor
func testWhenDownloadIsStartedInNewTab_tabIsClosed() async throws {
let preferences = DownloadsPreferences.shared
preferences.alwaysRequestDownloadLocation = false
preferences.selectedDownloadLocation = FileManager.default.temporaryDirectory
let dirURL = FileManager.default.temporaryDirectory.appendingPathComponent(UUID().uuidString)
try FileManager.default.createDirectory(at: dirURL, withIntermediateDirectories: true)

let downloadUrl = URL.testsServer
.appendingPathComponent("fname.dat")
.appendingTestParameters(data: data.html,
headers: ["Content-Disposition": "attachment; filename=\"fname.dat\"",
"Content-Type": "text/html"])

let pageUrl = URL.testsServer
.appendingTestParameters(data: """
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Clickable Body</title>
</head>
<body onclick="window.open('\(downloadUrl.absoluteString.escapedJavaScriptString())')" style="cursor: pointer;">
<h1>Click anywhere on the page to open the link</h1>
</body>
</html>
""".utf8data)
let tab = tabViewModel.tab
_=await tab.setUrl(pageUrl, source: .link)?.result

NSApp.activate(ignoringOtherApps: true)
let downloadTaskFuture = FileDownloadManager.shared.downloadsPublisher.timeout(5).first().promise()

let e1 = expectation(description: "new tab opened")
var e2: XCTestExpectation!
let c = tabCollectionViewModel.$selectedTabViewModel.dropFirst()
.receive(on: DispatchQueue.main)
.sink { [unowned self] tabViewModel in
guard let tabViewModel else { return }
print("tabViewModel", tabViewModel.tab, tab)
if tabViewModel.tab !== tab {
e1.fulfill()
e2 = expectation(description: "new tab closed")
} else {
e2.fulfill()
}
}

// click to open a new (download) tab and instantly deactivate it
click(tab.webView)

// download should start in the background tab
_=try await downloadTaskFuture.get()

// expect for the download tab to close
await fulfillment(of: [e1, e2], timeout: 10)
withExtendedLifetime(c, {})
}

@MainActor
func testWhenDownloadIsStartedInNewTabAfterRedirect_tabIsClosed() async throws {
let preferences = DownloadsPreferences.shared
preferences.alwaysRequestDownloadLocation = false
preferences.selectedDownloadLocation = FileManager.default.temporaryDirectory
let dirURL = FileManager.default.temporaryDirectory.appendingPathComponent(UUID().uuidString)
try FileManager.default.createDirectory(at: dirURL, withIntermediateDirectories: true)

let downloadUrl = URL.testsServer
.appendingPathComponent("fname.dat")
.appendingTestParameters(data: data.html,
headers: ["Content-Disposition": "attachment; filename=\"fname.dat\"",
"Content-Type": "text/html"])

let redirectUrl = URL.testsServer
.appendingTestParameters(data: """
<html><head>
<script>
window.location.replace('\(downloadUrl.absoluteString.escapedJavaScriptString())');
</script>
</head></html>
""".utf8data)

let pageUrl = URL.testsServer
.appendingTestParameters(data: """
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Clickable Body</title>
</head>
<body onclick="window.open('\(redirectUrl.absoluteString.escapedJavaScriptString())')" style="cursor: pointer;">
<h1>Click anywhere on the page to open the link</h1>
</body>
</html>
""".utf8data)
let tab = tabViewModel.tab
_=await tab.setUrl(pageUrl, source: .link)?.result

NSApp.activate(ignoringOtherApps: true)
let downloadTaskFuture = FileDownloadManager.shared.downloadsPublisher.timeout(5).first().promise()

let e1 = expectation(description: "new tab opened")
var e2: XCTestExpectation!
let c = tabCollectionViewModel.$selectedTabViewModel.dropFirst()
.receive(on: DispatchQueue.main)
.sink { [unowned self] tabViewModel in
guard let tabViewModel else { return }
print("tabViewModel", tabViewModel.tab, tab)
if tabViewModel.tab !== tab {
e1.fulfill()
e2 = expectation(description: "new tab closed")
} else {
e2.fulfill()
}
}

// click to open a new (download) tab and instantly deactivate it
click(tab.webView)

// download should start in the background tab
_=try await downloadTaskFuture.get()

// expect for the download tab to close
await fulfillment(of: [e1, e2], timeout: 10)
withExtendedLifetime(c, {})
}

@MainActor
func testWhenSaveDialogOpenInBackgroundTabAndTabIsClosed_downloadIsCancelled() async throws {
let persistor = DownloadsPreferencesUserDefaultsPersistor()
Expand Down
Loading

0 comments on commit 632cb2e

Please sign in to comment.