import { describe, it, expect, vi, beforeEach } from 'vitest'
// usePush touches Notification/navigator.serviceWorker at module load —
// stub the browser surface before importing it.
class FakeNotification {
static permission = 'default'
static requestPermission = vi.fn(async () => 'granted')
}
vi.stubGlobal('Notification', FakeNotification)
import { urlBase64ToUint8Array, usePush } from '@/composables/usePush.js'
import * as api from '@/api'
describe('urlBase64ToUint8Array', () => {
it('round-trips URL-safe base64 with padding', () => {
// VAPID keys are 65 bytes; this is a known 16-byte sample.
const b64 = 'BQEhHkLb1xqWzM3vFVdUfA'
const bytes = urlBase64ToUint8Array(b64)
expect(bytes).toBeInstanceOf(Uint8Array)
expect(bytes.length).toBe(16)
})
it('decodes standard base64 payloads unchanged', () => {
// 'AQID' → [1, 2, 3]
expect(Array.from(urlBase64ToUint8Array('AQID'))).toEqual([1, 2, 3])
})
})
describe('usePush', () => {
beforeEach(() => {
vi.restoreAllMocks()
})
it('exposes enable/disable/syncState and refs', () => {
const push = usePush()
expect(typeof push.enable).toBe('function')
expect(typeof push.disable).toBe('function')
expect(typeof push.syncState).toBe('function')
expect(typeof push.permission.value).toBe('string')
})
it('enable() subscribes and posts the endpoint payload', async ({ }) => {
const fakeSub = {
endpoint: 'https://push.example/endpoint/1',
toJSON: () => ({
endpoint: 'https://push.example/endpoint/1',
keys: { p256dh: 'P256DH', auth: 'AUTH' },
}),
unsubscribe: async () => true,
}
const fakeReg = {
pushManager: {
getSubscription: vi.fn(async () => null),
subscribe: vi.fn(async () => fakeSub),
},
}
vi.stubGlobal('navigator', {
userAgent: 'vitest',
serviceWorker: {
getRegistration: async () => fakeReg,
ready: Promise.resolve(fakeReg),
},
})
vi.stubGlobal('PushManager', function PushManager() {})
vi.spyOn(api, 'getVapidKey').mockResolvedValue({ public_key: 'AQIDBAUGBw' })
const subscribeSpy = vi.spyOn(api, 'subscribePush').mockResolvedValue({ id: '1' })
const push = usePush()
const ok = await push.enable()
expect(ok).toBe(true)
expect(fakeReg.pushManager.subscribe).toHaveBeenCalledWith(
expect.objectContaining({ userVisibleOnly: true })
)
expect(subscribeSpy).toHaveBeenCalledWith({
endpoint: 'https://push.example/endpoint/1',
keys: { p256dh: 'P256DH', auth: 'AUTH' },
user_agent: 'vitest',
})
expect(push.subscribed.value).toBe(true)
})
it('enable() returns false when the server has no VAPID key', async () => {
vi.stubGlobal('navigator', {
userAgent: 'vitest',
serviceWorker: {
getRegistration: async () => null,
ready: Promise.resolve({ pushManager: { getSubscription: async () => null, subscribe: async () => {} } }),
},
})
vi.stubGlobal('PushManager', function PushManager() {})
vi.spyOn(api, 'getVapidKey').mockResolvedValue({ public_key: null })
const push = usePush()
expect(await push.enable()).toBe(false)
})
})