Minor: Cypress improvements and flakiness fixes (#15068)

* fix glossary version page flakiness

* remove the commented code for alert tests

* fix flakiness in SearchIndexDetails spec

* Add Storage Service in Search Indexing App

* Add Storage Service in Search Indexing App

---------

Co-authored-by: mohitdeuex <mohit.y@deuexsolutions.com>
This commit is contained in:
Aniket Katkar 2024-02-07 19:49:57 +05:30 committed by GitHub
parent 11b82d4eea
commit 38f24fc363
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 274 additions and 198 deletions

View File

@ -84,7 +84,8 @@ public class SearchIndexApp extends AbstractNativeApplication {
"webAnalyticEntityViewReportData",
"webAnalyticUserActivityReportData",
"domain",
"storedProcedure");
"storedProcedure",
"storageService");
private final List<PaginatedEntitiesSource> paginatedEntitiesSources = new ArrayList<>();
private final List<PaginatedDataInsightSource> paginatedDataInsightSources = new ArrayList<>();
private Processor entityProcessor;

View File

@ -35,6 +35,7 @@
"webAnalyticUserActivityReportData",
"domain",
"storedProcedure",
"storageService",
"dataProduct"
],
"recreateIndex": true,

View File

@ -49,6 +49,7 @@
"webAnalyticUserActivityReportData",
"domain",
"storedProcedure",
"storageService",
"dataProduct"
],
"recreateIndex": true,

View File

