From eec6212cdff83a73d741c70511643c905c537870 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Sun, 14 Dec 2025 03:25:49 +0000 Subject: [PATCH] test(ios): add smoke coverage tests --- .../Bridge/BridgeConnectionController.swift | 6 ++- .../Tests/IOSBridgeChatTransportTests.swift | 34 ++++++++++++ apps/ios/Tests/SwiftUIRenderSmokeTests.swift | 54 +++++++++++++++++++ 3 files changed, 92 insertions(+), 2 deletions(-) create mode 100644 apps/ios/Tests/IOSBridgeChatTransportTests.swift create mode 100644 apps/ios/Tests/SwiftUIRenderSmokeTests.swift diff --git a/apps/ios/Sources/Bridge/BridgeConnectionController.swift b/apps/ios/Sources/Bridge/BridgeConnectionController.swift index c80989182..b3a053aa6 100644 --- a/apps/ios/Sources/Bridge/BridgeConnectionController.swift +++ b/apps/ios/Sources/Bridge/BridgeConnectionController.swift @@ -15,7 +15,7 @@ final class BridgeConnectionController: ObservableObject { private var didAutoConnect = false private var seenStableIDs = Set() - init(appModel: NodeAppModel) { + init(appModel: NodeAppModel, startDiscovery: Bool = true) { self.appModel = appModel BridgeSettingsStore.bootstrapPersistence() @@ -32,7 +32,9 @@ final class BridgeConnectionController: ObservableObject { self.discovery.$statusText .assign(to: &self.$discoveryStatusText) - self.discovery.start() + if startDiscovery { + self.discovery.start() + } } func setScenePhase(_ phase: ScenePhase) { diff --git a/apps/ios/Tests/IOSBridgeChatTransportTests.swift b/apps/ios/Tests/IOSBridgeChatTransportTests.swift new file mode 100644 index 000000000..6785c4ec0 --- /dev/null +++ b/apps/ios/Tests/IOSBridgeChatTransportTests.swift @@ -0,0 +1,34 @@ +import Testing +@testable import Clawdis + +@Suite struct IOSBridgeChatTransportTests { + @Test func requestsFailFastWhenBridgeNotConnected() async { + let bridge = BridgeSession() + let transport = IOSBridgeChatTransport(bridge: bridge) + + do { + try await transport.setActiveSessionKey("node-test") + Issue.record("Expected setActiveSessionKey to throw when bridge not connected") + } catch {} + + do { + _ = try await transport.requestHistory(sessionKey: "node-test") + Issue.record("Expected requestHistory to throw when bridge not connected") + } catch {} + + do { + _ = try await transport.sendMessage( + sessionKey: "node-test", + message: "hello", + thinking: "low", + idempotencyKey: "idempotency", + attachments: []) + Issue.record("Expected sendMessage to throw when bridge not connected") + } catch {} + + do { + _ = try await transport.requestHealth(timeoutMs: 250) + } catch {} + } +} + diff --git a/apps/ios/Tests/SwiftUIRenderSmokeTests.swift b/apps/ios/Tests/SwiftUIRenderSmokeTests.swift new file mode 100644 index 000000000..3d6fc4d90 --- /dev/null +++ b/apps/ios/Tests/SwiftUIRenderSmokeTests.swift @@ -0,0 +1,54 @@ +import SwiftUI +import Testing +import UIKit +@testable import Clawdis + +@Suite struct SwiftUIRenderSmokeTests { + @MainActor private static func host(_ view: V) -> UIWindow { + let window = UIWindow(frame: UIScreen.main.bounds) + window.rootViewController = UIHostingController(rootView: view) + window.makeKeyAndVisible() + window.rootViewController?.view.setNeedsLayout() + window.rootViewController?.view.layoutIfNeeded() + return window + } + + @Test @MainActor func settingsTabBuildsAViewHierarchy() { + let appModel = NodeAppModel() + let bridgeController = BridgeConnectionController(appModel: appModel, startDiscovery: false) + + let root = SettingsTab() + .environmentObject(appModel) + .environmentObject(appModel.voiceWake) + .environmentObject(bridgeController) + + _ = Self.host(root) + } + + @Test @MainActor func rootTabsBuildAViewHierarchy() { + let appModel = NodeAppModel() + let bridgeController = BridgeConnectionController(appModel: appModel, startDiscovery: false) + + let root = RootTabs() + .environmentObject(appModel) + .environmentObject(appModel.voiceWake) + .environmentObject(bridgeController) + + _ = Self.host(root) + } + + @Test @MainActor func voiceTabBuildsAViewHierarchy() { + let appModel = NodeAppModel() + + let root = VoiceTab() + .environmentObject(appModel) + .environmentObject(appModel.voiceWake) + + _ = Self.host(root) + } + + @Test @MainActor func voiceWakeWordsViewBuildsAViewHierarchy() { + let root = NavigationStack { VoiceWakeWordsSettingsView() } + _ = Self.host(root) + } +}