Files
tfm_ainventory/frontend/e2e/workflows/1-login.spec.ts

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();
});
});