From 6cb692eb2b6a7fcdb37e14f76c01ffed051b53ca Mon Sep 17 00:00:00 2001 From: Daniel Bedeleanu Date: Sun, 19 Apr 2026 07:57:23 +0300 Subject: [PATCH] feat: create admin settings workflow e2e tests --- .../e2e/workflows/4-admin-settings.spec.ts | 332 ++++++++++++++++++ 1 file changed, 332 insertions(+) create mode 100644 frontend/e2e/workflows/4-admin-settings.spec.ts diff --git a/frontend/e2e/workflows/4-admin-settings.spec.ts b/frontend/e2e/workflows/4-admin-settings.spec.ts new file mode 100644 index 00000000..3b46657f --- /dev/null +++ b/frontend/e2e/workflows/4-admin-settings.spec.ts @@ -0,0 +1,332 @@ +import { test, expect } from '@playwright/test'; +import * as auth from '../fixtures/auth'; +import * as assertions from '../utils/assertions'; +import * as helpers from '../utils/helpers'; +import { LOCAL_USERS, TEST_CATEGORIES } from '../fixtures/test-data'; + +test.describe('Admin Settings Workflow', () => { + const BASE_URL = process.env.BASE_URL || 'http://localhost:3000'; + + test.beforeEach(async ({ page }) => { + // Navigate to app and login as admin + await page.goto(BASE_URL); + await auth.loginWithLocalUser(page, LOCAL_USERS.admin, BASE_URL); + await assertions.assertUserAuthenticated(page, BASE_URL); + + // Open admin panel + const adminButton = page.locator('[data-testid="admin-button"]'); + await adminButton.click(); + + // Wait for admin overlay to appear + await assertions.assertAdminDashboardVisible(page); + }); + + test('should display admin dashboard with all tabs', async ({ page }) => { + await assertions.assertAdminDashboardVisible(page); + + // Verify all tabs are present + const identityTab = page.locator('[data-testid="admin-tab-identity"]'); + const databaseTab = page.locator('[data-testid="admin-tab-database"]'); + const ldapTab = page.locator('[data-testid="admin-tab-ldap"]'); + const aiTab = page.locator('[data-testid="admin-tab-ai"]'); + const categoriesTab = page.locator('[data-testid="admin-tab-categories"]'); + + await expect(identityTab).toBeVisible(); + await expect(databaseTab).toBeVisible(); + await expect(ldapTab).toBeVisible(); + await expect(aiTab).toBeVisible(); + await expect(categoriesTab).toBeVisible(); + }); + + test('should display users in identity tab', async ({ page }) => { + const identityTab = page.locator('[data-testid="admin-tab-identity"]'); + await identityTab.click(); + + // User list should be displayed + const userList = page.locator('[data-testid="user-list"]'); + await expect(userList).toBeVisible(); + + // Should have at least one user (admin) + const userItems = page.locator('[data-testid="user-list-item"]'); + const count = await userItems.count(); + expect(count).toBeGreaterThanOrEqual(1); + }); + + test('should allow creating new user', async ({ page }) => { + const identityTab = page.locator('[data-testid="admin-tab-identity"]'); + await identityTab.click(); + + // Click add user button + const addUserButton = page.locator('[data-testid="add-user-button"]'); + await addUserButton.click(); + + // Modal should appear + const modal = page.locator('[data-testid="create-user-modal"]'); + await expect(modal).toBeVisible(); + + // Fill form + await page.fill('[data-testid="new-user-name"]', 'TestUser123'); + await page.fill('[data-testid="new-user-password"]', 'Password123!'); + + // Submit + const submitButton = page.locator('[data-testid="create-user-submit"]'); + await submitButton.click(); + + // Should show success + const successToast = page.locator('[data-testid="toast-success"]'); + await expect(successToast).toBeVisible({ timeout: 5000 }); + }); + + test('should allow deleting user with confirmation', async ({ page }) => { + const identityTab = page.locator('[data-testid="admin-tab-identity"]'); + await identityTab.click(); + + // Find a non-admin user to delete + const deleteButtons = page.locator('[data-testid="delete-user-button"]'); + if (await deleteButtons.count() > 0) { + // Click delete on first user + await deleteButtons.first().click(); + + // Confirmation should appear + const confirmDialog = page.locator('[data-testid="confirmation-modal"]'); + await expect(confirmDialog).toBeVisible(); + + // Confirm deletion + const confirmButton = page.locator('[data-testid="confirm-action"]'); + await confirmButton.click(); + + // Should show success + const successToast = page.locator('[data-testid="toast-success"]'); + await expect(successToast).toBeVisible({ timeout: 5000 }); + } + }); + + test('should display database info in database tab', async ({ page }) => { + const databaseTab = page.locator('[data-testid="admin-tab-database"]'); + await databaseTab.click(); + + // Database info should be displayed + const dbInfo = page.locator('[data-testid="database-info"]'); + await expect(dbInfo).toBeVisible(); + + // Should show stats + const itemCount = page.locator('[data-testid="item-count"]'); + if (await itemCount.isVisible()) { + const count = await itemCount.textContent(); + expect(count).toMatch(/\d+/); + } + }); + + test('should allow backup creation', async ({ page }) => { + const databaseTab = page.locator('[data-testid="admin-tab-database"]'); + await databaseTab.click(); + + // Backup button should be present + const backupButton = page.locator('[data-testid="backup-button"]'); + if (await backupButton.isVisible()) { + await backupButton.click(); + + // Should show progress or success + const progressOrSuccess = page.locator( + '[data-testid="backup-progress"], [data-testid="backup-success"]' + ); + await expect(progressOrSuccess).toBeVisible({ timeout: 10000 }); + } + }); + + test('should display LDAP configuration in ldap tab', async ({ page }) => { + const ldapTab = page.locator('[data-testid="admin-tab-ldap"]'); + await ldapTab.click(); + + // LDAP config should be displayed + const ldapConfig = page.locator('[data-testid="ldap-config"]'); + await expect(ldapConfig).toBeVisible(); + }); + + test('should allow enabling/disabling LDAP', async ({ page }) => { + const ldapTab = page.locator('[data-testid="admin-tab-ldap"]'); + await ldapTab.click(); + + // Toggle LDAP + const ldapToggle = page.locator('[data-testid="ldap-enabled-toggle"]'); + if (await ldapToggle.isVisible()) { + const initialState = await ldapToggle.isChecked(); + + // Click toggle + await ldapToggle.click(); + + // Verify state changed + const newState = await ldapToggle.isChecked(); + expect(newState).not.toBe(initialState); + } + }); + + test('should allow saving LDAP settings', async ({ page }) => { + const ldapTab = page.locator('[data-testid="admin-tab-ldap"]'); + await ldapTab.click(); + + // Modify LDAP setting + const ldapServerInput = page.locator('[data-testid="ldap-server-input"]'); + if (await ldapServerInput.isVisible()) { + const currentValue = await ldapServerInput.inputValue(); + await ldapServerInput.fill('ldap.example.com'); + + // Save + const saveButton = page.locator('[data-testid="save-settings-button"]'); + await saveButton.click(); + + // Should show success + const successToast = page.locator('[data-testid="toast-success"]'); + await expect(successToast).toBeVisible({ timeout: 5000 }); + } + }); + + test('should display AI configuration in ai tab', async ({ page }) => { + const aiTab = page.locator('[data-testid="admin-tab-ai"]'); + await aiTab.click(); + + // AI config should be displayed + const aiConfig = page.locator('[data-testid="ai-config"]'); + await expect(aiConfig).toBeVisible(); + + // Provider selection should be visible + const providerSelect = page.locator('[data-testid="ai-provider-select"]'); + await expect(providerSelect).toBeVisible(); + }); + + test('should allow selecting AI provider', async ({ page }) => { + const aiTab = page.locator('[data-testid="admin-tab-ai"]'); + await aiTab.click(); + + const providerSelect = page.locator('[data-testid="ai-provider-select"]'); + const options = page.locator('[data-testid="provider-option"]'); + + if (await options.count() > 1) { + // Select second option + await options.nth(1).click(); + + // Should trigger save + const successToast = page.locator('[data-testid="toast-success"]'); + if (await successToast.isVisible({ timeout: 1000 }).catch(() => false)) { + await expect(successToast).toBeVisible(); + } + } + }); + + test('should allow entering API keys', async ({ page }) => { + const aiTab = page.locator('[data-testid="admin-tab-ai"]'); + await aiTab.click(); + + // API key input should be present + const apiKeyInput = page.locator('[data-testid="ai-api-key-input"]'); + if (await apiKeyInput.isVisible()) { + await apiKeyInput.fill('test-api-key-12345'); + + // Key should be masked + const inputType = await apiKeyInput.getAttribute('type'); + expect(inputType).toBe('password'); + + // Save + const saveButton = page.locator('[data-testid="save-settings-button"]'); + if (await saveButton.isVisible()) { + await saveButton.click(); + } + } + }); + + test('should display categories list in categories tab', async ({ page }) => { + const categoriesTab = page.locator('[data-testid="admin-tab-categories"]'); + await categoriesTab.click(); + + // Categories list should be displayed + const categoryList = page.locator('[data-testid="category-list"]'); + await expect(categoryList).toBeVisible(); + + // Should have category items + const categoryItems = page.locator('[data-testid="category-item"]'); + const count = await categoryItems.count(); + expect(count).toBeGreaterThanOrEqual(1); + }); + + test('should allow adding new category', async ({ page }) => { + const categoriesTab = page.locator('[data-testid="admin-tab-categories"]'); + await categoriesTab.click(); + + // Add category button + const addButton = page.locator('[data-testid="add-category-button"]'); + if (await addButton.isVisible()) { + await addButton.click(); + + // Form should appear + const categoryForm = page.locator('[data-testid="category-form"]'); + await expect(categoryForm).toBeVisible(); + + // Fill form + const nameInput = page.locator('[data-testid="category-name-input"]'); + await nameInput.fill('New Category'); + + // Submit + const submitButton = page.locator('[data-testid="add-category-submit"]'); + await submitButton.click(); + + // Should show success + const successToast = page.locator('[data-testid="toast-success"]'); + await expect(successToast).toBeVisible({ timeout: 5000 }); + } + }); + + test('should allow deleting category', async ({ page }) => { + const categoriesTab = page.locator('[data-testid="admin-tab-categories"]'); + await categoriesTab.click(); + + // Delete button + const deleteButtons = page.locator('[data-testid="delete-category-button"]'); + if (await deleteButtons.count() > 0) { + await deleteButtons.first().click(); + + // Confirmation should appear + const confirmDialog = page.locator('[data-testid="confirmation-modal"]'); + await expect(confirmDialog).toBeVisible(); + + // Confirm + const confirmButton = page.locator('[data-testid="confirm-action"]'); + await confirmButton.click(); + + // Should show success + const successToast = page.locator('[data-testid="toast-success"]'); + await expect(successToast).toBeVisible({ timeout: 5000 }); + } + }); + + test('should close admin dashboard', async ({ page }) => { + // Close button should be present + const closeButton = page.locator('[data-testid="close-admin-overlay"]'); + if (await closeButton.isVisible()) { + await closeButton.click(); + + // Admin overlay should close + const adminOverlay = page.locator('[data-testid="admin-overlay"]'); + await expect(adminOverlay).not.toBeVisible({ timeout: 3000 }); + } + }); + + test('should prevent non-admin users from accessing admin panel', async ({ page }) => { + // Login as regular user first + await page.goto(BASE_URL); + await auth.logout(page, BASE_URL); + + // Login with regular user (if available) + await page.goto(BASE_URL); + // Try to access admin endpoint directly + await page.goto(`${BASE_URL}/admin`); + + // Should be redirected or show error + const adminOverlay = page.locator('[data-testid="admin-overlay"]'); + const errorMessage = page.locator('[data-testid="unauthorized-error"]'); + + const isBlocked = !(await adminOverlay.isVisible().catch(() => false)) || + (await errorMessage.isVisible().catch(() => false)); + + expect(isBlocked).toBe(true); + }); +});