- Push notifications are not supported in this browser.
+ {unsupportedReason ?? 'Push notifications are not supported in this browser.'}
);
diff --git a/apps/web/src/hooks/usePushNotifications.test.ts b/apps/web/src/hooks/usePushNotifications.test.ts
index e966f650..4ef8fadd 100644
--- a/apps/web/src/hooks/usePushNotifications.test.ts
+++ b/apps/web/src/hooks/usePushNotifications.test.ts
@@ -1,63 +1,49 @@
import { describe, it, expect, vi, beforeEach } from 'vitest';
import { renderHook, act } from '@testing-library/react';
-// Set VAPID key before module load (vi.hoisted runs before imports)
-vi.hoisted(() => {
- process.env.NEXT_PUBLIC_VAPID_PUBLIC_KEY =
- 'BEl62iUYgUivxIkv69yViEuiBIa-Ib9-SkvMeAtA3LFgDzkOs-qy7505aFNGpOTN_4Bz8T5RA8ZjqO1QjAPGeZs';
+const mocks = vi.hoisted(() => {
+ class PushError extends Error {
+ reason: string;
+ constructor(reason: string, message = reason) {
+ super(message);
+ this.reason = reason;
+ }
+ }
+ return {
+ PushError,
+ pushSupport: vi.fn(),
+ getSubscription: vi.fn(),
+ subscribe: vi.fn(),
+ unsubscribe: vi.fn(),
+ };
});
+vi.mock('@profullstack/notifications/client', () => mocks);
+
import { usePushNotifications } from './usePushNotifications';
-const mockSubscription = {
+const subscriptionJson = {
endpoint: 'https://fcm.googleapis.com/fcm/send/test-endpoint',
- toJSON: () => ({
- endpoint: 'https://fcm.googleapis.com/fcm/send/test-endpoint',
- keys: { p256dh: 'test-p256dh', auth: 'test-auth' },
- }),
- unsubscribe: vi.fn().mockResolvedValue(true),
+ keys: { p256dh: 'test-p256dh', auth: 'test-auth' },
};
-const mockPushManager = {
- getSubscription: vi.fn().mockResolvedValue(null),
- subscribe: vi.fn().mockResolvedValue(mockSubscription),
-};
+const mockSubscription = { endpoint: subscriptionJson.endpoint };
-const mockRegistration = {
- pushManager: mockPushManager,
-};
+const SUPPORTED = { supported: true, reason: null, message: null, permission: 'default' };
describe('usePushNotifications', () => {
beforeEach(() => {
vi.clearAllMocks();
- mockPushManager.getSubscription.mockResolvedValue(null);
- mockPushManager.subscribe.mockResolvedValue(mockSubscription);
- mockSubscription.unsubscribe.mockResolvedValue(true);
-
- // Mock browser APIs
- Object.defineProperty(window, 'Notification', {
- value: {
- permission: 'default' as NotificationPermission,
- requestPermission: vi.fn().mockResolvedValue('granted'),
- },
- writable: true,
- configurable: true,
- });
-
- Object.defineProperty(navigator, 'serviceWorker', {
- value: {
- ready: Promise.resolve(mockRegistration),
- },
- writable: true,
- configurable: true,
- });
-
- // Ensure PushManager exists
- Object.defineProperty(window, 'PushManager', {
- value: vi.fn(),
- writable: true,
- configurable: true,
- });
+ mocks.pushSupport.mockReturnValue(SUPPORTED);
+ mocks.getSubscription.mockResolvedValue(null);
+ mocks.unsubscribe.mockResolvedValue(true);
+ // The package hands the new subscription to `save`; PairUX's save POSTs it.
+ mocks.subscribe.mockImplementation(
+ async (opts: { save: (json: typeof subscriptionJson) => Promise