Minor: Fix playwright circular dependencies (#17228)

* Fix circular dependencies in playwright test files

* Fix the type error
This commit is contained in:
Aniket Katkar 2024-07-30 15:05:56 +05:30 committed by GitHub
parent 84ad2062b8
commit 7f6fc5321e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 230 additions and 142 deletions

View File

@ -17,11 +17,10 @@ import {
checkDescriptionInEditModal, checkDescriptionInEditModal,
deleteFeedComments, deleteFeedComments,
} from '../../utils/activityFeed'; } from '../../utils/activityFeed';
import { performAdminLogin } from '../../utils/admin';
import { import {
createNewPage, createNewPage,
descriptionBox, descriptionBox,
performAdminLogin,
performUserLogin,
redirectToHomePage, redirectToHomePage,
toastNotification, toastNotification,
visitUserProfilePage, visitUserProfilePage,
@ -33,6 +32,7 @@ import {
createTagTask, createTagTask,
TaskDetails, TaskDetails,
} from '../../utils/task'; } from '../../utils/task';
import { performUserLogin } from '../../utils/user';
const entity = new TableClass(); const entity = new TableClass();
const entity2 = new TableClass(); const entity2 = new TableClass();

View File

@ -20,13 +20,13 @@ import { SearchIndexClass } from '../../support/entity/SearchIndexClass';
import { TableClass } from '../../support/entity/TableClass'; import { TableClass } from '../../support/entity/TableClass';
import { TopicClass } from '../../support/entity/TopicClass'; import { TopicClass } from '../../support/entity/TopicClass';
import { UserClass } from '../../support/user/UserClass'; import { UserClass } from '../../support/user/UserClass';
import { performAdminLogin } from '../../utils/admin';
import { import {
getEntityTypeSearchIndexMapping, getEntityTypeSearchIndexMapping,
performAdminLogin,
performUserLogin,
redirectToHomePage, redirectToHomePage,
} from '../../utils/common'; } from '../../utils/common';
import { checkDataAssetWidget } from '../../utils/entity'; import { checkDataAssetWidget } from '../../utils/entity';
import { performUserLogin } from '../../utils/user';
const entities = [ const entities = [
TableClass, TableClass,

View File

@ -14,8 +14,11 @@ import test from '@playwright/test';
import { SidebarItem } from '../../constant/sidebar'; import { SidebarItem } from '../../constant/sidebar';
import { Domain } from '../../support/domain/Domain'; import { Domain } from '../../support/domain/Domain';
import { TableClass } from '../../support/entity/TableClass'; import { TableClass } from '../../support/entity/TableClass';
import { createNewPage, redirectToHomePage } from '../../utils/common'; import {
import { assignDomain } from '../../utils/domain'; assignDomain,
createNewPage,
redirectToHomePage,
} from '../../utils/common';
import { assignTag } from '../../utils/entity'; import { assignTag } from '../../utils/entity';
import { searchAndClickOnOption, selectNullOption } from '../../utils/explore'; import { searchAndClickOnOption, selectNullOption } from '../../utils/explore';
import { sidebarClick } from '../../utils/sidebar'; import { sidebarClick } from '../../utils/sidebar';

View File

@ -19,9 +19,9 @@ import { Glossary } from '../../support/glossary/Glossary';
import { GlossaryTerm } from '../../support/glossary/GlossaryTerm'; import { GlossaryTerm } from '../../support/glossary/GlossaryTerm';
import { TeamClass } from '../../support/team/TeamClass'; import { TeamClass } from '../../support/team/TeamClass';
import { UserClass } from '../../support/user/UserClass'; import { UserClass } from '../../support/user/UserClass';
import { performAdminLogin } from '../../utils/admin';
import { import {
performAdminLogin, getRandomLastName,
performUserLogin,
redirectToHomePage, redirectToHomePage,
toastNotification, toastNotification,
uuid, uuid,
@ -39,7 +39,7 @@ import {
verifyGlossaryTermAssets, verifyGlossaryTermAssets,
} from '../../utils/glossary'; } from '../../utils/glossary';
import { sidebarClick } from '../../utils/sidebar'; import { sidebarClick } from '../../utils/sidebar';
import { getRandomLastName } from '../../utils/user'; import { performUserLogin } from '../../utils/user';
const user1 = new UserClass(); const user1 = new UserClass();
const user2 = new UserClass(); const user2 = new UserClass();

View File

@ -18,7 +18,8 @@ import {
import { SidebarItem } from '../../constant/sidebar'; import { SidebarItem } from '../../constant/sidebar';
import { AdminClass } from '../../support/user/AdminClass'; import { AdminClass } from '../../support/user/AdminClass';
import { UserClass } from '../../support/user/UserClass'; 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'; import { sidebarClick } from '../../utils/sidebar';
const user = new UserClass(); const user = new UserClass();

View File

@ -12,13 +12,13 @@
*/ */
import { APIRequestContext, Page } from '@playwright/test'; import { APIRequestContext, Page } from '@playwright/test';
import { CustomPropertySupportedEntityList } from '../../constant/customProperty'; import { CustomPropertySupportedEntityList } from '../../constant/customProperty';
import { assignDomain, removeDomain, updateDomain } from '../../utils/common';
import { import {
createCustomPropertyForEntity, createCustomPropertyForEntity,
CustomProperty, CustomProperty,
setValueForProperty, setValueForProperty,
validateValueForProperty, validateValueForProperty,
} from '../../utils/customProperty'; } from '../../utils/customProperty';
import { assignDomain, removeDomain, updateDomain } from '../../utils/domain';
import { import {
addMultiOwner, addMultiOwner,
addOwner, addOwner,

View File

@ -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<string, string>;
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[];
};

View File

@ -12,38 +12,12 @@
*/ */
import { APIRequestContext, expect, Page } from '@playwright/test'; import { APIRequestContext, expect, Page } from '@playwright/test';
import { omit } from 'lodash'; import { omit } from 'lodash';
import { uuid } from '../../utils/common'; import {
import { visitGlossaryPage } from '../../utils/glossary'; getRandomFirstName,
import { getRandomFirstName } from '../../utils/user'; uuid,
import { GlossaryTerm } from './GlossaryTerm'; visitGlossaryPage,
} from '../../utils/common';
type ResponseDataType = { import { GlossaryData, GlossaryResponseDataType } from './Glossary.interface';
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;
};
export class Glossary { export class Glossary {
randomName = getRandomFirstName(); randomName = getRandomFirstName();
@ -62,7 +36,7 @@ export class Glossary {
fullyQualifiedName: `\"PW%${this.randomId}.${this.randomName}\"`, fullyQualifiedName: `\"PW%${this.randomId}.${this.randomName}\"`,
}; };
responseData: ResponseDataType; responseData: GlossaryResponseDataType;
constructor(name?: string) { constructor(name?: string) {
this.data.name = name ?? this.data.name; this.data.name = name ?? this.data.name;

View File

@ -12,38 +12,12 @@
*/ */
import { APIRequestContext, expect, Page } from '@playwright/test'; import { APIRequestContext, expect, Page } from '@playwright/test';
import { omit } from 'lodash'; import { omit } from 'lodash';
import { uuid } from '../../utils/common'; import { getRandomLastName, uuid, visitGlossaryPage } from '../../utils/common';
import { visitGlossaryPage } from '../../utils/glossary'; import { Glossary } from './Glossary';
import { getRandomLastName } from '../../utils/user'; import {
import { Glossary, UserTeamRef } from './Glossary'; GlossaryTermData,
GlossaryTermResponseDataType,
type ResponseDataType = { } from './Glossary.interface';
name: string;
displayName: string;
description: string;
reviewers: unknown[];
relatedTerms: unknown[];
synonyms: unknown[];
mutuallyExclusive: boolean;
tags: unknown[];
glossary: Record<string, string>;
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[];
};
export class GlossaryTerm { export class GlossaryTerm {
randomName = getRandomLastName(); randomName = getRandomLastName();
@ -58,7 +32,7 @@ export class GlossaryTerm {
reviewers: [], reviewers: [],
}; };
responseData: ResponseDataType; responseData: GlossaryTermResponseDataType;
constructor(glossary: Glossary, name?: string) { constructor(glossary: Glossary, name?: string) {
this.data.glossary = glossary.data.name; this.data.glossary = glossary.data.name;

View File

@ -11,8 +11,8 @@
* limitations under the License. * limitations under the License.
*/ */
import { APIRequestContext, Page } from '@playwright/test'; import { APIRequestContext, Page } from '@playwright/test';
import { getRandomLastName } from '../../utils/common';
import { visitClassificationPage } from '../../utils/tag'; import { visitClassificationPage } from '../../utils/tag';
import { getRandomLastName } from '../../utils/user';
type ResponseDataType = { type ResponseDataType = {
style?: { style?: {

View File

@ -12,7 +12,7 @@
*/ */
import { APIRequestContext, Page } from '@playwright/test'; import { APIRequestContext, Page } from '@playwright/test';
import { Operation } from 'fast-json-patch'; import { Operation } from 'fast-json-patch';
import { generateRandomUsername } from '../../utils/user'; import { generateRandomUsername } from '../../utils/common';
type ResponseDataType = { type ResponseDataType = {
name: string; name: string;

View File

@ -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 };
};

View File

@ -12,8 +12,9 @@
*/ */
import { Browser, expect, Page, request } from '@playwright/test'; import { Browser, expect, Page, request } from '@playwright/test';
import { randomUUID } from 'crypto'; import { randomUUID } from 'crypto';
import { AdminClass } from '../support/user/AdminClass'; import { SidebarItem } from '../constant/sidebar';
import { UserClass } from '../support/user/UserClass'; import { adjectives, nouns } from '../constant/user';
import { sidebarClick } from './sidebar';
export const uuid = () => randomUUID().split('-')[0]; export const uuid = () => randomUUID().split('-')[0];
@ -102,34 +103,6 @@ export const getEntityTypeSearchIndexMapping = (entityType: string) => {
return entityMapping[entityType]; 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 ( export const toastNotification = async (
page: Page, page: Page,
message: string | RegExp message: string | RegExp
@ -161,3 +134,84 @@ export const visitUserProfilePage = async (page: Page) => {
await userResponse; await userResponse;
await clickOutside(page); 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',
};
};

View File

@ -11,18 +11,19 @@
* limitations under the License. * limitations under the License.
*/ */
import { expect, Page } from '@playwright/test'; import { expect, Page } from '@playwright/test';
import { get } from 'lodash'; import { get, isUndefined } from 'lodash';
import { SidebarItem } from '../constant/sidebar'; import { SidebarItem } from '../constant/sidebar';
import { GLOSSARY_TERM_PATCH_PAYLOAD } from '../constant/version'; import { GLOSSARY_TERM_PATCH_PAYLOAD } from '../constant/version';
import { DashboardClass } from '../support/entity/DashboardClass'; import { DashboardClass } from '../support/entity/DashboardClass';
import { EntityTypeEndpoint } from '../support/entity/Entity.interface'; import { EntityTypeEndpoint } from '../support/entity/Entity.interface';
import { TableClass } from '../support/entity/TableClass'; import { TableClass } from '../support/entity/TableClass';
import { TopicClass } from '../support/entity/TopicClass'; import { TopicClass } from '../support/entity/TopicClass';
import { Glossary, GlossaryData } from '../support/glossary/Glossary'; import { Glossary } from '../support/glossary/Glossary';
import { import {
GlossaryTerm, GlossaryData,
GlossaryTermData, GlossaryTermData,
} from '../support/glossary/GlossaryTerm'; } from '../support/glossary/Glossary.interface';
import { GlossaryTerm } from '../support/glossary/GlossaryTerm';
import { import {
getApiContext, getApiContext,
INVALID_NAMES, INVALID_NAMES,
@ -36,14 +37,6 @@ import { sidebarClick } from './sidebar';
export const descriptionBox = export const descriptionBox =
'.toastui-editor-md-container > .toastui-editor > .ProseMirror'; '.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) => { export const checkDisplayName = async (page: Page, displayName: string) => {
await expect(page.getByTestId('entity-header-display-name')).toHaveText( await expect(page.getByTestId('entity-header-display-name')).toHaveText(
displayName displayName
@ -449,10 +442,10 @@ export const fillGlossaryTermDetails = async (
await page.locator('[data-testid="color-color-input"]').fill(term.color); await page.locator('[data-testid="color-color-input"]').fill(term.color);
} }
if (term.owner) { if (!isUndefined(term.owners)) {
await addMultiOwner({ await addMultiOwner({
page, page,
ownerNames: term.owner.name, ownerNames: term.owners.map((owner) => owner.name),
activatorBtnDataTestId: 'add-owner', activatorBtnDataTestId: 'add-owner',
resultTestId: 'owner-container', resultTestId: 'owner-container',
endpoint: EntityTypeEndpoint.GlossaryTerm, endpoint: EntityTypeEndpoint.GlossaryTerm,

View File

@ -12,27 +12,20 @@
*/ */
import { expect, Page } from '@playwright/test'; import { expect, Page } from '@playwright/test';
import { adjectives, nouns } from '../constant/user'; import { UserClass } from '../support/user/UserClass';
import { toastNotification, uuid } from './common'; import { getAuthContext, getToken, toastNotification } from './common';
export const getRandomFirstName = () => { export const performUserLogin = async (browser, user: UserClass) => {
return `${ const page = await browser.newPage();
adjectives[Math.floor(Math.random() * adjectives.length)] await user.login(page);
}${uuid()}`; const token = await getToken(page);
}; const apiContext = await getAuthContext(token);
export const getRandomLastName = () => { const afterAction = async () => {
return `${nouns[Math.floor(Math.random() * nouns.length)]}${uuid()}`; await apiContext.dispose();
}; await page.close();
export const generateRandomUsername = () => {
const firstName = getRandomFirstName();
const lastName = getRandomLastName();
return {
firstName,
lastName,
email: `${firstName}.${lastName}@example.com`,
password: 'User@OMD123',
}; };
return { page, apiContext, afterAction };
}; };
export const nonDeletedUserChecks = async (page: Page) => { export const nonDeletedUserChecks = async (page: Page) => {