Test/RTL: Use userEvent as much as possible and remove unneeded jest.clearAllMocks() (#35070)

* use userEvent as much as possible then fireEvent only if needed

* remove unnecessary jest.clearAllMocks

* update comments
This commit is contained in:
sabril
2026-01-29 00:52:24 +08:00
committed by GitHub
parent 67b8c89508
commit 7417d07733
171 changed files with 716 additions and 989 deletions
+9 -1
View File
@@ -87,7 +87,15 @@ The following guidelines should be applied to both new and existing code. Howeve
- **Selectors**: Prefer using accessible RTL selectors to help ensure that components are accessible, roughly in this order: `getByRole` > `getByText`/`getByPlaceholderText` > `getByLabelText`/`getByAltText`/`getByTitle` > `getByTestId`. Usage of `getByTestId` should be rare.
- **User Interactions**: Prefer `userEvent` over `fireEvent` for user interactions, and don't directly call methods on DOM elements to simulate events. RTL's `userEvent` simulates events the most realistically, and it ensures that component changes are properly wrapped in `act`.
- **Async Interactions**: Always wait for all methods of `userEvent` as those methods are all asynchronous (e.g. `await userEvent.click(...)`).
- **Usage of act**: `act` should only be used when performing any action that causes React to update and when that action does not alreadu go through a helper provided by RTL such as `userEvent`. Typically, most tests can be written without using `act` explicitly.
- **When fireEvent is acceptable**: Use `fireEvent` only in these specific cases where `userEvent` cannot be used:
- **Focus/Blur events**: `userEvent` doesn't have direct focus/blur methods. Use `fireEvent.focus()` and `fireEvent.blur()`.
- **Scroll events**: `userEvent` doesn't support scroll events. Use `fireEvent.scroll()`.
- **Image loading events**: `userEvent` doesn't support image loading events. Use `fireEvent.load()` and `fireEvent.error()`.
- **Document-level keyboard events**: `userEvent.keyboard()` requires element focus. Use `fireEvent.keyDown(document, ...)` for global keyboard shortcuts.
- **Fake timers**: `userEvent` doesn't work well with `jest.useFakeTimers()` and causes timeouts. Use `fireEvent.click()` when tests use fake timers.
- **Disabled elements**: `userEvent` respects CSS `pointer-events: none` on disabled elements. Use `fireEvent.click()` when testing that disabled element handlers are properly guarded.
- **MouseMove events**: `userEvent.hover()` only triggers mouseEnter/mouseOver, not mouseMove. Use `fireEvent.mouseMove()` when testing mouseMove handlers specifically.
- **Usage of act**: `act` should only be used when performing any action that causes React to update and when that action does not already go through a helper provided by RTL such as `userEvent`. Typically, most tests can be written without using `act` explicitly.
### Dependencies & Packages
@@ -13,7 +13,6 @@ describe('burn_on_read_deletion actions', () => {
beforeEach(() => {
mockDispatch = jest.fn();
jest.clearAllMocks();
});
describe('burnPostNow', () => {
@@ -28,10 +28,6 @@ describe('burn_on_read_posts actions', () => {
...mockPost,
};
beforeEach(() => {
jest.clearAllMocks();
});
describe('revealBurnOnReadPost', () => {
const mockState = {
entities: {
@@ -253,10 +253,6 @@ describe('actions/integration_actions', () => {
describe('lookupInteractiveDialog', () => {
const {getDialogArguments} = require('mattermost-redux/selectors/entities/integrations');
beforeEach(() => {
jest.clearAllMocks();
});
test('lookupInteractiveDialog with current channel', async () => {
const testState = {
...initialState,
@@ -341,10 +337,6 @@ describe('actions/integration_actions', () => {
});
describe('loadIncomingHooksAndProfilesForTeam', () => {
beforeEach(() => {
jest.clearAllMocks();
});
test('should load hooks and profiles', async () => {
const testStore = mockStore(initialState);
await testStore.dispatch(Actions.loadIncomingHooksAndProfilesForTeam('team_id1', 0, 50, false));
@@ -368,10 +360,6 @@ describe('actions/integration_actions', () => {
});
describe('loadOutgoingHooksAndProfilesForTeam', () => {
beforeEach(() => {
jest.clearAllMocks();
});
test('should load outgoing hooks and profiles', async () => {
const testStore = mockStore(initialState);
await testStore.dispatch(Actions.loadOutgoingHooksAndProfilesForTeam('team_id1', 1, 25));
@@ -388,10 +376,6 @@ describe('actions/integration_actions', () => {
});
describe('loadCommandsAndProfilesForTeam', () => {
beforeEach(() => {
jest.clearAllMocks();
});
test('should load commands and profiles', async () => {
const testStore = mockStore(initialState);
await testStore.dispatch(Actions.loadCommandsAndProfilesForTeam('team_id1'));
@@ -408,10 +392,6 @@ describe('actions/integration_actions', () => {
});
describe('loadOAuthAppsAndProfiles', () => {
beforeEach(() => {
jest.clearAllMocks();
});
test('should load OAuth apps with custom parameters', async () => {
const testStore = mockStore(initialState);
await testStore.dispatch(Actions.loadOAuthAppsAndProfiles(2, 30));
@@ -435,10 +415,6 @@ describe('actions/integration_actions', () => {
});
describe('loadOutgoingOAuthConnectionsAndProfiles', () => {
beforeEach(() => {
jest.clearAllMocks();
});
test('should load outgoing OAuth connections', async () => {
const testStore = mockStore(initialState);
await testStore.dispatch(Actions.loadOutgoingOAuthConnectionsAndProfiles('team_id1', 1, 50));
@@ -1,12 +1,11 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {fireEvent, screen, waitFor} from '@testing-library/react';
import React from 'react';
import AccessHistoryModal from 'components/access_history_modal/access_history_modal';
import {renderWithContext} from 'tests/react_testing_utils';
import {renderWithContext, screen, userEvent, waitFor} from 'tests/react_testing_utils';
jest.mock('components/audit_table', () => {
return jest.fn().mockImplementation(() => {
@@ -85,7 +84,7 @@ describe('components/AccessHistoryModal', () => {
);
await waitFor(() => screen.getByText('Access History'));
fireEvent.click(screen.getByLabelText('Close'));
await userEvent.click(screen.getByLabelText('Close'));
expect(onHide).toHaveBeenCalledTimes(1);
});
@@ -1,7 +1,6 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {fireEvent, screen, waitFor} from '@testing-library/react';
import React from 'react';
import type {MouseEvent} from 'react';
@@ -9,7 +8,7 @@ import {General} from 'mattermost-redux/constants';
import ActivityLogModal from 'components/activity_log_modal/activity_log_modal';
import {renderWithContext} from 'tests/react_testing_utils';
import {renderWithContext, screen, userEvent, waitFor} from 'tests/react_testing_utils';
jest.mock('components/activity_log_modal/components/activity_log', () => {
return jest.fn().mockImplementation(({submitRevoke, currentSession}) => {
@@ -115,7 +114,7 @@ describe('components/ActivityLogModal', () => {
/>,
);
fireEvent.click(screen.getByTestId('activity-log'));
await userEvent.click(screen.getByTestId('activity-log'));
expect(revokeSession).toHaveBeenCalledTimes(1);
expect(revokeSession).toHaveBeenCalledWith('user1', 'session1');
@@ -137,7 +136,7 @@ describe('components/ActivityLogModal', () => {
);
await waitFor(() => screen.getByText('Active Sessions'));
fireEvent.click(screen.getByLabelText('Close'));
await userEvent.click(screen.getByLabelText('Close'));
expect(onHide).toHaveBeenCalledTimes(1);
});
@@ -1,12 +1,11 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {screen, waitFor, fireEvent} from '@testing-library/react';
import React from 'react';
import type {UserProfile} from '@mattermost/types/users';
import {renderWithContext} from 'tests/react_testing_utils';
import {renderWithContext, screen, userEvent, waitFor} from 'tests/react_testing_utils';
import {TestHelper} from 'utils/test_helper';
import TestResultsModal from './test_modal';
@@ -86,8 +85,6 @@ describe('TestResultsModal', () => {
};
beforeEach(() => {
jest.clearAllMocks();
// Mock Redux thunk that returns successful user search response
mockSearchUsers.mockReturnValue(() => Promise.resolve({
data: {
@@ -97,10 +94,6 @@ describe('TestResultsModal', () => {
}));
});
afterEach(() => {
jest.clearAllMocks();
});
it('should render modal with proper title and structure', async () => {
renderWithContext(<TestResultsModal {...defaultProps}/>);
@@ -147,7 +140,8 @@ describe('TestResultsModal', () => {
// Perform search
const searchInput = screen.getByTestId('search-input');
fireEvent.change(searchInput, {target: {value: 'test search'}});
await userEvent.clear(searchInput);
await userEvent.type(searchInput, 'test search');
await waitFor(() => {
expect(mockSearchUsers).toHaveBeenCalledWith('test search', '', 50);
@@ -172,7 +166,7 @@ describe('TestResultsModal', () => {
// Click next page - this should trigger pagination with page=2 which translates to 20 users per page
const nextPageButton = screen.getByTestId('next-page-button');
fireEvent.click(nextPageButton);
await userEvent.click(nextPageButton);
// The nextPage function gets called with page 1 (second page), but since it's above USERS_PER_PAGE (10)
// but less than USERS_TO_FETCH (50), it should use the cursor logic and call with the last user's ID
@@ -199,7 +193,7 @@ describe('TestResultsModal', () => {
// Click next page while loading
const nextPageButton = screen.getByTestId('next-page-button');
fireEvent.click(nextPageButton);
await userEvent.click(nextPageButton);
// Should not make additional call while loading
expect(mockSearchUsers).toHaveBeenCalledTimes(1);
@@ -241,7 +235,7 @@ describe('TestResultsModal', () => {
// Find and click the close button
const closeButton = screen.getByLabelText('Close');
fireEvent.click(closeButton);
await userEvent.click(closeButton);
await waitFor(() => {
expect(mockOnExited).toHaveBeenCalled();
@@ -302,15 +296,16 @@ describe('TestResultsModal', () => {
// Perform first search
const searchInput = screen.getByTestId('search-input');
fireEvent.change(searchInput, {target: {value: 'search1'}});
await userEvent.clear(searchInput);
await userEvent.type(searchInput, 'search1');
await waitFor(() => {
expect(mockSearchUsers).toHaveBeenCalledWith('search1', '', 50);
});
// Perform second search
fireEvent.change(searchInput, {target: {value: ''}});
fireEvent.change(searchInput, {target: {value: 'search2'}});
await userEvent.clear(searchInput);
await userEvent.type(searchInput, 'search2');
await waitFor(() => {
expect(mockSearchUsers).toHaveBeenCalledWith('search2', '', 50);
@@ -1,10 +1,11 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {fireEvent, render, screen} from '@testing-library/react';
import React from 'react';
import {MemoryRouter} from 'react-router-dom';
import {render, screen, userEvent} from 'tests/react_testing_utils';
import BlockableLink from './blockable_link';
jest.mock('utils/browser_history', () => ({
@@ -34,18 +35,18 @@ describe('components/admin_console/blockable_link/BlockableLink', () => {
expect(screen.getByRole('link')).toHaveAttribute('href', '/admin_console/test');
});
test('should navigate directly when not blocked', () => {
test('should navigate directly when not blocked', async () => {
render(
<MemoryRouter>
<BlockableLink {...defaultProps}/>
</MemoryRouter>,
);
fireEvent.click(screen.getByText('Link Text'));
await userEvent.click(screen.getByText('Link Text'));
expect(defaultProps.actions.deferNavigation).not.toHaveBeenCalled();
});
test('should defer navigation when blocked', () => {
test('should defer navigation when blocked', async () => {
const blockedProps = {
...defaultProps,
blocked: true,
@@ -57,11 +58,11 @@ describe('components/admin_console/blockable_link/BlockableLink', () => {
</MemoryRouter>,
);
fireEvent.click(screen.getByText('Link Text'));
await userEvent.click(screen.getByText('Link Text'));
expect(blockedProps.actions.deferNavigation).toHaveBeenCalled();
});
test('should call custom onClick handler if provided', () => {
test('should call custom onClick handler if provided', async () => {
const onClickProps = {
...defaultProps,
onClick: jest.fn(),
@@ -73,7 +74,7 @@ describe('components/admin_console/blockable_link/BlockableLink', () => {
</MemoryRouter>,
);
fireEvent.click(screen.getByText('Link Text'));
await userEvent.click(screen.getByText('Link Text'));
expect(onClickProps.onClick).toHaveBeenCalled();
});
@@ -3,7 +3,7 @@
import React from 'react';
import {renderWithContext, screen, fireEvent} from 'tests/react_testing_utils';
import {renderWithContext, screen, userEvent} from 'tests/react_testing_utils';
import CheckboxSetting from './checkbox_setting';
@@ -26,7 +26,7 @@ describe('components/admin_console/CheckboxSetting', () => {
expect(container).toMatchSnapshot();
});
test('onChange', () => {
test('onChange', async () => {
const onChange = jest.fn();
renderWithContext(
<CheckboxSetting
@@ -41,7 +41,7 @@ describe('components/admin_console/CheckboxSetting', () => {
const checkbox: HTMLInputElement = screen.getByRole('checkbox');
expect(checkbox).not.toBeChecked();
fireEvent.click(checkbox);
await userEvent.click(checkbox);
expect(onChange).toHaveBeenCalledTimes(1);
expect(onChange).toHaveBeenCalledWith('string.id', true);
@@ -1,12 +1,11 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {screen, fireEvent} from '@testing-library/react';
import React from 'react';
import type {ContentFlaggingAdditionalSettings} from '@mattermost/types/config';
import {renderWithContext} from 'tests/react_testing_utils';
import {renderWithContext, screen, userEvent} from 'tests/react_testing_utils';
import ContentFlaggingAdditionalSettingsSection from './additional_settings';
@@ -22,10 +21,6 @@ describe('ContentFlaggingAdditionalSettingsSection', () => {
} as ContentFlaggingAdditionalSettings,
};
beforeEach(() => {
jest.clearAllMocks();
});
test('should render with initial values', () => {
renderWithContext(<ContentFlaggingAdditionalSettingsSection {...defaultProps}/>);
@@ -60,10 +55,10 @@ describe('ContentFlaggingAdditionalSettingsSection', () => {
expect(screen.getByTestId('hideFlaggedPosts_true')).not.toBeChecked();
});
test('should call onChange when reporter comment requirement changes', () => {
test('should call onChange when reporter comment requirement changes', async () => {
renderWithContext(<ContentFlaggingAdditionalSettingsSection {...defaultProps}/>);
fireEvent.click(screen.getByTestId('requireReporterComment_true'));
await userEvent.click(screen.getByTestId('requireReporterComment_true'));
expect(defaultProps.onChange).toHaveBeenCalledWith('ContentFlaggingAdditionalSettings', {
...(defaultProps.value as ContentFlaggingAdditionalSettings),
@@ -71,10 +66,10 @@ describe('ContentFlaggingAdditionalSettingsSection', () => {
});
});
test('should call onChange when reviewer comment requirement changes', () => {
test('should call onChange when reviewer comment requirement changes', async () => {
renderWithContext(<ContentFlaggingAdditionalSettingsSection {...defaultProps}/>);
fireEvent.click(screen.getByTestId('requireReviewerComment_false'));
await userEvent.click(screen.getByTestId('requireReviewerComment_false'));
expect(defaultProps.onChange).toHaveBeenCalledWith('ContentFlaggingAdditionalSettings', {
...(defaultProps.value as ContentFlaggingAdditionalSettings),
@@ -82,10 +77,10 @@ describe('ContentFlaggingAdditionalSettingsSection', () => {
});
});
test('should call onChange when hide flagged content setting changes', () => {
test('should call onChange when hide flagged content setting changes', async () => {
renderWithContext(<ContentFlaggingAdditionalSettingsSection {...defaultProps}/>);
fireEvent.click(screen.getByTestId('hideFlaggedPosts_true'));
await userEvent.click(screen.getByTestId('hideFlaggedPosts_true'));
expect(defaultProps.onChange).toHaveBeenCalledWith('ContentFlaggingAdditionalSettings', {
...(defaultProps.value as ContentFlaggingAdditionalSettings),
@@ -153,18 +148,18 @@ describe('ContentFlaggingAdditionalSettingsSection', () => {
expect(selectInput).toHaveAttribute('id', 'contentFlaggingReasons');
});
test('should maintain state consistency across multiple changes', () => {
test('should maintain state consistency across multiple changes', async () => {
renderWithContext(<ContentFlaggingAdditionalSettingsSection {...defaultProps}/>);
// Change reporter comment requirement
fireEvent.click(screen.getByTestId('requireReporterComment_true'));
await userEvent.click(screen.getByTestId('requireReporterComment_true'));
expect(defaultProps.onChange).toHaveBeenLastCalledWith('ContentFlaggingAdditionalSettings', {
...(defaultProps.value as ContentFlaggingAdditionalSettings),
ReporterCommentRequired: true,
});
// Change hide flagged content
fireEvent.click(screen.getByTestId('hideFlaggedPosts_true'));
await userEvent.click(screen.getByTestId('hideFlaggedPosts_true'));
expect(defaultProps.onChange).toHaveBeenLastCalledWith('ContentFlaggingAdditionalSettings', {
...(defaultProps.value as ContentFlaggingAdditionalSettings),
ReporterCommentRequired: true,
@@ -1,11 +1,10 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {screen, fireEvent} from '@testing-library/react';
import React from 'react';
import type {MultiValueProps} from 'react-select/dist/declarations/src/components/MultiValue';
import {renderWithContext} from 'tests/react_testing_utils';
import {renderWithContext, screen, userEvent} from 'tests/react_testing_utils';
import {ReasonOption} from './reason_option';
@@ -32,10 +31,6 @@ describe('ReasonOption', () => {
theme: {} as any,
} as unknown as MultiValueProps<{label: string; value: string}, true>;
beforeEach(() => {
jest.clearAllMocks();
});
test('should render the reason option with correct label', () => {
renderWithContext(<ReasonOption {...mockProps}/>);
@@ -55,11 +50,11 @@ describe('ReasonOption', () => {
expect(removeButton).toBeInTheDocument();
});
test('should call onClick when remove button is clicked', () => {
test('should call onClick when remove button is clicked', async () => {
const {container} = renderWithContext(<ReasonOption {...mockProps}/>);
const removeButton = container.querySelector('.Remove');
fireEvent.click(removeButton!);
await userEvent.click(removeButton!);
expect(mockProps.removeProps.onClick).toHaveBeenCalledTimes(1);
});
@@ -1,12 +1,11 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {screen, fireEvent} from '@testing-library/react';
import React from 'react';
import type {ContentFlaggingReviewerSetting, TeamReviewerSetting} from '@mattermost/types/config';
import {renderWithContext} from 'tests/react_testing_utils';
import {renderWithContext, screen, userEvent} from 'tests/react_testing_utils';
import ContentFlaggingContentReviewers from './content_reviewers';
@@ -57,10 +56,6 @@ describe('ContentFlaggingContentReviewers', () => {
setByEnv: false,
};
beforeEach(() => {
jest.clearAllMocks();
});
it('renders the component with correct title and description', () => {
renderWithContext(<ContentFlaggingContentReviewers {...defaultProps}/>);
@@ -108,7 +103,7 @@ describe('ContentFlaggingContentReviewers', () => {
expect(screen.getByText('Team Administrators')).toBeInTheDocument();
});
it('handles same reviewers for all teams radio button change to true', () => {
it('handles same reviewers for all teams radio button change to true', async () => {
const props = {
...defaultProps,
value: {
@@ -120,7 +115,7 @@ describe('ContentFlaggingContentReviewers', () => {
renderWithContext(<ContentFlaggingContentReviewers {...props}/>);
const trueRadio = screen.getByTestId('sameReviewersForAllTeams_true');
fireEvent.click(trueRadio);
await userEvent.click(trueRadio);
expect(defaultProps.onChange).toHaveBeenCalledWith('content_reviewers', {
...props.value,
@@ -128,11 +123,11 @@ describe('ContentFlaggingContentReviewers', () => {
});
});
it('handles same reviewers for all teams radio button change to false', () => {
it('handles same reviewers for all teams radio button change to false', async () => {
renderWithContext(<ContentFlaggingContentReviewers {...defaultProps}/>);
const falseRadio = screen.getByTestId('sameReviewersForAllTeams_false');
fireEvent.click(falseRadio);
await userEvent.click(falseRadio);
expect(defaultProps.onChange).toHaveBeenCalledWith('content_reviewers', {
...(defaultProps.value as ContentFlaggingReviewerSetting),
@@ -140,11 +135,11 @@ describe('ContentFlaggingContentReviewers', () => {
});
});
it('handles system admin reviewer checkbox change', () => {
it('handles system admin reviewer checkbox change', async () => {
renderWithContext(<ContentFlaggingContentReviewers {...defaultProps}/>);
const systemAdminCheckbox = screen.getByRole('checkbox', {name: /system administrators/i});
fireEvent.click(systemAdminCheckbox);
await userEvent.click(systemAdminCheckbox);
expect(defaultProps.onChange).toHaveBeenCalledWith('content_reviewers', {
...(defaultProps.value as ContentFlaggingReviewerSetting),
@@ -152,11 +147,11 @@ describe('ContentFlaggingContentReviewers', () => {
});
});
it('handles team admin reviewer checkbox change', () => {
it('handles team admin reviewer checkbox change', async () => {
renderWithContext(<ContentFlaggingContentReviewers {...defaultProps}/>);
const teamAdminCheckbox = screen.getByRole('checkbox', {name: /team administrators/i});
fireEvent.click(teamAdminCheckbox);
await userEvent.click(teamAdminCheckbox);
expect(defaultProps.onChange).toHaveBeenCalledWith('content_reviewers', {
...(defaultProps.value as ContentFlaggingReviewerSetting),
@@ -164,11 +159,11 @@ describe('ContentFlaggingContentReviewers', () => {
});
});
it('handles common reviewers change', () => {
it('handles common reviewers change', async () => {
renderWithContext(<ContentFlaggingContentReviewers {...defaultProps}/>);
const changeUsersButton = screen.getByTestId('content_reviewers_common_reviewers-change-users');
fireEvent.click(changeUsersButton);
await userEvent.click(changeUsersButton);
expect(defaultProps.onChange).toHaveBeenCalledWith('content_reviewers', {
...(defaultProps.value as ContentFlaggingReviewerSetting),
@@ -176,7 +171,7 @@ describe('ContentFlaggingContentReviewers', () => {
});
});
it('handles team reviewer settings change', () => {
it('handles team reviewer settings change', async () => {
const props = {
...defaultProps,
value: {
@@ -188,7 +183,7 @@ describe('ContentFlaggingContentReviewers', () => {
renderWithContext(<ContentFlaggingContentReviewers {...props}/>);
const changeTeamReviewersButton = screen.getByTestId('team-reviewers-change');
fireEvent.click(changeTeamReviewersButton);
await userEvent.click(changeTeamReviewersButton);
expect(defaultProps.onChange).toHaveBeenCalledWith('content_reviewers', {
...props.value,
@@ -81,7 +81,6 @@ describe('TeamOptionComponent', () => {
} as unknown as OptionProps<AutocompleteOptionType<Team>, true>;
beforeEach(() => {
jest.clearAllMocks();
(Utils.imageURLForTeam as jest.Mock).mockReturnValue('http://example.com/team-icon.png');
});
@@ -1,7 +1,6 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {screen, fireEvent, waitFor} from '@testing-library/react';
import React from 'react';
import type {TeamReviewerSetting} from '@mattermost/types/config';
@@ -9,7 +8,7 @@ import type {Team} from '@mattermost/types/teams';
import {searchTeams} from 'mattermost-redux/actions/teams';
import {renderWithContext} from 'tests/react_testing_utils';
import {renderWithContext, screen, userEvent, waitFor} from 'tests/react_testing_utils';
import {TestHelper} from 'utils/test_helper';
import TeamReviewersSection from './team_reviewers_section';
@@ -40,8 +39,6 @@ describe('TeamReviewersSection', () => {
};
beforeEach(() => {
jest.clearAllMocks();
mockSearchTeams.mockReturnValue(async () => ({
data: {
teams: mockTeams,
@@ -88,7 +85,8 @@ describe('TeamReviewersSection', () => {
});
const searchInput = screen.getByRole('textbox');
fireEvent.change(searchInput, {target: {value: 'search term'}});
await userEvent.clear(searchInput);
await userEvent.type(searchInput, 'search term');
await waitFor(() => {
expect(mockSearchTeams).toHaveBeenCalledWith('search term', {page: 0, per_page: 10});
@@ -120,7 +118,7 @@ describe('TeamReviewersSection', () => {
});
const nextButton = screen.getByRole('button', {name: /next/i});
fireEvent.click(nextButton);
await userEvent.click(nextButton);
await waitFor(() => {
expect(mockSearchTeams).toHaveBeenCalledWith('', {page: 1, per_page: 10});
@@ -153,7 +151,7 @@ describe('TeamReviewersSection', () => {
});
const nextButton = screen.getByRole('button', {name: /Next page/i});
fireEvent.click(nextButton);
await userEvent.click(nextButton);
await waitFor(() => {
expect(mockSearchTeams).toHaveBeenCalledWith('', {page: 1, per_page: 10});
@@ -161,7 +159,7 @@ describe('TeamReviewersSection', () => {
// Then go back to previous page
const prevButton = screen.getByRole('button', {name: /Previous page/i});
fireEvent.click(prevButton);
await userEvent.click(prevButton);
await waitFor(() => {
expect(mockSearchTeams).toHaveBeenCalledWith('', {page: 0, per_page: 10});
@@ -192,7 +190,7 @@ describe('TeamReviewersSection', () => {
});
const toggle = screen.getAllByRole('button', {name: /enable or disable content reviewers for this team/i})[0];
fireEvent.click(toggle);
await userEvent.click(toggle);
expect(onChange).toHaveBeenCalledWith({
team1: {
@@ -233,7 +231,7 @@ describe('TeamReviewersSection', () => {
});
const toggle = screen.getAllByRole('button', {name: /enable or disable content reviewers for this team/i})[0];
fireEvent.click(toggle);
await userEvent.click(toggle);
expect(onChange).toHaveBeenCalledWith({
team1: {
@@ -327,7 +325,7 @@ describe('TeamReviewersSection', () => {
// Go to next page
const nextButton = screen.getByRole('button', {name: /next/i});
fireEvent.click(nextButton);
await userEvent.click(nextButton);
await waitFor(() => {
expect(mockSearchTeams).toHaveBeenCalledWith('', {page: 1, per_page: 10});
@@ -335,7 +333,8 @@ describe('TeamReviewersSection', () => {
// Search - should reset to page 0
const searchInput = screen.getByRole('textbox');
fireEvent.change(searchInput, {target: {value: 'search'}});
await userEvent.clear(searchInput);
await userEvent.type(searchInput, 'search');
await waitFor(() => {
expect(mockSearchTeams).toHaveBeenCalledWith('search', {page: 0, per_page: 10});
@@ -388,7 +387,7 @@ describe('TeamReviewersSection', () => {
const toggle = screen.getAllByRole('button', {name: /enable or disable content reviewers for this team/i})[0];
// First click - enable
fireEvent.click(toggle);
await userEvent.click(toggle);
expect(onChange).toHaveBeenCalledWith({
team1: {
Enabled: true,
@@ -416,7 +415,7 @@ describe('TeamReviewersSection', () => {
const updatedToggle = screen.getAllByRole('button', {name: /enable or disable content reviewers for this team/i})[0];
// Second click - disable
fireEvent.click(updatedToggle);
await userEvent.click(updatedToggle);
expect(onChange).toHaveBeenCalledWith({
team1: {
Enabled: true,
@@ -454,7 +453,7 @@ describe('TeamReviewersSection', () => {
});
const disableForAllButton = screen.getByTestId('disableForAllTeamsButton');
fireEvent.click(disableForAllButton);
await userEvent.click(disableForAllButton);
expect(onChange).toHaveBeenCalledWith({
team1: {
@@ -1,12 +1,13 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {render, screen, fireEvent} from '@testing-library/react';
import React from 'react';
import {IntlProvider} from 'react-intl';
import type {ContentFlaggingNotificationSettings} from '@mattermost/types/config';
import {fireEvent, render, screen, userEvent} from 'tests/react_testing_utils';
import ContentFlaggingNotificationSettingsSection from './notification_settings';
const renderWithContext = (component: React.ReactElement) => {
@@ -31,10 +32,6 @@ describe('ContentFlaggingNotificationSettingsSection', () => {
onChange: jest.fn(),
};
beforeEach(() => {
jest.clearAllMocks();
});
test('should render section title and description', () => {
renderWithContext(<ContentFlaggingNotificationSettingsSection {...defaultProps}/>);
@@ -80,11 +77,11 @@ describe('ContentFlaggingNotificationSettingsSection', () => {
expect(screen.getByTestId('dismissed_reporter')).not.toBeChecked();
});
test('should handle checkbox change when adding a target', () => {
test('should handle checkbox change when adding a target', async () => {
renderWithContext(<ContentFlaggingNotificationSettingsSection {...defaultProps}/>);
const flaggedAuthorsCheckbox = screen.getByTestId('flagged_author');
fireEvent.click(flaggedAuthorsCheckbox);
await userEvent.click(flaggedAuthorsCheckbox);
expect(defaultProps.onChange).toHaveBeenCalledWith('test-id', {
EventTargetMapping: {
@@ -96,11 +93,11 @@ describe('ContentFlaggingNotificationSettingsSection', () => {
});
});
test('should handle checkbox change when removing a target', () => {
test('should handle checkbox change when removing a target', async () => {
renderWithContext(<ContentFlaggingNotificationSettingsSection {...defaultProps}/>);
const removedAuthorCheckbox = screen.getByTestId('removed_author');
fireEvent.click(removedAuthorCheckbox);
await userEvent.click(removedAuthorCheckbox);
expect(defaultProps.onChange).toHaveBeenCalledWith('test-id', {
EventTargetMapping: {
@@ -140,6 +137,7 @@ describe('ContentFlaggingNotificationSettingsSection', () => {
renderWithContext(<ContentFlaggingNotificationSettingsSection {...propsWithoutMapping}/>);
// Use fireEvent.click to test defensive coding in handler (checkbox is disabled)
const flaggedReviewersCheckbox = screen.getByTestId('flagged_reviewers');
fireEvent.click(flaggedReviewersCheckbox);
@@ -153,7 +151,7 @@ describe('ContentFlaggingNotificationSettingsSection', () => {
});
});
test('should initialize action array if not present', () => {
test('should initialize action array if not present', async () => {
const propsWithPartialMapping = {
...defaultProps,
value: {
@@ -168,7 +166,7 @@ describe('ContentFlaggingNotificationSettingsSection', () => {
renderWithContext(<ContentFlaggingNotificationSettingsSection {...propsWithPartialMapping}/>);
const assignedReviewersCheckbox = screen.getByTestId('assigned_reviewers');
fireEvent.click(assignedReviewersCheckbox);
await userEvent.click(assignedReviewersCheckbox);
expect(defaultProps.onChange).toHaveBeenCalledWith('test-id', {
EventTargetMapping: {
@@ -181,6 +179,7 @@ describe('ContentFlaggingNotificationSettingsSection', () => {
test('should not add duplicate targets', () => {
renderWithContext(<ContentFlaggingNotificationSettingsSection {...defaultProps}/>);
// Use fireEvent.click to test defensive coding in handler (checkbox is disabled)
// Try to add 'reviewers' to flagged again (it's already there)
const flaggedReviewersCheckbox = screen.getByTestId('flagged_reviewers');
fireEvent.click(flaggedReviewersCheckbox);
@@ -196,16 +195,16 @@ describe('ContentFlaggingNotificationSettingsSection', () => {
});
});
test('should handle multiple checkbox changes correctly', () => {
test('should handle multiple checkbox changes correctly', async () => {
renderWithContext(<ContentFlaggingNotificationSettingsSection {...defaultProps}/>);
// First change: add author to flagged
const flaggedAuthorsCheckbox = screen.getByTestId('flagged_author');
fireEvent.click(flaggedAuthorsCheckbox);
await userEvent.click(flaggedAuthorsCheckbox);
// Second change: add reporter to removed
const removedReporterCheckbox = screen.getByTestId('removed_reporter');
fireEvent.click(removedReporterCheckbox);
await userEvent.click(removedReporterCheckbox);
expect(defaultProps.onChange).toHaveBeenCalledTimes(2);
@@ -228,13 +227,13 @@ describe('ContentFlaggingNotificationSettingsSection', () => {
});
});
test('should handle unchecking and rechecking the same checkbox', () => {
test('should handle unchecking and rechecking the same checkbox', async () => {
renderWithContext(<ContentFlaggingNotificationSettingsSection {...defaultProps}/>);
const removedAuthorCheckbox = screen.getByTestId('removed_author');
// First click: uncheck (remove author from removed)
fireEvent.click(removedAuthorCheckbox);
await userEvent.click(removedAuthorCheckbox);
expect(defaultProps.onChange).toHaveBeenNthCalledWith(1, 'test-id', {
EventTargetMapping: {
flagged: ['reviewers'],
@@ -245,7 +244,7 @@ describe('ContentFlaggingNotificationSettingsSection', () => {
});
// Second click: check again (add author back to removed)
fireEvent.click(removedAuthorCheckbox);
await userEvent.click(removedAuthorCheckbox);
expect(defaultProps.onChange).toHaveBeenNthCalledWith(2, 'test-id', {
EventTargetMapping: {
flagged: ['reviewers'],
@@ -8,7 +8,7 @@ import type {Group} from '@mattermost/types/groups';
import type {Team} from '@mattermost/types/teams';
import type {UserProfile} from '@mattermost/types/users';
import {fireEvent, renderWithContext} from 'tests/react_testing_utils';
import {renderWithContext, userEvent} from 'tests/react_testing_utils';
import {TestHelper} from 'utils/test_helper';
import type {AutocompleteOptionType} from './user_multiselector';
@@ -66,10 +66,6 @@ describe('components/admin_console/content_flagging/user_multiselector/UserProfi
},
};
beforeEach(() => {
jest.clearAllMocks();
});
test('should render user profile pill with avatar and display name', () => {
const {container} = renderWithContext(
<MultiUserProfilePill {...baseProps}/>,
@@ -110,7 +106,7 @@ describe('components/admin_console/content_flagging/user_multiselector/UserProfi
expect(removeComponent).toBeInTheDocument();
});
test('should call onClick when remove button is clicked', () => {
test('should call onClick when remove button is clicked', async () => {
const mockOnClick = jest.fn();
const propsWithClick = {
...baseProps,
@@ -128,7 +124,7 @@ describe('components/admin_console/content_flagging/user_multiselector/UserProfi
expect(removeComponent).toBeInTheDocument();
expect(removeComponent).toBeDefined();
fireEvent.click(removeComponent!);
await userEvent.click(removeComponent!);
expect(mockOnClick).toHaveBeenCalledTimes(1);
});
@@ -1,11 +1,10 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {fireEvent, screen} from '@testing-library/react';
import React from 'react';
import {FormattedMessage} from 'react-intl';
import {renderWithContext} from 'tests/react_testing_utils';
import {renderWithContext, screen, userEvent} from 'tests/react_testing_utils';
import CustomEnableDisableGuestAccountsSetting from './custom_enable_disable_guest_accounts_setting';
@@ -50,7 +49,7 @@ describe('components/AdminConsole/CustomEnableDisableGuestAccountsSetting', () =
});
describe('handleChange', () => {
test('should enable without show confirmation modal or warning', () => {
test('should enable without show confirmation modal or warning', async () => {
const props = {
showConfirm: true,
onChange: jest.fn(),
@@ -64,12 +63,12 @@ describe('components/AdminConsole/CustomEnableDisableGuestAccountsSetting', () =
);
const trueRadio = screen.getByTestId('MySettingtrue');
fireEvent.click(trueRadio);
await userEvent.click(trueRadio);
expect(props.onChange).toHaveBeenCalledWith(baseProps.id, true, false, false, '');
});
test('should show confirmation modal and warning when disabling', () => {
test('should show confirmation modal and warning when disabling', async () => {
const props = {
value: true,
showConfirm: true,
@@ -84,12 +83,12 @@ describe('components/AdminConsole/CustomEnableDisableGuestAccountsSetting', () =
);
const falseRadio = screen.getByTestId('MySettingfalse');
fireEvent.click(falseRadio);
await userEvent.click(falseRadio);
expect(props.onChange).toHaveBeenCalledWith(baseProps.id, false, true, false, warningMessage);
});
test('should call onChange with doSubmit = true when confirm is true', () => {
test('should call onChange with doSubmit = true when confirm is true', async () => {
const props = {
...baseProps,
onChange: jest.fn(),
@@ -103,10 +102,10 @@ describe('components/AdminConsole/CustomEnableDisableGuestAccountsSetting', () =
);
const falseRadio = screen.getByTestId('MySettingfalse');
fireEvent.click(falseRadio);
await userEvent.click(falseRadio);
const confirmButton = screen.getByText('Save and Disable Guest Access');
fireEvent.click(confirmButton);
await userEvent.click(confirmButton);
expect(props.onChange).toHaveBeenCalledWith(baseProps.id, false, true, true, warningMessage);
});
@@ -1,14 +1,13 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {screen, fireEvent} from '@testing-library/react';
import React from 'react';
import type {UserPropertyField, UserPropertyFieldGroupID, UserPropertyFieldType} from '@mattermost/types/properties';
import {Client4} from 'mattermost-redux/client';
import {act, renderWithContext} from 'tests/react_testing_utils';
import {act, renderWithContext, screen, userEvent} from 'tests/react_testing_utils';
import CustomProfileAttributes from './custom_profile_attributes';
@@ -56,10 +55,6 @@ describe('components/admin_console/custom_profile_attributes/CustomProfileAttrib
const initialState = createInitialState({attr1, attr2});
beforeEach(() => {
jest.clearAllMocks();
});
test('should not render anything when no attributes exist', () => {
const {container} = renderWithContext(
<CustomProfileAttributes {...baseProps}/>,
@@ -100,9 +95,11 @@ describe('components/admin_console/custom_profile_attributes/CustomProfileAttrib
);
const input = await screen.findByDisplayValue('department');
fireEvent.change(input, {target: {value: 'new-department'}});
await userEvent.clear(input);
await userEvent.type(input, 'new-department');
const saveAction = baseProps.registerSaveAction.mock.calls[1][0];
const calls = baseProps.registerSaveAction.mock.calls;
const saveAction = calls[calls.length - 1][0];
await act(async () => {
await saveAction();
});
@@ -158,9 +155,11 @@ describe('components/admin_console/custom_profile_attributes/CustomProfileAttrib
);
const input = await screen.findByDisplayValue('title');
fireEvent.change(input, {target: {value: 'new-title'}});
await userEvent.clear(input);
await userEvent.type(input, 'new-title');
const saveAction = baseProps.registerSaveAction.mock.calls[1][0];
const calls = baseProps.registerSaveAction.mock.calls;
const saveAction = calls[calls.length - 1][0];
await act(async () => {
await saveAction();
});
@@ -199,9 +198,11 @@ describe('components/admin_console/custom_profile_attributes/CustomProfileAttrib
);
const input = await screen.findByDisplayValue('department');
fireEvent.change(input, {target: {value: 'new-department'}});
await userEvent.clear(input);
await userEvent.type(input, 'new-department');
const saveAction = baseProps.registerSaveAction.mock.calls[1][0];
const calls = baseProps.registerSaveAction.mock.calls;
const saveAction = calls[calls.length - 1][0];
// Verify the save action catches and returns the error
await expect(saveAction()).resolves.toEqual(
@@ -1,12 +1,11 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {fireEvent, waitFor} from '@testing-library/react';
import React from 'react';
import type {AllowedIPRange} from '@mattermost/types/config';
import {renderWithContext} from 'tests/react_testing_utils';
import {fireEvent, renderWithContext, userEvent, waitFor} from 'tests/react_testing_utils';
import IPFilteringAddOrEditModal from './add_edit_ip_filter_modal';
@@ -73,9 +72,11 @@ describe('IPFilteringAddOrEditModal', () => {
/>,
);
fireEvent.change(getByLabelText('Enter a name for this rule'), {target: {value: 'Test IP Filter 2'}});
fireEvent.change(getByLabelText('Enter IP Range'), {target: {value: '10.0.0.0/8'}});
fireEvent.click(getByTestId('save-add-edit-button'));
await userEvent.clear(getByLabelText('Enter a name for this rule'));
await userEvent.type(getByLabelText('Enter a name for this rule'), 'Test IP Filter 2');
await userEvent.clear(getByLabelText('Enter IP Range'));
await userEvent.type(getByLabelText('Enter IP Range'), '10.0.0.0/8');
await userEvent.click(getByTestId('save-add-edit-button'));
await waitFor(() => {
expect(onSave).toHaveBeenCalledWith({
@@ -96,9 +97,11 @@ describe('IPFilteringAddOrEditModal', () => {
/>,
);
fireEvent.change(getByLabelText('Enter a name for this rule'), {target: {value: 'Test IP Filter 2'}});
fireEvent.change(getByLabelText('Enter IP Range'), {target: {value: '10.0.0.0/8'}});
fireEvent.click(getByTestId('save-add-edit-button'));
await userEvent.clear(getByLabelText('Enter a name for this rule'));
await userEvent.type(getByLabelText('Enter a name for this rule'), 'Test IP Filter 2');
await userEvent.clear(getByLabelText('Enter IP Range'));
await userEvent.type(getByLabelText('Enter IP Range'), '10.0.0.0/8');
await userEvent.click(getByTestId('save-add-edit-button'));
await waitFor(() => {
expect(onSave).toHaveBeenCalledWith({
@@ -118,9 +121,12 @@ describe('IPFilteringAddOrEditModal', () => {
/>,
);
fireEvent.change(getByLabelText('Enter IP Range'), {target: {value: 'invalid-cidr'}});
await userEvent.clear(getByLabelText('Enter IP Range'));
await userEvent.type(getByLabelText('Enter IP Range'), 'invalid-cidr');
// Trigger validation on blur - fireEvent used because userEvent doesn't have direct focus/blur methods
fireEvent.blur(getByLabelText('Enter IP Range'));
fireEvent.click(getByTestId('save-add-edit-button'));
await userEvent.click(getByTestId('save-add-edit-button'));
await waitFor(() => {
expect(getByText('Invalid CIDR address range')).toBeInTheDocument();
@@ -129,14 +135,16 @@ describe('IPFilteringAddOrEditModal', () => {
});
});
test('disables the Save button when an invalid CIDR is entered', () => {
test('disables the Save button when an invalid CIDR is entered', async () => {
const {getByLabelText, getByTestId} = renderWithContext(
<IPFilteringAddOrEditModal
{...baseProps}
/>,
);
fireEvent.change(getByLabelText('Enter IP Range'), {target: {value: 'invalid-cidr'}});
await userEvent.clear(getByLabelText('Enter IP Range'));
await userEvent.type(getByLabelText('Enter IP Range'), 'invalid-cidr');
fireEvent.blur(getByLabelText('Enter IP Range'));
expect(getByTestId('save-add-edit-button')).toBeDisabled();
@@ -1,9 +1,10 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {render, fireEvent, waitFor} from '@testing-library/react';
import React from 'react';
import {render, userEvent, waitFor} from 'tests/react_testing_utils';
import DeleteConfirmationModal from './delete_confirmation';
describe('DeleteConfirmationModal', () => {
@@ -41,14 +42,14 @@ describe('DeleteConfirmationModal', () => {
expect(getByText('Test IP Filter')).toBeInTheDocument();
});
test('calls the onClose function when the Cancel button is clicked', () => {
test('calls the onClose function when the Cancel button is clicked', async () => {
const {getByText} = render(
<DeleteConfirmationModal
{...baseProps}
/>,
);
fireEvent.click(getByText('Cancel'));
await userEvent.click(getByText('Cancel'));
expect(onExited).toHaveBeenCalled();
expect(onConfirm).not.toHaveBeenCalled();
@@ -61,7 +62,7 @@ describe('DeleteConfirmationModal', () => {
/>,
);
fireEvent.click(getByText('Delete filter'));
await userEvent.click(getByText('Delete filter'));
await waitFor(() => {
expect(onConfirm).toHaveBeenCalledWith(filterToDelete);
@@ -1,12 +1,11 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {screen, fireEvent} from '@testing-library/react';
import React from 'react';
import type {AllowedIPRange} from '@mattermost/types/config';
import {renderWithContext} from 'tests/react_testing_utils';
import {renderWithContext, screen, userEvent} from 'tests/react_testing_utils';
import EditSection from './';
@@ -49,28 +48,28 @@ describe('EditSection', () => {
expect(screen.getByText('192.168.0.0/24')).toBeInTheDocument();
});
test('clicking the Add Filter button calls setShowAddModal', () => {
test('clicking the Add Filter button calls setShowAddModal', async () => {
renderWithContext(
<EditSection
{...baseProps}
/>,
);
fireEvent.click(screen.getByText('Add Filter'));
await userEvent.click(screen.getByText('Add Filter'));
expect(setShowAddModal).toHaveBeenCalledTimes(1);
expect(setShowAddModal).toHaveBeenCalledWith(true);
});
test('clicking the Edit button calls setEditFilter', () => {
test('clicking the Edit button calls setEditFilter', async () => {
renderWithContext(
<EditSection
{...baseProps}
/>,
);
fireEvent.mouseEnter(screen.getByText('Test Filter'));
fireEvent.click(screen.getByRole('button', {
await userEvent.hover(screen.getByText('Test Filter'));
await userEvent.click(screen.getByRole('button', {
name: /Edit/i,
}));
@@ -78,15 +77,15 @@ describe('EditSection', () => {
expect(setEditFilter).toHaveBeenCalledWith(ipFilters[0]);
});
test('clicking the Delete button calls handleConfirmDeleteFilter', () => {
test('clicking the Delete button calls handleConfirmDeleteFilter', async () => {
renderWithContext(
<EditSection
{...baseProps}
/>,
);
fireEvent.mouseEnter(screen.getByText('Test Filter'));
fireEvent.click(screen.getByRole('button', {
await userEvent.hover(screen.getByText('Test Filter'));
await userEvent.click(screen.getByRole('button', {
name: /Delete/i,
}));
@@ -1,10 +1,9 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {screen, fireEvent} from '@testing-library/react';
import React from 'react';
import {renderWithContext} from 'tests/react_testing_utils';
import {renderWithContext, screen, userEvent} from 'tests/react_testing_utils';
import EnableSectionContent from './enable_section';
jest.mock('components/external_link', () => {
@@ -35,14 +34,14 @@ describe('EnableSectionContent', () => {
expect(screen.getByRole('button', {pressed: true})).toBeInTheDocument();
});
test('clicking the toggle calls setFilterToggle', () => {
test('clicking the toggle calls setFilterToggle', async () => {
renderWithContext(
<EnableSectionContent
{...baseProps}
/>,
);
fireEvent.click(screen.getByTestId('filterToggle-button'));
await userEvent.click(screen.getByTestId('filterToggle-button'));
expect(setFilterToggle).toHaveBeenCalledTimes(1);
expect(setFilterToggle).toHaveBeenCalledWith(false);
@@ -1,7 +1,6 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {render, fireEvent, waitFor, screen} from '@testing-library/react';
import React from 'react';
import {IntlProvider} from 'react-intl';
import {Provider} from 'react-redux';
@@ -16,6 +15,8 @@ import configureStore from 'store';
import ModalController from 'components/modal_controller';
import {fireEvent, render, screen, userEvent, waitFor} from 'tests/react_testing_utils';
import IPFiltering from './index';
jest.mock('mattermost-redux/client');
@@ -99,7 +100,7 @@ describe('IPFiltering', () => {
expect(screen.getByRole('button', {pressed: true})).toBeInTheDocument();
});
fireEvent.click(screen.getByTestId('filterToggle-button'));
await userEvent.click(screen.getByTestId('filterToggle-button'));
await waitFor(() => {
expect(screen.getByRole('button', {pressed: false})).toBeInTheDocument();
@@ -113,15 +114,17 @@ describe('IPFiltering', () => {
expect(getByText('Add Filter')).toBeInTheDocument();
});
fireEvent.click(getByText('Add Filter'));
await userEvent.click(getByText('Add Filter'));
const descriptionInput = getByLabelText('Enter a name for this rule');
const cidrInput = getByLabelText('Enter IP Range');
const saveButton = screen.getByTestId('save-add-edit-button');
fireEvent.change(cidrInput, {target: {value: '192.168.0.0/16'}});
fireEvent.change(descriptionInput, {target: {value: 'Test IP Filter 2'}});
fireEvent.click(saveButton);
await userEvent.clear(cidrInput);
await userEvent.type(cidrInput, '192.168.0.0/16');
await userEvent.clear(descriptionInput);
await userEvent.type(descriptionInput, 'Test IP Filter 2');
await userEvent.click(saveButton);
await waitFor(() => {
expect(getByText('Test IP Filter 2')).toBeInTheDocument();
@@ -136,8 +139,8 @@ describe('IPFiltering', () => {
expect(getByText('Test IP Filter')).toBeInTheDocument();
});
fireEvent.mouseEnter(screen.getByText('Test IP Filter'));
fireEvent.click(screen.getByRole('button', {
await userEvent.hover(screen.getByText('Test IP Filter'));
await userEvent.click(screen.getByRole('button', {
name: /Edit/i,
}));
@@ -145,9 +148,11 @@ describe('IPFiltering', () => {
const cidrInput = getByLabelText('Enter IP Range');
const saveButton = screen.getByTestId('save-add-edit-button');
fireEvent.change(cidrInput, {target: {value: '192.168.0.0/16'}});
fireEvent.change(descriptionInput, {target: {value: 'zzzzzfilter'}});
fireEvent.click(saveButton);
await userEvent.clear(cidrInput);
await userEvent.type(cidrInput, '192.168.0.0/16');
await userEvent.clear(descriptionInput);
await userEvent.type(descriptionInput, 'zzzzzfilter');
await userEvent.click(saveButton);
await waitFor(() => {
expect(getByText('zzzzzfilter')).toBeInTheDocument();
@@ -165,14 +170,14 @@ describe('IPFiltering', () => {
expect(getByText('Test IP Filter')).toBeInTheDocument();
});
fireEvent.mouseEnter(screen.getByText('Test IP Filter'));
fireEvent.click(screen.getByRole('button', {
await userEvent.hover(screen.getByText('Test IP Filter'));
await userEvent.click(screen.getByRole('button', {
name: /Delete/i,
}));
const confirmButton = getByText('Delete filter');
fireEvent.click(confirmButton);
await userEvent.click(confirmButton);
await waitFor(() => {
expect(queryByText('Test IP Filter')).not.toBeInTheDocument();
@@ -187,7 +192,7 @@ describe('IPFiltering', () => {
expect(screen.getByRole('button', {pressed: true})).toBeInTheDocument();
});
fireEvent.click(screen.getByTestId('filterToggle-button'));
await userEvent.click(screen.getByTestId('filterToggle-button'));
await waitFor(() => {
expect(screen.getByRole('button', {pressed: false})).toBeInTheDocument();
@@ -197,8 +202,8 @@ describe('IPFiltering', () => {
expect(queryByText('Test IP Filter')).not.toBeInTheDocument();
});
fireEvent.click(getByText('Save'));
fireEvent.click(screen.getByTestId('save-confirmation-button'));
await userEvent.click(getByText('Save'));
await userEvent.click(screen.getByTestId('save-confirmation-button'));
await waitFor(() => {
expect(applyIPFiltersMock).toHaveBeenCalledTimes(1);
@@ -212,8 +217,8 @@ describe('IPFiltering', () => {
expect(getByText('Test IP Filter')).toBeInTheDocument();
});
fireEvent.mouseEnter(screen.getByText('Test IP Filter'));
fireEvent.click(screen.getByRole('button', {
await userEvent.hover(screen.getByText('Test IP Filter'));
await userEvent.click(screen.getByRole('button', {
name: /Edit/i,
}));
@@ -221,9 +226,11 @@ describe('IPFiltering', () => {
const cidrInput = getByLabelText('Enter IP Range');
const saveButton = screen.getByTestId('save-add-edit-button');
fireEvent.change(cidrInput, {target: {value: '192.168.0.0/16'}});
fireEvent.change(descriptionInput, {target: {value: 'zzzzzfilter'}});
fireEvent.click(saveButton);
await userEvent.clear(cidrInput);
await userEvent.type(cidrInput, '192.168.0.0/16');
await userEvent.clear(descriptionInput);
await userEvent.type(descriptionInput, 'zzzzzfilter');
await userEvent.click(saveButton);
await waitFor(() => {
expect(getByText('zzzzzfilter')).toBeInTheDocument();
@@ -247,6 +254,7 @@ describe('IPFiltering', () => {
expect(screen.getByRole('button', {pressed: true})).toBeInTheDocument();
});
// Use fireEvent.click here because userEvent doesn't work well with fake timers
fireEvent.click(screen.getByTestId('filterToggle-button'));
await waitFor(() => {
@@ -1,10 +1,9 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {fireEvent} from '@testing-library/react';
import React from 'react';
import {renderWithContext} from 'tests/react_testing_utils';
import {renderWithContext, userEvent} from 'tests/react_testing_utils';
import SaveConfirmationModal from './save_confirmation_modal';
@@ -51,26 +50,26 @@ describe('SaveConfirmationModal', () => {
expect(getByText('Using the Customer Portal to restore access')).toBeInTheDocument();
});
test('calls onClose when the cancel button is clicked', () => {
test('calls onClose when the cancel button is clicked', async () => {
const {getByText} = renderWithContext(
<SaveConfirmationModal
{...baseProps}
/>,
);
fireEvent.click(getByText('Cancel'));
await userEvent.click(getByText('Cancel'));
expect(onExitedMock).toHaveBeenCalledTimes(1);
});
test('calls onConfirm when the confirm button is clicked', () => {
test('calls onConfirm when the confirm button is clicked', async () => {
const {getByText} = renderWithContext(
<SaveConfirmationModal
{...baseProps}
/>,
);
fireEvent.click(getByText(buttonText));
await userEvent.click(getByText(buttonText));
expect(onConfirmMock).toHaveBeenCalledTimes(1);
});
@@ -54,10 +54,6 @@ const actImmediate = (wrapper: ReactWrapper) =>
);
describe('components/RenewalLicenseCard', () => {
afterEach(() => {
jest.clearAllMocks();
});
const props = {
license: {
id: 'license_id',
@@ -34,10 +34,6 @@ describe('components/admin_console/permission_schemes_settings/guest_permissions
},
};
beforeEach(() => {
jest.clearAllMocks();
});
test('should render guest permissions tree with headers', () => {
const {container} = renderWithContext(<GuestPermissionsTree {...defaultProps}/>);
@@ -26,10 +26,6 @@ describe('components/admin_console/reset_email_modal/reset_email_modal.tsx', ()
onExited: jest.fn(),
};
beforeEach(() => {
jest.clearAllMocks();
});
test('should render modal with user name in title', () => {
renderWithContext(<ResetEmailModal {...baseProps}/>);
@@ -49,10 +49,6 @@ describe('components/admin_console/reset_password_modal/reset_password_modal.tsx
},
};
beforeEach(() => {
jest.clearAllMocks();
});
test('should render modal with user name in title', () => {
renderWithContext(<ResetPasswordModal {...baseProps}/>);
@@ -1,14 +1,13 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import userEvent from '@testing-library/user-event';
import React from 'react';
import type {CloudState} from '@mattermost/types/cloud';
import type {AdminConfig, EnvironmentConfig} from '@mattermost/types/config';
import {defaultIntl} from 'tests/helpers/intl-test-helper';
import {renderWithContext, screen, waitFor} from 'tests/react_testing_utils';
import {renderWithContext, screen, userEvent, waitFor} from 'tests/react_testing_utils';
import SchemaAdminSettings, {SchemaAdminSettings as SchemaAdminSettingsClass} from './schema_admin_settings';
import type {ConsoleAccess, AdminDefinitionSubSectionSchema, AdminDefinitionSettingInput} from './types';
@@ -1,14 +1,13 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {screen, fireEvent} from '@testing-library/react';
import React from 'react';
import type {UserPropertyField} from '@mattermost/types/properties';
import {openModal} from 'actions/views/modals';
import {renderWithContext, renderHookWithContext} from 'tests/react_testing_utils';
import {renderHookWithContext, renderWithContext, screen, userEvent} from 'tests/react_testing_utils';
import {ModalIdentifiers} from 'utils/constants';
import RemoveUserPropertyFieldModal, {useUserPropertyFieldDelete} from './user_properties_delete_modal';
@@ -22,10 +21,6 @@ describe('RemoveUserPropertyFieldModal', () => {
const onCancel = jest.fn();
const onExited = jest.fn();
beforeEach(() => {
jest.clearAllMocks();
});
it('renders with the correct field name', () => {
renderWithContext(
<RemoveUserPropertyFieldModal
@@ -41,7 +36,7 @@ describe('RemoveUserPropertyFieldModal', () => {
expect(screen.getByText('Delete')).toBeInTheDocument();
});
it('calls onConfirm when confirm button is clicked', () => {
it('calls onConfirm when confirm button is clicked', async () => {
renderWithContext(
<RemoveUserPropertyFieldModal
name='Test Field'
@@ -51,11 +46,11 @@ describe('RemoveUserPropertyFieldModal', () => {
/>,
);
fireEvent.click(screen.getByText('Delete'));
await userEvent.click(screen.getByText('Delete'));
expect(onConfirm).toHaveBeenCalledTimes(1);
});
it('calls onCancel when cancel button is clicked', () => {
it('calls onCancel when cancel button is clicked', async () => {
renderWithContext(
<RemoveUserPropertyFieldModal
name='Test Field'
@@ -65,7 +60,7 @@ describe('RemoveUserPropertyFieldModal', () => {
/>,
);
fireEvent.click(screen.getByText('Cancel'));
await userEvent.click(screen.getByText('Cancel'));
expect(onCancel).toHaveBeenCalledTimes(1);
});
});
@@ -1,15 +1,14 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {fireEvent, screen, waitFor} from '@testing-library/react';
import React from 'react';
import type {ComponentProps} from 'react';
import React from 'react';
import type {UserPropertyField} from '@mattermost/types/properties';
import ModalController from 'components/modal_controller';
import {renderWithContext} from 'tests/react_testing_utils';
import {renderWithContext, screen, userEvent, waitFor} from 'tests/react_testing_utils';
import DotMenu from './user_properties_dot_menu';
@@ -33,10 +32,6 @@ describe('UserPropertyDotMenu', () => {
const deleteField = jest.fn();
const createField = jest.fn();
beforeEach(() => {
jest.clearAllMocks();
});
const renderComponent = (field: UserPropertyField = baseField, dotMenuProps?: Partial<ComponentProps<typeof DotMenu>>) => {
return renderWithContext(
(
@@ -79,7 +74,7 @@ describe('UserPropertyDotMenu', () => {
// Open the menu
const menuButton = screen.getByTestId(`user-property-field_dotmenu-${baseField.id}`);
fireEvent.click(menuButton);
await userEvent.click(menuButton);
// Verify the current visibility option is shown
expect(screen.getByText('Hide when empty')).toBeInTheDocument();
@@ -90,15 +85,15 @@ describe('UserPropertyDotMenu', () => {
// Open the menu
const menuButton = screen.getByTestId(`user-property-field_dotmenu-${baseField.id}`);
fireEvent.click(menuButton);
await userEvent.click(menuButton);
// Open the visibility submenu
const visibilityMenuItem = screen.getByRole('menuitem', {name: /Visibility/});
fireEvent.mouseOver(visibilityMenuItem);
await userEvent.hover(visibilityMenuItem);
// Click "Always show" option
const alwaysShowOption = screen.getByRole('menuitemradio', {name: /Always show/});
fireEvent.click(alwaysShowOption);
await userEvent.click(alwaysShowOption);
// Verify the field was updated with the new visibility
expect(updateField).toHaveBeenCalledWith({
@@ -115,7 +110,7 @@ describe('UserPropertyDotMenu', () => {
// Open the menu
const menuButton = screen.getByTestId(`user-property-field_dotmenu-${baseField.id}`);
fireEvent.click(menuButton);
await userEvent.click(menuButton);
// Verify both link options are shown
expect(screen.getByText('Link attribute to AD/LDAP')).toBeInTheDocument();
@@ -132,7 +127,7 @@ describe('UserPropertyDotMenu', () => {
// Open the menu
const menuButton = screen.getByTestId(`user-property-field_dotmenu-${pendingField.id}`);
fireEvent.click(menuButton);
await userEvent.click(menuButton);
// Verify both link options are not shown
expect(screen.queryByText('Link attribute to AD/LDAP')).not.toBeInTheDocument();
@@ -152,7 +147,7 @@ describe('UserPropertyDotMenu', () => {
// Open the menu
const menuButton = screen.getByTestId(`user-property-field_dotmenu-${linkedField.id}`);
fireEvent.click(menuButton);
await userEvent.click(menuButton);
// Verify the LDAP link text shows the edit option
expect(screen.getByText('Edit LDAP link')).toBeInTheDocument();
@@ -171,7 +166,7 @@ describe('UserPropertyDotMenu', () => {
// Open the menu
const menuButton = screen.getByTestId(`user-property-field_dotmenu-${linkedField.id}`);
fireEvent.click(menuButton);
await userEvent.click(menuButton);
// Verify the SAML link text shows the edit option
expect(screen.getByText('Edit SAML link')).toBeInTheDocument();
@@ -182,10 +177,10 @@ describe('UserPropertyDotMenu', () => {
// Open the menu
const menuButton = screen.getByTestId(`user-property-field_dotmenu-${baseField.id}`);
fireEvent.click(menuButton);
await userEvent.click(menuButton);
// Click the duplicate option
fireEvent.click(screen.getByText(/Duplicate attribute/));
await userEvent.click(screen.getByText(/Duplicate attribute/));
// Wait for createField to be called
await waitFor(() => {
@@ -202,7 +197,7 @@ describe('UserPropertyDotMenu', () => {
// Open the menu
const menuButton = screen.getByTestId(`user-property-field_dotmenu-${baseField.id}`);
fireEvent.click(menuButton);
await userEvent.click(menuButton);
// Verify duplicate option is not shown
expect(screen.queryByText(/Duplicate attribute/)).not.toBeInTheDocument();
@@ -213,11 +208,11 @@ describe('UserPropertyDotMenu', () => {
// Open the menu
const menuButton = screen.getByTestId(`user-property-field_dotmenu-${baseField.id}`);
fireEvent.click(menuButton);
await userEvent.click(menuButton);
// Click delete option
const deleteOption = screen.getByRole('menuitem', {name: /Delete attribute/});
fireEvent.click(deleteOption);
await userEvent.click(deleteOption);
await waitFor(() => {
// Verify the delete modal is shown
@@ -226,7 +221,7 @@ describe('UserPropertyDotMenu', () => {
// click delete confirm button
const deleteConfirmButton = screen.getByRole('button', {name: /Delete/});
fireEvent.click(deleteConfirmButton);
await userEvent.click(deleteConfirmButton);
await waitFor(() => {
// Verify deleteField was called
@@ -245,11 +240,11 @@ describe('UserPropertyDotMenu', () => {
// Open the menu
const menuButton = screen.getByTestId(`user-property-field_dotmenu-${pendingField.id}`);
fireEvent.click(menuButton);
await userEvent.click(menuButton);
// Click delete option
const deleteOption = screen.getByRole('menuitem', {name: /Delete attribute/});
fireEvent.click(deleteOption);
await userEvent.click(deleteOption);
await waitFor(() => {
// Verify deleteField was called
@@ -1,13 +1,12 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {fireEvent, screen, waitFor} from '@testing-library/react';
import React from 'react';
import type {UserPropertyField} from '@mattermost/types/properties';
import {collectionFromArray} from '@mattermost/types/utilities';
import {renderWithContext} from 'tests/react_testing_utils';
import {fireEvent, renderWithContext, screen, userEvent, waitFor} from 'tests/react_testing_utils';
import {UserPropertiesTable} from './user_properties_table';
@@ -58,10 +57,6 @@ describe('UserPropertiesTable', () => {
const deleteField = jest.fn();
const reorderField = jest.fn();
beforeEach(() => {
jest.clearAllMocks();
});
const renderComponent = (fields = baseFields) => {
const collection = collectionFromArray(fields);
@@ -93,11 +88,14 @@ describe('UserPropertiesTable', () => {
expect(screen.getByText('Select')).toBeInTheDocument();
});
it('allows editing field names', () => {
it('allows editing field names', async () => {
renderComponent();
const field1Input = screen.getByDisplayValue('Field 1');
fireEvent.change(field1Input, {target: {value: 'Edited Field 1'}});
await userEvent.clear(field1Input);
await userEvent.type(field1Input, 'Edited Field 1');
// Trigger blur to save the edited field name - fireEvent used because userEvent doesn't have direct focus/blur methods
fireEvent.blur(field1Input);
expect(updateField).toHaveBeenCalledWith({
@@ -1,12 +1,11 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {fireEvent, screen} from '@testing-library/react';
import React from 'react';
import type {UserPropertyField} from '@mattermost/types/properties';
import {renderWithContext} from 'tests/react_testing_utils';
import {renderWithContext, screen, userEvent} from 'tests/react_testing_utils';
import SelectType from './user_properties_type_menu';
@@ -37,10 +36,6 @@ describe('UserPropertyTypeMenu', () => {
);
};
beforeEach(() => {
jest.clearAllMocks();
});
it('renders with correct current type', () => {
renderComponent();
@@ -76,14 +71,14 @@ describe('UserPropertyTypeMenu', () => {
expect(menuButton).toBeDisabled();
});
it('changes field type when a new type is selected', () => {
it('changes field type when a new type is selected', async () => {
renderComponent();
// Open the menu
fireEvent.click(screen.getByText('Text'));
await userEvent.click(screen.getByText('Text'));
// Click to select Phone type
fireEvent.click(screen.getByText('Phone'));
await userEvent.click(screen.getByText('Phone'));
// Verify the field was updated with the new type
expect(updateField).toHaveBeenCalledWith({
@@ -96,26 +91,27 @@ describe('UserPropertyTypeMenu', () => {
});
});
it('filters options when searching', () => {
it('filters options when searching', async () => {
renderComponent();
// Open the menu
fireEvent.click(screen.getByText('Text'));
await userEvent.click(screen.getByText('Text'));
// Type in the filter input
const filterInput = screen.getByRole('textbox', {name: 'Attribute type'});
fireEvent.change(filterInput, {target: {value: 'multi'}});
await userEvent.clear(filterInput);
await userEvent.type(filterInput, 'multi');
// Should only see Multi-select now
expect(screen.getByText('Multi-select')).toBeInTheDocument();
expect(screen.getAllByRole('menuitemradio')).toHaveLength(1);
});
it('disables non-supported options when ldap-linked', () => {
it('disables non-supported options when ldap-linked', async () => {
renderComponent({...baseField, attrs: {...baseField.attrs, ldap: 'ldapPropName'}});
// Open the menu
fireEvent.click(screen.getByText('Text'));
await userEvent.click(screen.getByText('Text'));
// Non-text should be disabled
expect(screen.getByRole('menuitemradio', {name: 'Phone'})).toHaveAttribute('aria-disabled', 'true');
@@ -125,11 +121,11 @@ describe('UserPropertyTypeMenu', () => {
expect(screen.getByRole('menuitemradio', {name: 'Select'})).toHaveAttribute('aria-disabled', 'true');
});
it('disables non-supported options when saml-linked', () => {
it('disables non-supported options when saml-linked', async () => {
renderComponent({...baseField, attrs: {...baseField.attrs, saml: 'samlPropName'}});
// Open the menu
fireEvent.click(screen.getByText('Text'));
await userEvent.click(screen.getByText('Text'));
// Non-text should be disabled
expect(screen.getByRole('menuitemradio', {name: 'Phone'})).toHaveAttribute('aria-disabled', 'true');
@@ -139,7 +135,7 @@ describe('UserPropertyTypeMenu', () => {
expect(screen.getByRole('menuitemradio', {name: 'Select'})).toHaveAttribute('aria-disabled', 'true');
});
it('shows check icon for current type', () => {
it('shows check icon for current type', async () => {
const selectField = {
...baseField,
type: 'select' as const,
@@ -152,7 +148,7 @@ describe('UserPropertyTypeMenu', () => {
renderComponent(selectField);
// Open the menu
fireEvent.click(screen.getByText('Select'));
await userEvent.click(screen.getByText('Select'));
// All options should be visible, but Select should have a check
expect(screen.getByRole('menuitemradio', {name: 'Select'})).toHaveAttribute('aria-checked', 'true');
@@ -1,12 +1,11 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {screen, fireEvent} from '@testing-library/react';
import React from 'react';
import type {UserPropertyField} from '@mattermost/types/properties';
import {renderWithContext} from 'tests/react_testing_utils';
import {fireEvent, renderWithContext, screen, userEvent} from 'tests/react_testing_utils';
import UserPropertyValues from './user_properties_values';
@@ -42,10 +41,6 @@ describe('UserPropertyValues', () => {
);
};
beforeEach(() => {
jest.clearAllMocks();
});
it('renders correctly for select/multiselect field types', () => {
renderComponent();
@@ -69,8 +64,9 @@ describe('UserPropertyValues', () => {
renderComponent();
const input = screen.getByRole('combobox');
fireEvent.change(input, {target: {value: 'New Option'}});
fireEvent.keyDown(input, {key: 'Enter'});
await userEvent.clear(input);
await userEvent.type(input, 'New Option');
await userEvent.keyboard('{Enter}');
expect(updateField).toHaveBeenCalledWith({
...baseField,
@@ -88,7 +84,10 @@ describe('UserPropertyValues', () => {
renderComponent();
const input = screen.getByRole('combobox');
fireEvent.change(input, {target: {value: 'New Option'}});
await userEvent.clear(input);
await userEvent.type(input, 'New Option');
// Trigger blur to save the new option value - fireEvent used because userEvent doesn't have direct focus/blur methods
fireEvent.blur(input);
expect(updateField).toHaveBeenCalledWith({
@@ -108,7 +107,7 @@ describe('UserPropertyValues', () => {
// Find and click the first remove button (x)
const removeButtons = screen.getAllByRole('button');
fireEvent.click(removeButtons[0]);
await userEvent.click(removeButtons[0]);
expect(updateField).toHaveBeenCalledWith({
...baseField,
@@ -123,13 +122,14 @@ describe('UserPropertyValues', () => {
renderComponent();
const input = screen.getByRole('combobox');
fireEvent.change(input, {target: {value: 'Option 1'}}); // This already exists
await userEvent.clear(input);
await userEvent.type(input, 'Option 1'); // This already exists
// Error message should appear
expect(screen.getByText('Values must be unique.')).toBeInTheDocument();
// Pressing Enter shouldn't add the duplicate
fireEvent.keyDown(input, {key: 'Enter'});
await userEvent.keyboard('{Enter}');
expect(updateField).not.toHaveBeenCalled();
});
@@ -117,10 +117,6 @@ describe('ChannelLevelAccessRules', () => {
isDisabled: false,
};
beforeEach(() => {
jest.clearAllMocks();
});
it('should render the component with correct title and subtitle', () => {
renderWithContext(<ChannelLevelAccessRules {...defaultProps}/>);
@@ -1,12 +1,11 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import userEvent from '@testing-library/user-event';
import React from 'react';
import {PAGE_SIZE} from 'components/admin_console/team_channel_settings/abstract_list';
import {renderWithContext, screen, waitFor} from 'tests/react_testing_utils';
import {renderWithContext, screen, userEvent, waitFor} from 'tests/react_testing_utils';
import {TestHelper} from 'utils/test_helper';
import TeamList from './team_list';
@@ -5,7 +5,7 @@ import React from 'react';
import type {Agent} from '@mattermost/types/agents';
import {renderWithContext, screen, fireEvent} from 'tests/react_testing_utils';
import {renderWithContext, screen, userEvent} from 'tests/react_testing_utils';
import {RewriteAction} from './rewrite_action';
import type {RewriteMenuProps} from './rewrite_menu';
@@ -115,10 +115,6 @@ describe('RewriteMenu', () => {
customPromptRef: React.createRef<HTMLInputElement>(),
};
beforeEach(() => {
jest.clearAllMocks();
});
test('should not render agent dropdown when no agents', () => {
renderWithContext(
<RewriteMenu
@@ -176,7 +172,7 @@ describe('RewriteMenu', () => {
expect(screen.getByText('Stop generating')).toBeInTheDocument();
});
test('should call onCancelProcessing when stop generating button is clicked', () => {
test('should call onCancelProcessing when stop generating button is clicked', async () => {
const onCancelProcessing = jest.fn();
renderWithContext(
<RewriteMenu
@@ -185,7 +181,7 @@ describe('RewriteMenu', () => {
onCancelProcessing={onCancelProcessing}
/>,
);
fireEvent.click(screen.getByText('Stop generating'));
await userEvent.click(screen.getByText('Stop generating'));
expect(onCancelProcessing).toHaveBeenCalled();
});
@@ -217,7 +213,7 @@ describe('RewriteMenu', () => {
expect(screen.queryByTestId('menu-footer')).not.toBeInTheDocument();
});
test('should call onUndoMessage when discard button is clicked', () => {
test('should call onUndoMessage when discard button is clicked', async () => {
const onUndoMessage = jest.fn();
renderWithContext(
<RewriteMenu
@@ -228,11 +224,11 @@ describe('RewriteMenu', () => {
onUndoMessage={onUndoMessage}
/>,
);
fireEvent.click(screen.getByText('Discard'));
await userEvent.click(screen.getByText('Discard'));
expect(onUndoMessage).toHaveBeenCalled();
});
test('should call onRegenerateMessage when regenerate button is clicked', () => {
test('should call onRegenerateMessage when regenerate button is clicked', async () => {
const onRegenerateMessage = jest.fn();
renderWithContext(
<RewriteMenu
@@ -243,11 +239,11 @@ describe('RewriteMenu', () => {
onRegenerateMessage={onRegenerateMessage}
/>,
);
fireEvent.click(screen.getByText('Regenerate'));
await userEvent.click(screen.getByText('Regenerate'));
expect(onRegenerateMessage).toHaveBeenCalled();
});
test('should call onMenuAction when menu item is clicked', () => {
test('should call onMenuAction when menu item is clicked', async () => {
const onMenuAction = jest.fn(() => () => {});
renderWithContext(
<RewriteMenu
@@ -257,11 +253,11 @@ describe('RewriteMenu', () => {
/>,
);
const menuItems = screen.getAllByTestId('menu-item');
fireEvent.click(menuItems[0]);
await userEvent.click(menuItems[0]);
expect(onMenuAction).toHaveBeenCalled();
});
test('should call setPrompt when prompt input changes', () => {
test('should call setPrompt when prompt input changes', async () => {
const setPrompt = jest.fn();
renderWithContext(
<RewriteMenu
@@ -270,11 +266,12 @@ describe('RewriteMenu', () => {
/>,
);
const input = screen.getByTestId('prompt-input-field');
fireEvent.change(input, {target: {value: 'New prompt'}});
await userEvent.clear(input);
await userEvent.type(input, 'New prompt');
expect(setPrompt).toHaveBeenCalled();
});
test('should call onCustomPromptKeyDown when key is pressed in prompt input', () => {
test('should call onCustomPromptKeyDown when key is pressed in prompt input', async () => {
const onCustomPromptKeyDown = jest.fn();
renderWithContext(
<RewriteMenu
@@ -283,7 +280,8 @@ describe('RewriteMenu', () => {
/>,
);
const input = screen.getByTestId('prompt-input-field');
fireEvent.keyDown(input, {key: 'Enter'});
input.focus();
await userEvent.keyboard('{Enter}');
expect(onCustomPromptKeyDown).toHaveBeenCalled();
});
@@ -337,7 +335,7 @@ describe('RewriteMenu', () => {
expect(screen.queryByTestId('agent-dropdown')).not.toBeInTheDocument();
});
test('should call setSelectedAgentId when agent is selected', () => {
test('should call setSelectedAgentId when agent is selected', async () => {
const setSelectedAgentId = jest.fn();
renderWithContext(
<RewriteMenu
@@ -346,7 +344,7 @@ describe('RewriteMenu', () => {
/>,
);
const select = screen.getByTestId('agent-select');
fireEvent.change(select, {target: {value: 'agent2'}});
await userEvent.selectOptions(select, 'agent2');
expect(setSelectedAgentId).toHaveBeenCalledWith('agent2');
});
});
@@ -7,7 +7,7 @@ import React from 'react';
import useTimePostBoxIndicator from 'components/advanced_text_editor/use_post_box_indicator';
import {WithTestMenuContext} from 'components/menu/menu_context_test';
import {renderWithContext, fireEvent, screen} from 'tests/react_testing_utils';
import {fireEvent, renderWithContext, screen} from 'tests/react_testing_utils';
import CoreMenuOptions from './core_menu_options';
@@ -48,7 +48,6 @@ describe('CoreMenuOptions Component', () => {
const handleOnSelect = jest.fn();
beforeEach(() => {
jest.clearAllMocks();
handleOnSelect.mockReset();
mockedUseTimePostBoxIndicator.mockReturnValue({
...defaultUseTimePostBoxIndicatorReturnValue,
@@ -137,6 +136,8 @@ describe('CoreMenuOptions Component', () => {
renderComponent();
const tomorrowOption = screen.getByText(/Tomorrow at/);
// Use fireEvent.click here because userEvent doesn't work well with fake timers
fireEvent.click(tomorrowOption);
const expectedTimestamp = DateTime.now().
@@ -6,7 +6,7 @@ import React from 'react';
import {getPreferenceKey} from 'mattermost-redux/utils/preference_utils';
import {renderWithContext, fireEvent, screen} from 'tests/react_testing_utils';
import {fireEvent, renderWithContext, screen} from 'tests/react_testing_utils';
import {scheduledPosts} from 'utils/constants';
import RecentUsedCustomDate from './recent_used_custom_date';
@@ -51,7 +51,6 @@ describe('CoreMenuOptions Component', () => {
let nextMonday: number;
beforeEach(() => {
jest.clearAllMocks();
handleOnSelect.mockReset();
now = DateTime.fromISO('2024-11-01T10:00:00', {zone: userCurrentTimezone});
jest.useFakeTimers();
@@ -134,6 +133,8 @@ describe('CoreMenuOptions Component', () => {
renderComponent(state, handleOnSelectMock);
const recentCustomOption = screen.getByText(recentUsedCustomDateString);
// Use fireEvent.click here because userEvent doesn't work well with fake timers
fireEvent.click(recentCustomOption);
expect(handleOnSelectMock).toHaveBeenCalledWith(expect.anything(), recentTimestamp);
@@ -3,7 +3,7 @@
import React from 'react';
import {renderWithContext, fireEvent, screen} from 'tests/react_testing_utils';
import {renderWithContext, screen, userEvent} from 'tests/react_testing_utils';
import ShowFormatting from './show_formatting';
@@ -23,7 +23,7 @@ describe('ShowFormatting Component', () => {
expect(screen.getByLabelText('Eye Icon')).toBeInTheDocument();
});
it('should call onClick handler when clicked', () => {
it('should call onClick handler when clicked', async () => {
const onClick = jest.fn();
renderWithContext(
<ShowFormatting
@@ -32,7 +32,7 @@ describe('ShowFormatting Component', () => {
/>,
);
fireEvent.click(screen.getByLabelText('Eye Icon'));
await userEvent.click(screen.getByLabelText('Eye Icon'));
expect(onClick).toHaveBeenCalledTimes(1);
});
@@ -3,7 +3,7 @@
import React from 'react';
import {renderWithContext, fireEvent, screen} from 'tests/react_testing_utils';
import {fireEvent, renderWithContext, screen, userEvent} from 'tests/react_testing_utils';
import ToggleFormattingBar from './toggle_formatting_bar';
@@ -24,7 +24,7 @@ describe('ToggleFormattingBar Component', () => {
expect(screen.getAllByLabelText('Format letter Case Icon')[0]).toBeInTheDocument();
});
it('should call onClick handler when clicked', () => {
it('should call onClick handler when clicked', async () => {
const onClick = jest.fn();
renderWithContext(
<ToggleFormattingBar
@@ -34,7 +34,7 @@ describe('ToggleFormattingBar Component', () => {
/>,
);
fireEvent.click(screen.getByLabelText('formatting'));
await userEvent.click(screen.getByLabelText('formatting'));
expect(onClick).toHaveBeenCalledTimes(1);
});
@@ -48,6 +48,7 @@ describe('ToggleFormattingBar Component', () => {
/>,
);
// Use fireEvent.click to test disabled behavior (userEvent respects pointer-events: none)
fireEvent.click(screen.getByLabelText('formatting'));
expect(onClick).not.toHaveBeenCalled();
});
@@ -85,7 +85,6 @@ describe('useRewrite', () => {
};
beforeEach(() => {
jest.clearAllMocks();
MockedRewriteMenu.mockClear();
document.body.innerHTML = '';
try {
@@ -8,7 +8,7 @@ import type {DeepPartial} from '@mattermost/types/utilities';
import {savePreferences} from 'mattermost-redux/actions/preferences';
import {General} from 'mattermost-redux/constants';
import {fireEvent, renderWithContext, screen} from 'tests/react_testing_utils';
import {renderWithContext, screen, userEvent} from 'tests/react_testing_utils';
import {OverActiveUserLimits, Preferences, SelfHostedProducts, StatTypes} from 'utils/constants';
import {TestHelper} from 'utils/test_helper';
import {generateId} from 'utils/utils';
@@ -201,7 +201,7 @@ describe('components/overage_users_banner', () => {
expect(screen.getByText(contactSalesTextLink)).toBeInTheDocument();
});
it('should track if the admin click Contact Sales CTA in a 10% overage state', () => {
it('should track if the admin click Contact Sales CTA in a 10% overage state', async () => {
const store = JSON.parse(JSON.stringify(initialState));
store.entities.cloud = {
@@ -217,7 +217,7 @@ describe('components/overage_users_banner', () => {
renderWithContext(<OverageUsersBanner/>, store);
fireEvent.click(screen.getByText(contactSalesTextLink));
await userEvent.click(screen.getByText(contactSalesTextLink));
expect(windowSpy).toHaveBeenCalledTimes(1);
// only the email is encoded and other params are empty. See logic for useOpenSalesLink hook
@@ -255,7 +255,7 @@ describe('components/overage_users_banner', () => {
expect(screen.getByText(contactSalesTextLink)).toBeInTheDocument();
});
it('should save the preferences for 5% banner if admin click on close', () => {
it('should save the preferences for 5% banner if admin click on close', async () => {
const store = JSON.parse(JSON.stringify(initialState));
store.entities.admin = {
@@ -267,7 +267,7 @@ describe('components/overage_users_banner', () => {
renderWithContext(<OverageUsersBanner/>, store);
fireEvent.click(screen.getByRole('link'));
await userEvent.click(screen.getByRole('link'));
expect(savePreferences).toHaveBeenCalledTimes(1);
expect(savePreferences).toHaveBeenCalledWith(store.entities.users.profiles.current_user.id, [{
@@ -298,7 +298,7 @@ describe('components/overage_users_banner', () => {
expect(screen.getByText(contactSalesTextLink)).toBeInTheDocument();
});
it('should track if the admin click Contact Sales CTA in a 10% overage state', () => {
it('should track if the admin click Contact Sales CTA in a 10% overage state', async () => {
const store = JSON.parse(JSON.stringify(initialState));
store.entities.cloud = {
@@ -314,7 +314,7 @@ describe('components/overage_users_banner', () => {
renderWithContext(<OverageUsersBanner/>, store);
fireEvent.click(screen.getByText(contactSalesTextLink));
await userEvent.click(screen.getByText(contactSalesTextLink));
expect(windowSpy).toHaveBeenCalledTimes(1);
// only the email is encoded and other params are empty. See logic for useOpenSalesLink hook
@@ -8,7 +8,7 @@ import type {DeepPartial} from '@mattermost/types/utilities';
import {savePreferences} from 'mattermost-redux/actions/preferences';
import {General} from 'mattermost-redux/constants';
import {fireEvent, renderWithContext, screen} from 'tests/react_testing_utils';
import {renderWithContext, screen, userEvent} from 'tests/react_testing_utils';
import {Preferences} from 'utils/constants';
import {TestHelper} from 'utils/test_helper';
import {generateId} from 'utils/utils';
@@ -54,8 +54,6 @@ describe('components/announcement_bar/PostHistoryLimitBanner', () => {
let mockToLocaleDateString: jest.SpyInstance;
beforeEach(() => {
jest.clearAllMocks();
mockOpenPricingModal = jest.fn();
mockUseOpenPricingModal.mockReturnValue({openPricingModal: mockOpenPricingModal});
@@ -259,19 +257,19 @@ describe('components/announcement_bar/PostHistoryLimitBanner', () => {
describe('User Interactions', () => {
const preferenceName = 'post_history_limit_banner';
it('should call openPricingModal when upgrade button is clicked', () => {
it('should call openPricingModal when upgrade button is clicked', async () => {
setupServerLimits(true);
const state = createInitialState(true, []);
renderWithContext(<PostHistoryLimitBanner/>, state);
const upgradeButton = screen.getByText('Restore Access');
fireEvent.click(upgradeButton);
await userEvent.click(upgradeButton);
expect(mockOpenPricingModal).toHaveBeenCalled();
});
it('should save dismissal timestamp when close button is clicked', () => {
it('should save dismissal timestamp when close button is clicked', async () => {
setupServerLimits(true);
const state = createInitialState(true, []);
@@ -281,7 +279,7 @@ describe('components/announcement_bar/PostHistoryLimitBanner', () => {
renderWithContext(<PostHistoryLimitBanner/>, state);
const closeButton = screen.getByRole('link', {name: '×'});
fireEvent.click(closeButton);
await userEvent.click(closeButton);
expect(mockDispatch).toHaveBeenCalledWith(
mockSavePreferences(currentUserId, [{
@@ -54,10 +54,6 @@ const actImmediate = (wrapper: ReactWrapper) =>
);
describe('components/RenewalLink', () => {
afterEach(() => {
jest.clearAllMocks();
});
test('should show Contact sales button', async () => {
const store = mockStore(initialState);
const wrapper = mountWithIntl(<Provider store={store}><RenewalLink/></Provider>);
@@ -1,13 +1,11 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {screen, waitFor} from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import React from 'react';
import {AppCallResponseTypes} from 'mattermost-redux/constants/apps';
import {renderWithContext} from 'tests/react_testing_utils';
import {renderWithContext, screen, waitFor, userEvent} from 'tests/react_testing_utils';
import {AppsForm} from './apps_form_component';
import type {Props} from './apps_form_component';
@@ -71,10 +69,6 @@ describe('AppsFormComponent', () => {
},
};
afterEach(() => {
jest.clearAllMocks();
});
test('should render form with title, header, fields and initial values', () => {
renderWithContext(
<AppsForm
@@ -1,12 +1,11 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {screen, fireEvent} from '@testing-library/react';
import React from 'react';
import type {AppField} from '@mattermost/types/apps';
import {renderWithContext} from 'tests/react_testing_utils';
import {fireEvent, renderWithContext, screen} from 'tests/react_testing_utils';
import AppsFormDateField from './apps_form_date_field';
@@ -29,8 +28,6 @@ describe('AppsFormDateField', () => {
};
beforeEach(() => {
jest.clearAllMocks();
// Mock current time to avoid timezone-dependent tests
jest.useFakeTimers();
jest.setSystemTime(new Date('2025-01-15T10:00:00.000Z'));
@@ -90,6 +87,8 @@ describe('AppsFormDateField', () => {
it('should handle input click to open date picker', () => {
renderComponent();
const button = screen.getByRole('button');
// Use fireEvent.click here because userEvent doesn't work well with fake timers
fireEvent.click(button);
// DatePicker opening is handled by the DatePicker component itself
@@ -101,6 +100,7 @@ describe('AppsFormDateField', () => {
renderComponent();
const button = screen.getByRole('button');
// Simulate keyboard Enter key - fireEvent used because userEvent doesn't work well with fake timers
fireEvent.keyDown(button, {key: 'Enter'});
expect(button).toBeInTheDocument();
@@ -44,8 +44,6 @@ describe('AppsFormDateTimeField', () => {
};
beforeEach(() => {
jest.clearAllMocks();
// Mock current time to avoid timezone-dependent tests
jest.useFakeTimers();
jest.setSystemTime(new Date('2025-01-15T10:00:00.000Z'));
@@ -3,7 +3,7 @@
import React from 'react';
import {renderWithContext, fireEvent, screen} from 'tests/react_testing_utils';
import {renderWithContext, userEvent, screen} from 'tests/react_testing_utils';
import BurnOnReadButton from './burn_on_read_button';
@@ -19,10 +19,6 @@ describe('BurnOnReadButton', () => {
durationMinutes: 10,
};
beforeEach(() => {
jest.clearAllMocks();
});
it('should render correctly when disabled', () => {
renderWithContext(
<BurnOnReadButton {...defaultProps}/>,
@@ -46,7 +42,7 @@ describe('BurnOnReadButton', () => {
expect(button).toHaveClass('control');
});
it('should call onToggle with true when clicked while disabled', () => {
it('should call onToggle with true when clicked while disabled', async () => {
const onToggle = jest.fn();
renderWithContext(
<BurnOnReadButton
@@ -57,13 +53,13 @@ describe('BurnOnReadButton', () => {
);
const button = screen.getByRole('button');
fireEvent.click(button);
await userEvent.click(button);
expect(onToggle).toHaveBeenCalledTimes(1);
expect(onToggle).toHaveBeenCalledWith(true);
});
it('should call onToggle with false when clicked while enabled', () => {
it('should call onToggle with false when clicked while enabled', async () => {
const onToggle = jest.fn();
renderWithContext(
<BurnOnReadButton
@@ -74,7 +70,7 @@ describe('BurnOnReadButton', () => {
);
const button = screen.getByRole('button');
fireEvent.click(button);
await userEvent.click(button);
expect(onToggle).toHaveBeenCalledTimes(1);
expect(onToggle).toHaveBeenCalledWith(false);
@@ -3,7 +3,7 @@
import React from 'react';
import {renderWithContext, fireEvent, screen} from 'tests/react_testing_utils';
import {renderWithContext, userEvent, screen} from 'tests/react_testing_utils';
import BurnOnReadLabel from './burn_on_read_label';
@@ -14,10 +14,6 @@ describe('BurnOnReadLabel', () => {
durationMinutes: 10,
};
beforeEach(() => {
jest.clearAllMocks();
});
it('should render correctly with duration', () => {
renderWithContext(
<BurnOnReadLabel {...defaultProps}/>,
@@ -62,7 +58,7 @@ describe('BurnOnReadLabel', () => {
expect(closeButton).not.toBeInTheDocument();
});
it('should call onRemove when close button is clicked', () => {
it('should call onRemove when close button is clicked', async () => {
const onRemove = jest.fn();
renderWithContext(
<BurnOnReadLabel
@@ -72,7 +68,7 @@ describe('BurnOnReadLabel', () => {
);
const closeButton = screen.getByRole('button');
fireEvent.click(closeButton);
await userEvent.click(closeButton);
expect(onRemove).toHaveBeenCalledTimes(1);
});
@@ -1,10 +1,9 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {fireEvent} from '@testing-library/react';
import React from 'react';
import {renderWithContext, screen} from 'tests/react_testing_utils';
import {renderWithContext, screen, userEvent} from 'tests/react_testing_utils';
import BurnOnReadConfirmationModal from './burn_on_read_confirmation_modal';
@@ -15,10 +14,6 @@ describe('BurnOnReadConfirmationModal', () => {
onCancel: jest.fn(),
};
beforeEach(() => {
jest.clearAllMocks();
});
it('should render receiver delete message when show is true and isSenderDelete is false', () => {
renderWithContext(<BurnOnReadConfirmationModal {...baseProps}/>);
@@ -49,7 +44,7 @@ describe('BurnOnReadConfirmationModal', () => {
expect(screen.queryByText('Delete Message Now?')).not.toBeInTheDocument();
});
it('should call onCancel when Cancel button is clicked', () => {
it('should call onCancel when Cancel button is clicked', async () => {
const onCancel = jest.fn();
renderWithContext(
<BurnOnReadConfirmationModal
@@ -59,12 +54,12 @@ describe('BurnOnReadConfirmationModal', () => {
);
const cancelButton = screen.getByText('Cancel');
fireEvent.click(cancelButton);
await userEvent.click(cancelButton);
expect(onCancel).toHaveBeenCalledTimes(1);
});
it('should call onConfirm with false when Delete Now button is clicked without checkbox', () => {
it('should call onConfirm with false when Delete Now button is clicked without checkbox', async () => {
const onConfirm = jest.fn();
renderWithContext(
<BurnOnReadConfirmationModal
@@ -74,7 +69,7 @@ describe('BurnOnReadConfirmationModal', () => {
);
const confirmButton = screen.getByText('Delete Now');
fireEvent.click(confirmButton);
await userEvent.click(confirmButton);
expect(onConfirm).toHaveBeenCalledWith(false);
});
@@ -103,7 +98,7 @@ describe('BurnOnReadConfirmationModal', () => {
expect(screen.queryByRole('checkbox')).not.toBeInTheDocument();
});
it('should call onConfirm with true when checkbox is checked', () => {
it('should call onConfirm with true when checkbox is checked', async () => {
const onConfirm = jest.fn();
renderWithContext(
<BurnOnReadConfirmationModal
@@ -114,10 +109,10 @@ describe('BurnOnReadConfirmationModal', () => {
);
const checkbox = screen.getByRole('checkbox');
fireEvent.click(checkbox);
await userEvent.click(checkbox);
const confirmButton = screen.getByText('Delete Now');
fireEvent.click(confirmButton);
await userEvent.click(confirmButton);
expect(onConfirm).toHaveBeenCalledWith(true);
});
@@ -88,10 +88,6 @@ jest.mock('mattermost-redux/actions/shared_channels', () => ({
describe('components/channel_header/ChannelHeaderTitle', () => {
const mockStore = configureStore();
afterEach(() => {
jest.clearAllMocks();
});
test('should not fetch shared channels for non-shared channels', () => {
// Mock non-shared channel
const channel = {
@@ -1,7 +1,6 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {screen, fireEvent, act, waitFor} from '@testing-library/react';
import React from 'react';
import type {Channel} from '@mattermost/types/channels';
@@ -9,7 +8,7 @@ import type {Channel} from '@mattermost/types/channels';
import {favoriteChannel, unfavoriteChannel} from 'mattermost-redux/actions/channels';
import * as channelsSelectors from 'mattermost-redux/selectors/entities/channels';
import {renderWithContext} from 'tests/react_testing_utils';
import {act, fireEvent, renderWithContext, screen, userEvent, waitFor} from 'tests/react_testing_utils';
import type {A11yFocusEventDetail} from 'utils/constants';
import {A11yCustomEventTypes} from 'utils/constants';
@@ -47,8 +46,6 @@ describe('ChannelHeaderTitleFavorite Component', () => {
} as Channel;
beforeEach(() => {
jest.clearAllMocks();
// Spy on selectors
isCurrentChannelFavoriteMock = jest.spyOn(channelsSelectors, 'isCurrentChannelFavorite');
getCurrentChannelMock = jest.spyOn(channelsSelectors, 'getCurrentChannel');
@@ -66,7 +63,7 @@ describe('ChannelHeaderTitleFavorite Component', () => {
return renderWithContext(<ChannelHeaderTitleFavorite/>);
}
it('should dispatch favoriteChannel when "Add to Favorites" button is clicked', () => {
it('should dispatch favoriteChannel when "Add to Favorites" button is clicked', async () => {
isCurrentChannelFavoriteMock.mockReturnValue(false);
getCurrentChannelMock.mockReturnValue(activeChannel);
@@ -79,7 +76,7 @@ describe('ChannelHeaderTitleFavorite Component', () => {
renderComponent();
const button = screen.getByRole('button', {name: ADD_TO_FAVORITES_REGEX});
fireEvent.click(button);
await userEvent.click(button);
expect(dispatchMock).toHaveBeenCalledTimes(1);
expect(dispatchMock).toHaveBeenCalledWith({
@@ -88,7 +85,7 @@ describe('ChannelHeaderTitleFavorite Component', () => {
});
});
it('should dispatch unfavoriteChannel when "Remove from Favorites" button is clicked', () => {
it('should dispatch unfavoriteChannel when "Remove from Favorites" button is clicked', async () => {
isCurrentChannelFavoriteMock.mockReturnValue(true);
getCurrentChannelMock.mockReturnValue(activeChannel);
@@ -101,7 +98,7 @@ describe('ChannelHeaderTitleFavorite Component', () => {
renderComponent();
const button = screen.getByRole('button', {name: REMOVE_FROM_FAVORITES_REGEX});
fireEvent.click(button);
await userEvent.click(button);
expect(dispatchMock).toHaveBeenCalledTimes(1);
expect(dispatchMock).toHaveBeenCalledWith({
@@ -205,11 +202,11 @@ describe('ChannelHeaderTitleFavorite Component', () => {
const button = screen.getByRole('button', {name: ADD_TO_FAVORITES_REGEX});
// Ensure the ref is set by triggering a focus event
// Trigger focus to ensure the button ref is set before clicking - fireEvent used because userEvent doesn't have direct focus/blur methods
fireEvent.focus(button);
act(() => {
fireEvent.click(button);
await act(async () => {
await userEvent.click(button);
});
expect(dispatchMock).toHaveBeenCalledWith({
@@ -9,7 +9,7 @@ import * as modalActions from 'actions/views/modals';
import ChannelInviteModal from 'components/channel_invite_modal';
import {WithTestMenuContext} from 'components/menu/menu_context_test';
import {renderWithContext, screen, fireEvent} from 'tests/react_testing_utils';
import {renderWithContext, screen, userEvent} from 'tests/react_testing_utils';
import {ModalIdentifiers} from 'utils/constants';
import {TestHelper} from 'utils/test_helper';
@@ -40,7 +40,7 @@ describe('components/ChannelHeaderMenu/MenuItems/AddChannelMembers', () => {
expect(menuItem).toBeInTheDocument(); // Check if text "Add Members" renders
});
test('dispatches openModal action on click', () => {
test('dispatches openModal action on click', async () => {
renderWithContext(
<WithTestMenuContext>
<AddChannelMembers
@@ -51,7 +51,7 @@ describe('components/ChannelHeaderMenu/MenuItems/AddChannelMembers', () => {
const menuItem = screen.getByText('Add Members');
expect(menuItem).toBeInTheDocument(); // Check if text "Add Members" renders
fireEvent.click(menuItem); // Simulate click on the menu item
await userEvent.click(menuItem); // Simulate click on the menu item
expect(useDispatch).toHaveBeenCalledTimes(1); // Ensure dispatch was called
expect(modalActions.openModal).toHaveBeenCalledTimes(1);
@@ -9,7 +9,7 @@ import * as modalActions from 'actions/views/modals';
import {WithTestMenuContext} from 'components/menu/menu_context_test';
import MoreDirectChannels from 'components/more_direct_channels';
import {renderWithContext, screen, fireEvent} from 'tests/react_testing_utils';
import {renderWithContext, screen, userEvent} from 'tests/react_testing_utils';
import {ModalIdentifiers} from 'utils/constants';
import AddGroupMembers from './add_group_members';
@@ -35,7 +35,7 @@ describe('components/ChannelHeaderMenu/MenuItems/AddGroupMembers', () => {
expect(menuItem).toBeInTheDocument(); // Check if text "Add Members" renders
});
test('dispatches openModal action on click', () => {
test('dispatches openModal action on click', async () => {
renderWithContext(
<WithTestMenuContext>
<AddGroupMembers/>
@@ -44,7 +44,7 @@ describe('components/ChannelHeaderMenu/MenuItems/AddGroupMembers', () => {
const menuItem = screen.getByText('Add Members');
expect(menuItem).toBeInTheDocument(); // Check if text "Add Members" renders
fireEvent.click(menuItem); // Simulate click on the menu item
await userEvent.click(menuItem); // Simulate click on the menu item
expect(useDispatch).toHaveBeenCalledTimes(1); // Ensure dispatch was called
expect(modalActions.openModal).toHaveBeenCalledTimes(1);
@@ -10,7 +10,7 @@ import LocalStorageStore from 'stores/local_storage_store';
import DeleteChannelModal from 'components/delete_channel_modal';
import {WithTestMenuContext} from 'components/menu/menu_context_test';
import {renderWithContext, screen, fireEvent} from 'tests/react_testing_utils';
import {renderWithContext, screen, userEvent} from 'tests/react_testing_utils';
import {ModalIdentifiers} from 'utils/constants';
import {TestHelper} from 'utils/test_helper';
@@ -66,10 +66,6 @@ describe('components/ChannelHeaderMenu/MenuItems/ArchiveChannel', () => {
jest.spyOn(require('react-redux'), 'useDispatch');
});
afterEach(() => {
jest.clearAllMocks();
});
test('renders the component correctly', () => {
renderWithContext(
<ArchiveChannel channel={channel}/>, initialState,
@@ -79,7 +75,7 @@ describe('components/ChannelHeaderMenu/MenuItems/ArchiveChannel', () => {
expect(menuItem).toBeInTheDocument(); // Check if text "Add Members" renders
});
test('dispatches openModal action on click with default channel', () => {
test('dispatches openModal action on click with default channel', async () => {
renderWithContext(
<WithTestMenuContext>
<ArchiveChannel channel={channel}/>
@@ -88,7 +84,7 @@ describe('components/ChannelHeaderMenu/MenuItems/ArchiveChannel', () => {
const menuItem = screen.getByText('Archive Channel');
expect(menuItem).toBeInTheDocument(); // Check if text "Add Members" renders
fireEvent.click(menuItem); // Simulate click on the menu item
await userEvent.click(menuItem); // Simulate click on the menu item
expect(useDispatch).toHaveBeenCalledTimes(1); // Ensure dispatch was called
expect(modalActions.openModal).toHaveBeenCalledTimes(1);
@@ -7,7 +7,7 @@ import * as channelActions from 'actions/views/channel';
import {WithTestMenuContext} from 'components/menu/menu_context_test';
import {renderWithContext, screen, fireEvent} from 'tests/react_testing_utils';
import {renderWithContext, screen, userEvent} from 'tests/react_testing_utils';
import CloseChannel from './close_channel';
@@ -20,7 +20,7 @@ describe('components/ChannelHeaderMenu/MenuItems/CloseChannel', () => {
jest.clearAllMocks();
});
test('renders the component correctly, handle click event', () => {
test('renders the component correctly, handle click event', async () => {
renderWithContext(
<WithTestMenuContext>
<CloseChannel/>
@@ -30,7 +30,7 @@ describe('components/ChannelHeaderMenu/MenuItems/CloseChannel', () => {
const menuItem = screen.getByText('Close Channel');
expect(menuItem).toBeInTheDocument();
fireEvent.click(menuItem); // Simulate click on the menu item
await userEvent.click(menuItem); // Simulate click on the menu item
expect(channelActions.goToLastViewedChannel).toHaveBeenCalledTimes(1); // Ensure dispatch was called
});
});
@@ -11,7 +11,7 @@ import * as channelActions from 'actions/views/channel';
import {WithTestMenuContext} from 'components/menu/menu_context_test';
import {renderWithContext, screen, fireEvent} from 'tests/react_testing_utils';
import {renderWithContext, screen, userEvent} from 'tests/react_testing_utils';
import {Constants} from 'utils/constants';
import {TestHelper} from 'utils/test_helper';
@@ -80,7 +80,7 @@ describe('components/ChannelHeaderMenu/MenuItems/CloseMessage', () => {
jest.clearAllMocks();
});
test('renders the component correctly for group channel', () => {
test('renders the component correctly for group channel', async () => {
renderWithContext(
<WithTestMenuContext>
<CloseMessage
@@ -93,7 +93,7 @@ describe('components/ChannelHeaderMenu/MenuItems/CloseMessage', () => {
const menuItem = screen.getByText('Close Group Message');
expect(menuItem).toBeInTheDocument();
fireEvent.click(menuItem); // Simulate click on the menu item
await userEvent.click(menuItem); // Simulate click on the menu item
expect(channelActions.leaveDirectChannel).toHaveBeenCalledTimes(1); // Ensure dispatch was called
expect(channelActions.leaveDirectChannel).toHaveBeenCalledWith(groupChannel.name);
@@ -104,7 +104,7 @@ describe('components/ChannelHeaderMenu/MenuItems/CloseMessage', () => {
);
});
test('renders the component correctly for direct channel', () => {
test('renders the component correctly for direct channel', async () => {
renderWithContext(
<WithTestMenuContext>
<CloseMessage
@@ -117,7 +117,7 @@ describe('components/ChannelHeaderMenu/MenuItems/CloseMessage', () => {
const menuItem = screen.getByText('Close Direct Message');
expect(menuItem).toBeInTheDocument();
fireEvent.click(menuItem); // Simulate click on the menu item
await userEvent.click(menuItem); // Simulate click on the menu item
expect(channelActions.leaveDirectChannel).toHaveBeenCalledTimes(1); // Ensure dispatch was called
expect(channelActions.leaveDirectChannel).toHaveBeenCalledWith(directChannel.name);
@@ -9,7 +9,7 @@ import * as modalActions from 'actions/views/modals';
import ConvertGmToChannelModal from 'components/convert_gm_to_channel_modal';
import {WithTestMenuContext} from 'components/menu/menu_context_test';
import {renderWithContext, screen, fireEvent} from 'tests/react_testing_utils';
import {renderWithContext, screen, userEvent} from 'tests/react_testing_utils';
import {ModalIdentifiers} from 'utils/constants';
import {TestHelper} from 'utils/test_helper';
@@ -28,7 +28,7 @@ describe('components/ChannelHeaderMenu/MenuItems/ConvertGMtoPrivate', () => {
});
const channel = TestHelper.getChannelMock();
test('renders the component correctly, handle click event', () => {
test('renders the component correctly, handle click event', async () => {
renderWithContext(
<WithTestMenuContext>
<ConvertGMtoPrivate channel={channel}/>
@@ -38,7 +38,7 @@ describe('components/ChannelHeaderMenu/MenuItems/ConvertGMtoPrivate', () => {
const menuItem = screen.getByText('Convert to Private Channel');
expect(menuItem).toBeInTheDocument();
fireEvent.click(menuItem); // Simulate click on the menu item
await userEvent.click(menuItem); // Simulate click on the menu item
expect(useDispatch).toHaveBeenCalledTimes(1); // Ensure dispatch was called
expect(modalActions.openModal).toHaveBeenCalledTimes(1);
expect(modalActions.openModal).toHaveBeenCalledWith({
@@ -9,7 +9,7 @@ import * as modalActions from 'actions/views/modals';
import EditChannelHeaderModal from 'components/edit_channel_header_modal';
import {WithTestMenuContext} from 'components/menu/menu_context_test';
import {renderWithContext, screen, fireEvent} from 'tests/react_testing_utils';
import {renderWithContext, screen, userEvent} from 'tests/react_testing_utils';
import {ModalIdentifiers} from 'utils/constants';
import {TestHelper} from 'utils/test_helper';
@@ -23,12 +23,9 @@ describe('components/ChannelHeaderMenu/MenuItems/EditConversationHeader', () =>
jest.spyOn(require('react-redux'), 'useDispatch');
});
afterEach(() => {
jest.clearAllMocks();
});
const channel = TestHelper.getChannelMock();
test('renders the component correctly, handle click event', () => {
test('renders the component correctly, handle click event', async () => {
renderWithContext(
<WithTestMenuContext>
<EditConversationHeader channel={channel}/>
@@ -38,7 +35,7 @@ describe('components/ChannelHeaderMenu/MenuItems/EditConversationHeader', () =>
const menuItem = screen.getByText('Edit Header');
expect(menuItem).toBeInTheDocument();
fireEvent.click(menuItem); // Simulate click on the menu item
await userEvent.click(menuItem); // Simulate click on the menu item
expect(useDispatch).toHaveBeenCalledTimes(1); // Ensure dispatch was called
expect(modalActions.openModal).toHaveBeenCalledTimes(1);
expect(modalActions.openModal).toHaveBeenCalledWith({
@@ -10,7 +10,7 @@ import AddGroupsToChannelModal from 'components/add_groups_to_channel_modal';
import ChannelGroupsManageModal from 'components/channel_groups_manage_modal';
import {WithTestMenuContext} from 'components/menu/menu_context_test';
import {renderWithContext, screen, fireEvent} from 'tests/react_testing_utils';
import {renderWithContext, screen, userEvent} from 'tests/react_testing_utils';
import {ModalIdentifiers} from 'utils/constants';
import {TestHelper} from 'utils/test_helper';
@@ -24,12 +24,9 @@ describe('components/ChannelHeaderMenu/MenuItems/Groups', () => {
jest.spyOn(require('react-redux'), 'useDispatch');
});
afterEach(() => {
jest.clearAllMocks();
});
const channel = TestHelper.getChannelMock();
test('renders the component correctly, handle click event for add groups', () => {
test('renders the component correctly, handle click event for add groups', async () => {
renderWithContext(
<WithTestMenuContext>
<Groups channel={channel}/>
@@ -39,7 +36,7 @@ describe('components/ChannelHeaderMenu/MenuItems/Groups', () => {
const menuItem = screen.getByText('Add Groups');
expect(menuItem).toBeInTheDocument();
fireEvent.click(menuItem); // Simulate click on the menu item
await userEvent.click(menuItem); // Simulate click on the menu item
expect(useDispatch).toHaveBeenCalledTimes(1); // Ensure dispatch was called
expect(modalActions.openModal).toHaveBeenCalledTimes(1);
expect(modalActions.openModal).toHaveBeenCalledWith({
@@ -48,7 +45,7 @@ describe('components/ChannelHeaderMenu/MenuItems/Groups', () => {
});
});
test('renders the component correctly, handle click event for manage groups', () => {
test('renders the component correctly, handle click event for manage groups', async () => {
renderWithContext(
<WithTestMenuContext>
<Groups channel={channel}/>
@@ -58,7 +55,7 @@ describe('components/ChannelHeaderMenu/MenuItems/Groups', () => {
const menuItemMG = screen.getByText('Manage Groups');
expect(menuItemMG).toBeInTheDocument();
fireEvent.click(menuItemMG); // Simulate click on the menu item
await userEvent.click(menuItemMG); // Simulate click on the menu item
expect(useDispatch).toHaveBeenCalledTimes(1); // Ensure dispatch was called
expect(modalActions.openModal).toHaveBeenCalledTimes(1);
expect(modalActions.openModal).toHaveBeenCalledWith({
@@ -10,7 +10,7 @@ import * as modalActions from 'actions/views/modals';
import LeaveChannelModal from 'components/leave_channel_modal';
import {WithTestMenuContext} from 'components/menu/menu_context_test';
import {renderWithContext, screen, fireEvent} from 'tests/react_testing_utils';
import {renderWithContext, screen, userEvent} from 'tests/react_testing_utils';
import {ModalIdentifiers} from 'utils/constants';
import {TestHelper} from 'utils/test_helper';
@@ -25,11 +25,7 @@ describe('components/ChannelHeaderMenu/MenuItems/LeaveChannelTest', () => {
jest.spyOn(require('react-redux'), 'useDispatch');
});
afterEach(() => {
jest.clearAllMocks();
});
test('renders the component correctly, handle click event correctly for Public Channel', () => {
test('renders the component correctly, handle click event correctly for Public Channel', async () => {
const channel = TestHelper.getChannelMock();
renderWithContext(
@@ -41,13 +37,13 @@ describe('components/ChannelHeaderMenu/MenuItems/LeaveChannelTest', () => {
const menuItem = screen.getByText('Leave Channel');
expect(menuItem).toBeInTheDocument();
fireEvent.click(menuItem); // Simulate click on the menu item
await userEvent.click(menuItem); // Simulate click on the menu item
expect(useDispatch).toHaveBeenCalledTimes(1); // Ensure dispatch was called
expect(channelActions.leaveChannel).toHaveBeenCalledTimes(1); // Ensure dispatch was called
expect(channelActions.leaveChannel).toHaveBeenCalledWith(channel.id);
});
test('renders the component correctly, handle click event for manage groups', () => {
test('renders the component correctly, handle click event for manage groups', async () => {
const channel = TestHelper.getChannelMock({type: 'P'});
renderWithContext(
@@ -59,7 +55,7 @@ describe('components/ChannelHeaderMenu/MenuItems/LeaveChannelTest', () => {
const menuItemMG = screen.getByText('Leave Channel');
expect(menuItemMG).toBeInTheDocument();
fireEvent.click(menuItemMG); // Simulate click on the menu item
await userEvent.click(menuItemMG); // Simulate click on the menu item
expect(useDispatch).toHaveBeenCalledTimes(1); // Ensure dispatch was called
expect(modalActions.openModal).toHaveBeenCalledTimes(1);
expect(modalActions.openModal).toHaveBeenCalledWith({
@@ -13,7 +13,7 @@ import * as modalActions from 'actions/views/modals';
import {WithTestMenuContext} from 'components/menu/menu_context_test';
import {renderWithContext, screen, fireEvent, waitFor} from 'tests/react_testing_utils';
import {renderWithContext, screen, userEvent, waitFor} from 'tests/react_testing_utils';
import {TestHelper} from 'utils/test_helper';
import MobileChannelHeaderPlugins from './mobile_channel_header_plugins';
@@ -104,7 +104,7 @@ describe('components/ChannelHeaderMenu/MenuItems/MobileChannelHeaderPlugins, wit
expect(container.firstChild).toBeNull();
});
test('renders the component correctly, with one extended component, and handle click event', () => {
test('renders the component correctly, with one extended component, and handle click event', async () => {
renderWithContext(
<WithTestMenuContext>
<MobileChannelHeaderPlugins
@@ -115,7 +115,7 @@ describe('components/ChannelHeaderMenu/MenuItems/MobileChannelHeaderPlugins, wit
);
const menuItem = screen.getByText('some dropdown text');
expect(menuItem).toBeInTheDocument();
fireEvent.click(menuItem);
await userEvent.click(menuItem);
expect(action).toHaveBeenCalledTimes(1);
});
@@ -205,7 +205,7 @@ describe('components/ChannelHeaderMenu/MenuItems/MobileChannelHeaderPlugins, wit
const menuItem = screen.getByText('App 1 Channel Header');
expect(menuItem).toBeInTheDocument();
fireEvent.click(menuItem);
await userEvent.click(menuItem);
await waitFor(() => {
expect(useDispatch).toHaveBeenCalledTimes(1); // Ensure dispatch was called
expect(appsActions.handleBindingClick).toHaveBeenCalledTimes(1);
@@ -239,7 +239,7 @@ describe('components/ChannelHeaderMenu/MenuItems/MobileChannelHeaderPlugins, wit
const menuItem = screen.getByText('App 1 Channel Header');
expect(menuItem).toBeInTheDocument();
fireEvent.click(menuItem);
await userEvent.click(menuItem);
await waitFor(() => {
// expect(useDispatch).toHaveBeenCalledTimes(1); // Ensure dispatch was called
expect(appsActions.handleBindingClick).toHaveBeenCalledTimes(1);
@@ -269,7 +269,7 @@ describe('components/ChannelHeaderMenu/MenuItems/MobileChannelHeaderPlugins, wit
const menuItem = screen.getByText('App 1 Channel Header');
expect(menuItem).toBeInTheDocument();
fireEvent.click(menuItem);
await userEvent.click(menuItem);
await waitFor(() => {
// expect(useDispatch).toHaveBeenCalledTimes(1); // Ensure dispatch was called
expect(appsActions.handleBindingClick).toHaveBeenCalledTimes(1);
@@ -277,7 +277,7 @@ describe('components/ChannelHeaderMenu/MenuItems/MobileChannelHeaderPlugins, wit
});
});
test('renders the component correctly, with one extended component, isDropDown false', () => {
test('renders the component correctly, with one extended component, isDropDown false', async () => {
const action = jest.fn();
const pluginState = {
plugins: {
@@ -305,7 +305,7 @@ describe('components/ChannelHeaderMenu/MenuItems/MobileChannelHeaderPlugins, wit
);
const button = screen.getByRole('button');
expect(button).toBeInTheDocument();
fireEvent.click(button);
await userEvent.click(button);
expect(action).toHaveBeenCalledTimes(1);
});
@@ -328,7 +328,7 @@ describe('components/ChannelHeaderMenu/MenuItems/MobileChannelHeaderPlugins, wit
);
const button = screen.getByRole('button');
expect(button).toBeInTheDocument();
fireEvent.click(button);
await userEvent.click(button);
await waitFor(() => {
expect(appsActions.handleBindingClick).toHaveBeenCalledTimes(1);
});
@@ -9,7 +9,7 @@ import * as modalActions from 'actions/views/modals';
import ChannelNotificationsModal from 'components/channel_notifications_modal';
import {WithTestMenuContext} from 'components/menu/menu_context_test';
import {renderWithContext, screen, fireEvent} from 'tests/react_testing_utils';
import {renderWithContext, screen, userEvent} from 'tests/react_testing_utils';
import {ModalIdentifiers} from 'utils/constants';
import {TestHelper} from 'utils/test_helper';
@@ -23,11 +23,7 @@ describe('components/ChannelHeaderMenu/MenuItems/Notification', () => {
jest.spyOn(require('react-redux'), 'useDispatch');
});
afterEach(() => {
jest.clearAllMocks();
});
test('renders the component correctly, handle click event', () => {
test('renders the component correctly, handle click event', async () => {
const channel = TestHelper.getChannelMock();
const user = TestHelper.getUserMock();
@@ -43,7 +39,7 @@ describe('components/ChannelHeaderMenu/MenuItems/Notification', () => {
const menuItemMG = screen.getByText('Notification Preferences');
expect(menuItemMG).toBeInTheDocument();
fireEvent.click(menuItemMG); // Simulate click on the menu item
await userEvent.click(menuItemMG); // Simulate click on the menu item
expect(useDispatch).toHaveBeenCalledTimes(1); // Ensure dispatch was called
expect(modalActions.openModal).toHaveBeenCalledTimes(1);
expect(modalActions.openModal).toHaveBeenCalledWith({
@@ -9,7 +9,7 @@ import * as rhsActions from 'actions/views/rhs';
import {WithTestMenuContext} from 'components/menu/menu_context_test';
import {renderWithContext, screen, fireEvent} from 'tests/react_testing_utils';
import {renderWithContext, screen, userEvent} from 'tests/react_testing_utils';
import {RHSStates} from 'utils/constants';
import {TestHelper} from 'utils/test_helper';
@@ -23,11 +23,7 @@ describe('components/ChannelHeaderMenu/MenuItems/OpenMembersRHS', () => {
jest.spyOn(require('react-redux'), 'useDispatch');
});
afterEach(() => {
jest.clearAllMocks();
});
test('renders the component correctly, handles click event, rhs closed', () => {
test('renders the component correctly, handles click event, rhs closed', async () => {
const state = {
views: {
rhs: {
@@ -55,13 +51,13 @@ describe('components/ChannelHeaderMenu/MenuItems/OpenMembersRHS', () => {
const menuItem = screen.getByText('View Members');
expect(menuItem).toBeInTheDocument();
fireEvent.click(menuItem); // Simulate click on the menu item
await userEvent.click(menuItem); // Simulate click on the menu item
expect(useDispatch).toHaveBeenCalledTimes(1); // Ensure dispatch was called
expect(rhsActions.showChannelMembers).toHaveBeenCalledTimes(1);
expect(rhsActions.showChannelMembers).toHaveBeenCalledWith(channel.id, false);
});
test('renders the component correctly, handles correct click event, rhs open', () => {
test('renders the component correctly, handles correct click event, rhs open', async () => {
const state = {
views: {
rhs: {
@@ -91,7 +87,7 @@ describe('components/ChannelHeaderMenu/MenuItems/OpenMembersRHS', () => {
const menuItem = screen.getByText('View Members');
expect(menuItem).toBeInTheDocument();
fireEvent.click(menuItem); // Simulate click on the menu
await userEvent.click(menuItem); // Simulate click on the menu
expect(rhsActions.showChannelMembers).not.toHaveBeenCalled();
});
});
@@ -8,7 +8,7 @@ import * as channelActions from 'mattermost-redux/actions/channels';
import {WithTestMenuContext} from 'components/menu/menu_context_test';
import {renderWithContext, screen, fireEvent} from 'tests/react_testing_utils';
import {renderWithContext, screen, userEvent} from 'tests/react_testing_utils';
import {TestHelper} from 'utils/test_helper';
import ToggleFavoriteChannel from './toggle_favorite_channel';
@@ -22,11 +22,7 @@ describe('components/ChannelHeaderMenu/MenuItems/ToggleFavoriteChannel', () => {
jest.spyOn(require('react-redux'), 'useDispatch');
});
afterEach(() => {
jest.clearAllMocks();
});
test('renders the component correctly, handles correct click event, is favorite false', () => {
test('renders the component correctly, handles correct click event, is favorite false', async () => {
renderWithContext(
<WithTestMenuContext>
<ToggleFavoriteChannel
@@ -39,13 +35,13 @@ describe('components/ChannelHeaderMenu/MenuItems/ToggleFavoriteChannel', () => {
const menuItem = screen.getByText('Add to Favorites');
expect(menuItem).toBeInTheDocument();
fireEvent.click(menuItem); // Simulate click on the menu item
await userEvent.click(menuItem); // Simulate click on the menu item
// expect(useDispatch).toHaveBeenCalledTimes(1); // Ensure dispatch was called
expect(channelActions.favoriteChannel).toHaveBeenCalledTimes(1);
expect(channelActions.favoriteChannel).toHaveBeenCalledWith(channel.id);
});
test('renders the component correctly, handles correct click event, is favorite true', () => {
test('renders the component correctly, handles correct click event, is favorite true', async () => {
renderWithContext(
<WithTestMenuContext>
<ToggleFavoriteChannel
@@ -58,7 +54,7 @@ describe('components/ChannelHeaderMenu/MenuItems/ToggleFavoriteChannel', () => {
const menuItem = screen.getByText('Remove from Favorites');
expect(menuItem).toBeInTheDocument();
fireEvent.click(menuItem); // Simulate click on the menu item
await userEvent.click(menuItem); // Simulate click on the menu item
expect(useDispatch).toHaveBeenCalledTimes(1); // Ensure dispatch was called
expect(channelActions.unfavoriteChannel).toHaveBeenCalledTimes(1);
});
@@ -8,7 +8,7 @@ import * as rhsActions from 'actions/views/rhs';
import {WithTestMenuContext} from 'components/menu/menu_context_test';
import {renderWithContext, screen, fireEvent} from 'tests/react_testing_utils';
import {renderWithContext, screen, userEvent} from 'tests/react_testing_utils';
import {RHSStates} from 'utils/constants';
import {TestHelper} from 'utils/test_helper';
@@ -22,11 +22,7 @@ describe('components/ChannelHeaderMenu/MenuItems/ToggleInfo', () => {
jest.spyOn(require('react-redux'), 'useDispatch');
});
afterEach(() => {
jest.clearAllMocks();
});
test('renders the component correctly, handles click event, rhs closed', () => {
test('renders the component correctly, handles click event, rhs closed', async () => {
const state = {
views: {
rhs: {
@@ -45,13 +41,13 @@ describe('components/ChannelHeaderMenu/MenuItems/ToggleInfo', () => {
const menuItem = screen.getByText('View Info');
expect(menuItem).toBeInTheDocument();
fireEvent.click(menuItem); // Simulate click on the menu item
await userEvent.click(menuItem); // Simulate click on the menu item
// expect(useDispatch).toHaveBeenCalledTimes(1); // Ensure dispatch was called
expect(rhsActions.showChannelInfo).toHaveBeenCalledTimes(1);
expect(rhsActions.showChannelInfo).toHaveBeenCalledWith(channel.id);
});
test('renders the component correctly, handles correct click event, rhs open', () => {
test('renders the component correctly, handles correct click event, rhs open', async () => {
const state = {
views: {
rhs: {
@@ -72,7 +68,7 @@ describe('components/ChannelHeaderMenu/MenuItems/ToggleInfo', () => {
const menuItem = screen.getByText('Close Info');
expect(menuItem).toBeInTheDocument();
fireEvent.click(menuItem); // Simulate click on the menu item
await userEvent.click(menuItem); // Simulate click on the menu item
expect(useDispatch).toHaveBeenCalledTimes(1); // Ensure dispatch was called
expect(rhsActions.closeRightHandSide).toHaveBeenCalledTimes(1);
});
@@ -8,7 +8,7 @@ import * as channelActions from 'mattermost-redux/actions/channels';
import {WithTestMenuContext} from 'components/menu/menu_context_test';
import {renderWithContext, screen, fireEvent} from 'tests/react_testing_utils';
import {renderWithContext, screen, userEvent} from 'tests/react_testing_utils';
import {NotificationLevels} from 'utils/constants';
import {TestHelper} from 'utils/test_helper';
@@ -23,11 +23,7 @@ describe('components/ChannelHeaderMenu/MenuItems/ToggleMuteChannel', () => {
jest.spyOn(require('react-redux'), 'useDispatch');
});
afterEach(() => {
jest.clearAllMocks();
});
test('renders the component correctly, public channel, not muted', () => {
test('renders the component correctly, public channel, not muted', async () => {
renderWithContext(
<WithTestMenuContext>
<ToggleMuteChannel
@@ -41,7 +37,7 @@ describe('components/ChannelHeaderMenu/MenuItems/ToggleMuteChannel', () => {
const menuItem = screen.getByText('Mute Channel');
expect(menuItem).toBeInTheDocument();
fireEvent.click(menuItem); // Simulate click on the menu item
await userEvent.click(menuItem); // Simulate click on the menu item
expect(useDispatch).toHaveBeenCalledTimes(1); // Ensure dispatch was called
expect(channelActions.updateChannelNotifyProps).toHaveBeenCalledTimes(1);
expect(channelActions.updateChannelNotifyProps).toHaveBeenCalledWith(
@@ -51,7 +47,7 @@ describe('components/ChannelHeaderMenu/MenuItems/ToggleMuteChannel', () => {
);
});
test('renders the component correctly, public channel, muted', () => {
test('renders the component correctly, public channel, muted', async () => {
renderWithContext(
<WithTestMenuContext>
<ToggleMuteChannel
@@ -65,7 +61,7 @@ describe('components/ChannelHeaderMenu/MenuItems/ToggleMuteChannel', () => {
const menuItem = screen.getByText('Unmute Channel');
expect(menuItem).toBeInTheDocument();
fireEvent.click(menuItem); // Simulate click on the menu item
await userEvent.click(menuItem); // Simulate click on the menu item
expect(useDispatch).toHaveBeenCalledTimes(1); // Ensure dispatch was called
expect(channelActions.updateChannelNotifyProps).toHaveBeenCalledTimes(1);
expect(channelActions.updateChannelNotifyProps).toHaveBeenCalledWith(
@@ -75,7 +71,7 @@ describe('components/ChannelHeaderMenu/MenuItems/ToggleMuteChannel', () => {
);
});
test('renders the component correctly, dm channel, not muted', () => {
test('renders the component correctly, dm channel, not muted', async () => {
const channel = TestHelper.getChannelMock({type: 'D'});
renderWithContext(
<WithTestMenuContext>
@@ -90,7 +86,7 @@ describe('components/ChannelHeaderMenu/MenuItems/ToggleMuteChannel', () => {
const menuItem = screen.getByText('Mute');
expect(menuItem).toBeInTheDocument();
fireEvent.click(menuItem); // Simulate click on the menu item
await userEvent.click(menuItem); // Simulate click on the menu item
expect(useDispatch).toHaveBeenCalledTimes(1); // Ensure dispatch was called
expect(channelActions.updateChannelNotifyProps).toHaveBeenCalledTimes(1);
expect(channelActions.updateChannelNotifyProps).toHaveBeenCalledWith(
@@ -99,7 +95,7 @@ describe('components/ChannelHeaderMenu/MenuItems/ToggleMuteChannel', () => {
{mark_unread: NotificationLevels.MENTION},
);
});
test('renders the component correctly, dm channel, muted', () => {
test('renders the component correctly, dm channel, muted', async () => {
const channel = TestHelper.getChannelMock({type: 'D'});
renderWithContext(
<WithTestMenuContext>
@@ -114,7 +110,7 @@ describe('components/ChannelHeaderMenu/MenuItems/ToggleMuteChannel', () => {
const menuItem = screen.getByText('Unmute');
expect(menuItem).toBeInTheDocument();
fireEvent.click(menuItem); // Simulate click on the menu item
await userEvent.click(menuItem); // Simulate click on the menu item
expect(useDispatch).toHaveBeenCalledTimes(1); // Ensure dispatch was called
expect(channelActions.updateChannelNotifyProps).toHaveBeenCalledTimes(1);
expect(channelActions.updateChannelNotifyProps).toHaveBeenCalledWith(
@@ -9,7 +9,7 @@ import * as modalActions from 'actions/views/modals';
import {WithTestMenuContext} from 'components/menu/menu_context_test';
import UnarchiveChannelModal from 'components/unarchive_channel_modal';
import {renderWithContext, screen, fireEvent} from 'tests/react_testing_utils';
import {renderWithContext, screen, userEvent} from 'tests/react_testing_utils';
import {ModalIdentifiers} from 'utils/constants';
import {TestHelper} from 'utils/test_helper';
@@ -21,11 +21,7 @@ describe('components/ChannelHeaderMenu/MenuItems/UnarchiveChannel', () => {
jest.spyOn(require('react-redux'), 'useDispatch');
});
afterEach(() => {
jest.clearAllMocks();
});
test('renders the component correctly, handle click event', () => {
test('renders the component correctly, handle click event', async () => {
const channel = TestHelper.getChannelMock();
renderWithContext(
@@ -37,7 +33,7 @@ describe('components/ChannelHeaderMenu/MenuItems/UnarchiveChannel', () => {
const menuItem = screen.getByText('Unarchive Channel');
expect(menuItem).toBeInTheDocument();
fireEvent.click(menuItem); // Simulate click on the menu item
await userEvent.click(menuItem); // Simulate click on the menu item
expect(useDispatch).toHaveBeenCalledTimes(1); // Ensure dispatch was called
expect(modalActions.openModal).toHaveBeenCalledTimes(1);
expect(modalActions.openModal).toHaveBeenCalledWith({
@@ -8,7 +8,7 @@ import * as rhsActions from 'actions/views/rhs';
import {WithTestMenuContext} from 'components/menu/menu_context_test';
import {renderWithContext, screen, fireEvent} from 'tests/react_testing_utils';
import {renderWithContext, screen, userEvent} from 'tests/react_testing_utils';
import {RHSStates} from 'utils/constants';
import {TestHelper} from 'utils/test_helper';
@@ -22,11 +22,7 @@ describe('components/ChannelHeaderMenu/MenuItems/ViewPinnedPosts', () => {
jest.spyOn(require('react-redux'), 'useDispatch');
});
afterEach(() => {
jest.clearAllMocks();
});
test('renders the component correctly, handles correct click event', () => {
test('renders the component correctly, handles correct click event', async () => {
const state = {
views: {
rhs: {
@@ -45,13 +41,13 @@ describe('components/ChannelHeaderMenu/MenuItems/ViewPinnedPosts', () => {
const menuItem = screen.getByText('View Pinned Posts');
expect(menuItem).toBeInTheDocument();
fireEvent.click(menuItem); // Simulate click on the menu item
await userEvent.click(menuItem); // Simulate click on the menu item
expect(useDispatch).toHaveBeenCalledTimes(1); // Ensure dispatch was called
expect(rhsActions.showPinnedPosts).toHaveBeenCalledTimes(1);
expect(rhsActions.showPinnedPosts).toHaveBeenCalledWith(channel.id);
});
test('renders the component correctly, handles correct click event', () => {
test('renders the component correctly, handles correct click event', async () => {
const state = {
views: {
rhs: {
@@ -70,7 +66,7 @@ describe('components/ChannelHeaderMenu/MenuItems/ViewPinnedPosts', () => {
const menuItem = screen.getByText('View Pinned Posts');
expect(menuItem).toBeInTheDocument();
fireEvent.click(menuItem); // Simulate click on the menu item
await userEvent.click(menuItem); // Simulate click on the menu item
expect(useDispatch).toHaveBeenCalledTimes(1); // Ensure dispatch was called
expect(rhsActions.closeRightHandSide).toHaveBeenCalledTimes(1);
});
@@ -3,7 +3,7 @@
import React from 'react';
import {fireEvent, renderWithContext, screen} from 'tests/react_testing_utils';
import {renderWithContext, screen, userEvent} from 'tests/react_testing_utils';
import EditableArea from './editable_area';
@@ -33,7 +33,7 @@ describe('channel_info_rhs/components/editable_area', () => {
);
expect(screen.getByLabelText('Edit')).toBeInTheDocument();
fireEvent.click(screen.getByLabelText('Edit'));
await userEvent.click(screen.getByLabelText('Edit'));
expect(mockOnEdit).toHaveBeenCalled();
});
@@ -64,10 +64,10 @@ describe('channel_info_rhs/components/editable_area', () => {
expect(screen.getByText('No content')).toBeInTheDocument();
// We should be able to click on the text...
fireEvent.click(screen.getByText('No content'));
await userEvent.click(screen.getByText('No content'));
// ... or the Edit icon
fireEvent.click(screen.getByLabelText('Edit'));
await userEvent.click(screen.getByLabelText('Edit'));
expect(mockOnEdit).toHaveBeenCalledTimes(2);
});
});
@@ -5,7 +5,7 @@ import React from 'react';
import type {Channel} from '@mattermost/types/channels';
import {fireEvent, renderWithContext, screen} from 'tests/react_testing_utils';
import {renderWithContext, screen, userEvent} from 'tests/react_testing_utils';
import Header from './header';
@@ -22,7 +22,7 @@ describe('channel_info_rhs/header', () => {
expect(screen.getByText('my channel title')).toBeInTheDocument();
});
test('should call onClose when clicking on the close icon', () => {
test('should call onClose when clicking on the close icon', async () => {
const onClose = jest.fn();
renderWithContext(
@@ -34,11 +34,11 @@ describe('channel_info_rhs/header', () => {
/>,
);
fireEvent.click(screen.getByLabelText('Close Sidebar Icon'));
await userEvent.click(screen.getByLabelText('Close Sidebar Icon'));
expect(onClose).toHaveBeenCalled();
});
test('should call onClose when clicking on the back icon', () => {
test('should call onClose when clicking on the back icon', async () => {
const onClose = jest.fn();
renderWithContext(
@@ -50,7 +50,7 @@ describe('channel_info_rhs/header', () => {
/>,
);
fireEvent.click(screen.getByLabelText('Back Icon'));
await userEvent.click(screen.getByLabelText('Back Icon'));
expect(onClose).toHaveBeenCalled();
});
@@ -7,9 +7,9 @@ import type {Channel, ChannelStats} from '@mattermost/types/channels';
import {
act,
fireEvent,
renderWithContext,
screen,
userEvent,
} from 'tests/react_testing_utils';
import Constants from 'utils/constants';
@@ -54,7 +54,7 @@ describe('channel_info_rhs/menu', () => {
});
expect(screen.getByText('Notification Preferences')).toBeInTheDocument();
fireEvent.click(screen.getByText('Notification Preferences'));
await userEvent.click(screen.getByText('Notification Preferences'));
expect(props.actions.openNotificationSettings).toHaveBeenCalled();
});
@@ -115,7 +115,7 @@ describe('channel_info_rhs/menu', () => {
expect(fileItem).toBeInTheDocument();
expect(fileItem.parentElement).toHaveTextContent('3');
fireEvent.click(fileItem);
await userEvent.click(fileItem);
expect(props.actions.showChannelFiles).toHaveBeenCalled();
});
@@ -137,7 +137,7 @@ describe('channel_info_rhs/menu', () => {
expect(fileItem).toBeInTheDocument();
expect(fileItem.parentElement).toHaveTextContent('12');
fireEvent.click(fileItem);
await userEvent.click(fileItem);
expect(props.actions.showPinnedPosts).toHaveBeenCalled();
});
@@ -159,7 +159,7 @@ describe('channel_info_rhs/menu', () => {
expect(membersItem).toBeInTheDocument();
expect(membersItem.parentElement).toHaveTextContent('32');
fireEvent.click(membersItem);
await userEvent.click(membersItem);
expect(props.actions.showChannelMembers).toHaveBeenCalled();
});
@@ -3,7 +3,7 @@
import React from 'react';
import {fireEvent, renderWithContext, screen} from 'tests/react_testing_utils';
import {renderWithContext, screen, userEvent} from 'tests/react_testing_utils';
import Constants from 'utils/constants';
import TopButtons from './top_buttons';
@@ -35,7 +35,7 @@ describe('channel_info_rhs/top_buttons', () => {
},
};
test('should display and toggle Favorite', () => {
test('should display and toggle Favorite', async () => {
const toggleFavorite = jest.fn();
// Favorite to Favorited
@@ -54,7 +54,7 @@ describe('channel_info_rhs/top_buttons', () => {
);
expect(screen.getByText('Favorite')).toBeInTheDocument();
fireEvent.click(screen.getByText('Favorite'));
await userEvent.click(screen.getByText('Favorite'));
expect(toggleFavorite).toHaveBeenCalled();
// Favorited to Favorite
@@ -67,11 +67,11 @@ describe('channel_info_rhs/top_buttons', () => {
);
expect(screen.getByText('Favorited')).toBeInTheDocument();
fireEvent.click(screen.getByText('Favorited'));
await userEvent.click(screen.getByText('Favorited'));
expect(toggleFavorite).toHaveBeenCalled();
});
test('should display and toggle Mute', () => {
test('should display and toggle Mute', async () => {
const toggleMute = jest.fn();
// Mute to Muted
@@ -90,7 +90,7 @@ describe('channel_info_rhs/top_buttons', () => {
);
expect(screen.getByText('Mute')).toBeInTheDocument();
fireEvent.click(screen.getByText('Mute'));
await userEvent.click(screen.getByText('Mute'));
expect(toggleMute).toHaveBeenCalled();
// Muted to Mute
@@ -103,11 +103,11 @@ describe('channel_info_rhs/top_buttons', () => {
);
expect(screen.getByText('Muted')).toBeInTheDocument();
fireEvent.click(screen.getByText('Muted'));
await userEvent.click(screen.getByText('Muted'));
expect(toggleMute).toHaveBeenCalled();
});
test('should display and active call Add People', () => {
test('should display and active call Add People', async () => {
const addPeople = jest.fn();
const testProps = {
@@ -125,7 +125,7 @@ describe('channel_info_rhs/top_buttons', () => {
);
expect(screen.getByText('Add People')).toBeInTheDocument();
fireEvent.click(screen.getByText('Add People'));
await userEvent.click(screen.getByText('Add People'));
expect(addPeople).toHaveBeenCalled();
});
test('should not Add People in DM', () => {
@@ -158,7 +158,7 @@ describe('channel_info_rhs/top_buttons', () => {
expect(screen.queryByText('Add People')).not.toBeInTheDocument();
});
test('can copy link', () => {
test('can copy link', async () => {
renderWithContext(
<TopButtons
{...topButtonDefaultProps}
@@ -166,7 +166,7 @@ describe('channel_info_rhs/top_buttons', () => {
);
expect(screen.getByText('Copy Link')).toBeInTheDocument();
fireEvent.click(screen.getByText('Copy Link'));
await userEvent.click(screen.getByText('Copy Link'));
expect(mockOnCopyTextClick).toHaveBeenCalled();
});
@@ -1,8 +1,6 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {fireEvent, screen, waitFor} from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import React from 'react';
import {GenericModal} from '@mattermost/components';
@@ -17,7 +15,7 @@ import ChannelInviteModal from 'components/channel_invite_modal/channel_invite_m
import type {Value} from 'components/multiselect/multiselect';
import {shallowWithIntl} from 'tests/helpers/intl-test-helper';
import {act, renderWithContext} from 'tests/react_testing_utils';
import {act, renderWithContext, screen, userEvent, waitFor} from 'tests/react_testing_utils';
type UserProfileValue = Value & UserProfile;
@@ -430,9 +428,8 @@ describe('components/channel_invite_modal', () => {
const input = screen.getByRole('combobox', {name: /search for people/i});
// Directly trigger the change event with a value that has spaces
act(() => {
fireEvent.change(input, {target: {value: ' something '}});
});
await userEvent.clear(input);
await userEvent.type(input, ' something ');
// Verify the search was called with the trimmed term
await waitFor(() => {
@@ -3,7 +3,7 @@
import React from 'react';
import {fireEvent, renderWithContext, screen} from 'tests/react_testing_utils';
import {renderWithContext, screen, userEvent} from 'tests/react_testing_utils';
import Constants from 'utils/constants';
import ActionBar from './action_bar';
@@ -42,7 +42,7 @@ describe('channel_members_rhs/action_bar', () => {
expect(screen.getByText(`${testProps.membersCount} members`)).toBeInTheDocument();
});
test('should display Add button', () => {
test('should display Add button', async () => {
const testProps: Props = {...actionBarDefaultProps};
renderWithContext(
@@ -52,7 +52,7 @@ describe('channel_members_rhs/action_bar', () => {
);
expect(screen.getByText('Add')).toBeInTheDocument();
fireEvent.click(screen.getByText('Add'));
await userEvent.click(screen.getByText('Add'));
expect(testProps.actions.inviteMembers).toHaveBeenCalled();
});
@@ -68,7 +68,7 @@ describe('channel_members_rhs/action_bar', () => {
expect(screen.queryByText('Add')).not.toBeInTheDocument();
});
test('should display Manage', () => {
test('should display Manage', async () => {
const testProps: Props = {...actionBarDefaultProps};
renderWithContext(
@@ -78,11 +78,11 @@ describe('channel_members_rhs/action_bar', () => {
);
expect(screen.getByText('Manage')).toBeInTheDocument();
fireEvent.click(screen.getByText('Manage'));
await userEvent.click(screen.getByText('Manage'));
expect(testProps.actions.startEditing).toHaveBeenCalled();
});
test('should display Done', () => {
test('should display Done', async () => {
const testProps: Props = {
...actionBarDefaultProps,
editing: true,
@@ -95,7 +95,7 @@ describe('channel_members_rhs/action_bar', () => {
);
expect(screen.getByText('Done')).toBeInTheDocument();
fireEvent.click(screen.getByText('Done'));
await userEvent.click(screen.getByText('Done'));
expect(testProps.actions.stopEditing).toHaveBeenCalled();
});
@@ -1,13 +1,12 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import userEvent from '@testing-library/user-event';
import React from 'react';
import type {ChannelType} from '@mattermost/types/channels';
import type {UserProfile} from '@mattermost/types/users';
import {renderWithContext, screen, waitFor} from 'tests/react_testing_utils';
import {renderWithContext, screen, waitFor, userEvent} from 'tests/react_testing_utils';
import Member from './member';
import type {ChannelMember} from './member_list';
@@ -256,6 +255,5 @@ describe('components/channel_members_rhs/Member', () => {
afterEach(() => {
jest.clearAllTimers();
jest.useRealTimers();
jest.clearAllMocks();
});
});
@@ -1,8 +1,6 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {screen, waitFor} from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import React from 'react';
import type {ChannelMembership} from '@mattermost/types/channels';
@@ -11,7 +9,7 @@ import type {UserNotifyProps} from '@mattermost/types/users';
import ChannelNotificationsModal, {createChannelNotifyPropsFromSelectedSettings, getInitialValuesOfChannelNotifyProps, areDesktopAndMobileSettingsDifferent} from 'components/channel_notifications_modal/channel_notifications_modal';
import type {Props} from 'components/channel_notifications_modal/channel_notifications_modal';
import {renderWithContext} from 'tests/react_testing_utils';
import {renderWithContext, screen, waitFor, userEvent} from 'tests/react_testing_utils';
import {DesktopSound, IgnoreChannelMentions, NotificationLevels} from 'utils/constants';
import {DesktopNotificationSounds, convertDesktopSoundNotifyPropFromUserToDesktop} from 'utils/notification_sounds';
import {TestHelper} from 'utils/test_helper';
@@ -1,11 +1,9 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {screen} from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import React from 'react';
import {renderWithContext} from 'tests/react_testing_utils';
import {renderWithContext, screen, userEvent} from 'tests/react_testing_utils';
import ChannelActivityWarningModal from './channel_activity_warning_modal';
@@ -17,10 +15,6 @@ describe('ChannelActivityWarningModal', () => {
channelName: 'test-channel',
};
beforeEach(() => {
jest.clearAllMocks();
});
test('should render modal when isOpen is true', () => {
renderWithContext(
<ChannelActivityWarningModal {...defaultProps}/>,
@@ -185,8 +185,6 @@ describe('ChannelSettingsAccessRulesTab - Activity Warning Integration', () => {
};
beforeEach(() => {
jest.clearAllMocks();
// Set up default mock implementations
mockUseChannelAccessControlActions.mockReturnValue(mockActions);
mockUseChannelSystemPolicies.mockReturnValue({
@@ -1,8 +1,6 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {screen, waitFor} from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import React from 'react';
import type {Team} from '@mattermost/types/teams';
@@ -11,7 +9,7 @@ import * as teams from 'mattermost-redux/selectors/entities/teams';
import * as channelActions from 'actions/views/channel';
import {renderWithContext} from 'tests/react_testing_utils';
import {renderWithContext, screen, userEvent, waitFor} from 'tests/react_testing_utils';
import {TestHelper} from 'utils/test_helper';
import ChannelSettingsArchiveTab from './channel_settings_archive_tab';
@@ -49,8 +47,6 @@ const baseProps = {
describe('ChannelSettingsArchiveTab', () => {
const {getHistory} = require('utils/browser_history');
beforeEach(() => {
jest.clearAllMocks();
jest.spyOn(teams, 'getCurrentTeam').mockReturnValue({
id: 'team1',
name: 'team-name',
@@ -1,11 +1,9 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {screen} from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import React from 'react';
import {renderWithContext} from 'tests/react_testing_utils';
import {renderWithContext, screen, userEvent} from 'tests/react_testing_utils';
import {TestHelper} from 'utils/test_helper';
import ChannelSettingsConfigurationTab from './channel_settings_configuration_tab';
@@ -66,10 +64,6 @@ const baseProps = {
};
describe('ChannelSettingsConfigurationTab', () => {
beforeEach(() => {
jest.clearAllMocks();
});
it('should render with the correct initial values when banner is disabled', () => {
renderWithContext(<ChannelSettingsConfigurationTab {...baseProps}/>);
@@ -1,13 +1,11 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {act, screen} from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import React from 'react';
import type {ChannelType} from '@mattermost/types/channels';
import {renderWithContext} from 'tests/react_testing_utils';
import {act, renderWithContext, screen, userEvent} from 'tests/react_testing_utils';
import {TestHelper} from 'utils/test_helper';
import ChannelSettingsInfoTab from './channel_settings_info_tab';
@@ -128,7 +126,6 @@ const baseProps = {
describe('ChannelSettingsInfoTab', () => {
beforeEach(() => {
jest.clearAllMocks();
mockChannelPropertiesPermission = true;
mockConvertToPublicPermission = true;
mockConvertToPrivatePermission = true;
@@ -1,13 +1,11 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {screen, waitFor} from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import React from 'react';
import {General} from 'mattermost-redux/constants';
import {renderWithContext} from 'tests/react_testing_utils';
import {renderWithContext, screen, waitFor, userEvent} from 'tests/react_testing_utils';
import {TestHelper} from 'utils/test_helper';
import ChannelSettingsModal from './channel_settings_modal';
@@ -166,7 +164,6 @@ describe('ChannelSettingsModal', () => {
}
beforeEach(() => {
jest.clearAllMocks();
mockPrivateChannelPermission = true;
mockPublicChannelPermission = true;
mockManageChannelAccessRulesPermission = false; // Default to no access rules permission
@@ -518,10 +515,6 @@ describe('ChannelSettingsModal', () => {
});
describe('warn-once modal closing behavior', () => {
beforeEach(() => {
jest.clearAllMocks();
});
it('should close immediately when no unsaved changes exist', async () => {
renderWithContext(<ChannelSettingsModal {...baseProps}/>, makeTestState());
@@ -1,14 +1,13 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {fireEvent, screen, waitFor} from '@testing-library/react';
import React from 'react';
import * as reactRedux from 'react-redux';
import type {Subscription, PreviewModalContentData} from '@mattermost/types/cloud';
import type {TeamType} from '@mattermost/types/teams';
import {renderWithContext} from 'tests/react_testing_utils';
import {renderWithContext, screen, userEvent, waitFor} from 'tests/react_testing_utils';
import CloudPreviewModal from './cloud_preview_modal_controller';
import {modalContent} from './preview_modal_content_data';
@@ -258,13 +257,13 @@ describe('CloudPreviewModal', () => {
// Click close button
const closeButton = screen.getByText('Close');
fireEvent.click(closeButton);
await userEvent.click(closeButton);
// Check that dispatch was called (savePreferences action)
expect(dummyDispatch).toHaveBeenCalled();
});
it('should reset preference and reopen modal when FAB is clicked', () => {
it('should reset preference and reopen modal when FAB is clicked', async () => {
const dummyDispatch = jest.fn();
useDispatchMock.mockReturnValue(dummyDispatch);
@@ -280,7 +279,7 @@ describe('CloudPreviewModal', () => {
// Click the FAB button
const button = fabButton.querySelector('button');
expect(button).toBeInTheDocument();
fireEvent.click(button!);
await userEvent.click(button!);
// Check that dispatch was called to reset the preference
expect(dummyDispatch).toHaveBeenCalled();
@@ -1,10 +1,9 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {screen, fireEvent} from '@testing-library/react';
import React from 'react';
import {renderWithContext} from 'tests/react_testing_utils';
import {renderWithContext, screen, userEvent} from 'tests/react_testing_utils';
import PreviewModalContent from './preview_modal_content';
import type {PreviewModalContentData} from './preview_modal_content_data';
@@ -129,7 +128,7 @@ describe('PreviewModalContent', () => {
expect(playButton).toHaveClass('custom-play-button');
});
it('should hide play button and show controls when play button is clicked', () => {
it('should hide play button and show controls when play button is clicked', async () => {
const content = {
...baseContent,
videoUrl: 'https://example.com/video.mp4',
@@ -142,7 +141,7 @@ describe('PreviewModalContent', () => {
renderComponent(content);
const playButton = screen.getByLabelText('Play video');
fireEvent.click(playButton);
await userEvent.click(playButton);
expect(mockPlay).toHaveBeenCalled();
expect(screen.queryByLabelText('Play video')).not.toBeInTheDocument();
@@ -1,10 +1,9 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {screen, fireEvent} from '@testing-library/react';
import React from 'react';
import {renderWithContext} from 'tests/react_testing_utils';
import {renderWithContext, screen, userEvent} from 'tests/react_testing_utils';
import PreviewModalController from './preview_modal_content_controller';
import type {PreviewModalContentData} from './preview_modal_content_data';
@@ -121,43 +120,43 @@ describe('PreviewModalController', () => {
expect(screen.getByText('1/3')).toBeInTheDocument();
});
it('should update page counter when navigating', () => {
it('should update page counter when navigating', async () => {
renderComponent();
expect(screen.getByText('1/3')).toBeInTheDocument();
const nextButton = screen.getByText('Next');
fireEvent.click(nextButton);
await userEvent.click(nextButton);
expect(screen.getByText('2/3')).toBeInTheDocument();
});
it('should navigate to next slide when Next is clicked', () => {
it('should navigate to next slide when Next is clicked', async () => {
renderComponent();
const nextButton = screen.getByText('Next');
fireEvent.click(nextButton);
await userEvent.click(nextButton);
expect(screen.getByText('Second Slide')).toBeInTheDocument();
expect(screen.queryByText('First Slide')).not.toBeInTheDocument();
});
it('should navigate to previous slide when Previous is clicked', () => {
it('should navigate to previous slide when Previous is clicked', async () => {
renderComponent();
// Go to second slide first
const nextButton = screen.getByText('Next');
fireEvent.click(nextButton);
await userEvent.click(nextButton);
// Now go back
const previousButton = screen.getByText('Previous');
fireEvent.click(previousButton);
await userEvent.click(previousButton);
expect(screen.getByText('First Slide')).toBeInTheDocument();
expect(screen.queryByText('Second Slide')).not.toBeInTheDocument();
});
it('should show Skip for now button only on first slide', () => {
it('should show Skip for now button only on first slide', async () => {
renderComponent();
// First slide should have Skip button
@@ -165,7 +164,7 @@ describe('PreviewModalController', () => {
// Go to second slide
const nextButton = screen.getByText('Next');
fireEvent.click(nextButton);
await userEvent.click(nextButton);
// Second slide should not have Skip button
expect(screen.queryByText('Skip for now')).not.toBeInTheDocument();
@@ -176,47 +175,47 @@ describe('PreviewModalController', () => {
expect(screen.queryByText('Previous')).not.toBeInTheDocument();
});
it('should show Done button on last slide', () => {
it('should show Done button on last slide', async () => {
renderComponent();
// Navigate to last slide
const nextButton = screen.getByText('Next');
fireEvent.click(nextButton);
fireEvent.click(nextButton);
await userEvent.click(nextButton);
await userEvent.click(nextButton);
expect(screen.getByText('Finish')).toBeInTheDocument();
expect(screen.queryByText('Next')).not.toBeInTheDocument();
});
it('should call onClose when Skip is clicked', () => {
it('should call onClose when Skip is clicked', async () => {
renderComponent();
const skipButton = screen.getByText('Skip for now');
fireEvent.click(skipButton);
await userEvent.click(skipButton);
expect(mockOnClose).toHaveBeenCalledTimes(1);
});
it('should call onClose when Finish is clicked on last slide', () => {
it('should call onClose when Finish is clicked on last slide', async () => {
renderComponent();
// Navigate to last slide
const nextButton = screen.getByText('Next');
fireEvent.click(nextButton);
fireEvent.click(nextButton);
await userEvent.click(nextButton);
await userEvent.click(nextButton);
const finishButton = screen.getByText('Finish');
fireEvent.click(finishButton);
await userEvent.click(finishButton);
expect(mockOnClose).toHaveBeenCalledTimes(1);
});
it('should call onClose when close button is clicked', () => {
it('should call onClose when close button is clicked', async () => {
renderComponent();
// Look for the actual close button from GenericModal
const closeButton = screen.getByLabelText('Close');
fireEvent.click(closeButton);
await userEvent.click(closeButton);
expect(mockOnClose).toHaveBeenCalledTimes(1);
});
@@ -74,7 +74,7 @@ describe('components/ColorInput', () => {
expect(container.querySelector('.color-popover')).toBeInTheDocument();
});
test('should keep what the user types in the textbox until blur', () => {
test('should keep what the user types in the textbox until blur', async () => {
let currentValue = '#ffffff';
const onChange = jest.fn((value: string) => {
currentValue = value;
@@ -91,9 +91,11 @@ describe('components/ColorInput', () => {
const input = screen.getByRole('textbox');
const colorIcon = container.querySelector('.color-icon') as HTMLElement;
// Simulate focus on input - fireEvent used because userEvent doesn't have direct focus/blur methods
fireEvent.focus(input);
fireEvent.change(input, {target: {value: '#abc'}});
await userEvent.clear(input);
await userEvent.type(input, '#abc');
expect(onChange).toHaveBeenLastCalledWith('#aabbcc');
expect(input).toHaveValue('#abc');
expect(colorIcon.style.backgroundColor).toBe('rgb(170, 187, 204)');
@@ -41,10 +41,6 @@ describe('AgentDropdown', () => {
defaultBotId: 'bot1',
};
beforeEach(() => {
jest.clearAllMocks();
});
test('should render with selected bot name', () => {
renderWithContext(<AgentDropdown {...defaultProps}/>);
@@ -59,10 +59,6 @@ describe('useAccessControlAttributes', () => {
</Provider>
);
beforeEach(() => {
jest.clearAllMocks();
});
test('should return initial state', () => {
const {result} = renderHook(() => useAccessControlAttributes(EntityType.Channel, undefined, undefined), {wrapper});
@@ -61,6 +61,7 @@ describe('/components/common/InfiniteScroll', () => {
Object.defineProperty(scrollContainer, 'scrollTop', {value: 500, configurable: true});
await act(async () => {
// Simulate scroll event - fireEvent used because userEvent doesn't support scroll events
fireEvent.scroll(scrollContainer);
// Wait for debounce (200ms) plus some buffer
@@ -32,7 +32,7 @@ describe('Scrollbars', () => {
</Scrollbars>,
);
// Ideally, we'd actually scroll the content of the element, but jsdom doesn't implement scroll events
// Simulate scrolling to verify the onScroll handler is attached correctly - fireEvent used because userEvent doesn't support scroll events
fireEvent.scroll(document.querySelector('.simplebar-content-wrapper')!);
expect(onScroll).toHaveBeenCalled();
@@ -1,7 +1,7 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {fireEvent, waitForElementToBeRemoved} from '@testing-library/react';
import {waitForElementToBeRemoved} from '@testing-library/react';
import React from 'react';
import {General} from 'mattermost-redux/constants';
@@ -39,7 +39,7 @@ describe('component/ConvertChannelModal', () => {
test('should not call updateChannelPrivacy when Close button is clicked', async () => {
renderWithContext(<ConvertChannelModal {...baseProps}/>);
fireEvent.click(screen.getByRole('button', {name: 'Close'}));
await userEvent.click(screen.getByRole('button', {name: 'Close'}));
await waitForElementToBeRemoved(() => screen.getByText('Convert Channel Display Name to a Private Channel?'));
expect(updateChannelPrivacy).not.toHaveBeenCalled();
@@ -47,7 +47,7 @@ describe('component/ConvertChannelModal', () => {
test('should not call updateChannelPrivacy when other Cancel is clicked', async () => {
renderWithContext(<ConvertChannelModal {...baseProps}/>);
fireEvent.click(screen.getByRole('button', {name: 'No, cancel'}));
await userEvent.click(screen.getByRole('button', {name: 'No, cancel'}));
await waitForElementToBeRemoved(() => screen.getByText('Convert Channel Display Name to a Private Channel?'));
expect(updateChannelPrivacy).not.toHaveBeenCalled();
@@ -1,7 +1,6 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {fireEvent, waitFor} from '@testing-library/react';
import nock from 'nock';
import React from 'react';
@@ -16,7 +15,7 @@ import {Preferences} from 'mattermost-redux/constants';
import ConvertGmToChannelModal from 'components/convert_gm_to_channel_modal/convert_gm_to_channel_modal';
import TestHelper from 'packages/mattermost-redux/test/test_helper';
import {act, renderWithContext, screen} from 'tests/react_testing_utils';
import {fireEvent, renderWithContext, screen, userEvent, waitFor} from 'tests/react_testing_utils';
import type {GlobalState} from 'types/store';
@@ -161,18 +160,17 @@ describe('component/ConvertGmToChannelModal', () => {
const team1Option = screen.queryByText('Team 1');
expect(team1Option).toBeInTheDocument();
fireEvent.click(team1Option!);
await userEvent.click(team1Option!);
const channelNameInput = screen.queryByPlaceholderText('Channel name');
expect(channelNameInput).toBeInTheDocument();
fireEvent.change(channelNameInput!, {target: {value: 'Channel name set by me'}});
await userEvent.clear(channelNameInput!);
await userEvent.type(channelNameInput!, 'Channel name set by me');
const confirmButton = screen.queryByText('Convert to private channel');
expect(channelNameInput).toBeInTheDocument();
await act(async () => {
fireEvent.click(confirmButton!);
});
await userEvent.click(confirmButton!);
});
test('duplicate channel names should npt be allowed', async () => {
@@ -202,14 +200,13 @@ describe('component/ConvertGmToChannelModal', () => {
const channelNameInput = screen.queryByPlaceholderText('Channel name');
expect(channelNameInput).toBeInTheDocument();
fireEvent.change(channelNameInput!, {target: {value: 'Channel'}});
await userEvent.clear(channelNameInput!);
await userEvent.type(channelNameInput!, 'Channel');
const confirmButton = screen.queryByText('Convert to private channel');
expect(channelNameInput).toBeInTheDocument();
await act(async () => {
fireEvent.click(confirmButton!);
});
await userEvent.click(confirmButton!);
expect(screen.queryByText('A channel with that URL already exists')).toBeInTheDocument();
});
@@ -66,10 +66,6 @@ describe('ChannelSelector', () => {
unreadChannels: mockUnreadChannels,
};
beforeEach(() => {
jest.clearAllMocks();
});
describe('Rendering', () => {
it('should render the component with label', () => {
renderWithContext(<ChannelSelector {...defaultProps}/>);
@@ -115,10 +115,6 @@ describe('CreateRecapModal', () => {
},
};
beforeEach(() => {
jest.clearAllMocks();
});
test('should render modal with header including AI agent dropdown', () => {
renderWithContext(<CreateRecapModal {...defaultProps}/>, initialState);
@@ -33,10 +33,6 @@ describe('RecapConfiguration', () => {
unreadChannels: mockUnreadChannels,
};
beforeEach(() => {
jest.clearAllMocks();
});
describe('Recap Name Input', () => {
it('should render name input field', () => {
renderWithContext(<RecapConfiguration {...defaultProps}/>);
@@ -5,7 +5,7 @@ import React from 'react';
import DisplayName from 'components/create_team/components/display_name';
import {renderWithContext, screen, fireEvent, userEvent} from 'tests/react_testing_utils';
import {renderWithContext, screen, userEvent} from 'tests/react_testing_utils';
import {cleanUpUrlable} from 'utils/url';
jest.mock('images/logo.png', () => 'logo.png');
@@ -55,7 +55,8 @@ describe('/components/create_team/components/display_name', () => {
};
const input = screen.getByRole('textbox');
fireEvent.change(input, {target: {value: teamDisplayName}});
await userEvent.clear(input);
await userEvent.type(input, teamDisplayName);
await userEvent.click(screen.getByRole('button', {name: /next/i}));
@@ -26,7 +26,6 @@ describe('components/datetime_input/DateTimeInput', () => {
};
beforeEach(() => {
jest.clearAllMocks();
mockGetCurrentMomentForTimezone.mockReturnValue(moment('2025-06-08T10:00:00Z'));
mockIsBeforeTime.mockReturnValue(false);
});
@@ -55,7 +55,6 @@ describe('components/dialog_router/DialogRouter', () => {
};
beforeEach(() => {
jest.clearAllMocks();
jest.spyOn(console, 'error').mockImplementation(() => {});
});

Some files were not shown because too many files have changed in this diff Show More