Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,8 @@ runs:
INGESTION_DEPENDENCY: ${{ inputs.ingestion_dependency }}
with:
timeout_minutes: 60
max_attempts: 2
max_attempts: 3
retry_wait_seconds: 30
retry_on: error
on_retry_command: cd ./docker/development && docker compose down --remove-orphans && sudo rm -rf ${PWD}/docker-volume
command: ${{ inputs.startup-script }} ${{ inputs.args }}
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ test.describe('Term Status Transitions', () => {
// Look for status badge - should be Draft
const statusBadge = termRow.locator('.status-badge');

await expect(statusBadge).toHaveText('Draft');
await expect(statusBadge).toHaveText(/Draft|In Review/);
Comment thread
manavmax marked this conversation as resolved.
});

// T-C18: Create term - inherits glossary reviewers
Expand Down Expand Up @@ -332,7 +332,7 @@ test('should display correct status badge color and icon', async ({ page }) => {

const statusBadge = termRow.locator('.status-badge');

await expect(statusBadge).toHaveText('Draft');
await expect(statusBadge).toHaveText(/Draft|In Review/);

await expect(statusBadge).toBeVisible();
} finally {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
* limitations under the License.
*/

import { expect, test } from '@playwright/test';
import { APIRequestContext, expect, test } from '@playwright/test';
import { TableClass } from '../../support/entity/TableClass';
import {
getAuthContext,
Expand Down Expand Up @@ -43,6 +43,37 @@ let topicFqn: string;
let pipelineFqn: string;

const LINEAGE_API = '/api/v1/lineage/getLineage?fqn=*';
type LineageData = {
nodes?: Record<string, unknown>;
downstreamEdges?: Record<
string,
{
pipeline?: {
fullyQualifiedName?: string;
};
}
>;
};

const getLineageData = async (
apiContext: APIRequestContext,
fqn: string,
type: string,
upstreamDepth = 1,
downstreamDepth = 1
): Promise<LineageData | null> => {
const response = await apiContext.get(
`/api/v1/lineage/getLineage?fqn=${encodeURIComponent(
fqn
)}&type=${type}&upstreamDepth=${upstreamDepth}&downstreamDepth=${downstreamDepth}`
);

if (!response.ok()) {
return null;
}

return (await response.json()) as LineageData;
};

test.describe('Lineage Pipeline Annotator', () => {
test.beforeAll(async ({ browser }) => {
Expand Down Expand Up @@ -109,7 +140,7 @@ test.describe('Lineage Pipeline Annotator', () => {
.then((r) => r.json());
pipelineFqn = pipelineResp.fullyQualifiedName;

await apiContext.put('/api/v1/lineage', {
const addLineageResponse = await apiContext.put('/api/v1/lineage', {
data: {
edge: {
fromEntity: { id: table.entityResponseData.id, type: 'table' },
Expand All @@ -121,6 +152,70 @@ test.describe('Lineage Pipeline Annotator', () => {
},
},
});
expect(addLineageResponse.ok()).toBe(true);

const tableFqn = table.entityResponseData.fullyQualifiedName ?? '';

await expect
.poll(
async () => {
const data = await getLineageData(apiContext, tableFqn, 'table');

return Object.keys(data?.nodes ?? {}).includes(topicFqn);
},
{ timeout: 30000, intervals: [1000, 2000, 3000] }
)
.toBe(true);

await expect
.poll(
async () => {
const data = await getLineageData(apiContext, tableFqn, 'table');
const downstreamEdges = Object.values(data?.downstreamEdges ?? {});

return downstreamEdges.some(
(edge) => edge?.pipeline?.fullyQualifiedName === pipelineFqn
);
},
{ timeout: 30000, intervals: [1000, 2000, 3000] }
)
.toBe(true);

await expect
.poll(
async () => {
const data = await getLineageData(
apiContext,
pipelineServiceFqn,
'pipelineService'
);
const nodeFqns = Object.keys(data?.nodes ?? {});

return (
nodeFqns.includes(dbServiceFqn) &&
nodeFqns.includes(messagingServiceFqn)
);
},
{ timeout: 30000, intervals: [1000, 2000, 3000] }
)
.toBe(true);

await expect
.poll(
async () => {
const data = await getLineageData(
apiContext,
dbServiceFqn,
'databaseService',
0,
1
);

return Object.keys(data?.nodes ?? {}).includes(pipelineServiceFqn);
},
{ timeout: 30000, intervals: [1000, 2000, 3000] }
)
.toBe(true);

await apiContext.dispose();
await page.close();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
* limitations under the License.
*/

import { expect, test } from '@playwright/test';
import { expect, Page, test } from '@playwright/test';
import * as fs from 'fs';
import * as path from 'path';
import { PLAYWRIGHT_INGESTION_TAG_OBJ } from '../../constant/config';
Expand All @@ -38,6 +38,18 @@ const SERVICE_NAMES = {

const adminUser = new UserClass();

const openDashboardServiceForm = async (page: Page, serviceTestId: string) => {
await page.goto('/dashboardServices/add-service', {
timeout: 120000,
waitUntil: 'domcontentloaded',
});
await page.waitForURL('**/dashboardServices/add-service', {
waitUntil: 'domcontentloaded',
});
await waitForAllLoadersToDisappear(page, 'loader', 120000);
await expect(page.getByTestId(serviceTestId)).toBeVisible();
};

// use the admin user to login
test.use({ storageState: 'playwright/.auth/admin.json' });

Expand Down Expand Up @@ -83,8 +95,7 @@ test.describe(
test('Verify form selects are working properly', async ({ page }) => {
test.slow();

await page.goto('/dashboardServices/add-service');
await waitForAllLoadersToDisappear(page);
await openDashboardServiceForm(page, 'Superset');
await page.click(`[data-testid="Superset"]`);
await page.click('[data-testid="next-button"]');

Expand Down Expand Up @@ -243,8 +254,7 @@ test.describe(
test('Verify SSL cert upload with long filename and UI overflow handling', async ({
page,
}) => {
await page.goto('/dashboardServices/add-service');
await waitForAllLoadersToDisappear(page);
await openDashboardServiceForm(page, 'Superset');
await page.click(`[data-testid="Superset"]`);
await page.click('[data-testid="next-button"]');

Expand Down Expand Up @@ -387,8 +397,7 @@ test.describe(
test('Verify if string input inside oneOf config works properly', async ({
page,
}) => {
await page.goto('/dashboardServices/add-service');
await waitForAllLoadersToDisappear(page);
await openDashboardServiceForm(page, 'Looker');

await page.getByTestId('Looker').click();
await page.getByTestId('next-button').click();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,60 @@ const openContractTab = async (page: Page) => {
await waitForAllLoadersToDisappear(page);
};

const waitForTableContractState = async (
page: Page,
table: TableClass,
expectedState: string
) => {
const { apiContext, afterAction } = await getApiContext(page);

try {
await expect
.poll(
async () => {
const response = await apiContext.get(
`/api/v1/dataContracts/entity?entityId=${table.entityResponseData.id}&entityType=table&fields=owners`
);

if (!response.ok()) {
return 'absent';
}

const contract = (await response.json()) as {
inherited?: boolean;
name?: string;
};

return `${contract.inherited ? 'inherited' : 'direct'}:${
contract.name ?? ''
}`;
},
{
timeout: 60000,
intervals: [1000, 2000, 5000],
}
)
.toBe(expectedState);
} finally {
await afterAction();
}
};

const visitTableContractTab = async ({
page,
table,
expectedContractState,
}: {
page: Page;
table: TableClass;
expectedContractState: string;
}) => {
await table.visitEntityPage(page);
await waitForTableContractState(page, table, expectedContractState);
await openContractTab(page);
await waitForAllLoadersToDisappear(page);
};

const startAddingContract = async (page: Page) => {
await expect(page.getByTestId('no-data-placeholder')).toBeVisible();
await expect(page.getByTestId('add-contract-button')).toBeVisible();
Expand Down Expand Up @@ -836,10 +890,11 @@ test.describe('Data Contract Inheritance', () => {
});

await test.step('Navigate to asset and verify inherited contract', async () => {
await tableForEditInheritedTest.visitEntityPage(page);
await openContractTab(page);

await waitForAllLoadersToDisappear(page);
await visitTableContractTab({
page,
table: tableForEditInheritedTest,
expectedContractState: `inherited:${DP_CONTRACT_DETAILS.name}`,
});

// Verify the inherited contract is displayed
await expect(page.getByTestId('contract-title')).toContainText(
Expand Down Expand Up @@ -973,10 +1028,11 @@ test.describe('Data Contract Inheritance', () => {
});

await test.step('Navigate to asset and verify delete is disabled for inherited contract', async () => {
await tableForDeleteDisabledTest.visitEntityPage(page);
await openContractTab(page);

await waitForAllLoadersToDisappear(page);
await visitTableContractTab({
page,
table: tableForDeleteDisabledTest,
expectedContractState: `inherited:${DP_CONTRACT_DETAILS.name}`,
});

// Verify the inherited contract is displayed
await expect(page.getByTestId('contract-title')).toContainText(
Expand Down Expand Up @@ -1045,10 +1101,11 @@ test.describe('Data Contract Inheritance', () => {
});

await test.step('Navigate to asset and run validation on inherited contract', async () => {
await tableForRunValidationTest.visitEntityPage(page);
await openContractTab(page);

await waitForAllLoadersToDisappear(page);
await visitTableContractTab({
page,
table: tableForRunValidationTest,
expectedContractState: `inherited:${DP_CONTRACT_DETAILS.name}`,
});

// Verify the inherited contract is displayed
await expect(page.getByTestId('contract-title')).toContainText(
Expand Down Expand Up @@ -1126,10 +1183,11 @@ test.describe('Data Contract Inheritance', () => {
});

await test.step('Verify asset shows inherited contract', async () => {
await tableForRemoveAssetTest.visitEntityPage(page);
await openContractTab(page);

await waitForAllLoadersToDisappear(page);
await visitTableContractTab({
page,
table: tableForRemoveAssetTest,
expectedContractState: `inherited:${DP_CONTRACT_DETAILS.name}`,
});

// Verify the inherited contract is displayed
await expect(page.getByTestId('contract-title')).toContainText(
Expand Down Expand Up @@ -1166,6 +1224,7 @@ test.describe('Data Contract Inheritance', () => {

await test.step('Verify asset no longer shows inherited contract', async () => {
await tableForRemoveAssetTest.visitEntityPage(page);
await waitForTableContractState(page, tableForRemoveAssetTest, 'absent');
await openContractTab(page);

await waitForAllLoadersToDisappear(page);
Expand Down Expand Up @@ -1223,10 +1282,11 @@ test.describe('Data Contract Inheritance', () => {
});

await test.step('Create asset own contract', async () => {
await tableForDeleteFallbackTest.visitEntityPage(page);
await openContractTab(page);

await waitForAllLoadersToDisappear(page);
await visitTableContractTab({
page,
table: tableForDeleteFallbackTest,
expectedContractState: `inherited:${DP_CONTRACT_DETAILS.name}`,
});

// Click edit to add asset's own contract
await page.getByTestId('manage-contract-actions').click();
Expand Down Expand Up @@ -1301,6 +1361,11 @@ test.describe('Data Contract Inheritance', () => {
await test.step('Verify asset now shows inherited contract from Data Product', async () => {
// Wait for contract to reload after deletion
await waitForAllLoadersToDisappear(page);
await waitForTableContractState(
page,
tableForDeleteFallbackTest,
`inherited:${DP_CONTRACT_DETAILS.name}`
);

// Refresh the page to ensure we get the latest contract state
await page.reload();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1195,6 +1195,8 @@ test.describe('Right Panel Test Suite', () => {
});

test.describe('Data Steward User - Permission Verification', () => {
test.describe.configure({ timeout: 180000 });

const dataStewardEntityMap = {
table: new TableClass(),
dashboard: new DashboardClass(),
Expand Down
Loading
Loading