From c03541cd6c020f921d8ddf6ec234455b8d73a54a Mon Sep 17 00:00:00 2001
From: Amlan Kumar Nandy <45410599+amlannandy@users.noreply.github.com>
Date: Fri, 9 May 2025 11:41:41 +0700
Subject: [PATCH] chore: improve error handling and loading states in summary
view of metrics explorer (#7862)
---
.../MetricsExplorer/Summary/MetricsTable.tsx | 38 ++--
.../Summary/MetricsTreemap.tsx | 11 +-
.../MetricsExplorer/Summary/Summary.tsx | 14 +-
.../Summary/__tests__/MetricsTable.test.tsx | 200 ++++++++++++++++++
.../Summary/__tests__/MetricsTreemap.test.tsx | 139 ++++++++++++
5 files changed, 385 insertions(+), 17 deletions(-)
create mode 100644 frontend/src/container/MetricsExplorer/Summary/__tests__/MetricsTable.test.tsx
create mode 100644 frontend/src/container/MetricsExplorer/Summary/__tests__/MetricsTreemap.test.tsx
diff --git a/frontend/src/container/MetricsExplorer/Summary/MetricsTable.tsx b/frontend/src/container/MetricsExplorer/Summary/MetricsTable.tsx
index d103fc99de..93aff3ad33 100644
--- a/frontend/src/container/MetricsExplorer/Summary/MetricsTable.tsx
+++ b/frontend/src/container/MetricsExplorer/Summary/MetricsTable.tsx
@@ -50,27 +50,39 @@ function MetricsTable({
return (
-
-
- List View
-
-
-
-
-
+ {!isError && !isLoading && (
+
+
+ List View
+
+
+
+
+
+ )}
} />,
+ indicator: (
+
}
+ />
+ ),
}}
dataSource={data}
columns={metricsTableColumns}
locale={{
emptyText: isLoading ? null : (
-
+

+
+
+
);
}
@@ -66,6 +68,7 @@ function MetricsTreemap({
return (
);
@@ -75,13 +78,17 @@ function MetricsTreemap({
return (
);
}
return (
-
+
Proportion View
isMetricsError || (metricsData && metricsData.statusCode !== 200),
+ [isMetricsError, metricsData],
+ );
+
const {
data: treeMapData,
isLoading: isTreeMapLoading,
@@ -132,6 +137,11 @@ function Summary(): JSX.Element {
enabled: !!metricsTreemapQuery && !isInspectModalOpen,
});
+ const isProportionViewError = useMemo(
+ () => isTreeMapError || treeMapData?.statusCode !== 200,
+ [isTreeMapError, treeMapData],
+ );
+
const handleFilterChange = useCallback(
(value: TagFilter) => {
handleChangeQueryData('filters', value);
@@ -208,13 +218,13 @@ function Summary(): JSX.Element {
{
+ jest
+ .spyOn(useGetMetricsListFilterValues, 'useGetMetricsListFilterValues')
+ .mockReturnValue({
+ data: {
+ statusCode: 200,
+ payload: {
+ status: 'success',
+ data: {
+ filterValues: ['metric1', 'metric2'],
+ },
+ },
+ },
+ isLoading: false,
+ isError: false,
+ } as any);
+
+ it('renders table with data correctly', () => {
+ render(
+
+
+
+
+ ,
+ );
+
+ expect(screen.getByText('List View')).toBeInTheDocument();
+ expect(screen.getByText('Metric 1')).toBeInTheDocument();
+ expect(screen.getByText('Metric 2')).toBeInTheDocument();
+ });
+
+ it('shows loading state', () => {
+ render(
+
+
+
+
+ ,
+ );
+
+ expect(screen.getByTestId('metrics-table-loading-state')).toBeInTheDocument();
+ });
+
+ it('shows error state', () => {
+ render(
+
+
+
+
+ ,
+ );
+
+ expect(screen.getByTestId('metrics-table-error-state')).toBeInTheDocument();
+ expect(
+ screen.getByText(
+ 'Error fetching metrics. If the problem persists, please contact support.',
+ ),
+ ).toBeInTheDocument();
+ });
+
+ it('shows empty state when no data', () => {
+ render(
+
+
+
+
+ ,
+ );
+
+ expect(screen.getByTestId('metrics-table-empty-state')).toBeInTheDocument();
+ expect(
+ screen.getByText(
+ 'This query had no results. Edit your query and try again!',
+ ),
+ ).toBeInTheDocument();
+ });
+
+ it('calls openMetricDetails when row is clicked', () => {
+ const mockOpenMetricDetails = jest.fn();
+ render(
+
+
+
+
+ ,
+ );
+
+ fireEvent.click(screen.getByText('Metric 1'));
+ expect(mockOpenMetricDetails).toHaveBeenCalledWith('metric1');
+ });
+
+ it('calls setOrderBy when column header is clicked', () => {
+ const mockSetOrderBy = jest.fn();
+ render(
+
+
+
+
+ ,
+ );
+
+ const samplesHeader = screen.getByText('SAMPLES');
+ fireEvent.click(samplesHeader);
+
+ expect(mockSetOrderBy).toHaveBeenCalledWith({
+ columnName: 'samples',
+ order: 'asc',
+ });
+ });
+});
diff --git a/frontend/src/container/MetricsExplorer/Summary/__tests__/MetricsTreemap.test.tsx b/frontend/src/container/MetricsExplorer/Summary/__tests__/MetricsTreemap.test.tsx
new file mode 100644
index 0000000000..78465e4e19
--- /dev/null
+++ b/frontend/src/container/MetricsExplorer/Summary/__tests__/MetricsTreemap.test.tsx
@@ -0,0 +1,139 @@
+import { render, screen } from '@testing-library/react';
+import { Provider } from 'react-redux';
+import { MemoryRouter } from 'react-router-dom';
+import store from 'store';
+
+import MetricsTreemap from '../MetricsTreemap';
+import { TreemapViewType } from '../types';
+
+jest.mock('d3-hierarchy', () => ({
+ stratify: jest.fn().mockReturnValue({
+ id: jest.fn().mockReturnValue({
+ parentId: jest.fn().mockReturnValue(
+ jest.fn().mockReturnValue({
+ sum: jest.fn().mockReturnValue({
+ descendants: jest.fn().mockReturnValue([]),
+ eachBefore: jest.fn().mockReturnValue([]),
+ }),
+ }),
+ ),
+ }),
+ }),
+ treemapBinary: jest.fn(),
+}));
+jest.mock('react-use', () => ({
+ useWindowSize: jest.fn().mockReturnValue({ width: 1000, height: 1000 }),
+}));
+
+const mockData = [
+ {
+ metric_name: 'Metric 1',
+ percentage: 0.5,
+ total_value: 15,
+ },
+ {
+ metric_name: 'Metric 2',
+ percentage: 0.6,
+ total_value: 10,
+ },
+];
+
+describe('MetricsTreemap', () => {
+ it('renders treemap with data correctly', () => {
+ render(
+
+
+
+
+ ,
+ );
+
+ expect(screen.getByText('Proportion View')).toBeInTheDocument();
+ });
+
+ it('shows loading state', () => {
+ render(
+
+
+
+
+ ,
+ );
+
+ expect(
+ screen.getByTestId('metrics-treemap-loading-state'),
+ ).toBeInTheDocument();
+ });
+
+ it('shows error state', () => {
+ render(
+
+
+
+
+ ,
+ );
+
+ expect(screen.getByTestId('metrics-treemap-error-state')).toBeInTheDocument();
+ expect(
+ screen.getByText(
+ 'Error fetching metrics. If the problem persists, please contact support.',
+ ),
+ ).toBeInTheDocument();
+ });
+
+ it('shows empty state when no data', () => {
+ render(
+
+
+
+
+ ,
+ );
+
+ expect(screen.getByTestId('metrics-treemap-empty-state')).toBeInTheDocument();
+ expect(screen.getByText('No metrics found')).toBeInTheDocument();
+ });
+});