From e862ac11bc617e663e58c2a64e375a87784dacc1 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Thu, 12 Nov 2026 09:50:51 +0000 Subject: [PATCH 1/4] fix(ci): fail swift-packages when XCTest reports failures Parse swift test output for XCTest and Swift Testing failure summaries even when the CLI exits 0. Stabilize CompassData all-day and initial week anchor tests under SPM by pinning Denver through ViewStore or prefs. Co-authored-by: Tyler Dane --- .../swift-test-xctest-failure-sample.txt | 8 ++++ .../scripts/selftest-swift-packages-exit.sh | 35 ++++++++++++++++++ .github/scripts/test-macos-swift-packages.sh | 37 ++++++++++++++++++- .../NativeCalendarRootModelAllDayTests.swift | 2 +- ...endarRootModelInitialWeekAnchorTests.swift | 12 ++++-- 5 files changed, 89 insertions(+), 5 deletions(-) create mode 100644 .github/scripts/fixtures/swift-test-xctest-failure-sample.txt create mode 100644 .github/scripts/selftest-swift-packages-exit.sh diff --git a/.github/scripts/fixtures/swift-test-xctest-failure-sample.txt b/.github/scripts/fixtures/swift-test-xctest-failure-sample.txt new file mode 100644 index 0000000000..f4733c0dad --- /dev/null +++ b/.github/scripts/fixtures/swift-test-xctest-failure-sample.txt @@ -0,0 +1,8 @@ +Test Case '-[CompassDataTests.ExampleTests testBroken]' failed (0.001 seconds). +Test Suite 'ExampleTests' failed at 2026-11-12 09:00:29.633. +Test Suite 'CompassDataPackageTests.xctest' failed at 2026-11-12 09:00:29.633. +Test Suite 'All tests' failed at 2026-11-12 09:00:29.633. + Executed 374 tests, with 6 failures (0 unexpected) in 55.831 (57.313) seconds +◇ Test run started. +↳ Testing Library Version: 0.1.0 +✔ Test run with 0 tests in 0 suites passed after 0.001 seconds. diff --git a/.github/scripts/selftest-swift-packages-exit.sh b/.github/scripts/selftest-swift-packages-exit.sh new file mode 100644 index 0000000000..b0fa2e9b0c --- /dev/null +++ b/.github/scripts/selftest-swift-packages-exit.sh @@ -0,0 +1,35 @@ +#!/usr/bin/env bash +# Verify swift-packages log parsing catches XCTest failures even when swift exits 0. +set -euo pipefail + +ROOT=$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd) + +swift_package_log_has_test_failures() { + local log="$1" + if grep -qE 'Executed [0-9]+ tests?, with [1-9][0-9]* failures' "$log"; then + return 0 + fi + if grep -qE "Test Suite 'All tests' failed" "$log"; then + return 0 + fi + return 1 +} + +fixture="${ROOT}/.github/scripts/fixtures/swift-test-xctest-failure-sample.txt" +if ! swift_package_log_has_test_failures "$fixture"; then + echo "selftest: expected fixture log to count as failures" >&2 + exit 1 +fi + +pass_log=$(mktemp) +trap 'rm -f "$pass_log"' EXIT +cat >"$pass_log" <<'EOF' +Test Suite 'All tests' passed at 2026-01-01 00:00:00.000. + Executed 12 tests, with 0 failures (0 unexpected) in 0.010 (0.012) seconds +EOF +if swift_package_log_has_test_failures "$pass_log"; then + echo "selftest: pass log must not count as failures" >&2 + exit 1 +fi + +echo "selftest-swift-packages-exit: ok" diff --git a/.github/scripts/test-macos-swift-packages.sh b/.github/scripts/test-macos-swift-packages.sh index 36f451704f..a2d79ea1bb 100755 --- a/.github/scripts/test-macos-swift-packages.sh +++ b/.github/scripts/test-macos-swift-packages.sh @@ -33,6 +33,25 @@ if [ "${MACOS_SWIFT_PACKAGES_SKIP_BUILD:-0}" = "1" ]; then echo "swift-packages: skip build (using warmed .build artifacts)" fi +# `swift test` can exit 0 when XCTest suites fail and Swift Testing runs afterward +# with zero tests. Scan the full log for XCTest and Swift Testing failure markers. +swift_package_log_has_test_failures() { + local log="$1" + if grep -qE 'Executed [0-9]+ tests?, with [1-9][0-9]* failures' "$log"; then + return 0 + fi + if grep -qE "Test Suite 'All tests' failed" "$log"; then + return 0 + fi + if grep -qE 'Test run with [1-9][0-9]* failures' "$log"; then + return 0 + fi + if grep -qE 'with [1-9][0-9]* issues' "$log"; then + return 0 + fi + return 1 +} + run_package_tests() { local name="$1" local dir="apps/calendar-macos/${name}" @@ -47,8 +66,24 @@ run_package_tests() { echo "── swift ${args[*]} ──" local start start=$(date +%s) - swift "${args[@]}" + local log + log=$(mktemp) + local swift_ec=0 + set +e + swift "${args[@]}" 2>&1 | tee "$log" + swift_ec=${PIPESTATUS[0]} + set -e + local parsed_fail=0 + if swift_package_log_has_test_failures "$log"; then + echo "swift-packages: ${name} reported test failures in log (swift exit ${swift_ec})" >&2 + parsed_fail=1 + fi + rm -f "$log" echo "── ${name} tests finished in $(( $(date +%s) - start ))s ──" + if [ "$swift_ec" -ne 0 ] || [ "$parsed_fail" -ne 0 ]; then + return 1 + fi + return 0 } job_start=$(date +%s) diff --git a/apps/calendar-macos/CompassData/Tests/CompassDataTests/NativeCalendarRootModelAllDayTests.swift b/apps/calendar-macos/CompassData/Tests/CompassDataTests/NativeCalendarRootModelAllDayTests.swift index 9520ef74cd..c38b1d8947 100644 --- a/apps/calendar-macos/CompassData/Tests/CompassDataTests/NativeCalendarRootModelAllDayTests.swift +++ b/apps/calendar-macos/CompassData/Tests/CompassDataTests/NativeCalendarRootModelAllDayTests.swift @@ -38,7 +38,7 @@ final class NativeCalendarRootModelAllDayTests: XCTestCase { private func model(startDay: Int, endDay: Int) throws -> NativeCalendarRootModel { let model = NativeCalendarRootModel(environment: try NativeCalendarEnvironment(inMemoryDatabase: true)) - EffectiveTimeZone.identifier = "America/Denver" + model.viewStore.setCalendarTimeZoneHint("America/Denver") model.draftStore.startGridDraft(activity: .keyboardPlace, draft: GridEventDraft( clientId: .init(rawValue: "all-day"), schedule: .init(start: date(startDay), end: date(endDay), kind: .allDay), calendarId: .init(rawValue: "cal-1"))) diff --git a/apps/calendar-macos/CompassData/Tests/CompassDataTests/NativeCalendarRootModelInitialWeekAnchorTests.swift b/apps/calendar-macos/CompassData/Tests/CompassDataTests/NativeCalendarRootModelInitialWeekAnchorTests.swift index f295dbc0a7..ba6d254a68 100644 --- a/apps/calendar-macos/CompassData/Tests/CompassDataTests/NativeCalendarRootModelInitialWeekAnchorTests.swift +++ b/apps/calendar-macos/CompassData/Tests/CompassDataTests/NativeCalendarRootModelInitialWeekAnchorTests.swift @@ -5,9 +5,15 @@ import XCTest @MainActor final class NativeCalendarRootModelInitialWeekAnchorTests: XCTestCase { func testInitialWeekAnchorUsesDeviceZoneBeforeViewStore() throws { - let priorDefault = NSTimeZone.default - defer { NSTimeZone.default = priorDefault } - NSTimeZone.default = try XCTUnwrap(TimeZone(identifier: "America/Denver")) + let priorPinned = CompassDevicePreferences.readPinnedTimeZone() + defer { + if let priorPinned { + _ = CompassDevicePreferences.writePinnedTimeZone(priorPinned) + } else { + _ = CompassDevicePreferences.writePinnedTimeZone(nil) + } + } + XCTAssertTrue(CompassDevicePreferences.writePinnedTimeZone("America/Denver")) let referenceNow = try XCTUnwrap( CompassDateParsing.parseGridDateTime( From fff6469749459f5f234da0d2ce78f4400ce76867 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Thu, 12 Nov 2026 09:50:55 +0000 Subject: [PATCH 2/4] ci: run swift-packages exit selftest before SPM tests Co-authored-by: Tyler Dane --- .github/scripts/test-macos-swift-packages.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/scripts/test-macos-swift-packages.sh b/.github/scripts/test-macos-swift-packages.sh index a2d79ea1bb..d36be35423 100755 --- a/.github/scripts/test-macos-swift-packages.sh +++ b/.github/scripts/test-macos-swift-packages.sh @@ -7,6 +7,8 @@ export NSUnbufferedIO=YES ROOT=$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd) cd "$ROOT" +bash "${ROOT}/.github/scripts/selftest-swift-packages-exit.sh" + # CompassKitTests in `swift test --package-path CompassKit` mirror the # `apps/calendar-macos/CompassKitTests/` tree (diff -rq reports no differences). # macos-build already runs those cases via xcodebuild -only-testing:CompassKitTests From 5ff47fe9aa8f343c161e54f342cc13b1a1a011ce Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Thu, 12 Nov 2026 10:29:08 +0000 Subject: [PATCH 3/4] fix(macos): harden swift-packages gate and timezone test seams Share log detection with selftest using a run 43186705883 fixture, add CompassDeviceTimeZone for device-zone tests, seed Denver primary in AllDay tests, and split initial week anchor device vs pin coverage. Co-authored-by: Tyler Dane --- ...test-xctest-failure-43186705883-sample.txt | 11 +++++ .../swift-test-xctest-failure-sample.txt | 8 ---- .../scripts/selftest-swift-packages-exit.sh | 30 +++++++----- .github/scripts/swift-packages-log-detect.sh | 23 +++++++++ .github/scripts/test-macos-swift-packages.sh | 22 ++------- .../CompassData/NativeCalendarRootModel.swift | 12 ++++- .../Preferences/CompassDeviceTimeZone.swift | 20 ++++++++ .../NativeCalendarRootModelAllDayTests.swift | 38 ++++++++++++++- ...endarRootModelInitialWeekAnchorTests.swift | 48 ++++++++++++++----- 9 files changed, 157 insertions(+), 55 deletions(-) create mode 100644 .github/scripts/fixtures/swift-test-xctest-failure-43186705883-sample.txt delete mode 100644 .github/scripts/fixtures/swift-test-xctest-failure-sample.txt create mode 100644 .github/scripts/swift-packages-log-detect.sh create mode 100644 apps/calendar-macos/CompassData/Sources/CompassData/Preferences/CompassDeviceTimeZone.swift diff --git a/.github/scripts/fixtures/swift-test-xctest-failure-43186705883-sample.txt b/.github/scripts/fixtures/swift-test-xctest-failure-43186705883-sample.txt new file mode 100644 index 0000000000..9af9f07659 --- /dev/null +++ b/.github/scripts/fixtures/swift-test-xctest-failure-43186705883-sample.txt @@ -0,0 +1,11 @@ +Test Suite 'FocusedEventShiftNudgeTests' failed at 2026-11-12 08:59:44.322. +Test Suite 'NativeCalendarRootModelAllDayTests' failed at 2026-11-12 08:59:51.205. +Test Suite 'NativeCalendarRootModelInitialWeekAnchorTests' failed at 2026-11-12 09:00:02.882. +Test Suite 'CompassDataPackageTests.xctest' failed at 2026-11-12 09:00:29.633. +Test Suite 'All tests' failed at 2026-11-12 09:00:29.633. + Executed 327 tests, with 3 tests skipped and 6 failures (0 unexpected) in 55.567 (55.666) seconds + Executed 327 tests, with 3 tests skipped and 6 failures (0 unexpected) in 55.567 (55.671) seconds +◇ Test run started. +↳ Testing Library Version: 1902 +✗ ExampleSuite.example() failed after 0.001 seconds +✔ Test run with 0 tests in 0 suites passed after 0.001 seconds. diff --git a/.github/scripts/fixtures/swift-test-xctest-failure-sample.txt b/.github/scripts/fixtures/swift-test-xctest-failure-sample.txt deleted file mode 100644 index f4733c0dad..0000000000 --- a/.github/scripts/fixtures/swift-test-xctest-failure-sample.txt +++ /dev/null @@ -1,8 +0,0 @@ -Test Case '-[CompassDataTests.ExampleTests testBroken]' failed (0.001 seconds). -Test Suite 'ExampleTests' failed at 2026-11-12 09:00:29.633. -Test Suite 'CompassDataPackageTests.xctest' failed at 2026-11-12 09:00:29.633. -Test Suite 'All tests' failed at 2026-11-12 09:00:29.633. - Executed 374 tests, with 6 failures (0 unexpected) in 55.831 (57.313) seconds -◇ Test run started. -↳ Testing Library Version: 0.1.0 -✔ Test run with 0 tests in 0 suites passed after 0.001 seconds. diff --git a/.github/scripts/selftest-swift-packages-exit.sh b/.github/scripts/selftest-swift-packages-exit.sh index b0fa2e9b0c..17b406f903 100644 --- a/.github/scripts/selftest-swift-packages-exit.sh +++ b/.github/scripts/selftest-swift-packages-exit.sh @@ -3,19 +3,10 @@ set -euo pipefail ROOT=$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd) +# shellcheck source=swift-packages-log-detect.sh +source "${ROOT}/.github/scripts/swift-packages-log-detect.sh" -swift_package_log_has_test_failures() { - local log="$1" - if grep -qE 'Executed [0-9]+ tests?, with [1-9][0-9]* failures' "$log"; then - return 0 - fi - if grep -qE "Test Suite 'All tests' failed" "$log"; then - return 0 - fi - return 1 -} - -fixture="${ROOT}/.github/scripts/fixtures/swift-test-xctest-failure-sample.txt" +fixture="${ROOT}/.github/scripts/fixtures/swift-test-xctest-failure-43186705883-sample.txt" if ! swift_package_log_has_test_failures "$fixture"; then echo "selftest: expected fixture log to count as failures" >&2 exit 1 @@ -26,10 +17,25 @@ trap 'rm -f "$pass_log"' EXIT cat >"$pass_log" <<'EOF' Test Suite 'All tests' passed at 2026-01-01 00:00:00.000. Executed 12 tests, with 0 failures (0 unexpected) in 0.010 (0.012) seconds +◇ Test run started. +↳ Testing Library Version: 1902 +✔ Test run with 0 tests in 0 suites passed after 0.001 seconds. +compiled with 3 issues in other contexts EOF if swift_package_log_has_test_failures "$pass_log"; then echo "selftest: pass log must not count as failures" >&2 exit 1 fi +skipped_pass_log=$(mktemp) +trap 'rm -f "$pass_log" "$skipped_pass_log"' EXIT +cat >"$skipped_pass_log" <<'EOF' +Test Suite 'All tests' passed at 2026-01-01 00:00:00.000. + Executed 100 tests, with 3 tests skipped and 0 failures (0 unexpected) in 1.0 (1.1) seconds +EOF +if swift_package_log_has_test_failures "$skipped_pass_log"; then + echo "selftest: skipped-only summary must not count as failures" >&2 + exit 1 +fi + echo "selftest-swift-packages-exit: ok" diff --git a/.github/scripts/swift-packages-log-detect.sh b/.github/scripts/swift-packages-log-detect.sh new file mode 100644 index 0000000000..d771433d25 --- /dev/null +++ b/.github/scripts/swift-packages-log-detect.sh @@ -0,0 +1,23 @@ +#!/usr/bin/env bash +# Shared swift-packages XCTest / Swift Testing failure detection (sourced, not executed). +swift_package_log_has_test_failures() { + local log="$1" + # XCTest aggregate line, including "with N tests skipped and M failures". + if grep -qE 'Executed [0-9]+ tests?, with ([0-9]+ tests? skipped and )?[1-9][0-9]* failures' "$log"; then + return 0 + fi + if grep -qE "Test Suite 'All tests' failed" "$log"; then + return 0 + fi + if grep -qE "Test Suite 'CompassDataPackageTests.xctest' failed" "$log"; then + return 0 + fi + # Swift Testing failed runs (exclude "0 tests" pass summaries). + if grep -qE 'Test run with [1-9][0-9]* tests.*failed' "$log"; then + return 0 + fi + if grep -qE '✗.*failed' "$log"; then + return 0 + fi + return 1 +} diff --git a/.github/scripts/test-macos-swift-packages.sh b/.github/scripts/test-macos-swift-packages.sh index d36be35423..2c69c9cd98 100755 --- a/.github/scripts/test-macos-swift-packages.sh +++ b/.github/scripts/test-macos-swift-packages.sh @@ -7,6 +7,9 @@ export NSUnbufferedIO=YES ROOT=$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd) cd "$ROOT" +# shellcheck source=swift-packages-log-detect.sh +source "${ROOT}/.github/scripts/swift-packages-log-detect.sh" + bash "${ROOT}/.github/scripts/selftest-swift-packages-exit.sh" # CompassKitTests in `swift test --package-path CompassKit` mirror the @@ -35,25 +38,6 @@ if [ "${MACOS_SWIFT_PACKAGES_SKIP_BUILD:-0}" = "1" ]; then echo "swift-packages: skip build (using warmed .build artifacts)" fi -# `swift test` can exit 0 when XCTest suites fail and Swift Testing runs afterward -# with zero tests. Scan the full log for XCTest and Swift Testing failure markers. -swift_package_log_has_test_failures() { - local log="$1" - if grep -qE 'Executed [0-9]+ tests?, with [1-9][0-9]* failures' "$log"; then - return 0 - fi - if grep -qE "Test Suite 'All tests' failed" "$log"; then - return 0 - fi - if grep -qE 'Test run with [1-9][0-9]* failures' "$log"; then - return 0 - fi - if grep -qE 'with [1-9][0-9]* issues' "$log"; then - return 0 - fi - return 1 -} - run_package_tests() { local name="$1" local dir="apps/calendar-macos/${name}" diff --git a/apps/calendar-macos/CompassData/Sources/CompassData/NativeCalendarRootModel.swift b/apps/calendar-macos/CompassData/Sources/CompassData/NativeCalendarRootModel.swift index 57fdb7d3e2..6141d8568e 100644 --- a/apps/calendar-macos/CompassData/Sources/CompassData/NativeCalendarRootModel.swift +++ b/apps/calendar-macos/CompassData/Sources/CompassData/NativeCalendarRootModel.swift @@ -202,7 +202,7 @@ public final class NativeCalendarRootModel { ? CompassDevicePreferences.readPinnedTimeZoneResolvingAccidentalUtc() : nil EffectiveTimeZone.identifier = - demoTimeZone ?? pinnedTimeZone ?? TimeZone.current.identifier + demoTimeZone ?? pinnedTimeZone ?? CompassDeviceTimeZone.currentIdentifier eventsStore = environment.eventsStore hiddenEventsStore = environment.hiddenEventsStore calendarVisibilityStore = CalendarVisibilityStore() @@ -229,7 +229,7 @@ public final class NativeCalendarRootModel { anchorDate: anchor, visibleDayCount: CalendarWindowMath.weekDayCount, pinnedTimeZone: pinnedTimeZone, - browserTimeZone: demoTimeZone ?? TimeZone.current.identifier + browserTimeZone: demoTimeZone ?? CompassDeviceTimeZone.currentIdentifier ) if demoPresentation == nil { viewStore.setTimeTravelTimeZone(CompassDevicePreferences.readTimeTravelTimeZone()) @@ -1190,3 +1190,11 @@ public final class NativeCalendarRootModel { } } } + +extension NativeCalendarRootModel { + /// Tests seed calendar list before presentation rebuild (hint sync). + internal func applyCalendarsForPresentationTesting(_ updated: [CompassCalendar]) { + calendars = updated + rebuildPresentation() + } +} diff --git a/apps/calendar-macos/CompassData/Sources/CompassData/Preferences/CompassDeviceTimeZone.swift b/apps/calendar-macos/CompassData/Sources/CompassData/Preferences/CompassDeviceTimeZone.swift new file mode 100644 index 0000000000..9b11c56e18 --- /dev/null +++ b/apps/calendar-macos/CompassData/Sources/CompassData/Preferences/CompassDeviceTimeZone.swift @@ -0,0 +1,20 @@ +import Foundation + +/// Device (browser) timezone at app bootstrap, overridable in tests without touching globals. +public enum CompassDeviceTimeZone { + private nonisolated(unsafe) static var identifierProvider: () -> String = { + TimeZone.current.identifier + } + + public static var currentIdentifier: String { + identifierProvider() + } + + public static func setIdentifierProviderForTests(_ provider: @escaping () -> String) { + identifierProvider = provider + } + + public static func resetIdentifierProviderForTests() { + identifierProvider = { TimeZone.current.identifier } + } +} diff --git a/apps/calendar-macos/CompassData/Tests/CompassDataTests/NativeCalendarRootModelAllDayTests.swift b/apps/calendar-macos/CompassData/Tests/CompassDataTests/NativeCalendarRootModelAllDayTests.swift index c38b1d8947..861d58d767 100644 --- a/apps/calendar-macos/CompassData/Tests/CompassDataTests/NativeCalendarRootModelAllDayTests.swift +++ b/apps/calendar-macos/CompassData/Tests/CompassDataTests/NativeCalendarRootModelAllDayTests.swift @@ -36,12 +36,46 @@ final class NativeCalendarRootModelAllDayTests: XCTestCase { EffectiveTimeZone.calendar.date(from: DateComponents(year: 2026, month: 3, day: day))! } + private func denverPrimaryCalendar() -> CompassCalendar { + CompassCalendar( + access: .owner, + accountEmail: "a@example.com", + backgroundColor: "#ffffff", + capabilities: .init( + canInviteAttendees: false, + canManage: false, + canReadAvailability: true, + canReadDetails: true, + canWatchEvents: false, + canWrite: true, + conferenceKinds: [] + ), + conference: nil, + createsGoogleMeet: false, + description: "", + foregroundColor: "#000000", + id: "denver-primary", + isActive: true, + isPrimary: true, + isVisible: true, + name: "Primary", + provider: "google", + timeZone: IANATimeZone(rawValue: "America/Denver") + ) + } + private func model(startDay: Int, endDay: Int) throws -> NativeCalendarRootModel { + CompassDeviceTimeZone.setIdentifierProviderForTests { "GMT" } let model = NativeCalendarRootModel(environment: try NativeCalendarEnvironment(inMemoryDatabase: true)) - model.viewStore.setCalendarTimeZoneHint("America/Denver") + model.applyCalendarsForPresentationTesting([denverPrimaryCalendar()]) model.draftStore.startGridDraft(activity: .keyboardPlace, draft: GridEventDraft( clientId: .init(rawValue: "all-day"), schedule: .init(start: date(startDay), end: date(endDay), kind: .allDay), - calendarId: .init(rawValue: "cal-1"))) + calendarId: .init(rawValue: "denver-primary"))) return model } + + override func tearDown() async throws { + CompassDeviceTimeZone.resetIdentifierProviderForTests() + try await super.tearDown() + } } diff --git a/apps/calendar-macos/CompassData/Tests/CompassDataTests/NativeCalendarRootModelInitialWeekAnchorTests.swift b/apps/calendar-macos/CompassData/Tests/CompassDataTests/NativeCalendarRootModelInitialWeekAnchorTests.swift index ba6d254a68..ce55e929bd 100644 --- a/apps/calendar-macos/CompassData/Tests/CompassDataTests/NativeCalendarRootModelInitialWeekAnchorTests.swift +++ b/apps/calendar-macos/CompassData/Tests/CompassDataTests/NativeCalendarRootModelInitialWeekAnchorTests.swift @@ -4,28 +4,52 @@ import XCTest @MainActor final class NativeCalendarRootModelInitialWeekAnchorTests: XCTestCase { + override func tearDown() async throws { + CompassDeviceTimeZone.resetIdentifierProviderForTests() + _ = CompassDevicePreferences.writePinnedTimeZone(nil) + try await super.tearDown() + } + func testInitialWeekAnchorUsesDeviceZoneBeforeViewStore() throws { - let priorPinned = CompassDevicePreferences.readPinnedTimeZone() - defer { - if let priorPinned { - _ = CompassDevicePreferences.writePinnedTimeZone(priorPinned) - } else { - _ = CompassDevicePreferences.writePinnedTimeZone(nil) - } - } - XCTAssertTrue(CompassDevicePreferences.writePinnedTimeZone("America/Denver")) + CompassDeviceTimeZone.setIdentifierProviderForTests { "America/Denver" } + XCTAssertTrue(CompassDevicePreferences.writePinnedTimeZone(nil)) + // Monday 06:00 UTC is still Sunday evening in Denver; week start differs from GMT midnight. let referenceNow = try XCTUnwrap( CompassDateParsing.parseGridDateTime( - "2026-11-12T01:30:00.000", + "2026-11-10T06:00:00.000", timeZoneIdentifier: "UTC" ) ) let environment = try NativeCalendarEnvironment(inMemoryDatabase: true) let model = NativeCalendarRootModel(environment: environment, now: { referenceNow }) - let expected = CalendarWindowMath.sundayWeekViewStart(containing: referenceNow) - XCTAssertEqual(model.viewStore.anchorDate, expected) XCTAssertEqual(EffectiveTimeZone.identifier, "America/Denver") + let denverAnchor = CalendarWindowMath.sundayWeekViewStart(containing: referenceNow) + XCTAssertEqual(model.viewStore.anchorDate, denverAnchor) + + EffectiveTimeZone.identifier = "GMT" + let gmtAnchor = CalendarWindowMath.sundayWeekViewStart(containing: referenceNow) + XCTAssertNotEqual(denverAnchor, gmtAnchor) + } + + func testInitialWeekAnchorHonorsPinnedZoneOverDevice() throws { + CompassDeviceTimeZone.setIdentifierProviderForTests { "GMT" } + XCTAssertTrue(CompassDevicePreferences.writePinnedTimeZone("America/Chicago")) + + let referenceNow = try XCTUnwrap( + CompassDateParsing.parseGridDateTime( + "2026-06-15T12:00:00.000", + timeZoneIdentifier: "UTC" + ) + ) + let environment = try NativeCalendarEnvironment(inMemoryDatabase: true) + let model = NativeCalendarRootModel(environment: environment, now: { referenceNow }) + + XCTAssertEqual(EffectiveTimeZone.identifier, "America/Chicago") + XCTAssertEqual( + model.viewStore.anchorDate, + CalendarWindowMath.sundayWeekViewStart(containing: referenceNow) + ) } } From 4a8c2b1400f81f09d36c109f27817cfb7267e7fa Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Thu, 12 Nov 2026 11:39:20 +0000 Subject: [PATCH 4/4] fix(macos): scroll event form to recurrence focus target Register EventFormField.recurrence in the form ScrollView so Mod+digit jumps scroll the toggle into view instead of leaving it not hittable. Co-authored-by: Tyler Dane --- .../CompassUI/Sources/CompassUI/EventForm/EventFormView.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/calendar-macos/CompassUI/Sources/CompassUI/EventForm/EventFormView.swift b/apps/calendar-macos/CompassUI/Sources/CompassUI/EventForm/EventFormView.swift index d78004aab4..4dda3168a3 100644 --- a/apps/calendar-macos/CompassUI/Sources/CompassUI/EventForm/EventFormView.swift +++ b/apps/calendar-macos/CompassUI/Sources/CompassUI/EventForm/EventFormView.swift @@ -57,6 +57,7 @@ public struct EventFormView: View { model: model, draft: draft ) + .id(EventFormField.recurrence) .disabled(model.isScheduleLocked(for: draft)) } }