/** * Acceptance Test: Account Creation, Login, and Deletion (UI-based) * * This test demonstrates the full workflow using the UI: * 1. Create a test account via registration * 2. Log in using the authentication UI * 3. Delete the test account */ import { test, expect } from '@playwright/test'; import { prisma } from '@/lib/prisma'; // Generate unique test account credentials function getTestCredentials() { const timestamp = Date.now(); return { email: `test-${timestamp}@example.com`, password: 'TestPassword1234!', name: `Test User ${timestamp}` }; } test.describe.serial('Account Lifecycle Acceptance Test', () => { let testEmail: string; let testPassword: string; let testName: string; test.beforeAll(async () => { const credentials = getTestCredentials(); testEmail = credentials.email; testPassword = credentials.password; testName = credentials.name; }); test.afterAll(async () => { // Clean up: delete test user if they still exist try { const user = await prisma.user.findUnique({ where: { email: testEmail } }); if (user) { await prisma.user.delete({ where: { id: user.id } }); console.log(`Cleaned up test user: ${testEmail}`); } } catch (error) { console.error('Cleanup error:', error); } }); /** * Test 1: Create test account via registration * Uses the unauthenticated project (no storage state) */ test('1. Create test account via registration', async ({ page }) => { // Navigate to registration page await page.goto('/auth/register'); // Wait for JavaScript to be ready await page.waitForLoadState('networkidle'); // Wait for the form to be visible and the submit button to be enabled await page.waitForSelector('form'); await page.waitForSelector('button[type="submit"]:not([disabled])'); // Fill in registration form await page.fill('input[name="name"]', testName); await page.fill('input[name="email"]', testEmail); await page.fill('input[name="password"]', testPassword); // Submit the form await page.click('button[type="submit"]'); // Wait for redirect to player profile (regular users are redirected to their profile) await page.waitForURL(/\/players\/\d+\/profile/, { timeout: 10000 }); // Wait a moment for the user to be saved to database await page.waitForTimeout(1000); // Verify user was created in database const user = await prisma.user.findUnique({ where: { email: testEmail } }); expect(user).not.toBeNull(); expect(user?.email).toBe(testEmail); expect(user?.role).toBe('player'); }); /** * Test 2: Log in with test account * Uses the unauthenticated project (no storage state) */ test('2. Log in with test account', async ({ page }) => { // Navigate to login page await page.goto('/auth/login'); // Fill in login form await page.fill('input[name="email"]', testEmail); await page.fill('input[name="password"]', testPassword); // Submit the form await page.click('button[type="submit"]'); // Wait for redirect to admin or player profile await page.waitForURL(/\/(admin|players)/, { timeout: 10000 }); // Reload to ensure session is loaded from cookies await page.reload(); await page.waitForLoadState('networkidle'); // Wait for logout button to appear await page.waitForSelector('text=Sign out', { timeout: 10000 }); // Check for user's email or name in the navigation const userEmail = await page.locator(`text=${testEmail}`).count(); const userName = await page.locator(`text=${testName}`).count(); const logoutButton = await page.locator('text=Sign out').count(); // At least one of these should be present if logged in expect(userEmail + userName + logoutButton).toBeGreaterThan(0); }); /** * Test 3: Delete test account * Uses the authenticated project (admin) */ test('3. Delete test account', async () => { // For now, we'll delete via direct database access // In a real scenario, this would be done via an admin API endpoint const user = await prisma.user.findUnique({ where: { email: testEmail } }); if (user) { await prisma.user.delete({ where: { id: user.id } }); console.log(`Test user deleted: ${testEmail}`); } // Verify user was deleted const deletedUser = await prisma.user.findUnique({ where: { email: testEmail } }); expect(deletedUser).toBeNull(); }); });