minor(test): migrate persona spec (#17701)

* minor(test): migrate persona spec

* remove persona cypress spec

* address comments
This commit is contained in:
Chirag Madlani 2024-09-04 22:45:40 +05:30 committed by GitHub
parent 35bed7138d
commit b86f3d8ae7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 298 additions and 310 deletions

View File

@ -1,309 +0,0 @@
/*
* Copyright 2022 Collate.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import {
descriptionBox,
interceptURL,
toastNotification,
verifyResponseStatusCode,
} from '../../common/common';
import { validateFormNameFieldInput } from '../../common/Utils/Form';
import { getToken } from '../../common/Utils/LocalStorage';
import { DELETE_TERM } from '../../constants/constants';
import { PERSONA_DETAILS, USER_DETAILS } from '../../constants/EntityConstant';
import { GlobalSettingOptions } from '../../constants/settings.constant';
const updatePersonaDisplayName = (displayName) => {
interceptURL('PATCH', `/api/v1/personas/*`, 'updatePersona');
cy.get('[data-testid="manage-button"]').click();
cy.get(
'[data-testid="manage-dropdown-list-container"] [data-testid="rename-button"]'
).click();
cy.get('#name').should('be.disabled');
cy.get('#displayName').should('not.be.disabled').clear();
cy.get('#displayName').type(displayName);
cy.get('[data-testid="save-button"]').click();
verifyResponseStatusCode('@updatePersona', 200);
};
describe('Persona operations', { tags: 'Settings' }, () => {
const user = {
details: {
id: '',
name: '',
},
};
const userSearchText = `${USER_DETAILS.firstName}${USER_DETAILS.lastName}`;
before(() => {
cy.login();
cy.getAllLocalStorage().then((data) => {
const token = getToken(data);
// Create a new user
cy.request({
method: 'POST',
url: `/api/v1/users/signup`,
headers: { Authorization: `Bearer ${token}` },
body: USER_DETAILS,
}).then((response) => {
user.details = response.body;
});
});
});
after(() => {
cy.login();
cy.getAllLocalStorage().then((data) => {
const token = getToken(data);
// Delete created user
cy.request({
method: 'DELETE',
url: `/api/v1/users/${user.details.id}?hardDelete=true&recursive=false`,
headers: { Authorization: `Bearer ${token}` },
});
});
});
beforeEach(() => {
cy.login();
interceptURL('GET', '/api/v1/personas*', 'getPersonas');
cy.settingClick(GlobalSettingOptions.PERSONA);
verifyResponseStatusCode('@getPersonas', 200);
});
it('Persona creation should work properly', () => {
interceptURL(
'GET',
'/api/v1/users?limit=25&isBot=false',
'getInitialUsers'
);
interceptURL(
'GET',
'/api/v1/search/query?q=***%20AND%20isBot:false&from=0&size=25&index=user_search_index',
'getUserSearch'
);
cy.get('[data-testid="add-persona-button"]').scrollIntoView().click();
cy.get('[data-testid="name"]').clear().type(PERSONA_DETAILS.name);
validateFormNameFieldInput({
value: PERSONA_DETAILS.name,
fieldName: 'Name',
fieldSelector: '[data-testid="name"]',
errorDivSelector: '#name_help',
});
cy.get('[data-testid="displayName"]')
.clear()
.type(PERSONA_DETAILS.displayName);
cy.get(descriptionBox).type(PERSONA_DETAILS.description);
cy.get('[data-testid="add-users"]').scrollIntoView().click();
verifyResponseStatusCode('@getInitialUsers', 200);
cy.get('[data-testid="searchbar"]').type(userSearchText);
verifyResponseStatusCode('@getUserSearch', 200);
cy.get(`.ant-popover [title="${userSearchText}"]`).click();
cy.get('[data-testid="selectable-list-update-btn"]')
.scrollIntoView()
.click();
interceptURL('POST', '/api/v1/personas', 'createPersona');
cy.get('.ant-modal-footer > .ant-btn-primary')
.contains('Create')
.scrollIntoView()
.click();
verifyResponseStatusCode('@createPersona', 201);
// Verify created persona details
cy.get('[data-testid="persona-details-card"] .ant-card-meta-title').should(
'contain',
PERSONA_DETAILS.displayName
);
cy.get(
'[data-testid="persona-details-card"] .ant-card-meta-description'
).should('contain', PERSONA_DETAILS.description);
interceptURL(
'GET',
`/api/v1/personas/name/${PERSONA_DETAILS.name}*`,
'getPersonaDetails'
);
cy.get('[data-testid="persona-details-card"]')
.contains(PERSONA_DETAILS.displayName)
.scrollIntoView()
.click();
verifyResponseStatusCode('@getPersonaDetails', 200);
cy.get('[data-testid="entity-header-name"]').should(
'contain',
PERSONA_DETAILS.name
);
cy.get('[data-testid="entity-header-display-name"]').should(
'contain',
PERSONA_DETAILS.displayName
);
cy.get(
'[data-testid="viewer-container"] [data-testid="markdown-parser"]'
).should('contain', PERSONA_DETAILS.description);
cy.get(
`[data-row-key="${user.details.name}"] [data-testid="${user.details.name}"]`
).should('contain', user.details.name);
});
it('Persona update description flow should work properly', () => {
interceptURL(
'GET',
`/api/v1/personas/name/${PERSONA_DETAILS.name}*`,
'getPersonaDetails'
);
cy.get('[data-testid="persona-details-card"]')
.contains(PERSONA_DETAILS.displayName)
.scrollIntoView()
.click();
verifyResponseStatusCode('@getPersonaDetails', 200);
cy.get('[data-testid="edit-description"]').click();
cy.get(`[data-testid="markdown-editor"] ${descriptionBox}`)
.clear()
.type('Updated description.');
interceptURL('PATCH', `/api/v1/personas/*`, 'updatePersona');
cy.get(`[data-testid="markdown-editor"] [data-testid="save"]`).click();
verifyResponseStatusCode('@updatePersona', 200);
cy.get(
`[data-testid="viewer-container"] [data-testid="markdown-parser"]`
).should('contain', 'Updated description.');
});
it('Persona rename flow should work properly', () => {
interceptURL(
'GET',
`/api/v1/personas/name/${PERSONA_DETAILS.name}*`,
'getPersonaDetails'
);
cy.get('[data-testid="persona-details-card"]')
.contains(PERSONA_DETAILS.displayName)
.scrollIntoView()
.click();
verifyResponseStatusCode('@getPersonaDetails', 200);
updatePersonaDisplayName('Test Persona');
cy.get('[data-testid="entity-header-display-name"]').should(
'contain',
'Test Persona'
);
updatePersonaDisplayName(PERSONA_DETAILS.displayName);
cy.get('[data-testid="entity-header-display-name"]').should(
'contain',
PERSONA_DETAILS.displayName
);
});
it('Remove users in persona should work properly', () => {
// Remove user from the users tab
interceptURL(
'GET',
`/api/v1/personas/name/${PERSONA_DETAILS.name}*`,
'getPersonaDetails'
);
cy.get('[data-testid="persona-details-card"]')
.contains(PERSONA_DETAILS.displayName)
.scrollIntoView()
.click();
verifyResponseStatusCode('@getPersonaDetails', 200);
cy.get(
`[data-row-key="${user.details.name}"] [data-testid="remove-user-btn"]`
).click();
cy.get('[data-testid="remove-confirmation-modal"]').should(
'contain',
`Are you sure you want to remove ${user.details.name}?`
);
interceptURL('PATCH', `/api/v1/personas/*`, 'updatePersona');
cy.get('[data-testid="remove-confirmation-modal"]')
.contains('Confirm')
.click();
verifyResponseStatusCode('@updatePersona', 200);
});
it('Delete persona should work properly', () => {
interceptURL(
'GET',
`/api/v1/personas/name/${PERSONA_DETAILS.name}*`,
'getPersonaDetails'
);
cy.get('[data-testid="persona-details-card"]')
.contains(PERSONA_DETAILS.displayName)
.scrollIntoView()
.click();
verifyResponseStatusCode('@getPersonaDetails', 200);
cy.get('[data-testid="manage-button"]').click();
cy.get('[data-testid="delete-button-title"]').click();
cy.get('.ant-modal-header').should('contain', PERSONA_DETAILS.displayName);
cy.get(`[data-testid="hard-delete-option"]`).click();
cy.get('[data-testid="confirm-button"]').should('be.disabled');
cy.get('[data-testid="confirmation-text-input"]').type(DELETE_TERM);
interceptURL(
'DELETE',
`/api/v1/personas/*?hardDelete=true&recursive=false`,
`deletePersona`
);
cy.get('[data-testid="confirm-button"]').should('not.be.disabled');
cy.get('[data-testid="confirm-button"]').click();
verifyResponseStatusCode(`@deletePersona`, 200);
toastNotification(`"${PERSONA_DETAILS.displayName}" deleted successfully!`);
});
});

View File

@ -30,3 +30,5 @@ export const NAME_MIN_MAX_LENGTH_VALIDATION_ERROR =
export const NAME_MAX_LENGTH_VALIDATION_ERROR =
'Name size must be between 1 and 128';
export const DELETE_TERM = 'DELETE';

View File

@ -0,0 +1,259 @@
/*
* Copyright 2022 Collate.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import test, { expect } from '@playwright/test';
import { DELETE_TERM } from '../../constant/common';
import { GlobalSettingOptions } from '../../constant/settings';
import { UserClass } from '../../support/user/UserClass';
import {
createNewPage,
descriptionBox,
redirectToHomePage,
toastNotification,
uuid,
} from '../../utils/common';
import { validateFormNameFieldInput } from '../../utils/form';
import { updatePersonaDisplayName } from '../../utils/persona';
import { settingClick } from '../../utils/sidebar';
const PERSONA_DETAILS = {
name: `persona-with-%-${uuid()}`,
displayName: `persona ${uuid()}`,
description: `Persona description ${uuid()}.`,
};
// use the admin user to login
test.use({
storageState: 'playwright/.auth/admin.json',
});
test.describe.serial('Persona operations', () => {
const user = new UserClass();
test.beforeAll('pre-requisites', async ({ browser }) => {
const { apiContext, afterAction } = await createNewPage(browser);
await user.create(apiContext);
await afterAction();
});
test.afterAll('cleanup', async ({ browser }) => {
const { apiContext, afterAction } = await createNewPage(browser);
await user.delete(apiContext);
await afterAction();
});
test.beforeEach(async ({ page }) => {
await redirectToHomePage(page);
await settingClick(page, GlobalSettingOptions.PERSONA);
});
test('Persona creation should work properly', async ({ page }) => {
await page.getByTestId('add-persona-button').click();
await validateFormNameFieldInput({
page,
value: PERSONA_DETAILS.name,
fieldName: 'Name',
fieldSelector: '[data-testid="name"]',
errorDivSelector: '#name_help',
});
await page.getByTestId('displayName').fill(PERSONA_DETAILS.displayName);
await page.locator(descriptionBox).fill(PERSONA_DETAILS.description);
await page.getByTestId('add-users').click();
const searchUser = page.waitForResponse(
`/api/v1/search/query?q=*${encodeURIComponent(
user.responseData.displayName
)}*`
);
await page.getByTestId('searchbar').fill(user.responseData.displayName);
await searchUser;
await page.click(`.ant-popover [title="${user.responseData.displayName}"]`);
await page.getByTestId('selectable-list-update-btn').click();
await page.getByRole('button', { name: 'Create' }).click();
// Verify created persona details
await expect(
page
.getByTestId('persona-details-card')
.getByText(PERSONA_DETAILS.displayName)
).toBeVisible();
await expect(
page
.getByTestId('persona-details-card')
.getByText(PERSONA_DETAILS.description)
).toBeVisible();
const personaResponse = page.waitForResponse(
`/api/v1/personas/name/${encodeURIComponent(
PERSONA_DETAILS.name
)}?fields=users`
);
await page
.locator('[data-testid="persona-details-card"]')
.getByText(PERSONA_DETAILS.displayName)
.click();
await personaResponse;
await page.waitForSelector('[data-testid="entity-header-name"]', {
state: 'visible',
});
await expect(page.getByTestId('entity-header-name')).toContainText(
PERSONA_DETAILS.name
);
await expect(page.getByTestId('entity-header-display-name')).toContainText(
PERSONA_DETAILS.displayName
);
await expect(
page.locator(
'[data-testid="viewer-container"] [data-testid="markdown-parser"]'
)
).toContainText(PERSONA_DETAILS.description);
await expect(page.getByTestId(user.responseData.name)).toContainText(
user.responseData.name
);
});
test('Persona update description flow should work properly', async ({
page,
}) => {
await page
.locator('[data-testid="persona-details-card"]')
.getByText(PERSONA_DETAILS.displayName)
.click();
await page.getByTestId('edit-description').click();
await page
.locator(`[data-testid="markdown-editor"] ${descriptionBox}`)
.clear();
await page
.locator(`[data-testid="markdown-editor"] ${descriptionBox}`)
.fill('Updated description.');
await page
.locator(`[data-testid="markdown-editor"] [data-testid="save"]`)
.click();
await expect(
page.locator(
`[data-testid="viewer-container"] [data-testid="markdown-parser"]`
)
).toContainText('Updated description.');
});
test('Persona rename flow should work properly', async ({ page }) => {
await page
.locator('[data-testid="persona-details-card"]')
.getByText(PERSONA_DETAILS.displayName)
.click();
await updatePersonaDisplayName({ page, displayName: 'Test Persona' });
await expect(page.getByTestId('entity-header-display-name')).toContainText(
'Test Persona'
);
await updatePersonaDisplayName({
page,
displayName: PERSONA_DETAILS.displayName,
});
await expect(page.getByTestId('entity-header-display-name')).toContainText(
PERSONA_DETAILS.displayName
);
});
test('Remove users in persona should work properly', async ({ page }) => {
await page
.locator('[data-testid="persona-details-card"]')
.getByText(PERSONA_DETAILS.displayName)
.click();
await page
.locator(
`[data-row-key="${user.responseData.name}"] [data-testid="remove-user-btn"]`
)
.click();
await expect(
page.locator('[data-testid="remove-confirmation-modal"]')
).toContainText(
`Are you sure you want to remove ${user.responseData.name}?`
);
const updateResponse = page.waitForResponse(`/api/v1/personas/*`);
await page
.locator('[data-testid="remove-confirmation-modal"]')
.getByText('Confirm')
.click();
await updateResponse;
});
test('Delete persona should work properly', async ({ page }) => {
await page
.locator('[data-testid="persona-details-card"]')
.getByText(PERSONA_DETAILS.displayName)
.click();
await page.click('[data-testid="manage-button"]');
await page.click('[data-testid="delete-button-title"]');
await expect(page.locator('.ant-modal-header')).toContainText(
PERSONA_DETAILS.displayName
);
await page.click(`[data-testid="hard-delete-option"]`);
await expect(page.locator('[data-testid="confirm-button"]')).toBeDisabled();
await page
.locator('[data-testid="confirmation-text-input"]')
.fill(DELETE_TERM);
const deleteResponse = page.waitForResponse(
`/api/v1/personas/*?hardDelete=true&recursive=false`
);
await expect(
page.locator('[data-testid="confirm-button"]')
).not.toBeDisabled();
await page.click('[data-testid="confirm-button"]');
await deleteResponse;
await toastNotification(
page,
`"${PERSONA_DETAILS.displayName}" deleted successfully!`
);
});
});

View File

@ -0,0 +1,36 @@
/*
* Copyright 2024 Collate.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { expect, Page } from '@playwright/test';
export const updatePersonaDisplayName = async ({
page,
displayName,
}: {
page: Page;
displayName: string;
}) => {
await page.click('[data-testid="manage-button"]');
await page.click(
'[data-testid="manage-dropdown-list-container"] [data-testid="rename-button"]'
);
await page.waitForSelector('#name', { state: 'visible' });
await expect(page.locator('#name')).toBeDisabled();
await page.waitForSelector('#displayName', { state: 'visible' });
await page.fill('#displayName', displayName);
await page.click('[data-testid="save-button"]');
};

View File

@ -139,7 +139,7 @@ export const UsersTab = ({ users, onRemoveUser }: UsersTabProps) => {
),
}}
pagination={false}
rowKey="fullyQualifiedName"
rowKey="name"
size="small"
/>
{Boolean(removeUserDetails?.state) && (