feat(test): implement comprehensive Playwright test suite
- Add complete E2E test coverage for authentication flows - Implement component interaction and navigation testing - Create responsive design validation across viewports - Add theme switching and visual regression testing - Include smoke tests for critical user paths - Configure Playwright with proper test setup Test suite ensures application reliability with automated validation of user flows, accessibility, and visual consistency. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
265
reactrebuild0825/tests/auth-realistic.spec.ts
Normal file
265
reactrebuild0825/tests/auth-realistic.spec.ts
Normal file
@@ -0,0 +1,265 @@
|
||||
import { test, expect, Page } from '@playwright/test';
|
||||
import path from 'path';
|
||||
|
||||
const DEMO_ACCOUNTS = {
|
||||
admin: { email: 'admin@example.com', password: 'demo123' },
|
||||
organizer: { email: 'organizer@example.com', password: 'demo123' },
|
||||
staff: { email: 'staff@example.com', password: 'demo123' },
|
||||
};
|
||||
|
||||
async function takeScreenshot(page: Page, name: string) {
|
||||
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
|
||||
const fileName = `auth_${name}_${timestamp}.png`;
|
||||
await page.screenshot({
|
||||
path: path.join('screenshots', fileName),
|
||||
fullPage: true
|
||||
});
|
||||
return fileName;
|
||||
}
|
||||
|
||||
async function clearAuthStorage(page: Page) {
|
||||
await page.evaluate(() => {
|
||||
localStorage.removeItem('bct_auth_user');
|
||||
localStorage.removeItem('bct_auth_remember');
|
||||
});
|
||||
}
|
||||
|
||||
test.describe('Authentication Flows (Realistic)', () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
// Clear any existing auth state
|
||||
await clearAuthStorage(page);
|
||||
await page.goto('/');
|
||||
});
|
||||
|
||||
test('should redirect to login when accessing protected route', async ({ page }) => {
|
||||
await page.goto('/dashboard');
|
||||
|
||||
// Should redirect to login page
|
||||
await expect(page).toHaveURL('/login');
|
||||
await expect(page.locator('h1')).toContainText('Black Canyon Tickets');
|
||||
await expect(page.locator('text=Sign in to your account')).toBeVisible();
|
||||
|
||||
await takeScreenshot(page, 'protected-route-redirect');
|
||||
});
|
||||
|
||||
test('should login successfully with valid admin credentials', async ({ page }) => {
|
||||
await page.goto('/login');
|
||||
await takeScreenshot(page, 'login-page-initial');
|
||||
|
||||
// Fill in admin credentials using form elements
|
||||
await page.fill('input[name="email"]', DEMO_ACCOUNTS.admin.email);
|
||||
await page.fill('input[name="password"]', DEMO_ACCOUNTS.admin.password);
|
||||
|
||||
await takeScreenshot(page, 'login-form-filled');
|
||||
|
||||
// Submit login form
|
||||
await page.click('button[type="submit"]');
|
||||
|
||||
// Wait for loading state
|
||||
await expect(page.locator('text=Signing in...')).toBeVisible();
|
||||
await takeScreenshot(page, 'login-loading-state');
|
||||
|
||||
// Should redirect to dashboard
|
||||
await expect(page).toHaveURL('/', { timeout: 10000 });
|
||||
|
||||
// Verify user is logged in by checking for user name in sidebar
|
||||
await expect(page.locator('text=Sarah Admin')).toBeVisible();
|
||||
|
||||
await takeScreenshot(page, 'dashboard-logged-in-admin');
|
||||
});
|
||||
|
||||
test('should login successfully with organizer credentials', async ({ page }) => {
|
||||
await page.goto('/login');
|
||||
|
||||
await page.fill('input[name="email"]', DEMO_ACCOUNTS.organizer.email);
|
||||
await page.fill('input[name="password"]', DEMO_ACCOUNTS.organizer.password);
|
||||
await page.click('button[type="submit"]');
|
||||
|
||||
await expect(page).toHaveURL('/', { timeout: 10000 });
|
||||
await expect(page.locator('text=John Organizer')).toBeVisible();
|
||||
|
||||
await takeScreenshot(page, 'dashboard-logged-in-organizer');
|
||||
});
|
||||
|
||||
test('should login successfully with staff credentials', async ({ page }) => {
|
||||
await page.goto('/login');
|
||||
|
||||
await page.fill('input[name="email"]', DEMO_ACCOUNTS.staff.email);
|
||||
await page.fill('input[name="password"]', DEMO_ACCOUNTS.staff.password);
|
||||
await page.click('button[type="submit"]');
|
||||
|
||||
await expect(page).toHaveURL('/', { timeout: 10000 });
|
||||
await expect(page.locator('text=Emma Staff')).toBeVisible();
|
||||
|
||||
await takeScreenshot(page, 'dashboard-logged-in-staff');
|
||||
});
|
||||
|
||||
test('should show error for invalid credentials', async ({ page }) => {
|
||||
await page.goto('/login');
|
||||
|
||||
await page.fill('input[name="email"]', 'invalid@example.com');
|
||||
await page.fill('input[name="password"]', 'wrongpassword');
|
||||
await page.click('button[type="submit"]');
|
||||
|
||||
// Should show error message
|
||||
await expect(page.locator('[role="alert"]')).toBeVisible();
|
||||
await expect(page.locator('text=Invalid email or password')).toBeVisible();
|
||||
|
||||
// Should remain on login page
|
||||
await expect(page).toHaveURL('/login');
|
||||
|
||||
await takeScreenshot(page, 'login-error-state');
|
||||
});
|
||||
|
||||
test('should toggle password visibility', async ({ page }) => {
|
||||
await page.goto('/login');
|
||||
|
||||
const passwordInput = page.locator('input[name="password"]');
|
||||
const toggleButton = page.locator('button[type="button"]').filter({ hasText: '' }); // Eye icon button
|
||||
|
||||
// Password should be hidden initially
|
||||
await expect(passwordInput).toHaveAttribute('type', 'password');
|
||||
|
||||
await page.fill('input[name="password"]', 'testpassword');
|
||||
await takeScreenshot(page, 'password-hidden');
|
||||
|
||||
// Click toggle to show password
|
||||
await toggleButton.click();
|
||||
await expect(passwordInput).toHaveAttribute('type', 'text');
|
||||
await takeScreenshot(page, 'password-visible');
|
||||
|
||||
// Click toggle to hide password again
|
||||
await toggleButton.click();
|
||||
await expect(passwordInput).toHaveAttribute('type', 'password');
|
||||
});
|
||||
|
||||
test('should remember login when remember me is checked', async ({ page }) => {
|
||||
await page.goto('/login');
|
||||
|
||||
await page.fill('input[name="email"]', DEMO_ACCOUNTS.admin.email);
|
||||
await page.fill('input[name="password"]', DEMO_ACCOUNTS.admin.password);
|
||||
|
||||
// Check remember me
|
||||
await page.check('input[name="rememberMe"]');
|
||||
await takeScreenshot(page, 'remember-me-checked');
|
||||
|
||||
await page.click('button[type="submit"]');
|
||||
await expect(page).toHaveURL('/', { timeout: 10000 });
|
||||
|
||||
// Verify localStorage has auth data
|
||||
const authData = await page.evaluate(() => localStorage.getItem('bct_auth_user'));
|
||||
const rememberMe = await page.evaluate(() => localStorage.getItem('bct_auth_remember'));
|
||||
|
||||
expect(authData).toBeTruthy();
|
||||
expect(rememberMe).toBe('true');
|
||||
|
||||
// Refresh page - should stay logged in
|
||||
await page.reload();
|
||||
await expect(page).toHaveURL('/');
|
||||
await expect(page.locator('text=Sarah Admin')).toBeVisible();
|
||||
|
||||
await takeScreenshot(page, 'persistent-login-after-refresh');
|
||||
});
|
||||
|
||||
test('should use demo account buttons', async ({ page }) => {
|
||||
await page.goto('/login');
|
||||
|
||||
// Click admin demo account button
|
||||
await page.click('text=Sarah Admin');
|
||||
|
||||
// Form should be filled
|
||||
await expect(page.locator('input[name="email"]')).toHaveValue(DEMO_ACCOUNTS.admin.email);
|
||||
await expect(page.locator('input[name="password"]')).toHaveValue('demo123');
|
||||
|
||||
await takeScreenshot(page, 'demo-account-filled');
|
||||
|
||||
// Submit and verify login
|
||||
await page.click('button[type="submit"]');
|
||||
await expect(page).toHaveURL('/', { timeout: 10000 });
|
||||
await expect(page.locator('text=Sarah Admin')).toBeVisible();
|
||||
|
||||
await takeScreenshot(page, 'demo-account-login-success');
|
||||
});
|
||||
|
||||
test('should validate empty form submission', async ({ page }) => {
|
||||
await page.goto('/login');
|
||||
|
||||
// Try to submit empty form
|
||||
await page.click('button[type="submit"]');
|
||||
|
||||
// Should show validation errors
|
||||
await expect(page.locator('text=Email is required')).toBeVisible();
|
||||
|
||||
await takeScreenshot(page, 'form-validation-errors');
|
||||
});
|
||||
|
||||
test('should validate password requirement', async ({ page }) => {
|
||||
await page.goto('/login');
|
||||
|
||||
// Fill email but not password
|
||||
await page.fill('input[name="email"]', DEMO_ACCOUNTS.admin.email);
|
||||
await page.click('button[type="submit"]');
|
||||
|
||||
await expect(page.locator('text=Password is required')).toBeVisible();
|
||||
|
||||
await takeScreenshot(page, 'password-required-error');
|
||||
});
|
||||
|
||||
test('should handle redirect after login', async ({ page }) => {
|
||||
// Try to access events page directly
|
||||
await page.goto('/events');
|
||||
|
||||
// Should redirect to login
|
||||
await expect(page).toHaveURL('/login');
|
||||
|
||||
// Login
|
||||
await page.fill('input[name="email"]', DEMO_ACCOUNTS.admin.email);
|
||||
await page.fill('input[name="password"]', DEMO_ACCOUNTS.admin.password);
|
||||
await page.click('button[type="submit"]');
|
||||
|
||||
// Should redirect back to events page (or dashboard for now)
|
||||
await expect(page).toHaveURL(/\/(events|dashboard|$)/, { timeout: 10000 });
|
||||
|
||||
await takeScreenshot(page, 'redirect-after-login');
|
||||
});
|
||||
|
||||
test('should show loading screen during initial auth check', async ({ page }) => {
|
||||
// Set up a user in localStorage to trigger auth loading
|
||||
await page.evaluate(() => {
|
||||
localStorage.setItem('bct_auth_user', JSON.stringify({
|
||||
id: 'test',
|
||||
email: 'admin@example.com',
|
||||
name: 'Test User'
|
||||
}));
|
||||
localStorage.setItem('bct_auth_remember', 'true');
|
||||
});
|
||||
|
||||
await page.goto('/');
|
||||
|
||||
// Should briefly show loading state
|
||||
const loading = page.locator('text=Loading...');
|
||||
if (await loading.isVisible()) {
|
||||
await takeScreenshot(page, 'auth-loading-screen');
|
||||
}
|
||||
|
||||
// Should eventually show dashboard or redirect to login
|
||||
await page.waitForTimeout(3000);
|
||||
await takeScreenshot(page, 'auth-check-complete');
|
||||
});
|
||||
|
||||
test('should handle demo account role display', async ({ page }) => {
|
||||
await page.goto('/login');
|
||||
|
||||
// Verify all demo accounts are shown with correct roles
|
||||
await expect(page.locator('text=Sarah Admin')).toBeVisible();
|
||||
await expect(page.locator('text=admin').first()).toBeVisible();
|
||||
|
||||
await expect(page.locator('text=John Organizer')).toBeVisible();
|
||||
await expect(page.locator('text=organizer')).toBeVisible();
|
||||
|
||||
await expect(page.locator('text=Emma Staff')).toBeVisible();
|
||||
await expect(page.locator('text=staff')).toBeVisible();
|
||||
|
||||
await takeScreenshot(page, 'demo-accounts-display');
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user