@ -307,10 +307,9 @@ const checkActionOrFilterDetails = (filters) => {
if (!isEmpty(filter.arguments)) {
filter.arguments.forEach((argument) => {
// Check filter arguments
// TODO: uncomment this when backend API gives the name of the argument
// cy.get(`[data-testid="argument-container-${argument.name}"]`).should(
// 'exist'
// );
cy.get(`[data-testid="argument-container-${argument.name}"]`).should(
'exist'
);
argument.input.forEach((val) => {
cy.get('[data-testid="argument-value"]').should('contain', val);
});

View File

@ -72,7 +72,7 @@ export const addOwner = (ownerName: string, dataTestId?: string) => {
interceptURL(
'GET',
`api/v1/search/query?q=*${encodeURI(ownerName)}*&index=user_search_index`,
`api/v1/search/query?q=*&index=user_search_index*`,
'searchOwner'
);
@ -122,13 +122,17 @@ export const updateOwner = (ownerName: string, dataTestId?: string) => {
};
export const removeOwner = (ownerName: string, dataTestId?: string) => {
cy.get('[data-testid="edit-owner"]').click();
cy.get('[data-testid="edit-owner"]').scrollIntoView().click();
cy.get("[data-testid='select-owner-tabs']").should('be.visible');
interceptURL('PATCH', `/api/v1/**`, 'patchOwner');
cy.get('[data-testid="remove-owner"]').scrollIntoView().click();
cy.get('[data-testid="select-owner-tabs"]').should('be.visible');
cy.get(
'[data-testid="select-owner-tabs"] [data-testid="remove-owner"]'
).click();
verifyResponseStatusCode('@patchOwner', 200);
cy.get(`[data-testid=${dataTestId ?? 'owner-link'}]`).should(

View File

@ -10,9 +10,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// eslint-disable-next-line spaced-comment
/// <reference types="cypress" />
import { uuid } from '../common/common';
import { SEARCH_SERVICE } from '../constants/EntityConstant';
export const TIER = 'Tier1';
export const TAG_1 = {
@ -37,6 +40,30 @@ export const USER_CREDENTIALS = {
password: 'User@OMD123',
};
export const POLICY_DETAILS = {
name: `cy-data-steward-policy-${uuid()}`,
rules: [
{
name: 'DataStewardPolicy-EditRule',
resources: ['All'],
operations: [
'EditDescription',
'EditDisplayName',
'EditOwner',
'EditLineage',
'EditTags',
'ViewAll',
],
effect: 'allow',
},
],
};
export const ROLE_DETAILS = {
name: `cy-data-steward-role-${uuid()}`,
policies: [POLICY_DETAILS.name],
};
export const SEARCH_INDEX_DETAILS_FOR_ANNOUNCEMENT = {
term: SEARCH_INDEX_NAME,
displayName: SEARCH_INDEX_DISPLAY_NAME,
@ -47,13 +74,13 @@ export const SEARCH_INDEX_DETAILS_FOR_ANNOUNCEMENT = {
export const SEARCH_INDEX_DETAILS_FOR_DETAILS_PAGE_TEST = {
name: SEARCH_INDEX_NAME,
service: 'elasticsearch_sample',
service: SEARCH_SERVICE.service.name,
fields: [
{
name: 'name',
dataType: 'TEXT',
dataTypeDisplay: 'text',
fullyQualifiedName: `elasticsearch_sample.${SEARCH_INDEX_NAME}.name`,
fullyQualifiedName: `${SEARCH_SERVICE.service.name}.${SEARCH_INDEX_NAME}.name`,
tags: [],
},
{
@ -61,42 +88,42 @@ export const SEARCH_INDEX_DETAILS_FOR_DETAILS_PAGE_TEST = {
dataType: 'TEXT',
dataTypeDisplay: 'text',
description: 'Description for field displayName',
fullyQualifiedName: `elasticsearch_sample.${SEARCH_INDEX_NAME}.displayName`,
fullyQualifiedName: `${SEARCH_SERVICE.service.name}.${SEARCH_INDEX_NAME}.displayName`,
tags: [],
},
{
name: 'description',
dataType: 'TEXT',
dataTypeDisplay: 'text',
fullyQualifiedName: `elasticsearch_sample.${SEARCH_INDEX_NAME}.description`,
fullyQualifiedName: `${SEARCH_SERVICE.service.name}.${SEARCH_INDEX_NAME}.description`,
tags: [],
},
{
name: 'columns',
dataType: 'NESTED',
dataTypeDisplay: 'nested',
fullyQualifiedName: `elasticsearch_sample.${SEARCH_INDEX_NAME}.columns`,
fullyQualifiedName: `${SEARCH_SERVICE.service.name}.${SEARCH_INDEX_NAME}.columns`,
tags: [],
children: [
{
name: 'name',
dataType: 'TEXT',
dataTypeDisplay: 'text',
fullyQualifiedName: `elasticsearch_sample.${SEARCH_INDEX_NAME}.columns.name`,
fullyQualifiedName: `${SEARCH_SERVICE.service.name}.${SEARCH_INDEX_NAME}.columns.name`,
tags: [],
},
{
name: 'displayName',
dataType: 'TEXT',
dataTypeDisplay: 'text',
fullyQualifiedName: `elasticsearch_sample.${SEARCH_INDEX_NAME}.columns.displayName`,
fullyQualifiedName: `${SEARCH_SERVICE.service.name}.${SEARCH_INDEX_NAME}.columns.displayName`,
tags: [],
},
{
name: 'description',
dataType: 'TEXT',
dataTypeDisplay: 'text',
fullyQualifiedName: `elasticsearch_sample.${SEARCH_INDEX_NAME}.columns.description`,
fullyQualifiedName: `${SEARCH_SERVICE.service.name}.${SEARCH_INDEX_NAME}.columns.description`,
tags: [],
},
],
@ -106,9 +133,14 @@ export const SEARCH_INDEX_DETAILS_FOR_DETAILS_PAGE_TEST = {
dataType: 'TEXT',
dataTypeDisplay: 'text',
description: 'Database Schema that this table belongs to.',
fullyQualifiedName: `elasticsearch_sample.${SEARCH_INDEX_NAME}.databaseSchema`,
fullyQualifiedName: `${SEARCH_SERVICE.service.name}.${SEARCH_INDEX_NAME}.databaseSchema`,
tags: [],
},
],
tags: [],
};
export const SEARCH_SERVICE_DETAILS = {
...SEARCH_SERVICE,
entity: SEARCH_INDEX_DETAILS_FOR_DETAILS_PAGE_TEST,
};

View File

@ -21,6 +21,7 @@ import {
visitGlossaryPage,
} from '../../common/GlossaryUtils';
import { addOwner, removeOwner } from '../../common/Utils/Owner';
import { USER_DETAILS } from '../../constants/EntityConstant';
import { GLOSSARY_OWNER_LINK_TEST_ID } from '../../constants/glossary.constant';
import {
GLOSSARY_FOR_VERSION_TEST,
@ -30,19 +31,26 @@ import {
GLOSSARY_TERM_NAME_FOR_VERSION_TEST1,
GLOSSARY_TERM_NAME_FOR_VERSION_TEST2,
GLOSSARY_TERM_PATCH_PAYLOAD2,
OWNER,
REVIEWER,
} from '../../constants/Version.constants';
describe('Glossary and glossary term version pages should work properly', () => {
let glossaryId;
let glossaryTerm1Id;
let glossaryTerm2Id;
let data = {};
before(() => {
cy.login();
cy.getAllLocalStorage().then((data) => {
const token = Object.values(data)[0].oidcIdToken;
cy.getAllLocalStorage().then((storageData) => {
const token = Object.values(storageData)[0].oidcIdToken;
// Create a new user
cy.request({
method: 'POST',
url: `/api/v1/users/signup`,
headers: { Authorization: `Bearer ${token}` },
body: USER_DETAILS,
}).then((response) => {
data.user = response.body;
});
// Create Glossary
cy.request({
method: 'PUT',
@ -50,11 +58,11 @@ describe('Glossary and glossary term version pages should work properly', () =>
headers: { Authorization: `Bearer ${token}` },
body: GLOSSARY_FOR_VERSION_TEST,
}).then((response) => {
glossaryId = response.body.id;
data.glossary = response.body;
cy.request({
method: 'PATCH',
url: `/api/v1/glossaries/${glossaryId}`,
url: `/api/v1/glossaries/${data.glossary.id}`,
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json-patch+json',
@ -70,7 +78,7 @@ describe('Glossary and glossary term version pages should work properly', () =>
headers: { Authorization: `Bearer ${token}` },
body: GLOSSARY_TERM_FOR_VERSION_TEST1,
}).then((response) => {
glossaryTerm1Id = response.body.id;
data.glossaryTerm1 = response.body;
});
// Create Second Glossary Term
@ -80,13 +88,13 @@ describe('Glossary and glossary term version pages should work properly', () =>
headers: { Authorization: `Bearer ${token}` },
body: GLOSSARY_TERM_FOR_VERSION_TEST2,
}).then((response) => {
glossaryTerm2Id = response.body.id;
data.glossaryTerm2 = response.body;
const relatedTermsPatchValue = {
op: 'add',
path: '/relatedTerms/0',
value: {
id: glossaryTerm1Id,
id: data.glossaryTerm1.id,
type: 'glossaryTerm',
displayName: GLOSSARY_TERM_NAME_FOR_VERSION_TEST1,
name: GLOSSARY_TERM_NAME_FOR_VERSION_TEST1,
@ -95,7 +103,7 @@ describe('Glossary and glossary term version pages should work properly', () =>
cy.request({
method: 'PATCH',
url: `/api/v1/glossaryTerms/${glossaryTerm2Id}`,
url: `/api/v1/glossaryTerms/${data.glossaryTerm2.id}`,
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json-patch+json',
@ -113,6 +121,20 @@ describe('Glossary and glossary term version pages should work properly', () =>
visitGlossaryPage();
});
after(() => {
cy.login();
cy.getAllLocalStorage().then((storageData) => {
const token = Object.values(storageData)[0].oidcIdToken;
// Delete created user
cy.request({
method: 'DELETE',
url: `/api/v1/users/${data.user.id}?hardDelete=true&recursive=false`,
headers: { Authorization: `Bearer ${token}` },
});
});
});
it('Glossary version page should display the version changes properly', () => {
cy.get(`[data-menu-id*=${GLOSSARY_FOR_VERSION_TEST.displayName}]`).click();
@ -140,7 +162,7 @@ describe('Glossary and glossary term version pages should work properly', () =>
cy.get('[data-testid="version-button"]').contains('0.2');
addOwner(OWNER, GLOSSARY_OWNER_LINK_TEST_ID);
addOwner(data.user.displayName, GLOSSARY_OWNER_LINK_TEST_ID);
interceptURL('GET', `/api/v1/glossaries/*/versions`, 'getVersionsList');
interceptURL(
@ -165,7 +187,7 @@ describe('Glossary and glossary term version pages should work properly', () =>
verifyResponseStatusCode('@getGlossaryDetails', 200);
verifyResponseStatusCode('@getGlossaryTerms', 200);
removeOwner(OWNER, GLOSSARY_OWNER_LINK_TEST_ID);
removeOwner(data.user.displayName, GLOSSARY_OWNER_LINK_TEST_ID);
addReviewer(REVIEWER, 'glossaries');
@ -269,7 +291,7 @@ describe('Glossary and glossary term version pages should work properly', () =>
cy.get('[data-testid="version-button"]').contains('0.2');
addOwner(OWNER, GLOSSARY_OWNER_LINK_TEST_ID);
addOwner(data.user.displayName, GLOSSARY_OWNER_LINK_TEST_ID);
interceptURL('GET', `/api/v1/glossaryTerms/*/versions`, 'getVersionsList');
interceptURL(
@ -294,7 +316,7 @@ describe('Glossary and glossary term version pages should work properly', () =>
verifyResponseStatusCode('@getGlossaryTermParents', 200);
verifyResponseStatusCode('@getChildGlossaryTerms', 200);
removeOwner(OWNER, GLOSSARY_OWNER_LINK_TEST_ID);
removeOwner(data.user.displayName, GLOSSARY_OWNER_LINK_TEST_ID);
addReviewer(REVIEWER, 'glossaryTerms');

View File

@ -22,44 +22,22 @@ import {
updateTableFieldDescription,
verifyResponseStatusCode,
} from '../../common/common';
import { visitEntityDetailsPage } from '../../common/Utils/Entity';
import { BASE_URL, uuid } from '../../constants/constants';
import { SidebarItem } from '../../constants/Entity.interface';
import {
createSingleLevelEntity,
hardDeleteService,
} from '../../common/EntityUtils';
import { visitEntityDetailsPage } from '../../common/Utils/Entity';
import { BASE_URL } from '../../constants/constants';
import {
POLICY_DETAILS,
ROLE_DETAILS,
SEARCH_INDEX_DETAILS_FOR_DETAILS_PAGE_TEST,
SEARCH_INDEX_DISPLAY_NAME,
SEARCH_SERVICE_DETAILS,
TAG_1,
UPDATE_FIELD_DESCRIPTION,
USER_CREDENTIALS,
USER_NAME,
} from '../../constants/SearchIndexDetails.constants';
import { GlobalSettingOptions } from '../../constants/settings.constant';
const policy = {
name: `cy-data-steward-policy-${uuid()}`,
rules: [
{
name: 'DataStewardPolicy-EditRule',
resources: ['All'],
operations: [
'EditDescription',
'EditDisplayName',
'EditOwner',
'EditLineage',
'EditTags',
'ViewAll',
],
effect: 'allow',
},
],
};
let policyId = '';
const role = {
name: `cy-data-steward-role-${uuid()}`,
policies: [policy.name],
};
let roleId = '';
const performCommonOperations = () => {
// User should be able to edit search index field tags
@ -98,69 +76,59 @@ const performCommonOperations = () => {
).contains('No Description');
};
describe('Prerequisite for search index details page test', () => {
describe('SearchIndexDetails page should work properly for data consumer role', () => {
let data = {};
before(() => {
cy.login();
});
cy.getAllLocalStorage().then((storageData) => {
const token = Object.values(storageData)[0].oidcIdToken;
it('Prerequisites', () => {
const token = localStorage.getItem('oidcIdToken');
// Create search index entity
cy.request({
method: 'PUT',
url: `/api/v1/searchIndexes`,
headers: { Authorization: `Bearer ${token}` },
body: SEARCH_INDEX_DETAILS_FOR_DETAILS_PAGE_TEST,
}).then((response) => {
expect(response.status).to.eq(201);
SEARCH_INDEX_DETAILS_FOR_DETAILS_PAGE_TEST.id = response.body.id;
SEARCH_INDEX_DETAILS_FOR_DETAILS_PAGE_TEST.fullyQualifiedName =
response.body.fullyQualifiedName;
});
// Create Data Steward Policy
cy.request({
method: 'POST',
url: `/api/v1/policies`,
headers: { Authorization: `Bearer ${token}` },
body: policy,
}).then((response) => {
policyId = response.body.id;
expect(response.status).to.eq(201);
// Create search index entity
createSingleLevelEntity({
token,
...SEARCH_SERVICE_DETAILS,
});
// Create a new user
cy.request({
method: 'POST',
url: `/api/v1/roles`,
url: `/api/v1/users/signup`,
headers: { Authorization: `Bearer ${token}` },
body: role,
body: USER_CREDENTIALS,
}).then((response) => {
roleId = response.body.id;
expect(response.status).to.eq(201);
data.user = response.body;
});
});
// Create a new user
cy.request({
method: 'POST',
url: `/api/v1/users/signup`,
headers: { Authorization: `Bearer ${token}` },
body: USER_CREDENTIALS,
}).then((response) => {
expect(response.status).to.eq(201);
USER_CREDENTIALS.id = response.body.id;
cy.logout();
});
});
after(() => {
cy.login();
cy.getAllLocalStorage().then((storageData) => {
const token = Object.values(storageData)[0].oidcIdToken;
// Delete search index
hardDeleteService({
token,
serviceFqn: SEARCH_SERVICE_DETAILS.service.name,
serviceType: SEARCH_SERVICE_DETAILS.serviceType,
});
// Delete created user
cy.request({
method: 'DELETE',
url: `/api/v1/users/${data.user.id}?hardDelete=true&recursive=false`,
headers: { Authorization: `Bearer ${token}` },
});
});
});
});
describe('SearchIndexDetails page should work properly for data consumer role', () => {
beforeEach(() => {
// Login with the created user
login(USER_CREDENTIALS.email, USER_CREDENTIALS.password);
cy.login(USER_CREDENTIALS.email, USER_CREDENTIALS.password);
cy.url().should('eq', `${BASE_URL}/my-data`);
});
@ -183,54 +151,116 @@ describe('SearchIndexDetails page should work properly for data consumer role',
).should('not.exist');
performCommonOperations();
});
});
describe('Prerequisite for data steward role tests', () => {
it('Add data steward role to the user', () => {
cy.login();
// Assign data steward role to the created user
cy.sidebarClick(SidebarItem.SETTINGS);
interceptURL('GET', `/api/v1/users?*`, 'getUsersList');
cy.settingClick(GlobalSettingOptions.USERS);
verifyResponseStatusCode('@getUsersList', 200);
cy.get('[data-testid="searchbar"]').type(
`${USER_CREDENTIALS.firstName}${USER_CREDENTIALS.lastName}`
);
interceptURL('GET', `/api/v1/users/name/${USER_NAME}*`, 'getUserDetails');
cy.get(`[data-testid="${USER_NAME}"]`).click();
verifyResponseStatusCode('@getUserDetails', 200);
cy.get('[data-testid="user-profile"] .ant-collapse-arrow').click();
cy.get('[data-testid="edit-roles-button"]').click();
cy.get('[data-testid="inline-edit-container"] #select-role')
.click()
.type(role.name);
cy.get(`[title=${role.name}]`).click();
cy.clickOutside();
interceptURL('PATCH', `/api/v1/users/${USER_CREDENTIALS.id}`, 'updateRole');
cy.get('[data-testid="inline-save-btn"]').click();
verifyResponseStatusCode('@updateRole', 200);
cy.logout();
});
});
describe('SearchIndexDetails page should work properly for data steward role', () => {
let data = {};
before(() => {
cy.login();
cy.getAllLocalStorage().then((storageData) => {
const token = Object.values(storageData)[0].oidcIdToken;
// Create search index entity
createSingleLevelEntity({
token,
...SEARCH_SERVICE_DETAILS,
});
// Create Data Steward Policy
cy.request({
method: 'POST',
url: `/api/v1/policies`,
headers: { Authorization: `Bearer ${token}` },
body: POLICY_DETAILS,
}).then((policyResponse) => {
data.policy = policyResponse.body;
// Create Data Steward Role
cy.request({
method: 'POST',
url: `/api/v1/roles`,
headers: { Authorization: `Bearer ${token}` },
body: ROLE_DETAILS,
}).then((roleResponse) => {
data.role = roleResponse.body;
// Create a new user
cy.request({
method: 'POST',
url: `/api/v1/users/signup`,
headers: { Authorization: `Bearer ${token}` },
body: USER_CREDENTIALS,
}).then((userResponse) => {
data.user = userResponse.body;
// Assign data steward role to the user
cy.request({
method: 'PATCH',
url: `/api/v1/users/${data.user.id}`,
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json-patch+json',
},
body: [
{
op: 'add',
path: '/roles/0',
value: {
id: data.role.id,
type: 'role',
name: data.role.name,
},
},
],
});
});
});
});
cy.logout();
});
});
after(() => {
cy.login();
cy.getAllLocalStorage().then((storageData) => {
const token = Object.values(storageData)[0].oidcIdToken;
// Delete created user
cy.request({
method: 'DELETE',
url: `/api/v1/users/${data.user.id}?hardDelete=true&recursive=false`,
headers: { Authorization: `Bearer ${token}` },
});
// Delete policy
cy.request({
method: 'DELETE',
url: `/api/v1/policies/${data.policy.id}?hardDelete=true&recursive=false`,
headers: { Authorization: `Bearer ${token}` },
});
// Delete role
cy.request({
method: 'DELETE',
url: `/api/v1/roles/${data.role.id}?hardDelete=true&recursive=false`,
headers: { Authorization: `Bearer ${token}` },
});
// Delete search index
hardDeleteService({
token,
serviceFqn: SEARCH_SERVICE_DETAILS.service.name,
serviceType: SEARCH_SERVICE_DETAILS.serviceType,
});
});
});
beforeEach(() => {
// Login with the created user
login(USER_CREDENTIALS.email, USER_CREDENTIALS.password);
@ -271,11 +301,7 @@ describe('SearchIndexDetails page should work properly for data steward role', (
cy.get('#displayName').clear().type(SEARCH_INDEX_DISPLAY_NAME);
interceptURL(
'PATCH',
`/api/v1/searchIndexes/${SEARCH_INDEX_DETAILS_FOR_DETAILS_PAGE_TEST.id}`,
'updateDisplayName'
);
interceptURL('PATCH', `/api/v1/searchIndexes/*`, 'updateDisplayName');
cy.get('[data-testid="save-button"]').click();
@ -290,6 +316,34 @@ describe('SearchIndexDetails page should work properly for data steward role', (
});
describe('SearchIndexDetails page should work properly for admin role', () => {
before(() => {
cy.login();
cy.getAllLocalStorage().then((storageData) => {
const token = Object.values(storageData)[0].oidcIdToken;
// Create search index entity
createSingleLevelEntity({
token,
...SEARCH_SERVICE_DETAILS,
});
});
});
after(() => {
cy.login();
cy.getAllLocalStorage().then((storageData) => {
const token = Object.values(storageData)[0].oidcIdToken;
// Delete search index
hardDeleteService({
token,
serviceFqn: SEARCH_SERVICE_DETAILS.service.name,
serviceType: SEARCH_SERVICE_DETAILS.serviceType,
});
});
});
beforeEach(() => {
cy.login();
});
@ -379,41 +433,3 @@ describe('SearchIndexDetails page should work properly for admin role', () => {
);
});
});
describe('Cleanup', () => {
before(() => {
Cypress.session.clearAllSavedSessions();
cy.login();
});
it('Delete user, role and policy', () => {
const token = localStorage.getItem('oidcIdToken');
// Delete created user
cy.request({
method: 'DELETE',
url: `/api/v1/users/${USER_CREDENTIALS.id}?hardDelete=true&recursive=false`,
headers: { Authorization: `Bearer ${token}` },
}).then((response) => {
expect(response.status).to.eq(200);
});
// Delete policy
cy.request({
method: 'DELETE',
url: `/api/v1/policies/${policyId}?hardDelete=true&recursive=false`,
headers: { Authorization: `Bearer ${token}` },
}).then((response) => {
expect(response.status).to.eq(200);
});
// Delete role
cy.request({
method: 'DELETE',
url: `/api/v1/roles/${roleId}?hardDelete=true&recursive=false`,
headers: { Authorization: `Bearer ${token}` },
}).then((response) => {
expect(response.status).to.eq(200);
});
});
});