diff --git a/openmetadata-ui/src/main/resources/ui/playwright/e2e/Features/ActivityFeed.spec.ts b/openmetadata-ui/src/main/resources/ui/playwright/e2e/Features/ActivityFeed.spec.ts index 2474fe1a58f..eb0721a344a 100644 --- a/openmetadata-ui/src/main/resources/ui/playwright/e2e/Features/ActivityFeed.spec.ts +++ b/openmetadata-ui/src/main/resources/ui/playwright/e2e/Features/ActivityFeed.spec.ts @@ -17,11 +17,10 @@ import { checkDescriptionInEditModal, deleteFeedComments, } from '../../utils/activityFeed'; +import { performAdminLogin } from '../../utils/admin'; import { createNewPage, descriptionBox, - performAdminLogin, - performUserLogin, redirectToHomePage, toastNotification, visitUserProfilePage, @@ -33,6 +32,7 @@ import { createTagTask, TaskDetails, } from '../../utils/task'; +import { performUserLogin } from '../../utils/user'; const entity = new TableClass(); const entity2 = new TableClass(); diff --git a/openmetadata-ui/src/main/resources/ui/playwright/e2e/Features/DataAssetsWidget.spec.ts b/openmetadata-ui/src/main/resources/ui/playwright/e2e/Features/DataAssetsWidget.spec.ts index a7210e151d4..5bb30ed850f 100644 --- a/openmetadata-ui/src/main/resources/ui/playwright/e2e/Features/DataAssetsWidget.spec.ts +++ b/openmetadata-ui/src/main/resources/ui/playwright/e2e/Features/DataAssetsWidget.spec.ts @@ -20,13 +20,13 @@ import { SearchIndexClass } from '../../support/entity/SearchIndexClass'; import { TableClass } from '../../support/entity/TableClass'; import { TopicClass } from '../../support/entity/TopicClass'; import { UserClass } from '../../support/user/UserClass'; +import { performAdminLogin } from '../../utils/admin'; import { getEntityTypeSearchIndexMapping, - performAdminLogin, - performUserLogin, redirectToHomePage, } from '../../utils/common'; import { checkDataAssetWidget } from '../../utils/entity'; +import { performUserLogin } from '../../utils/user'; const entities = [ TableClass, diff --git a/openmetadata-ui/src/main/resources/ui/playwright/e2e/Features/ExploreQuickFilters.spec.ts b/openmetadata-ui/src/main/resources/ui/playwright/e2e/Features/ExploreQuickFilters.spec.ts index d404eb36534..c0a0968e49c 100644 --- a/openmetadata-ui/src/main/resources/ui/playwright/e2e/Features/ExploreQuickFilters.spec.ts +++ b/openmetadata-ui/src/main/resources/ui/playwright/e2e/Features/ExploreQuickFilters.spec.ts @@ -14,8 +14,11 @@ import test from '@playwright/test'; import { SidebarItem } from '../../constant/sidebar'; import { Domain } from '../../support/domain/Domain'; import { TableClass } from '../../support/entity/TableClass'; -import { createNewPage, redirectToHomePage } from '../../utils/common'; -import { assignDomain } from '../../utils/domain'; +import { + assignDomain, + createNewPage, + redirectToHomePage, +} from '../../utils/common'; import { assignTag } from '../../utils/entity'; import { searchAndClickOnOption, selectNullOption } from '../../utils/explore'; import { sidebarClick } from '../../utils/sidebar'; diff --git a/openmetadata-ui/src/main/resources/ui/playwright/e2e/Pages/Glossary.spec.ts b/openmetadata-ui/src/main/resources/ui/playwright/e2e/Pages/Glossary.spec.ts index ba6a7b109e1..89844e61a0e 100644 --- a/openmetadata-ui/src/main/resources/ui/playwright/e2e/Pages/Glossary.spec.ts +++ b/openmetadata-ui/src/main/resources/ui/playwright/e2e/Pages/Glossary.spec.ts @@ -19,9 +19,9 @@ import { Glossary } from '../../support/glossary/Glossary'; import { GlossaryTerm } from '../../support/glossary/GlossaryTerm'; import { TeamClass } from '../../support/team/TeamClass'; import { UserClass } from '../../support/user/UserClass'; +import { performAdminLogin } from '../../utils/admin'; import { - performAdminLogin, - performUserLogin, + getRandomLastName, redirectToHomePage, toastNotification, uuid, @@ -39,7 +39,7 @@ import { verifyGlossaryTermAssets, } from '../../utils/glossary'; import { sidebarClick } from '../../utils/sidebar'; -import { getRandomLastName } from '../../utils/user'; +import { performUserLogin } from '../../utils/user'; const user1 = new UserClass(); const user2 = new UserClass(); diff --git a/openmetadata-ui/src/main/resources/ui/playwright/e2e/Pages/ProfilerConfigurationPage.spec.ts b/openmetadata-ui/src/main/resources/ui/playwright/e2e/Pages/ProfilerConfigurationPage.spec.ts index 4a97f7ef559..fae85658d9b 100644 --- a/openmetadata-ui/src/main/resources/ui/playwright/e2e/Pages/ProfilerConfigurationPage.spec.ts +++ b/openmetadata-ui/src/main/resources/ui/playwright/e2e/Pages/ProfilerConfigurationPage.spec.ts @@ -18,7 +18,8 @@ import { import { SidebarItem } from '../../constant/sidebar'; import { AdminClass } from '../../support/user/AdminClass'; import { UserClass } from '../../support/user/UserClass'; -import { performAdminLogin, redirectToHomePage } from '../../utils/common'; +import { performAdminLogin } from '../../utils/admin'; +import { redirectToHomePage } from '../../utils/common'; import { sidebarClick } from '../../utils/sidebar'; const user = new UserClass(); diff --git a/openmetadata-ui/src/main/resources/ui/playwright/support/entity/EntityClass.ts b/openmetadata-ui/src/main/resources/ui/playwright/support/entity/EntityClass.ts index 5379e05fbee..ff2979b9f9c 100644 --- a/openmetadata-ui/src/main/resources/ui/playwright/support/entity/EntityClass.ts +++ b/openmetadata-ui/src/main/resources/ui/playwright/support/entity/EntityClass.ts @@ -12,13 +12,13 @@ */ import { APIRequestContext, Page } from '@playwright/test'; import { CustomPropertySupportedEntityList } from '../../constant/customProperty'; +import { assignDomain, removeDomain, updateDomain } from '../../utils/common'; import { createCustomPropertyForEntity, CustomProperty, setValueForProperty, validateValueForProperty, } from '../../utils/customProperty'; -import { assignDomain, removeDomain, updateDomain } from '../../utils/domain'; import { addMultiOwner, addOwner, diff --git a/openmetadata-ui/src/main/resources/ui/playwright/support/glossary/Glossary.interface.ts b/openmetadata-ui/src/main/resources/ui/playwright/support/glossary/Glossary.interface.ts new file mode 100644 index 00000000000..3c633429b2e --- /dev/null +++ b/openmetadata-ui/src/main/resources/ui/playwright/support/glossary/Glossary.interface.ts @@ -0,0 +1,67 @@ +/* + * 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. + */ +export type GlossaryResponseDataType = { + name: string; + displayName: string; + description: string; + reviewers: unknown[]; + tags: unknown[]; + mutuallyExclusive: boolean; + id: string; + fullyQualifiedName: string; +}; + +export type UserTeamRef = { + name: string; + type: string; +}; + +export type GlossaryData = { + name: string; + displayName: string; + description: string; + reviewers: UserTeamRef[]; + tags: string[]; + mutuallyExclusive: boolean; + terms: { data: GlossaryTermData }[]; + owners: UserTeamRef[]; + fullyQualifiedName: string; +}; + +export type GlossaryTermResponseDataType = { + name: string; + displayName: string; + description: string; + reviewers: unknown[]; + relatedTerms: unknown[]; + synonyms: unknown[]; + mutuallyExclusive: boolean; + tags: unknown[]; + glossary: Record; + id: string; + fullyQualifiedName: string; +}; + +export type GlossaryTermData = { + name: string; + displayName: string; + description: string; + mutuallyExclusive: boolean; + glossary: string; + synonyms: string; + icon?: string; + color?: string; + owners?: UserTeamRef[]; + fullyQualifiedName: string; + reviewers: UserTeamRef[]; +}; diff --git a/openmetadata-ui/src/main/resources/ui/playwright/support/glossary/Glossary.ts b/openmetadata-ui/src/main/resources/ui/playwright/support/glossary/Glossary.ts index 84eb176c06e..a45e33e0e84 100644 --- a/openmetadata-ui/src/main/resources/ui/playwright/support/glossary/Glossary.ts +++ b/openmetadata-ui/src/main/resources/ui/playwright/support/glossary/Glossary.ts @@ -12,38 +12,12 @@ */ import { APIRequestContext, expect, Page } from '@playwright/test'; import { omit } from 'lodash'; -import { uuid } from '../../utils/common'; -import { visitGlossaryPage } from '../../utils/glossary'; -import { getRandomFirstName } from '../../utils/user'; -import { GlossaryTerm } from './GlossaryTerm'; - -type ResponseDataType = { - name: string; - displayName: string; - description: string; - reviewers: unknown[]; - tags: unknown[]; - mutuallyExclusive: boolean; - id: string; - fullyQualifiedName: string; -}; - -export type UserTeamRef = { - name: string; - type: string; -}; - -export type GlossaryData = { - name: string; - displayName: string; - description: string; - reviewers: UserTeamRef[]; - tags: string[]; - mutuallyExclusive: boolean; - terms: GlossaryTerm[]; - owners: UserTeamRef[]; - fullyQualifiedName: string; -}; +import { + getRandomFirstName, + uuid, + visitGlossaryPage, +} from '../../utils/common'; +import { GlossaryData, GlossaryResponseDataType } from './Glossary.interface'; export class Glossary { randomName = getRandomFirstName(); @@ -62,7 +36,7 @@ export class Glossary { fullyQualifiedName: `\"PW%${this.randomId}.${this.randomName}\"`, }; - responseData: ResponseDataType; + responseData: GlossaryResponseDataType; constructor(name?: string) { this.data.name = name ?? this.data.name; diff --git a/openmetadata-ui/src/main/resources/ui/playwright/support/glossary/GlossaryTerm.ts b/openmetadata-ui/src/main/resources/ui/playwright/support/glossary/GlossaryTerm.ts index bd3e2f5d466..a9a6c436432 100644 --- a/openmetadata-ui/src/main/resources/ui/playwright/support/glossary/GlossaryTerm.ts +++ b/openmetadata-ui/src/main/resources/ui/playwright/support/glossary/GlossaryTerm.ts @@ -12,38 +12,12 @@ */ import { APIRequestContext, expect, Page } from '@playwright/test'; import { omit } from 'lodash'; -import { uuid } from '../../utils/common'; -import { visitGlossaryPage } from '../../utils/glossary'; -import { getRandomLastName } from '../../utils/user'; -import { Glossary, UserTeamRef } from './Glossary'; - -type ResponseDataType = { - name: string; - displayName: string; - description: string; - reviewers: unknown[]; - relatedTerms: unknown[]; - synonyms: unknown[]; - mutuallyExclusive: boolean; - tags: unknown[]; - glossary: Record; - id: string; - fullyQualifiedName: string; -}; - -export type GlossaryTermData = { - name: string; - displayName: string; - description: string; - mutuallyExclusive: boolean; - glossary: string; - synonyms: string; - icon?: string; - color?: string; - owner?: UserTeamRef; - fullyQualifiedName: string; - reviewers: UserTeamRef[]; -}; +import { getRandomLastName, uuid, visitGlossaryPage } from '../../utils/common'; +import { Glossary } from './Glossary'; +import { + GlossaryTermData, + GlossaryTermResponseDataType, +} from './Glossary.interface'; export class GlossaryTerm { randomName = getRandomLastName(); @@ -58,7 +32,7 @@ export class GlossaryTerm { reviewers: [], }; - responseData: ResponseDataType; + responseData: GlossaryTermResponseDataType; constructor(glossary: Glossary, name?: string) { this.data.glossary = glossary.data.name; diff --git a/openmetadata-ui/src/main/resources/ui/playwright/support/tag/TagClass.ts b/openmetadata-ui/src/main/resources/ui/playwright/support/tag/TagClass.ts index c5aa76bbc28..5f8fcaaca50 100644 --- a/openmetadata-ui/src/main/resources/ui/playwright/support/tag/TagClass.ts +++ b/openmetadata-ui/src/main/resources/ui/playwright/support/tag/TagClass.ts @@ -11,8 +11,8 @@ * limitations under the License. */ import { APIRequestContext, Page } from '@playwright/test'; +import { getRandomLastName } from '../../utils/common'; import { visitClassificationPage } from '../../utils/tag'; -import { getRandomLastName } from '../../utils/user'; type ResponseDataType = { style?: { diff --git a/openmetadata-ui/src/main/resources/ui/playwright/support/user/UserClass.ts b/openmetadata-ui/src/main/resources/ui/playwright/support/user/UserClass.ts index 0d1bb4ed06c..318e9afad2d 100644 --- a/openmetadata-ui/src/main/resources/ui/playwright/support/user/UserClass.ts +++ b/openmetadata-ui/src/main/resources/ui/playwright/support/user/UserClass.ts @@ -12,7 +12,7 @@ */ import { APIRequestContext, Page } from '@playwright/test'; import { Operation } from 'fast-json-patch'; -import { generateRandomUsername } from '../../utils/user'; +import { generateRandomUsername } from '../../utils/common'; type ResponseDataType = { name: string; diff --git a/openmetadata-ui/src/main/resources/ui/playwright/utils/admin.ts b/openmetadata-ui/src/main/resources/ui/playwright/utils/admin.ts new file mode 100644 index 00000000000..34a5347d893 --- /dev/null +++ b/openmetadata-ui/src/main/resources/ui/playwright/utils/admin.ts @@ -0,0 +1,29 @@ +/* + * 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 { AdminClass } from '../support/user/AdminClass'; +import { getAuthContext, getToken, redirectToHomePage } from './common'; + +export const performAdminLogin = async (browser) => { + const admin = new AdminClass(); + const page = await browser.newPage(); + await admin.login(page); + await redirectToHomePage(page); + const token = await getToken(page); + const apiContext = await getAuthContext(token); + const afterAction = async () => { + await apiContext.dispose(); + await page.close(); + }; + + return { page, apiContext, afterAction }; +}; diff --git a/openmetadata-ui/src/main/resources/ui/playwright/utils/common.ts b/openmetadata-ui/src/main/resources/ui/playwright/utils/common.ts index e6159a3d9e7..3e0abbeac5d 100644 --- a/openmetadata-ui/src/main/resources/ui/playwright/utils/common.ts +++ b/openmetadata-ui/src/main/resources/ui/playwright/utils/common.ts @@ -12,8 +12,9 @@ */ import { Browser, expect, Page, request } from '@playwright/test'; import { randomUUID } from 'crypto'; -import { AdminClass } from '../support/user/AdminClass'; -import { UserClass } from '../support/user/UserClass'; +import { SidebarItem } from '../constant/sidebar'; +import { adjectives, nouns } from '../constant/user'; +import { sidebarClick } from './sidebar'; export const uuid = () => randomUUID().split('-')[0]; @@ -102,34 +103,6 @@ export const getEntityTypeSearchIndexMapping = (entityType: string) => { return entityMapping[entityType]; }; -export const performAdminLogin = async (browser) => { - const admin = new AdminClass(); - const page = await browser.newPage(); - await admin.login(page); - await redirectToHomePage(page); - const token = await getToken(page); - const apiContext = await getAuthContext(token); - const afterAction = async () => { - await apiContext.dispose(); - await page.close(); - }; - - return { page, apiContext, afterAction }; -}; - -export const performUserLogin = async (browser, user: UserClass) => { - const page = await browser.newPage(); - await user.login(page); - const token = await getToken(page); - const apiContext = await getAuthContext(token); - const afterAction = async () => { - await apiContext.dispose(); - await page.close(); - }; - - return { page, apiContext, afterAction }; -}; - export const toastNotification = async ( page: Page, message: string | RegExp @@ -161,3 +134,84 @@ export const visitUserProfilePage = async (page: Page) => { await userResponse; await clickOutside(page); }; + +export const assignDomain = async ( + page: Page, + domain: { name: string; displayName: string } +) => { + await page.getByTestId('add-domain').click(); + await page.waitForSelector('[data-testid="loader"]', { state: 'detached' }); + await page + .getByTestId('selectable-list') + .getByTestId('searchbar') + .fill(domain.name); + await page.waitForResponse( + `/api/v1/search/query?q=*${encodeURIComponent(domain.name)}*` + ); + await page.getByRole('listitem', { name: domain.displayName }).click(); + + await expect(page.getByTestId('domain-link')).toContainText( + domain.displayName + ); +}; + +export const updateDomain = async ( + page: Page, + domain: { name: string; displayName: string } +) => { + await page.getByTestId('add-domain').click(); + await page.waitForSelector('[data-testid="loader"]', { state: 'detached' }); + await page.getByTestId('selectable-list').getByTestId('searchbar').clear(); + await page + .getByTestId('selectable-list') + .getByTestId('searchbar') + .fill(domain.name); + await page.waitForResponse( + `/api/v1/search/query?q=*${encodeURIComponent(domain.name)}*` + ); + await page.getByRole('listitem', { name: domain.displayName }).click(); + + await expect(page.getByTestId('domain-link')).toContainText( + domain.displayName + ); +}; + +export const removeDomain = async (page: Page) => { + await page.getByTestId('add-domain').click(); + await page.waitForSelector('[data-testid="loader"]', { state: 'detached' }); + + await expect(page.getByTestId('remove-owner').locator('path')).toBeVisible(); + + await page.getByTestId('remove-owner').locator('svg').click(); + + await expect(page.getByTestId('no-domain-text')).toContainText('No Domain'); +}; + +export const visitGlossaryPage = async (page: Page, glossaryName: string) => { + await redirectToHomePage(page); + const glossaryResponse = page.waitForResponse('/api/v1/glossaries?fields=*'); + await sidebarClick(page, SidebarItem.GLOSSARY); + await glossaryResponse; + await page.getByRole('menuitem', { name: glossaryName }).click(); +}; + +export const getRandomFirstName = () => { + return `${ + adjectives[Math.floor(Math.random() * adjectives.length)] + }${uuid()}`; +}; +export const getRandomLastName = () => { + return `${nouns[Math.floor(Math.random() * nouns.length)]}${uuid()}`; +}; + +export const generateRandomUsername = () => { + const firstName = getRandomFirstName(); + const lastName = getRandomLastName(); + + return { + firstName, + lastName, + email: `${firstName}.${lastName}@example.com`, + password: 'User@OMD123', + }; +}; diff --git a/openmetadata-ui/src/main/resources/ui/playwright/utils/glossary.ts b/openmetadata-ui/src/main/resources/ui/playwright/utils/glossary.ts index d4c7c1da06a..2243eaded7d 100644 --- a/openmetadata-ui/src/main/resources/ui/playwright/utils/glossary.ts +++ b/openmetadata-ui/src/main/resources/ui/playwright/utils/glossary.ts @@ -11,18 +11,19 @@ * limitations under the License. */ import { expect, Page } from '@playwright/test'; -import { get } from 'lodash'; +import { get, isUndefined } from 'lodash'; import { SidebarItem } from '../constant/sidebar'; import { GLOSSARY_TERM_PATCH_PAYLOAD } from '../constant/version'; import { DashboardClass } from '../support/entity/DashboardClass'; import { EntityTypeEndpoint } from '../support/entity/Entity.interface'; import { TableClass } from '../support/entity/TableClass'; import { TopicClass } from '../support/entity/TopicClass'; -import { Glossary, GlossaryData } from '../support/glossary/Glossary'; +import { Glossary } from '../support/glossary/Glossary'; import { - GlossaryTerm, + GlossaryData, GlossaryTermData, -} from '../support/glossary/GlossaryTerm'; +} from '../support/glossary/Glossary.interface'; +import { GlossaryTerm } from '../support/glossary/GlossaryTerm'; import { getApiContext, INVALID_NAMES, @@ -36,14 +37,6 @@ import { sidebarClick } from './sidebar'; export const descriptionBox = '.toastui-editor-md-container > .toastui-editor > .ProseMirror'; -export const visitGlossaryPage = async (page: Page, glossaryName: string) => { - await redirectToHomePage(page); - const glossaryResponse = page.waitForResponse('/api/v1/glossaries?fields=*'); - await sidebarClick(page, SidebarItem.GLOSSARY); - await glossaryResponse; - await page.getByRole('menuitem', { name: glossaryName }).click(); -}; - export const checkDisplayName = async (page: Page, displayName: string) => { await expect(page.getByTestId('entity-header-display-name')).toHaveText( displayName @@ -449,10 +442,10 @@ export const fillGlossaryTermDetails = async ( await page.locator('[data-testid="color-color-input"]').fill(term.color); } - if (term.owner) { + if (!isUndefined(term.owners)) { await addMultiOwner({ page, - ownerNames: term.owner.name, + ownerNames: term.owners.map((owner) => owner.name), activatorBtnDataTestId: 'add-owner', resultTestId: 'owner-container', endpoint: EntityTypeEndpoint.GlossaryTerm, diff --git a/openmetadata-ui/src/main/resources/ui/playwright/utils/user.ts b/openmetadata-ui/src/main/resources/ui/playwright/utils/user.ts index 282ee699583..48ac2374591 100644 --- a/openmetadata-ui/src/main/resources/ui/playwright/utils/user.ts +++ b/openmetadata-ui/src/main/resources/ui/playwright/utils/user.ts @@ -12,27 +12,20 @@ */ import { expect, Page } from '@playwright/test'; -import { adjectives, nouns } from '../constant/user'; -import { toastNotification, uuid } from './common'; +import { UserClass } from '../support/user/UserClass'; +import { getAuthContext, getToken, toastNotification } from './common'; -export const getRandomFirstName = () => { - return `${ - adjectives[Math.floor(Math.random() * adjectives.length)] - }${uuid()}`; -}; -export const getRandomLastName = () => { - return `${nouns[Math.floor(Math.random() * nouns.length)]}${uuid()}`; -}; -export const generateRandomUsername = () => { - const firstName = getRandomFirstName(); - const lastName = getRandomLastName(); - - return { - firstName, - lastName, - email: `${firstName}.${lastName}@example.com`, - password: 'User@OMD123', +export const performUserLogin = async (browser, user: UserClass) => { + const page = await browser.newPage(); + await user.login(page); + const token = await getToken(page); + const apiContext = await getAuthContext(token); + const afterAction = async () => { + await apiContext.dispose(); + await page.close(); }; + + return { page, apiContext, afterAction }; }; export const nonDeletedUserChecks = async (page: Page) => {