|
1 | 1 | import {waitFor} from "@testing-library/react-native" |
| 2 | +import * as Calendar from "expo-calendar" |
2 | 3 | import {router} from "expo-router" |
3 | 4 |
|
4 | 5 | import mantle from "@/services/MantleManager" |
@@ -67,6 +68,9 @@ jest.mock("@/utils/e2eMetrics", () => ({ |
67 | 68 | })) |
68 | 69 |
|
69 | 70 | jest.mock("expo-calendar", () => ({ |
| 71 | + // Denied by default: the boot-time sync then skips quietly, and only the |
| 72 | + // calendar test below opts into the granted path. |
| 73 | + getCalendarPermissionsAsync: jest.fn(() => Promise.resolve({status: "denied"})), |
70 | 74 | getCalendarsAsync: jest.fn(() => Promise.resolve([])), |
71 | 75 | getEventsAsync: jest.fn(() => Promise.resolve([])), |
72 | 76 | EntityTypes: {EVENT: "event"}, |
@@ -287,6 +291,52 @@ describe("MantleManager", () => { |
287 | 291 | ) |
288 | 292 | }) |
289 | 293 |
|
| 294 | + it("writes calendar events through the settings store so full pushes carry them", async () => { |
| 295 | + useGlassesStore.getState().setGlassesInfo({deviceModel: "Even Realities G1"}) |
| 296 | + ;(Calendar.getCalendarPermissionsAsync as jest.Mock).mockResolvedValueOnce({status: "granted"}) |
| 297 | + ;(Calendar.getCalendarsAsync as jest.Mock).mockResolvedValueOnce([{id: "cal-1"}]) |
| 298 | + ;(Calendar.getEventsAsync as jest.Mock).mockResolvedValueOnce([ |
| 299 | + {title: "Design review", startDate: "2026-08-03T12:00:00.000Z", endDate: "2026-08-03T13:00:00.000Z"}, |
| 300 | + { |
| 301 | + title: "Standup", |
| 302 | + location: "Room 4", |
| 303 | + startDate: "2026-08-02T15:00:00.000Z", |
| 304 | + endDate: "2026-08-02T16:00:00.000Z", |
| 305 | + }, |
| 306 | + {title: "Retro", startDate: "2026-08-04T12:00:00.000Z", endDate: "2026-08-04T12:30:00.000Z"}, |
| 307 | + {title: "Breakfast", startDate: "2026-08-02T09:00:00.000Z", endDate: "2026-08-02T09:30:00.000Z"}, |
| 308 | + ]) |
| 309 | + ;(bluetoothSdkMock.updateBluetoothSettings as jest.Mock).mockClear() |
| 310 | + |
| 311 | + await (mantle as unknown as {sendCalendarEvents: () => Promise<void>}).sendCalendarEvents() |
| 312 | + |
| 313 | + const expected = [ |
| 314 | + {title: "Breakfast", time: expect.any(String), endDate: Date.parse("2026-08-02T09:30:00.000Z") / 1000}, |
| 315 | + { |
| 316 | + title: "Standup", |
| 317 | + location: "Room 4", |
| 318 | + time: expect.any(String), |
| 319 | + endDate: Date.parse("2026-08-02T16:00:00.000Z") / 1000, |
| 320 | + }, |
| 321 | + {title: "Design review", time: expect.any(String), endDate: Date.parse("2026-08-03T13:00:00.000Z") / 1000}, |
| 322 | + ] |
| 323 | + expect(useSettingsStore.getState().getSetting(SETTINGS.calendar_events.key)).toEqual(expected) |
| 324 | + expect(useSettingsStore.getState().getBluetoothSettings().calendar_events).toEqual(expected) |
| 325 | + expect(bluetoothSdkMock.setCalendarEvents).not.toHaveBeenCalled() |
| 326 | + |
| 327 | + jest.runOnlyPendingTimers() |
| 328 | + expect(bluetoothSdkMock.updateBluetoothSettings).toHaveBeenCalledWith( |
| 329 | + expect.objectContaining({calendar_events: expected}), |
| 330 | + ) |
| 331 | + ;(bluetoothSdkMock.updateBluetoothSettings as jest.Mock).mockClear() |
| 332 | + emitBluetoothSdkEvent("glasses_status", {connection: {state: "connected", fullyBooted: true}}) |
| 333 | + await waitFor(() => { |
| 334 | + expect(bluetoothSdkMock.updateBluetoothSettings).toHaveBeenCalledWith( |
| 335 | + expect.objectContaining({calendar_events: expected}), |
| 336 | + ) |
| 337 | + }) |
| 338 | + }) |
| 339 | + |
290 | 340 | it("syncs standalone WiFi status events into the glasses store", () => { |
291 | 341 | emitBluetoothSdkEvent("wifi_status_change", { |
292 | 342 | type: "wifi_status_change", |
|
0 commit comments