From eaa11e4798cf6f89ecf1f893c9927bff6c7a9833 Mon Sep 17 00:00:00 2001 From: rodrigopk Date: Wed, 14 Jan 2026 11:55:43 -0500 Subject: [PATCH] Use isProvisionedResource in useMuteTimings - Removed duplicated logic - Added regression tests for useMuteTimings hook --- .../mute-timings/useMuteTimings.test.tsx | 115 ++++++++++++++++++ .../mute-timings/useMuteTimings.tsx | 4 +- 2 files changed, 117 insertions(+), 2 deletions(-) create mode 100644 public/app/features/alerting/unified/components/mute-timings/useMuteTimings.test.tsx diff --git a/public/app/features/alerting/unified/components/mute-timings/useMuteTimings.test.tsx b/public/app/features/alerting/unified/components/mute-timings/useMuteTimings.test.tsx new file mode 100644 index 00000000000..aa2b44576fc --- /dev/null +++ b/public/app/features/alerting/unified/components/mute-timings/useMuteTimings.test.tsx @@ -0,0 +1,115 @@ +import { renderHook, waitFor } from '@testing-library/react'; +import { ReactNode } from 'react'; +import { getWrapper } from 'test/test-utils'; + +import { setupMswServer } from 'app/features/alerting/unified/mockApi'; +import { grantUserPermissions } from 'app/features/alerting/unified/mocks'; +import { + TIME_INTERVAL_NAME_FILE_PROVISIONED, + TIME_INTERVAL_NAME_HAPPY_PATH, +} from 'app/features/alerting/unified/mocks/server/handlers/k8s/timeIntervals.k8s'; +import { GRAFANA_RULES_SOURCE_NAME } from 'app/features/alerting/unified/utils/datasource'; +import { AccessControlAction } from 'app/types/accessControl'; + +import { useGetMuteTiming, useMuteTimings } from './useMuteTimings'; + +const wrapper = ({ children }: { children: ReactNode }) => { + const ProviderWrapper = getWrapper({ renderWithRouter: true }); + return {children}; +}; + +setupMswServer(); + +describe('useMuteTimings', () => { + beforeEach(() => { + grantUserPermissions([AccessControlAction.AlertingNotificationsRead]); + }); + + describe('useMuteTimings', () => { + it('should return mute timings with correct data structure', async () => { + const { result } = renderHook( + () => + useMuteTimings({ + alertmanager: GRAFANA_RULES_SOURCE_NAME, + skip: false, + }), + { + wrapper, + } + ); + + await waitFor(() => { + expect(result.current.isLoading).toBe(false); + }); + + expect(result.current.data).toBeDefined(); + expect(Array.isArray(result.current.data)).toBe(true); + + const timings = result.current.data!; + expect(timings.length).toBeGreaterThan(0); + + // Verify structure of first timing + const firstTiming = timings[0]; + expect(firstTiming).toHaveProperty('id'); + expect(firstTiming).toHaveProperty('name'); + expect(firstTiming).toHaveProperty('time_intervals'); + expect(typeof firstTiming.id).toBe('string'); + expect(typeof firstTiming.name).toBe('string'); + expect(Array.isArray(firstTiming.time_intervals)).toBe(true); + }); + + it('should correctly identify provisioned intervals', async () => { + const { result } = renderHook( + () => + useMuteTimings({ + alertmanager: GRAFANA_RULES_SOURCE_NAME, + skip: false, + }), + { + wrapper, + } + ); + + await waitFor(() => { + expect(result.current.isLoading).toBe(false); + }); + + const timings = result.current.data!; + + // Find the provisioned interval + const provisionedTiming = timings.find((t) => t.name === TIME_INTERVAL_NAME_FILE_PROVISIONED); + expect(provisionedTiming).toBeDefined(); + expect(provisionedTiming?.provisioned).toBe(true); + + // Find the non-provisioned interval + const nonProvisionedTiming = timings.find((t) => t.name === TIME_INTERVAL_NAME_HAPPY_PATH); + expect(nonProvisionedTiming).toBeDefined(); + expect(nonProvisionedTiming?.provisioned).toBe(false); + }); + }); + + describe('useGetMuteTiming', () => { + it('should return single mute timing by name for editing', async () => { + const { result } = renderHook( + () => + useGetMuteTiming({ + alertmanager: GRAFANA_RULES_SOURCE_NAME, + name: TIME_INTERVAL_NAME_HAPPY_PATH, + }), + { + wrapper, + } + ); + + await waitFor(() => { + expect(result.current.isLoading).toBe(false); + }); + + expect(result.current.data).toBeDefined(); + expect(result.current.data?.name).toBe(TIME_INTERVAL_NAME_HAPPY_PATH); + expect(result.current.data?.id).toBe(TIME_INTERVAL_NAME_HAPPY_PATH); + expect(result.current.data).toHaveProperty('time_intervals'); + expect(result.current.isError).toBe(false); + }); + }); +}); diff --git a/public/app/features/alerting/unified/components/mute-timings/useMuteTimings.tsx b/public/app/features/alerting/unified/components/mute-timings/useMuteTimings.tsx index ce0871ac2cd..a3154d3ca24 100644 --- a/public/app/features/alerting/unified/components/mute-timings/useMuteTimings.tsx +++ b/public/app/features/alerting/unified/components/mute-timings/useMuteTimings.tsx @@ -9,9 +9,9 @@ import { IoK8SApimachineryPkgApisMetaV1ObjectMeta, } from 'app/features/alerting/unified/openapi/timeIntervalsApi.gen'; import { BaseAlertmanagerArgs, Skippable } from 'app/features/alerting/unified/types/hooks'; -import { KnownProvenance } from 'app/features/alerting/unified/types/knownProvenance'; import { isK8sEntityProvisioned, + isProvisionedResource, shouldUseK8sApi, stringifyFieldSelector, } from 'app/features/alerting/unified/utils/k8s/utils'; @@ -62,7 +62,7 @@ const parseAmTimeInterval: (interval: MuteTimeInterval, provenance: string) => M return { ...interval, id: interval.name, - provisioned: Boolean(provenance && provenance !== KnownProvenance.None), + provisioned: isProvisionedResource(provenance), }; };