Skip to content

Commit 614e4b2

Browse files
committed
Uncommitted ShareSheetUITests.swift changes
1 parent f18d8ab commit 614e4b2

1 file changed

Lines changed: 169 additions & 0 deletions

File tree

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
import Network
2+
import Synchronization
3+
import XCTest
4+
5+
@MainActor
6+
final class ShareSheetUITests: XCTestCase {
7+
override func setUpWithError() throws {
8+
continueAfterFailure = false
9+
}
10+
11+
func testShareSheetHandoffLandsOnDetail() throws {
12+
let app = XCUIApplication()
13+
try app.launchStubbed()
14+
app.requireForeground()
15+
16+
let galleryURL = try XCTUnwrap(UITestConstants.galleryURL(scheme: "https"))
17+
let sharePageServer = try LocalSharePageServer(galleryURL: galleryURL)
18+
let safari = XCUIApplication(bundleIdentifier: "com.apple.mobilesafari")
19+
safari.launch()
20+
21+
let tabOverviewDoneButton = safari.buttons["DoneButton"]
22+
if tabOverviewDoneButton.waitForExistence(timeout: 2) {
23+
tabOverviewDoneButton.tap()
24+
}
25+
26+
let addressButton = safari.buttons["TabBarItemTitle"].firstMatch
27+
XCTAssertTrue(
28+
addressButton.waitForExistence(timeout: 5),
29+
"Safari did not expose its TabBarItemTitle address button.\n\(safari.debugDescription)"
30+
)
31+
addressButton.tap()
32+
33+
let addressField = safari.textFields.firstMatch
34+
XCTAssertTrue(
35+
addressField.waitForExistence(timeout: 5),
36+
"Safari did not expose an address field after activating its address button."
37+
)
38+
addressField.typeText(sharePageServer.url.absoluteString + "\n")
39+
40+
let galleryLink = safari.links[LocalSharePageServer.linkLabel]
41+
XCTAssertTrue(
42+
galleryLink.waitForExistence(timeout: 10),
43+
"Safari did not render the local gallery-link fixture.\n\(safari.debugDescription)"
44+
)
45+
galleryLink.press(forDuration: 1)
46+
47+
let shareMenuItem = safari.buttons["Share"].firstMatch
48+
XCTAssertTrue(
49+
shareMenuItem.waitForExistence(timeout: 5),
50+
"Safari's link menu did not expose Share.\n\(safari.debugDescription)"
51+
)
52+
shareMenuItem.tap()
53+
54+
let ehPandaActivity = safari.descendants(matching: .any)
55+
.matching(NSPredicate(format: "label == %@", "EhPanda"))
56+
.firstMatch
57+
if ehPandaActivity.waitForExistence(timeout: 5) == false {
58+
let activityList = safari.collectionViews.firstMatch
59+
if activityList.exists {
60+
activityList.swipeLeft()
61+
}
62+
}
63+
if ehPandaActivity.waitForExistence(timeout: 5) == false {
64+
safari.swipeUp()
65+
}
66+
XCTAssertTrue(
67+
ehPandaActivity.waitForExistence(timeout: 5),
68+
"The activity view did not expose the EhPanda extension.\n\(safari.debugDescription)"
69+
)
70+
ehPandaActivity.tap()
71+
72+
app.requireForeground(timeout: 15)
73+
app.requireElement("detail_view", matching: .scrollView, timeout: 15)
74+
XCTAssertTrue(
75+
app.buttons[UITestConstants.primaryMarkerTitle]
76+
.waitForExistence(timeout: 10),
77+
"The share handoff did not render the hermetic gallery marker."
78+
)
79+
}
80+
}
81+
82+
private final class LocalSharePageServer {
83+
static let linkLabel = "EhPanda Gallery"
84+
85+
let url: URL
86+
87+
private let listener: NWListener
88+
89+
init(galleryURL: URL) throws {
90+
let listener = try NWListener(using: .tcp, on: .any)
91+
let readiness = Mutex<Result<Void, Error>?>(nil)
92+
let readinessSignal = DispatchSemaphore(value: 0)
93+
94+
listener.stateUpdateHandler = { state in
95+
switch state {
96+
case .ready:
97+
readiness.withLock({ $0 = .success(()) })
98+
readinessSignal.signal()
99+
case .failed(let error):
100+
readiness.withLock({ $0 = .failure(error) })
101+
readinessSignal.signal()
102+
default:
103+
break
104+
}
105+
}
106+
107+
let response = Self.response(galleryURL: galleryURL)
108+
listener.newConnectionHandler = { connection in
109+
connection.start(queue: .global(qos: .userInitiated))
110+
connection.receive(
111+
minimumIncompleteLength: 1,
112+
maximumLength: 4_096
113+
) { _, _, _, _ in
114+
connection.send(
115+
content: response,
116+
contentContext: .finalMessage,
117+
isComplete: true,
118+
completion: .contentProcessed({ _ in connection.cancel() })
119+
)
120+
}
121+
}
122+
listener.start(queue: .global(qos: .userInitiated))
123+
124+
guard readinessSignal.wait(timeout: .now() + 5) == .success else {
125+
listener.cancel()
126+
throw LocalSharePageServerError.startTimedOut
127+
}
128+
if let readinessResult = readiness.withLock({ $0 }) {
129+
try readinessResult.get()
130+
}
131+
guard let port = listener.port,
132+
let url = URL(string: "http://127.0.0.1:\(port.rawValue)/")
133+
else {
134+
listener.cancel()
135+
throw LocalSharePageServerError.missingURL
136+
}
137+
138+
self.listener = listener
139+
self.url = url
140+
}
141+
142+
deinit {
143+
listener.cancel()
144+
}
145+
146+
private static func response(galleryURL: URL) -> Data {
147+
let html = """
148+
<!doctype html>
149+
<meta name="viewport" content="width=device-width, initial-scale=1">
150+
<a href="\(galleryURL.absoluteString)">\(linkLabel)</a>
151+
"""
152+
let htmlData = Data(html.utf8)
153+
let headers = """
154+
HTTP/1.1 200 OK\r
155+
Content-Type: text/html; charset=utf-8\r
156+
Content-Length: \(htmlData.count)\r
157+
Connection: close\r
158+
\r
159+
"""
160+
var response = Data(headers.utf8)
161+
response.append(htmlData)
162+
return response
163+
}
164+
}
165+
166+
private enum LocalSharePageServerError: Error {
167+
case missingURL
168+
case startTimedOut
169+
}

0 commit comments

Comments
 (0)