test: expand settings coverage
This commit is contained in:
@@ -0,0 +1,29 @@
|
||||
import Testing
|
||||
@testable import Clawdis
|
||||
|
||||
@Suite(.serialized)
|
||||
@MainActor
|
||||
struct AnthropicAuthControlsSmokeTests {
|
||||
@Test func anthropicAuthControlsBuildsBodyLocal() {
|
||||
let pkce = AnthropicOAuth.PKCE(verifier: "verifier", challenge: "challenge")
|
||||
let view = AnthropicAuthControls(
|
||||
connectionMode: .local,
|
||||
oauthStatus: .connected(expiresAtMs: 1_700_000_000_000),
|
||||
pkce: pkce,
|
||||
code: "code#state",
|
||||
statusText: "Detected code",
|
||||
autoDetectClipboard: false,
|
||||
autoConnectClipboard: false)
|
||||
_ = view.body
|
||||
}
|
||||
|
||||
@Test func anthropicAuthControlsBuildsBodyRemote() {
|
||||
let view = AnthropicAuthControls(
|
||||
connectionMode: .remote,
|
||||
oauthStatus: .missingFile,
|
||||
pkce: nil,
|
||||
code: "",
|
||||
statusText: nil)
|
||||
_ = view.body
|
||||
}
|
||||
}
|
||||
@@ -6,21 +6,9 @@ import Testing
|
||||
struct AnthropicAuthResolverTests {
|
||||
@Test
|
||||
func prefersOAuthFileOverEnv() throws {
|
||||
let key = "CLAWDIS_OAUTH_DIR"
|
||||
let previous = ProcessInfo.processInfo.environment[key]
|
||||
defer {
|
||||
if let previous {
|
||||
setenv(key, previous, 1)
|
||||
} else {
|
||||
unsetenv(key)
|
||||
}
|
||||
}
|
||||
|
||||
let dir = FileManager.default.temporaryDirectory
|
||||
.appendingPathComponent("clawdis-oauth-\(UUID().uuidString)", isDirectory: true)
|
||||
try FileManager.default.createDirectory(at: dir, withIntermediateDirectories: true)
|
||||
setenv(key, dir.path, 1)
|
||||
|
||||
let oauthFile = dir.appendingPathComponent("oauth.json")
|
||||
let payload = [
|
||||
"anthropic": [
|
||||
@@ -33,9 +21,10 @@ struct AnthropicAuthResolverTests {
|
||||
let data = try JSONSerialization.data(withJSONObject: payload, options: [.prettyPrinted, .sortedKeys])
|
||||
try data.write(to: oauthFile, options: [.atomic])
|
||||
|
||||
let status = ClawdisOAuthStore.anthropicOAuthStatus(at: oauthFile)
|
||||
let mode = AnthropicAuthResolver.resolve(environment: [
|
||||
"ANTHROPIC_API_KEY": "sk-ant-ignored",
|
||||
])
|
||||
], oauthStatus: status)
|
||||
#expect(mode == .oauthFile)
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
import SwiftUI
|
||||
import Testing
|
||||
@testable import Clawdis
|
||||
|
||||
@Suite(.serialized)
|
||||
@MainActor
|
||||
struct ConnectionsSettingsSmokeTests {
|
||||
@Test func connectionsSettingsBuildsBodyWithSnapshot() {
|
||||
let store = ConnectionsStore(isPreview: true)
|
||||
store.snapshot = ProvidersStatusSnapshot(
|
||||
ts: 1_700_000_000_000,
|
||||
whatsapp: ProvidersStatusSnapshot.WhatsAppStatus(
|
||||
configured: true,
|
||||
linked: true,
|
||||
authAgeMs: 86_400_000,
|
||||
self: ProvidersStatusSnapshot.WhatsAppSelf(
|
||||
e164: "+15551234567",
|
||||
jid: nil),
|
||||
running: true,
|
||||
connected: false,
|
||||
lastConnectedAt: 1_700_000_000_000,
|
||||
lastDisconnect: ProvidersStatusSnapshot.WhatsAppDisconnect(
|
||||
at: 1_700_000_050_000,
|
||||
status: 401,
|
||||
error: "logged out",
|
||||
loggedOut: true),
|
||||
reconnectAttempts: 2,
|
||||
lastMessageAt: 1_700_000_060_000,
|
||||
lastEventAt: 1_700_000_060_000,
|
||||
lastError: "needs login"),
|
||||
telegram: ProvidersStatusSnapshot.TelegramStatus(
|
||||
configured: true,
|
||||
tokenSource: "env",
|
||||
running: true,
|
||||
mode: "polling",
|
||||
lastStartAt: 1_700_000_000_000,
|
||||
lastStopAt: nil,
|
||||
lastError: nil,
|
||||
probe: ProvidersStatusSnapshot.TelegramProbe(
|
||||
ok: true,
|
||||
status: 200,
|
||||
error: nil,
|
||||
elapsedMs: 120,
|
||||
bot: ProvidersStatusSnapshot.TelegramBot(id: 123, username: "clawdisbot"),
|
||||
webhook: ProvidersStatusSnapshot.TelegramWebhook(url: "https://example.com/hook", hasCustomCert: false)),
|
||||
lastProbeAt: 1_700_000_050_000))
|
||||
|
||||
store.whatsappLoginMessage = "Scan QR"
|
||||
store.whatsappLoginQrDataUrl =
|
||||
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mP8/x8AAwMB/ay7pS8AAAAASUVORK5CYII="
|
||||
store.telegramToken = "123:abc"
|
||||
store.telegramRequireMention = false
|
||||
store.telegramAllowFrom = "123456789"
|
||||
store.telegramProxy = "socks5://localhost:9050"
|
||||
store.telegramWebhookUrl = "https://example.com/telegram"
|
||||
store.telegramWebhookSecret = "secret"
|
||||
store.telegramWebhookPath = "/telegram"
|
||||
|
||||
let view = ConnectionsSettings(store: store)
|
||||
_ = view.body
|
||||
}
|
||||
|
||||
@Test func connectionsSettingsBuildsBodyWithoutSnapshot() {
|
||||
let store = ConnectionsStore(isPreview: true)
|
||||
store.snapshot = ProvidersStatusSnapshot(
|
||||
ts: 1_700_000_000_000,
|
||||
whatsapp: ProvidersStatusSnapshot.WhatsAppStatus(
|
||||
configured: false,
|
||||
linked: false,
|
||||
authAgeMs: nil,
|
||||
self: nil,
|
||||
running: false,
|
||||
connected: false,
|
||||
lastConnectedAt: nil,
|
||||
lastDisconnect: nil,
|
||||
reconnectAttempts: 0,
|
||||
lastMessageAt: nil,
|
||||
lastEventAt: nil,
|
||||
lastError: nil),
|
||||
telegram: ProvidersStatusSnapshot.TelegramStatus(
|
||||
configured: false,
|
||||
tokenSource: nil,
|
||||
running: false,
|
||||
mode: nil,
|
||||
lastStartAt: nil,
|
||||
lastStopAt: nil,
|
||||
lastError: "bot missing",
|
||||
probe: ProvidersStatusSnapshot.TelegramProbe(
|
||||
ok: false,
|
||||
status: 403,
|
||||
error: "unauthorized",
|
||||
elapsedMs: 120,
|
||||
bot: nil,
|
||||
webhook: nil),
|
||||
lastProbeAt: 1_700_000_100_000))
|
||||
|
||||
let view = ConnectionsSettings(store: store)
|
||||
_ = view.body
|
||||
}
|
||||
}
|
||||
@@ -55,5 +55,14 @@ struct CronJobEditorSmokeTests {
|
||||
onSave: { _ in })
|
||||
_ = view.body
|
||||
}
|
||||
}
|
||||
|
||||
@Test func cronJobEditorExercisesBuilders() {
|
||||
var view = CronJobEditor(
|
||||
job: nil,
|
||||
isSaving: .constant(false),
|
||||
error: .constant(nil),
|
||||
onCancel: {},
|
||||
onSave: { _ in })
|
||||
view.exerciseForTesting()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
import Testing
|
||||
@testable import Clawdis
|
||||
|
||||
@Suite(.serialized)
|
||||
@MainActor
|
||||
struct InstancesSettingsSmokeTests {
|
||||
@Test func instancesSettingsBuildsBodyWithMultipleInstances() {
|
||||
let store = InstancesStore(isPreview: true)
|
||||
store.statusMessage = "Loaded"
|
||||
store.instances = [
|
||||
InstanceInfo(
|
||||
id: "macbook",
|
||||
host: "macbook-pro",
|
||||
ip: "10.0.0.2",
|
||||
version: "1.2.3",
|
||||
platform: "macOS 15.1",
|
||||
deviceFamily: "Mac",
|
||||
modelIdentifier: "MacBookPro18,1",
|
||||
lastInputSeconds: 15,
|
||||
mode: "local",
|
||||
reason: "heartbeat",
|
||||
text: "MacBook Pro local",
|
||||
ts: 1_700_000_000_000),
|
||||
InstanceInfo(
|
||||
id: "android",
|
||||
host: "pixel",
|
||||
ip: "10.0.0.3",
|
||||
version: "2.0.0",
|
||||
platform: "Android 14",
|
||||
deviceFamily: "Android",
|
||||
modelIdentifier: nil,
|
||||
lastInputSeconds: 120,
|
||||
mode: "node",
|
||||
reason: "presence",
|
||||
text: "Android node",
|
||||
ts: 1_700_000_100_000),
|
||||
InstanceInfo(
|
||||
id: "gateway",
|
||||
host: "gateway",
|
||||
ip: "10.0.0.4",
|
||||
version: "3.0.0",
|
||||
platform: "iOS 17",
|
||||
deviceFamily: nil,
|
||||
modelIdentifier: nil,
|
||||
lastInputSeconds: nil,
|
||||
mode: "gateway",
|
||||
reason: "gateway",
|
||||
text: "Gateway",
|
||||
ts: 1_700_000_200_000),
|
||||
]
|
||||
|
||||
let view = InstancesSettings(store: store)
|
||||
_ = view.body
|
||||
}
|
||||
|
||||
@Test func instancesSettingsExercisesHelpers() {
|
||||
InstancesSettings.exerciseForTesting()
|
||||
}
|
||||
}
|
||||
@@ -13,6 +13,7 @@ struct SettingsViewSmokeTests {
|
||||
let job1 = CronJob(
|
||||
id: "job-1",
|
||||
name: " Morning Check-in ",
|
||||
description: nil,
|
||||
enabled: true,
|
||||
createdAtMs: 1_700_000_000_000,
|
||||
updatedAtMs: 1_700_000_100_000,
|
||||
@@ -31,7 +32,8 @@ struct SettingsViewSmokeTests {
|
||||
|
||||
let job2 = CronJob(
|
||||
id: "job-2",
|
||||
name: nil,
|
||||
name: "",
|
||||
description: nil,
|
||||
enabled: false,
|
||||
createdAtMs: 1_700_000_000_000,
|
||||
updatedAtMs: 1_700_000_100_000,
|
||||
@@ -74,6 +76,10 @@ struct SettingsViewSmokeTests {
|
||||
_ = view.body
|
||||
}
|
||||
|
||||
@Test func cronSettingsExercisesPrivateViews() {
|
||||
CronSettings.exerciseForTesting()
|
||||
}
|
||||
|
||||
@Test func configSettingsBuildsBody() {
|
||||
let view = ConfigSettings()
|
||||
_ = view.body
|
||||
@@ -90,6 +96,10 @@ struct SettingsViewSmokeTests {
|
||||
_ = view.body
|
||||
}
|
||||
|
||||
@Test func generalSettingsExercisesBranches() {
|
||||
GeneralSettings.exerciseForTesting()
|
||||
}
|
||||
|
||||
@Test func sessionsSettingsBuildsBody() {
|
||||
let view = SessionsSettings(rows: SessionRow.previewRows, isPreview: true)
|
||||
_ = view.body
|
||||
|
||||
118
apps/macos/Tests/ClawdisIPCTests/SkillsSettingsSmokeTests.swift
Normal file
118
apps/macos/Tests/ClawdisIPCTests/SkillsSettingsSmokeTests.swift
Normal file
@@ -0,0 +1,118 @@
|
||||
import Testing
|
||||
@testable import Clawdis
|
||||
|
||||
@Suite(.serialized)
|
||||
@MainActor
|
||||
struct SkillsSettingsSmokeTests {
|
||||
@Test func skillsSettingsBuildsBodyWithSkillsRemote() {
|
||||
let model = SkillsSettingsModel()
|
||||
model.statusMessage = "Loaded"
|
||||
model.skills = [
|
||||
SkillStatus(
|
||||
name: "Needs Setup",
|
||||
description: "Missing bins and env",
|
||||
source: "clawdis-managed",
|
||||
filePath: "/tmp/skills/needs-setup",
|
||||
baseDir: "/tmp/skills",
|
||||
skillKey: "needs-setup",
|
||||
primaryEnv: "API_KEY",
|
||||
emoji: "🧰",
|
||||
homepage: "https://example.com/needs-setup",
|
||||
always: false,
|
||||
disabled: false,
|
||||
eligible: false,
|
||||
requirements: SkillRequirements(
|
||||
bins: ["python3"],
|
||||
env: ["API_KEY"],
|
||||
config: ["skills.needs-setup"]),
|
||||
missing: SkillMissing(
|
||||
bins: ["python3"],
|
||||
env: ["API_KEY"],
|
||||
config: ["skills.needs-setup"]),
|
||||
configChecks: [
|
||||
SkillStatusConfigCheck(path: "skills.needs-setup", value: AnyCodable(false), satisfied: false),
|
||||
],
|
||||
install: [
|
||||
SkillInstallOption(id: "brew", kind: "brew", label: "brew install python", bins: ["python3"]),
|
||||
]),
|
||||
SkillStatus(
|
||||
name: "Ready Skill",
|
||||
description: "All set",
|
||||
source: "clawdis-bundled",
|
||||
filePath: "/tmp/skills/ready",
|
||||
baseDir: "/tmp/skills",
|
||||
skillKey: "ready",
|
||||
primaryEnv: nil,
|
||||
emoji: "✅",
|
||||
homepage: "https://example.com/ready",
|
||||
always: false,
|
||||
disabled: false,
|
||||
eligible: true,
|
||||
requirements: SkillRequirements(bins: [], env: [], config: []),
|
||||
missing: SkillMissing(bins: [], env: [], config: []),
|
||||
configChecks: [
|
||||
SkillStatusConfigCheck(path: "skills.ready", value: AnyCodable(true), satisfied: true),
|
||||
SkillStatusConfigCheck(path: "skills.limit", value: AnyCodable(5), satisfied: true),
|
||||
],
|
||||
install: []),
|
||||
SkillStatus(
|
||||
name: "Disabled Skill",
|
||||
description: "Disabled in config",
|
||||
source: "clawdis-extra",
|
||||
filePath: "/tmp/skills/disabled",
|
||||
baseDir: "/tmp/skills",
|
||||
skillKey: "disabled",
|
||||
primaryEnv: nil,
|
||||
emoji: "🚫",
|
||||
homepage: nil,
|
||||
always: false,
|
||||
disabled: true,
|
||||
eligible: false,
|
||||
requirements: SkillRequirements(bins: [], env: [], config: []),
|
||||
missing: SkillMissing(bins: [], env: [], config: []),
|
||||
configChecks: [],
|
||||
install: []),
|
||||
]
|
||||
|
||||
let state = AppState(preview: true)
|
||||
state.connectionMode = .remote
|
||||
var view = SkillsSettings(state: state, model: model)
|
||||
view.setFilterForTesting("all")
|
||||
_ = view.body
|
||||
view.setFilterForTesting("needsSetup")
|
||||
_ = view.body
|
||||
}
|
||||
|
||||
@Test func skillsSettingsBuildsBodyWithLocalMode() {
|
||||
let model = SkillsSettingsModel()
|
||||
model.skills = [
|
||||
SkillStatus(
|
||||
name: "Local Skill",
|
||||
description: "Local ready",
|
||||
source: "clawdis-workspace",
|
||||
filePath: "/tmp/skills/local",
|
||||
baseDir: "/tmp/skills",
|
||||
skillKey: "local",
|
||||
primaryEnv: nil,
|
||||
emoji: "🏠",
|
||||
homepage: nil,
|
||||
always: false,
|
||||
disabled: false,
|
||||
eligible: true,
|
||||
requirements: SkillRequirements(bins: [], env: [], config: []),
|
||||
missing: SkillMissing(bins: [], env: [], config: []),
|
||||
configChecks: [],
|
||||
install: []),
|
||||
]
|
||||
|
||||
let state = AppState(preview: true)
|
||||
state.connectionMode = .local
|
||||
var view = SkillsSettings(state: state, model: model)
|
||||
view.setFilterForTesting("ready")
|
||||
_ = view.body
|
||||
}
|
||||
|
||||
@Test func skillsSettingsExercisesPrivateViews() {
|
||||
SkillsSettings.exerciseForTesting()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
import SwiftUI
|
||||
import Testing
|
||||
@testable import Clawdis
|
||||
|
||||
@Suite(.serialized)
|
||||
@MainActor
|
||||
struct TailscaleIntegrationSectionTests {
|
||||
@Test func tailscaleSectionBuildsBodyWhenNotInstalled() {
|
||||
let service = TailscaleService(isInstalled: false, isRunning: false, statusError: "not installed")
|
||||
var view = TailscaleIntegrationSection(connectionMode: .local, isPaused: false)
|
||||
view.setTestingService(service)
|
||||
view.setTestingState(mode: "off", requireCredentials: false, statusMessage: "Idle")
|
||||
_ = view.body
|
||||
}
|
||||
|
||||
@Test func tailscaleSectionBuildsBodyForServeMode() {
|
||||
let service = TailscaleService(
|
||||
isInstalled: true,
|
||||
isRunning: true,
|
||||
tailscaleHostname: "clawdis.tailnet.ts.net",
|
||||
tailscaleIP: "100.64.0.1")
|
||||
var view = TailscaleIntegrationSection(connectionMode: .local, isPaused: false)
|
||||
view.setTestingService(service)
|
||||
view.setTestingState(
|
||||
mode: "serve",
|
||||
requireCredentials: true,
|
||||
password: "secret",
|
||||
statusMessage: "Running")
|
||||
_ = view.body
|
||||
}
|
||||
|
||||
@Test func tailscaleSectionBuildsBodyForFunnelMode() {
|
||||
let service = TailscaleService(
|
||||
isInstalled: true,
|
||||
isRunning: false,
|
||||
tailscaleHostname: nil,
|
||||
tailscaleIP: nil,
|
||||
statusError: "not running")
|
||||
var view = TailscaleIntegrationSection(connectionMode: .remote, isPaused: false)
|
||||
view.setTestingService(service)
|
||||
view.setTestingState(
|
||||
mode: "funnel",
|
||||
requireCredentials: false,
|
||||
statusMessage: "Needs start",
|
||||
validationMessage: "Invalid token")
|
||||
_ = view.body
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user