UNPKG

onesignal-web-sdk

Version:

Web push notifications from OneSignal.

210 lines (169 loc) 8.47 kB
import test from 'ava'; import '../../support/polyfills/polyfills'; import sinon, { SinonSandbox } from 'sinon'; import { ServiceWorker } from '../../../src/service-worker/ServiceWorker'; import { setBrowser } from '../../support/tester/browser'; import { BrowserUserAgent, TestEnvironment } from '../../support/sdk/TestEnvironment'; import Database from '../../../src/services/Database'; import { ConfigIntegrationKind } from '../../../src/models/AppConfig'; import { PushSubscriptionChangeEvent } from "../../support/mocks/service-workers/models/PushSubscriptionChangeEvent"; import ServiceWorkerGlobalScope from '../../support/mocks/service-workers/ServiceWorkerGlobalScope'; import PushManager from '../../support/mocks/service-workers/models/PushManager'; import Random from "../../support/tester/Random"; import PushSubscription from '../../support/mocks/service-workers/models/PushSubscription'; import { SubscriptionManager } from '../../../src/managers/SubscriptionManager'; import OneSignalApiSW from '../../../src/OneSignalApiSW'; declare var self: ServiceWorkerGlobalScope; const appId = Random.getRandomUuid(); const existingDeviceId = Random.getRandomUuid(); let oldSubscription: PushSubscription; let newSubscription: PushSubscription; let sinonSandbox: SinonSandbox; test.beforeEach(async() => { sinonSandbox = sinon.sandbox.create(); sinonSandbox.stub(OneSignalApiSW, 'downloadServerAppConfig') .resolves(TestEnvironment.getFakeServerAppConfig(ConfigIntegrationKind.Custom)); sinonSandbox.stub(OneSignalApiSW, 'updatePlayer').resolves(); oldSubscription = await new PushManager().subscribe({ userVisibleOnly: true, applicationServerKey: Random.getRandomUint8Array(65).buffer }); newSubscription = await new PushManager().subscribe({ userVisibleOnly: true, applicationServerKey: Random.getRandomUint8Array(65).buffer }); await TestEnvironment.initializeForServiceWorker({ url: new URL(`https://site.com/service-worker.js?appId=${appId}`) }); setBrowser(BrowserUserAgent.ChromeMacSupported); }); test.afterEach(function (_t: TestContext) { sinonSandbox.restore(); }); test(`called with an old and new subscription successfully updates the subscription`, async t => { /* For this test, pretend the user revoked permissions, pushsubscriptionchange's event provides an oldSubscription but not a new subscription, and the service worker tries to resubscribe anyways. It's going to fail due to the blocked permission, so let's simulate that here. */ sinonSandbox .stub(SubscriptionManager.prototype, 'subscribeFcmFromWorker') .throws('some-error'); await setInitialDatabaseState(existingDeviceId, oldSubscription.endpoint); //before subscription change let subscription = await Database.getSubscription(); t.deepEqual(subscription.deviceId, existingDeviceId); t.deepEqual(subscription.subscriptionToken, oldSubscription.endpoint); const event = new PushSubscriptionChangeEvent(); event.oldSubscription = oldSubscription; event.newSubscription = newSubscription; // navigator.permissions is undefined in Firefox service worker context, lets simulate that here sinonSandbox.stub(navigator, 'permissions').value(undefined); await runPushSubscriptionChange(event); // After pushsubscriptionchange subscription = await Database.getSubscription(); // The device record ID should stay the same t.deepEqual(subscription.deviceId, existingDeviceId); // The subscription endpoint should be the new endpoint t.deepEqual(subscription.subscriptionToken, newSubscription.endpoint); }); test(`without an existing device ID, lookup existing device ID, updates the looked-up record`, async t => { const idReturnedByLookupCall = Random.getRandomUuid(); sinonSandbox.stub(OneSignalApiSW, 'getUserIdFromSubscriptionIdentifier').resolves(idReturnedByLookupCall); // Before pushsubscriptionchange let subscription = await Database.getSubscription(); // There should be no existing device ID, we'll look this up by push endpoint in the test t.deepEqual(subscription.deviceId, null); // Don't check existence of old endpoint, it isn't used, pushsubscriptionchange provides the old endpoint const event = new PushSubscriptionChangeEvent(); event.oldSubscription = oldSubscription; event.newSubscription = newSubscription; await runPushSubscriptionChange(event); // After pushsubscriptionchange subscription = await Database.getSubscription(); // We should now have a device ID t.deepEqual(subscription.deviceId, idReturnedByLookupCall); // Our push endpoint should be the new updated one t.deepEqual(subscription.subscriptionToken, newSubscription.endpoint); }); test(`called with an old and without a new subscription, custom resubscription succeeds and updates record endpoint`, async t => { const newSubscriptionByReregistration = newSubscription; sinonSandbox.stub(PushManager.prototype, 'subscribe') .callsFake(async _options => { const subscription = await self.registration.pushManager.getSubscription(); if (!subscription) { return newSubscriptionByReregistration; } else { return oldSubscription; } }); await setInitialDatabaseState(existingDeviceId, oldSubscription.endpoint); // Before pushsubscriptionchange let subscription = await Database.getSubscription(); t.deepEqual(subscription.deviceId, existingDeviceId); t.deepEqual(subscription.subscriptionToken, oldSubscription.endpoint); const event = new PushSubscriptionChangeEvent(); event.oldSubscription = oldSubscription; await runPushSubscriptionChange(event); // After pushsubscriptionchange subscription = await Database.getSubscription(); t.deepEqual(subscription.deviceId, existingDeviceId); t.deepEqual(subscription.subscriptionToken, newSubscriptionByReregistration.endpoint); }); test( `called with an existing device ID, with old and without new subscription, custom resubscription fails ` + `and updates existing device record to clear subscription`, async t => { sinonSandbox .stub(SubscriptionManager.prototype, 'subscribeFcmFromWorker') .throws('some-error'); await setInitialDatabaseState(existingDeviceId, oldSubscription.endpoint); // Before pushsubscriptionchange let subscription = await Database.getSubscription(); t.deepEqual(subscription.deviceId, existingDeviceId); t.deepEqual(subscription.subscriptionToken, oldSubscription.endpoint); const event = new PushSubscriptionChangeEvent(); event.oldSubscription = oldSubscription; await runPushSubscriptionChange(event); // After pushsubscriptionchange subscription = await Database.getSubscription(); t.deepEqual(subscription.deviceId, existingDeviceId); t.deepEqual(subscription.subscriptionToken, null); }); test(`called without an existing device ID, without old and new subscription, custom resubscription fails ` + `and local data is cleared`, async t => { sinonSandbox .stub(SubscriptionManager.prototype, 'subscribeFcmFromWorker') .throws('some-error'); // Before pushsubscriptionchange let subscription = await Database.getSubscription(); t.deepEqual(subscription.deviceId, null); t.deepEqual(subscription.subscriptionToken, null); const event = new PushSubscriptionChangeEvent(); await runPushSubscriptionChange(event); // After pushsubscriptionchange subscription = await Database.getSubscription(); t.deepEqual(subscription.deviceId, null); t.deepEqual(subscription.subscriptionToken, null); }); /** * Helpers */ async function setInitialDatabaseState(deviceId?: string, subscriptionToken?: string) { let subscription = await Database.getSubscription(); subscription.deviceId = deviceId; subscription.subscriptionToken = subscriptionToken; await Database.setSubscription(subscription); } async function runPushSubscriptionChange(event: PushSubscriptionChangeEvent): Promise<void> { const testPromise = new Promise(resolve => { self.addEventListener("pushsubscriptionchange", async (evt: any) => { await ServiceWorker.onPushSubscriptionChange(evt); resolve(); }); }); self.dispatchEvent(event); await testPromise; }