Skip to content

Commit

Permalink
added extension playwrigth test and fix enumWithDescription object fa…
Browse files Browse the repository at this point in the history
…ilure
  • Loading branch information
Ashish8689 committed Sep 29, 2024
1 parent 6ad168a commit 1986cf0
Show file tree
Hide file tree
Showing 6 changed files with 228 additions and 10 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
export const CUSTOM_PROPERTIES_TYPES = {
STRING: 'String',
MARKDOWN: 'Markdown',
SQL_QUERY: 'Sql Query',
ENUM_WITH_DESCRIPTIONS: 'Enum With Descriptions',
};

export const FIELD_VALUES_CUSTOM_PROPERTIES = {
STRING: 'This is "testing" string;',
MARKDOWN: `## Overview
This project is designed to **simplify** and *automate* daily tasks. It aims to:
- Increase productivity
- Reduce manual effort
- Provide real-time data insights
## Features
1. **Task Management**: Organize tasks efficiently with custom tags.
2. **Real-Time Analytics**: Get up-to-date insights on task progress.
3. **Automation**: Automate repetitive workflows using custom scripts.`,
SQL_QUERY: 'SELECT * FROM table_name WHERE id="20";',
};
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@
* limitations under the License.
*/
import { expect, test } from '@playwright/test';
import { CUSTOM_PROPERTIES_ENTITIES } from '../../constant/customProperty';
import { CUSTOM_PROPERTIES_TYPES } from '../../constant/glossaryImportExport';
import { GlobalSettingOptions } from '../../constant/settings';
import { SidebarItem } from '../../constant/sidebar';
import { Glossary } from '../../support/glossary/Glossary';
import { GlossaryTerm } from '../../support/glossary/GlossaryTerm';
Expand All @@ -19,14 +22,19 @@ import {
createNewPage,
redirectToHomePage,
toastNotification,
uuid,
} from '../../utils/common';
import {
addCustomPropertiesForEntity,
deleteCreatedProperty,
} from '../../utils/customProperty';
import { selectActiveGlossary } from '../../utils/glossary';
import {
createGlossaryTermRowDetails,
fillGlossaryRowDetails,
validateImportStatus,
} from '../../utils/importUtils';
import { sidebarClick } from '../../utils/sidebar';
import { settingClick, sidebarClick } from '../../utils/sidebar';

