diff --git a/Sources/Dependencies/DependencyValues/OpenURL.swift b/Sources/Dependencies/DependencyValues/OpenURL.swift index 23d216d3..ee84c4c3 100644 --- a/Sources/Dependencies/DependencyValues/OpenURL.swift +++ b/Sources/Dependencies/DependencyValues/OpenURL.swift @@ -1,4 +1,7 @@ #if canImport(SwiftUI) + #if os(macOS) + import AppKit + #endif public import Foundation import IssueReporting import SwiftUI @@ -14,32 +17,50 @@ @available(iOS 14, macOS 11, tvOS 14, watchOS 7, *) private enum OpenURLKey: DependencyKey { - static let liveValue = OpenURLEffect { url in - let stream = AsyncStream { continuation in - let task = Task { @MainActor in - #if os(watchOS) - EnvironmentValues().openURL(url) - continuation.yield(true) - continuation.finish() - #else - EnvironmentValues().openURL(url) { canOpen in - continuation.yield(canOpen) + #if os(macOS) + static let liveValue = OpenURLPlatform.liveValue() + #else + static let liveValue = OpenURLEffect { url in + let stream = AsyncStream { continuation in + let task = Task { @MainActor in + #if os(watchOS) + EnvironmentValues().openURL(url) + continuation.yield(true) continuation.finish() - } - #endif - } - continuation.onTermination = { @Sendable _ in - task.cancel() + #else + EnvironmentValues().openURL(url) { canOpen in + continuation.yield(canOpen) + continuation.finish() + } + #endif + } + continuation.onTermination = { @Sendable _ in + task.cancel() + } } + return await stream.first(where: { _ in true }) ?? false } - return await stream.first(where: { _ in true }) ?? false - } + #endif static let testValue = OpenURLEffect { _ in reportIssue(#"Unimplemented: @Dependency(\.openURL)"#) return false } } + #if os(macOS) + enum OpenURLPlatform { + static func liveValue( + using workspaceOpen: @escaping @MainActor @Sendable (URL) -> Bool = { + NSWorkspace.shared.open($0) + } + ) -> OpenURLEffect { + OpenURLEffect { url in + await workspaceOpen(url) + } + } + } + #endif + public struct OpenURLEffect: Sendable { private let handler: @Sendable (URL) async -> Bool diff --git a/Tests/DependenciesTests/OpenURLTests.swift b/Tests/DependenciesTests/OpenURLTests.swift new file mode 100644 index 00000000..145e7f1f --- /dev/null +++ b/Tests/DependenciesTests/OpenURLTests.swift @@ -0,0 +1,29 @@ +#if os(macOS) + @testable import Dependencies + import Foundation + import XCTest + + final class OpenURLTests: XCTestCase { + @MainActor + func testLiveOpenURLUsesWorkspace() async { + let url = URL(string: "https://example.com")! + var openedURL: URL? + let openURL = OpenURLPlatform.liveValue { + openedURL = $0 + return true + } + let didOpen = await openURL(url) + + XCTAssertTrue(didOpen) + XCTAssertEqual(openedURL, url) + } + + @MainActor + func testLiveOpenURLReturnsWorkspaceFailure() async { + let openURL = OpenURLPlatform.liveValue { _ in false } + let didOpen = await openURL(URL(string: "https://example.com")!) + + XCTAssertFalse(didOpen) + } + } +#endif