Skip to content

Commit 4961d00

Browse files
ochafikclaude
andcommitted
fix: Update Swift SDK tests for API changes
- Use EmptyCapability() instead of Bool for capabilities - Use McpUiToolInputNotificationParams instead of removed type - Use McpUiResourceMetaCsp for resource meta tests - Add @mainactor to WKWebViewTransport tests - Use actor-based state capture for Sendable closure compliance - Extract async values before XCTAssert calls 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
1 parent 4b23834 commit 4961d00

File tree

2 files changed

+66
-44
lines changed

2 files changed

+66
-44
lines changed

swift/Tests/McpAppsTests/AppBridgeTests.swift

Lines changed: 44 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@ final class AppBridgeTests: XCTestCase {
66
let testHostInfo = Implementation(name: "TestHost", version: "1.0.0")
77
let testAppInfo = Implementation(name: "TestApp", version: "1.0.0")
88
let testHostCapabilities = McpUiHostCapabilities(
9-
openLinks: true,
9+
openLinks: EmptyCapability(),
1010
serverTools: ServerToolsCapability(),
11-
logging: true
11+
logging: EmptyCapability()
1212
)
1313

1414
func testMessageTypes() throws {
@@ -58,7 +58,7 @@ final class AppBridgeTests: XCTestCase {
5858
}
5959

6060
func testToolInputParams() throws {
61-
let params = McpUiToolInputParams(
61+
let params = McpUiToolInputNotificationParams(
6262
arguments: [
6363
"query": AnyCodable("weather in NYC"),
6464
"count": AnyCodable(5)
@@ -69,7 +69,7 @@ final class AppBridgeTests: XCTestCase {
6969
let decoder = JSONDecoder()
7070

7171
let encoded = try encoder.encode(params)
72-
let decoded = try decoder.decode(McpUiToolInputParams.self, from: encoded)
72+
let decoded = try decoder.decode(McpUiToolInputNotificationParams.self, from: encoded)
7373

7474
XCTAssertEqual(decoded.arguments?["query"]?.value as? String, "weather in NYC")
7575
XCTAssertEqual(decoded.arguments?["count"]?.value as? Int, 5)
@@ -136,9 +136,13 @@ final class AppBridgeTests: XCTestCase {
136136
hostCapabilities: testHostCapabilities
137137
)
138138

139-
XCTAssertFalse(await bridge.isReady())
140-
XCTAssertNil(await bridge.getAppCapabilities())
141-
XCTAssertNil(await bridge.getAppVersion())
139+
let isReady = await bridge.isReady()
140+
let capabilities = await bridge.getAppCapabilities()
141+
let version = await bridge.getAppVersion()
142+
143+
XCTAssertFalse(isReady)
144+
XCTAssertNil(capabilities)
145+
XCTAssertNil(version)
142146
}
143147

144148
func testInMemoryTransportCreation() async throws {
@@ -168,32 +172,25 @@ final class AppBridgeTests: XCTestCase {
168172

169173
XCTAssertEqual(decoded.protocolVersion, McpAppsConfig.latestProtocolVersion)
170174
XCTAssertEqual(decoded.hostInfo.name, testHostInfo.name)
171-
XCTAssertEqual(decoded.hostContext.theme, .light)
175+
XCTAssertEqual(decoded.hostContext.theme, McpUiTheme.light)
172176
}
173177

174178
func testLogLevel() throws {
175179
let levels: [LogLevel] = [.debug, .info, .notice, .warning, .error, .critical, .alert, .emergency]
176180

177-
for level in levels {
178-
let params = LoggingMessageParams(
179-
level: level,
180-
data: AnyCodable("Test message"),
181-
logger: "TestLogger"
182-
)
183-
184-
let encoder = JSONEncoder()
185-
let decoder = JSONDecoder()
186-
187-
let encoded = try encoder.encode(params)
188-
let decoded = try decoder.decode(LoggingMessageParams.self, from: encoded)
181+
let encoder = JSONEncoder()
182+
let decoder = JSONDecoder()
189183

190-
XCTAssertEqual(decoded.level, level)
184+
for level in levels {
185+
let encoded = try encoder.encode(level)
186+
let decoded = try decoder.decode(LogLevel.self, from: encoded)
187+
XCTAssertEqual(decoded, level)
191188
}
192189
}
193190

194191
func testResourceMeta() throws {
195192
let meta = McpUiResourceMeta(
196-
csp: McpUiResourceCsp(
193+
csp: McpUiResourceMetaCsp(
197194
connectDomains: ["https://api.example.com"],
198195
resourceDomains: ["https://cdn.example.com"]
199196
),
@@ -218,12 +215,19 @@ final class AppBridgeTests: XCTestCase {
218215
hostCapabilities: testHostCapabilities
219216
)
220217

221-
// Set up callback to handle tools/call
222-
var receivedToolName: String?
223-
var receivedArguments: [String: AnyCodable]?
218+
// Use actors for thread-safe state capture
219+
actor CallState {
220+
var toolName: String?
221+
var arguments: [String: AnyCodable]?
222+
func set(name: String, args: [String: AnyCodable]?) {
223+
self.toolName = name
224+
self.arguments = args
225+
}
226+
}
227+
let state = CallState()
228+
224229
await bridge.setOnToolCall { name, arguments in
225-
receivedToolName = name
226-
receivedArguments = arguments
230+
await state.set(name: name, args: arguments)
227231
return [
228232
"content": AnyCodable([
229233
["type": "text", "text": "Tool result"]
@@ -255,6 +259,8 @@ final class AppBridgeTests: XCTestCase {
255259
try await Task.sleep(nanoseconds: 100_000_000) // 100ms
256260

257261
// Verify callback was called
262+
let receivedToolName = await state.toolName
263+
let receivedArguments = await state.arguments
258264
XCTAssertEqual(receivedToolName, "test_tool")
259265
XCTAssertNotNil(receivedArguments)
260266
XCTAssertEqual(receivedArguments?["param1"]?.value as? String, "value1")
@@ -270,10 +276,15 @@ final class AppBridgeTests: XCTestCase {
270276
hostCapabilities: testHostCapabilities
271277
)
272278

273-
// Set up callback to handle resources/read
274-
var receivedUri: String?
279+
// Use actor for thread-safe state capture
280+
actor UriState {
281+
var uri: String?
282+
func set(_ value: String) { uri = value }
283+
}
284+
let state = UriState()
285+
275286
await bridge.setOnResourceRead { uri in
276-
receivedUri = uri
287+
await state.set(uri)
277288
return [
278289
"contents": AnyCodable([
279290
[
@@ -305,6 +316,7 @@ final class AppBridgeTests: XCTestCase {
305316
try await Task.sleep(nanoseconds: 100_000_000) // 100ms
306317

307318
// Verify callback was called
319+
let receivedUri = await state.uri
308320
XCTAssertEqual(receivedUri, "ui://test-app")
309321

310322
await bridge.close()
@@ -340,7 +352,8 @@ final class AppBridgeTests: XCTestCase {
340352

341353
// Verify error response was sent (we can't easily check the response without more infrastructure)
342354
// Just verify the bridge is still functional
343-
XCTAssertFalse(await bridge.isReady())
355+
let isReady = await bridge.isReady()
356+
XCTAssertFalse(isReady)
344357

345358
await bridge.close()
346359
await guestTransport.close()

swift/Tests/McpAppsTests/WKWebViewTransportTests.swift

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@ import XCTest
22
import WebKit
33
@testable import McpApps
44

5-
@available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *)
5+
@available(iOS 16.0, macOS 13.0, tvOS 16.0, watchOS 9.0, *)
66
final class WKWebViewTransportTests: XCTestCase {
77

8+
@MainActor
89
func testTransportCreation() async throws {
910
let webView = WKWebView()
1011
let transport = WKWebViewTransport(webView: webView)
@@ -13,6 +14,7 @@ final class WKWebViewTransportTests: XCTestCase {
1314
XCTAssertNotNil(transport)
1415
}
1516

17+
@MainActor
1618
func testTransportStartAndClose() async throws {
1719
let webView = WKWebView()
1820
let transport = WKWebViewTransport(webView: webView)
@@ -24,6 +26,7 @@ final class WKWebViewTransportTests: XCTestCase {
2426
await transport.close()
2527
}
2628

29+
@MainActor
2730
func testTransportSendRequest() async throws {
2831
let webView = WKWebView()
2932
let transport = WKWebViewTransport(webView: webView)
@@ -43,6 +46,7 @@ final class WKWebViewTransportTests: XCTestCase {
4346
await transport.close()
4447
}
4548

49+
@MainActor
4650
func testTransportSendNotification() async throws {
4751
let webView = WKWebView()
4852
let transport = WKWebViewTransport(webView: webView)
@@ -61,6 +65,7 @@ final class WKWebViewTransportTests: XCTestCase {
6165
await transport.close()
6266
}
6367

68+
@MainActor
6469
func testTransportSendResponse() async throws {
6570
let webView = WKWebView()
6671
let transport = WKWebViewTransport(webView: webView)
@@ -79,6 +84,7 @@ final class WKWebViewTransportTests: XCTestCase {
7984
await transport.close()
8085
}
8186

87+
@MainActor
8288
func testTransportSendError() async throws {
8389
let webView = WKWebView()
8490
let transport = WKWebViewTransport(webView: webView)
@@ -100,6 +106,7 @@ final class WKWebViewTransportTests: XCTestCase {
100106
await transport.close()
101107
}
102108

109+
@MainActor
103110
func testCustomHandlerName() async throws {
104111
let webView = WKWebView()
105112
let customHandlerName = "customBridge"
@@ -115,6 +122,7 @@ final class WKWebViewTransportTests: XCTestCase {
115122
await transport.close()
116123
}
117124

125+
@MainActor
118126
func testMultipleStartCallsAreIdempotent() async throws {
119127
let webView = WKWebView()
120128
let transport = WKWebViewTransport(webView: webView)
@@ -127,6 +135,7 @@ final class WKWebViewTransportTests: XCTestCase {
127135
await transport.close()
128136
}
129137

138+
@MainActor
130139
func testSendWithoutStartThrows() async throws {
131140
let webView = WKWebView()
132141
let transport = WKWebViewTransport(webView: webView)
@@ -149,6 +158,7 @@ final class WKWebViewTransportTests: XCTestCase {
149158
}
150159
}
151160

161+
@MainActor
152162
func testJSONEncodingWithSpecialCharacters() async throws {
153163
let webView = WKWebView()
154164
let transport = WKWebViewTransport(webView: webView)
@@ -171,6 +181,7 @@ final class WKWebViewTransportTests: XCTestCase {
171181
await transport.close()
172182
}
173183

184+
@MainActor
174185
func testMessageReception() async throws {
175186
let webView = WKWebView()
176187
let transport = WKWebViewTransport(webView: webView)
@@ -199,6 +210,7 @@ final class WKWebViewTransportTests: XCTestCase {
199210
await transport.close()
200211
}
201212

213+
@MainActor
202214
func testTransportWithNilWebView() async throws {
203215
// Create a weak reference to test behavior with deallocated webView
204216
var webView: WKWebView? = WKWebView()
@@ -224,6 +236,7 @@ final class WKWebViewTransportTests: XCTestCase {
224236
await transport.close()
225237
}
226238

239+
@MainActor
227240
func testConcurrentSends() async throws {
228241
let webView = WKWebView()
229242
let transport = WKWebViewTransport(webView: webView)
@@ -249,6 +262,7 @@ final class WKWebViewTransportTests: XCTestCase {
249262
await transport.close()
250263
}
251264

265+
@MainActor
252266
func testMessageWithDifferentIdTypes() async throws {
253267
let webView = WKWebView()
254268
let transport = WKWebViewTransport(webView: webView)
@@ -274,6 +288,7 @@ final class WKWebViewTransportTests: XCTestCase {
274288
await transport.close()
275289
}
276290

291+
@MainActor
277292
func testComplexNestedParams() async throws {
278293
let webView = WKWebView()
279294
let transport = WKWebViewTransport(webView: webView)
@@ -305,6 +320,7 @@ final class WKWebViewTransportTests: XCTestCase {
305320
await transport.close()
306321
}
307322

323+
@MainActor
308324
func testMessageEventFormat() async throws {
309325
let webView = WKWebView()
310326
let transport = WKWebViewTransport(webView: webView)
@@ -334,9 +350,7 @@ final class WKWebViewTransportTests: XCTestCase {
334350
</html>
335351
"""
336352

337-
await MainActor.run {
338-
webView.loadHTMLString(html, baseURL: nil)
339-
}
353+
webView.loadHTMLString(html, baseURL: nil)
340354

341355
// Wait for page to load
342356
try await Task.sleep(nanoseconds: 500_000_000) // 0.5 seconds
@@ -354,18 +368,14 @@ final class WKWebViewTransportTests: XCTestCase {
354368
try await Task.sleep(nanoseconds: 100_000_000) // 0.1 seconds
355369

356370
// Verify the event was captured correctly
357-
let result = try await MainActor.run {
358-
try await webView.evaluateJavaScript("window.capturedEvents.length")
359-
}
371+
let result = try await webView.evaluateJavaScript("window.capturedEvents.length")
360372

361373
// Should have captured at least one event
362374
if let count = result as? Int {
363375
XCTAssertGreaterThan(count, 0, "Should have captured at least one message event")
364376

365377
// Check the format of the first event
366-
let firstEvent = try await MainActor.run {
367-
try await webView.evaluateJavaScript("JSON.stringify(window.capturedEvents[0])")
368-
}
378+
let firstEvent = try await webView.evaluateJavaScript("JSON.stringify(window.capturedEvents[0])")
369379

370380
if let eventJson = firstEvent as? String {
371381
// Parse and verify the event structure
@@ -382,6 +392,7 @@ final class WKWebViewTransportTests: XCTestCase {
382392
await transport.close()
383393
}
384394

395+
@MainActor
385396
func testBridgeScriptPostMessage() async throws {
386397
let webView = WKWebView()
387398
let transport = WKWebViewTransport(webView: webView)
@@ -422,9 +433,7 @@ final class WKWebViewTransportTests: XCTestCase {
422433
}
423434
}
424435

425-
await MainActor.run {
426-
webView.loadHTMLString(html, baseURL: nil)
427-
}
436+
webView.loadHTMLString(html, baseURL: nil)
428437

429438
await fulfillment(of: [expectation], timeout: 2.0)
430439

0 commit comments

Comments
 (0)