veza/apps/web/e2e/cross-browser.spec.ts
2026-01-07 19:39:21 +01:00

302 lines
11 KiB
TypeScript

/* eslint-disable no-console */
import { test, expect } from '@playwright/test';
import { TEST_CONFIG } from './utils/test-helpers';
/**
* Cross-Browser Tests
*
* These tests verify that core functionality works across different browsers:
* - Chromium (Chrome, Edge)
* - Firefox
* - WebKit (Safari)
*
* These tests run on all browsers configured in playwright.config.ts
*
* To run cross-browser tests:
* - Run: npx playwright test cross-browser
* - Run on specific browser: npx playwright test cross-browser --project=firefox
*/
test.describe('Cross-Browser Compatibility', () => {
// Use authenticated state for most tests
test.use({ storageState: 'e2e/.auth/user.json' });
test.describe('Authentication', () => {
test('should login successfully on all browsers', async ({ page, browserName }) => {
// Use unauthenticated state for login test
await page.context().clearCookies();
await page.goto(`${TEST_CONFIG.FRONTEND_URL}/login`);
await page.waitForLoadState('networkidle');
// Wait for form to be ready
await page.waitForSelector('form', { timeout: 5000 });
await page.waitForTimeout(500);
// Fill login form
await page.fill('input[type="email"], input[name="email"]', TEST_CONFIG.TEST_USER_EMAIL);
await page.fill('input[type="password"], input[name="password"]', TEST_CONFIG.TEST_USER_PASSWORD);
// Submit form
await page.click('button[type="submit"], button:has-text("Login"), button:has-text("Sign in")');
// Wait for navigation to dashboard
await page.waitForURL('**/dashboard', { timeout: 10000 });
// Verify we're on dashboard
expect(page.url()).toContain('/dashboard');
console.log(`✅ Login successful on ${browserName}`);
});
test('should display login form correctly on all browsers', async ({ page, browserName }) => {
await page.context().clearCookies();
await page.goto(`${TEST_CONFIG.FRONTEND_URL}/login`);
await page.waitForLoadState('networkidle');
// Check that form elements are visible
const emailInput = page.locator('input[type="email"], input[name="email"]').first();
const passwordInput = page.locator('input[type="password"], input[name="password"]').first();
const submitButton = page.locator('button[type="submit"]').first();
await expect(emailInput).toBeVisible();
await expect(passwordInput).toBeVisible();
await expect(submitButton).toBeVisible();
console.log(`✅ Login form displayed correctly on ${browserName}`);
});
});
test.describe('Navigation', () => {
test('should navigate between pages on all browsers', async ({ page, browserName }) => {
await page.goto(`${TEST_CONFIG.FRONTEND_URL}/dashboard`);
await page.waitForLoadState('networkidle');
// Navigate to profile
await page.click('a[href="/profile"], a[href*="profile"]', { timeout: 5000 });
await page.waitForURL('**/profile', { timeout: 5000 });
expect(page.url()).toContain('/profile');
// Navigate back to dashboard
await page.click('a[href="/dashboard"], a[href*="dashboard"]', { timeout: 5000 });
await page.waitForURL('**/dashboard', { timeout: 5000 });
expect(page.url()).toContain('/dashboard');
console.log(`✅ Navigation works on ${browserName}`);
});
test('should handle browser back/forward buttons', async ({ page, browserName }) => {
await page.goto(`${TEST_CONFIG.FRONTEND_URL}/dashboard`);
await page.waitForLoadState('networkidle');
// Navigate to profile
await page.click('a[href="/profile"], a[href*="profile"]', { timeout: 5000 });
await page.waitForURL('**/profile', { timeout: 5000 });
// Use browser back button
await page.goBack();
await page.waitForURL('**/dashboard', { timeout: 5000 });
expect(page.url()).toContain('/dashboard');
// Use browser forward button
await page.goForward();
await page.waitForURL('**/profile', { timeout: 5000 });
expect(page.url()).toContain('/profile');
console.log(`✅ Browser navigation works on ${browserName}`);
});
});
test.describe('UI Components', () => {
test('should render buttons correctly on all browsers', async ({ page, browserName }) => {
await page.goto(`${TEST_CONFIG.FRONTEND_URL}/dashboard`);
await page.waitForLoadState('networkidle');
// Find buttons on the page
const buttons = page.locator('button').first();
await expect(buttons).toBeVisible();
// Check button styling (basic check)
const buttonStyles = await buttons.evaluate((el) => {
const styles = window.getComputedStyle(el);
return {
display: styles.display,
visibility: styles.visibility,
};
});
expect(buttonStyles.display).not.toBe('none');
expect(buttonStyles.visibility).not.toBe('hidden');
console.log(`✅ Buttons render correctly on ${browserName}`);
});
test('should render forms correctly on all browsers', async ({ page, browserName }) => {
await page.goto(`${TEST_CONFIG.FRONTEND_URL}/profile`);
await page.waitForLoadState('networkidle');
// Wait for form elements
await page.waitForTimeout(1000);
// Check for input fields
const inputs = page.locator('input, textarea, select');
const inputCount = await inputs.count();
// Should have at least some form elements
expect(inputCount).toBeGreaterThan(0);
console.log(`✅ Forms render correctly on ${browserName}`);
});
});
test.describe('JavaScript Features', () => {
test('should support ES6+ features on all browsers', async ({ page, browserName }) => {
const result = await page.evaluate(() => {
// Test various ES6+ features
const features = {
arrowFunctions: typeof (() => { }) === 'function',
promises: typeof Promise !== 'undefined',
asyncAwait: typeof (async () => { }) === 'function',
templateLiterals: typeof `test` === 'string',
destructuring: (() => {
try {
const { a } = { a: 1 };
return a === 1;
} catch {
return false;
}
})(),
spreadOperator: (() => {
try {
const arr = [...[1, 2, 3]];
return arr.length === 3;
} catch {
return false;
}
})(),
};
return features;
});
// All modern browsers should support these features
expect(result.arrowFunctions).toBe(true);
expect(result.promises).toBe(true);
expect(result.asyncAwait).toBe(true);
expect(result.templateLiterals).toBe(true);
expect(result.destructuring).toBe(true);
expect(result.spreadOperator).toBe(true);
console.log(`✅ ES6+ features supported on ${browserName}`);
});
test('should support Web APIs on all browsers', async ({ page, browserName }) => {
const result = await page.evaluate(() => {
return {
fetch: typeof fetch !== 'undefined',
localStorage: typeof localStorage !== 'undefined',
sessionStorage: typeof sessionStorage !== 'undefined',
webSocket: typeof WebSocket !== 'undefined',
history: typeof window.history !== 'undefined' && typeof window.history.pushState === 'function',
};
});
// All modern browsers should support these APIs
expect(result.fetch).toBe(true);
expect(result.localStorage).toBe(true);
expect(result.sessionStorage).toBe(true);
expect(result.webSocket).toBe(true);
expect(result.history).toBe(true);
console.log(`✅ Web APIs supported on ${browserName}`);
});
});
test.describe('CSS Features', () => {
test('should support modern CSS features on all browsers', async ({ page, browserName }) => {
const result = await page.evaluate(() => {
const testElement = document.createElement('div');
testElement.style.cssText = 'display: flex; grid-template-columns: 1fr; transform: translateX(0);';
document.body.appendChild(testElement);
const styles = window.getComputedStyle(testElement);
const supported = {
flexbox: styles.display === 'flex' || styles.display === '-webkit-flex',
grid: styles.gridTemplateColumns !== undefined,
transform: styles.transform !== 'none' || styles.webkitTransform !== 'none',
};
document.body.removeChild(testElement);
return supported;
});
// All modern browsers should support these CSS features
expect(result.flexbox).toBe(true);
expect(result.grid).toBe(true);
expect(result.transform).toBe(true);
console.log(`✅ Modern CSS features supported on ${browserName}`);
});
});
test.describe('Responsive Design', () => {
test('should be responsive on all browsers', async ({ page, browserName }) => {
// Test mobile viewport
await page.setViewportSize({ width: 375, height: 667 });
await page.goto(`${TEST_CONFIG.FRONTEND_URL}/dashboard`);
await page.waitForLoadState('networkidle');
// Check that page is visible and not broken
const body = page.locator('body');
await expect(body).toBeVisible();
// Test tablet viewport
await page.setViewportSize({ width: 768, height: 1024 });
await page.reload();
await page.waitForLoadState('networkidle');
await expect(body).toBeVisible();
// Test desktop viewport
await page.setViewportSize({ width: 1920, height: 1080 });
await page.reload();
await page.waitForLoadState('networkidle');
await expect(body).toBeVisible();
console.log(`✅ Responsive design works on ${browserName}`);
});
});
test.describe('Error Handling', () => {
test('should handle errors gracefully on all browsers', async ({ page, browserName }) => {
// Navigate to a non-existent page
await page.goto(`${TEST_CONFIG.FRONTEND_URL}/non-existent-page-12345`);
await page.waitForLoadState('networkidle');
// Should show 404 page or error message, not blank page
const body = page.locator('body');
const bodyText = await body.textContent();
expect(bodyText).not.toBe('');
expect(bodyText).not.toBeNull();
console.log(`✅ Error handling works on ${browserName}`);
});
});
test.describe('Performance', () => {
test('should load pages within acceptable time on all browsers', async ({ page, browserName }) => {
const startTime = Date.now();
await page.goto(`${TEST_CONFIG.FRONTEND_URL}/dashboard`);
await page.waitForLoadState('networkidle');
const loadTime = Date.now() - startTime;
// Should load within 10 seconds (generous threshold for cross-browser)
expect(loadTime).toBeLessThan(10000);
console.log(`✅ Page loaded in ${loadTime}ms on ${browserName}`);
});
});
});