Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

423 lines
12 KiB
TypeScript
Raw Normal View History

/*
* 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 } from '@playwright/test';
import { get } from 'lodash';
feat(#10933): API service UI (#17003) * feat(#10933): API service UI * feat: Add support for API collections in multiple languages * feat: add collection page * feat: Add support for multiple languages in endpoint-plural translation * chore: Add 'Beta' tag to API Services card, mark 'REST' service as beta, hide Pipelines tab, and update API Schemas card in settings. * fix: api service version page to show list of collections * feat: add api collect version page * feat: add custom property support for api collections and endpoints * feat: Add API Collection and API Endpoint translations in multiple languages * Refactor proxy configuration to use '/api/' context instead of '/api/v1' * feat: add apiEndpoint page * feat: add APIEndpoint summary component * feat: add APIEndpoint schema component * chore: remove the schema type from APIEndpointSchema component * feat: add version page component for API endpoint * chore: add task support for api collection and api endpoint * chore: remove schema from request and response label * chore: don't show add ingestion button for api services * feat: add search support for api entity * feat: add request and response schema field translations for multiple languages * chore: update icons * refactor: Add null checks in EntityUtils.tsx * feat: show deleted child entities if service is deleted * chore: Update addApiEndpointFollower function in apiEndpointsAPI.ts * feat: Add API collection and endpoint retrieval in EntityPopOverCard.tsx * chore: add api endpoint in data assets widget * feat: Add extra info link in data assets header * chore: Add API endpoint index to DataAssetsWidget test * feat: add api endpoint to explore tree * test: add cypress for apiendpoint and apicollection custom property * test: add playwright test for api service entity * test: add playwright test for api collection entity * test: Add ApiEndpoint playwright test * test: fix api endpoint and api collection test * fix: minor issues * test: add playwright test for creating service from ui and explore page tree * test: add playwright test for api endpoint lineage * feat: Update API collection page to use specific fields for owner, tags, and votes * test: remove api endpoint class from linage spec
2024-07-26 14:31:17 +05:30
import { ApiEndpointClass } from '../support/entity/ApiEndpointClass';
import { ContainerClass } from '../support/entity/ContainerClass';
import { DashboardClass } from '../support/entity/DashboardClass';
import { EntityClass } from '../support/entity/EntityClass';
Issue-15768: Support Metric Entity (#17680) * Issue-15768: Support Metric Entity * Issue-15768: Support Metric Entity * Issue-15768: Support Metric Entity * Fix tests * Fix tests * Fix tests * Minor: Fix tests * ui: add metricsAPI rest utils * ui: metric list page part 1 * feat: Add metric translations for multiple languages * chore: Add "metric" field to SearchIndexingApplication schema * ui: add create metric page * ui: metric details page patch 1 * ui: add custom property and lineage support for metric entity * ui: add expression component * ui: add metric summary component * chore: Update tab labels in MetricDetails and MetricVersion components * ui: show other info like metric type, granularity, etc * feat: Add support for metric entity in search dropdown * feat: Rename custom property to Metric in MetricEntity.md * feat: Add OwnerLabel component to MetricListPage * Fix expression field in Metric * chore: update expression to metricExpression * ui: add metric header component with edit option * Add metric to SearchIndexApp * chore: Update expression to metricExpression * ui: allow metric expression edit * ui: update metric icon * minor improvements * Fix lineage indexing for Metric * Update GlobalSettingsClassBase.ts to use MetricIcon for metrics in the global settings menu * Fix error handling in MetricListPage component * add related metrics * minor improvements * Fix relatedTerms patch * Fix relatedTerms validation * Add Boolean for deleted * filter active entity from related metric list * playwrite e2e part 1 * Refactor MetricSummary component to include RelatedMetrics in the summary panel * test: add playwright test for metric special cases * Add 'Metrics' to Explore Tree * test: add e2e for add metric page * test: add test for metric listing page content * Add Boolean for deleted, remove deleted from suggests * Refactor LineageProvider to handle deleted flag properly * add playwright for metric listing * fix test * Add colored metric icon and update its usage in GlobalSettingsClassBase * Fixed py_test test_ometa_endpoint for metric --------- Co-authored-by: Sachin Chaurasiya <sachinchaurasiyachotey87@gmail.com> Co-authored-by: mohitdeuex <mohit.y@deuexsolutions.com> Co-authored-by: Chirag Madlani <12962843+chirag-madlani@users.noreply.github.com> Co-authored-by: SumanMaharana <sumanmaharana786@gmail.com> Co-authored-by: Ashish Gupta <ashish@getcollate.io>
2024-09-15 23:06:31 -07:00
import { MetricClass } from '../support/entity/MetricClass';
import { MlModelClass } from '../support/entity/MlModelClass';
import { PipelineClass } from '../support/entity/PipelineClass';
import { SearchIndexClass } from '../support/entity/SearchIndexClass';
import { TableClass } from '../support/entity/TableClass';
import { TopicClass } from '../support/entity/TopicClass';
import { getApiContext, getEntityTypeSearchIndexMapping } from './common';
export const verifyColumnLayerInactive = async (page: Page) => {
await page.click('[data-testid="lineage-layer-btn"]'); // Open Layer popover
await page.waitForSelector(
'[data-testid="lineage-layer-column-btn"]:not(.active)'
);
await page.click('[data-testid="lineage-layer-btn"]'); // Close Layer popover
};
export const activateColumnLayer = async (page: Page) => {
await page.click('[data-testid="lineage-layer-btn"]');
await page.click('[data-testid="lineage-layer-column-btn"]');
};
export const editLineage = async (page: Page) => {
await page.click('[data-testid="edit-lineage"]');
await expect(
page.getByTestId('table_search_index-draggable-icon')
).toBeVisible();
};
export const performZoomOut = async (page: Page) => {
const zoomOutBtn = page.locator('.react-flow__controls-zoomout');
const enabled = await zoomOutBtn.isEnabled();
if (enabled) {
for (const _ of Array.from({ length: 8 })) {
await zoomOutBtn.dispatchEvent('click');
}
}
};
export const deleteEdge = async (
page: Page,
fromNode: EntityClass,
toNode: EntityClass
) => {
const fromNodeFqn = get(fromNode, 'entityResponseData.fullyQualifiedName');
const toNodeFqn = get(toNode, 'entityResponseData.fullyQualifiedName');
await page
.locator(`[data-testid="edge-${fromNodeFqn}-${toNodeFqn}"]`)
.dispatchEvent('click');
await page.locator('[data-testid="add-pipeline"]').dispatchEvent('click');
await expect(page.locator('[role="dialog"]')).toBeVisible();
await page
.locator(
'[data-testid="add-edge-modal"] [data-testid="remove-edge-button"]'
)
.dispatchEvent('click');
await expect(page.locator('[role="dialog"]')).toBeVisible();
const deleteRes = page.waitForResponse('/api/v1/lineage/**');
await page
.locator('[data-testid="delete-edge-confirmation-modal"] .ant-btn-primary')
.dispatchEvent('click');
await deleteRes;
};
export const dragAndDropNode = async (
page: Page,
originSelector: string,
destinationSelector: string
) => {
const destinationElement = await page.waitForSelector(destinationSelector);
await page.hover(originSelector);
await page.mouse.down();
const box = (await destinationElement.boundingBox())!;
await page.mouse.move(box.x + box.width / 2, box.y + box.height / 2);
await destinationElement.hover();
await page.mouse.up();
};
export const dragConnection = async (
page: Page,
sourceId: string,
targetId: string,
isColumnLineage = false
) => {
const selector = !isColumnLineage
? '.lineage-node-handle'
: '.lineage-column-node-handle';
const lineageRes = page.waitForResponse('/api/v1/lineage');
await page
.locator(`[data-testid="${sourceId}"] ${selector}.react-flow__handle-right`)
.dispatchEvent('click');
await page
.locator(`[data-testid="${targetId}"] ${selector}.react-flow__handle-left`)
.dispatchEvent('click');
await lineageRes;
};
export const connectEdgeBetweenNodes = async (
page: Page,
fromNode: EntityClass,
toNode: EntityClass
) => {
const type = getEntityTypeSearchIndexMapping(toNode.type);
const fromNodeFqn = get(fromNode, 'entityResponseData.fullyQualifiedName');
const toNodeName = get(toNode, 'entityResponseData.name');
const toNodeFqn = get(toNode, 'entityResponseData.fullyQualifiedName');
const source = `[data-testid="${type}-draggable-icon"]`;
const target = '[data-testid="lineage-details"]';
await dragAndDropNode(page, source, target);
await page.locator('[data-testid="suggestion-node"]').dispatchEvent('click');
const waitForSearchResponse = page.waitForResponse(
`/api/v1/search/query?q=*&from=0&size=10&*`
);
await page.locator('[data-testid="suggestion-node"] input').fill(toNodeName);
await waitForSearchResponse;
await page
.locator(`[data-testid="node-suggestion-${toNodeFqn}"]`)
.dispatchEvent('click');
await dragConnection(
page,
`lineage-node-${fromNodeFqn}`,
`lineage-node-${toNodeFqn}`
);
};
export const verifyNodePresent = async (page: Page, node: EntityClass) => {
const nodeFqn = get(node, 'entityResponseData.fullyQualifiedName');
const name = get(node, 'entityResponseData.name');
const lineageNode = page.locator(`[data-testid="lineage-node-${nodeFqn}"]`);
await expect(lineageNode).toBeVisible();
const entityHeaderName = lineageNode.locator(
'[data-testid="entity-header-name"]'
);
await expect(entityHeaderName).toHaveText(name);
};
export const setupEntitiesForLineage = async (
page: Page,
currentEntity:
| TableClass
| DashboardClass
| TopicClass
| MlModelClass
| ContainerClass
| SearchIndexClass
feat(#10933): API service UI (#17003) * feat(#10933): API service UI * feat: Add support for API collections in multiple languages * feat: add collection page * feat: Add support for multiple languages in endpoint-plural translation * chore: Add 'Beta' tag to API Services card, mark 'REST' service as beta, hide Pipelines tab, and update API Schemas card in settings. * fix: api service version page to show list of collections * feat: add api collect version page * feat: add custom property support for api collections and endpoints * feat: Add API Collection and API Endpoint translations in multiple languages * Refactor proxy configuration to use '/api/' context instead of '/api/v1' * feat: add apiEndpoint page * feat: add APIEndpoint summary component * feat: add APIEndpoint schema component * chore: remove the schema type from APIEndpointSchema component * feat: add version page component for API endpoint * chore: add task support for api collection and api endpoint * chore: remove schema from request and response label * chore: don't show add ingestion button for api services * feat: add search support for api entity * feat: add request and response schema field translations for multiple languages * chore: update icons * refactor: Add null checks in EntityUtils.tsx * feat: show deleted child entities if service is deleted * chore: Update addApiEndpointFollower function in apiEndpointsAPI.ts * feat: Add API collection and endpoint retrieval in EntityPopOverCard.tsx * chore: add api endpoint in data assets widget * feat: Add extra info link in data assets header * chore: Add API endpoint index to DataAssetsWidget test * feat: add api endpoint to explore tree * test: add cypress for apiendpoint and apicollection custom property * test: add playwright test for api service entity * test: add playwright test for api collection entity * test: Add ApiEndpoint playwright test * test: fix api endpoint and api collection test * fix: minor issues * test: add playwright test for creating service from ui and explore page tree * test: add playwright test for api endpoint lineage * feat: Update API collection page to use specific fields for owner, tags, and votes * test: remove api endpoint class from linage spec
2024-07-26 14:31:17 +05:30
| ApiEndpointClass
Issue-15768: Support Metric Entity (#17680) * Issue-15768: Support Metric Entity * Issue-15768: Support Metric Entity * Issue-15768: Support Metric Entity * Fix tests * Fix tests * Fix tests * Minor: Fix tests * ui: add metricsAPI rest utils * ui: metric list page part 1 * feat: Add metric translations for multiple languages * chore: Add "metric" field to SearchIndexingApplication schema * ui: add create metric page * ui: metric details page patch 1 * ui: add custom property and lineage support for metric entity * ui: add expression component * ui: add metric summary component * chore: Update tab labels in MetricDetails and MetricVersion components * ui: show other info like metric type, granularity, etc * feat: Add support for metric entity in search dropdown * feat: Rename custom property to Metric in MetricEntity.md * feat: Add OwnerLabel component to MetricListPage * Fix expression field in Metric * chore: update expression to metricExpression * ui: add metric header component with edit option * Add metric to SearchIndexApp * chore: Update expression to metricExpression * ui: allow metric expression edit * ui: update metric icon * minor improvements * Fix lineage indexing for Metric * Update GlobalSettingsClassBase.ts to use MetricIcon for metrics in the global settings menu * Fix error handling in MetricListPage component * add related metrics * minor improvements * Fix relatedTerms patch * Fix relatedTerms validation * Add Boolean for deleted * filter active entity from related metric list * playwrite e2e part 1 * Refactor MetricSummary component to include RelatedMetrics in the summary panel * test: add playwright test for metric special cases * Add 'Metrics' to Explore Tree * test: add e2e for add metric page * test: add test for metric listing page content * Add Boolean for deleted, remove deleted from suggests * Refactor LineageProvider to handle deleted flag properly * add playwright for metric listing * fix test * Add colored metric icon and update its usage in GlobalSettingsClassBase * Fixed py_test test_ometa_endpoint for metric --------- Co-authored-by: Sachin Chaurasiya <sachinchaurasiyachotey87@gmail.com> Co-authored-by: mohitdeuex <mohit.y@deuexsolutions.com> Co-authored-by: Chirag Madlani <12962843+chirag-madlani@users.noreply.github.com> Co-authored-by: SumanMaharana <sumanmaharana786@gmail.com> Co-authored-by: Ashish Gupta <ashish@getcollate.io>
2024-09-15 23:06:31 -07:00
| MetricClass
) => {
const entities = [
new TableClass(),
new DashboardClass(),
new TopicClass(),
new MlModelClass(),
new ContainerClass(),
new SearchIndexClass(),
feat(#10933): API service UI (#17003) * feat(#10933): API service UI * feat: Add support for API collections in multiple languages * feat: add collection page * feat: Add support for multiple languages in endpoint-plural translation * chore: Add 'Beta' tag to API Services card, mark 'REST' service as beta, hide Pipelines tab, and update API Schemas card in settings. * fix: api service version page to show list of collections * feat: add api collect version page * feat: add custom property support for api collections and endpoints * feat: Add API Collection and API Endpoint translations in multiple languages * Refactor proxy configuration to use '/api/' context instead of '/api/v1' * feat: add apiEndpoint page * feat: add APIEndpoint summary component * feat: add APIEndpoint schema component * chore: remove the schema type from APIEndpointSchema component * feat: add version page component for API endpoint * chore: add task support for api collection and api endpoint * chore: remove schema from request and response label * chore: don't show add ingestion button for api services * feat: add search support for api entity * feat: add request and response schema field translations for multiple languages * chore: update icons * refactor: Add null checks in EntityUtils.tsx * feat: show deleted child entities if service is deleted * chore: Update addApiEndpointFollower function in apiEndpointsAPI.ts * feat: Add API collection and endpoint retrieval in EntityPopOverCard.tsx * chore: add api endpoint in data assets widget * feat: Add extra info link in data assets header * chore: Add API endpoint index to DataAssetsWidget test * feat: add api endpoint to explore tree * test: add cypress for apiendpoint and apicollection custom property * test: add playwright test for api service entity * test: add playwright test for api collection entity * test: Add ApiEndpoint playwright test * test: fix api endpoint and api collection test * fix: minor issues * test: add playwright test for creating service from ui and explore page tree * test: add playwright test for api endpoint lineage * feat: Update API collection page to use specific fields for owner, tags, and votes * test: remove api endpoint class from linage spec
2024-07-26 14:31:17 +05:30
new ApiEndpointClass(),
Issue-15768: Support Metric Entity (#17680) * Issue-15768: Support Metric Entity * Issue-15768: Support Metric Entity * Issue-15768: Support Metric Entity * Fix tests * Fix tests * Fix tests * Minor: Fix tests * ui: add metricsAPI rest utils * ui: metric list page part 1 * feat: Add metric translations for multiple languages * chore: Add "metric" field to SearchIndexingApplication schema * ui: add create metric page * ui: metric details page patch 1 * ui: add custom property and lineage support for metric entity * ui: add expression component * ui: add metric summary component * chore: Update tab labels in MetricDetails and MetricVersion components * ui: show other info like metric type, granularity, etc * feat: Add support for metric entity in search dropdown * feat: Rename custom property to Metric in MetricEntity.md * feat: Add OwnerLabel component to MetricListPage * Fix expression field in Metric * chore: update expression to metricExpression * ui: add metric header component with edit option * Add metric to SearchIndexApp * chore: Update expression to metricExpression * ui: allow metric expression edit * ui: update metric icon * minor improvements * Fix lineage indexing for Metric * Update GlobalSettingsClassBase.ts to use MetricIcon for metrics in the global settings menu * Fix error handling in MetricListPage component * add related metrics * minor improvements * Fix relatedTerms patch * Fix relatedTerms validation * Add Boolean for deleted * filter active entity from related metric list * playwrite e2e part 1 * Refactor MetricSummary component to include RelatedMetrics in the summary panel * test: add playwright test for metric special cases * Add 'Metrics' to Explore Tree * test: add e2e for add metric page * test: add test for metric listing page content * Add Boolean for deleted, remove deleted from suggests * Refactor LineageProvider to handle deleted flag properly * add playwright for metric listing * fix test * Add colored metric icon and update its usage in GlobalSettingsClassBase * Fixed py_test test_ometa_endpoint for metric --------- Co-authored-by: Sachin Chaurasiya <sachinchaurasiyachotey87@gmail.com> Co-authored-by: mohitdeuex <mohit.y@deuexsolutions.com> Co-authored-by: Chirag Madlani <12962843+chirag-madlani@users.noreply.github.com> Co-authored-by: SumanMaharana <sumanmaharana786@gmail.com> Co-authored-by: Ashish Gupta <ashish@getcollate.io>
2024-09-15 23:06:31 -07:00
new MetricClass(),
] as const;
const { apiContext, afterAction } = await getApiContext(page);
for (const entity of entities) {
await entity.create(apiContext);
}
await currentEntity.create(apiContext);
const cleanup = async () => {
await currentEntity.delete(apiContext);
for (const entity of entities) {
await entity.delete(apiContext);
}
await afterAction();
};
return { currentEntity, entities, cleanup };
};
export const editPipelineEdgeDescription = async (
page: Page,
fromNode: EntityClass,
toNode: EntityClass,
pipelineData,
description: string
) => {
const fromNodeFqn = get(fromNode, 'entityResponseData.fullyQualifiedName');
const toNodeFqn = get(toNode, 'entityResponseData.fullyQualifiedName');
await page.click(
`[data-testid="pipeline-label-${fromNodeFqn}-${toNodeFqn}"]`
);
await page.locator('.edge-info-drawer').isVisible();
await page
.locator('.edge-info-drawer [data-testid="Edge"] a')
.filter({ hasText: pipelineData.name });
await page.click('.edge-info-drawer [data-testid="edit-description"]');
await page.locator('.ProseMirror').first().click();
await page.locator('.ProseMirror').first().clear();
await page.locator('.ProseMirror').first().fill(description);
const descRes = page.waitForResponse('/api/v1/lineage');
await page.getByTestId('save').click();
await descRes;
await expect(
page.getByTestId('asset-description-container').getByRole('paragraph')
).toContainText(description);
};
const verifyPipelineDataInDrawer = async (
page: Page,
fromNode: EntityClass,
toNode: EntityClass,
pipelineItem: PipelineClass,
bVisitPipelinePageFromDrawer: boolean
) => {
const fromNodeFqn = get(fromNode, 'entityResponseData.fullyQualifiedName');
const toNodeFqn = get(toNode, 'entityResponseData.fullyQualifiedName');
const pipelineName = get(pipelineItem, 'entityResponseData.name');
await page.click(
`[data-testid="pipeline-label-${fromNodeFqn}-${toNodeFqn}"]`
);
await page.locator('.edge-info-drawer').isVisible();
await page
.locator('.edge-info-drawer [data-testid="Edge"] a')
.filter({ hasText: pipelineName });
if (bVisitPipelinePageFromDrawer) {
await page.locator('.edge-info-drawer [data-testid="Edge"] a').click();
await page.click('[data-testid="lineage"]');
await fromNode.visitEntityPage(page);
await page.click('[data-testid="lineage"]');
} else {
await page.click('.edge-info-drawer .ant-drawer-header .anticon-close');
}
};
export const applyPipelineFromModal = async (
page: Page,
fromNode: EntityClass,
toNode: EntityClass,
pipelineItem?: PipelineClass
) => {
const fromNodeFqn = get(fromNode, 'entityResponseData.fullyQualifiedName');
const toNodeFqn = get(toNode, 'entityResponseData.fullyQualifiedName');
const pipelineName = get(pipelineItem, 'entityResponseData.name');
const pipelineFqn = get(
pipelineItem,
'entityResponseData.fullyQualifiedName'
);
await page
.locator(`[data-testid="edge-${fromNodeFqn}-${toNodeFqn}"]`)
.dispatchEvent('click');
await page.locator('[data-testid="add-pipeline"]').dispatchEvent('click');
const waitForSearchResponse = page.waitForResponse(
`/api/v1/search/query?q=*&from=0&size=10&*`
);
await page
.locator('[data-testid="add-edge-modal"] [data-testid="field-input"]')
.fill(pipelineName);
await waitForSearchResponse;
await page.click(`[data-testid="pipeline-entry-${pipelineFqn}"]`);
const saveRes = page.waitForResponse('/api/v1/lineage');
await page.click('[data-testid="save-button"]');
await saveRes;
};
export const deleteNode = async (page: Page, node: EntityClass) => {
const nodeFqn = get(node, 'entityResponseData.fullyQualifiedName');
await page
.locator(`[data-testid="lineage-node-${nodeFqn}"]`)
.dispatchEvent('click');
const lineageRes = page.waitForResponse('/api/v1/lineage/**');
await page
.locator('[data-testid="lineage-node-remove-btn"]')
.dispatchEvent('click');
await lineageRes;
};
export const addColumnLineage = async (
page: Page,
fromColumnNode: string,
toColumnNode: string,
exitEditMode = true
) => {
const lineageRes = page.waitForResponse('/api/v1/lineage');
await dragConnection(
page,
`column-${fromColumnNode}`,
`column-${toColumnNode}`,
true
);
await lineageRes;
if (exitEditMode) {
await page.click('[data-testid="edit-lineage"]');
}
await expect(
page.locator(
`[data-testid="column-edge-${btoa(fromColumnNode)}-${btoa(
toColumnNode
)}"]`
)
).toBeVisible();
};
export const removeColumnLineage = async (
page: Page,
fromColumnNode: string,
toColumnNode: string
) => {
await page
.locator(
`[data-testid="column-edge-${btoa(fromColumnNode)}-${btoa(
toColumnNode
)}"]`
)
.dispatchEvent('click');
await page.locator('[data-testid="delete-button"]').dispatchEvent('click');
const deleteRes = page.waitForResponse('/api/v1/lineage');
await page
.locator('[data-testid="delete-edge-confirmation-modal"] .ant-btn-primary')
.dispatchEvent('click');
await deleteRes;
await page.click('[data-testid="edit-lineage"]');
await expect(
page.locator(
`[data-testid="column-edge-${btoa(fromColumnNode)}-${btoa(
toColumnNode
)}"]`
)
).not.toBeVisible();
};
export const addPipelineBetweenNodes = async (
page: Page,
sourceEntity: EntityClass,
targetEntity: EntityClass,
pipelineItem?: PipelineClass,
bVerifyPipeline = false
) => {
await sourceEntity.visitEntityPage(page);
await page.click('[data-testid="lineage"]');
await editLineage(page);
await performZoomOut(page);
await connectEdgeBetweenNodes(page, sourceEntity, targetEntity);
if (pipelineItem) {
await applyPipelineFromModal(
page,
sourceEntity,
targetEntity,
pipelineItem
);
await page.click('[data-testid="edit-lineage"]');
await verifyPipelineDataInDrawer(
page,
sourceEntity,
targetEntity,
pipelineItem,
bVerifyPipeline
);
}
};
export const visitLineageTab = async (page: Page) => {
const lineageRes = page.waitForResponse('/api/v1/lineage/getLineage?*');
await page.click('[data-testid="lineage"]');
await lineageRes;
};