Ashish Gupta 307e883b10
FIX: Api version endpoint page breaking due to STRING changeDescription updated (#22060)
* fix the api version endpoint page breaking due to STRING changeDescription updated

* change the logic and use same function which  displayName use

* added unit test for schemaVersionUtils

* change function name to be generic

* added support for dataDisplayType diff supported for other supporting entity as well

* adde playwright test
2025-07-05 17:16:23 +05:30

314 lines
9.4 KiB
TypeScript

/*
* 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, test as base } from '@playwright/test';
import { BIG_ENTITY_DELETE_TIMEOUT } from '../../constant/delete';
import { EntityDataClass } from '../../support/entity/EntityDataClass';
import { EntityDataClassCreationConfig } from '../../support/entity/EntityDataClass.interface';
import { TableClass } from '../../support/entity/TableClass';
import { UserClass } from '../../support/user/UserClass';
import { performAdminLogin } from '../../utils/admin';
import {
descriptionBoxReadOnly,
redirectToHomePage,
toastNotification,
} from '../../utils/common';
import {
addMultiOwner,
assignTier,
getEntityDataTypeDisplayPatch,
} from '../../utils/entity';
const entityCreationConfig: EntityDataClassCreationConfig = {
apiEndpoint: true,
table: true,
storedProcedure: true,
dashboard: true,
pipeline: true,
topic: true,
mlModel: true,
container: true,
searchIndex: true,
dashboardDataModel: true,
entityDetails: true,
};
const entities = [
EntityDataClass.apiEndpoint1,
EntityDataClass.table1,
EntityDataClass.storedProcedure1,
EntityDataClass.dashboard1,
EntityDataClass.pipeline1,
EntityDataClass.topic1,
EntityDataClass.mlModel1,
EntityDataClass.container1,
EntityDataClass.searchIndex1,
EntityDataClass.dashboardDataModel1,
];
// use the admin user to login
const adminUser = new UserClass();
const test = base.extend<{ page: Page }>({
page: async ({ browser }, use) => {
const adminPage = await browser.newPage();
await adminUser.login(adminPage);
await use(adminPage);
await adminPage.close();
},
});
test.describe('Entity Version pages', () => {
test.beforeAll('Setup pre-requests', async ({ browser }) => {
test.slow();
const { apiContext, afterAction } = await performAdminLogin(browser);
await adminUser.create(apiContext);
await adminUser.setAdminRole(apiContext);
await EntityDataClass.preRequisitesForTests(
apiContext,
entityCreationConfig
);
const domain = EntityDataClass.domain1.responseData;
for (const entity of entities) {
const dataTypeDisplayPath = getEntityDataTypeDisplayPatch(entity);
await entity.patch({
apiContext,
patchData: [
{
op: 'add',
path: '/tags/0',
value: {
labelType: 'Manual',
state: 'Confirmed',
source: 'Classification',
tagFQN: 'PersonalData.SpecialCategory',
},
},
{
op: 'add',
path: '/tags/1',
value: {
labelType: 'Manual',
state: 'Confirmed',
source: 'Classification',
tagFQN: 'PII.Sensitive',
},
},
{
op: 'add',
path: '/description',
value: 'Description for newly added service',
},
{
op: 'add',
path: '/domain',
value: {
id: domain.id,
type: 'domain',
name: domain.name,
description: domain.description,
},
},
...(dataTypeDisplayPath
? [
{
op: 'add' as const,
path: dataTypeDisplayPath,
value: 'OBJECT',
},
]
: []),
],
});
}
await afterAction();
});
test.beforeEach('Visit entity details page', async ({ page }) => {
await redirectToHomePage(page);
});
test.afterAll('Cleanup', async ({ browser }) => {
test.slow();
const { apiContext, afterAction } = await performAdminLogin(browser);
await adminUser.delete(apiContext);
await EntityDataClass.postRequisitesForTests(
apiContext,
entityCreationConfig
);
await afterAction();
});
entities.forEach((entity) => {
test(`${entity.getType()}`, async ({ page }) => {
test.slow();
await entity.visitEntityPage(page);
const versionDetailResponse = page.waitForResponse(`**/versions/0.2`);
await page.locator('[data-testid="version-button"]').click();
await versionDetailResponse;
await test.step(
'should show edited tags and description changes',
async () => {
await expect(
page.locator(
'[data-testid="domain-link"] [data-testid="diff-added"]'
)
).toBeVisible();
await expect(
page.locator(
`[data-testid="asset-description-container"] ${descriptionBoxReadOnly} [data-testid="diff-added"]`
)
).toBeVisible();
await expect(
page.locator(
'[data-testid="entity-right-panel"] .diff-added [data-testid="tag-PersonalData.SpecialCategory"]'
)
).toBeVisible();
await expect(
page.locator(
'[data-testid="entity-right-panel"] .diff-added [data-testid="tag-PII.Sensitive"]'
)
).toBeVisible();
}
);
await test.step('should show owner changes', async () => {
await page.locator('[data-testid="version-button"]').click();
const OWNER1 = EntityDataClass.user1.getUserName();
await addMultiOwner({
page,
ownerNames: [OWNER1],
activatorBtnDataTestId: 'edit-owner',
resultTestId: 'data-assets-header',
endpoint: entity.endpoint,
type: 'Users',
});
const versionDetailResponse = page.waitForResponse(`**/versions/0.3`);
await page.locator('[data-testid="version-button"]').click();
await versionDetailResponse;
await expect(
page.locator('[data-testid="owner-link"] [data-testid="diff-added"]')
).toBeVisible();
});
if (entity.endpoint === 'tables') {
await test.step(
'should show column display name changes properly',
async () => {
await page.locator('[data-testid="version-button"]').click();
await page
.locator(
`[data-row-key$="${
(entity as TableClass).entity.columns[0].name
}"] [data-testid="edit-displayName-button"]`
)
.click();
await page.locator('#displayName').clear();
await page.locator('#displayName').fill('New Column Name');
await page
.locator('.ant-modal-footer [data-testid="save-button"]')
.click();
await page.waitForSelector('.ant-modal-body', {
state: 'detached',
});
await page.locator('[data-testid="version-button"]').click();
await expect(
page.locator(
`[data-row-key$="${
(entity as TableClass).entity.columns[0].name
}"] [data-testid="diff-added"]`
)
).toBeVisible();
}
);
}
await test.step('should show tier changes', async () => {
await page.locator('[data-testid="version-button"]').click();
await assignTier(page, 'Tier1', entity.endpoint);
const versionDetailResponse = page.waitForResponse(`**/versions/0.3`);
await page.locator('[data-testid="version-button"]').click();
await versionDetailResponse;
await expect(
page.locator('[data-testid="Tier"] > [data-testid="diff-added"]')
).toBeVisible();
});
await test.step(
'should show version details after soft deleted',
async () => {
await page.locator('[data-testid="version-button"]').click();
await page.click('[data-testid="manage-button"]');
await page.click('[data-testid="delete-button"]');
await page.waitForSelector('[role="dialog"].ant-modal');
await expect(page.locator('[role="dialog"].ant-modal')).toBeVisible();
await page.fill('[data-testid="confirmation-text-input"]', 'DELETE');
const deleteResponse = page.waitForResponse(
`/api/v1/${entity.endpoint}/async/*?hardDelete=false&recursive=true`
);
await page.click('[data-testid="confirm-button"]');
await deleteResponse;
await toastNotification(
page,
/deleted successfully!/,
BIG_ENTITY_DELETE_TIMEOUT
);
await page.reload();
const deletedBadge = page.locator('[data-testid="deleted-badge"]');
await expect(deletedBadge).toHaveText('Deleted');
const versionDetailResponse = page.waitForResponse(`**/versions/0.4`);
await page.locator('[data-testid="version-button"]').click();
await versionDetailResponse;
// Deleted badge should be visible
await expect(
page.locator('[data-testid="deleted-badge"]')
).toBeVisible();
}
);
});
});
});