diff options
Diffstat (limited to 'tools/sw-push-quota.test.js')
| -rw-r--r-- | tools/sw-push-quota.test.js | 89 |
1 files changed, 89 insertions, 0 deletions
diff --git a/tools/sw-push-quota.test.js b/tools/sw-push-quota.test.js new file mode 100644 index 0000000..cf4a7bf --- /dev/null +++ b/tools/sw-push-quota.test.js @@ -0,0 +1,89 @@ +// WebKit drops a push subscription after three pushes that show no +// notification, so on an Apple endpoint every path through the worker's push +// handler must end in one. Run: bun test tools/sw-push-quota.test.js +import { test, expect, mock } from 'bun:test'; + +let respond = async () => true; +mock.module('../src/nwc-respond.js', () => ({ respondFromBg: (...a) => respond(...a), tendRenewals: async () => {}, tendLnPays: async () => [] })); +mock.module('../src/nwc-lock.js', () => ({ withRequestLock: async (_id, fn) => fn(), withWorkLock: async (fn) => fn() })); +mock.module('../src/nwc-bg.js', () => ({ appendBgLog: async () => {}, takeLease: async () => ({ waited: 0, release: async () => {} }) })); +mock.module('../src/bg-autowithdraw.js', () => ({ bgAutoWithdraw: async () => {} })); +mock.module('../src/dm-inbox.js', () => ({ + allInboxes: async () => [{ muted: ['m'.repeat(64)] }], + classifyDm: async () => ({ own: true }), shouldNotifyDm: () => false, classifyCall: async () => null, +})); + +const listeners = {}; +let endpoint = 'https://web.push.apple.com/abc'; +let windows = []; +const shown = [], closed = []; +globalThis.self = { + location: { hostname: 'v3.coinos.io', origin: 'https://v3.coinos.io' }, + addEventListener: (t, f) => { listeners[t] = f; }, + clients: { matchAll: async () => windows }, + registration: { + pushManager: { getSubscription: async () => ({ endpoint }) }, + showNotification: async (title, o) => { shown.push({ title, ...o }); }, + getNotifications: async ({ tag }) => shown.filter((n) => n.tag === tag).map((n) => ({ close: () => closed.push(n) })), + }, +}; +await import('../src/sw-nwc.js'); + +async function push(data) { + shown.length = 0; closed.length = 0; + let done; + listeners.push({ data: { json: () => data }, waitUntil: (p) => { done = p; } }); + await done; + return shown.map((n) => n.title); +} +const nwc = { type: 'nwc', servicePubkey: 'a'.repeat(64), event: { id: 'e'.repeat(64), kind: 23194 } }; +const hidden = { visibilityState: 'hidden', postMessage: () => {} }; +const visible = { visibilityState: 'visible', postMessage: () => {} }; + +test('apple: every quiet path shows the stand-in', async () => { + endpoint = 'https://web.push.apple.com/abc'; windows = []; + respond = async () => true; // a lookup answered, or another device took it + expect(await push(nwc)).toEqual(['Coinos']); + expect(await push({ type: 'notify', reason: 'dm', wrap: {} })).toEqual(['Coinos']); + expect(await push({ type: 'notify', reason: 'reaction', from: 'm'.repeat(64) })).toEqual(['Coinos']); + expect(await push({ type: 'notify', reason: 'call', wrapId: 'x' })).toEqual(['Coinos']); + expect(await push({ type: 'weird' })).toEqual(['Coinos']); + expect(closed.length).toBe(0); +}); + +test('apple: a send finished from an earlier wake shows its own line and drops the stand-in', async () => { + endpoint = 'https://web.push.apple.com/abc'; windows = []; + respond = async () => ({ notices: [{ title: 'Payment sent', body: '-21 sats via a connected app', tag: 'nwc-sent' }] }); + expect(await push(nwc)).toEqual(['Coinos', 'Payment sent']); + expect(closed.length).toBe(1); +}); + +test('apple: an app on screen gets the stand-in closed at once', async () => { + windows = [visible]; + expect(await push({ type: 'notify', reason: 'payment', amountSat: 5 })).toEqual(['Coinos']); + expect(closed.length).toBe(1); +}); + +test('apple: a suspended background app does not swallow the request', async () => { + windows = [hidden]; + let asked = 0; + respond = async () => { asked++; return { notify: { title: 'Payment sent', body: '' } }; }; + // the stand-in goes up first and the outcome replaces it (91dbee4) + expect(await push(nwc)).toEqual(['Coinos', 'Payment sent']); + expect(closed.length).toBe(1); + expect(asked).toBe(1); +}); + +test('elsewhere: quiet stays quiet', async () => { + endpoint = 'https://fcm.googleapis.com/fcm/send/abc'; windows = []; + respond = async () => true; + expect(await push(nwc)).toEqual([]); + windows = [hidden]; + let asked = 0; + respond = async () => { asked++; return true; }; + expect(await push(nwc)).toEqual([]); + expect(asked).toBe(0); // the open (if hidden) window answers on Android + windows = []; + respond = async () => false; + expect(await push(nwc)).toEqual(['Payment request']); +}); |
