From 5ace7c9c665dcac387ea60457dcd4feff225b2b3 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Sun, 14 Dec 2025 02:54:30 +0000 Subject: [PATCH] test(macos): add settings view smoke coverage --- .../ClawdisIPCTests/CronModelsTests.swift | 85 ++++++++++++++++ .../SettingsViewSmokeTests.swift | 98 +++++++++++++++++++ 2 files changed, 183 insertions(+) create mode 100644 apps/macos/Tests/ClawdisIPCTests/CronModelsTests.swift create mode 100644 apps/macos/Tests/ClawdisIPCTests/SettingsViewSmokeTests.swift diff --git a/apps/macos/Tests/ClawdisIPCTests/CronModelsTests.swift b/apps/macos/Tests/ClawdisIPCTests/CronModelsTests.swift new file mode 100644 index 000000000..dd1925545 --- /dev/null +++ b/apps/macos/Tests/ClawdisIPCTests/CronModelsTests.swift @@ -0,0 +1,85 @@ +import Foundation +import Testing +@testable import Clawdis + +@Suite +struct CronModelsTests { + @Test func scheduleAtEncodesAndDecodes() throws { + let schedule = CronSchedule.at(atMs: 123) + let data = try JSONEncoder().encode(schedule) + let decoded = try JSONDecoder().decode(CronSchedule.self, from: data) + #expect(decoded == schedule) + } + + @Test func scheduleEveryEncodesAndDecodesWithAnchor() throws { + let schedule = CronSchedule.every(everyMs: 5_000, anchorMs: 10_000) + let data = try JSONEncoder().encode(schedule) + let decoded = try JSONDecoder().decode(CronSchedule.self, from: data) + #expect(decoded == schedule) + } + + @Test func scheduleCronEncodesAndDecodesWithTimezone() throws { + let schedule = CronSchedule.cron(expr: "*/5 * * * *", tz: "Europe/Vienna") + let data = try JSONEncoder().encode(schedule) + let decoded = try JSONDecoder().decode(CronSchedule.self, from: data) + #expect(decoded == schedule) + } + + @Test func payloadAgentTurnEncodesAndDecodes() throws { + let payload = CronPayload.agentTurn( + message: "hello", + thinking: "low", + timeoutSeconds: 15, + deliver: true, + channel: "whatsapp", + to: "+15551234567", + bestEffortDeliver: false) + let data = try JSONEncoder().encode(payload) + let decoded = try JSONDecoder().decode(CronPayload.self, from: data) + #expect(decoded == payload) + } + + @Test func displayNameTrimsWhitespaceAndFallsBack() { + let base = CronJob( + id: "x", + name: " hello ", + enabled: true, + createdAtMs: 0, + updatedAtMs: 0, + schedule: .at(atMs: 0), + sessionTarget: .main, + wakeMode: .now, + payload: .systemEvent(text: "hi"), + isolation: nil, + state: CronJobState()) + #expect(base.displayName == "hello") + + var unnamed = base + unnamed.name = " " + #expect(unnamed.displayName == "Untitled job") + } + + @Test func nextRunDateAndLastRunDateDeriveFromState() { + let job = CronJob( + id: "x", + name: "t", + enabled: true, + createdAtMs: 0, + updatedAtMs: 0, + schedule: .at(atMs: 0), + sessionTarget: .main, + wakeMode: .now, + payload: .systemEvent(text: "hi"), + isolation: nil, + state: CronJobState( + nextRunAtMs: 1_700_000_000_000, + runningAtMs: nil, + lastRunAtMs: 1_700_000_050_000, + lastStatus: nil, + lastError: nil, + lastDurationMs: nil)) + #expect(job.nextRunDate == Date(timeIntervalSince1970: 1_700_000_000)) + #expect(job.lastRunDate == Date(timeIntervalSince1970: 1_700_000_050)) + } +} + diff --git a/apps/macos/Tests/ClawdisIPCTests/SettingsViewSmokeTests.swift b/apps/macos/Tests/ClawdisIPCTests/SettingsViewSmokeTests.swift new file mode 100644 index 000000000..eaf12aa23 --- /dev/null +++ b/apps/macos/Tests/ClawdisIPCTests/SettingsViewSmokeTests.swift @@ -0,0 +1,98 @@ +import SwiftUI +import Testing +@testable import Clawdis + +@Suite(.serialized) +@MainActor +struct SettingsViewSmokeTests { + @Test func cronSettingsBuildsBody() { + let store = CronJobsStore(isPreview: true) + store.schedulerEnabled = false + store.schedulerStorePath = "/tmp/clawdis-cron-store.json" + + let job1 = CronJob( + id: "job-1", + name: " Morning Check-in ", + enabled: true, + createdAtMs: 1_700_000_000_000, + updatedAtMs: 1_700_000_100_000, + schedule: .cron(expr: "0 8 * * *", tz: "UTC"), + sessionTarget: .main, + wakeMode: .now, + payload: .systemEvent(text: "ping"), + isolation: nil, + state: CronJobState( + nextRunAtMs: 1_700_000_200_000, + runningAtMs: nil, + lastRunAtMs: 1_700_000_050_000, + lastStatus: "ok", + lastError: nil, + lastDurationMs: 123)) + + let job2 = CronJob( + id: "job-2", + name: nil, + enabled: false, + createdAtMs: 1_700_000_000_000, + updatedAtMs: 1_700_000_100_000, + schedule: .every(everyMs: 30_000, anchorMs: nil), + sessionTarget: .isolated, + wakeMode: .nextHeartbeat, + payload: .agentTurn( + message: "hello", + thinking: "low", + timeoutSeconds: 30, + deliver: true, + channel: "sms", + to: "+15551234567", + bestEffortDeliver: true), + isolation: CronIsolation(postToMainPrefix: "[cron] "), + state: CronJobState( + nextRunAtMs: nil, + runningAtMs: nil, + lastRunAtMs: nil, + lastStatus: nil, + lastError: nil, + lastDurationMs: nil)) + + store.jobs = [job1, job2] + store.selectedJobId = job1.id + store.runEntries = [ + CronRunLogEntry( + ts: 1_700_000_050_000, + jobId: job1.id, + action: "finished", + status: "ok", + error: nil, + summary: "ok", + runAtMs: 1_700_000_050_000, + durationMs: 123, + nextRunAtMs: 1_700_000_200_000), + ] + + let view = CronSettings(store: store) + _ = view.body + } + + @Test func configSettingsBuildsBody() { + let view = ConfigSettings() + _ = view.body + } + + @Test func debugSettingsBuildsBody() { + let view = DebugSettings() + _ = view.body + } + + @Test func voiceWakeSettingsBuildsBody() { + let state = AppState(preview: true) + let view = VoiceWakeSettings(state: state) + _ = view.body + } + + @Test func toolsSettingsBuildsBody() { + let view = ToolsSettings() + _ = view.body + } +} +