Implement Password Grant Flow for Authentication and Enhance User Experience

- Introduced Password Grant Flow for user authentication, allowing direct login with email and password.
- Updated `useAuth` composable to manage login and logout processes, including Single Sign-Out from Cidaas.
- Enhanced user interface with a new `UserMenu` component displaying user information and logout functionality.
- Updated homepage to show personalized greetings for logged-in users and a login prompt for guests.
- Added logout confirmation page with a countdown redirect to the homepage.
- Documented the implementation details and future enhancements for OAuth2 flows in CLAUDE.md and other relevant documentation.
- Added test credentials and guidelines for automated testing in the new TESTING.md file.
This commit is contained in:
Bastian Masanek
2025-11-01 15:23:08 +01:00
parent 83ba708023
commit cc35636d1a
40 changed files with 1843 additions and 31 deletions

View File

@@ -0,0 +1,81 @@
/**
* E2E Test: Authentication - Login Flow
*
* This is an EXAMPLE test showing how to use test credentials.
* To run this test:
*
* 1. Copy .env.example to .env
* 2. Set TEST_USER_EMAIL and TEST_USER_PASSWORD
* 3. Run: pnpm test:e2e
*
* @example
* ```bash
* # .env
* TEST_USER_EMAIL=bm@noxware.de
* TEST_USER_PASSWORD=%654321qQ!
* ```
*/
import { test, expect } from '@playwright/test'
test.describe('Authentication - Login Flow', () => {
test.beforeEach(async ({ page }) => {
// Navigate to auth page before each test
await page.goto('/auth')
})
test('should login with test credentials from environment', async ({ page }) => {
// Fetch test credentials from API endpoint
const response = await fetch('http://localhost:3000/api/test/credentials')
// Skip test if credentials not configured
if (!response.ok) {
test.skip()
return
}
const { email, password } = await response.json()
// Fill in login form
await page.fill('input[type="email"]', email)
await page.fill('input[type="password"]', password)
// Submit form
await page.click('button[type="submit"]')
// Wait for navigation to complete
await page.waitForURL('/')
// Verify we're on homepage
expect(page.url()).toBe('http://localhost:3000/')
// Optional: Verify user is logged in (check for user menu, etc.)
// await expect(page.locator('[data-testid="user-menu"]')).toBeVisible()
})
test('should show error with invalid credentials', async ({ page }) => {
// Fill in login form with invalid credentials
await page.fill('input[type="email"]', 'invalid@example.com')
await page.fill('input[type="password"]', 'wrongpassword')
// Submit form
await page.click('button[type="submit"]')
// Verify error message is shown
await expect(page.locator('[role="alert"]')).toBeVisible()
await expect(page.locator('[role="alert"]')).toContainText('Invalid credentials')
})
test('should validate email format', async ({ page }) => {
// Fill in invalid email
await page.fill('input[type="email"]', 'not-an-email')
await page.fill('input[type="password"]', 'somepassword')
// Submit form
await page.click('button[type="submit"]')
// Verify validation error
// Note: Exact selector depends on your validation error display
await expect(page.locator('text=Invalid email')).toBeVisible()
})
})