// use the admin user to login
test.use({
Expand All @@ -39,6 +47,9 @@ const glossary1 = new Glossary();
const glossary2 = new Glossary();
const glossaryTerm1 = new GlossaryTerm(glossary1);
const glossaryTerm2 = new GlossaryTerm(glossary2);
const propertiesList = Object.values(CUSTOM_PROPERTIES_TYPES);

const propertyListName: Record<string, string> = {};

test.describe('Glossary Bulk Import Export', () => {
test.slow(true);
Expand Down Expand Up @@ -72,6 +83,24 @@ test.describe('Glossary Bulk Import Export', () => {
});

test('Glossary Bulk Import Export', async ({ page }) => {
await test.step('create custom properties for extension edit', async () => {
for (const property of propertiesList) {
const entity = CUSTOM_PROPERTIES_ENTITIES.entity_glossaryTerm;
const propertyName = `pwcustomproperty${entity.name}test${uuid()}`;
propertyListName[property] = propertyName;

await settingClick(page, GlobalSettingOptions.GLOSSARY_TERM, true);

await addCustomPropertiesForEntity({
page,
propertyName,
customPropertyData: entity,
customType: property,
enumWithDescriptionConfig: entity.enumWithDescriptionConfig,
});
}
});

await test.step('should export data glossary term details', async () => {
await sidebarClick(page, SidebarItem.GLOSSARY);
await selectActiveGlossary(page, glossary1.data.displayName);
Expand All @@ -89,7 +118,7 @@ test.describe('Glossary Bulk Import Export', () => {
});

await test.step(
'should import and edit with two additional database',
'should import and edit with one additional glossaryTerm',
async () => {
await sidebarClick(page, SidebarItem.GLOSSARY);
await selectActiveGlossary(page, glossary1.data.displayName);
Expand Down Expand Up @@ -130,7 +159,8 @@ test.describe('Glossary Bulk Import Export', () => {
name: glossaryTerm2.data.name,
},
},
page
page,
propertyListName
);

await page.getByRole('button', { name: 'Next' }).click();
Expand Down Expand Up @@ -167,5 +197,17 @@ test.describe('Glossary Bulk Import Export', () => {
);
}
);

await test.step('delete custom properties', async () => {
for (const propertyName of Object.values(propertyListName)) {
await settingClick(page, GlobalSettingOptions.GLOSSARY_TERM, true);

await page.waitForLoadState('networkidle');

await page.getByTestId('loader').waitFor({ state: 'detached' });

await deleteCreatedProperty(page, propertyName);
}
});
});
});
110 changes: 108 additions & 2 deletions openmetadata-ui/src/main/resources/ui/playwright/utils/importUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,12 @@
* limitations under the License.
*/
import { expect, Page } from '@playwright/test';
import { uuid } from './common';
import { CUSTOM_PROPERTIES_ENTITIES } from '../constant/customProperty';
import {
CUSTOM_PROPERTIES_TYPES,
FIELD_VALUES_CUSTOM_PROPERTIES,
} from '../constant/glossaryImportExport';
import { descriptionBox, uuid } from './common';

export const createGlossaryTermRowDetails = () => {
return {
Expand Down Expand Up @@ -129,6 +134,100 @@ export const fillDomainDetails = async (
await page.waitForTimeout(100);
};

const editGlossaryCustomProperty = async (
page: Page,
propertyName: string,
type: string
) => {
await page
.locator(
`[data-testid=${propertyName}] [data-testid='edit-icon-right-panel']`
)
.click();

if (type === CUSTOM_PROPERTIES_TYPES.STRING) {
await page
.getByTestId('value-input')
.fill(FIELD_VALUES_CUSTOM_PROPERTIES.STRING);
await page.getByTestId('inline-save-btn').click();
}

if (type === CUSTOM_PROPERTIES_TYPES.MARKDOWN) {
await page.waitForSelector(descriptionBox, { state: 'visible' });

await page
.locator(descriptionBox)
.fill(FIELD_VALUES_CUSTOM_PROPERTIES.MARKDOWN);

await page.getByTestId('markdown-editor').getByTestId('save').click();

await page.waitForSelector(descriptionBox, {
state: 'detached',
});
}

if (type === CUSTOM_PROPERTIES_TYPES.SQL_QUERY) {
await page
.getByTestId('code-mirror-container')
.getByRole('textbox')
.fill(FIELD_VALUES_CUSTOM_PROPERTIES.SQL_QUERY);

await page.getByTestId('inline-save-btn').click();
}

if (type === CUSTOM_PROPERTIES_TYPES.ENUM_WITH_DESCRIPTIONS) {
await page.getByTestId('enum-with-description-select').click();

await page.waitForSelector('.ant-select-dropdown', {
state: 'visible',
});

// await page
// .getByRole('option', {
// name: CUSTOM_PROPERTIES_ENTITIES.entity_glossaryTerm
// .enumWithDescriptionConfig.values[0].key,
// })
// .click();

await page
.locator('span')
.filter({
hasText:
CUSTOM_PROPERTIES_ENTITIES.entity_glossaryTerm
.enumWithDescriptionConfig.values[0].key,
})
.click();

await page.getByTestId('inline-save-btn').click();
}
};

export const fillCustomPropertyDetails = async (
page: Page,
propertyListName: Record<string, string>
) => {
await page
.locator('.InovuaReactDataGrid__cell--cell-active')
.press('Enter', { delay: 100 });

// Wait for the loader to disappear
await page.waitForSelector('.ant-skeleton-content', { state: 'hidden' });

for (const propertyName of Object.values(CUSTOM_PROPERTIES_TYPES)) {
await editGlossaryCustomProperty(
page,
propertyListName[propertyName],
propertyName
);
}

await page.getByTestId('save').click();

await expect(page.locator('.ant-modal-wrap')).not.toBeVisible();

await page.click('.InovuaReactDataGrid__cell--cell-active');
};

export const fillGlossaryRowDetails = async (
row: {
name: string;
Expand All @@ -144,7 +243,8 @@ export const fillGlossaryRowDetails = async (
reviewers: string[];
owners: string[];
},
page: Page
page: Page,
propertyListName: Record<string, string>
) => {
await page
.locator('.InovuaReactDataGrid__cell--cell-active')
Expand Down Expand Up @@ -200,6 +300,12 @@ export const fillGlossaryRowDetails = async (
.press('ArrowRight', { delay: 100 });

await fillOwnerDetails(page, row.owners);

await page
.locator('.InovuaReactDataGrid__cell--cell-active')
.press('ArrowRight', { delay: 100 });

await fillCustomPropertyDetails(page, propertyListName);
};

export const validateImportStatus = async (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,14 @@
* limitations under the License.
*/
import { Button, Modal, Typography } from 'antd';
import React, { useEffect, useState } from 'react';
import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next';

import { AxiosError } from 'axios';
import { isObject } from 'lodash';
import { EntityType } from '../../../enums/entity.enum';
import { GlossaryTerm } from '../../../generated/entity/data/glossaryTerm';
import { Type } from '../../../generated/entity/type';
import { EnumConfig, Type, ValueClass } from '../../../generated/entity/type';
import { getTypeByFQN } from '../../../rest/metadataTypeAPI';
import {
convertCustomPropertyStringToEntityExtension,
Expand Down Expand Up @@ -46,6 +47,20 @@ export const ModalWithCustomPropertyEditor = ({
useState<ExtensionDataProps>();
const [customPropertyTypes, setCustomPropertyTypes] = useState<Type>();

const enumWithDescriptionsKeyPairValues = useMemo(() => {
const valuesWithEnumKey: Record<string, ValueClass[]> = {};

customPropertyTypes?.customProperties?.forEach((property) => {
if (property.propertyType.name === 'enumWithDescriptions') {
valuesWithEnumKey[property.name] = (
property.customPropertyConfig?.config as EnumConfig
).values as ValueClass[];
}
});

return valuesWithEnumKey;
}, [customPropertyTypes]);

const fetchTypeDetail = async () => {
setIsLoading(true);
try {
Expand All @@ -72,8 +87,42 @@ export const ModalWithCustomPropertyEditor = ({
setIsSaveLoading(false);
};

// EnumWithDescriptions values are change only contain keys,
// so we need to modify the extension data to include descriptions for them to display in the table
const modifyExtensionData = useCallback(
(extension: ExtensionDataProps) => {
const modifiedExtension = Object.entries(extension).reduce(
(acc, [key, value]) => {
if (enumWithDescriptionsKeyPairValues[key]) {
return {
...acc,
[key]: (value as string[] | ValueClass[]).map((item) => {
if (isObject(item)) {
return item;
}

return {
key: item,
description: enumWithDescriptionsKeyPairValues[key].find(
(val) => val.key === item
)?.description,
};
}),
};
}

return { ...acc, [key]: value };
},
{}
);

return modifiedExtension;
},
[enumWithDescriptionsKeyPairValues]
);

const onExtensionUpdate = async (data: GlossaryTerm) => {
setCustomPropertyValue(data.extension);
setCustomPropertyValue(modifyExtensionData(data.extension));
};

useEffect(() => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1002,7 +1002,7 @@ export const PropertyValue: FC<PropertyValueProps> = ({
}, [property, extension, contentRef, value]);

const customPropertyElement = (
<Row gutter={[0, 16]}>
<Row data-testid={propertyName} gutter={[0, 16]}>
<Col span={24}>
<Row gutter={[0, 2]}>
<Col className="d-flex justify-between w-full" span={24}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -934,5 +934,5 @@ export const removeOuterEscapes = (input: string) => {
const match = input.match(VALIDATE_ESCAPE_START_END_REGEX);

// Return the middle part without the outer escape characters or the original input if no match
return match ? match[2] : input;
return match && match.length > 3 ? match[2] : input;
};

0 comments on commit 1986cf0

Please sign in to comment.