simplify
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* E2E Tests for Push Notifications
|
||||
*
|
||||
*
|
||||
* Tests the complete push notification workflow using Playwright:
|
||||
* - Permission granting
|
||||
* - Subscription creation
|
||||
@@ -8,197 +8,199 @@
|
||||
* - 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;
|
||||
let context: BrowserContext;
|
||||
|
||||
test.beforeEach(async ({ browser }) => {
|
||||
// Create new context with notification permissions granted
|
||||
context = await browser.newContext();
|
||||
await context.grantPermissions(['notifications']);
|
||||
});
|
||||
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.afterEach(async () => {
|
||||
await context?.close();
|
||||
});
|
||||
|
||||
test('should subscribe to push notifications', async () => {
|
||||
const page = await context.newPage();
|
||||
await page.goto('/');
|
||||
await page.waitForLoadState('networkidle');
|
||||
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);
|
||||
// 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);
|
||||
// Find the notification toggle button
|
||||
const toggleButton = page.getByRole('button', { name: /enable notifications/i });
|
||||
await expect(toggleButton).toBeVisible();
|
||||
|
||||
// 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;
|
||||
});
|
||||
// Click to enable notifications
|
||||
await toggleButton.click();
|
||||
|
||||
expect(subscription).not.toBeNull();
|
||||
expect(subscription?.endpoint).toBeTruthy();
|
||||
expect(subscription?.endpoint).toContain('https://');
|
||||
expect(subscription?.hasKeys).toBe(true);
|
||||
// Wait for subscription to complete
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
// Verify button text changed to "Disable Notifications"
|
||||
await expect(toggleButton).toHaveText(/disable notifications/i);
|
||||
|
||||
await page.close();
|
||||
});
|
||||
// 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;
|
||||
});
|
||||
|
||||
test('should show test notification buttons when subscribed', async () => {
|
||||
const page = await context.newPage();
|
||||
await page.goto('/');
|
||||
await page.waitForLoadState('networkidle');
|
||||
expect(subscription).not.toBeNull();
|
||||
expect(subscription?.endpoint).toBeTruthy();
|
||||
expect(subscription?.endpoint).toContain('https://');
|
||||
expect(subscription?.hasKeys).toBe(true);
|
||||
|
||||
// Wait for service worker
|
||||
await page.waitForFunction(() => 'serviceWorker' in navigator);
|
||||
// Verify button text changed to "Disable Notifications"
|
||||
await expect(toggleButton).toHaveText(/disable notifications/i);
|
||||
|
||||
// Enable notifications first
|
||||
const toggleButton = page.getByRole('button', { name: /enable notifications/i });
|
||||
await toggleButton.click();
|
||||
await page.waitForTimeout(2000);
|
||||
await page.close();
|
||||
});
|
||||
|
||||
// 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 });
|
||||
test('should show test notification buttons when subscribed', async () => {
|
||||
const page = await context.newPage();
|
||||
await page.goto('/');
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
await expect(testSuccessButton).toBeVisible();
|
||||
await expect(testErrorButton).toBeVisible();
|
||||
await expect(testProgressButton).toBeVisible();
|
||||
// Wait for service worker
|
||||
await page.waitForFunction(() => 'serviceWorker' in navigator);
|
||||
|
||||
await page.close();
|
||||
});
|
||||
// Enable notifications first
|
||||
const toggleButton = page.getByRole('button', { name: /enable notifications/i });
|
||||
await toggleButton.click();
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
test('should send test notifications', async () => {
|
||||
const page = await context.newPage();
|
||||
await page.goto('/');
|
||||
await page.waitForLoadState('networkidle');
|
||||
// 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 });
|
||||
|
||||
// Wait for service worker
|
||||
await page.waitForFunction(() => 'serviceWorker' in navigator);
|
||||
await expect(testSuccessButton).toBeVisible();
|
||||
await expect(testErrorButton).toBeVisible();
|
||||
await expect(testProgressButton).toBeVisible();
|
||||
|
||||
// Enable notifications first
|
||||
const toggleButton = page.getByRole('button', { name: /enable notifications/i });
|
||||
await toggleButton.click();
|
||||
await page.waitForTimeout(2000);
|
||||
await page.close();
|
||||
});
|
||||
|
||||
// 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 })
|
||||
});
|
||||
});
|
||||
test('should send test notifications', async () => {
|
||||
const page = await context.newPage();
|
||||
await page.goto('/');
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
// Click test success button
|
||||
const testSuccessButton = page.getByRole('button', { name: /test success/i });
|
||||
await testSuccessButton.click();
|
||||
// Wait for service worker
|
||||
await page.waitForFunction(() => 'serviceWorker' in navigator);
|
||||
|
||||
// Wait for and verify success message
|
||||
const successMessage = page.getByText(/✓ test success notification sent/i);
|
||||
await expect(successMessage).toBeVisible({ timeout: 5000 });
|
||||
// Enable notifications first
|
||||
const toggleButton = page.getByRole('button', { name: /enable notifications/i });
|
||||
await toggleButton.click();
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
// Verify message contains subscriber count
|
||||
await expect(successMessage).toContainText('1 subscriber');
|
||||
// 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 })
|
||||
});
|
||||
});
|
||||
|
||||
// Wait for auto-dismiss
|
||||
await expect(successMessage).not.toBeVisible({ timeout: 4000 });
|
||||
// Click test success button
|
||||
const testSuccessButton = page.getByRole('button', { name: /test success/i });
|
||||
await testSuccessButton.click();
|
||||
|
||||
await page.close();
|
||||
});
|
||||
// Wait for and verify success message
|
||||
const successMessage = page.getByText(/✓ test success notification sent/i);
|
||||
await expect(successMessage).toBeVisible({ timeout: 5000 });
|
||||
|
||||
test('should unsubscribe from push notifications', async () => {
|
||||
const page = await context.newPage();
|
||||
await page.goto('/');
|
||||
await page.waitForLoadState('networkidle');
|
||||
// Verify message contains subscriber count
|
||||
await expect(successMessage).toContainText('1 subscriber');
|
||||
|
||||
// Wait for service worker
|
||||
await page.waitForFunction(() => 'serviceWorker' in navigator);
|
||||
// Wait for auto-dismiss
|
||||
await expect(successMessage).not.toBeVisible({ timeout: 4000 });
|
||||
|
||||
// First subscribe
|
||||
const toggleButton = page.getByRole('button', { name: /enable notifications/i });
|
||||
await toggleButton.click();
|
||||
await page.waitForTimeout(2000);
|
||||
await page.close();
|
||||
});
|
||||
|
||||
// Verify subscribed
|
||||
await expect(toggleButton).toHaveText(/disable notifications/i);
|
||||
test('should unsubscribe from push notifications', async () => {
|
||||
const page = await context.newPage();
|
||||
await page.goto('/');
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
// Now unsubscribe
|
||||
await toggleButton.click();
|
||||
await page.waitForTimeout(2000);
|
||||
// Wait for service worker
|
||||
await page.waitForFunction(() => 'serviceWorker' in navigator);
|
||||
|
||||
// Verify subscription was removed
|
||||
const subscription = await page.evaluate(async () => {
|
||||
const registration = await navigator.serviceWorker.ready;
|
||||
return await registration.pushManager.getSubscription();
|
||||
});
|
||||
// First subscribe
|
||||
const toggleButton = page.getByRole('button', { name: /enable notifications/i });
|
||||
await toggleButton.click();
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
expect(subscription).toBeNull();
|
||||
// Verify subscribed
|
||||
await expect(toggleButton).toHaveText(/disable notifications/i);
|
||||
|
||||
// Verify button text changed back
|
||||
await expect(toggleButton).toHaveText(/enable notifications/i);
|
||||
// Now unsubscribe
|
||||
await toggleButton.click();
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
// Verify test buttons are no longer visible
|
||||
const testSuccessButton = page.getByRole('button', { name: /test success/i });
|
||||
await expect(testSuccessButton).not.toBeVisible();
|
||||
// Verify subscription was removed
|
||||
const subscription = await page.evaluate(async () => {
|
||||
const registration = await navigator.serviceWorker.ready;
|
||||
return await registration.pushManager.getSubscription();
|
||||
});
|
||||
|
||||
await page.close();
|
||||
});
|
||||
expect(subscription).toBeNull();
|
||||
|
||||
test('should persist clientId in localStorage', async () => {
|
||||
const page = await context.newPage();
|
||||
await page.goto('/');
|
||||
await page.waitForLoadState('networkidle');
|
||||
// Verify button text changed back
|
||||
await expect(toggleButton).toHaveText(/enable notifications/i);
|
||||
|
||||
// Wait for service worker
|
||||
await page.waitForFunction(() => 'serviceWorker' in navigator);
|
||||
// Verify test buttons are no longer visible
|
||||
const testSuccessButton = page.getByRole('button', { name: /test success/i });
|
||||
await expect(testSuccessButton).not.toBeVisible();
|
||||
|
||||
// Enable notifications
|
||||
const toggleButton = page.getByRole('button', { name: /enable notifications/i });
|
||||
await toggleButton.click();
|
||||
await page.waitForTimeout(2000);
|
||||
await page.close();
|
||||
});
|
||||
|
||||
// Verify clientId is stored in localStorage
|
||||
const clientId = await page.evaluate(() => {
|
||||
return localStorage.getItem('push-client-id');
|
||||
});
|
||||
test('should persist clientId in localStorage', async () => {
|
||||
const page = await context.newPage();
|
||||
await page.goto('/');
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
expect(clientId).toBeTruthy();
|
||||
expect(clientId).toMatch(/^client_[a-f0-9-]+$/);
|
||||
// Wait for service worker
|
||||
await page.waitForFunction(() => 'serviceWorker' in navigator);
|
||||
|
||||
// Reload page and verify clientId persists
|
||||
await page.reload();
|
||||
await page.waitForLoadState('networkidle');
|
||||
// Enable notifications
|
||||
const toggleButton = page.getByRole('button', { name: /enable notifications/i });
|
||||
await toggleButton.click();
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
const persistedClientId = await page.evaluate(() => {
|
||||
return localStorage.getItem('push-client-id');
|
||||
});
|
||||
// Verify clientId is stored in localStorage
|
||||
const clientId = await page.evaluate(() => {
|
||||
return localStorage.getItem('push-client-id');
|
||||
});
|
||||
|
||||
expect(persistedClientId).toBe(clientId);
|
||||
expect(clientId).toBeTruthy();
|
||||
expect(clientId).toMatch(/^client_[a-f0-9-]+$/);
|
||||
|
||||
await page.close();
|
||||
});
|
||||
// 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();
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user