Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -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))
Original file line number Diff line number Diff line change
@@ -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<string, AlertServiceType>[] = [
{ label: 'Linode', value: 'linode' },
{ label: 'Databases', value: 'dbaas' },
];

const mockAlerts: GroupedBy<Alert> = [
[
'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(
<GroupedAlertsTable
groupedAlerts={mockAlerts}
handleDetails={mockHandleDetails}
handleEdit={mockHandleEdit}
handleStatusChange={mockHandleStatusChange}
services={mockServices}
/>
);

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<Alert> = [
['tag1', alertFactory.buildList(50, { tags: ['tag1'] })],
];

renderWithTheme(
<GroupedAlertsTable
groupedAlerts={alerts}
handleDetails={mockHandleDetails}
handleEdit={mockHandleEdit}
handleStatusChange={mockHandleStatusChange}
services={mockServices}
/>
);

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<Alert> = [
['tag1', alertFactory.buildList(50, { tags: ['tag1'] })],
];

renderWithTheme(
<GroupedAlertsTable
groupedAlerts={alerts}
handleDetails={mockHandleDetails}
handleEdit={mockHandleEdit}
handleStatusChange={mockHandleStatusChange}
services={mockServices}
/>
);

// 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);
});
});
Original file line number Diff line number Diff line change
@@ -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 });
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ export const usePreferencesToggle = <K extends keyof ManagerPreferences>({

// 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 {
Expand Down