Redirect to persona page when clicked on default persona (#23141)

* Redirect to persona page when clicked on default persona

* add e2e tests

* fix e2e tests

* address comments

* fix e2e tests

* fix e2e tests
This commit is contained in:
Harshit Shah 2025-09-06 16:40:05 +05:30 committed by Harshit Shah
parent e18747946b
commit 9f73fdde74
6 changed files with 304 additions and 27 deletions

View File

@ -18,6 +18,7 @@ import { PolicyClass } from '../../support/access-control/PoliciesClass';
import { RolesClass } from '../../support/access-control/RolesClass';
import { EntityTypeEndpoint } from '../../support/entity/Entity.interface';
import { TableClass } from '../../support/entity/TableClass';
import { PersonaClass } from '../../support/persona/PersonaClass';
import { UserClass } from '../../support/user/UserClass';
import { performAdminLogin } from '../../utils/admin';
import {
@ -25,7 +26,7 @@ import {
uuid,
visitOwnProfilePage,
} from '../../utils/common';
import { addOwner } from '../../utils/entity';
import { addOwner, waitForAllLoadersToDisappear } from '../../utils/entity';
import { settingClick, sidebarClick } from '../../utils/sidebar';
import {
addUser,
@ -72,6 +73,8 @@ const tableEntity = new TableClass();
const tableEntity2 = new TableClass();
const policy = new PolicyClass();
const role = new RolesClass();
const persona1 = new PersonaClass();
const persona2 = new PersonaClass();
const test = base.extend<{
adminPage: Page;
@ -114,6 +117,8 @@ base.beforeAll('Setup pre-requests', async ({ browser }) => {
await tableEntity2.create(apiContext);
await policy.create(apiContext, DATA_STEWARD_RULES);
await role.create(apiContext, [policy.responseData.name]);
await persona1.create(apiContext);
await persona2.create(apiContext);
await afterAction();
});
@ -129,6 +134,8 @@ base.afterAll('Cleanup', async ({ browser }) => {
await tableEntity2.delete(apiContext);
await policy.delete(apiContext);
await role.delete(apiContext);
await persona1.delete(apiContext);
await persona2.delete(apiContext);
await afterAction();
});
@ -538,3 +545,263 @@ test.describe('User Profile Feed Interactions', () => {
).not.toBeVisible();
});
});
test.describe('User Profile Persona Interactions', () => {
test('Should add, remove, and navigate to persona pages for Personas section', async ({
adminPage,
}) => {
await redirectToHomePage(adminPage);
await visitOwnProfilePage(adminPage);
// Wait for the persona card to be visible
await adminPage.waitForSelector('[data-testid="persona-details-card"]');
// Test adding personas
await test.step('Add personas to user profile', async () => {
// Click edit button for Personas section
await adminPage
.locator('[data-testid="edit-user-persona"]')
.first()
.click();
// Wait for persona popover to be visible
await adminPage.waitForSelector('[data-testid="persona-select-list"]');
// Open the persona select dropdown and wait for options to load
await adminPage.locator('[data-testid="persona-select-list"]').click();
// Wait for dropdown to open and options to be visible
await adminPage.waitForSelector('.ant-select-dropdown', {
state: 'visible',
});
// Select first available persona - try test ID first, fallback to role selector
const personaOptionTestId = adminPage.getByTestId(
`${persona1.data.displayName}-option`
);
await personaOptionTestId.click();
// Save the changes
await adminPage
.locator('[data-testid="user-profile-persona-edit-save"]')
.click();
// Wait for the API call to complete and persona to appear
await adminPage.waitForResponse('/api/v1/users/*');
await adminPage.waitForSelector(
'[data-testid="chip-container"] [data-testid="tag-chip"]'
);
});
// Test clicking on persona chip to navigate to persona page
await test.step(
'Navigate to persona page by clicking on persona chip',
async () => {
const personaChip = adminPage
.locator('[data-testid="chip-container"] [data-testid="tag-chip"]')
.first();
const personaLink = personaChip.locator('a').first();
// Get the persona name/link for verification
const personaText = await personaLink.textContent();
expect(personaText).toBeTruthy();
// Click the persona link to navigate
await personaLink.click();
await adminPage.waitForLoadState('networkidle');
// Verify we're on the persona page
await expect(adminPage.url()).toContain('/persona/');
}
);
// Navigate back to user profile for removal test
await test.step('Navigate back to user profile', async () => {
await visitOwnProfilePage(adminPage);
await adminPage.waitForSelector('[data-testid="persona-details-card"]');
});
// Test removing personas
await test.step('Remove personas from user profile', async () => {
// Click edit button for Personas section
await adminPage
.locator('[data-testid="edit-user-persona"]')
.first()
.click();
// Wait for persona popover to be visible
await adminPage.waitForSelector('[data-testid="persona-select-list"]');
// Clear all selected personas
await adminPage
.locator('[data-testid="persona-select-list"] .ant-select-clear')
.click();
// Save the changes
await adminPage
.locator('[data-testid="user-profile-persona-edit-save"]')
.click();
// Wait for the API call to complete and verify no personas are shown
await adminPage.waitForResponse('/api/v1/users/*');
await expect(
adminPage
.getByTestId('persona-details-card')
.getByText('No persona assigned')
).toBeVisible();
});
});
test('Should add, remove, and navigate to persona pages for Default Persona section', async ({
adminPage,
}) => {
await redirectToHomePage(adminPage);
await visitOwnProfilePage(adminPage);
// Wait for the persona card to be visible
await adminPage.waitForSelector('[data-testid="persona-details-card"]');
// First, add some personas to the user so we can select a default persona
await test.step('Add personas to user profile first', async () => {
// Click edit button for Personas section (regular personas, not default)
await adminPage
.locator('[data-testid="edit-user-persona"]')
.first()
.click();
// Wait for persona popover and select multiple personas
await adminPage.waitForSelector('[data-testid="persona-select-list"]');
await adminPage.locator('[data-testid="persona-select-list"]').click();
// Wait for dropdown to open and options to be visible
await adminPage.waitForSelector('.ant-select-dropdown', {
state: 'visible',
});
// Select multiple personas - try test IDs first, fallback to role selectors
const persona1OptionTestId = adminPage.getByTestId(
`${persona1.data.displayName}-option`
);
await persona1OptionTestId.click();
const persona2OptionTestId = adminPage.getByTestId(
`${persona2.data.displayName}-option`
);
await persona2OptionTestId.click();
// Save the changes
await adminPage
.locator('[data-testid="user-profile-persona-edit-save"]')
.click();
await adminPage.waitForResponse('/api/v1/users/*');
});
// Test adding default persona
await test.step('Add default persona to user profile', async () => {
// Click edit button for Default Persona section using specific test ID
await adminPage
.locator('[data-testid="default-edit-user-persona"]')
.click();
// Wait for persona popover to be visible
await adminPage.waitForSelector(
'[data-testid="default-persona-select-list"]'
);
// Open the default persona select dropdown
await adminPage
.locator('[data-testid="default-persona-select-list"]')
.click();
// Wait for dropdown to open and options to load
await adminPage.waitForSelector('.ant-select-dropdown', {
state: 'visible',
});
await adminPage.waitForLoadState('networkidle');
// Select specific persona for default - try test ID first, fallback to role selector
const defaultPersonaOptionTestId = adminPage.getByTestId(
`${persona1.data.displayName}-option`
);
await defaultPersonaOptionTestId.click();
// Save the changes
await adminPage
.locator('[data-testid="user-profile-default-persona-edit-save"]')
.click();
// Wait for the API call to complete and default persona to appear
await adminPage.waitForResponse('/api/v1/users/*');
await adminPage.waitForSelector(
'.default-persona-text [data-testid="tag-chip"]'
);
});
// Test clicking on default persona chip to navigate to persona page
await test.step(
'Navigate to persona page by clicking on default persona chip',
async () => {
const defaultPersonaChip = adminPage
.locator('.default-persona-text [data-testid="tag-chip"]')
.first();
const personaLink = defaultPersonaChip.locator('a').first();
// Get the persona name/link for verification
const personaText = await personaLink.textContent();
expect(personaText).toBeTruthy();
// Click the persona link to navigate
await personaLink.click();
await adminPage.waitForLoadState('networkidle');
// Verify we're on the persona page
await expect(adminPage.url()).toContain('/persona/');
}
);
// Navigate back to user profile for removal test
await test.step('Navigate back to user profile', async () => {
await visitOwnProfilePage(adminPage);
await adminPage.waitForSelector('[data-testid="persona-details-card"]');
});
// Test removing default persona
await test.step('Remove default persona from user profile', async () => {
// Click edit button for Default Persona section using specific test ID
await adminPage
.locator('[data-testid="default-edit-user-persona"]')
.click();
await waitForAllLoadersToDisappear(adminPage);
// Wait for persona popover to be visible
await adminPage.waitForSelector(
'[data-testid="default-persona-select-list"]'
);
// Clear the selected default persona
await adminPage
.locator(
'[data-testid="default-persona-select-list"] .ant-select-clear'
)
.click();
// Save the changes
await adminPage
.locator('[data-testid="user-profile-default-persona-edit-save"]')
.click();
// Wait for the API call to complete and verify no default persona is shown
await adminPage.waitForResponse('api/v1/users/*');
await expect(adminPage.getByText('No default persona')).toBeVisible();
});
});
});

View File

@ -186,13 +186,13 @@ export const setUserDefaultPersona = async (
) => {
await visitOwnProfilePage(page);
await page.locator('[data-testid="edit-user-persona"]').nth(1).click();
await page.locator('[data-testid="default-edit-user-persona"]').click();
await expect(
page.locator('[data-testid="persona-select-list"]')
page.locator('[data-testid="default-persona-select-list"]')
).toBeVisible();
await page.locator('[data-testid="persona-select-list"]').click();
await page.locator('[data-testid="default-persona-select-list"]').click();
await page.waitForLoadState('networkidle');
const setDefaultPersona = page.waitForResponse('/api/v1/users/*');
@ -200,7 +200,9 @@ export const setUserDefaultPersona = async (
// Click on the persona option by text within the dropdown
await page.locator(`[data-testid="${personaName}-option"]`).click();
await page.locator('[data-testid="user-profile-persona-edit-save"]').click();
await page
.locator('[data-testid="user-profile-default-persona-edit-save"]')
.click();
await setDefaultPersona;

View File

@ -66,8 +66,8 @@ export const checkPersonaInProfile = async (
if (expectedPersonaName) {
// Expect persona to be visible with specific name
await expect(page.getByTestId('default-persona-text')).toBeVisible();
await expect(page.getByTestId('default-persona-text')).toContainText(
await expect(page.getByTestId('default-persona-chip')).toBeVisible();
await expect(page.getByTestId('default-persona-chip')).toContainText(
expectedPersonaName
);
} else {

View File

@ -190,7 +190,9 @@ export const PersonaSelectableList = ({
className={classNames('profile-edit-popover', {
'single-select': isDefaultPersona,
})}
data-testid="persona-select-list"
data-testid={`${
isDefaultPersona ? 'default-' : ''
}persona-select-list`}
defaultValue={selectedPersonas.map((persona) => persona.id)}
dropdownStyle={{
maxHeight: '200px',
@ -229,7 +231,9 @@ export const PersonaSelectableList = ({
<div className="flex justify-end gap-2">
<Button
className="persona-profile-edit-save"
data-testid="user-profile-persona-edit-cancel"
data-testid={`user-profile${
isDefaultPersona ? '-default' : ''
}persona-edit-cancel`}
icon={<ClosePopoverIcon height={24} />}
size="small"
type="primary"
@ -237,7 +241,9 @@ export const PersonaSelectableList = ({
/>
<Button
className="persona-profile-edit-cancel"
data-testid="user-profile-persona-edit-save"
data-testid={`user-profile${
isDefaultPersona ? '-default' : ''
}-persona-edit-save`}
icon={<SavePopoverIcon height={24} />}
loading={isSaving}
size="small"
@ -263,7 +269,9 @@ export const PersonaSelectableList = ({
})}>
<EditIcon
className="cursor-pointer"
data-testid="edit-user-persona"
data-testid={`${
isDefaultPersona ? 'default-' : ''
}edit-user-persona`}
height={16}
/>
</Tooltip>

View File

@ -20,7 +20,6 @@ import { EntityReference, User } from '../../../../generated/entity/teams/user';
import { useAuth } from '../../../../hooks/authHooks';
import { useApplicationStore } from '../../../../hooks/useApplicationStore';
import { useFqn } from '../../../../hooks/useFqn';
import { getEntityName } from '../../../../utils/EntityUtils';
import Chip from '../../../common/Chip/Chip.component';
import { PersonaSelectableList } from '../../../MyData/Persona/PersonaSelectableList/PersonaSelectableList.component';
import '../users.less';
@ -87,18 +86,15 @@ const UserProfilePersonas = ({
/>
</div>
</div>
<div className="user-profile-card-body d-flex justify-start gap-2">
{defaultPersona?.fullyQualifiedName || defaultPersona?.name ? (
<Typography.Text
className="default-persona-text cursor-pointer"
data-testid="default-persona-text">
{getEntityName(defaultPersona)}
</Typography.Text>
) : (
<Typography.Paragraph className="m-b-0 text-sm no-default-persona-text">
{t('message.no-default-persona')}
</Typography.Paragraph>
)}
<div
className="user-profile-card-body default-persona-text ml-8"
data-testid="default-persona-chip">
<Chip
showNoDataPlaceholder
data={defaultPersona ? [defaultPersona] : []}
entityType={EntityType.PERSONA}
noDataPlaceholder={t('message.no-default-persona')}
/>
</div>
</>
),

View File

@ -221,9 +221,13 @@
}
.default-persona-text {
padding-left: 26px;
color: @primary-heading-color;
font-size: 14px;
.chip-tag-link {
color: @primary-heading-color;
}
.no-data-chip-placeholder {
margin-top: 0;
}
}
.no-default-persona-text {