import { describe, it, expect, vi, beforeEach, afterEach } from "vitest"; vi.mock("@/api/driver", () => ({ getPushKey: vi.fn(async () => ({ key: "BIIh_RELLY", enabled: true })), subscribePush: vi.fn(async () => ({ ok: true })), unsubscribePush: vi.fn(async () => ({ ok: true })), })); import { currentState, enable, supported } from "./push"; import * as api from "@/api/driver"; const SUB = { endpoint: "https://fcm.googleapis.com/fcm/send/abc", toJSON: () => ({ endpoint: "https://fcm.googleapis.com/fcm/send/abc", keys: { p256dh: "p256", auth: "auth" }, }), unsubscribe: vi.fn(async () => true), }; function stubBrowser(opts: { permission?: NotificationPermission; existing?: unknown; ios?: boolean; standalone?: boolean; } = {}) { const perm = opts.permission ?? "default"; const registration = { pushManager: { getSubscription: vi.fn(async () => opts.existing ?? null), subscribe: vi.fn(async () => SUB), }, }; vi.stubGlobal("navigator", { serviceWorker: { getRegistration: vi.fn(async () => registration), ready: Promise.resolve(registration), }, userAgent: opts.ios ? "iPhone" : "Android Chrome", standalone: opts.standalone, }); const notification = { permission: perm, requestPermission: vi.fn(async () => (opts.permission === "denied" ? "denied" : "granted")), }; // Notification обязан лежать И в window: supported() проверяет именно его — // так же, как это делает браузер. vi.stubGlobal("window", { PushManager: function () {}, Notification: notification, matchMedia: () => ({ matches: !!opts.standalone }), }); vi.stubGlobal("Notification", notification); return registration; } describe("уведомления в приложении", () => { beforeEach(() => vi.clearAllMocks()); afterEach(() => vi.unstubAllGlobals()); it("iPhone без установки на экран: объясняем, а не молчим", async () => { vi.stubGlobal("navigator", { userAgent: "iPhone", standalone: false }); vi.stubGlobal("window", { matchMedia: () => ({ matches: false }) }); expect(supported()).toBe(false); expect(await currentState()).toBe("needs-install"); }); it("разрешение отклонено — переспросить нечем", async () => { stubBrowser({ permission: "denied" }); expect(await currentState()).toBe("denied"); }); it("подписка уходит на сервер с ключами из браузера", async () => { stubBrowser(); expect(await enable()).toBe("on"); expect(api.subscribePush).toHaveBeenCalledWith({ endpoint: "https://fcm.googleapis.com/fcm/send/abc", p256dh: "p256", auth: "auth", }); }); it("сервер не настроен — разрешение НЕ спрашиваем", async () => { // Единственная попытка на установку: потратить её впустую нельзя. vi.mocked(api.getPushKey).mockResolvedValueOnce({ key: "", enabled: false }); stubBrowser(); expect(await enable()).toBe("off"); expect(Notification.requestPermission).not.toHaveBeenCalled(); expect(api.subscribePush).not.toHaveBeenCalled(); }); });