207 lines
6.3 KiB
TypeScript
207 lines
6.3 KiB
TypeScript
/**
|
|
* E2E Tests for Push Notifications
|
|
*
|
|
* Tests the complete push notification workflow using Playwright:
|
|
* - Permission granting
|
|
* - Subscription creation
|
|
* - Server registration
|
|
* - Manual test notifications
|
|
* - Unsubscribe flow
|
|
* - localStorage persistence
|
|
*
|
|
* Note: These tests require the dev server to be running.
|
|
*/
|
|
|
|
import { test, expect, type BrowserContext } from '@playwright/test';
|
|
|
|
test.describe('Push Notifications E2E', () => {
|
|
let context: BrowserContext;
|
|
|
|
test.beforeEach(async ({ browser }) => {
|
|
// Create new context with notification permissions granted
|
|
context = await browser.newContext();
|
|
await context.grantPermissions(['notifications']);
|
|
});
|
|
|
|
test.afterEach(async () => {
|
|
await context?.close();
|
|
});
|
|
|
|
test('should subscribe to push notifications', async () => {
|
|
const page = await context.newPage();
|
|
await page.goto('/');
|
|
await page.waitForLoadState('networkidle');
|
|
|
|
// Wait for service worker to be registered
|
|
await page.waitForFunction(() => 'serviceWorker' in navigator && 'PushManager' in window);
|
|
|
|
// Find the notification toggle button
|
|
const toggleButton = page.getByRole('button', { name: /enable notifications/i });
|
|
await expect(toggleButton).toBeVisible();
|
|
|
|
// Click to enable notifications
|
|
await toggleButton.click();
|
|
|
|
// Wait for subscription to complete
|
|
await page.waitForTimeout(2000);
|
|
|
|
// Verify subscription was created in browser
|
|
const subscription = await page.evaluate(async () => {
|
|
const registration = await navigator.serviceWorker.ready;
|
|
const sub = await registration.pushManager.getSubscription();
|
|
return sub
|
|
? {
|
|
endpoint: sub.endpoint,
|
|
hasKeys: !!(sub as any).keys
|
|
}
|
|
: null;
|
|
});
|
|
|
|
expect(subscription).not.toBeNull();
|
|
expect(subscription?.endpoint).toBeTruthy();
|
|
expect(subscription?.endpoint).toContain('https://');
|
|
expect(subscription?.hasKeys).toBe(true);
|
|
|
|
// Verify button text changed to "Disable Notifications"
|
|
await expect(toggleButton).toHaveText(/disable notifications/i);
|
|
|
|
await page.close();
|
|
});
|
|
|
|
test('should show test notification buttons when subscribed', async () => {
|
|
const page = await context.newPage();
|
|
await page.goto('/');
|
|
await page.waitForLoadState('networkidle');
|
|
|
|
// Wait for service worker
|
|
await page.waitForFunction(() => 'serviceWorker' in navigator);
|
|
|
|
// Enable notifications first
|
|
const toggleButton = page.getByRole('button', { name: /enable notifications/i });
|
|
await toggleButton.click();
|
|
await page.waitForTimeout(2000);
|
|
|
|
// Verify test buttons are visible
|
|
const testSuccessButton = page.getByRole('button', { name: /test success/i });
|
|
const testErrorButton = page.getByRole('button', { name: /test error/i });
|
|
const testProgressButton = page.getByRole('button', { name: /test progress/i });
|
|
|
|
await expect(testSuccessButton).toBeVisible();
|
|
await expect(testErrorButton).toBeVisible();
|
|
await expect(testProgressButton).toBeVisible();
|
|
|
|
await page.close();
|
|
});
|
|
|
|
test('should send test notifications', async () => {
|
|
const page = await context.newPage();
|
|
await page.goto('/');
|
|
await page.waitForLoadState('networkidle');
|
|
|
|
// Wait for service worker
|
|
await page.waitForFunction(() => 'serviceWorker' in navigator);
|
|
|
|
// Enable notifications first
|
|
const toggleButton = page.getByRole('button', { name: /enable notifications/i });
|
|
await toggleButton.click();
|
|
await page.waitForTimeout(2000);
|
|
|
|
// Mock the test notification API response
|
|
await page.route('/api/notifications/test', async (route) => {
|
|
await route.fulfill({
|
|
status: 200,
|
|
contentType: 'application/json',
|
|
body: JSON.stringify({ success: true, subscriberCount: 1 })
|
|
});
|
|
});
|
|
|
|
// Click test success button
|
|
const testSuccessButton = page.getByRole('button', { name: /test success/i });
|
|
await testSuccessButton.click();
|
|
|
|
// Wait for and verify success message
|
|
const successMessage = page.getByText(/✓ test success notification sent/i);
|
|
await expect(successMessage).toBeVisible({ timeout: 5000 });
|
|
|
|
// Verify message contains subscriber count
|
|
await expect(successMessage).toContainText('1 subscriber');
|
|
|
|
// Wait for auto-dismiss
|
|
await expect(successMessage).not.toBeVisible({ timeout: 4000 });
|
|
|
|
await page.close();
|
|
});
|
|
|
|
test('should unsubscribe from push notifications', async () => {
|
|
const page = await context.newPage();
|
|
await page.goto('/');
|
|
await page.waitForLoadState('networkidle');
|
|
|
|
// Wait for service worker
|
|
await page.waitForFunction(() => 'serviceWorker' in navigator);
|
|
|
|
// First subscribe
|
|
const toggleButton = page.getByRole('button', { name: /enable notifications/i });
|
|
await toggleButton.click();
|
|
await page.waitForTimeout(2000);
|
|
|
|
// Verify subscribed
|
|
await expect(toggleButton).toHaveText(/disable notifications/i);
|
|
|
|
// Now unsubscribe
|
|
await toggleButton.click();
|
|
await page.waitForTimeout(2000);
|
|
|
|
// Verify subscription was removed
|
|
const subscription = await page.evaluate(async () => {
|
|
const registration = await navigator.serviceWorker.ready;
|
|
return await registration.pushManager.getSubscription();
|
|
});
|
|
|
|
expect(subscription).toBeNull();
|
|
|
|
// Verify button text changed back
|
|
await expect(toggleButton).toHaveText(/enable notifications/i);
|
|
|
|
// Verify test buttons are no longer visible
|
|
const testSuccessButton = page.getByRole('button', { name: /test success/i });
|
|
await expect(testSuccessButton).not.toBeVisible();
|
|
|
|
await page.close();
|
|
});
|
|
|
|
test('should persist clientId in localStorage', async () => {
|
|
const page = await context.newPage();
|
|
await page.goto('/');
|
|
await page.waitForLoadState('networkidle');
|
|
|
|
// Wait for service worker
|
|
await page.waitForFunction(() => 'serviceWorker' in navigator);
|
|
|
|
// Enable notifications
|
|
const toggleButton = page.getByRole('button', { name: /enable notifications/i });
|
|
await toggleButton.click();
|
|
await page.waitForTimeout(2000);
|
|
|
|
// Verify clientId is stored in localStorage
|
|
const clientId = await page.evaluate(() => {
|
|
return localStorage.getItem('push-client-id');
|
|
});
|
|
|
|
expect(clientId).toBeTruthy();
|
|
expect(clientId).toMatch(/^client_[a-f0-9-]+$/);
|
|
|
|
// Reload page and verify clientId persists
|
|
await page.reload();
|
|
await page.waitForLoadState('networkidle');
|
|
|
|
const persistedClientId = await page.evaluate(() => {
|
|
return localStorage.getItem('push-client-id');
|
|
});
|
|
|
|
expect(persistedClientId).toBe(clientId);
|
|
|
|
await page.close();
|
|
});
|
|
});
|