From 37f32cce3aca65a9c478c7f944c418ffb4e40fff Mon Sep 17 00:00:00 2001 From: Jeff Date: Sat, 19 Oct 2024 19:20:51 -0400 Subject: [PATCH] Replace vapid key that accidentally got committed, show notifications in app --- .gitignore | 1 + app/worker.test.ts | 101 ++++++++++++++++++++++++++++++++++----------- app/worker.ts | 37 ++++++++--------- package-lock.json | 30 +++++++------- pushPublicKey.ts | 2 +- send-it.js | 22 ---------- 6 files changed, 111 insertions(+), 82 deletions(-) delete mode 100644 send-it.js diff --git a/.gitignore b/.gitignore index 0654967..926ee4a 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,4 @@ build/ /playwright-report/ /blob-report/ /playwright/.cache/ +send-it.js \ No newline at end of file diff --git a/app/worker.test.ts b/app/worker.test.ts index 87edf95..6822a8e 100644 --- a/app/worker.test.ts +++ b/app/worker.test.ts @@ -20,9 +20,11 @@ const createSelf = () => subscribe: jest.fn(() => Promise.resolve(createSubscription())), getSubscription: jest.fn(() => Promise.resolve(createSubscription())), }, + showNotification: jest.fn(), }, clients: { claim: jest.fn(() => Promise.resolve()), + openWindow: jest.fn(() => Promise.resolve()), }, }) as unknown as ServiceWorkerGlobalScope @@ -37,28 +39,25 @@ describe("service worker", () => { indexedDB = new IDBFactory() self = createSelf() - // fetchMock.mockIf(/http:\/\/localhost\/api\/subscribe\/?/, (req) => { - // return Promise.resolve( - // req.method === "POST" - // ? { - // body: JSON.stringify({ subscriptionId: 123 }), - // } - // : req.method === "PUT" - // ? { init: { status: 200 } } - // : { init: { status: 405 } } - // ) - // }) - fetchMock.mockResponse((req) => { - return Promise.resolve( + if ( + req.url.replace(/https?:\/\/[a-zA-Z0-9\.]*/, "") === + "/api/subscription/" && req.method === "POST" - ? { - body: JSON.stringify({ subscriptionId: 123 }), - } - : req.method === "PUT" - ? { init: { status: 200 } } - : { init: { status: 405 } } - ) + ) { + return Promise.resolve({ + body: JSON.stringify({ subscriptionId: 123 }), + }) + } else if ( + req.url + .replace(/https?:\/\/[a-zA-Z0-9\.]*/, "") + .startsWith("/api/subscription/") && + req.method === "PUT" + ) { + return Promise.resolve({ init: { status: 200 } }) + } + + return Promise.resolve({ init: { status: 500 } }) }) }) @@ -67,13 +66,56 @@ describe("service worker", () => { global.window = originalWindow }) - xtest("displays push notifications", () => { + test("displays push notifications", async () => { initWorker(self) const pushHandler = getHandler("push") - const pushEvent = createEvent({ data: "HI" }) + const pushEvent = createPushEvent( + JSON.stringify({ + title: "Test title", + body: "Test text", + icon: "Test icon", + badge: "Test badge", + destination: "tackupnow.com/hi", + }) + ) pushHandler(pushEvent) + await waitUntilCalls(pushEvent) + + expect(self.registration.showNotification).toHaveBeenCalledWith( + "Test title", + { + body: "Test text", + icon: "Test icon", + badge: "Test badge", + data: { destination: "tackupnow.com/hi" }, + } + ) + }) + + test("closes notification on click", async () => { + initWorker(self) + + const notificationHandler = getHandler("notificationclick") + + const event = createNotificationEvent("tackupnow.com") + notificationHandler(event) + await waitUntilCalls(event) + + expect(event.notification.close).toHaveBeenCalled() + }) + + test("opens tack up now on click", async () => { + initWorker(self) + + const notificationHandler = getHandler("notificationclick") + + const event = createNotificationEvent("tackupnow.com") + notificationHandler(event) + await waitUntilCalls(event) + + expect(self.clients.openWindow).toHaveBeenCalledWith("tackupnow.com") }) test("claims on activate", async () => { @@ -292,8 +334,19 @@ function createPushEvent(data: string) { return createEvent(pushFields) } -function createMessageEvent(message: any) { - return createEvent({ data: message }) +function createNotificationEvent(destination: string): NotificationEvent & { + waitUntil: jest.Mock> +} { + return createEvent({ + notification: { + close: jest.fn(), + data: { + destination, + }, + }, + }) as any as NotificationEvent & { + waitUntil: jest.Mock> + } } function createEvent(properties?: object) { diff --git a/app/worker.ts b/app/worker.ts index 4f6f9a0..cce3cb4 100644 --- a/app/worker.ts +++ b/app/worker.ts @@ -16,29 +16,26 @@ export default function start(self: ServiceWorkerGlobalScope) { event.waitUntil(self.clients.claim()) }) - // self.addEventListener("push", function (event: PushEvent) { - // console.log("[Service Worker] Push Received.") - // console.log(`[Service Worker] Push had this data: "${event.data?.text()}"`) + self.addEventListener("push", function (event: PushEvent) { + const { title, body, badge, icon, destination } = event.data?.json() - // const title = "Push Codelab" - // const options = { - // body: "Yay it works.", - // icon: "images/icon.png", - // badge: "images/badge.png", - // } + event.waitUntil( + self.registration.showNotification(title, { + body, + badge, + icon, + data: { destination }, + }) + ) + }) - // event.waitUntil(self.registration.showNotification(title, options)) - // }) + self.addEventListener("notificationclick", function (event) { + event.notification.close() - // self.addEventListener("notificationclick", function (event) { - // console.log("[Service Worker] Notification click Received.") - - // event.notification.close() - - // event.waitUntil( - // self.clients.openWindow("https://developers.google.com/web/") - // ) - // }) + event.waitUntil( + self.clients.openWindow(event.notification.data.destination) + ) + }) self.addEventListener("message", function (event) { const waitEvent = event as ExtendableEvent diff --git a/package-lock.json b/package-lock.json index ae75e1f..a626631 100644 --- a/package-lock.json +++ b/package-lock.json @@ -31,7 +31,7 @@ "@babel/preset-env": "^7.24.5", "@babel/preset-react": "^7.24.1", "@babel/preset-typescript": "^7.24.1", - "@playwright/test": "^1.44.1", + "@playwright/test": "^1.48.1", "@remix-pwa/dev": "^3.1.0", "@remix-run/dev": "^2.9.0", "@remix-run/testing": "^2.9.1", @@ -3324,18 +3324,18 @@ } }, "node_modules/@playwright/test": { - "version": "1.44.1", - "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.44.1.tgz", - "integrity": "sha512-1hZ4TNvD5z9VuhNJ/walIjvMVvYkZKf71axoF/uiAqpntQJXpG64dlXhoDXE3OczPuTuvjf/M5KWFg5VAVUS3Q==", + "version": "1.48.1", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.48.1.tgz", + "integrity": "sha512-s9RtWoxkOLmRJdw3oFvhFbs9OJS0BzrLUc8Hf6l2UdCNd1rqeEyD4BhCJkvzeEoD1FsK4mirsWwGerhVmYKtZg==", "dev": true, "dependencies": { - "playwright": "1.44.1" + "playwright": "1.48.1" }, "bin": { "playwright": "cli.js" }, "engines": { - "node": ">=16" + "node": ">=18" } }, "node_modules/@remix-pwa/dev": { @@ -13843,33 +13843,33 @@ } }, "node_modules/playwright": { - "version": "1.44.1", - "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.44.1.tgz", - "integrity": "sha512-qr/0UJ5CFAtloI3avF95Y0L1xQo6r3LQArLIg/z/PoGJ6xa+EwzrwO5lpNr/09STxdHuUoP2mvuELJS+hLdtgg==", + "version": "1.48.1", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.48.1.tgz", + "integrity": "sha512-j8CiHW/V6HxmbntOfyB4+T/uk08tBy6ph0MpBXwuoofkSnLmlfdYNNkFTYD6ofzzlSqLA1fwH4vwvVFvJgLN0w==", "dev": true, "dependencies": { - "playwright-core": "1.44.1" + "playwright-core": "1.48.1" }, "bin": { "playwright": "cli.js" }, "engines": { - "node": ">=16" + "node": ">=18" }, "optionalDependencies": { "fsevents": "2.3.2" } }, "node_modules/playwright-core": { - "version": "1.44.1", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.44.1.tgz", - "integrity": "sha512-wh0JWtYTrhv1+OSsLPgFzGzt67Y7BE/ZS3jEqgGBlp2ppp1ZDj8c+9IARNW4dwf1poq5MgHreEM2KV/GuR4cFA==", + "version": "1.48.1", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.48.1.tgz", + "integrity": "sha512-Yw/t4VAFX/bBr1OzwCuOMZkY1Cnb4z/doAFSwf4huqAGWmf9eMNjmK7NiOljCdLmxeRYcGPPmcDgU0zOlzP0YA==", "dev": true, "bin": { "playwright-core": "cli.js" }, "engines": { - "node": ">=16" + "node": ">=18" } }, "node_modules/playwright/node_modules/fsevents": { diff --git a/pushPublicKey.ts b/pushPublicKey.ts index 39f1b0e..0a0792d 100644 --- a/pushPublicKey.ts +++ b/pushPublicKey.ts @@ -1 +1 @@ -export default "BKc02U2-z7PkTbYgYLlxELWqzTVE631fs4IPuMLbxY_rxdo9VaduthqwkPOiblwjETl99uXes2Nc9EtPbS5x4uA" +export default "BLoc3g9yZAgSB1HRwolI4NcGUaJRFhLKtf2Ys3Jcbtsr8yKsoCLldc4ynADLTGMbihTYbIKS8PdSHEKDGkCR4fI" diff --git a/send-it.js b/send-it.js deleted file mode 100644 index 9d55ca0..0000000 --- a/send-it.js +++ /dev/null @@ -1,22 +0,0 @@ -import webPush from "web-push" - -const subscription = { - endpoint: - "https://updates.push.services.mozilla.com/wpush/v2/gAAAAABm9FlbY5vMro60hF2iJF3UUBzweuFcg5NRSHXPSpHfUpjo5jKGVRnUxR4ekg0-FsvdQCP89cu__IFd06Tu2TJZ649YyqivRUBnAav0DgOLHGx5-t943QLS-wLvBqyJRCuuLlM1bLz6S9ph9AWJ8CG7rQuTabsHvw--s_w2KDQo3GcQXIM", - expirationTime: null, - keys: { - auth: "dDUqtFo26ekGEAmNzvmJAw", - p256dh: - "BHIT3J6xSRiHfz0m-QRHagDThiOZGVIANtPzOasrOBYG0s_yUnshTVharX5dZcq8GA5OkyMm3mqmA7_o_lFR4WE", - }, -} -webPush.setVapidDetails( - "https://tackupnow.com", - "BKc02U2-z7PkTbYgYLlxELWqzTVE631fs4IPuMLbxY_rxdo9VaduthqwkPOiblwjETl99uXes2Nc9EtPbS5x4uA", - "Xmv5Pc4mqr138V3sCxXq7UmsbL5UgSOY43UuJ50nxPw" -) - -webPush - .sendNotification(subscription, "Hi what's up?", {}) - .then((x) => console.log("It sent", x)) - .catch((error) => console.log("It did not send", error))