diff --git a/openmetadata-ui/src/main/resources/ui/src/components/DataInsight/KPIChart.test.tsx b/openmetadata-ui/src/main/resources/ui/src/components/DataInsight/KPIChart.test.tsx
new file mode 100644
index 000000000000..63142726bf4f
--- /dev/null
+++ b/openmetadata-ui/src/main/resources/ui/src/components/DataInsight/KPIChart.test.tsx
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2023 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 { render, screen } from '@testing-library/react';
+import React from 'react';
+import { MemoryRouter } from 'react-router-dom';
+import { act } from 'react-test-renderer';
+import { KPI_LIST } from '../../pages/KPIPage/KPIMock.mock';
+import KPIChart from './KPIChart';
+
+jest.mock('../../rest/KpiAPI', () => ({
+ getListKPIs: jest
+ .fn()
+ .mockImplementation(() => Promise.resolve({ data: KPI_LIST })),
+}));
+
+describe('Test KPIChart Component', () => {
+ const mockProps = {
+ chartFilter: {
+ startTs: 1234567890,
+ endTs: 1234567899,
+ },
+ kpiList: KPI_LIST,
+ isKpiLoading: false,
+ viewKPIPermission: true,
+ createKPIPermission: true,
+ };
+
+ it('Should render KPIChart component', async () => {
+ await act(async () => {
+ render(, {
+ wrapper: MemoryRouter,
+ });
+ });
+
+ const kpiCard = screen.getByTestId('kpi-card');
+
+ expect(kpiCard).toBeInTheDocument();
+ });
+
+ it('Should render EmptyGraphPlaceholder when no data is available', async () => {
+ await act(async () => {
+ render(, {
+ wrapper: MemoryRouter,
+ });
+ });
+
+ const emptyPlaceholder = screen.getByText(
+ 'message.no-kpi-available-add-new-one'
+ );
+
+ expect(emptyPlaceholder).toBeInTheDocument();
+ });
+
+ it('Should render "Add KPI" button when no KPIs exist and user has create permission', async () => {
+ await act(async () => {
+ render(, {
+ wrapper: MemoryRouter,
+ });
+ });
+
+ const addButton = screen.getByText('label.add-entity');
+
+ expect(addButton).toBeInTheDocument();
+ });
+
+ it('Should not render "Add KPI" button when no create permission', async () => {
+ await act(async () => {
+ render(
+ ,
+ {
+ wrapper: MemoryRouter,
+ }
+ );
+ });
+
+ const addButton = screen.queryByText('label.add-entity');
+
+ expect(addButton).not.toBeInTheDocument();
+ });
+});
diff --git a/openmetadata-ui/src/main/resources/ui/src/components/DataInsight/KPIChart.tsx b/openmetadata-ui/src/main/resources/ui/src/components/DataInsight/KPIChart.tsx
index ecf8ee845284..622ae96ddad9 100644
--- a/openmetadata-ui/src/main/resources/ui/src/components/DataInsight/KPIChart.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/components/DataInsight/KPIChart.tsx
@@ -219,6 +219,12 @@ const KPIChart: FC = ({
}
}, [kpiList, chartFilter]);
+ const hasAtLeastOneData = useMemo(() => {
+ return kpiNames.some(
+ (key) => kpiResults[key] && kpiResults[key].length > 0
+ );
+ }, [kpiNames, kpiResults]);
+
return (
= ({
}>
{kpiList.length ? (
- {!isEmpty(kpiResults) ? (
+ {hasAtLeastOneData ? (
<>
{
expect(submitButton).toBeInTheDocument();
});
+ it('should show validation error when description is empty', async () => {
+ render(, { wrapper: MemoryRouter });
+
+ const submitButton = await screen.findByTestId('submit-btn');
+
+ await act(async () => {
+ fireEvent.click(submitButton);
+ });
+
+ const validationMessages = await screen.findAllByText(
+ 'label.field-required'
+ );
+ // we have start date and end date field with the same label, hence we have 3 validation messages
+ // and description is the last field in the form
+ const lastValidationMessage =
+ validationMessages[validationMessages.length - 1];
+
+ expect(lastValidationMessage).toBeInTheDocument();
+ });
+
it.skip('Should render the proper metric input based on metric type', async () => {
render(, { wrapper: MemoryRouter });
diff --git a/openmetadata-ui/src/main/resources/ui/src/pages/KPIPage/AddKPIPage.tsx b/openmetadata-ui/src/main/resources/ui/src/pages/KPIPage/AddKPIPage.tsx
index 3f60e70f9892..4181c9b8cf76 100644
--- a/openmetadata-ui/src/main/resources/ui/src/pages/KPIPage/AddKPIPage.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/pages/KPIPage/AddKPIPage.tsx
@@ -349,6 +349,14 @@ const AddKPIPage = () => {