Skip to content

Commit 2d0cec9

Browse files
authored
[url_launcher] Improving unit tests on mac (flutter#4472)
Add unit tests for url_launcher canLaunch and launch methods on mac with success and failure results. Fixes flutter#92969
1 parent de267d3 commit 2d0cec9

File tree

4 files changed

+167
-8
lines changed

4 files changed

+167
-8
lines changed

packages/url_launcher/url_launcher_macos/CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
## NEXT
1+
## 2.0.3
22

33
* Updates code for new analysis options.
4+
* Updates unit tests.
45

56
## 2.0.2
67

packages/url_launcher/url_launcher_macos/example/macos/RunnerTests/RunnerTests.swift

Lines changed: 134 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,149 @@ import FlutterMacOS
66
import XCTest
77
import url_launcher_macos
88

9+
/// A stub to simulate the system Url handler.
10+
class StubWorkspace: SystemURLHandler {
11+
12+
var isSuccessful = true
13+
14+
func open(_ url: URL) -> Bool {
15+
return isSuccessful
16+
}
17+
18+
func urlForApplication(toOpen: URL) -> URL? {
19+
return toOpen
20+
}
21+
}
22+
923
class RunnerTests: XCTestCase {
10-
func testCanLaunch() throws {
24+
25+
func testCanLaunchSuccessReturnsTrue() throws {
26+
let expectation = XCTestExpectation(description: "Check if the URL can be launched")
1127
let plugin = UrlLauncherPlugin()
28+
1229
let call = FlutterMethodCall(
1330
methodName: "canLaunch",
1431
arguments: ["url": "https://flutter.dev"])
15-
var canLaunch: Bool?
32+
33+
plugin.handle(
34+
call,
35+
result: { (result: Any?) -> Void in
36+
XCTAssertEqual(result as? Bool, true)
37+
expectation.fulfill()
38+
})
39+
40+
wait(for: [expectation], timeout: 10.0)
41+
}
42+
43+
func testCanLaunchNoAppIsAbleToOpenUrlReturnsFalse() throws {
44+
let expectation = XCTestExpectation(description: "Check if the URL can be launched")
45+
let plugin = UrlLauncherPlugin()
46+
47+
let call = FlutterMethodCall(
48+
methodName: "canLaunch",
49+
arguments: ["url": "example://flutter.dev"])
50+
51+
plugin.handle(
52+
call,
53+
result: { (result: Any?) -> Void in
54+
XCTAssertEqual(result as? Bool, false)
55+
expectation.fulfill()
56+
})
57+
58+
wait(for: [expectation], timeout: 10.0)
59+
}
60+
61+
func testCanLaunchInvalidUrlReturnsFalse() throws {
62+
let expectation = XCTestExpectation(description: "Check if the URL can be launched")
63+
let plugin = UrlLauncherPlugin()
64+
65+
let call = FlutterMethodCall(
66+
methodName: "canLaunch",
67+
arguments: ["url": "brokenUrl"])
68+
69+
plugin.handle(
70+
call,
71+
result: { (result: Any?) -> Void in
72+
XCTAssertEqual(result as? Bool, false)
73+
expectation.fulfill()
74+
})
75+
76+
wait(for: [expectation], timeout: 10.0)
77+
}
78+
79+
func testCanLaunchMissingArgumentReturnsFlutterError() throws {
80+
let expectation = XCTestExpectation(description: "Check if the URL can be launched")
81+
let plugin = UrlLauncherPlugin()
82+
83+
let call = FlutterMethodCall(
84+
methodName: "canLaunch",
85+
arguments: [])
86+
1687
plugin.handle(
1788
call,
1889
result: { (result: Any?) -> Void in
19-
canLaunch = result as? Bool
90+
XCTAssertTrue(result is FlutterError)
91+
expectation.fulfill()
92+
})
93+
94+
wait(for: [expectation], timeout: 10.0)
95+
}
96+
97+
func testLaunchSuccessReturnsTrue() throws {
98+
let expectation = XCTestExpectation(description: "Try to open the URL")
99+
let workspace = StubWorkspace()
100+
let pluginWithStubWorkspace = UrlLauncherPlugin(workspace)
101+
102+
let call = FlutterMethodCall(
103+
methodName: "launch",
104+
arguments: ["url": "https://flutter.dev"])
105+
106+
pluginWithStubWorkspace.handle(
107+
call,
108+
result: { (result: Any?) -> Void in
109+
XCTAssertEqual(result as? Bool, true)
110+
expectation.fulfill()
111+
})
112+
113+
wait(for: [expectation], timeout: 10.0)
114+
}
115+
116+
func testLaunchNoAppIsAbleToOpenUrlReturnsFalse() throws {
117+
let expectation = XCTestExpectation(description: "Try to open the URL")
118+
let workspace = StubWorkspace()
119+
workspace.isSuccessful = false
120+
let pluginWithStubWorkspace = UrlLauncherPlugin(workspace)
121+
122+
let call = FlutterMethodCall(
123+
methodName: "launch",
124+
arguments: ["url": "schemethatdoesnotexist://flutter.dev"])
125+
126+
pluginWithStubWorkspace.handle(
127+
call,
128+
result: { (result: Any?) -> Void in
129+
XCTAssertEqual(result as? Bool, false)
130+
expectation.fulfill()
131+
})
132+
133+
wait(for: [expectation], timeout: 10.0)
134+
}
135+
136+
func testLaunchMissingArgumentReturnsFlutterError() throws {
137+
let expectation = XCTestExpectation(description: "Try to open the URL")
138+
let workspace = StubWorkspace()
139+
let pluginWithStubWorkspace = UrlLauncherPlugin(workspace)
140+
141+
let call = FlutterMethodCall(
142+
methodName: "launch",
143+
arguments: [])
144+
145+
pluginWithStubWorkspace.handle(
146+
call,
147+
result: { (result: Any?) -> Void in
148+
XCTAssertTrue(result is FlutterError)
149+
expectation.fulfill()
20150
})
21151

22-
XCTAssertTrue(canLaunch == true)
152+
wait(for: [expectation], timeout: 10.0)
23153
}
24154
}

packages/url_launcher/url_launcher_macos/macos/Classes/UrlLauncherPlugin.swift

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,35 @@
55
import FlutterMacOS
66
import Foundation
77

8+
/// A handler that can launch other apps, check if any app is able to open the URL.
9+
public protocol SystemURLHandler {
10+
11+
/// Opens the location at the specified URL.
12+
///
13+
/// - Parameters:
14+
/// - url: A URL specifying the location to open.
15+
/// - Returns: true if the location was successfully opened; otherwise, false.
16+
func open(_ url: URL) -> Bool
17+
18+
/// Returns the URL to the default app that would be opened.
19+
///
20+
/// - Parameters:
21+
/// - toOpen: The URL of the file to open.
22+
/// - Returns: The URL of the default app that would open the specified url.
23+
/// Returns nil if no app is able to open the URL, or if the file URL does not exist.
24+
func urlForApplication(toOpen: URL) -> URL?
25+
}
26+
27+
extension NSWorkspace: SystemURLHandler {}
28+
829
public class UrlLauncherPlugin: NSObject, FlutterPlugin {
30+
31+
private var workspace: SystemURLHandler
32+
33+
public init(_ workspace: SystemURLHandler = NSWorkspace.shared) {
34+
self.workspace = workspace
35+
}
36+
937
public static func register(with registrar: FlutterPluginRegistrar) {
1038
let channel = FlutterMethodChannel(
1139
name: "plugins.flutter.io/url_launcher",
@@ -24,15 +52,15 @@ public class UrlLauncherPlugin: NSObject, FlutterPlugin {
2452
result(invalidURLError(urlString))
2553
return
2654
}
27-
result(NSWorkspace.shared.urlForApplication(toOpen: url) != nil)
55+
result(workspace.urlForApplication(toOpen: url) != nil)
2856
case "launch":
2957
guard let unwrappedURLString = urlString,
3058
let url = URL.init(string: unwrappedURLString)
3159
else {
3260
result(invalidURLError(urlString))
3361
return
3462
}
35-
result(NSWorkspace.shared.open(url))
63+
result(workspace.open(url))
3664
default:
3765
result(FlutterMethodNotImplemented)
3866
}

packages/url_launcher/url_launcher_macos/pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ name: url_launcher_macos
22
description: macOS implementation of the url_launcher plugin.
33
repository: https://github.com/flutter/plugins/tree/master/packages/url_launcher/url_launcher_macos
44
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+url_launcher%22
5-
version: 2.0.2
5+
version: 2.0.3
66

77
environment:
88
sdk: ">=2.12.0 <3.0.0"

0 commit comments

Comments
 (0)