fix kpi data not showing in widget (#17594)

This commit is contained in:
Ashish Gupta 2024-08-27 21:18:26 +05:30 committed by GitHub
parent 60ed221cf1
commit 7813d82b91
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 230 additions and 43 deletions

View File

@ -22,6 +22,11 @@ test.use({ storageState: 'playwright/.auth/admin.json' });
test.describe.configure({ mode: 'serial' }); test.describe.configure({ mode: 'serial' });
const DESCRIPTION_WITH_PERCENTAGE =
'playwright-description-with-percentage-percentage';
const DESCRIPTION_WITH_OWNER = 'playwright-owner-with-percentage-percentage';
test.describe('Data Insight Page', { tag: '@data-insight' }, () => { test.describe('Data Insight Page', { tag: '@data-insight' }, () => {
test.beforeAll(async ({ browser }) => { test.beforeAll(async ({ browser }) => {
const { apiContext } = await createNewPage(browser); const { apiContext } = await createNewPage(browser);
@ -137,14 +142,10 @@ test.describe('Data Insight Page', { tag: '@data-insight' }, () => {
await expect(page.getByTestId('kpi-card')).toBeVisible(); await expect(page.getByTestId('kpi-card')).toBeVisible();
await expect( await expect(
page.locator( page.locator(`[data-row-key=${DESCRIPTION_WITH_PERCENTAGE}]`)
'[data-row-key="playwright-description-with-percentage-percentage"]'
)
).toBeVisible(); ).toBeVisible();
await expect( await expect(
page.locator( page.locator(`[data-row-key=${DESCRIPTION_WITH_OWNER}]`)
'[data-row-key="playwright-owner-with-percentage-percentage"]'
)
).toBeVisible(); ).toBeVisible();
}); });
@ -162,6 +163,20 @@ test.describe('Data Insight Page', { tag: '@data-insight' }, () => {
} }
}); });
test('Verify KPI widget in Landing page', async ({ page }) => {
const kpiResponse = page.waitForResponse('/api/v1/kpi/*/kpiResult?*');
await redirectToHomePage(page);
await kpiResponse;
expect(page.locator('[data-testid="kpi-widget"]')).toBeVisible();
// description and owner data to be visible
expect(page.getByTestId(DESCRIPTION_WITH_PERCENTAGE)).toBeVisible();
expect(page.getByTestId(DESCRIPTION_WITH_OWNER)).toBeVisible();
});
test('Delete Kpi', async ({ page }) => { test('Delete Kpi', async ({ page }) => {
await page.waitForResponse( await page.waitForResponse(
'/api/v1/kpi/playwright-owner-with-percentage-percentage/latestKpiResult' '/api/v1/kpi/playwright-owner-with-percentage-percentage/latestKpiResult'

View File

@ -33,12 +33,11 @@ import {
} from '../../../../constants/constants'; } from '../../../../constants/constants';
import { DATA_INSIGHT_GRAPH_COLORS } from '../../../../constants/DataInsight.constants'; import { DATA_INSIGHT_GRAPH_COLORS } from '../../../../constants/DataInsight.constants';
import { DATA_INSIGHT_DOCS } from '../../../../constants/docs.constants'; import { DATA_INSIGHT_DOCS } from '../../../../constants/docs.constants';
import { SIZE } from '../../../../enums/common.enum'; import { ERROR_PLACEHOLDER_TYPE, SIZE } from '../../../../enums/common.enum';
import { WidgetWidths } from '../../../../enums/CustomizablePage.enum'; import { WidgetWidths } from '../../../../enums/CustomizablePage.enum';
import { TabSpecificField } from '../../../../enums/entity.enum'; import { TabSpecificField } from '../../../../enums/entity.enum';
import { Kpi, KpiResult } from '../../../../generated/dataInsight/kpi/kpi'; import { Kpi, KpiResult } from '../../../../generated/dataInsight/kpi/kpi';
import { UIKpiResult } from '../../../../interface/data-insight.interface'; import { UIKpiResult } from '../../../../interface/data-insight.interface';
import { useDataInsightProvider } from '../../../../pages/DataInsightPage/DataInsightProvider';
import { DataInsightCustomChartResult } from '../../../../rest/DataInsightAPI'; import { DataInsightCustomChartResult } from '../../../../rest/DataInsightAPI';
import { import {
getLatestKpiResult, getLatestKpiResult,
@ -46,42 +45,17 @@ import {
getListKPIs, getListKPIs,
} from '../../../../rest/KpiAPI'; } from '../../../../rest/KpiAPI';
import { Transi18next } from '../../../../utils/CommonUtils'; import { Transi18next } from '../../../../utils/CommonUtils';
import { customFormatDateTime } from '../../../../utils/date-time/DateTimeUtils'; import {
customFormatDateTime,
getCurrentMillis,
getEpochMillisForPastDays,
} from '../../../../utils/date-time/DateTimeUtils';
import { showErrorToast } from '../../../../utils/ToastUtils'; import { showErrorToast } from '../../../../utils/ToastUtils';
import ErrorPlaceHolder from '../../../common/ErrorWithPlaceholder/ErrorPlaceHolder';
import KPILatestResultsV1 from '../../../DataInsight/KPILatestResultsV1'; import KPILatestResultsV1 from '../../../DataInsight/KPILatestResultsV1';
import './kpi-widget.less'; import './kpi-widget.less';
import { KPIWidgetProps } from './KPIWidget.interface'; import { KPIWidgetProps } from './KPIWidget.interface';
const EmptyPlaceholder = () => {
const { t } = useTranslation();
return (
<div className="flex-center flex-col h-full p-t-sm">
<KPIEmptyIcon width={SIZE.X_SMALL} />
<div className="m-t-xs text-center">
<Typography.Paragraph style={{ marginBottom: '0' }}>
{t('message.no-kpi')}
</Typography.Paragraph>
<Typography.Paragraph>
<Transi18next
i18nKey="message.refer-to-our-doc"
renderElement={
<Link
rel="noreferrer"
target="_blank"
to={{ pathname: DATA_INSIGHT_DOCS }}
/>
}
values={{
doc: t('label.doc-plural-lowercase'),
}}
/>
</Typography.Paragraph>
</div>
</div>
);
};
const KPIWidget = ({ const KPIWidget = ({
isEditView = false, isEditView = false,
selectedDays = CHART_WIDGET_DAYS_DURATION, selectedDays = CHART_WIDGET_DAYS_DURATION,
@ -98,12 +72,11 @@ const KPIWidget = ({
const [kpiLatestResults, setKpiLatestResults] = const [kpiLatestResults, setKpiLatestResults] =
useState<Record<string, UIKpiResult>>(); useState<Record<string, UIKpiResult>>();
const [isLoading, setIsLoading] = useState<boolean>(false); const [isLoading, setIsLoading] = useState<boolean>(false);
const { chartFilter } = useDataInsightProvider();
const getKPIResult = async (kpi: Kpi) => { const getKPIResult = async (kpi: Kpi) => {
const response = await getListKpiResult(kpi.fullyQualifiedName ?? '', { const response = await getListKpiResult(kpi.fullyQualifiedName ?? '', {
startTs: chartFilter.startTs, startTs: getEpochMillisForPastDays(selectedDays),
endTs: chartFilter.endTs, endTs: getCurrentMillis(),
}); });
return { name: kpi.name, data: response.results }; return { name: kpi.name, data: response.results };
@ -253,7 +226,28 @@ const KPIWidget = ({
</Col> </Col>
</Row> </Row>
{isEmpty(kpiList) || isEmpty(kpiResults) ? ( {isEmpty(kpiList) || isEmpty(kpiResults) ? (
<EmptyPlaceholder /> <ErrorPlaceHolder
icon={<KPIEmptyIcon height={SIZE.X_SMALL} width={SIZE.X_SMALL} />}
type={ERROR_PLACEHOLDER_TYPE.CUSTOM}>
<Typography.Paragraph style={{ marginBottom: '0' }}>
{t('message.no-kpi')}
</Typography.Paragraph>
<Typography.Paragraph>
<Transi18next
i18nKey="message.refer-to-our-doc"
renderElement={
<Link
rel="noreferrer"
target="_blank"
to={{ pathname: DATA_INSIGHT_DOCS }}
/>
}
values={{
doc: t('label.doc-plural-lowercase'),
}}
/>
</Typography.Paragraph>
</ErrorPlaceHolder>
) : ( ) : (
<Row className="p-t-md"> <Row className="p-t-md">
<Col span={isWidgetSizeMedium ? 14 : 24}> <Col span={isWidgetSizeMedium ? 14 : 24}>

View File

@ -0,0 +1,145 @@
/*
* 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 { fireEvent, render, screen } from '@testing-library/react';
import React from 'react';
import { act } from 'react-test-renderer';
import { WidgetWidths } from '../../../../enums/CustomizablePage.enum';
import { MOCK_KPI_LIST_RESPONSE } from '../../../../pages/KPIPage/KPIMock.mock';
import { getListKPIs } from '../../../../rest/KpiAPI';
import KPIWidget from './KPIWidget.component';
jest.mock('../../../../constants/DataInsight.constants', () => ({
DATA_INSIGHT_GRAPH_COLORS: ['#E7B85D'],
}));
jest.mock('../../../../constants/constants', () => ({
CHART_WIDGET_DAYS_DURATION: 14,
GRAPH_BACKGROUND_COLOR: '#000000',
}));
jest.mock('../../../../utils/date-time/DateTimeUtils', () => ({
customFormatDateTime: jest.fn().mockReturnValue('Dec 05, 11:54'),
getCurrentMillis: jest.fn().mockReturnValue(1711583974000),
getEpochMillisForPastDays: jest.fn().mockReturnValue(1709424034000),
}));
jest.mock('../../../../rest/DataInsightAPI', () => ({
DataInsightCustomChartResult: jest
.fn()
.mockImplementation(() => Promise.resolve()),
}));
jest.mock('../../../../rest/KpiAPI', () => ({
getLatestKpiResult: jest.fn().mockImplementation(() =>
Promise.resolve({
timestamp: 1724760319723,
kpiFqn: 'description-percentage',
targetResult: [
{
value: '23.52941176470588',
targetMet: false,
},
],
})
),
getListKpiResult: jest.fn().mockImplementation(() =>
Promise.resolve({
results: [
{
count: 23.52941176470588,
day: 1724716800000,
},
],
})
),
getListKPIs: jest
.fn()
.mockImplementation(() => Promise.resolve(MOCK_KPI_LIST_RESPONSE)),
}));
jest.mock('../../../../utils/ToastUtils', () => ({
showErrorToast: jest.fn(),
}));
jest.mock('../../../../utils/CommonUtils', () => ({
Transi18next: jest.fn().mockReturnValue('text'),
}));
jest.mock('../../../DataInsight/KPILatestResultsV1', () =>
jest.fn().mockReturnValue(<p>KPILatestResultsV1.Component</p>)
);
jest.mock('../../../common/ErrorWithPlaceholder/ErrorPlaceHolder', () =>
jest.fn().mockReturnValue(<p>ErrorPlaceHolder.Component</p>)
);
const mockHandleRemoveWidget = jest.fn();
const widgetProps = {
selectedGridSize: WidgetWidths.medium,
isEditView: true,
widgetKey: 'testWidgetKey',
handleRemoveWidget: mockHandleRemoveWidget,
};
describe('KPIWidget', () => {
it('should fetch kpi list api initially', async () => {
render(<KPIWidget {...widgetProps} />);
expect(getListKPIs).toHaveBeenCalledWith({ fields: 'dataInsightChart' });
});
it('should handle close click when in edit view', async () => {
await act(async () => {
render(<KPIWidget {...widgetProps} />);
});
fireEvent.click(screen.getByTestId('remove-widget-button'));
expect(mockHandleRemoveWidget).toHaveBeenCalledWith(widgetProps.widgetKey);
});
it('should render charts and data if present', async () => {
await act(async () => {
render(<KPIWidget {...widgetProps} />);
});
expect(screen.getByText('label.kpi-title')).toBeInTheDocument();
expect(
screen.getByText('KPILatestResultsV1.Component')
).toBeInTheDocument();
});
it('should not render data if selectedGridSize is small', async () => {
await act(async () => {
render(
<KPIWidget {...widgetProps} selectedGridSize={WidgetWidths.small} />
);
});
expect(screen.getByText('label.kpi-title')).toBeInTheDocument();
expect(
screen.queryByText('KPILatestResultsV1.Component')
).not.toBeInTheDocument();
});
it('should render ErrorPlaceholder if no data there', async () => {
(getListKPIs as jest.Mock).mockImplementation(() => Promise.resolve());
await act(async () => {
render(<KPIWidget {...widgetProps} />);
});
expect(screen.getByText('ErrorPlaceHolder.Component')).toBeInTheDocument();
});
});

View File

@ -442,3 +442,36 @@ export const DESCRIPTION_CHART = {
href: 'http://localhost:8585/api/v1/analytics/dataInsights/charts/7dc794d3-1881-408c-92fc-6182aa453bc8', href: 'http://localhost:8585/api/v1/analytics/dataInsights/charts/7dc794d3-1881-408c-92fc-6182aa453bc8',
deleted: false, deleted: false,
}; };
export const MOCK_KPI_LIST_RESPONSE = {
data: [
{
id: '17651e36-2350-414a-a68d-bea58cc96d02',
name: 'description-percentage',
displayName: 'description',
fullyQualifiedName: 'description-percentage',
description: 'this is description',
metricType: 'PERCENTAGE',
dataInsightChart: {
id: 'e10d1bef-0d6b-42cd-a215-5771f40803eb',
type: 'dataInsightCustomChart',
name: 'percentage_of_data_asset_with_description_kpi',
fullyQualifiedName: 'percentage_of_data_asset_with_description_kpi',
displayName: 'percentage_of_data_asset_with_description_kpi',
deleted: false,
href: 'http://localhost:8585/api/v1/analytics/dataInsights/system/charts/e10d1bef-0d6b-42cd-a215-5771f40803eb',
},
targetValue: 58,
startDate: 1724697000000,
endDate: 1725128999999,
version: 0.1,
updatedAt: 1724760086039,
updatedBy: 'admin',
href: 'http://localhost:8585/api/v1/kpi/17651e36-2350-414a-a68d-bea58cc96d02',
deleted: false,
},
],
paging: {
total: 1,
},
};