| // META: global=window-module | |
| // META: script=/resources/testdriver.js | |
| // META: script=/resources/testdriver-vendor.js | |
| // META: script=/notifications/resources/helpers.js | |
| // META: variant=?includeAppServerKey=true | |
| // META: variant=?includeAppServerKey=false | |
| import { encrypt } from "./resources/helpers.js" | |
| import { createVapid } from "./resources/vapid.js"; | |
| const includeAppServerKey = new URL(location.href).searchParams.get("includeAppServerKey") === "true"; | |
| let registration; | |
| async function subscribe(t) { | |
| if (includeAppServerKey) { | |
| const vapid = await createVapid(); | |
| const subscription = await registration.pushManager.subscribe({ | |
| applicationServerKey: vapid.publicKey | |
| }); | |
| t.add_cleanup(() => subscription.unsubscribe()); | |
| return { vapid, subscription }; | |
| } | |
| // without key | |
| try { | |
| const subscription = await registration.pushManager.subscribe(); | |
| t.add_cleanup(() => subscription.unsubscribe()); | |
| return { subscription }; | |
| } catch (err) { | |
| if (err.name === "NotSupportedError") { | |
| // happens if and only if applicationServerKey omission is disallowed, | |
| // which is permitted per the spec. Throwing OptionalFeatureUnsupportedError marks the | |
| // result as PRECONDITION_FAILED. | |
| // | |
| // https://w3c.github.io/push-api/#subscribe-method | |
| // If the options argument does not include a non-null value for the applicationServerKey | |
| // member, and the push service requires one to be given, queue a global task on the | |
| // networking task source using global to reject promise with a "NotSupportedError" | |
| // DOMException. | |
| throw new OptionalFeatureUnsupportedError(description); | |
| } else { | |
| throw err; | |
| } | |
| } | |
| } | |
| async function pushMessage(subscription, { vapid, message }) { | |
| const result = !message | |
| ? { headers: { TTL: 15 } } | |
| : await encrypt( | |
| message, | |
| subscription.getKey("p256dh"), | |
| subscription.getKey("auth") | |
| ); | |
| if (includeAppServerKey) { | |
| result.headers.Authorization = await vapid.generateAuthHeader( | |
| new URL(subscription.endpoint).origin | |
| ); | |
| } | |
| const promise = new Promise(r => { | |
| navigator.serviceWorker.addEventListener("message", r, { once: true }) | |
| }); | |
| await fetch(subscription.endpoint, { | |
| method: "post", | |
| ...result | |
| }); | |
| return (await promise).data; | |
| } | |
| promise_setup(async () => { | |
| await trySettingPermission("granted"); | |
| registration = await prepareActiveServiceWorker("push-sw.js"); | |
| }); | |
| promise_test(async (t) => { | |
| const { vapid, subscription } = await subscribe(t); | |
| const event = await pushMessage(subscription, { vapid }); | |
| assert_equals(event.constructor, "PushEvent"); | |
| assert_equals(event.data, null); | |
| }, "Posting to the push endpoint should fire push event on the service worker"); | |
| const entries = [ | |
| { isJSON: false, message: new TextEncoder().encode("Hello") }, | |
| { isJSON: false, message: new Uint8Array([226, 130, 40, 240, 40, 140, 188]) }, | |
| { isJSON: true, message: new TextEncoder().encode(JSON.stringify({ hello: "world" })) }, | |
| { isJSON: false, message: new Uint8Array() }, | |
| { isJSON: false, message: new Uint8Array([0x48, 0x69, 0x21, 0x20, 0xf0, 0x9f, 0x91, 0x80]) }, | |
| ]; | |
| for (const { isJSON, message } of entries) { | |
| promise_test(async (t) => { | |
| const { vapid, subscription } = await subscribe(t); | |
| const event = await pushMessage(subscription, { vapid, message }); | |
| assert_equals(event.constructor, "PushEvent"); | |
| assert_array_equals(new Uint8Array(event.data.arrayBuffer), message); | |
| assert_array_equals(new Uint8Array(await event.data.blob.arrayBuffer()), message); | |
| assert_equals(event.data.text, new TextDecoder().decode(message)); | |
| assert_equals(event.data.json.ok, isJSON); | |
| if (isJSON) { | |
| assert_array_equals( | |
| new TextEncoder().encode(JSON.stringify(event.data.json.value)), | |
| message | |
| ); | |
| } | |
| }, `Posting to the push endpoint with encrypted data ${message} should fire push event on the service worker`); | |
| } |