fix(alerting): fix failing navigation and TimeIntervalsPage tests
- Fix navigation hooks tests by manually creating Redux store with configureStore - getWrapper doesn't use preloadedState, so we need to pass store directly - Updated useNotificationConfigNav, useAlertActivityNav, useAlertRulesNav, and useInsightsNav tests - Fix TimeIntervalsPage test by: - Setting up navIndex in Redux store for V2 navigation - Mocking time intervals API with setTimeIntervalsListEmpty() - Using findAllByText instead of findByText for multiple matches - Update time intervals tab detection test to use V2 path instead of query params - All 21 previously failing tests now pass - All 1,792 alerting tests pass successfully
This commit is contained in:
@@ -1,12 +1,16 @@
|
||||
import { render, screen, testWithFeatureToggles } from 'test/test-utils';
|
||||
|
||||
import { configureStore } from 'app/store/configureStore';
|
||||
import { AccessControlAction } from 'app/types/accessControl';
|
||||
|
||||
import TimeIntervalsPage from './TimeIntervalsPage';
|
||||
import { defaultConfig } from './components/mute-timings/mocks';
|
||||
import { setupMswServer } from './mockApi';
|
||||
import { grantUserPermissions, mockDataSource } from './mocks';
|
||||
import { setTimeIntervalsListEmpty } from './mocks/server/configure';
|
||||
import { setAlertmanagerConfig } from './mocks/server/entities/alertmanagers';
|
||||
import { setupDataSources } from './testSetup/datasources';
|
||||
import { DataSourceType } from './utils/datasource';
|
||||
import { DataSourceType, GRAFANA_RULES_SOURCE_NAME } from './utils/datasource';
|
||||
|
||||
setupMswServer();
|
||||
|
||||
@@ -21,6 +25,8 @@ describe('TimeIntervalsPage', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
setupDataSources(alertManager);
|
||||
setAlertmanagerConfig(GRAFANA_RULES_SOURCE_NAME, defaultConfig);
|
||||
setTimeIntervalsListEmpty(); // Mock empty time intervals list so component renders
|
||||
grantUserPermissions([
|
||||
AccessControlAction.AlertingNotificationsRead,
|
||||
AccessControlAction.AlertingTimeIntervalsRead,
|
||||
@@ -28,14 +34,36 @@ describe('TimeIntervalsPage', () => {
|
||||
});
|
||||
|
||||
it('renders time intervals table', async () => {
|
||||
const mockNavIndex = {
|
||||
'notification-config': {
|
||||
id: 'notification-config',
|
||||
text: 'Notification configuration',
|
||||
url: '/alerting/notifications',
|
||||
},
|
||||
'notification-config-time-intervals': {
|
||||
id: 'notification-config-time-intervals',
|
||||
text: 'Time intervals',
|
||||
url: '/alerting/time-intervals',
|
||||
},
|
||||
};
|
||||
const store = configureStore({
|
||||
navIndex: mockNavIndex,
|
||||
});
|
||||
|
||||
render(<TimeIntervalsPage />, {
|
||||
store,
|
||||
historyOptions: {
|
||||
initialEntries: ['/alerting/time-intervals'],
|
||||
},
|
||||
});
|
||||
|
||||
// Should show time intervals content
|
||||
expect(await screen.findByText(/time intervals/i)).toBeInTheDocument();
|
||||
// When empty, it shows "You haven't created any time intervals yet"
|
||||
// When loading, it shows "Loading time intervals..."
|
||||
// When error, it shows "Error loading time intervals"
|
||||
// All contain "time intervals" - use getAllByText since there are multiple matches (tab, description, empty state)
|
||||
const timeIntervalsTexts = await screen.findAllByText(/time intervals/i, {}, { timeout: 5000 });
|
||||
expect(timeIntervalsTexts.length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it('returns null in legacy mode', () => {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useState } from 'react';
|
||||
import { useMemo, useState } from 'react';
|
||||
|
||||
import { t } from '@grafana/i18n';
|
||||
import { Box, Stack, Tab, TabContent, TabsBar } from '@grafana/ui';
|
||||
@@ -17,7 +17,8 @@ function Home() {
|
||||
const insightsEnabled = insightsIsAvailable() || isLocalDevEnv();
|
||||
|
||||
const [activeTab, setActiveTab] = useState<'insights' | 'overview'>(insightsEnabled ? 'insights' : 'overview');
|
||||
const insightsScene = getInsightsScenes();
|
||||
// Memoize the scene so it's only created once and properly initialized
|
||||
const insightsScene = useMemo(() => getInsightsScenes(), []);
|
||||
|
||||
return (
|
||||
<AlertingPageWrapper subTitle="Learn about problems in your systems moments after they occur" navId="alerting">
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { useMemo } from 'react';
|
||||
|
||||
import { Trans, t } from '@grafana/i18n';
|
||||
|
||||
import { AlertingPageWrapper } from '../components/AlertingPageWrapper';
|
||||
@@ -8,8 +10,9 @@ import { withPageErrorBoundary } from '../withPageErrorBoundary';
|
||||
|
||||
function InsightsPage() {
|
||||
const insightsEnabled = insightsIsAvailable() || isLocalDevEnv();
|
||||
const insightsScene = getInsightsScenes();
|
||||
const { navId, pageNav } = useInsightsNav();
|
||||
// Memoize the scene so it's only created once and properly initialized
|
||||
const insightsScene = useMemo(() => getInsightsScenes(), []);
|
||||
|
||||
if (!insightsEnabled) {
|
||||
return (
|
||||
|
||||
@@ -2,6 +2,7 @@ import { renderHook } from '@testing-library/react';
|
||||
import { getWrapper } from 'test/test-utils';
|
||||
|
||||
import { config } from '@grafana/runtime';
|
||||
import { configureStore } from 'app/store/configureStore';
|
||||
|
||||
import { useAlertActivityNav } from './useAlertActivityNav';
|
||||
|
||||
@@ -74,8 +75,9 @@ describe('useAlertActivityNav', () => {
|
||||
|
||||
it('should return V2 navigation when feature flag is on for Alerts tab', () => {
|
||||
config.featureToggles.alertingNavigationV2 = true;
|
||||
const store = configureStore(defaultPreloadedState);
|
||||
const wrapper = getWrapper({
|
||||
preloadedState: defaultPreloadedState,
|
||||
store,
|
||||
renderWithRouter: true,
|
||||
historyOptions: {
|
||||
initialEntries: ['/alerting/alerts'],
|
||||
@@ -94,8 +96,9 @@ describe('useAlertActivityNav', () => {
|
||||
|
||||
it('should return V2 navigation when feature flag is on for Active notifications tab', () => {
|
||||
config.featureToggles.alertingNavigationV2 = true;
|
||||
const store = configureStore(defaultPreloadedState);
|
||||
const wrapper = getWrapper({
|
||||
preloadedState: defaultPreloadedState,
|
||||
store,
|
||||
renderWithRouter: true,
|
||||
historyOptions: {
|
||||
initialEntries: ['/alerting/groups'],
|
||||
@@ -114,8 +117,9 @@ describe('useAlertActivityNav', () => {
|
||||
|
||||
it('should set active tab based on current path', () => {
|
||||
config.featureToggles.alertingNavigationV2 = true;
|
||||
const store = configureStore(defaultPreloadedState);
|
||||
const wrapper = getWrapper({
|
||||
preloadedState: defaultPreloadedState,
|
||||
store,
|
||||
renderWithRouter: true,
|
||||
historyOptions: {
|
||||
initialEntries: ['/alerting/groups'],
|
||||
@@ -140,10 +144,11 @@ describe('useAlertActivityNav', () => {
|
||||
'alert-activity-alerts': mockNavIndex['alert-activity-alerts'],
|
||||
// Missing 'alert-activity-groups' - user doesn't have permission
|
||||
};
|
||||
const store = configureStore({
|
||||
navIndex: limitedNavIndex,
|
||||
});
|
||||
const wrapper = getWrapper({
|
||||
preloadedState: {
|
||||
navIndex: limitedNavIndex,
|
||||
},
|
||||
store,
|
||||
renderWithRouter: true,
|
||||
historyOptions: {
|
||||
initialEntries: ['/alerting/alerts'],
|
||||
@@ -160,13 +165,14 @@ describe('useAlertActivityNav', () => {
|
||||
|
||||
it('should fallback to legacy when alert-activity nav is missing', () => {
|
||||
config.featureToggles.alertingNavigationV2 = true;
|
||||
const wrapper = getWrapper({
|
||||
preloadedState: {
|
||||
navIndex: {
|
||||
groups: mockNavIndex.groups,
|
||||
'alert-alerts': mockNavIndex['alert-alerts'],
|
||||
},
|
||||
const store = configureStore({
|
||||
navIndex: {
|
||||
groups: mockNavIndex.groups,
|
||||
'alert-alerts': mockNavIndex['alert-alerts'],
|
||||
},
|
||||
});
|
||||
const wrapper = getWrapper({
|
||||
store,
|
||||
renderWithRouter: true,
|
||||
historyOptions: {
|
||||
initialEntries: ['/alerting/groups'],
|
||||
|
||||
@@ -2,6 +2,7 @@ import { renderHook } from '@testing-library/react';
|
||||
import { getWrapper } from 'test/test-utils';
|
||||
|
||||
import { config } from '@grafana/runtime';
|
||||
import { configureStore } from 'app/store/configureStore';
|
||||
|
||||
import { useAlertRulesNav } from './useAlertRulesNav';
|
||||
|
||||
@@ -55,8 +56,9 @@ describe('useAlertRulesNav', () => {
|
||||
|
||||
it('should return V2 navigation when feature flag is on', () => {
|
||||
config.featureToggles.alertingNavigationV2 = true;
|
||||
const store = configureStore(defaultPreloadedState);
|
||||
const wrapper = getWrapper({
|
||||
preloadedState: defaultPreloadedState,
|
||||
store,
|
||||
renderWithRouter: true,
|
||||
historyOptions: {
|
||||
initialEntries: ['/alerting/list'],
|
||||
@@ -80,10 +82,11 @@ describe('useAlertRulesNav', () => {
|
||||
'alert-rules-list': mockNavIndex['alert-rules-list'],
|
||||
// Missing 'alert-rules-recently-deleted' - user doesn't have permission
|
||||
};
|
||||
const store = configureStore({
|
||||
navIndex: limitedNavIndex,
|
||||
});
|
||||
const wrapper = getWrapper({
|
||||
preloadedState: {
|
||||
navIndex: limitedNavIndex,
|
||||
},
|
||||
store,
|
||||
renderWithRouter: true,
|
||||
historyOptions: {
|
||||
initialEntries: ['/alerting/list'],
|
||||
@@ -100,8 +103,9 @@ describe('useAlertRulesNav', () => {
|
||||
|
||||
it('should set active tab based on current path', () => {
|
||||
config.featureToggles.alertingNavigationV2 = true;
|
||||
const store = configureStore(defaultPreloadedState);
|
||||
const wrapper = getWrapper({
|
||||
preloadedState: defaultPreloadedState,
|
||||
store,
|
||||
renderWithRouter: true,
|
||||
historyOptions: {
|
||||
initialEntries: ['/alerting/recently-deleted'],
|
||||
|
||||
@@ -2,6 +2,7 @@ import { renderHook } from '@testing-library/react';
|
||||
import { getWrapper } from 'test/test-utils';
|
||||
|
||||
import { config } from '@grafana/runtime';
|
||||
import { configureStore } from 'app/store/configureStore';
|
||||
|
||||
import { useInsightsNav } from './useInsightsNav';
|
||||
|
||||
@@ -54,8 +55,9 @@ describe('useInsightsNav', () => {
|
||||
|
||||
it('should return V2 navigation when feature flag is on', () => {
|
||||
config.featureToggles.alertingNavigationV2 = true;
|
||||
const store = configureStore(defaultPreloadedState);
|
||||
const wrapper = getWrapper({
|
||||
preloadedState: defaultPreloadedState,
|
||||
store,
|
||||
renderWithRouter: true,
|
||||
historyOptions: {
|
||||
initialEntries: ['/alerting/insights'],
|
||||
@@ -72,8 +74,9 @@ describe('useInsightsNav', () => {
|
||||
|
||||
it('should set active tab based on current path', () => {
|
||||
config.featureToggles.alertingNavigationV2 = true;
|
||||
const store = configureStore(defaultPreloadedState);
|
||||
const wrapper = getWrapper({
|
||||
preloadedState: defaultPreloadedState,
|
||||
store,
|
||||
renderWithRouter: true,
|
||||
historyOptions: {
|
||||
initialEntries: ['/alerting/history'],
|
||||
@@ -94,10 +97,11 @@ describe('useInsightsNav', () => {
|
||||
'insights-system': mockNavIndex['insights-system'],
|
||||
// Missing 'insights-history' - user doesn't have permission
|
||||
};
|
||||
const store = configureStore({
|
||||
navIndex: limitedNavIndex,
|
||||
});
|
||||
const wrapper = getWrapper({
|
||||
preloadedState: {
|
||||
navIndex: limitedNavIndex,
|
||||
},
|
||||
store,
|
||||
renderWithRouter: true,
|
||||
historyOptions: {
|
||||
initialEntries: ['/alerting/insights'],
|
||||
|
||||
@@ -2,6 +2,7 @@ import { renderHook } from '@testing-library/react';
|
||||
import { getWrapper } from 'test/test-utils';
|
||||
|
||||
import { config } from '@grafana/runtime';
|
||||
import { configureStore } from 'app/store/configureStore';
|
||||
|
||||
import { useNotificationConfigNav } from './useNotificationConfigNav';
|
||||
|
||||
@@ -69,8 +70,9 @@ describe('useNotificationConfigNav', () => {
|
||||
|
||||
it('should return V2 navigation when feature flag is on', () => {
|
||||
config.featureToggles.alertingNavigationV2 = true;
|
||||
const store = configureStore(defaultPreloadedState);
|
||||
const wrapper = getWrapper({
|
||||
preloadedState: defaultPreloadedState,
|
||||
store,
|
||||
renderWithRouter: true,
|
||||
historyOptions: {
|
||||
initialEntries: ['/alerting/notifications'],
|
||||
@@ -85,13 +87,14 @@ describe('useNotificationConfigNav', () => {
|
||||
expect(result.current.pageNav?.children).toBeDefined();
|
||||
});
|
||||
|
||||
it('should detect time intervals tab from query params', () => {
|
||||
it('should detect time intervals tab from V2 path', () => {
|
||||
config.featureToggles.alertingNavigationV2 = true;
|
||||
const store = configureStore(defaultPreloadedState);
|
||||
const wrapper = getWrapper({
|
||||
preloadedState: defaultPreloadedState,
|
||||
store,
|
||||
renderWithRouter: true,
|
||||
historyOptions: {
|
||||
initialEntries: ['/alerting/routes?tab=time_intervals'],
|
||||
initialEntries: ['/alerting/time-intervals'],
|
||||
},
|
||||
});
|
||||
|
||||
@@ -111,10 +114,11 @@ describe('useNotificationConfigNav', () => {
|
||||
'notification-config-contact-points': mockNavIndex['notification-config-contact-points'],
|
||||
// Missing other tabs - user doesn't have permission
|
||||
};
|
||||
const store = configureStore({
|
||||
navIndex: limitedNavIndex,
|
||||
});
|
||||
const wrapper = getWrapper({
|
||||
preloadedState: {
|
||||
navIndex: limitedNavIndex,
|
||||
},
|
||||
store,
|
||||
renderWithRouter: true,
|
||||
historyOptions: {
|
||||
initialEntries: ['/alerting/notifications'],
|
||||
|
||||
Reference in New Issue
Block a user