Files
euchre_camp/e2e/epic1-auth-logout.test.ts
2026-04-26 19:13:38 -07:00

209 lines
7.1 KiB
TypeScript

/**
* Epic 1: Authentication & User Management
* Acceptance Test: User Logout
*
* User Story: As a logged-in user, I want to log out so that I can secure my account
*
* Acceptance Criteria:
* - Logout button in navigation
* - Session cleared on logout
* - Redirect to home page
*/
import { test, expect } from '@playwright/test';
import { prisma } from '@/lib/prisma';
function getTestCredentials() {
const timestamp = Date.now();
return {
email: `logout-test-${timestamp}@example.com`,
password: 'TestPassword1234!',
name: `Logout Test User ${timestamp}`
};
}
test.describe.serial('Epic 1: User Logout', () => {
let testEmail: string;
let testPassword: string;
let testName: string;
test.beforeAll(async () => {
const credentials = getTestCredentials();
testEmail = credentials.email;
testPassword = credentials.password;
testName = credentials.name;
// Create test user via API with proper origin header
const response = await fetch('http://localhost:3000/api/auth/sign-up/email', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Origin': 'http://localhost:3000',
'X-Requested-With': 'XMLHttpRequest'
},
body: JSON.stringify({
email: testEmail,
password: testPassword,
name: testName
})
});
if (!response.ok) {
const errorText = await response.text();
console.error('Failed to create user:', response.status, errorText);
throw new Error(`Failed to create user: ${response.status}`);
}
const data = await response.json();
console.log('User created via API:', data.user?.email);
// Wait for the database hook to complete (creating Player record)
await new Promise(resolve => setTimeout(resolve, 2000));
// Verify the user was created in the database
const user = await prisma.user.findUnique({
where: { email: testEmail }
});
if (!user) {
throw new Error(`User ${testEmail} was not created in database`);
}
if (!user.playerId) {
throw new Error(`User ${testEmail} does not have a playerId (database hook may not have run)`);
}
console.log(`User ${testEmail} created with playerId: ${user.playerId}`);
});
test.afterAll(async () => {
try {
const user = await prisma.user.findUnique({
where: { email: testEmail }
});
if (user) {
await prisma.user.delete({ where: { id: user.id } });
}
} catch (error) {
console.error('Cleanup error:', error);
}
});
test('Logout button appears in navigation when logged in', async ({ page }) => {
// Login first
await page.goto('http://localhost:3000/auth/login');
// Wait for page to load
await page.waitForLoadState('domcontentloaded');
await page.waitForSelector('form');
await page.waitForSelector('button[type="submit"]:not([disabled])');
await page.fill('input[name="email"]', testEmail);
await page.fill('input[name="password"]', testPassword);
// Wait for redirect to admin or player profile after clicking submit
const [response] = await Promise.all([
page.waitForResponse(response =>
response.url().includes('/api/auth/sign-in/email') && response.status() === 200,
{ timeout: 10000 }
),
page.click('button[type="submit"]')
]);
console.log('Login response:', response.status());
// Wait for redirect
await page.waitForURL(/\/(admin|players)/, { timeout: 10000 });
console.log('After login URL:', page.url());
// Check cookies
const cookies = await page.context().cookies();
console.log('Cookies after login:', cookies.map(c => `${c.name}=${c.value.substring(0, 20)}...`).join(', '));
// Check if better-auth.session_token exists
const sessionCookie = cookies.find(c => c.name.includes('session'));
console.log('Session cookie:', sessionCookie ? `${sessionCookie.name}=${sessionCookie.value.substring(0, 20)}...` : 'NOT FOUND');
// Navigate to home page to check navigation (session should persist)
// Use reload to ensure session is read from cookies
await page.reload();
await page.waitForLoadState('domcontentloaded');
// Wait a moment for the navigation component to update
await page.waitForTimeout(1000);
// Debug: Check what's on the page
const pageContent = await page.content();
console.log('Page content contains Sign out:', pageContent.includes('Sign out'));
console.log('Page content contains Sign in:', pageContent.includes('Sign in'));
console.log('Page content length:', pageContent.length);
console.log('Current URL:', page.url());
console.log('Page HTML snippet:', pageContent.substring(0, 500));
// Wait for the Navigation component to load and render
await page.waitForSelector('nav', { timeout: 5000 });
// Wait for the session to be loaded (check for logout button directly)
await page.waitForSelector('text=Sign out', { timeout: 10000 });
// Check for logout button
const logoutButton = await page.locator('text=Sign out').count();
console.log('Logout button count:', logoutButton);
expect(logoutButton).toBeGreaterThan(0);
});
test('Logout clears session and redirects to home', async ({ page }) => {
// Login first
await page.goto('http://localhost:3000/auth/login');
await page.fill('input[name="email"]', testEmail);
await page.fill('input[name="password"]', testPassword);
await page.click('button[type="submit"]');
// Wait for redirect to admin or player profile (indicates successful login)
await page.waitForURL(/\/(admin|players)/, { timeout: 10000 });
// Navigate to home using reload to ensure session is loaded
await page.reload();
await page.waitForLoadState('domcontentloaded');
// Wait for logout button to appear
await page.waitForSelector('text=Sign out', { timeout: 10000 });
// Click logout
await page.click('text=Sign out');
// Wait for redirect to login page
await page.waitForURL('**/auth/login**', { timeout: 10000 });
});
test('After logout, protected pages redirect to login', async ({ page }) => {
// Login first
await page.goto('http://localhost:3000/auth/login');
await page.fill('input[name="email"]', testEmail);
await page.fill('input[name="password"]', testPassword);
await page.click('button[type="submit"]');
// Wait for redirect to admin or player profile (indicates successful login)
await page.waitForURL(/\/(admin|players)/, { timeout: 10000 });
// Navigate to home using reload to ensure session is loaded
await page.reload();
await page.waitForLoadState('domcontentloaded');
// Wait for logout button to appear
await page.waitForSelector('text=Sign out', { timeout: 10000 });
// Logout
await page.click('text=Sign out');
await page.waitForURL('**/auth/login**', { timeout: 10000 });
// Try to access admin page
await page.goto('http://localhost:3000/admin');
// Should redirect to login
await expect(page).toHaveURL(/.*auth\/login.*/);
});
});