mirror of
https://github.com/open-metadata/OpenMetadata.git
synced 2026-01-06 12:36:56 +00:00
Refactor: Update DataQualityAndProfiler tests and ColumnProfileTable logic (#22364)
* Refactor: Update DataQualityAndProfiler tests and ColumnProfileTable logic - Replaced `createNewPage` with `performAdminLogin` for improved login handling in DataQualityAndProfiler tests. - Enhanced test case for profiler matrix visibility to include checks for admin, data consumer, and data steward roles. - Updated ColumnProfileTable to use `fqn` consistently instead of `tableProfiler?.fullyQualifiedName` for fetching table columns. This refactor aims to streamline the test setup and improve code clarity. * Enhance ColumnProfileTable to utilize getTableFQNFromColumnFQN for improved FQN handling - Updated ColumnProfileTable to derive table FQN from column FQN using the new utility function. - Refactored related logic to ensure consistent usage of table FQN across navigation and data fetching. - Added unit tests for getTableFQNFromColumnFQN to validate its functionality. This change aims to streamline the handling of fully qualified names in the profiler component.
This commit is contained in:
parent
05fa0b3185
commit
71ad8766d9
@ -10,7 +10,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { expect, Page, test } from '@playwright/test';
|
||||
import { expect, Page } from '@playwright/test';
|
||||
import { PLAYWRIGHT_INGESTION_TAG_OBJ } from '../../constant/config';
|
||||
import { SidebarItem } from '../../constant/sidebar';
|
||||
import { Domain } from '../../support/domain/Domain';
|
||||
@ -19,10 +19,10 @@ import { Glossary } from '../../support/glossary/Glossary';
|
||||
import { GlossaryTerm } from '../../support/glossary/GlossaryTerm';
|
||||
import { ClassificationClass } from '../../support/tag/ClassificationClass';
|
||||
import { TagClass } from '../../support/tag/TagClass';
|
||||
import { performAdminLogin } from '../../utils/admin';
|
||||
import {
|
||||
assignDomain,
|
||||
clickOutside,
|
||||
createNewPage,
|
||||
descriptionBox,
|
||||
getApiContext,
|
||||
redirectToHomePage,
|
||||
@ -33,9 +33,7 @@ import { getCurrentMillis } from '../../utils/dateTime';
|
||||
import { visitEntityPage } from '../../utils/entity';
|
||||
import { sidebarClick } from '../../utils/sidebar';
|
||||
import { deleteTestCase, visitDataQualityTab } from '../../utils/testCases';
|
||||
|
||||
// use the admin user to login
|
||||
test.use({ storageState: 'playwright/.auth/admin.json' });
|
||||
import { test } from '../fixtures/pages';
|
||||
|
||||
const table1 = new TableClass();
|
||||
const table2 = new TableClass();
|
||||
@ -53,7 +51,7 @@ const testGlossaryTerm1 = new GlossaryTerm(testGlossary);
|
||||
const testGlossaryTerm2 = new GlossaryTerm(testGlossary);
|
||||
|
||||
test.beforeAll(async ({ browser }) => {
|
||||
const { apiContext, afterAction } = await createNewPage(browser);
|
||||
const { apiContext, afterAction } = await performAdminLogin(browser);
|
||||
await table1.create(apiContext);
|
||||
await table2.create(apiContext);
|
||||
await table2.createTestCase(apiContext, {
|
||||
@ -77,7 +75,7 @@ test.beforeAll(async ({ browser }) => {
|
||||
});
|
||||
|
||||
test.afterAll(async ({ browser }) => {
|
||||
const { apiContext, afterAction } = await createNewPage(browser);
|
||||
const { apiContext, afterAction } = await performAdminLogin(browser);
|
||||
await table1.delete(apiContext);
|
||||
await table2.delete(apiContext);
|
||||
|
||||
@ -408,74 +406,106 @@ test('Column test case', PLAYWRIGHT_INGESTION_TAG_OBJ, async ({ page }) => {
|
||||
});
|
||||
|
||||
test(
|
||||
'Profiler matrix and test case graph should visible',
|
||||
'Profiler matrix and test case graph should visible for admin, data consumer and data steward',
|
||||
PLAYWRIGHT_INGESTION_TAG_OBJ,
|
||||
async ({ page }) => {
|
||||
async ({ page: adminPage, dataConsumerPage, dataStewardPage }) => {
|
||||
test.slow();
|
||||
|
||||
const DATA_QUALITY_TABLE = {
|
||||
term: 'dim_address',
|
||||
serviceName: 'sample_data',
|
||||
testCaseName: 'column_value_max_to_be_between',
|
||||
};
|
||||
|
||||
await visitEntityPage({
|
||||
page,
|
||||
searchTerm: DATA_QUALITY_TABLE.term,
|
||||
dataTestId: `${DATA_QUALITY_TABLE.serviceName}-${DATA_QUALITY_TABLE.term}`,
|
||||
});
|
||||
await page.waitForSelector(`[data-testid="entity-header-name"]`);
|
||||
const runProfilerTest = async (page: Page) => {
|
||||
await redirectToHomePage(page);
|
||||
await visitEntityPage({
|
||||
page,
|
||||
searchTerm: DATA_QUALITY_TABLE.term,
|
||||
dataTestId: `${DATA_QUALITY_TABLE.serviceName}-${DATA_QUALITY_TABLE.term}`,
|
||||
});
|
||||
|
||||
await expect(
|
||||
page.locator(`[data-testid="entity-header-name"]`)
|
||||
).toContainText(DATA_QUALITY_TABLE.term);
|
||||
await page.waitForSelector(`[data-testid="entity-header-name"]`);
|
||||
|
||||
const profilerResponse = page.waitForResponse(
|
||||
`/api/v1/tables/*/tableProfile/latest?includeColumnProfile=false`
|
||||
);
|
||||
await page.click('[data-testid="profiler"]');
|
||||
await profilerResponse;
|
||||
await page.waitForTimeout(1000);
|
||||
await page
|
||||
.getByRole('menuitem', {
|
||||
name: 'Column Profile',
|
||||
})
|
||||
.click();
|
||||
const getProfilerInfo = page.waitForResponse(
|
||||
'/api/v1/tables/*/columnProfile?*'
|
||||
);
|
||||
await page.locator('[data-row-key="shop_id"]').getByText('shop_id').click();
|
||||
await getProfilerInfo;
|
||||
await expect(
|
||||
page.locator(`[data-testid="entity-header-name"]`)
|
||||
).toContainText(DATA_QUALITY_TABLE.term);
|
||||
|
||||
await expect(page.locator('#count_graph')).toBeVisible();
|
||||
await expect(page.locator('#proportion_graph')).toBeVisible();
|
||||
await expect(page.locator('#math_graph')).toBeVisible();
|
||||
await expect(page.locator('#sum_graph')).toBeVisible();
|
||||
const profilerApiCall = page.waitForResponse(
|
||||
`/api/v1/tables/*/tableProfile/latest?includeColumnProfile=false`
|
||||
);
|
||||
await page.click('[data-testid="profiler"]');
|
||||
const profilerResponse = await profilerApiCall;
|
||||
|
||||
await page
|
||||
.getByRole('menuitem', {
|
||||
name: 'Data Quality',
|
||||
})
|
||||
.click();
|
||||
expect(profilerResponse.status()).toBe(200);
|
||||
|
||||
await page.waitForSelector(
|
||||
`[data-testid="${DATA_QUALITY_TABLE.testCaseName}"]`
|
||||
);
|
||||
const getTestCaseDetails = page.waitForResponse(
|
||||
'/api/v1/dataQuality/testCases/name/*?fields=*'
|
||||
);
|
||||
const getTestResult = page.waitForResponse(
|
||||
'/api/v1/dataQuality/testCases/testCaseResults/*?*'
|
||||
);
|
||||
await page
|
||||
.locator(`[data-testid="${DATA_QUALITY_TABLE.testCaseName}"]`)
|
||||
.getByText(DATA_QUALITY_TABLE.testCaseName)
|
||||
.click();
|
||||
const listColumnApiCall = page.waitForResponse(
|
||||
'/api/v1/tables/name/*/columns?*'
|
||||
);
|
||||
await page
|
||||
.getByRole('menuitem', {
|
||||
name: 'Column Profile',
|
||||
})
|
||||
.click();
|
||||
await listColumnApiCall;
|
||||
const listColumnResponse = await listColumnApiCall;
|
||||
|
||||
await getTestCaseDetails;
|
||||
await getTestResult;
|
||||
expect(listColumnResponse.status()).toBe(200);
|
||||
|
||||
await expect(
|
||||
page.locator(`#${DATA_QUALITY_TABLE.testCaseName}_graph`)
|
||||
).toBeVisible();
|
||||
const getProfilerInfo = page.waitForResponse(
|
||||
'/api/v1/tables/*/columnProfile?*'
|
||||
);
|
||||
await page
|
||||
.locator('[data-row-key="shop_id"]')
|
||||
.getByText('shop_id')
|
||||
.click();
|
||||
await getProfilerInfo;
|
||||
const getProfilerInfoResponse = await getProfilerInfo;
|
||||
|
||||
expect(getProfilerInfoResponse.status()).toBe(200);
|
||||
|
||||
await expect(page.locator('#count_graph')).toBeVisible();
|
||||
await expect(page.locator('#proportion_graph')).toBeVisible();
|
||||
await expect(page.locator('#math_graph')).toBeVisible();
|
||||
await expect(page.locator('#sum_graph')).toBeVisible();
|
||||
|
||||
await page
|
||||
.getByRole('menuitem', {
|
||||
name: 'Data Quality',
|
||||
})
|
||||
.click();
|
||||
|
||||
await page.waitForSelector(
|
||||
`[data-testid="${DATA_QUALITY_TABLE.testCaseName}"]`
|
||||
);
|
||||
const getTestCaseDetails = page.waitForResponse(
|
||||
'/api/v1/dataQuality/testCases/name/*?fields=*'
|
||||
);
|
||||
const getTestResult = page.waitForResponse(
|
||||
'/api/v1/dataQuality/testCases/testCaseResults/*?*'
|
||||
);
|
||||
await page
|
||||
.locator(`[data-testid="${DATA_QUALITY_TABLE.testCaseName}"]`)
|
||||
.getByText(DATA_QUALITY_TABLE.testCaseName)
|
||||
.click();
|
||||
|
||||
const getTestCaseDetailsResponse = await getTestCaseDetails;
|
||||
const getTestResultResponse = await getTestResult;
|
||||
|
||||
expect(getTestCaseDetailsResponse.status()).toBe(200);
|
||||
expect(getTestResultResponse.status()).toBe(200);
|
||||
|
||||
await expect(
|
||||
page.locator(`#${DATA_QUALITY_TABLE.testCaseName}_graph`)
|
||||
).toBeVisible();
|
||||
};
|
||||
|
||||
// Run all three user roles in parallel
|
||||
await Promise.all([
|
||||
runProfilerTest(adminPage),
|
||||
runProfilerTest(dataConsumerPage),
|
||||
runProfilerTest(dataStewardPage),
|
||||
]);
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
@ -49,6 +49,7 @@ jest.mock('../../../../common/SummaryCard/SummaryCard.component', () => ({
|
||||
|
||||
jest.mock('../../../../../utils/CommonUtils', () => ({
|
||||
formatNumberWithComma: jest.fn(),
|
||||
getTableFQNFromColumnFQN: jest.fn().mockImplementation((fqn) => fqn),
|
||||
}));
|
||||
jest.mock('../../../../common/SearchBarComponent/SearchBar.component', () => {
|
||||
return jest
|
||||
|
||||
@ -56,7 +56,10 @@ import {
|
||||
searchTableColumnsByFQN,
|
||||
} from '../../../../../rest/tableAPI';
|
||||
import { getListTestCaseBySearch } from '../../../../../rest/testAPI';
|
||||
import { formatNumberWithComma } from '../../../../../utils/CommonUtils';
|
||||
import {
|
||||
formatNumberWithComma,
|
||||
getTableFQNFromColumnFQN,
|
||||
} from '../../../../../utils/CommonUtils';
|
||||
import { getEntityName } from '../../../../../utils/EntityUtils';
|
||||
import { getEntityColumnFQN } from '../../../../../utils/FeedUtils';
|
||||
import { getPrioritizedEditPermission } from '../../../../../utils/PermissionsUtils';
|
||||
@ -92,6 +95,7 @@ const ColumnProfileTable = () => {
|
||||
const { t } = useTranslation();
|
||||
const navigate = useNavigate();
|
||||
const { fqn } = useFqn();
|
||||
const tableFqn = useMemo(() => getTableFQNFromColumnFQN(fqn), [fqn]);
|
||||
const {
|
||||
isTestsLoading,
|
||||
isProfilerDataLoading,
|
||||
@ -316,7 +320,7 @@ const ColumnProfileTable = () => {
|
||||
navigate({
|
||||
pathname: getAddDataQualityTableTestPath(
|
||||
ProfilerDashboardType.COLUMN,
|
||||
fqn
|
||||
tableFqn
|
||||
),
|
||||
search: activeColumnFqn ? Qs.stringify({ activeColumnFqn }) : '',
|
||||
});
|
||||
@ -327,7 +331,10 @@ const ColumnProfileTable = () => {
|
||||
key: 'custom-metric',
|
||||
onClick: () => {
|
||||
navigate({
|
||||
pathname: getAddCustomMetricPath(ProfilerDashboardType.COLUMN, fqn),
|
||||
pathname: getAddCustomMetricPath(
|
||||
ProfilerDashboardType.COLUMN,
|
||||
tableFqn
|
||||
),
|
||||
search: activeColumnFqn ? Qs.stringify({ activeColumnFqn }) : '',
|
||||
});
|
||||
},
|
||||
@ -405,9 +412,7 @@ const ColumnProfileTable = () => {
|
||||
|
||||
const fetchTableColumnWithProfiler = useCallback(
|
||||
async (page: number, searchText: string) => {
|
||||
const tableFQN = tableProfiler?.fullyQualifiedName;
|
||||
|
||||
if (!tableFQN) {
|
||||
if (!tableFqn) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -416,13 +421,13 @@ const ColumnProfileTable = () => {
|
||||
const offset = (page - 1) * pageSize;
|
||||
// Use search API if there's a search query, otherwise use regular pagination
|
||||
const response = searchText
|
||||
? await searchTableColumnsByFQN(tableFQN, {
|
||||
? await searchTableColumnsByFQN(tableFqn, {
|
||||
q: searchText,
|
||||
limit: pageSize,
|
||||
offset: offset,
|
||||
fields: TabSpecificField.PROFILE,
|
||||
})
|
||||
: await getTableColumnsByFQN(tableFQN, {
|
||||
: await getTableColumnsByFQN(tableFqn, {
|
||||
limit: pageSize,
|
||||
offset: offset,
|
||||
fields: TabSpecificField.PROFILE,
|
||||
@ -440,7 +445,7 @@ const ColumnProfileTable = () => {
|
||||
setIsColumnsLoading(false);
|
||||
}
|
||||
},
|
||||
[tableProfiler?.fullyQualifiedName, pageSize, searchText]
|
||||
[tableFqn, pageSize, searchText]
|
||||
);
|
||||
|
||||
const handleColumnProfilePageChange = useCallback(
|
||||
@ -451,10 +456,10 @@ const ColumnProfileTable = () => {
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (tableProfiler?.fullyQualifiedName) {
|
||||
if (tableFqn) {
|
||||
fetchTableColumnWithProfiler(currentPage, searchText);
|
||||
}
|
||||
}, [tableProfiler?.fullyQualifiedName, currentPage, searchText, pageSize]);
|
||||
}, [tableFqn, currentPage, searchText, pageSize]);
|
||||
|
||||
useEffect(() => {
|
||||
if (activeColumnFqn) {
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { filterSelectOptions } from './CommonUtils';
|
||||
import { filterSelectOptions, getTableFQNFromColumnFQN } from './CommonUtils';
|
||||
|
||||
describe('Tests for CommonUtils', () => {
|
||||
describe('filterSelectOptions', () => {
|
||||
@ -64,4 +64,20 @@ describe('Tests for CommonUtils', () => {
|
||||
expect(filterSelectOptions(input, option)).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getTableFQNFromColumnFQN', () => {
|
||||
it('should return the table FQN from a column FQN', () => {
|
||||
const columnFQN = 'service.database.schema.table.column';
|
||||
const tableFQN = getTableFQNFromColumnFQN(columnFQN);
|
||||
|
||||
expect(tableFQN).toBe('service.database.schema.table');
|
||||
});
|
||||
|
||||
it('should return the table FQN as it is if table FQN is provided', () => {
|
||||
const tableFQN = 'service.database.schema.table';
|
||||
const result = getTableFQNFromColumnFQN(tableFQN);
|
||||
|
||||
expect(result).toBe(tableFQN);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user