From b3be165a938060247e63082ba1f819b280ce7140 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 5 Nov 2026 00:12:19 +0000 Subject: [PATCH 1/2] Test: snapshot del widget (oggi, arretrati, Inbox) (#19) Co-Authored-By: Claude Sonnet 5.5 Claude-Session: https://claude.ai/code/session_01AVhvvLN9VgMHL95Pau4vAE --- CalenTask/Support/WidgetBridge.swift | 9 +++--- CalenTaskTests/WidgetSnapshotTests.swift | 41 ++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 4 deletions(-) create mode 100644 CalenTaskTests/WidgetSnapshotTests.swift diff --git a/CalenTask/Support/WidgetBridge.swift b/CalenTask/Support/WidgetBridge.swift index 80de1b1..3985ca7 100644 --- a/CalenTask/Support/WidgetBridge.swift +++ b/CalenTask/Support/WidgetBridge.swift @@ -62,7 +62,7 @@ enum WidgetBridge { static func refresh(in context: ModelContext) { guard let url = snapshotURL else { return } do { - let snapshot = try makeSnapshot(in: context) + let snapshot = try makeSnapshot(in: context, now: .now) let encoder = JSONEncoder() encoder.dateEncodingStrategy = .iso8601 try encoder.encode(snapshot).write(to: url, options: .atomic) @@ -73,9 +73,10 @@ enum WidgetBridge { } } - private static func makeSnapshot(in context: ModelContext) throws -> WidgetSnapshot { + /// Internal (non private) per i test (#19): `now` è iniettabile. + static func makeSnapshot(in context: ModelContext, now: Date) throws -> WidgetSnapshot { let calendar = Calendar.app - let today = Date.now.startOfDay + let today = now.startOfDay let open = try context.fetch(FetchDescriptor(predicate: TodoTask.openPredicate)) let inbox = try context.fetchCount(FetchDescriptor(predicate: TodoTask.inboxPredicate)) @@ -104,7 +105,7 @@ enum WidgetBridge { } return WidgetSnapshot( - generatedAt: .now, + generatedAt: now, dayLabel: today.formatted(.dateTime.weekday(.wide).day().month(.wide)), items: Array(items), overdueCount: overdue.count, diff --git a/CalenTaskTests/WidgetSnapshotTests.swift b/CalenTaskTests/WidgetSnapshotTests.swift new file mode 100644 index 0000000..d22ec6c --- /dev/null +++ b/CalenTaskTests/WidgetSnapshotTests.swift @@ -0,0 +1,41 @@ +import Foundation +import SwiftData +import Testing +@testable import CalenTask + +/// #19 — snapshot del widget: cosa finisce in "oggi", arretrati e Inbox. +@MainActor +struct WidgetSnapshotTests { + + private func makeContext() throws -> ModelContext { + let schema = Schema([ + Workspace.self, Membership.self, UserProfile.self, + Project.self, TodoTask.self, TaskDependency.self, Tag.self, + CustomFieldDefinition.self, CustomFieldValue.self, SavedView.self, WorkflowStage.self, AutomationRule.self, Attachment.self, + Contact.self, CrewAssignment.self, ProductionScene.self, + ]) + let config = ModelConfiguration(schema: schema, isStoredInMemoryOnly: true) + return try ModelContainer(for: schema, configurations: [config]).mainContext + } + + @Test func snapshotCountsTodayOverdueAndInbox() throws { + let context = try makeContext() + let ws = UUID(), me = UUID() + let now = try #require(Calendar.app.date( + bySettingHour: 10, minute: 0, second: 0, of: Date(timeIntervalSince1970: 1_790_000_000) + )) + let today = now.startOfDay + + let todayTask = TodoTask(workspaceID: ws, title: "Oggi", dueAt: today.addingTimeInterval(14 * 3600), createdByID: me) + let overdue = TodoTask(workspaceID: ws, title: "Arretrato", dueAt: today.addingTimeInterval(-86_400), createdByID: me) + let deleted = TodoTask(workspaceID: ws, title: "Eliminata", dueAt: today.addingTimeInterval(14 * 3600), createdByID: me) + deleted.deletedAt = now + for task in [todayTask, overdue, deleted] { context.insert(task) } + + let snapshot = try WidgetBridge.makeSnapshot(in: context, now: now) + #expect(snapshot.generatedAt == now) + #expect(snapshot.items.map(\.title) == ["Oggi"]) + #expect(snapshot.overdueCount == 1) + #expect(snapshot.inboxCount == 2) + } +} From ee9f95e9db0021dc0c5e61184f1d45539d81d1aa Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 5 Nov 2026 00:16:46 +0000 Subject: [PATCH 2/2] Test: il container del widget resta vivo durante il test (#19) Co-Authored-By: Claude Sonnet 5.5 Claude-Session: https://claude.ai/code/session_01AVhvvLN9VgMHL95Pau4vAE --- CalenTaskTests/WidgetSnapshotTests.swift | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/CalenTaskTests/WidgetSnapshotTests.swift b/CalenTaskTests/WidgetSnapshotTests.swift index d22ec6c..16bb422 100644 --- a/CalenTaskTests/WidgetSnapshotTests.swift +++ b/CalenTaskTests/WidgetSnapshotTests.swift @@ -7,7 +7,7 @@ import Testing @MainActor struct WidgetSnapshotTests { - private func makeContext() throws -> ModelContext { + private func makeContainer() throws -> ModelContainer { let schema = Schema([ Workspace.self, Membership.self, UserProfile.self, Project.self, TodoTask.self, TaskDependency.self, Tag.self, @@ -15,11 +15,12 @@ struct WidgetSnapshotTests { Contact.self, CrewAssignment.self, ProductionScene.self, ]) let config = ModelConfiguration(schema: schema, isStoredInMemoryOnly: true) - return try ModelContainer(for: schema, configurations: [config]).mainContext + return try ModelContainer(for: schema, configurations: [config]) } @Test func snapshotCountsTodayOverdueAndInbox() throws { - let context = try makeContext() + let container = try makeContainer() // va tenuto vivo: il contesto non lo trattiene + let context = container.mainContext let ws = UUID(), me = UUID() let now = try #require(Calendar.app.date( bySettingHour: 10, minute: 0, second: 0, of: Date(timeIntervalSince1970: 1_790_000_000) @@ -37,5 +38,6 @@ struct WidgetSnapshotTests { #expect(snapshot.items.map(\.title) == ["Oggi"]) #expect(snapshot.overdueCount == 1) #expect(snapshot.inboxCount == 2) + withExtendedLifetime(container) {} } }