// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
'use strict';
// The ResultQueue is a mechanism for passing messages back to the test
// framework.
var resultQueue = new ResultQueue();
// Waits for the given ServiceWorkerRegistration to become ready.
// Shim for https://github.com/w3c/ServiceWorker/issues/770.
function swRegistrationReady(reg) {
return new Promise((resolve, reject) => {
if (reg.active) {
resolve();
return;
}
if (!reg.installing && !reg.waiting) {
reject(Error('Install failed'));
return;
}
(reg.installing || reg.waiting).addEventListener('statechange', function() {
if (this.state == 'redundant') {
reject(Error('Install failed'));
} else if (this.state == 'activated') {
resolve();
}
});
});
}
// Notification permission has been coalesced with Push permission. After
// this is granted, Push API subscription can succeed.
function requestNotificationPermission() {
return new Promise(resolve => {
Notification.requestPermission(resolve);
}).then((permission) => 'permission status - ' + permission);
}
function registerServiceWorker() {
// The base dir used to resolve service_worker.js and the scope depends on
// whether this script is included from an html file in ./, subscope1/, or
// subscope2/.
return navigator.serviceWorker.register('service_worker.js', {
scope: './'
}).then(swRegistrationReady).then(() => {
return 'ok - service worker registered';
}).catch(formatError);
}
function unregisterServiceWorker() {
return navigator.serviceWorker.getRegistration()
.then(function(swRegistration) {
return swRegistration.unregister();
}).then(function(result) {
return 'service worker unregistration status: ' + result;
})
.catch(formatError);
}
function replaceServiceWorker() {
return navigator.serviceWorker.register(
'service_worker_with_skipWaiting_claim.js', {
scope: './'
}).then(swRegistrationReady).then(() => {
return 'ok - service worker replaced';
}).catch(formatError);
}
function removeManifest() {
var element = document.querySelector('link[rel="manifest"]');
if (element)
element.parentNode.removeChild(element);
return 'manifest removed';
}
function swapManifestNoSenderId() {
var element = document.querySelector('link[rel="manifest"]');
if (element) {
element.href = 'manifest_no_sender_id.json';
return 'sender id removed from manifest';
} else {
return 'unable to find manifest element';
}
}
// This is the old style of push subscriptions which we are phasing away
// from, where the subscription used a sender ID instead of public key.
function documentSubscribePushWithoutKey() {
return navigator.serviceWorker.ready.then(function(swRegistration) {
return swRegistration.pushManager.subscribe({userVisibleOnly: true});
}).then(function(subscription) {
return subscription.endpoint;
}).catch(formatError);
}
function documentSubscribePushWithEmptyOptions() {
return navigator.serviceWorker.ready.then(function(swRegistration) {
return swRegistration.pushManager.subscribe();
}).then(function(subscription) {
return subscription.endpoint;
}).catch(formatError);
}
function documentSubscribePush() {
return navigator.serviceWorker.ready.then(function(swRegistration) {
return swRegistration.pushManager.subscribe({
userVisibleOnly: true,
applicationServerKey: kApplicationServerKey.buffer
});
}).then(function(subscription) {
return subscription.endpoint;
}).catch(formatError);
}
function documentSubscribePushWithNumericKey() {
return navigator.serviceWorker.ready.then(function(swRegistration) {
return swRegistration.pushManager.subscribe({
userVisibleOnly: true,
applicationServerKey: new TextEncoder().encode('1234567890')
});
}).then(function(subscription) {
return subscription.endpoint;
}).catch(formatError);
}
function documentSubscribePushWithBase64URLEncodedString() {
return navigator.serviceWorker.ready.then(function(swRegistration) {
return swRegistration.pushManager.subscribe({
userVisibleOnly: true,
applicationServerKey: kBase64URLEncodedKey
});
}).then(function(subscription) {
return subscription.endpoint;
}).catch(formatError);
}
function documentSubscribePushGetExpirationTime() {
return navigator.serviceWorker.ready.then(function(swRegistration) {
return swRegistration.pushManager.subscribe({
userVisibleOnly: true,
applicationServerKey: kApplicationServerKey.buffer
});
}).then(function(subscription) {
return String(subscription.expirationTime);
}).catch(formatError);
}
function workerSubscribePush() {
// Send the message to the worker for it to subscribe
return new Promise(resolve => {
navigator.serviceWorker.addEventListener('message', resolve, false);
navigator.serviceWorker.controller.postMessage(
{command: 'workerSubscribe'});
}).then((event) => JSON.parse(event.data).data);
}
function workerSubscribePushNoKey() {
// The worker will try to subscribe without providing a key. This should
// succeed if the worker was previously subscribed with a numeric key
// and fail otherwise.
return new Promise(resolve => {
navigator.serviceWorker.addEventListener('message', resolve, false);
navigator.serviceWorker.controller.postMessage(
{command: 'workerSubscribeNoKey'});
}).then((event) => JSON.parse(event.data).data);
}
function workerSubscribePushWithNumericKey(numericKey = '1234567890') {
// Send the message to the worker for it to subscribe with the given numeric key
return new Promise(resolve => {
navigator.serviceWorker.addEventListener('message', resolve, false);
navigator.serviceWorker.controller.postMessage(
{command: 'workerSubscribeWithNumericKey', key: numericKey});
}).then((event) => JSON.parse(event.data).data);
}
function workerSubscribePushWithBase64URLEncodedString() {
// Send the message to the worker for it to subscribe with the given Base64URLEncoded key
return new Promise(resolve => {
navigator.serviceWorker.addEventListener('message', resolve, false);
navigator.serviceWorker.controller.postMessage(
{command: 'workerSubscribePushWithBase64URLEncodedString',
key: kBase64URLEncodedKey});
}).then((event) => JSON.parse(event.data).data);
}
function GetP256dh() {
return navigator.serviceWorker.ready.then(function(swRegistration) {
return swRegistration.pushManager.getSubscription();
}).then(function(subscription) {
return btoa(String.fromCharCode.apply(null,
new Uint8Array(subscription.getKey('p256dh'))));
}).catch(formatError);
}
function GetSubscriptionExpirationTime() {
return navigator.serviceWorker.ready.then(function(swRegistration) {
return swRegistration.pushManager.getSubscription();
}).then(function(subscription) {
return String(subscription.expirationTime);
}).catch(formatError);
}
function pushManagerPermissionState() {
return navigator.serviceWorker.ready.then(function(swRegistration) {
return swRegistration.pushManager.permissionState({userVisibleOnly: true});
}).then(function(permission) {
return 'permission status - ' + permission;
}).catch(formatError);
}
function notificationPermissionState() {
return 'permission status - ' + Notification.permission;
}
function notificationPermissionAPIState() {
return navigator.permissions.query({name: 'notifications'}).then(
permission_status => {
return 'permission status - ' + permission_status.state;
}).catch(formatError);
}
function isControlled() {
if (navigator.serviceWorker.controller) {
return 'true - is controlled';
} else {
return 'false - is not controlled';
}
}
async function unsubscribePush() {
const swRegistration = await navigator.serviceWorker.ready;
if (!swRegistration) {
return 'unsubscribe result: false';
}
const pushSubscription = await swRegistration.pushManager.getSubscription();
if (!pushSubscription) {
return 'unsubscribe result: false';
}
try {
const result = await pushSubscription.unsubscribe();
return 'unsubscribe result: ' + result;
} catch(error) {
return 'unsubscribe error: ' + error.message;
}
}
function storePushSubscription() {
return navigator.serviceWorker.ready.then(swRegistration => {
return swRegistration.pushManager.getSubscription();
}).then(pushSubscription => {
window.storedPushSubscription = pushSubscription;
return 'ok - stored';
})
.catch(formatError);
}
function unsubscribeStoredPushSubscription() {
return window.storedPushSubscription.unsubscribe().then(function(result) {
return 'unsubscribe result: ' + result;
}, function(error) {
return 'unsubscribe error: ' + error.message;
});
}
function hasSubscription() {
return navigator.serviceWorker.ready.then(function(swRegistration) {
return swRegistration.pushManager.getSubscription();
}).then(function(subscription) {
return subscription ? 'true - subscribed'
: 'false - not subscribed';
}).catch(formatError);
}
navigator.serviceWorker.addEventListener('message', function(event) {
var message = JSON.parse(event.data);
if (message.type === 'push') {
resultQueue.push(message.data);
} else if (message.type === 'pushsubscriptionchange') {
resultQueue.push(message.data.oldEndpoint);
resultQueue.push(message.data.newEndpoint);
}
}, false);