tack-up-now/e2e/install.spec.ts

280 lines
7.8 KiB
TypeScript

import { test, expect, Page } from "@playwright/test"
import matchPath from "./urlMatcher"
import { messageSW } from "@remix-pwa/sw"
const { describe, beforeEach, skip, use } = test
function webkitOnly() {
beforeEach(async ({ browserName }) => {
if (browserName !== "webkit") skip()
})
}
function nonWebkitOnly() {
beforeEach(async ({ browserName }) => {
if (browserName === "webkit") skip()
})
}
describe("when user is on iOS", () => {
webkitOnly()
describe("version 16.4 or higher", () => {
use({
userAgent:
"Mozilla/5.0 (iPhone; CPU iPhone OS 16_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.6 Mobile/15E148 Safari/604.1",
})
describe("and the browser is not safari", () => {
use({
userAgent:
"Mozilla/5.0 (iPhone; U; CPU iPhone OS 16_4 like Mac OS X; en-gb) AppleWebKit/534.46.0 (KHTML, like Gecko) CriOS/19.0.1084.60 Mobile/9B206 Safari/7534.48.3",
})
test("the user is told they need to install through Safari, because reasons, I guess", async ({
page,
}) => {
await page.goto("/")
const safariText = await page.getByText(/Open tackupnow.com in Safari/)
await expect(safariText).toBeAttached()
})
})
test("and tack up now is not running as a PWA, they are instructed to install tack up now", async ({
page,
}) => {
await page.goto("/")
const installText = await page.getByText(/Install Tack Up Now!/)
await expect(installText).toBeAttached()
})
describe("and tack up now is running as a PWA", () => {
beforeEach(async ({ page }) => {
await page.addInitScript(
() => ((window.navigator as any)["standalone"] = true)
)
await stubServiceWorker(page)
})
describe("and notifications aren't enabled", () => {
test("they are asked to enable notifications", async ({ page }) => {
await stubNotifications(page, { permission: "default" })
await page.goto("/")
const enableButton = await page.getByText(/Enable Notifications/)
await expect(enableButton).toBeAttached()
})
describe("and then the user enables notifications", () => {
beforeEach(async ({ page }) => {
await stubNotifications(page, {
permission: "default",
requestPermissionResult: "granted",
})
})
test("users see tack up now after enabling notifications", async ({
page,
}) => {
await page.goto("/")
await page.getByText(/Enable Notifications/).click()
const yourNotificationsHeading =
page.getByText(/Your Notifications/)
await expect(yourNotificationsHeading).toBeVisible()
})
test("the subscription is submitted", async ({ page }) => {
await page.goto("/")
await page.getByText(/Enable Notifications/).click()
const postedMessages = await page.evaluate(() => {
return (window as any).postedMessages
})
expect(postedMessages).toContainEqual({
type: "subscribed",
subscription: {
subscription: "HI",
},
})
})
})
})
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" })
})
test("they aren't asked to enable notifications", async ({ page }) => {
await page.goto("/")
await page.evaluate(async () => await navigator.serviceWorker.ready)
const notificationText = page.getByText(/Enable Notifications/)
await expect(notificationText).not.toBeAttached()
})
test("users see tack up now", async ({ page }) => {
await page.goto("/")
const yourNotificationsHeading = page.getByText(/Your Notifications/)
await expect(yourNotificationsHeading).toBeVisible()
})
})
})
})
describe("version 16.3 and under", () => {
use({
userAgent:
"Mozilla/5.0 (iPhone; CPU iPhone OS 16_3_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.6 Mobile/15E148 Safari/604.1",
})
test("version 16.3 and under they are informed that their iOS version isn't supported", async ({
page,
}) => {
await page.goto("/")
const sorryText = page.getByText(/Sorry/)
await expect(sorryText).toBeVisible()
})
})
})
describe("other browsers", () => {
nonWebkitOnly()
beforeEach(async ({ page }) => {
await page.route(matchPath(page, "/api/subscription"), async (route) => {
await route.fulfill()
})
await stubServiceWorker(page)
})
test("prompt the user to allow notifications", async ({ page }) => {
await stubNotifications(page, { permission: "default" })
await page.goto("/")
const notificationText = page.getByText(/Enable Notifications/)
await expect(notificationText).toBeAttached()
})
test("show tack up now when permission is granted", async ({ page }) => {
await stubNotifications(page, { permission: "granted" })
await page.goto("/")
const yourNotificationsHeading = page.getByText(/Your Notifications/)
await expect(yourNotificationsHeading).toBeVisible()
})
test("prompt to allow notifications if permission was denied", async ({
page,
}) => {
await stubNotifications(page, { permission: "denied" })
await page.goto("/")
const deniedText = page.getByText(/requires notifications permissions/)
await expect(deniedText).toBeAttached()
})
})
function stubNotifications(
page: Page,
args: {
permission: NotificationPermission
requestPermissionResult?: NotificationPermission
}
) {
return page.addInitScript(
(args: {
permission: NotificationPermission
requestPermissionResult?: NotificationPermission
}) => {
window.Notification = window.Notification ?? {}
Object.defineProperty(window.Notification, "permission", {
value: args.permission,
writable: true,
})
Object.defineProperty(window.Notification, "requestPermission", {
value: () =>
Promise.resolve(args.requestPermissionResult ?? args.permission),
})
},
args
)
}
function stubServiceWorker(page: Page) {
return page.addInitScript(() => {
function createSubscription(testToken = "HI") {
return {
toJSON: () => ({
subscription: testToken,
}),
}
}
let postedMessages: any[] = []
const serviceWorker = {
postMessage: (message: any) => postedMessages.push(message),
}
const registration = {
pushManager: {
getSubscription() {
return Promise.resolve(createSubscription())
},
subscribe(args: Parameters<PushManager["subscribe"]>[0]) {
return Promise.resolve(createSubscription())
},
},
active: serviceWorker,
}
Object.defineProperty(window, "postedMessages", {
value: postedMessages,
writable: true,
})
Object.defineProperty(navigator, "serviceWorker", {
value: {
ready: Promise.resolve(registration),
register() {
return Promise.resolve(registration)
},
getRegistration() {
return Promise.resolve(registration)
},
addEventListener() {},
removeEventListener() {},
},
writable: false,
})
})
}