Skip to content

Commit 4812212

Browse files
siddhant1Siddhant
andauthored
Fix tag search in mUI Tag Suggestion (#25579)
* fix-tag-search * fix tag search * add unit test * fix race * filterOptions * filterOptions --------- Co-authored-by: Siddhant <[email protected]>
1 parent 72f710e commit 4812212

File tree

7 files changed

+626
-19
lines changed

7 files changed

+626
-19
lines changed

openmetadata-ui/src/main/resources/ui/playwright/e2e/Pages/DataProducts.spec.ts

Lines changed: 75 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,10 @@ import { ClassificationClass } from '../../support/tag/ClassificationClass';
2222
import { TagClass } from '../../support/tag/TagClass';
2323
import { UserClass } from '../../support/user/UserClass';
2424
import { performAdminLogin } from '../../utils/admin';
25-
import { redirectToHomePage, toastNotification } from '../../utils/common';
25+
import {
26+
descriptionBox,
27+
redirectToHomePage,
28+
} from '../../utils/common';
2629
import {
2730
addAssetsToDataProduct,
2831
createDataProductFromListPage,
@@ -31,6 +34,7 @@ import {
3134
} from '../../utils/domain';
3235
import { followEntity, waitForAllLoadersToDisappear } from '../../utils/entity';
3336
import { sidebarClick } from '../../utils/sidebar';
37+
import { selectTagInMUITagSuggestion } from '../../utils/tag';
3438
import { EntityTypeEndpoint } from '../../support/entity/Entity.interface';
3539

3640
const user = new UserClass();
@@ -154,8 +158,6 @@ test.describe('Data Products', () => {
154158

155159
await test.step('Create new data product', async () => {
156160
await createDataProductFromListPage(page, dataProduct.data, domain.data);
157-
158-
await toastNotification(page, /data product created successfully/i);
159161
});
160162

161163
await test.step('Open data product details', async () => {
@@ -465,4 +467,74 @@ test.describe('Data Products', () => {
465467
await afterAction();
466468
});
467469
});
470+
471+
test('Create data product with tags using MUITagSuggestion', async ({
472+
page,
473+
}) => {
474+
const dataProduct = new DataProduct([domain]);
475+
476+
await test.step('Navigate to add data product', async () => {
477+
await sidebarClick(page, SidebarItem.DATA_PRODUCT);
478+
await page.waitForLoadState('networkidle');
479+
await waitForAllLoadersToDisappear(page);
480+
await page.getByTestId('add-entity-button').click();
481+
await expect(page.getByTestId('form-heading')).toContainText(
482+
'Add Data Product'
483+
);
484+
});
485+
486+
await test.step('Fill data product form', async () => {
487+
await page.locator('#root\\/name').fill(dataProduct.data.name);
488+
await page
489+
.locator('#root\\/displayName')
490+
.fill(dataProduct.data.displayName);
491+
await page.locator(descriptionBox).fill(dataProduct.data.description);
492+
493+
const domainInput = page.getByTestId('domain-select');
494+
await domainInput.scrollIntoViewIfNeeded();
495+
await domainInput.waitFor({ state: 'visible' });
496+
await domainInput.click();
497+
const searchDomain = page.waitForResponse(
498+
'/api/v1/search/query?q=*index=domain_search_index*'
499+
);
500+
await domainInput.fill(domain.data.displayName);
501+
await searchDomain;
502+
const domainOption = page.getByText(domain.data.displayName);
503+
await domainOption.waitFor({ state: 'visible' });
504+
await domainOption.click();
505+
});
506+
507+
await test.step('Search and select tag via MUITagSuggestion', async () => {
508+
await selectTagInMUITagSuggestion(page, {
509+
searchTerm: tag.data.displayName,
510+
tagFqn: tag.responseData.fullyQualifiedName,
511+
});
512+
513+
await expect(page.locator('[data-testid="tag-suggestion"]')).toContainText(
514+
tag.data.displayName
515+
);
516+
});
517+
518+
await test.step('Save and verify tag is applied', async () => {
519+
const dpRes = page.waitForResponse('/api/v1/dataProducts');
520+
await page.getByTestId('save-btn').click();
521+
await dpRes;
522+
523+
await selectDataProduct(page, dataProduct.data);
524+
525+
await expect(
526+
page.locator(
527+
`[data-testid="tag-${tag.responseData.fullyQualifiedName}"]`
528+
)
529+
).toBeVisible();
530+
});
531+
532+
await test.step('Cleanup', async () => {
533+
const { apiContext, afterAction } = await performAdminLogin(
534+
page.context().browser()!
535+
);
536+
await dataProduct.delete(apiContext);
537+
await afterAction();
538+
});
539+
});
468540
});

openmetadata-ui/src/main/resources/ui/playwright/e2e/Pages/Domains.spec.ts

Lines changed: 100 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ import {
3636
clickOutside,
3737
getApiContext,
3838
redirectToHomePage,
39-
toastNotification,
4039
uuid,
4140
visitGlossaryPage,
4241
} from '../../utils/common';
@@ -86,6 +85,7 @@ import {
8685
SettingOptionsType,
8786
sidebarClick,
8887
} from '../../utils/sidebar';
88+
import { selectTagInMUITagSuggestion } from '../../utils/tag';
8989
import { performUserLogin, visitUserProfilePage } from '../../utils/user';
9090
const user = new UserClass();
9191

@@ -1197,6 +1197,105 @@ test.describe('Domains', () => {
11971197
}
11981198
});
11991199

1200+
test('Create domain with tags using MUITagSuggestion', async ({ page }) => {
1201+
const { afterAction, apiContext } = await getApiContext(page);
1202+
const testDomain = new Domain();
1203+
1204+
try {
1205+
await test.step('Navigate to add domain', async () => {
1206+
await sidebarClick(page, SidebarItem.DOMAIN);
1207+
await waitForAllLoadersToDisappear(page);
1208+
await page.click('[data-testid="add-domain"]');
1209+
await page.waitForSelector('h6:has-text("Add Domain")', { state: 'visible' });
1210+
});
1211+
1212+
await test.step('Fill domain form', async () => {
1213+
await fillDomainForm(page, testDomain.data);
1214+
});
1215+
1216+
await test.step('Search and select tag via MUITagSuggestion', async () => {
1217+
await selectTagInMUITagSuggestion(page, {
1218+
searchTerm: tag.data.displayName,
1219+
tagFqn: tag.responseData.fullyQualifiedName,
1220+
});
1221+
1222+
await expect(page.locator('[data-testid="tag-suggestion"]')).toContainText(
1223+
tag.data.displayName
1224+
);
1225+
});
1226+
1227+
await test.step('Save domain and verify tag is applied', async () => {
1228+
const domainRes = page.waitForResponse('/api/v1/domains');
1229+
await page.getByRole('button', { name: 'Save' }).click();
1230+
await domainRes;
1231+
await selectDomain(page, testDomain.data);
1232+
1233+
await expect(
1234+
page.locator(
1235+
`[data-testid="tag-${tag.responseData.fullyQualifiedName}"]`
1236+
)
1237+
).toBeVisible();
1238+
});
1239+
} finally {
1240+
await testDomain.delete(apiContext);
1241+
await afterAction();
1242+
}
1243+
});
1244+
1245+
test('Create subdomain with tags using MUITagSuggestion', async ({ page }) => {
1246+
const { afterAction, apiContext } = await getApiContext(page);
1247+
const parentDomain = new Domain();
1248+
const subDomain = new SubDomain(parentDomain);
1249+
1250+
try {
1251+
await parentDomain.create(apiContext);
1252+
await page.reload();
1253+
1254+
await test.step('Navigate to domain and open subdomain modal', async () => {
1255+
await sidebarClick(page, SidebarItem.DOMAIN);
1256+
await waitForAllLoadersToDisappear(page);
1257+
await selectDomain(page, parentDomain.data);
1258+
1259+
await page.getByTestId('domain-details-add-button').click();
1260+
await page.getByRole('menuitem', { name: 'Sub Domains' }).click();
1261+
await expect(page.getByText('Add Sub Domain')).toBeVisible();
1262+
});
1263+
1264+
await test.step('Fill subdomain form', async () => {
1265+
await fillDomainForm(page, subDomain.data, false);
1266+
});
1267+
1268+
await test.step('Search and select tag via MUITagSuggestion', async () => {
1269+
await selectTagInMUITagSuggestion(page, {
1270+
searchTerm: tag.data.displayName,
1271+
tagFqn: tag.responseData.fullyQualifiedName,
1272+
});
1273+
1274+
await expect(
1275+
page.locator('[data-testid="tag-suggestion"]')
1276+
).toContainText(tag.data.displayName);
1277+
});
1278+
1279+
await test.step('Save subdomain and verify tag is applied', async () => {
1280+
const saveRes = page.waitForResponse('/api/v1/domains');
1281+
await page.getByTestId('save-btn').click();
1282+
await saveRes;
1283+
1284+
await navigateToSubDomain(page, subDomain.data);
1285+
1286+
await expect(
1287+
page.locator(
1288+
`[data-testid="tag-${tag.responseData.fullyQualifiedName}"]`
1289+
)
1290+
).toBeVisible();
1291+
});
1292+
} finally {
1293+
await subDomain.delete(apiContext);
1294+
await parentDomain.delete(apiContext);
1295+
await afterAction();
1296+
}
1297+
});
1298+
12001299
test('Verify data product tags and glossary terms', async ({ page }) => {
12011300
const { afterAction, apiContext } = await getApiContext(page);
12021301
const domain1 = new Domain();
@@ -1327,12 +1426,6 @@ test.describe('Domains', () => {
13271426
await expect(page.getByTestId('save-btn')).toBeVisible();
13281427
await saveButton;
13291428
await domainRes;
1330-
1331-
// Verify duplicate error message
1332-
await toastNotification(
1333-
page,
1334-
/already exists. Duplicated domains are not allowed./
1335-
);
13361429
} finally {
13371430
await domain.delete(apiContext);
13381431
await afterAction();

openmetadata-ui/src/main/resources/ui/playwright/utils/tag.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -595,3 +595,33 @@ export const verifyEntityTypeFilterInTagAssets = async (
595595
await page.getByText('Clear').click();
596596
await clearResponse;
597597
};
598+
599+
export const selectTagInMUITagSuggestion = async (
600+
page: Page,
601+
{
602+
searchTerm,
603+
tagFqn,
604+
}: {
605+
searchTerm: string;
606+
tagFqn: string;
607+
}
608+
) => {
609+
const tagInput = page.getByRole('combobox', { name: 'Tags' });
610+
611+
const tagSearchResponse = page.waitForResponse((response) => {
612+
const url = response.url();
613+
return (
614+
url.includes('/api/v1/search/query') &&
615+
url.includes('index=tag_search_index') &&
616+
response.request().method() === 'GET'
617+
);
618+
});
619+
620+
await tagInput.fill(searchTerm);
621+
await tagSearchResponse;
622+
623+
await page.waitForSelector('[role="listbox"]', { state: 'visible' });
624+
const tagOption = page.getByTestId(`tag-option-${tagFqn}`);
625+
await tagOption.waitFor({ state: 'visible' });
626+
await tagOption.click();
627+
};
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/*
2+
* Copyright 2024 Collate.
3+
* Licensed under the Apache License, Version 2.0 (the "License");
4+
* you may not use this file except in compliance with the License.
5+
* You may obtain a copy of the License at
6+
* http://www.apache.org/licenses/LICENSE-2.0
7+
* Unless required by applicable law or agreed to in writing, software
8+
* distributed under the License is distributed on an "AS IS" BASIS,
9+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10+
* See the License for the specific language governing permissions and
11+
* limitations under the License.
12+
*/
13+
export const MOCK_TAG_OPTIONS = [
14+
{
15+
label: 'Personal',
16+
value: 'PersonalData.Personal',
17+
data: {
18+
tagFQN: 'PersonalData.Personal',
19+
name: 'Personal',
20+
displayName: 'Personal Data',
21+
description: 'Personal data tag',
22+
source: 'Classification',
23+
},
24+
},
25+
{
26+
label: 'PII',
27+
value: 'PersonalData.PII',
28+
data: {
29+
tagFQN: 'PersonalData.PII',
30+
name: 'PII',
31+
displayName: 'Personally Identifiable Information',
32+
description: 'PII data tag',
33+
source: 'Classification',
34+
},
35+
},
36+
{
37+
label: 'Sensitive',
38+
value: 'SecurityData.Sensitive',
39+
data: {
40+
tagFQN: 'SecurityData.Sensitive',
41+
name: 'Sensitive',
42+
displayName: 'Sensitive Data',
43+
description: 'Sensitive data tag',
44+
source: 'Classification',
45+
},
46+
},
47+
];

0 commit comments

Comments
 (0)