From 97865bf862acc28fdfd7b00e8bf5285dae358f85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A1n=20Vor=C4=8D=C3=A1k?= Date: Sat, 27 Dec 2025 20:17:56 +0100 Subject: [PATCH 1/3] Modified e2e tests so that they pass --- .../src/components/pages/acls/acl-list.tsx | 22 +- .../console/acls/user-management.spec.ts | 264 ++++++++++++++++++ 2 files changed, 281 insertions(+), 5 deletions(-) create mode 100644 frontend/tests/console/acls/user-management.spec.ts diff --git a/frontend/src/components/pages/acls/acl-list.tsx b/frontend/src/components/pages/acls/acl-list.tsx index ec2cdd926..8bc28d251 100644 --- a/frontend/src/components/pages/acls/acl-list.tsx +++ b/frontend/src/components/pages/acls/acl-list.tsx @@ -40,6 +40,7 @@ import { EditIcon, MoreHorizontalIcon, TrashIcon } from 'components/icons'; import { isServerless } from 'config'; import { makeObservable, observable } from 'mobx'; import { observer } from 'mobx-react'; +import { parseAsString } from 'nuqs'; import { ACL_Operation, ACL_PermissionType, @@ -65,6 +66,7 @@ import { AclPrincipalGroupEditor } from './principal-group-editor'; import { ChangePasswordModal, ChangeRolesModal } from './user-edit-modals'; import { UserRoleTags } from './user-permission-assignments'; import ErrorResult from '../../../components/misc/error-result'; +import { useQueryStateWithCallback } from '../../../hooks/use-query-state-with-callback'; import { useDeleteAclMutation, useListACLAsPrincipalGroups } from '../../../react-query/api/acl'; import { appGlobal } from '../../../state/app-global'; import { api, rolesApi } from '../../../state/backend-api'; @@ -315,13 +317,24 @@ const PermissionsListTab = observer(() => { }); const UsersTab = observer(() => { + const [searchQuery, setSearchQuery] = useQueryStateWithCallback( + { + onUpdate: () => { + // Query state is managed by the URL + }, + getDefaultValue: () => '', + }, + 'q', + parseAsString.withDefault('') + ); + const users: UsersEntry[] = (api.serviceAccounts?.users ?? []).map((u) => ({ name: u, type: 'SERVICE_ACCOUNT', })); const usersFiltered = users.filter((u) => { - const filter = uiSettings.aclList.usersTab.quickSearch; + const filter = searchQuery; if (!filter) { return true; } @@ -345,11 +358,10 @@ const UsersTab = observer(() => { { - uiSettings.aclList.usersTab.quickSearch = x; - }} + searchText={searchQuery ?? ''} + setSearchText={(x) => setSearchQuery(x)} width="300px" /> diff --git a/frontend/tests/console/acls/user-management.spec.ts b/frontend/tests/console/acls/user-management.spec.ts new file mode 100644 index 000000000..25019ff9d --- /dev/null +++ b/frontend/tests/console/acls/user-management.spec.ts @@ -0,0 +1,264 @@ +// spec: ACL User Management Tests +// seed: tests/seed.spec.ts + +import { expect, test } from '@playwright/test'; + +test.describe('ACL User Management', () => { + test.beforeEach(async ({ page }) => { + // Navigate to Security/Users page + await page.goto('/security/'); + await expect(page).toHaveURL('/security/users'); + }); + + test('should create a new user with special characters in password', async ({ page }) => { + // 1. Click Create user button to open user creation dialog + await page.getByTestId('create-user-button').click(); + await expect(page).toHaveURL('/security/users/create'); + await expect(page.getByRole('heading', { name: 'Create user' })).toBeVisible(); + + // 2. Fill in username field with timestamp suffix for unique test runs + const timestamp = Date.now(); + const username = `test-user-e2e-${timestamp}`; + const usernameInput = page.getByTestId('create-user-name'); + await usernameInput.fill(username); + + // 3. Enable special characters checkbox + await page.locator('label').filter({ hasText: 'Generate with special' }).click(); + await expect(page.getByRole('checkbox', { name: 'Generate with special' })).toBeChecked(); + + // 4. Verify Create button is enabled and submit + const createButton = page.getByRole('button', { name: 'Create' }); + await expect(createButton).toBeEnabled(); + await createButton.click(); + + // 5. Verify success message + await expect(page.getByRole('heading', { name: 'User created successfully' })).toBeVisible(); + await expect(page.getByText(username)).toBeVisible(); + + // 6. Return to users list + await page.getByRole('button', { name: 'Done' }).click(); + await expect(page).toHaveURL('/security/users'); + + // 7. Verify user appears in the list + await expect(page.getByRole('link', { name: username })).toBeVisible(); + }); + + test('should toggle special characters checkbox and regenerate password', async ({ page }) => { + // 1. Navigate to create user page + await page.getByTestId('create-user-button').click(); + + // 2. Get initial password value (find first input within the password field container) + const passwordInput = page.getByTestId('create-user-password').locator('input').first(); + const initialPassword = await passwordInput.inputValue(); + + await page.getByTestId('password-input-toggle').click(); + + // 3. Toggle special characters checkbox on + const specialCharsCheckbox = page.locator('label').filter({ hasText: 'Generate with special characters' }); + await specialCharsCheckbox.click(); + await expect(page.getByRole('checkbox', { name: 'Generate with special characters' })).toBeChecked(); + + // 4. Verify password changed after checkbox toggle + const passwordAfterToggle = await passwordInput.inputValue(); + expect(passwordAfterToggle).not.toBe(initialPassword); + + // 5. Toggle checkbox off + await specialCharsCheckbox.click(); + await expect(page.getByRole('checkbox', { name: 'Generate with special' })).not.toBeChecked(); + + // 6. Verify password changed again + const finalPassword = await passwordInput.inputValue(); + expect(finalPassword).not.toBe(passwordAfterToggle); + + // Cancel and return to list + await page.getByRole('button', { name: 'Cancel' }).click(); + await expect(page).toHaveURL('/security/users'); + }); + + test('should filter users by name', async ({ page }) => { + // 1. Create a unique test user for filtering + await page.getByTestId('create-user-button').click(); + const timestamp = Date.now(); + const username = `test-user-filter-${timestamp}`; + await page.getByTestId('create-user-name').fill(username); + await page.getByRole('button', { name: 'Create' }).click(); + await expect(page.getByRole('heading', { name: 'User created successfully' })).toBeVisible(); + await page.getByRole('button', { name: 'Done' }).click(); + await expect(page).toHaveURL('/security/users'); + + // 2. Verify initial user list is visible + const table = page.getByRole('table'); + await expect(table).toBeVisible(); + + + // 3. Get filter input + const filterInput = page.getByTestId('search-field-input').getByRole('textbox'); + await expect(filterInput).toBeVisible(); + + // 4. Filter by 'test' + await filterInput.fill('test'); + + // 5. Verify URL contains query parameter 'q=test' + await expect(page).toHaveURL('/security/users?q=test'); + + // 6. Verify filtered results - should only show users with 'test' in name + await expect(page.getByRole('link', { name: /test-user-.*/ }).first()).toBeVisible(); + await expect(page.getByRole('link', { name: 'e2euser', exact: true })).not.toBeVisible(); + + // 7. Clear filter + await filterInput.fill(''); + + // 8. Verify URL query parameter is removed + await expect(page).toHaveURL('/security/users'); + + // 9. Verify e2euser is visible again + await expect(page.getByRole('link', { name: 'e2euser' })).toBeVisible(); + }); + + test('should filter users by partial match', async ({ page }) => { + // 1. Create a unique test user for partial matching + await page.getByTestId('create-user-button').click(); + const timestamp = Date.now(); + const username = `test-user-partial-${timestamp}`; + await page.getByTestId('create-user-name').fill(username); + await page.getByRole('button', { name: 'Create' }).click(); + await expect(page.getByRole('heading', { name: 'User created successfully' })).toBeVisible(); + await page.getByRole('button', { name: 'Done' }).click(); + await expect(page).toHaveURL('/security/users'); + + // 2. Filter by 'e2e' + const filterInput = page.getByTestId('search-field-input').getByRole('textbox'); + await filterInput.fill('e2e'); + + // 3. Verify URL contains query parameter 'q=e2e' + await expect(page).toHaveURL('/security/users?q=e2e'); + + // 4. Verify only e2euser is visible + await expect(page.getByRole('link', { name: 'e2euser' })).toBeVisible(); + + // 5. Change filter to 'test' + await filterInput.fill('test'); + + // 6. Verify URL contains query parameter 'q=test' + await expect(page).toHaveURL('/security/users?q=test'); + + // 7. Verify test-user is visible + await expect(page.getByRole('link', { name: /test-user-.*/ }).first()).toBeVisible(); + await expect(page.getByRole('link', { name: 'e2euser', exact: true })).not.toBeVisible(); + + // 8. Clear filter + await filterInput.fill(''); + + // 9. Verify URL query parameter is removed + await expect(page).toHaveURL('/security/users'); + }); + + test('should navigate to user detail page and back', async ({ page }) => { + // 1. Create a unique test user for navigation test + await page.getByTestId('create-user-button').click(); + const timestamp = Date.now(); + const username = `test-user-nav-${timestamp}`; + await page.getByTestId('create-user-name').fill(username); + await page.getByRole('button', { name: 'Create' }).click(); + await expect(page.getByRole('heading', { name: 'User created successfully' })).toBeVisible(); + await page.getByRole('button', { name: 'Done' }).click(); + await expect(page).toHaveURL('/security/users'); + + // 2. Click on the created user link + await page.getByRole('link', { name: username, exact: true }).click(); + + // 3. Verify user detail page loads + await expect(page).toHaveURL(`/security/users/${username}/details`); + await expect(page.getByRole('heading', { name: username, exact: true })).toBeVisible(); + + // 4. Verify user information section + await expect(page.getByRole('heading', { name: 'User information' })).toBeVisible(); + await expect(page.getByText('Username')).toBeVisible(); + await expect(page.getByText(username, { exact: true }).first()).toBeVisible(); + await expect(page.getByText('Passwords cannot be viewed')).toBeVisible(); + + // 5. Verify sections are visible + await expect(page.getByRole('heading', { name: 'Roles' })).toBeVisible(); + await expect(page.getByRole('heading', { name: /ACLs/ })).toBeVisible(); + + // 6. Navigate back using breadcrumb + await page.getByRole('link', { name: 'Users' }).click(); + await expect(page).toHaveURL('/security/users'); + + // 7. Verify we're back on the users list + await expect(page.getByRole('heading', { name: 'Access Control' })).toBeVisible(); + await expect(page.getByTestId('create-user-button')).toBeVisible(); + }); + + test('should display user details with ACLs and roles information', async ({ page }) => { + // 1. Create a unique test user for details test + await page.getByTestId('create-user-button').click(); + const timestamp = Date.now(); + const username = `test-user-details-${timestamp}`; + await page.getByTestId('create-user-name').fill(username); + await page.getByRole('button', { name: 'Create' }).click(); + await expect(page.getByRole('heading', { name: 'User created successfully' })).toBeVisible(); + await page.getByRole('button', { name: 'Done' }).click(); + await expect(page).toHaveURL('/security/users'); + + // 2. Navigate to the created user detail page + await page.getByRole('link', { name: username, exact: true }).click(); + + // 3. Verify URL and heading + await expect(page).toHaveURL(`/security/users/${username}/details`); + await expect(page.getByRole('heading', { name: username, exact: true })).toBeVisible(); + + // 4. Verify User information section shows correct username + await expect(page.getByText('test-user-123', { exact: false })).not.toBeVisible(); + await expect(page.getByText('User information')).toBeVisible(); + + // 6. Verify Delete user button is available + await expect(page.getByRole('button', { name: 'Delete user' })).toBeVisible(); + + // 8. Navigate back to list using breadcrumb + await page.getByRole('link', { name: 'Users' }).click(); + await expect(page).toHaveURL('/security/users'); + }); + + test('should validate username format requirements', async ({ page }) => { + // 1. Navigate to create user page + await page.getByTestId('create-user-button').click(); + + // 2. Verify username input has help text + await expect( + page.getByText('Must not contain any whitespace. Dots, hyphens and underscores may be used.') + ).toBeVisible(); + + // 3. Fill in valid username with allowed characters + const usernameInput = page.getByTestId('create-user-name'); + await usernameInput.fill('valid-user.name_123'); + + // 4. Verify Create button becomes enabled + await expect(page.getByRole('button', { name: 'Create' })).toBeEnabled(); + + // Cancel and return + await page.getByRole('button', { name: 'Cancel' }).click(); + }); + + test('should display password requirements', async ({ page }) => { + // 1. Navigate to create user page + await page.getByTestId('create-user-button').click(); + + // 2. Verify password requirements are displayed + await expect(page.getByText('Must be at least 4 characters and should not exceed 64 characters.')).toBeVisible(); + + // 3. Verify password field has auto-generated value (find first input within the container) + const passwordInput = page.getByTestId('create-user-password').locator('input').first(); + const passwordValue = await passwordInput.inputValue(); + expect(passwordValue.length).toBeGreaterThan(0); + + // 4. Verify refresh button is available + await expect(page.locator('button[aria-label="Refresh"]')).toBeVisible(); + + // 5. Verify copy button is available + await expect(page.getByRole('button', { name: 'Copy' })).toBeVisible(); + + // Cancel and return + await page.getByRole('button', { name: 'Cancel' }).click(); + }); +}); From 90d4ead25380ad5c744e373923c1c87cec9a108c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A1n=20Vor=C4=8D=C3=A1k?= Date: Sun, 28 Dec 2025 11:13:12 +0100 Subject: [PATCH 2/3] Added delete user e2e test --- .../console/acls/user-management.spec.ts | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/frontend/tests/console/acls/user-management.spec.ts b/frontend/tests/console/acls/user-management.spec.ts index 25019ff9d..8a463c22a 100644 --- a/frontend/tests/console/acls/user-management.spec.ts +++ b/frontend/tests/console/acls/user-management.spec.ts @@ -261,4 +261,35 @@ test.describe('ACL User Management', () => { // Cancel and return await page.getByRole('button', { name: 'Cancel' }).click(); }); + + test('should delete a user', async ({ page }) => { + // 1. Create a unique test user for deletion + await page.getByTestId('create-user-button').click(); + const timestamp = Date.now(); + const username = `test-user-delete-${timestamp}`; + await page.getByTestId('create-user-name').fill(username); + await page.getByRole('button', { name: 'Create' }).click(); + await expect(page.getByRole('heading', { name: 'User created successfully' })).toBeVisible(); + await page.getByRole('button', { name: 'Done' }).click(); + await expect(page).toHaveURL('/security/users'); + + // 2. Verify user appears in the list + await expect(page.getByRole('link', { name: username, exact: true })).toBeVisible(); + + // 3. Navigate to user detail page + await page.getByRole('link', { name: username, exact: true }).click(); + await expect(page).toHaveURL(`/security/users/${username}/details`); + await expect(page.getByRole('heading', { name: username, exact: true })).toBeVisible(); + + // 4. Click Delete user button + await page.getByRole('button', { name: 'Delete user' }).click(); + + // 5. Confirm deletion + const filterInput = page.getByTestId('txt-confirmation-delete'); + await filterInput.fill(username); + await page.getByRole('button', { name: 'Delete' }).click(); + + // 6. Verify redirect to users list + await page.waitForURL('/security/users/', { timeout: 10000 }); + }); }); From c9570bea2c559a8358e5a8cb42fbf807b81bb093 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A1n=20Vor=C4=8D=C3=A1k?= Date: Mon, 5 Jan 2026 12:54:11 +0100 Subject: [PATCH 3/3] Adds steps into user management e2e test suite --- .../console/acls/user-management.spec.ts | 508 ++++++++++-------- 1 file changed, 290 insertions(+), 218 deletions(-) diff --git a/frontend/tests/console/acls/user-management.spec.ts b/frontend/tests/console/acls/user-management.spec.ts index 8a463c22a..04b23d1fe 100644 --- a/frontend/tests/console/acls/user-management.spec.ts +++ b/frontend/tests/console/acls/user-management.spec.ts @@ -11,285 +11,357 @@ test.describe('ACL User Management', () => { }); test('should create a new user with special characters in password', async ({ page }) => { - // 1. Click Create user button to open user creation dialog - await page.getByTestId('create-user-button').click(); - await expect(page).toHaveURL('/security/users/create'); - await expect(page.getByRole('heading', { name: 'Create user' })).toBeVisible(); + await test.step('1. Click Create user button to open user creation dialog', async () => { + await page.getByTestId('create-user-button').click(); + await expect(page).toHaveURL('/security/users/create'); + await expect(page.getByRole('heading', { name: 'Create user' })).toBeVisible(); + }); - // 2. Fill in username field with timestamp suffix for unique test runs const timestamp = Date.now(); const username = `test-user-e2e-${timestamp}`; - const usernameInput = page.getByTestId('create-user-name'); - await usernameInput.fill(username); - // 3. Enable special characters checkbox - await page.locator('label').filter({ hasText: 'Generate with special' }).click(); - await expect(page.getByRole('checkbox', { name: 'Generate with special' })).toBeChecked(); - - // 4. Verify Create button is enabled and submit - const createButton = page.getByRole('button', { name: 'Create' }); - await expect(createButton).toBeEnabled(); - await createButton.click(); - - // 5. Verify success message - await expect(page.getByRole('heading', { name: 'User created successfully' })).toBeVisible(); - await expect(page.getByText(username)).toBeVisible(); - - // 6. Return to users list - await page.getByRole('button', { name: 'Done' }).click(); - await expect(page).toHaveURL('/security/users'); - - // 7. Verify user appears in the list - await expect(page.getByRole('link', { name: username })).toBeVisible(); + await test.step('2. Fill in username field with timestamp suffix for unique test runs', async () => { + const usernameInput = page.getByTestId('create-user-name'); + await usernameInput.fill(username); + }); + + await test.step('3. Enable special characters checkbox', async () => { + await page.locator('label').filter({ hasText: 'Generate with special' }).click(); + await expect(page.getByRole('checkbox', { name: 'Generate with special' })).toBeChecked(); + }); + + await test.step('4. Verify Create button is enabled and submit', async () => { + const createButton = page.getByRole('button', { name: 'Create' }); + await expect(createButton).toBeEnabled(); + await createButton.click(); + }); + + await test.step('5. Verify success message', async () => { + await expect(page.getByRole('heading', { name: 'User created successfully' })).toBeVisible(); + await expect(page.getByText(username)).toBeVisible(); + }); + + await test.step('6. Return to users list', async () => { + await page.getByRole('button', { name: 'Done' }).click(); + await expect(page).toHaveURL('/security/users'); + }); + + await test.step('7. Verify user appears in the list', async () => { + await expect(page.getByRole('link', { name: username })).toBeVisible(); + }); }); test('should toggle special characters checkbox and regenerate password', async ({ page }) => { - // 1. Navigate to create user page - await page.getByTestId('create-user-button').click(); + await test.step('1. Navigate to create user page', async () => { + await page.getByTestId('create-user-button').click(); + }); - // 2. Get initial password value (find first input within the password field container) const passwordInput = page.getByTestId('create-user-password').locator('input').first(); - const initialPassword = await passwordInput.inputValue(); - - await page.getByTestId('password-input-toggle').click(); - - // 3. Toggle special characters checkbox on - const specialCharsCheckbox = page.locator('label').filter({ hasText: 'Generate with special characters' }); - await specialCharsCheckbox.click(); - await expect(page.getByRole('checkbox', { name: 'Generate with special characters' })).toBeChecked(); - - // 4. Verify password changed after checkbox toggle - const passwordAfterToggle = await passwordInput.inputValue(); - expect(passwordAfterToggle).not.toBe(initialPassword); - - // 5. Toggle checkbox off - await specialCharsCheckbox.click(); - await expect(page.getByRole('checkbox', { name: 'Generate with special' })).not.toBeChecked(); - - // 6. Verify password changed again - const finalPassword = await passwordInput.inputValue(); - expect(finalPassword).not.toBe(passwordAfterToggle); - - // Cancel and return to list - await page.getByRole('button', { name: 'Cancel' }).click(); - await expect(page).toHaveURL('/security/users'); + let initialPassword: string; + let passwordAfterToggle: string; + + await test.step('2. Get initial password value', async () => { + initialPassword = await passwordInput.inputValue(); + await page.getByTestId('password-input-toggle').click(); + }); + + await test.step('3. Toggle special characters checkbox on', async () => { + const specialCharsCheckbox = page.locator('label').filter({ hasText: 'Generate with special characters' }); + await specialCharsCheckbox.click(); + await expect(page.getByRole('checkbox', { name: 'Generate with special characters' })).toBeChecked(); + }); + + await test.step('4. Verify password changed after checkbox toggle', async () => { + passwordAfterToggle = await passwordInput.inputValue(); + expect(passwordAfterToggle).not.toBe(initialPassword); + }); + + await test.step('5. Toggle checkbox off', async () => { + const specialCharsCheckbox = page.locator('label').filter({ hasText: 'Generate with special characters' }); + await specialCharsCheckbox.click(); + await expect(page.getByRole('checkbox', { name: 'Generate with special' })).not.toBeChecked(); + }); + + await test.step('6. Verify password changed again', async () => { + const finalPassword = await passwordInput.inputValue(); + expect(finalPassword).not.toBe(passwordAfterToggle); + }); + + await test.step('Cancel and return to list', async () => { + await page.getByRole('button', { name: 'Cancel' }).click(); + await expect(page).toHaveURL('/security/users'); + }); }); test('should filter users by name', async ({ page }) => { - // 1. Create a unique test user for filtering - await page.getByTestId('create-user-button').click(); const timestamp = Date.now(); const username = `test-user-filter-${timestamp}`; - await page.getByTestId('create-user-name').fill(username); - await page.getByRole('button', { name: 'Create' }).click(); - await expect(page.getByRole('heading', { name: 'User created successfully' })).toBeVisible(); - await page.getByRole('button', { name: 'Done' }).click(); - await expect(page).toHaveURL('/security/users'); - // 2. Verify initial user list is visible - const table = page.getByRole('table'); - await expect(table).toBeVisible(); + await test.step('1. Create a unique test user for filtering', async () => { + await page.getByTestId('create-user-button').click(); + await page.getByTestId('create-user-name').fill(username); + await page.getByRole('button', { name: 'Create' }).click(); + await expect(page.getByRole('heading', { name: 'User created successfully' })).toBeVisible(); + await page.getByRole('button', { name: 'Done' }).click(); + await expect(page).toHaveURL('/security/users'); + }); + await test.step('2. Verify initial user list is visible', async () => { + const table = page.getByRole('table'); + await expect(table).toBeVisible(); + }); - // 3. Get filter input const filterInput = page.getByTestId('search-field-input').getByRole('textbox'); - await expect(filterInput).toBeVisible(); - // 4. Filter by 'test' - await filterInput.fill('test'); + await test.step('3. Get filter input', async () => { + await expect(filterInput).toBeVisible(); + }); - // 5. Verify URL contains query parameter 'q=test' - await expect(page).toHaveURL('/security/users?q=test'); + await test.step('4. Filter by test', async () => { + await filterInput.fill('test'); + }); - // 6. Verify filtered results - should only show users with 'test' in name - await expect(page.getByRole('link', { name: /test-user-.*/ }).first()).toBeVisible(); - await expect(page.getByRole('link', { name: 'e2euser', exact: true })).not.toBeVisible(); + await test.step('5. Verify URL contains query parameter q=test', async () => { + await expect(page).toHaveURL('/security/users?q=test'); + }); - // 7. Clear filter - await filterInput.fill(''); + await test.step('6. Verify filtered results show only users with test in name', async () => { + await expect(page.getByRole('link', { name: /test-user-.*/ }).first()).toBeVisible(); + await expect(page.getByRole('link', { name: 'e2euser', exact: true })).not.toBeVisible(); + }); - // 8. Verify URL query parameter is removed - await expect(page).toHaveURL('/security/users'); + await test.step('7. Clear filter', async () => { + await filterInput.fill(''); + }); + + await test.step('8. Verify URL query parameter is removed', async () => { + await expect(page).toHaveURL('/security/users'); + }); - // 9. Verify e2euser is visible again - await expect(page.getByRole('link', { name: 'e2euser' })).toBeVisible(); + await test.step('9. Verify e2euser is visible again', async () => { + await expect(page.getByRole('link', { name: 'e2euser' })).toBeVisible(); + }); }); test('should filter users by partial match', async ({ page }) => { - // 1. Create a unique test user for partial matching - await page.getByTestId('create-user-button').click(); const timestamp = Date.now(); const username = `test-user-partial-${timestamp}`; - await page.getByTestId('create-user-name').fill(username); - await page.getByRole('button', { name: 'Create' }).click(); - await expect(page.getByRole('heading', { name: 'User created successfully' })).toBeVisible(); - await page.getByRole('button', { name: 'Done' }).click(); - await expect(page).toHaveURL('/security/users'); - // 2. Filter by 'e2e' + await test.step('1. Create a unique test user for partial matching', async () => { + await page.getByTestId('create-user-button').click(); + await page.getByTestId('create-user-name').fill(username); + await page.getByRole('button', { name: 'Create' }).click(); + await expect(page.getByRole('heading', { name: 'User created successfully' })).toBeVisible(); + await page.getByRole('button', { name: 'Done' }).click(); + await expect(page).toHaveURL('/security/users'); + }); + const filterInput = page.getByTestId('search-field-input').getByRole('textbox'); - await filterInput.fill('e2e'); - // 3. Verify URL contains query parameter 'q=e2e' - await expect(page).toHaveURL('/security/users?q=e2e'); + await test.step('2. Filter by e2e', async () => { + await filterInput.fill('e2e'); + }); - // 4. Verify only e2euser is visible - await expect(page.getByRole('link', { name: 'e2euser' })).toBeVisible(); + await test.step('3. Verify URL contains query parameter q=e2e', async () => { + await expect(page).toHaveURL('/security/users?q=e2e'); + }); - // 5. Change filter to 'test' - await filterInput.fill('test'); + await test.step('4. Verify only e2euser is visible', async () => { + await expect(page.getByRole('link', { name: 'e2euser' })).toBeVisible(); + }); - // 6. Verify URL contains query parameter 'q=test' - await expect(page).toHaveURL('/security/users?q=test'); + await test.step('5. Change filter to test', async () => { + await filterInput.fill('test'); + }); - // 7. Verify test-user is visible - await expect(page.getByRole('link', { name: /test-user-.*/ }).first()).toBeVisible(); - await expect(page.getByRole('link', { name: 'e2euser', exact: true })).not.toBeVisible(); + await test.step('6. Verify URL contains query parameter q=test', async () => { + await expect(page).toHaveURL('/security/users?q=test'); + }); - // 8. Clear filter - await filterInput.fill(''); + await test.step('7. Verify test-user is visible', async () => { + await expect(page.getByRole('link', { name: /test-user-.*/ }).first()).toBeVisible(); + await expect(page.getByRole('link', { name: 'e2euser', exact: true })).not.toBeVisible(); + }); - // 9. Verify URL query parameter is removed - await expect(page).toHaveURL('/security/users'); + await test.step('8. Clear filter', async () => { + await filterInput.fill(''); + }); + + await test.step('9. Verify URL query parameter is removed', async () => { + await expect(page).toHaveURL('/security/users'); + }); }); test('should navigate to user detail page and back', async ({ page }) => { - // 1. Create a unique test user for navigation test - await page.getByTestId('create-user-button').click(); const timestamp = Date.now(); const username = `test-user-nav-${timestamp}`; - await page.getByTestId('create-user-name').fill(username); - await page.getByRole('button', { name: 'Create' }).click(); - await expect(page.getByRole('heading', { name: 'User created successfully' })).toBeVisible(); - await page.getByRole('button', { name: 'Done' }).click(); - await expect(page).toHaveURL('/security/users'); - - // 2. Click on the created user link - await page.getByRole('link', { name: username, exact: true }).click(); - - // 3. Verify user detail page loads - await expect(page).toHaveURL(`/security/users/${username}/details`); - await expect(page.getByRole('heading', { name: username, exact: true })).toBeVisible(); - - // 4. Verify user information section - await expect(page.getByRole('heading', { name: 'User information' })).toBeVisible(); - await expect(page.getByText('Username')).toBeVisible(); - await expect(page.getByText(username, { exact: true }).first()).toBeVisible(); - await expect(page.getByText('Passwords cannot be viewed')).toBeVisible(); - - // 5. Verify sections are visible - await expect(page.getByRole('heading', { name: 'Roles' })).toBeVisible(); - await expect(page.getByRole('heading', { name: /ACLs/ })).toBeVisible(); - // 6. Navigate back using breadcrumb - await page.getByRole('link', { name: 'Users' }).click(); - await expect(page).toHaveURL('/security/users'); - - // 7. Verify we're back on the users list - await expect(page.getByRole('heading', { name: 'Access Control' })).toBeVisible(); - await expect(page.getByTestId('create-user-button')).toBeVisible(); + await test.step('1. Create a unique test user for navigation test', async () => { + await page.getByTestId('create-user-button').click(); + await page.getByTestId('create-user-name').fill(username); + await page.getByRole('button', { name: 'Create' }).click(); + await expect(page.getByRole('heading', { name: 'User created successfully' })).toBeVisible(); + await page.getByRole('button', { name: 'Done' }).click(); + await expect(page).toHaveURL('/security/users'); + }); + + await test.step('2. Click on the created user link', async () => { + await page.getByRole('link', { name: username, exact: true }).click(); + }); + + await test.step('3. Verify user detail page loads', async () => { + await expect(page).toHaveURL(`/security/users/${username}/details`); + await expect(page.getByRole('heading', { name: username, exact: true })).toBeVisible(); + }); + + await test.step('4. Verify user information section', async () => { + await expect(page.getByRole('heading', { name: 'User information' })).toBeVisible(); + await expect(page.getByText('Username')).toBeVisible(); + await expect(page.getByText(username, { exact: true }).first()).toBeVisible(); + await expect(page.getByText('Passwords cannot be viewed')).toBeVisible(); + }); + + await test.step('5. Verify sections are visible', async () => { + await expect(page.getByRole('heading', { name: 'Roles' })).toBeVisible(); + await expect(page.getByRole('heading', { name: /ACLs/ })).toBeVisible(); + }); + + await test.step('6. Navigate back using breadcrumb', async () => { + await page.getByRole('link', { name: 'Users' }).click(); + await expect(page).toHaveURL('/security/users'); + }); + + await test.step('7. Verify we are back on the users list', async () => { + await expect(page.getByRole('heading', { name: 'Access Control' })).toBeVisible(); + await expect(page.getByTestId('create-user-button')).toBeVisible(); + }); }); test('should display user details with ACLs and roles information', async ({ page }) => { - // 1. Create a unique test user for details test - await page.getByTestId('create-user-button').click(); const timestamp = Date.now(); const username = `test-user-details-${timestamp}`; - await page.getByTestId('create-user-name').fill(username); - await page.getByRole('button', { name: 'Create' }).click(); - await expect(page.getByRole('heading', { name: 'User created successfully' })).toBeVisible(); - await page.getByRole('button', { name: 'Done' }).click(); - await expect(page).toHaveURL('/security/users'); - - // 2. Navigate to the created user detail page - await page.getByRole('link', { name: username, exact: true }).click(); - - // 3. Verify URL and heading - await expect(page).toHaveURL(`/security/users/${username}/details`); - await expect(page.getByRole('heading', { name: username, exact: true })).toBeVisible(); - - // 4. Verify User information section shows correct username - await expect(page.getByText('test-user-123', { exact: false })).not.toBeVisible(); - await expect(page.getByText('User information')).toBeVisible(); - // 6. Verify Delete user button is available - await expect(page.getByRole('button', { name: 'Delete user' })).toBeVisible(); - - // 8. Navigate back to list using breadcrumb - await page.getByRole('link', { name: 'Users' }).click(); - await expect(page).toHaveURL('/security/users'); + await test.step('1. Create a unique test user for details test', async () => { + await page.getByTestId('create-user-button').click(); + await page.getByTestId('create-user-name').fill(username); + await page.getByRole('button', { name: 'Create' }).click(); + await expect(page.getByRole('heading', { name: 'User created successfully' })).toBeVisible(); + await page.getByRole('button', { name: 'Done' }).click(); + await expect(page).toHaveURL('/security/users'); + }); + + await test.step('2. Navigate to the created user detail page', async () => { + await page.getByRole('link', { name: username, exact: true }).click(); + }); + + await test.step('3. Verify URL and heading', async () => { + await expect(page).toHaveURL(`/security/users/${username}/details`); + await expect(page.getByRole('heading', { name: username, exact: true })).toBeVisible(); + }); + + await test.step('4. Verify User information section shows correct username', async () => { + await expect(page.getByText('test-user-123', { exact: false })).not.toBeVisible(); + await expect(page.getByText('User information')).toBeVisible(); + }); + + await test.step('5. Verify Delete user button is available', async () => { + await expect(page.getByRole('button', { name: 'Delete user' })).toBeVisible(); + }); + + await test.step('6. Navigate back to list using breadcrumb', async () => { + await page.getByRole('link', { name: 'Users' }).click(); + await expect(page).toHaveURL('/security/users'); + }); }); test('should validate username format requirements', async ({ page }) => { - // 1. Navigate to create user page - await page.getByTestId('create-user-button').click(); - - // 2. Verify username input has help text - await expect( - page.getByText('Must not contain any whitespace. Dots, hyphens and underscores may be used.') - ).toBeVisible(); - - // 3. Fill in valid username with allowed characters - const usernameInput = page.getByTestId('create-user-name'); - await usernameInput.fill('valid-user.name_123'); - - // 4. Verify Create button becomes enabled - await expect(page.getByRole('button', { name: 'Create' })).toBeEnabled(); - - // Cancel and return - await page.getByRole('button', { name: 'Cancel' }).click(); + await test.step('1. Navigate to create user page', async () => { + await page.getByTestId('create-user-button').click(); + }); + + await test.step('2. Verify username input has help text', async () => { + await expect( + page.getByText('Must not contain any whitespace. Dots, hyphens and underscores may be used.') + ).toBeVisible(); + }); + + await test.step('3. Fill in valid username with allowed characters', async () => { + const usernameInput = page.getByTestId('create-user-name'); + await usernameInput.fill('valid-user.name_123'); + }); + + await test.step('4. Verify Create button becomes enabled', async () => { + await expect(page.getByRole('button', { name: 'Create' })).toBeEnabled(); + }); + + await test.step('Cancel and return', async () => { + await page.getByRole('button', { name: 'Cancel' }).click(); + }); }); test('should display password requirements', async ({ page }) => { - // 1. Navigate to create user page - await page.getByTestId('create-user-button').click(); - - // 2. Verify password requirements are displayed - await expect(page.getByText('Must be at least 4 characters and should not exceed 64 characters.')).toBeVisible(); - - // 3. Verify password field has auto-generated value (find first input within the container) - const passwordInput = page.getByTestId('create-user-password').locator('input').first(); - const passwordValue = await passwordInput.inputValue(); - expect(passwordValue.length).toBeGreaterThan(0); - - // 4. Verify refresh button is available - await expect(page.locator('button[aria-label="Refresh"]')).toBeVisible(); - - // 5. Verify copy button is available - await expect(page.getByRole('button', { name: 'Copy' })).toBeVisible(); - - // Cancel and return - await page.getByRole('button', { name: 'Cancel' }).click(); + await test.step('1. Navigate to create user page', async () => { + await page.getByTestId('create-user-button').click(); + }); + + await test.step('2. Verify password requirements are displayed', async () => { + await expect(page.getByText('Must be at least 4 characters and should not exceed 64 characters.')).toBeVisible(); + }); + + await test.step('3. Verify password field has auto-generated value', async () => { + const passwordInput = page.getByTestId('create-user-password').locator('input').first(); + const passwordValue = await passwordInput.inputValue(); + expect(passwordValue.length).toBeGreaterThan(0); + }); + + await test.step('4. Verify refresh button is available', async () => { + await expect(page.locator('button[aria-label="Refresh"]')).toBeVisible(); + }); + + await test.step('5. Verify copy button is available', async () => { + await expect(page.getByRole('button', { name: 'Copy' })).toBeVisible(); + }); + + await test.step('Cancel and return', async () => { + await page.getByRole('button', { name: 'Cancel' }).click(); + }); }); test('should delete a user', async ({ page }) => { - // 1. Create a unique test user for deletion - await page.getByTestId('create-user-button').click(); const timestamp = Date.now(); const username = `test-user-delete-${timestamp}`; - await page.getByTestId('create-user-name').fill(username); - await page.getByRole('button', { name: 'Create' }).click(); - await expect(page.getByRole('heading', { name: 'User created successfully' })).toBeVisible(); - await page.getByRole('button', { name: 'Done' }).click(); - await expect(page).toHaveURL('/security/users'); - - // 2. Verify user appears in the list - await expect(page.getByRole('link', { name: username, exact: true })).toBeVisible(); - - // 3. Navigate to user detail page - await page.getByRole('link', { name: username, exact: true }).click(); - await expect(page).toHaveURL(`/security/users/${username}/details`); - await expect(page.getByRole('heading', { name: username, exact: true })).toBeVisible(); - - // 4. Click Delete user button - await page.getByRole('button', { name: 'Delete user' }).click(); - - // 5. Confirm deletion - const filterInput = page.getByTestId('txt-confirmation-delete'); - await filterInput.fill(username); - await page.getByRole('button', { name: 'Delete' }).click(); - // 6. Verify redirect to users list - await page.waitForURL('/security/users/', { timeout: 10000 }); + await test.step('1. Create a unique test user for deletion', async () => { + await page.getByTestId('create-user-button').click(); + await page.getByTestId('create-user-name').fill(username); + await page.getByRole('button', { name: 'Create' }).click(); + await expect(page.getByRole('heading', { name: 'User created successfully' })).toBeVisible(); + await page.getByRole('button', { name: 'Done' }).click(); + await expect(page).toHaveURL('/security/users'); + }); + + await test.step('2. Verify user appears in the list', async () => { + await expect(page.getByRole('link', { name: username, exact: true })).toBeVisible(); + }); + + await test.step('3. Navigate to user detail page', async () => { + await page.getByRole('link', { name: username, exact: true }).click(); + await expect(page).toHaveURL(`/security/users/${username}/details`); + await expect(page.getByRole('heading', { name: username, exact: true })).toBeVisible(); + }); + + await test.step('4. Click Delete user button', async () => { + await page.getByRole('button', { name: 'Delete user' }).click(); + }); + + await test.step('5. Confirm deletion', async () => { + const filterInput = page.getByTestId('txt-confirmation-delete'); + await filterInput.fill(username); + await page.getByRole('button', { name: 'Delete' }).click(); + }); + + await test.step('6. Verify redirect to users list', async () => { + await page.waitForURL('/security/users/', { timeout: 10000 }); + }); }); });