| 1 | import { beforeEach, vi } from "vite-plus/test"; |
| 2 | import { describe, expect, it } from "@effect/vitest"; |
| 3 | import * as Effect from "effect/Effect"; |
| 4 | import * as Notifications from "expo-notifications"; |
| 5 | import { requestAgentNotificationPermission } from "./notificationPermissions"; |
| 6 | |
| 7 | const platform = vi.hoisted(() => ({ OS: "android" })); |
| 8 | vi.mock("react-native", () => ({ Platform: platform })); |
| 9 | vi.mock("expo-notifications", () => ({ |
| 10 | AndroidImportance: { HIGH: 4 }, |
| 11 | setNotificationChannelAsync: vi.fn(() => Promise.resolve(null)), |
| 12 | getPermissionsAsync: vi.fn(() => Promise.resolve({ granted: false, canAskAgain: true })), |
| 13 | requestPermissionsAsync: vi.fn(() => Promise.resolve({ granted: true, canAskAgain: true })), |
| 14 | })); |
| 15 | |
| 16 | describe("agent notification permission", () => { |
| 17 | beforeEach(() => { |
| 18 | vi.clearAllMocks(); |
| 19 | platform.OS = "android"; |
| 20 | }); |
| 21 | |
| 22 | it.effect("creates an Android channel before prompting for notification permission", () => |
| 23 | Effect.gen(function* () { |
| 24 | expect(yield* requestAgentNotificationPermission).toEqual({ type: "granted" }); |
| 25 | expect(Notifications.setNotificationChannelAsync).toHaveBeenCalledWith("agent-alerts", { |
| 26 | name: "Agent alerts", |
| 27 | importance: 4, |
| 28 | }); |
| 29 | expect( |
| 30 | vi.mocked(Notifications.setNotificationChannelAsync).mock.invocationCallOrder[0], |
| 31 | ).toBeLessThan(vi.mocked(Notifications.requestPermissionsAsync).mock.invocationCallOrder[0]!); |
| 32 | }), |
| 33 | ); |
| 34 | |
| 35 | it.effect("preserves denied permission when Android cannot ask again", () => |
| 36 | Effect.gen(function* () { |
| 37 | vi.mocked(Notifications.getPermissionsAsync).mockResolvedValueOnce({ |
| 38 | granted: false, |
| 39 | canAskAgain: false, |
| 40 | } as Notifications.NotificationPermissionsStatus); |
| 41 | expect(yield* requestAgentNotificationPermission).toEqual({ |
| 42 | type: "denied", |
| 43 | canAskAgain: false, |
| 44 | }); |
| 45 | expect(Notifications.requestPermissionsAsync).not.toHaveBeenCalled(); |
| 46 | }), |
| 47 | ); |
| 48 | |
| 49 | it.effect("keeps iOS permission requests free of Android channel setup", () => |
| 50 | Effect.gen(function* () { |
| 51 | platform.OS = "ios"; |
| 52 | expect(yield* requestAgentNotificationPermission).toEqual({ type: "granted" }); |
| 53 | expect(Notifications.setNotificationChannelAsync).not.toHaveBeenCalled(); |
| 54 | expect(Notifications.requestPermissionsAsync).toHaveBeenCalledWith({ |
| 55 | ios: { allowAlert: true, allowBadge: true, allowSound: true }, |
| 56 | }); |
| 57 | }), |
| 58 | ); |
| 59 | }); |