diff --git a/packages/manager/.changeset/pr-12042-upcoming-features-1744796837347.md b/packages/manager/.changeset/pr-12042-upcoming-features-1744796837347.md new file mode 100644 index 00000000000..8a2e5ac94a6 --- /dev/null +++ b/packages/manager/.changeset/pr-12042-upcoming-features-1744796837347.md @@ -0,0 +1,5 @@ +--- +"@linode/manager": Upcoming Features +--- + +Add unit tests in `GroupedAlertsTable.test.ts` and `UserPreference.test.ts` and fix preferences for alerts grouping at CloudPulse ([#12042](https://github.com/linode/manager/pull/12042)) diff --git a/packages/manager/src/features/CloudPulse/Alerts/AlertsListing/GroupedAlertsTable.test.tsx b/packages/manager/src/features/CloudPulse/Alerts/AlertsListing/GroupedAlertsTable.test.tsx new file mode 100644 index 00000000000..c922a49751d --- /dev/null +++ b/packages/manager/src/features/CloudPulse/Alerts/AlertsListing/GroupedAlertsTable.test.tsx @@ -0,0 +1,109 @@ +import { screen } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import * as React from 'react'; +import { vi } from 'vitest'; + +import { alertFactory } from 'src/factories'; +import { renderWithTheme } from 'src/utilities/testHelpers'; + +import { GroupedAlertsTable } from './GroupedAlertsTable'; + +import type { Item } from '../constants'; +import type { Alert, AlertServiceType } from '@linode/api-v4'; +import type { GroupedBy } from '@linode/utilities'; + +const mockScrollToElement = vi.hoisted(() => vi.fn()); + +vi.mock('../Utils/AlertResourceUtils', () => ({ + scrollToElement: mockScrollToElement, +})); + +const mockHandleDetails = vi.fn(); +const mockHandleEdit = vi.fn(); +const mockHandleStatusChange = vi.fn(); + +const mockServices: Item[] = [ + { label: 'Linode', value: 'linode' }, + { label: 'Databases', value: 'dbaas' }, +]; + +const mockAlerts: GroupedBy = [ + [ + 'tag1', + [ + alertFactory.build({ label: 'Alert 1', tags: ['tag1'] }), + alertFactory.build({ label: 'Alert 2', tags: ['tag1'] }), + ], + ], + ['tag2', [alertFactory.build({ label: 'Alert 3', tags: ['tag2'] })]], +]; + +describe('GroupedAlertsTable', () => { + it('should render grouped alerts by tag', () => { + renderWithTheme( + + ); + + expect(screen.getByText('tag1')).toBeVisible(); + expect(screen.getByText('tag2')).toBeVisible(); + expect(screen.getByText('Alert 1')).toBeVisible(); + expect(screen.getByText('Alert 2')).toBeVisible(); + expect(screen.getByText('Alert 3')).toBeVisible(); + }); + + it('should handle pagination properly', async () => { + const alerts: GroupedBy = [ + ['tag1', alertFactory.buildList(50, { tags: ['tag1'] })], + ]; + + renderWithTheme( + + ); + + expect(screen.getByRole('button', { name: 'page 1' })).toBeVisible(); + await userEvent.click( + screen.getByRole('button', { name: 'Go to next page' }) + ); + expect(screen.getByRole('button', { name: 'page 2' })).toBeVisible(); + }); + + it('should scroll to tag header when switching pages within tag pagination', async () => { + const alerts: GroupedBy = [ + ['tag1', alertFactory.buildList(50, { tags: ['tag1'] })], + ]; + + renderWithTheme( + + ); + + // Find and click next page within tag1's pagination + const nextPageButton = screen.getByRole('button', { + name: 'Go to next page', + }); + await userEvent.click(nextPageButton); + + const tagHeader = screen.getByRole('heading', { name: 'tag1' }); + expect(tagHeader).toBeVisible(); + + // Ensure that the user is scrolled to the tag header + expect(mockScrollToElement).toHaveBeenCalledWith(tagHeader); + }); +}); diff --git a/packages/manager/src/features/CloudPulse/Utils/UserPreference.test.ts b/packages/manager/src/features/CloudPulse/Utils/UserPreference.test.ts new file mode 100644 index 00000000000..20d401a56dc --- /dev/null +++ b/packages/manager/src/features/CloudPulse/Utils/UserPreference.test.ts @@ -0,0 +1,64 @@ +import { vi } from 'vitest'; + +import { usePreferencesToggle } from './UserPreference'; + +const queryMocks = vi.hoisted(() => ({ + useMutatePreferences: vi.fn(), + usePreferences: vi.fn(), +})); + +vi.mock('@linode/queries', () => ({ + useMutatePreferences: queryMocks.useMutatePreferences, + usePreferences: queryMocks.usePreferences, +})); + +describe('usePreferencesToggle', () => { + it('should initialize with undefined preference', () => { + queryMocks.usePreferences.mockReturnValue({ data: undefined }); + queryMocks.useMutatePreferences.mockReturnValue({ + mutateAsync: vi.fn().mockResolvedValue(undefined), + }); + const result = usePreferencesToggle({ + preferenceKey: 'aclpAlertsGroupByTag', + options: [false, true], + defaultValue: false, + }); + expect(result.preference).toBeUndefined(); + }); + + it('should toggle from undefined to second option', async () => { + const mockMutate = vi.fn().mockResolvedValue(undefined); + queryMocks.usePreferences.mockReturnValue({ data: undefined }); + queryMocks.useMutatePreferences.mockReturnValue({ + mutateAsync: mockMutate, + }); + + const result = usePreferencesToggle({ + preferenceKey: 'aclpAlertsGroupByTag', + options: [false, true], + defaultValue: false, + }); + + const newValue = result.toggle(); + expect(newValue).toBe(true); + expect(mockMutate).toHaveBeenCalledWith({ aclpAlertsGroupByTag: true }); + }); + + it('should toggle between options', async () => { + const mockMutate = vi.fn().mockResolvedValue(undefined); + queryMocks.usePreferences.mockReturnValue({ data: false }); + queryMocks.useMutatePreferences.mockReturnValue({ + mutateAsync: mockMutate, + }); + + const result = usePreferencesToggle({ + preferenceKey: 'aclpAlertsGroupByTag', + options: [false, true], + defaultValue: false, + }); + + const newValue = result.toggle(); + expect(newValue).toBe(true); + expect(mockMutate).toHaveBeenCalledWith({ aclpAlertsGroupByTag: true }); + }); +}); diff --git a/packages/manager/src/features/CloudPulse/Utils/UserPreference.ts b/packages/manager/src/features/CloudPulse/Utils/UserPreference.ts index 5541d155f83..c8985199e51 100644 --- a/packages/manager/src/features/CloudPulse/Utils/UserPreference.ts +++ b/packages/manager/src/features/CloudPulse/Utils/UserPreference.ts @@ -108,7 +108,7 @@ export const usePreferencesToggle = ({ // if the preference is undefined, set it to false if (preference === undefined) { - newPreferenceToSet = defaultValue; + newPreferenceToSet = options[defaultValue === options[0] ? 1 : 0]; } else if (preference === options[0]) { newPreferenceToSet = options[1]; } else {