diff --git a/.gitea/workflows/test.yaml b/.gitea/workflows/test.yaml index 8e833fe..f9fd104 100644 --- a/.gitea/workflows/test.yaml +++ b/.gitea/workflows/test.yaml @@ -7,4 +7,4 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - run: npm install && npm run test \ No newline at end of file + - run: npm install && npm run test && npx playwright test diff --git a/app/install/InstallPrompts.tsx b/app/install/InstallPrompts.tsx index 3760af9..de93024 100644 --- a/app/install/InstallPrompts.tsx +++ b/app/install/InstallPrompts.tsx @@ -4,6 +4,7 @@ import EnableNotifications from "./EnableNotifications" import OpenSafari from "./OpenSafari" import InstallPWA from "./InstallPWA" import Unsupported from "./Unsupported" +import PermissionDenied from "./PermissionDenied" interface InstallPromptsProps { isMobileSafari: boolean @@ -26,6 +27,7 @@ export default function InstallPrompts({ ), unsupported: , + "permission denied": , } return steps[step as keyof typeof steps] ?? null diff --git a/app/install/PermissionDenied.tsx b/app/install/PermissionDenied.tsx new file mode 100644 index 0000000..0ced448 --- /dev/null +++ b/app/install/PermissionDenied.tsx @@ -0,0 +1,13 @@ +import React from "react" + +export default function PermissionDenied() { + return ( +
+
+ Tack Up Now requires notifications permissions to work +
+
+
Grant notifications permissions to use Tack Up Now
+
+ ) +} diff --git a/app/useInstallState.ts b/app/useInstallState.ts index 19f9961..5440f05 100644 --- a/app/useInstallState.ts +++ b/app/useInstallState.ts @@ -6,6 +6,7 @@ type IOSInstallStep = | "open safari" | "enable notifications" | "unsupported" + | "permission denied" export default function useInstallState({ isSupported, @@ -29,6 +30,9 @@ export default function useInstallState({ window.Notification.permission === "granted") || canSendPush + const permissionDenied = + "Notification" in window && window.Notification.permission === "denied" + const isRunningPWA = ("standalone" in navigator && (navigator.standalone as boolean)) || matchMedia("(dislay-mode: standalone)").matches @@ -40,9 +44,11 @@ export default function useInstallState({ ? "open safari" : !isRunningPWA && isMobileSafari ? "install" - : !notificationsEnabled - ? "enable notifications" - : (null as IOSInstallStep | null), + : permissionDenied + ? "permission denied" + : !notificationsEnabled + ? "enable notifications" + : (null as IOSInstallStep | null), installed: notificationsEnabled, } } diff --git a/e2e/install.spec.ts b/e2e/install.spec.ts index b295ad8..81a7b93 100644 --- a/e2e/install.spec.ts +++ b/e2e/install.spec.ts @@ -95,13 +95,23 @@ describe("when user is on iOS", () => { await requestPromise const yourNotificationsHeading = - await page.getByText(/Your Notifications/) + page.getByText(/Your Notifications/) await expect(yourNotificationsHeading).toBeVisible() }) }) }) + test("and notifications have been denied", async ({ page }) => { + await stubNotifications(page, { permission: "denied" }) + + await page.goto("/") + + const deniedText = page.getByText(/requires notifications permissions/) + + await expect(deniedText).toBeAttached() + }) + describe("and notifications are enabled", () => { beforeEach(async ({ page }) => { await stubNotifications(page, { permission: "granted" }) @@ -111,7 +121,7 @@ describe("when user is on iOS", () => { await page.goto("/") await page.evaluate(async () => await navigator.serviceWorker.ready) - const notificationText = await page.getByText(/Enable Notifications/) + const notificationText = page.getByText(/Enable Notifications/) await expect(notificationText).not.toBeAttached() }) @@ -119,8 +129,7 @@ describe("when user is on iOS", () => { test("users see tack up now", async ({ page }) => { await page.goto("/") - const yourNotificationsHeading = - await page.getByText(/Your Notifications/) + const yourNotificationsHeading = page.getByText(/Your Notifications/) await expect(yourNotificationsHeading).toBeVisible() }) @@ -139,13 +148,21 @@ describe("when user is on iOS", () => { }) => { await page.goto("/") - const sorryText = await page.getByText(/Sorry/) + const sorryText = page.getByText(/Sorry/) await expect(sorryText).toBeVisible() }) }) }) +describe("other browsers", () => { + describe("when notifications permissions are unknown", () => { + test("prompt the user to allow notifications", async ({ page }) => { + // await page. + }) + }) +}) + function stubNotifications( page: Page, args: { diff --git a/vite.config.ts b/vite.config.ts index 3715143..a7ebb32 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -7,5 +7,9 @@ import { remixPWA } from "@remix-pwa/dev" installGlobals() export default defineConfig({ - plugins: [remix(), tsconfigPaths(), remixPWA()], + plugins: [ + remix({ ignoredRouteFiles: ["**/*.test.*"] }), + tsconfigPaths(), + remixPWA(), + ], })