228 lines
8.1 KiB
TypeScript
228 lines
8.1 KiB
TypeScript
import { test, expect } from '@playwright/test';
|
|
import * as auth from '../fixtures/auth';
|
|
import * as assertions from '../utils/assertions';
|
|
import { LDAP_USERS, LOCAL_USERS } from '../fixtures/test-data';
|
|
|
|
test.describe('Login Workflow', () => {
|
|
const BASE_URL = process.env.BASE_URL || 'http://localhost:3000';
|
|
|
|
test.beforeEach(async ({ page }) => {
|
|
// Navigate to login page
|
|
await page.goto(BASE_URL);
|
|
// Wait for identity check overlay
|
|
await page.waitForSelector('[data-testid="identity-check-overlay"]', { timeout: 10000 });
|
|
});
|
|
|
|
test('should display identity check overlay on app load', async ({ page }) => {
|
|
const overlay = page.locator('[data-testid="identity-check-overlay"]');
|
|
await expect(overlay).toBeVisible();
|
|
|
|
// Verify tabs are available
|
|
const ldapTab = page.locator('[data-testid="ldap-login-tab"]');
|
|
const localTab = page.locator('[data-testid="local-login-tab"]');
|
|
|
|
await expect(ldapTab).toBeVisible();
|
|
await expect(localTab).toBeVisible();
|
|
});
|
|
|
|
test('should display login form with username and password fields', async ({ page }) => {
|
|
await assertions.assertLoginFormVisible(page);
|
|
});
|
|
|
|
test('should reject empty login credentials', async ({ page }) => {
|
|
const submitButton = page.locator('[data-testid="login-submit"]');
|
|
await submitButton.click();
|
|
|
|
// Should show validation error
|
|
const errorMessage = page.locator('[data-testid="toast-error"]');
|
|
await expect(errorMessage).toBeVisible({ timeout: 3000 });
|
|
});
|
|
|
|
test('should reject invalid LDAP credentials', async ({ page }) => {
|
|
await auth.loginWithLdap(page, LDAP_USERS.invalid, BASE_URL);
|
|
|
|
// Should show error message
|
|
const errorToast = page.locator('[data-testid="toast-error"]');
|
|
await expect(errorToast).toBeVisible({ timeout: 5000 });
|
|
|
|
// Should still be on login page
|
|
await expect(page).toHaveURL(BASE_URL);
|
|
});
|
|
|
|
test('should successfully login with valid LDAP credentials', async ({ page }) => {
|
|
// Skip if LDAP is not configured in test environment
|
|
test.skip(process.env.SKIP_LDAP === 'true', 'LDAP not available in test environment');
|
|
|
|
await auth.loginWithLdap(page, LDAP_USERS.valid, BASE_URL);
|
|
|
|
// Verify we're authenticated
|
|
await assertions.assertUserAuthenticated(page, BASE_URL);
|
|
|
|
// Verify token is stored
|
|
const token = await auth.getAuthToken(page);
|
|
expect(token).toBeTruthy();
|
|
});
|
|
|
|
test('should reject invalid local user credentials', async ({ page }) => {
|
|
// Switch to local user tab
|
|
const localTab = page.locator('[data-testid="local-login-tab"]');
|
|
await localTab.click();
|
|
|
|
// Try to login with invalid credentials
|
|
await page.fill('[data-testid="local-username-input"]', 'invalid_user');
|
|
await page.fill('[data-testid="local-password-input"]', 'wrong_password');
|
|
await page.click('[data-testid="local-login-submit"]');
|
|
|
|
// Should show error
|
|
const errorToast = page.locator('[data-testid="toast-error"]');
|
|
await expect(errorToast).toBeVisible({ timeout: 5000 });
|
|
});
|
|
|
|
test('should successfully login with valid local user credentials', async ({ page }) => {
|
|
// Switch to local user tab
|
|
const localTab = page.locator('[data-testid="local-login-tab"]');
|
|
await localTab.click();
|
|
|
|
// Login with valid credentials
|
|
await auth.loginWithLocalUser(page, LOCAL_USERS.admin, BASE_URL);
|
|
|
|
// Verify authenticated
|
|
await assertions.assertUserAuthenticated(page, BASE_URL);
|
|
});
|
|
|
|
test('should show user identity after successful login', async ({ page }) => {
|
|
await auth.loginWithLocalUser(page, LOCAL_USERS.admin, BASE_URL);
|
|
|
|
// Check that user info is displayed
|
|
const userDisplay = page.locator('[data-testid="user-display"]');
|
|
await expect(userDisplay).toBeVisible();
|
|
|
|
// Verify username is shown
|
|
const username = await userDisplay.textContent();
|
|
expect(username).toContain(LOCAL_USERS.admin.username);
|
|
});
|
|
|
|
test('should maintain session across page reloads', async ({ page }) => {
|
|
await auth.loginWithLocalUser(page, LOCAL_USERS.admin, BASE_URL);
|
|
await assertions.assertUserAuthenticated(page, BASE_URL);
|
|
|
|
// Reload page
|
|
await page.reload();
|
|
|
|
// Should still be authenticated
|
|
const token = await auth.getAuthToken(page);
|
|
expect(token).toBeTruthy();
|
|
|
|
// Should not be on login page
|
|
await expect(page).not.toHaveURL(BASE_URL);
|
|
});
|
|
|
|
test('should support logout functionality', async ({ page }) => {
|
|
// Login first
|
|
await auth.loginWithLocalUser(page, LOCAL_USERS.admin, BASE_URL);
|
|
await assertions.assertUserAuthenticated(page, BASE_URL);
|
|
|
|
// Logout
|
|
await auth.logout(page, BASE_URL);
|
|
|
|
// Should be back on login page
|
|
const identityOverlay = page.locator('[data-testid="identity-check-overlay"]');
|
|
await expect(identityOverlay).toBeVisible({ timeout: 5000 });
|
|
|
|
// Token should be cleared
|
|
const token = await auth.getAuthToken(page);
|
|
expect(token).toBeFalsy();
|
|
});
|
|
|
|
test('should show admin button for admin users', async ({ page }) => {
|
|
await auth.loginWithLocalUser(page, LOCAL_USERS.admin, BASE_URL);
|
|
await assertions.assertUserAuthenticated(page, BASE_URL);
|
|
|
|
// Admin button should be visible
|
|
const adminButton = page.locator('[data-testid="admin-button"]');
|
|
await expect(adminButton).toBeVisible();
|
|
});
|
|
|
|
test('should allow switching between LDAP and local login tabs', async ({ page }) => {
|
|
const ldapTab = page.locator('[data-testid="ldap-login-tab"]');
|
|
const localTab = page.locator('[data-testid="local-login-tab"]');
|
|
|
|
// Start on LDAP tab
|
|
let ldapForm = page.locator('[data-testid="ldap-login-form"]');
|
|
await expect(ldapForm).toBeVisible();
|
|
|
|
// Switch to local
|
|
await localTab.click();
|
|
ldapForm = page.locator('[data-testid="ldap-login-form"]');
|
|
await expect(ldapForm).not.toBeVisible();
|
|
|
|
// Switch back to LDAP
|
|
await ldapTab.click();
|
|
ldapForm = page.locator('[data-testid="ldap-login-form"]');
|
|
await expect(ldapForm).toBeVisible();
|
|
});
|
|
|
|
test('should remember login preference on revisit', async ({ page, context }) => {
|
|
// Login with local user
|
|
await auth.loginWithLocalUser(page, LOCAL_USERS.admin, BASE_URL);
|
|
|
|
// Close and reopen browser
|
|
await page.close();
|
|
const newPage = await context.newPage();
|
|
await newPage.goto(BASE_URL);
|
|
|
|
// Should still be authenticated
|
|
const authenticated = await auth.isAuthenticated(newPage);
|
|
expect(authenticated).toBe(true);
|
|
|
|
await newPage.close();
|
|
});
|
|
|
|
test('should handle network errors gracefully', async ({ page }) => {
|
|
// Enable offline mode
|
|
await page.context().setOffline(true);
|
|
|
|
// Try to login
|
|
const usernameInput = page.locator('[data-testid="username-input"]');
|
|
const passwordInput = page.locator('[data-testid="password-input"]');
|
|
const submitButton = page.locator('[data-testid="login-submit"]');
|
|
|
|
await usernameInput.fill(LOCAL_USERS.admin.username);
|
|
await passwordInput.fill(LOCAL_USERS.admin.password);
|
|
await submitButton.click();
|
|
|
|
// Should show network error
|
|
const errorToast = page.locator('[data-testid="toast-error"]');
|
|
await expect(errorToast).toBeVisible({ timeout: 5000 });
|
|
|
|
// Re-enable network
|
|
await page.context().setOffline(false);
|
|
});
|
|
|
|
test('should display user list in local login tab', async ({ page }) => {
|
|
const localTab = page.locator('[data-testid="local-login-tab"]');
|
|
await localTab.click();
|
|
|
|
// User list should be visible
|
|
const userList = page.locator('[data-testid="user-list"]');
|
|
await expect(userList).toBeVisible();
|
|
|
|
// Should have at least one user
|
|
const userItems = page.locator('[data-testid="user-list-item"]');
|
|
expect(await userItems.count()).toBeGreaterThan(0);
|
|
});
|
|
|
|
test('should auto-login when clicking user from list', async ({ page }) => {
|
|
const localTab = page.locator('[data-testid="local-login-tab"]');
|
|
await localTab.click();
|
|
|
|
// Click first user in list
|
|
const firstUser = page.locator('[data-testid="user-list-item"]').first();
|
|
await firstUser.click();
|
|
|
|
// Password input should be focused
|
|
const passwordInput = page.locator('[data-testid="local-password-input"]');
|
|
await expect(passwordInput).toBeFocused();
|
|
});
|
|
});
|