diff --git a/webapp/STYLE_GUIDE.md b/webapp/STYLE_GUIDE.md
index 53cf04e667d..d38274c8579 100644
--- a/webapp/STYLE_GUIDE.md
+++ b/webapp/STYLE_GUIDE.md
@@ -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
diff --git a/webapp/channels/src/actions/burn_on_read_deletion.test.ts b/webapp/channels/src/actions/burn_on_read_deletion.test.ts
index 979592c678c..3ba5b604503 100644
--- a/webapp/channels/src/actions/burn_on_read_deletion.test.ts
+++ b/webapp/channels/src/actions/burn_on_read_deletion.test.ts
@@ -13,7 +13,6 @@ describe('burn_on_read_deletion actions', () => {
beforeEach(() => {
mockDispatch = jest.fn();
- jest.clearAllMocks();
});
describe('burnPostNow', () => {
diff --git a/webapp/channels/src/actions/burn_on_read_posts.test.ts b/webapp/channels/src/actions/burn_on_read_posts.test.ts
index 5d2b7e969c1..7f5cbf263d1 100644
--- a/webapp/channels/src/actions/burn_on_read_posts.test.ts
+++ b/webapp/channels/src/actions/burn_on_read_posts.test.ts
@@ -28,10 +28,6 @@ describe('burn_on_read_posts actions', () => {
...mockPost,
};
- beforeEach(() => {
- jest.clearAllMocks();
- });
-
describe('revealBurnOnReadPost', () => {
const mockState = {
entities: {
diff --git a/webapp/channels/src/actions/integration_actions.test.ts b/webapp/channels/src/actions/integration_actions.test.ts
index 51e3d15679e..474ea01bbdb 100644
--- a/webapp/channels/src/actions/integration_actions.test.ts
+++ b/webapp/channels/src/actions/integration_actions.test.ts
@@ -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));
diff --git a/webapp/channels/src/components/access_history_modal/access_history_modal.test.tsx b/webapp/channels/src/components/access_history_modal/access_history_modal.test.tsx
index 8ddf6234cae..cd7ad6cc7a8 100644
--- a/webapp/channels/src/components/access_history_modal/access_history_modal.test.tsx
+++ b/webapp/channels/src/components/access_history_modal/access_history_modal.test.tsx
@@ -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);
});
diff --git a/webapp/channels/src/components/activity_log_modal/activity_log_modal.test.tsx b/webapp/channels/src/components/activity_log_modal/activity_log_modal.test.tsx
index 567561b9636..733fc11ab57 100644
--- a/webapp/channels/src/components/activity_log_modal/activity_log_modal.test.tsx
+++ b/webapp/channels/src/components/activity_log_modal/activity_log_modal.test.tsx
@@ -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);
});
diff --git a/webapp/channels/src/components/admin_console/access_control/modals/policy_test/test_modal.test.tsx b/webapp/channels/src/components/admin_console/access_control/modals/policy_test/test_modal.test.tsx
index 5cd555dd2d3..ee606f92273 100644
--- a/webapp/channels/src/components/admin_console/access_control/modals/policy_test/test_modal.test.tsx
+++ b/webapp/channels/src/components/admin_console/access_control/modals/policy_test/test_modal.test.tsx
@@ -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();
@@ -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);
diff --git a/webapp/channels/src/components/admin_console/blockable_link/blockable_link.test.tsx b/webapp/channels/src/components/admin_console/blockable_link/blockable_link.test.tsx
index b426704f2be..ed39ec65370 100644
--- a/webapp/channels/src/components/admin_console/blockable_link/blockable_link.test.tsx
+++ b/webapp/channels/src/components/admin_console/blockable_link/blockable_link.test.tsx
@@ -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(
,
);
- 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', () => {
,
);
- 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', () => {
,
);
- fireEvent.click(screen.getByText('Link Text'));
+ await userEvent.click(screen.getByText('Link Text'));
expect(onClickProps.onClick).toHaveBeenCalled();
});
diff --git a/webapp/channels/src/components/admin_console/checkbox_setting.test.tsx b/webapp/channels/src/components/admin_console/checkbox_setting.test.tsx
index 4ebd8aea280..a91b2e0703f 100644
--- a/webapp/channels/src/components/admin_console/checkbox_setting.test.tsx
+++ b/webapp/channels/src/components/admin_console/checkbox_setting.test.tsx
@@ -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(
{
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);
diff --git a/webapp/channels/src/components/admin_console/content_flagging/additional_settings/additional_settings.test.tsx b/webapp/channels/src/components/admin_console/content_flagging/additional_settings/additional_settings.test.tsx
index d4366553fae..e14ae0da0ab 100644
--- a/webapp/channels/src/components/admin_console/content_flagging/additional_settings/additional_settings.test.tsx
+++ b/webapp/channels/src/components/admin_console/content_flagging/additional_settings/additional_settings.test.tsx
@@ -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();
@@ -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();
- 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();
- 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();
- 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();
// 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,
diff --git a/webapp/channels/src/components/admin_console/content_flagging/additional_settings/reason_option.test.tsx b/webapp/channels/src/components/admin_console/content_flagging/additional_settings/reason_option.test.tsx
index 8556425a9b4..864c3faea21 100644
--- a/webapp/channels/src/components/admin_console/content_flagging/additional_settings/reason_option.test.tsx
+++ b/webapp/channels/src/components/admin_console/content_flagging/additional_settings/reason_option.test.tsx
@@ -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();
@@ -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();
const removeButton = container.querySelector('.Remove');
- fireEvent.click(removeButton!);
+ await userEvent.click(removeButton!);
expect(mockProps.removeProps.onClick).toHaveBeenCalledTimes(1);
});
diff --git a/webapp/channels/src/components/admin_console/content_flagging/content_reviewers/content_reviewers.test.tsx b/webapp/channels/src/components/admin_console/content_flagging/content_reviewers/content_reviewers.test.tsx
index f48fac4c4ba..14c1ffa5669 100644
--- a/webapp/channels/src/components/admin_console/content_flagging/content_reviewers/content_reviewers.test.tsx
+++ b/webapp/channels/src/components/admin_console/content_flagging/content_reviewers/content_reviewers.test.tsx
@@ -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();
@@ -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();
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();
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();
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();
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();
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();
const changeTeamReviewersButton = screen.getByTestId('team-reviewers-change');
- fireEvent.click(changeTeamReviewersButton);
+ await userEvent.click(changeTeamReviewersButton);
expect(defaultProps.onChange).toHaveBeenCalledWith('content_reviewers', {
...props.value,
diff --git a/webapp/channels/src/components/admin_console/content_flagging/content_reviewers/team_option.test.tsx b/webapp/channels/src/components/admin_console/content_flagging/content_reviewers/team_option.test.tsx
index bf0090eebfe..66de25bfdee 100644
--- a/webapp/channels/src/components/admin_console/content_flagging/content_reviewers/team_option.test.tsx
+++ b/webapp/channels/src/components/admin_console/content_flagging/content_reviewers/team_option.test.tsx
@@ -81,7 +81,6 @@ describe('TeamOptionComponent', () => {
} as unknown as OptionProps, true>;
beforeEach(() => {
- jest.clearAllMocks();
(Utils.imageURLForTeam as jest.Mock).mockReturnValue('http://example.com/team-icon.png');
});
diff --git a/webapp/channels/src/components/admin_console/content_flagging/content_reviewers/team_reviewers_section/team_reviewers_section.test.tsx b/webapp/channels/src/components/admin_console/content_flagging/content_reviewers/team_reviewers_section/team_reviewers_section.test.tsx
index 80b1633b6bc..b70c2957a8d 100644
--- a/webapp/channels/src/components/admin_console/content_flagging/content_reviewers/team_reviewers_section/team_reviewers_section.test.tsx
+++ b/webapp/channels/src/components/admin_console/content_flagging/content_reviewers/team_reviewers_section/team_reviewers_section.test.tsx
@@ -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: {
diff --git a/webapp/channels/src/components/admin_console/content_flagging/notificatin_settings/notification_settings.test.tsx b/webapp/channels/src/components/admin_console/content_flagging/notificatin_settings/notification_settings.test.tsx
index f183574d272..f9419a04752 100644
--- a/webapp/channels/src/components/admin_console/content_flagging/notificatin_settings/notification_settings.test.tsx
+++ b/webapp/channels/src/components/admin_console/content_flagging/notificatin_settings/notification_settings.test.tsx
@@ -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();
@@ -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();
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();
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();
+ // 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();
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();
+ // 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();
// 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();
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'],
diff --git a/webapp/channels/src/components/admin_console/content_flagging/user_multiselector/user_profile_pill.test.tsx b/webapp/channels/src/components/admin_console/content_flagging/user_multiselector/user_profile_pill.test.tsx
index 9a14a7f7ec0..c3cbbf26ec2 100644
--- a/webapp/channels/src/components/admin_console/content_flagging/user_multiselector/user_profile_pill.test.tsx
+++ b/webapp/channels/src/components/admin_console/content_flagging/user_multiselector/user_profile_pill.test.tsx
@@ -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(
,
@@ -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);
});
diff --git a/webapp/channels/src/components/admin_console/custom_enable_disable_guest_accounts_setting.test.tsx b/webapp/channels/src/components/admin_console/custom_enable_disable_guest_accounts_setting.test.tsx
index 4225627a7d0..4fcc255ab3d 100644
--- a/webapp/channels/src/components/admin_console/custom_enable_disable_guest_accounts_setting.test.tsx
+++ b/webapp/channels/src/components/admin_console/custom_enable_disable_guest_accounts_setting.test.tsx
@@ -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);
});
diff --git a/webapp/channels/src/components/admin_console/custom_profile_attributes/custom_profile_attributes.test.tsx b/webapp/channels/src/components/admin_console/custom_profile_attributes/custom_profile_attributes.test.tsx
index fae291d43a4..d6217a1a581 100644
--- a/webapp/channels/src/components/admin_console/custom_profile_attributes/custom_profile_attributes.test.tsx
+++ b/webapp/channels/src/components/admin_console/custom_profile_attributes/custom_profile_attributes.test.tsx
@@ -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(
,
@@ -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(
diff --git a/webapp/channels/src/components/admin_console/ip_filtering/add_edit_ip_filter_modal.test.tsx b/webapp/channels/src/components/admin_console/ip_filtering/add_edit_ip_filter_modal.test.tsx
index 4ee51e6bb65..5706017646f 100644
--- a/webapp/channels/src/components/admin_console/ip_filtering/add_edit_ip_filter_modal.test.tsx
+++ b/webapp/channels/src/components/admin_console/ip_filtering/add_edit_ip_filter_modal.test.tsx
@@ -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(
,
);
- 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();
diff --git a/webapp/channels/src/components/admin_console/ip_filtering/delete_confirmation.test.tsx b/webapp/channels/src/components/admin_console/ip_filtering/delete_confirmation.test.tsx
index ee1fe18c9a3..44888f54099 100644
--- a/webapp/channels/src/components/admin_console/ip_filtering/delete_confirmation.test.tsx
+++ b/webapp/channels/src/components/admin_console/ip_filtering/delete_confirmation.test.tsx
@@ -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(
,
);
- 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);
diff --git a/webapp/channels/src/components/admin_console/ip_filtering/edit_section/edit_section.test.tsx b/webapp/channels/src/components/admin_console/ip_filtering/edit_section/edit_section.test.tsx
index eabd7af23a5..3218183db15 100644
--- a/webapp/channels/src/components/admin_console/ip_filtering/edit_section/edit_section.test.tsx
+++ b/webapp/channels/src/components/admin_console/ip_filtering/edit_section/edit_section.test.tsx
@@ -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(
,
);
- 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(
,
);
- 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(
,
);
- 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,
}));
diff --git a/webapp/channels/src/components/admin_console/ip_filtering/enable_section.test.tsx b/webapp/channels/src/components/admin_console/ip_filtering/enable_section.test.tsx
index 8c68e0e16fb..7e30072751c 100644
--- a/webapp/channels/src/components/admin_console/ip_filtering/enable_section.test.tsx
+++ b/webapp/channels/src/components/admin_console/ip_filtering/enable_section.test.tsx
@@ -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(
,
);
- fireEvent.click(screen.getByTestId('filterToggle-button'));
+ await userEvent.click(screen.getByTestId('filterToggle-button'));
expect(setFilterToggle).toHaveBeenCalledTimes(1);
expect(setFilterToggle).toHaveBeenCalledWith(false);
diff --git a/webapp/channels/src/components/admin_console/ip_filtering/ip_filtering.test.tsx b/webapp/channels/src/components/admin_console/ip_filtering/ip_filtering.test.tsx
index e33c26bddb3..d29ab5530a5 100644
--- a/webapp/channels/src/components/admin_console/ip_filtering/ip_filtering.test.tsx
+++ b/webapp/channels/src/components/admin_console/ip_filtering/ip_filtering.test.tsx
@@ -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(() => {
diff --git a/webapp/channels/src/components/admin_console/ip_filtering/save_confirmation_modal.test.tsx b/webapp/channels/src/components/admin_console/ip_filtering/save_confirmation_modal.test.tsx
index 4ba1c1ae966..056cea56a7f 100644
--- a/webapp/channels/src/components/admin_console/ip_filtering/save_confirmation_modal.test.tsx
+++ b/webapp/channels/src/components/admin_console/ip_filtering/save_confirmation_modal.test.tsx
@@ -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(
,
);
- 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(
,
);
- fireEvent.click(getByText(buttonText));
+ await userEvent.click(getByText(buttonText));
expect(onConfirmMock).toHaveBeenCalledTimes(1);
});
diff --git a/webapp/channels/src/components/admin_console/license_settings/renew_license_card/renew_license_card.test.tsx b/webapp/channels/src/components/admin_console/license_settings/renew_license_card/renew_license_card.test.tsx
index 78d0313c69b..6a265c0ad6e 100644
--- a/webapp/channels/src/components/admin_console/license_settings/renew_license_card/renew_license_card.test.tsx
+++ b/webapp/channels/src/components/admin_console/license_settings/renew_license_card/renew_license_card.test.tsx
@@ -54,10 +54,6 @@ const actImmediate = (wrapper: ReactWrapper) =>
);
describe('components/RenewalLicenseCard', () => {
- afterEach(() => {
- jest.clearAllMocks();
- });
-
const props = {
license: {
id: 'license_id',
diff --git a/webapp/channels/src/components/admin_console/permission_schemes_settings/guest_permissions_tree/guest_permissions_tree.test.tsx b/webapp/channels/src/components/admin_console/permission_schemes_settings/guest_permissions_tree/guest_permissions_tree.test.tsx
index 4b4f712778e..3b75fc3dc1b 100644
--- a/webapp/channels/src/components/admin_console/permission_schemes_settings/guest_permissions_tree/guest_permissions_tree.test.tsx
+++ b/webapp/channels/src/components/admin_console/permission_schemes_settings/guest_permissions_tree/guest_permissions_tree.test.tsx
@@ -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();
diff --git a/webapp/channels/src/components/admin_console/reset_email_modal/reset_email_modal.test.tsx b/webapp/channels/src/components/admin_console/reset_email_modal/reset_email_modal.test.tsx
index 0b3d4203bce..cad93647490 100644
--- a/webapp/channels/src/components/admin_console/reset_email_modal/reset_email_modal.test.tsx
+++ b/webapp/channels/src/components/admin_console/reset_email_modal/reset_email_modal.test.tsx
@@ -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();
diff --git a/webapp/channels/src/components/admin_console/reset_password_modal/reset_password_modal.test.tsx b/webapp/channels/src/components/admin_console/reset_password_modal/reset_password_modal.test.tsx
index 935994b57b7..87bd861aed4 100644
--- a/webapp/channels/src/components/admin_console/reset_password_modal/reset_password_modal.test.tsx
+++ b/webapp/channels/src/components/admin_console/reset_password_modal/reset_password_modal.test.tsx
@@ -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();
diff --git a/webapp/channels/src/components/admin_console/schema_admin_settings.test.tsx b/webapp/channels/src/components/admin_console/schema_admin_settings.test.tsx
index 6746d2461a0..88003c0208d 100644
--- a/webapp/channels/src/components/admin_console/schema_admin_settings.test.tsx
+++ b/webapp/channels/src/components/admin_console/schema_admin_settings.test.tsx
@@ -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';
diff --git a/webapp/channels/src/components/admin_console/system_properties/user_properties_delete_modal.test.tsx b/webapp/channels/src/components/admin_console/system_properties/user_properties_delete_modal.test.tsx
index b3af17e010b..dabccfb4d7c 100644
--- a/webapp/channels/src/components/admin_console/system_properties/user_properties_delete_modal.test.tsx
+++ b/webapp/channels/src/components/admin_console/system_properties/user_properties_delete_modal.test.tsx
@@ -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(
{
expect(screen.getByText('Delete')).toBeInTheDocument();
});
- it('calls onConfirm when confirm button is clicked', () => {
+ it('calls onConfirm when confirm button is clicked', async () => {
renderWithContext(
{
/>,
);
- 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(
{
/>,
);
- fireEvent.click(screen.getByText('Cancel'));
+ await userEvent.click(screen.getByText('Cancel'));
expect(onCancel).toHaveBeenCalledTimes(1);
});
});
diff --git a/webapp/channels/src/components/admin_console/system_properties/user_properties_dot_menu.test.tsx b/webapp/channels/src/components/admin_console/system_properties/user_properties_dot_menu.test.tsx
index 4da526bbf6e..16802efb26a 100644
--- a/webapp/channels/src/components/admin_console/system_properties/user_properties_dot_menu.test.tsx
+++ b/webapp/channels/src/components/admin_console/system_properties/user_properties_dot_menu.test.tsx
@@ -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>) => {
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
diff --git a/webapp/channels/src/components/admin_console/system_properties/user_properties_table.test.tsx b/webapp/channels/src/components/admin_console/system_properties/user_properties_table.test.tsx
index c1c6185484f..907d1008260 100644
--- a/webapp/channels/src/components/admin_console/system_properties/user_properties_table.test.tsx
+++ b/webapp/channels/src/components/admin_console/system_properties/user_properties_table.test.tsx
@@ -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({
diff --git a/webapp/channels/src/components/admin_console/system_properties/user_properties_type_menu.test.tsx b/webapp/channels/src/components/admin_console/system_properties/user_properties_type_menu.test.tsx
index 7d929adf4ec..0d26cf43b72 100644
--- a/webapp/channels/src/components/admin_console/system_properties/user_properties_type_menu.test.tsx
+++ b/webapp/channels/src/components/admin_console/system_properties/user_properties_type_menu.test.tsx
@@ -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');
diff --git a/webapp/channels/src/components/admin_console/system_properties/user_properties_values.test.tsx b/webapp/channels/src/components/admin_console/system_properties/user_properties_values.test.tsx
index 5dc2b367752..6d8c5613133 100644
--- a/webapp/channels/src/components/admin_console/system_properties/user_properties_values.test.tsx
+++ b/webapp/channels/src/components/admin_console/system_properties/user_properties_values.test.tsx
@@ -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();
});
diff --git a/webapp/channels/src/components/admin_console/team_channel_settings/channel/details/channel_level_access_rules.test.tsx b/webapp/channels/src/components/admin_console/team_channel_settings/channel/details/channel_level_access_rules.test.tsx
index 410c5dcb217..4c063169f73 100644
--- a/webapp/channels/src/components/admin_console/team_channel_settings/channel/details/channel_level_access_rules.test.tsx
+++ b/webapp/channels/src/components/admin_console/team_channel_settings/channel/details/channel_level_access_rules.test.tsx
@@ -117,10 +117,6 @@ describe('ChannelLevelAccessRules', () => {
isDisabled: false,
};
- beforeEach(() => {
- jest.clearAllMocks();
- });
-
it('should render the component with correct title and subtitle', () => {
renderWithContext();
diff --git a/webapp/channels/src/components/admin_console/team_channel_settings/team/list/team_list.test.tsx b/webapp/channels/src/components/admin_console/team_channel_settings/team/list/team_list.test.tsx
index f6c58353a43..377e110cf9d 100644
--- a/webapp/channels/src/components/admin_console/team_channel_settings/team/list/team_list.test.tsx
+++ b/webapp/channels/src/components/admin_console/team_channel_settings/team/list/team_list.test.tsx
@@ -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';
diff --git a/webapp/channels/src/components/advanced_text_editor/rewrite_menu.test.tsx b/webapp/channels/src/components/advanced_text_editor/rewrite_menu.test.tsx
index f5a4f979e1a..e318c4ca678 100644
--- a/webapp/channels/src/components/advanced_text_editor/rewrite_menu.test.tsx
+++ b/webapp/channels/src/components/advanced_text_editor/rewrite_menu.test.tsx
@@ -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(),
};
- beforeEach(() => {
- jest.clearAllMocks();
- });
-
test('should not render agent dropdown when no agents', () => {
renderWithContext(
{
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(
{
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(
{
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(
{
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(
{
/>,
);
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(
{
/>,
);
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(
{
/>,
);
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(
{
/>,
);
const select = screen.getByTestId('agent-select');
- fireEvent.change(select, {target: {value: 'agent2'}});
+ await userEvent.selectOptions(select, 'agent2');
expect(setSelectedAgentId).toHaveBeenCalledWith('agent2');
});
});
diff --git a/webapp/channels/src/components/advanced_text_editor/send_button/send_post_options/core_menu_options.test.tsx b/webapp/channels/src/components/advanced_text_editor/send_button/send_post_options/core_menu_options.test.tsx
index 63658edd521..9e202ef1d37 100644
--- a/webapp/channels/src/components/advanced_text_editor/send_button/send_post_options/core_menu_options.test.tsx
+++ b/webapp/channels/src/components/advanced_text_editor/send_button/send_post_options/core_menu_options.test.tsx
@@ -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().
diff --git a/webapp/channels/src/components/advanced_text_editor/send_button/send_post_options/recent_used_custom_date.test.tsx b/webapp/channels/src/components/advanced_text_editor/send_button/send_post_options/recent_used_custom_date.test.tsx
index e84b670772a..2427ed6d980 100644
--- a/webapp/channels/src/components/advanced_text_editor/send_button/send_post_options/recent_used_custom_date.test.tsx
+++ b/webapp/channels/src/components/advanced_text_editor/send_button/send_post_options/recent_used_custom_date.test.tsx
@@ -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);
diff --git a/webapp/channels/src/components/advanced_text_editor/show_formatting/show_formatting.test.tsx b/webapp/channels/src/components/advanced_text_editor/show_formatting/show_formatting.test.tsx
index 4ed2392835f..a78824fa5b4 100644
--- a/webapp/channels/src/components/advanced_text_editor/show_formatting/show_formatting.test.tsx
+++ b/webapp/channels/src/components/advanced_text_editor/show_formatting/show_formatting.test.tsx
@@ -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(
{
/>,
);
- fireEvent.click(screen.getByLabelText('Eye Icon'));
+ await userEvent.click(screen.getByLabelText('Eye Icon'));
expect(onClick).toHaveBeenCalledTimes(1);
});
diff --git a/webapp/channels/src/components/advanced_text_editor/toggle_formatting_bar.test.tsx b/webapp/channels/src/components/advanced_text_editor/toggle_formatting_bar.test.tsx
index 203f6115667..84b14f1e966 100644
--- a/webapp/channels/src/components/advanced_text_editor/toggle_formatting_bar.test.tsx
+++ b/webapp/channels/src/components/advanced_text_editor/toggle_formatting_bar.test.tsx
@@ -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(
{
/>,
);
- 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();
});
diff --git a/webapp/channels/src/components/advanced_text_editor/use_rewrite.test.tsx b/webapp/channels/src/components/advanced_text_editor/use_rewrite.test.tsx
index 4281d4a6ec0..105ad466808 100644
--- a/webapp/channels/src/components/advanced_text_editor/use_rewrite.test.tsx
+++ b/webapp/channels/src/components/advanced_text_editor/use_rewrite.test.tsx
@@ -85,7 +85,6 @@ describe('useRewrite', () => {
};
beforeEach(() => {
- jest.clearAllMocks();
MockedRewriteMenu.mockClear();
document.body.innerHTML = '';
try {
diff --git a/webapp/channels/src/components/announcement_bar/overage_users_banner/overage_users_banner.test.tsx b/webapp/channels/src/components/announcement_bar/overage_users_banner/overage_users_banner.test.tsx
index 941df93c7e6..7e8020531ab 100644
--- a/webapp/channels/src/components/announcement_bar/overage_users_banner/overage_users_banner.test.tsx
+++ b/webapp/channels/src/components/announcement_bar/overage_users_banner/overage_users_banner.test.tsx
@@ -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(, 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(, 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(, 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
diff --git a/webapp/channels/src/components/announcement_bar/post_history_limit_banner/post_history_limit_banner.test.tsx b/webapp/channels/src/components/announcement_bar/post_history_limit_banner/post_history_limit_banner.test.tsx
index 8e594a4358b..acaa5ea9709 100644
--- a/webapp/channels/src/components/announcement_bar/post_history_limit_banner/post_history_limit_banner.test.tsx
+++ b/webapp/channels/src/components/announcement_bar/post_history_limit_banner/post_history_limit_banner.test.tsx
@@ -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(, 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(, state);
const closeButton = screen.getByRole('link', {name: '×'});
- fireEvent.click(closeButton);
+ await userEvent.click(closeButton);
expect(mockDispatch).toHaveBeenCalledWith(
mockSavePreferences(currentUserId, [{
diff --git a/webapp/channels/src/components/announcement_bar/renewal_link/renewal_link.test.tsx b/webapp/channels/src/components/announcement_bar/renewal_link/renewal_link.test.tsx
index 06a2cc6242d..e478fbd025a 100644
--- a/webapp/channels/src/components/announcement_bar/renewal_link/renewal_link.test.tsx
+++ b/webapp/channels/src/components/announcement_bar/renewal_link/renewal_link.test.tsx
@@ -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();
diff --git a/webapp/channels/src/components/apps_form/apps_form_component.test.tsx b/webapp/channels/src/components/apps_form/apps_form_component.test.tsx
index 3222b23b849..ac49c2d9a6c 100644
--- a/webapp/channels/src/components/apps_form/apps_form_component.test.tsx
+++ b/webapp/channels/src/components/apps_form/apps_form_component.test.tsx
@@ -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(
{
};
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();
diff --git a/webapp/channels/src/components/apps_form/apps_form_datetime_field/apps_form_datetime_field.test.tsx b/webapp/channels/src/components/apps_form/apps_form_datetime_field/apps_form_datetime_field.test.tsx
index a3574ca75a3..fd440d690a3 100644
--- a/webapp/channels/src/components/apps_form/apps_form_datetime_field/apps_form_datetime_field.test.tsx
+++ b/webapp/channels/src/components/apps_form/apps_form_datetime_field/apps_form_datetime_field.test.tsx
@@ -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'));
diff --git a/webapp/channels/src/components/burn_on_read/burn_on_read_button.test.tsx b/webapp/channels/src/components/burn_on_read/burn_on_read_button.test.tsx
index 4f4b594b051..0fad31acdf5 100644
--- a/webapp/channels/src/components/burn_on_read/burn_on_read_button.test.tsx
+++ b/webapp/channels/src/components/burn_on_read/burn_on_read_button.test.tsx
@@ -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(
,
@@ -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(
{
);
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(
{
);
const button = screen.getByRole('button');
- fireEvent.click(button);
+ await userEvent.click(button);
expect(onToggle).toHaveBeenCalledTimes(1);
expect(onToggle).toHaveBeenCalledWith(false);
diff --git a/webapp/channels/src/components/burn_on_read/burn_on_read_label.test.tsx b/webapp/channels/src/components/burn_on_read/burn_on_read_label.test.tsx
index ee81b684a4b..0e42f0def18 100644
--- a/webapp/channels/src/components/burn_on_read/burn_on_read_label.test.tsx
+++ b/webapp/channels/src/components/burn_on_read/burn_on_read_label.test.tsx
@@ -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(
,
@@ -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(
{
);
const closeButton = screen.getByRole('button');
- fireEvent.click(closeButton);
+ await userEvent.click(closeButton);
expect(onRemove).toHaveBeenCalledTimes(1);
});
diff --git a/webapp/channels/src/components/burn_on_read_confirmation_modal/burn_on_read_confirmation_modal.test.tsx b/webapp/channels/src/components/burn_on_read_confirmation_modal/burn_on_read_confirmation_modal.test.tsx
index 2fad5e4cae9..c5c7ee3e8b4 100644
--- a/webapp/channels/src/components/burn_on_read_confirmation_modal/burn_on_read_confirmation_modal.test.tsx
+++ b/webapp/channels/src/components/burn_on_read_confirmation_modal/burn_on_read_confirmation_modal.test.tsx
@@ -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();
@@ -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(
{
);
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(
{
);
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(
{
);
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);
});
diff --git a/webapp/channels/src/components/channel_header/channel_header_title.test.tsx b/webapp/channels/src/components/channel_header/channel_header_title.test.tsx
index 3766a91614f..e5e17a3855d 100644
--- a/webapp/channels/src/components/channel_header/channel_header_title.test.tsx
+++ b/webapp/channels/src/components/channel_header/channel_header_title.test.tsx
@@ -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 = {
diff --git a/webapp/channels/src/components/channel_header/channel_header_title_favorite.test.tsx b/webapp/channels/src/components/channel_header/channel_header_title_favorite.test.tsx
index 4bb7b35f7f3..fbd8dd8b1dc 100644
--- a/webapp/channels/src/components/channel_header/channel_header_title_favorite.test.tsx
+++ b/webapp/channels/src/components/channel_header/channel_header_title_favorite.test.tsx
@@ -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();
}
- 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({
diff --git a/webapp/channels/src/components/channel_header_menu/menu_items/add_channel_members.test.tsx b/webapp/channels/src/components/channel_header_menu/menu_items/add_channel_members.test.tsx
index 4e5c358b91d..99fa678eb08 100644
--- a/webapp/channels/src/components/channel_header_menu/menu_items/add_channel_members.test.tsx
+++ b/webapp/channels/src/components/channel_header_menu/menu_items/add_channel_members.test.tsx
@@ -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(
{
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);
diff --git a/webapp/channels/src/components/channel_header_menu/menu_items/add_group_members.test.tsx b/webapp/channels/src/components/channel_header_menu/menu_items/add_group_members.test.tsx
index cc28c3fdb19..d031ccf3ae5 100644
--- a/webapp/channels/src/components/channel_header_menu/menu_items/add_group_members.test.tsx
+++ b/webapp/channels/src/components/channel_header_menu/menu_items/add_group_members.test.tsx
@@ -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(
@@ -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);
diff --git a/webapp/channels/src/components/channel_header_menu/menu_items/archive_channel.test.tsx b/webapp/channels/src/components/channel_header_menu/menu_items/archive_channel.test.tsx
index dc8a757ac16..1b0dbef87b2 100644
--- a/webapp/channels/src/components/channel_header_menu/menu_items/archive_channel.test.tsx
+++ b/webapp/channels/src/components/channel_header_menu/menu_items/archive_channel.test.tsx
@@ -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(
, 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(
@@ -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);
diff --git a/webapp/channels/src/components/channel_header_menu/menu_items/close_channel.test.tsx b/webapp/channels/src/components/channel_header_menu/menu_items/close_channel.test.tsx
index f89ecfaa74c..f7cab404a50 100644
--- a/webapp/channels/src/components/channel_header_menu/menu_items/close_channel.test.tsx
+++ b/webapp/channels/src/components/channel_header_menu/menu_items/close_channel.test.tsx
@@ -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(
@@ -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
});
});
diff --git a/webapp/channels/src/components/channel_header_menu/menu_items/close_message.test.tsx b/webapp/channels/src/components/channel_header_menu/menu_items/close_message.test.tsx
index 1ab8cd5b4bc..8f65fe616c4 100644
--- a/webapp/channels/src/components/channel_header_menu/menu_items/close_message.test.tsx
+++ b/webapp/channels/src/components/channel_header_menu/menu_items/close_message.test.tsx
@@ -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(
{
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(
{
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);
diff --git a/webapp/channels/src/components/channel_header_menu/menu_items/convert_gm_to_private.test.tsx b/webapp/channels/src/components/channel_header_menu/menu_items/convert_gm_to_private.test.tsx
index 45e042698ba..6835da74956 100644
--- a/webapp/channels/src/components/channel_header_menu/menu_items/convert_gm_to_private.test.tsx
+++ b/webapp/channels/src/components/channel_header_menu/menu_items/convert_gm_to_private.test.tsx
@@ -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(
@@ -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({
diff --git a/webapp/channels/src/components/channel_header_menu/menu_items/edit_conversation_header.test.tsx b/webapp/channels/src/components/channel_header_menu/menu_items/edit_conversation_header.test.tsx
index b4c5d64eba0..55425b94394 100644
--- a/webapp/channels/src/components/channel_header_menu/menu_items/edit_conversation_header.test.tsx
+++ b/webapp/channels/src/components/channel_header_menu/menu_items/edit_conversation_header.test.tsx
@@ -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(
@@ -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({
diff --git a/webapp/channels/src/components/channel_header_menu/menu_items/groups.test.tsx b/webapp/channels/src/components/channel_header_menu/menu_items/groups.test.tsx
index a0699880f0e..11023b33a1f 100644
--- a/webapp/channels/src/components/channel_header_menu/menu_items/groups.test.tsx
+++ b/webapp/channels/src/components/channel_header_menu/menu_items/groups.test.tsx
@@ -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(
@@ -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(
@@ -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({
diff --git a/webapp/channels/src/components/channel_header_menu/menu_items/leave_channel.test.tsx b/webapp/channels/src/components/channel_header_menu/menu_items/leave_channel.test.tsx
index b3f031ed822..7f14137c08e 100644
--- a/webapp/channels/src/components/channel_header_menu/menu_items/leave_channel.test.tsx
+++ b/webapp/channels/src/components/channel_header_menu/menu_items/leave_channel.test.tsx
@@ -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({
diff --git a/webapp/channels/src/components/channel_header_menu/menu_items/mobile_channel_header_plugins.test.tsx b/webapp/channels/src/components/channel_header_menu/menu_items/mobile_channel_header_plugins.test.tsx
index a95781414b7..f1d074d8399 100644
--- a/webapp/channels/src/components/channel_header_menu/menu_items/mobile_channel_header_plugins.test.tsx
+++ b/webapp/channels/src/components/channel_header_menu/menu_items/mobile_channel_header_plugins.test.tsx
@@ -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(
{
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);
});
diff --git a/webapp/channels/src/components/channel_header_menu/menu_items/notification.test.tsx b/webapp/channels/src/components/channel_header_menu/menu_items/notification.test.tsx
index 3b2f20d7c29..15f1b3a2654 100644
--- a/webapp/channels/src/components/channel_header_menu/menu_items/notification.test.tsx
+++ b/webapp/channels/src/components/channel_header_menu/menu_items/notification.test.tsx
@@ -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({
diff --git a/webapp/channels/src/components/channel_header_menu/menu_items/open_member_rhs.test.tsx b/webapp/channels/src/components/channel_header_menu/menu_items/open_member_rhs.test.tsx
index 433d84fef7b..c475b8669a8 100644
--- a/webapp/channels/src/components/channel_header_menu/menu_items/open_member_rhs.test.tsx
+++ b/webapp/channels/src/components/channel_header_menu/menu_items/open_member_rhs.test.tsx
@@ -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();
});
});
diff --git a/webapp/channels/src/components/channel_header_menu/menu_items/toggle_favorite_channel.test.tsx b/webapp/channels/src/components/channel_header_menu/menu_items/toggle_favorite_channel.test.tsx
index 8d2e4b9bdcd..6b89546fbe7 100644
--- a/webapp/channels/src/components/channel_header_menu/menu_items/toggle_favorite_channel.test.tsx
+++ b/webapp/channels/src/components/channel_header_menu/menu_items/toggle_favorite_channel.test.tsx
@@ -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(
{
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(
{
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);
});
diff --git a/webapp/channels/src/components/channel_header_menu/menu_items/toggle_info.test.tsx b/webapp/channels/src/components/channel_header_menu/menu_items/toggle_info.test.tsx
index cf09faa08fc..1ec63ad17cb 100644
--- a/webapp/channels/src/components/channel_header_menu/menu_items/toggle_info.test.tsx
+++ b/webapp/channels/src/components/channel_header_menu/menu_items/toggle_info.test.tsx
@@ -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);
});
diff --git a/webapp/channels/src/components/channel_header_menu/menu_items/toggle_mute_channel.test.tsx b/webapp/channels/src/components/channel_header_menu/menu_items/toggle_mute_channel.test.tsx
index c37c33a9168..4b1585bf814 100644
--- a/webapp/channels/src/components/channel_header_menu/menu_items/toggle_mute_channel.test.tsx
+++ b/webapp/channels/src/components/channel_header_menu/menu_items/toggle_mute_channel.test.tsx
@@ -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(
{
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(
{
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(
@@ -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(
@@ -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(
diff --git a/webapp/channels/src/components/channel_header_menu/menu_items/unarchive_channel.test.tsx b/webapp/channels/src/components/channel_header_menu/menu_items/unarchive_channel.test.tsx
index 172405d03a3..a657a86ba77 100644
--- a/webapp/channels/src/components/channel_header_menu/menu_items/unarchive_channel.test.tsx
+++ b/webapp/channels/src/components/channel_header_menu/menu_items/unarchive_channel.test.tsx
@@ -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({
diff --git a/webapp/channels/src/components/channel_header_menu/menu_items/view_pinned_posts.test.tsx b/webapp/channels/src/components/channel_header_menu/menu_items/view_pinned_posts.test.tsx
index 2e205ba9393..1903b4834cf 100644
--- a/webapp/channels/src/components/channel_header_menu/menu_items/view_pinned_posts.test.tsx
+++ b/webapp/channels/src/components/channel_header_menu/menu_items/view_pinned_posts.test.tsx
@@ -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);
});
diff --git a/webapp/channels/src/components/channel_info_rhs/components/editable_area.test.tsx b/webapp/channels/src/components/channel_info_rhs/components/editable_area.test.tsx
index cb2fbead5cd..891faad9114 100644
--- a/webapp/channels/src/components/channel_info_rhs/components/editable_area.test.tsx
+++ b/webapp/channels/src/components/channel_info_rhs/components/editable_area.test.tsx
@@ -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);
});
});
diff --git a/webapp/channels/src/components/channel_info_rhs/header.test.tsx b/webapp/channels/src/components/channel_info_rhs/header.test.tsx
index c041023b11a..542770a9785 100644
--- a/webapp/channels/src/components/channel_info_rhs/header.test.tsx
+++ b/webapp/channels/src/components/channel_info_rhs/header.test.tsx
@@ -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();
});
diff --git a/webapp/channels/src/components/channel_info_rhs/menu.test.tsx b/webapp/channels/src/components/channel_info_rhs/menu.test.tsx
index 293bb271b77..73e1007978d 100644
--- a/webapp/channels/src/components/channel_info_rhs/menu.test.tsx
+++ b/webapp/channels/src/components/channel_info_rhs/menu.test.tsx
@@ -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();
});
diff --git a/webapp/channels/src/components/channel_info_rhs/top_buttons.test.tsx b/webapp/channels/src/components/channel_info_rhs/top_buttons.test.tsx
index 1cc0ca76695..0bb41731b3b 100644
--- a/webapp/channels/src/components/channel_info_rhs/top_buttons.test.tsx
+++ b/webapp/channels/src/components/channel_info_rhs/top_buttons.test.tsx
@@ -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(
{
);
expect(screen.getByText('Copy Link')).toBeInTheDocument();
- fireEvent.click(screen.getByText('Copy Link'));
+ await userEvent.click(screen.getByText('Copy Link'));
expect(mockOnCopyTextClick).toHaveBeenCalled();
});
diff --git a/webapp/channels/src/components/channel_invite_modal/channel_invite_modal.test.tsx b/webapp/channels/src/components/channel_invite_modal/channel_invite_modal.test.tsx
index c512bcc4227..5932707578a 100644
--- a/webapp/channels/src/components/channel_invite_modal/channel_invite_modal.test.tsx
+++ b/webapp/channels/src/components/channel_invite_modal/channel_invite_modal.test.tsx
@@ -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(() => {
diff --git a/webapp/channels/src/components/channel_members_rhs/action_bar.test.tsx b/webapp/channels/src/components/channel_members_rhs/action_bar.test.tsx
index a6a9977beb2..6c75c7b3b8c 100644
--- a/webapp/channels/src/components/channel_members_rhs/action_bar.test.tsx
+++ b/webapp/channels/src/components/channel_members_rhs/action_bar.test.tsx
@@ -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();
});
diff --git a/webapp/channels/src/components/channel_members_rhs/member.test.tsx b/webapp/channels/src/components/channel_members_rhs/member.test.tsx
index 5963495f9bf..ccca8699b7f 100644
--- a/webapp/channels/src/components/channel_members_rhs/member.test.tsx
+++ b/webapp/channels/src/components/channel_members_rhs/member.test.tsx
@@ -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();
});
});
diff --git a/webapp/channels/src/components/channel_notifications_modal/channel_notifications_modal.test.tsx b/webapp/channels/src/components/channel_notifications_modal/channel_notifications_modal.test.tsx
index 581a55e7e5b..4810304a2f5 100644
--- a/webapp/channels/src/components/channel_notifications_modal/channel_notifications_modal.test.tsx
+++ b/webapp/channels/src/components/channel_notifications_modal/channel_notifications_modal.test.tsx
@@ -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';
diff --git a/webapp/channels/src/components/channel_settings_modal/channel_activity_warning_modal.test.tsx b/webapp/channels/src/components/channel_settings_modal/channel_activity_warning_modal.test.tsx
index 52ad2e369a6..91cfdd33c54 100644
--- a/webapp/channels/src/components/channel_settings_modal/channel_activity_warning_modal.test.tsx
+++ b/webapp/channels/src/components/channel_settings_modal/channel_activity_warning_modal.test.tsx
@@ -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(
,
diff --git a/webapp/channels/src/components/channel_settings_modal/channel_settings_access_rules_activity_warning.test.tsx b/webapp/channels/src/components/channel_settings_modal/channel_settings_access_rules_activity_warning.test.tsx
index edf2ce6aad7..cca7eb51f37 100644
--- a/webapp/channels/src/components/channel_settings_modal/channel_settings_access_rules_activity_warning.test.tsx
+++ b/webapp/channels/src/components/channel_settings_modal/channel_settings_access_rules_activity_warning.test.tsx
@@ -185,8 +185,6 @@ describe('ChannelSettingsAccessRulesTab - Activity Warning Integration', () => {
};
beforeEach(() => {
- jest.clearAllMocks();
-
// Set up default mock implementations
mockUseChannelAccessControlActions.mockReturnValue(mockActions);
mockUseChannelSystemPolicies.mockReturnValue({
diff --git a/webapp/channels/src/components/channel_settings_modal/channel_settings_archive_tab.test.tsx b/webapp/channels/src/components/channel_settings_modal/channel_settings_archive_tab.test.tsx
index 0672f56d27c..f5a268350dc 100644
--- a/webapp/channels/src/components/channel_settings_modal/channel_settings_archive_tab.test.tsx
+++ b/webapp/channels/src/components/channel_settings_modal/channel_settings_archive_tab.test.tsx
@@ -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',
diff --git a/webapp/channels/src/components/channel_settings_modal/channel_settings_configuration_tab.test.tsx b/webapp/channels/src/components/channel_settings_modal/channel_settings_configuration_tab.test.tsx
index 0af933044fb..0fee7c555d6 100644
--- a/webapp/channels/src/components/channel_settings_modal/channel_settings_configuration_tab.test.tsx
+++ b/webapp/channels/src/components/channel_settings_modal/channel_settings_configuration_tab.test.tsx
@@ -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();
diff --git a/webapp/channels/src/components/channel_settings_modal/channel_settings_info_tab.test.tsx b/webapp/channels/src/components/channel_settings_modal/channel_settings_info_tab.test.tsx
index 4b7adf94648..6ab2e224606 100644
--- a/webapp/channels/src/components/channel_settings_modal/channel_settings_info_tab.test.tsx
+++ b/webapp/channels/src/components/channel_settings_modal/channel_settings_info_tab.test.tsx
@@ -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;
diff --git a/webapp/channels/src/components/channel_settings_modal/channel_settings_modal.test.tsx b/webapp/channels/src/components/channel_settings_modal/channel_settings_modal.test.tsx
index 89c2071b1af..9aa9e1a1c95 100644
--- a/webapp/channels/src/components/channel_settings_modal/channel_settings_modal.test.tsx
+++ b/webapp/channels/src/components/channel_settings_modal/channel_settings_modal.test.tsx
@@ -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(, makeTestState());
diff --git a/webapp/channels/src/components/cloud_preview_modal/cloud_preview_modal_controller.test.tsx b/webapp/channels/src/components/cloud_preview_modal/cloud_preview_modal_controller.test.tsx
index 2d5fb1fc232..91045358872 100644
--- a/webapp/channels/src/components/cloud_preview_modal/cloud_preview_modal_controller.test.tsx
+++ b/webapp/channels/src/components/cloud_preview_modal/cloud_preview_modal_controller.test.tsx
@@ -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();
diff --git a/webapp/channels/src/components/cloud_preview_modal/preview_modal_content.test.tsx b/webapp/channels/src/components/cloud_preview_modal/preview_modal_content.test.tsx
index 7a592f0439d..1700ebb4ab0 100644
--- a/webapp/channels/src/components/cloud_preview_modal/preview_modal_content.test.tsx
+++ b/webapp/channels/src/components/cloud_preview_modal/preview_modal_content.test.tsx
@@ -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();
diff --git a/webapp/channels/src/components/cloud_preview_modal/preview_modal_content_controller.test.tsx b/webapp/channels/src/components/cloud_preview_modal/preview_modal_content_controller.test.tsx
index d83a43cdda2..121b8762767 100644
--- a/webapp/channels/src/components/cloud_preview_modal/preview_modal_content_controller.test.tsx
+++ b/webapp/channels/src/components/cloud_preview_modal/preview_modal_content_controller.test.tsx
@@ -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);
});
diff --git a/webapp/channels/src/components/color_input.test.tsx b/webapp/channels/src/components/color_input.test.tsx
index cad3b93f2fa..85e16ca2dd7 100644
--- a/webapp/channels/src/components/color_input.test.tsx
+++ b/webapp/channels/src/components/color_input.test.tsx
@@ -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)');
diff --git a/webapp/channels/src/components/common/agents/agent_dropdown.test.tsx b/webapp/channels/src/components/common/agents/agent_dropdown.test.tsx
index f4e90d60646..3fc30b9ba9e 100644
--- a/webapp/channels/src/components/common/agents/agent_dropdown.test.tsx
+++ b/webapp/channels/src/components/common/agents/agent_dropdown.test.tsx
@@ -41,10 +41,6 @@ describe('AgentDropdown', () => {
defaultBotId: 'bot1',
};
- beforeEach(() => {
- jest.clearAllMocks();
- });
-
test('should render with selected bot name', () => {
renderWithContext();
diff --git a/webapp/channels/src/components/common/hooks/useAccessControlAttributes.test.tsx b/webapp/channels/src/components/common/hooks/useAccessControlAttributes.test.tsx
index 07d8d8c97de..35c4113e578 100644
--- a/webapp/channels/src/components/common/hooks/useAccessControlAttributes.test.tsx
+++ b/webapp/channels/src/components/common/hooks/useAccessControlAttributes.test.tsx
@@ -59,10 +59,6 @@ describe('useAccessControlAttributes', () => {
);
- beforeEach(() => {
- jest.clearAllMocks();
- });
-
test('should return initial state', () => {
const {result} = renderHook(() => useAccessControlAttributes(EntityType.Channel, undefined, undefined), {wrapper});
diff --git a/webapp/channels/src/components/common/infinite_scroll.test.tsx b/webapp/channels/src/components/common/infinite_scroll.test.tsx
index 7237085f0c1..ec0f0838129 100644
--- a/webapp/channels/src/components/common/infinite_scroll.test.tsx
+++ b/webapp/channels/src/components/common/infinite_scroll.test.tsx
@@ -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
diff --git a/webapp/channels/src/components/common/scrollbars.test.tsx b/webapp/channels/src/components/common/scrollbars.test.tsx
index 1baaf7ca48b..0f234d3b0db 100644
--- a/webapp/channels/src/components/common/scrollbars.test.tsx
+++ b/webapp/channels/src/components/common/scrollbars.test.tsx
@@ -32,7 +32,7 @@ describe('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();
diff --git a/webapp/channels/src/components/convert_channel_modal/convert_channel_modal.test.tsx b/webapp/channels/src/components/convert_channel_modal/convert_channel_modal.test.tsx
index a8d416eabba..eca6893c9b9 100644
--- a/webapp/channels/src/components/convert_channel_modal/convert_channel_modal.test.tsx
+++ b/webapp/channels/src/components/convert_channel_modal/convert_channel_modal.test.tsx
@@ -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();
- 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();
- 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();
diff --git a/webapp/channels/src/components/convert_gm_to_channel_modal/convert_gm_to_channel_modal.test.tsx b/webapp/channels/src/components/convert_gm_to_channel_modal/convert_gm_to_channel_modal.test.tsx
index e0f7a9390d6..744f6437ac9 100644
--- a/webapp/channels/src/components/convert_gm_to_channel_modal/convert_gm_to_channel_modal.test.tsx
+++ b/webapp/channels/src/components/convert_gm_to_channel_modal/convert_gm_to_channel_modal.test.tsx
@@ -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();
});
diff --git a/webapp/channels/src/components/create_recap_modal/channel_selector.test.tsx b/webapp/channels/src/components/create_recap_modal/channel_selector.test.tsx
index 831e719af6b..5b4ca75a3cc 100644
--- a/webapp/channels/src/components/create_recap_modal/channel_selector.test.tsx
+++ b/webapp/channels/src/components/create_recap_modal/channel_selector.test.tsx
@@ -66,10 +66,6 @@ describe('ChannelSelector', () => {
unreadChannels: mockUnreadChannels,
};
- beforeEach(() => {
- jest.clearAllMocks();
- });
-
describe('Rendering', () => {
it('should render the component with label', () => {
renderWithContext();
diff --git a/webapp/channels/src/components/create_recap_modal/create_recap_modal.test.tsx b/webapp/channels/src/components/create_recap_modal/create_recap_modal.test.tsx
index fdbeea861c7..8d3d675cd63 100644
--- a/webapp/channels/src/components/create_recap_modal/create_recap_modal.test.tsx
+++ b/webapp/channels/src/components/create_recap_modal/create_recap_modal.test.tsx
@@ -115,10 +115,6 @@ describe('CreateRecapModal', () => {
},
};
- beforeEach(() => {
- jest.clearAllMocks();
- });
-
test('should render modal with header including AI agent dropdown', () => {
renderWithContext(, initialState);
diff --git a/webapp/channels/src/components/create_recap_modal/recap_configuration.test.tsx b/webapp/channels/src/components/create_recap_modal/recap_configuration.test.tsx
index 72ab574229d..a7bdb94c236 100644
--- a/webapp/channels/src/components/create_recap_modal/recap_configuration.test.tsx
+++ b/webapp/channels/src/components/create_recap_modal/recap_configuration.test.tsx
@@ -33,10 +33,6 @@ describe('RecapConfiguration', () => {
unreadChannels: mockUnreadChannels,
};
- beforeEach(() => {
- jest.clearAllMocks();
- });
-
describe('Recap Name Input', () => {
it('should render name input field', () => {
renderWithContext();
diff --git a/webapp/channels/src/components/create_team/components/display_name.test.tsx b/webapp/channels/src/components/create_team/components/display_name.test.tsx
index 02b886ae463..076374a7691 100644
--- a/webapp/channels/src/components/create_team/components/display_name.test.tsx
+++ b/webapp/channels/src/components/create_team/components/display_name.test.tsx
@@ -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}));
diff --git a/webapp/channels/src/components/datetime_input/datetime_input.test.tsx b/webapp/channels/src/components/datetime_input/datetime_input.test.tsx
index b0e5af5a550..fd8022d70a8 100644
--- a/webapp/channels/src/components/datetime_input/datetime_input.test.tsx
+++ b/webapp/channels/src/components/datetime_input/datetime_input.test.tsx
@@ -26,7 +26,6 @@ describe('components/datetime_input/DateTimeInput', () => {
};
beforeEach(() => {
- jest.clearAllMocks();
mockGetCurrentMomentForTimezone.mockReturnValue(moment('2025-06-08T10:00:00Z'));
mockIsBeforeTime.mockReturnValue(false);
});
diff --git a/webapp/channels/src/components/dialog_router/dialog_router.test.tsx b/webapp/channels/src/components/dialog_router/dialog_router.test.tsx
index 0a4df2c3526..2bb23c6bb02 100644
--- a/webapp/channels/src/components/dialog_router/dialog_router.test.tsx
+++ b/webapp/channels/src/components/dialog_router/dialog_router.test.tsx
@@ -55,7 +55,6 @@ describe('components/dialog_router/DialogRouter', () => {
};
beforeEach(() => {
- jest.clearAllMocks();
jest.spyOn(console, 'error').mockImplementation(() => {});
});
diff --git a/webapp/channels/src/components/dot_menu/dot_menu.test.tsx b/webapp/channels/src/components/dot_menu/dot_menu.test.tsx
index 0d42d511ae4..82f16b90585 100644
--- a/webapp/channels/src/components/dot_menu/dot_menu.test.tsx
+++ b/webapp/channels/src/components/dot_menu/dot_menu.test.tsx
@@ -1,15 +1,13 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
-import {fireEvent, screen} from '@testing-library/react';
-import userEvent from '@testing-library/user-event';
import React from 'react';
import type {ChannelType} from '@mattermost/types/channels';
import type {Post, PostType} from '@mattermost/types/posts';
import type {DeepPartial} from '@mattermost/types/utilities';
-import {renderWithContext} from 'tests/react_testing_utils';
+import {renderWithContext, screen, userEvent} from 'tests/react_testing_utils';
import {Locations} from 'utils/constants';
import {TestHelper} from 'utils/test_helper';
@@ -335,7 +333,8 @@ describe('components/dot_menu/DotMenu', () => {
// Simulate pressing 'W' key while menu is open
const menu = screen.getByRole('menu');
- fireEvent.keyDown(menu, {key: 'W', code: 'KeyW', keyCode: 87});
+ menu.focus();
+ await userEvent.keyboard('W');
// Move thread should not be triggered (menu item doesn't exist, so no way to verify the action wasn't called)
// The fact that canMove is false means the menu item is hidden and keyboard shortcut is blocked
@@ -454,7 +453,7 @@ describe('components/dot_menu/DotMenu', () => {
});
});
- test('should show flag post menu option when allowed', () => {
+ test('should show flag post menu option when allowed', async () => {
const props = {
...baseProps,
post: post1,
@@ -465,13 +464,13 @@ describe('components/dot_menu/DotMenu', () => {
);
const button = screen.getByTestId(`PostDotMenu-Button-${post1.id}`);
- fireEvent.click(button);
+ await userEvent.click(button);
const flagPostOption = screen.getByTestId(`flag_post_${post1.id}`);
expect(flagPostOption).toBeVisible();
});
- test('should not show flag post menu option for DM channel even when enabled', () => {
+ test('should not show flag post menu option for DM channel even when enabled', async () => {
const props = {
...baseProps,
post: dmPost,
@@ -482,13 +481,13 @@ describe('components/dot_menu/DotMenu', () => {
);
const button = screen.getByTestId(`PostDotMenu-Button-${dmPost.id}`);
- fireEvent.click(button);
+ await userEvent.click(button);
const flagPostOption = screen.queryByTestId(`flag_post_${dmPost.id}`);
expect(flagPostOption).toBeNull();
});
- test('should not show flag post menu option for GM channel even when enabled', () => {
+ test('should not show flag post menu option for GM channel even when enabled', async () => {
const props = {
...baseProps,
post: gmPost,
@@ -499,13 +498,13 @@ describe('components/dot_menu/DotMenu', () => {
);
const button = screen.getByTestId(`PostDotMenu-Button-${gmPost.id}`);
- fireEvent.click(button);
+ await userEvent.click(button);
const flagPostOption = screen.queryByTestId(`flag_post_${gmPost.id}`);
expect(flagPostOption).toBeNull();
});
- test('should not show flag post menu option for burn on read posts', () => {
+ test('should not show flag post menu option for burn on read posts', async () => {
const burnOnReadPost: Post = {
...post1,
type: 'burn_on_read',
@@ -517,13 +516,13 @@ describe('components/dot_menu/DotMenu', () => {
renderWithContext(, initialState);
const button = screen.getByTestId(`PostDotMenu-Button-${post1.id}`);
- fireEvent.click(button);
+ await userEvent.click(button);
const flagPostOption = screen.queryByTestId(`flag_post_${post1.id}`);
expect(flagPostOption).toBeNull();
});
- test('should show copy link for burn-on-read post sender', () => {
+ test('should show copy link for burn-on-read post sender', async () => {
const borPost = {
...post1,
type: 'burn_on_read' as PostType,
@@ -552,13 +551,13 @@ describe('components/dot_menu/DotMenu', () => {
);
const button = screen.getByTestId(`PostDotMenu-Button-${borPost.id}`);
- fireEvent.click(button);
+ await userEvent.click(button);
const copyLinkOption = screen.queryByTestId(`permalink_${borPost.id}`);
expect(copyLinkOption).not.toBeNull();
});
- test('should not show copy link for burn-on-read post receiver', () => {
+ test('should not show copy link for burn-on-read post receiver', async () => {
const borPost = {
...post1,
type: 'burn_on_read' as PostType,
@@ -587,13 +586,13 @@ describe('components/dot_menu/DotMenu', () => {
);
const button = screen.getByTestId(`PostDotMenu-Button-${borPost.id}`);
- fireEvent.click(button);
+ await userEvent.click(button);
const copyLinkOption = screen.queryByTestId(`permalink_${borPost.id}`);
expect(copyLinkOption).toBeNull();
});
- test('should not trigger reply when pressing R key on burn-on-read post', () => {
+ test('should not trigger reply when pressing R key on burn-on-read post', async () => {
const borPost = {
...post1,
type: 'burn_on_read' as PostType,
@@ -621,7 +620,7 @@ describe('components/dot_menu/DotMenu', () => {
renderWithContext(, stateWithBorPost);
const button = screen.getByTestId(`PostDotMenu-Button-${borPost.id}`);
- fireEvent.click(button);
+ await userEvent.click(button);
// Reply option should not be visible for BoR posts
const replyOption = screen.queryByTestId(`reply_to_post_${borPost.id}`);
@@ -629,7 +628,8 @@ describe('components/dot_menu/DotMenu', () => {
// Simulate pressing 'R' key while menu is open - should do nothing
const menu = screen.getByRole('menu');
- fireEvent.keyDown(menu, {key: 'R', code: 'KeyR', keyCode: 82});
+ menu.focus();
+ await userEvent.keyboard('R');
// Since reply option doesn't exist, keyboard shortcut should be blocked (no way to verify action wasn't called, but menu item being hidden confirms it)
expect(replyOption).toBeNull();
diff --git a/webapp/channels/src/components/drafts/draft_actions/schedule_post_actions/scheduled_post_actions.test.tsx b/webapp/channels/src/components/drafts/draft_actions/schedule_post_actions/scheduled_post_actions.test.tsx
index 021c9dee814..c6b739e2843 100644
--- a/webapp/channels/src/components/drafts/draft_actions/schedule_post_actions/scheduled_post_actions.test.tsx
+++ b/webapp/channels/src/components/drafts/draft_actions/schedule_post_actions/scheduled_post_actions.test.tsx
@@ -82,12 +82,6 @@ describe('ScheduledPostActions Component', () => {
let getMyChannelMembershipsnMock: jest.SpyInstance;
beforeEach(() => {
- jest.clearAllMocks();
- });
-
- beforeEach(() => {
- jest.clearAllMocks();
-
isCurrentUserSystemAdminMock = jest.spyOn(usersSelectors, 'isCurrentUserSystemAdmin');
getMyChannelMembershipsnMock = jest.spyOn(commonSelectors, 'getMyChannelMemberships');
diff --git a/webapp/channels/src/components/dynamic_virtualized_list/list_item.test.tsx b/webapp/channels/src/components/dynamic_virtualized_list/list_item.test.tsx
index e64d4ae07eb..8d2de193937 100644
--- a/webapp/channels/src/components/dynamic_virtualized_list/list_item.test.tsx
+++ b/webapp/channels/src/components/dynamic_virtualized_list/list_item.test.tsx
@@ -40,10 +40,6 @@ describe('ListItem', () => {
onUnmount: jest.fn(),
};
- beforeEach(() => {
- jest.clearAllMocks();
- });
-
test('renders the item content correctly', () => {
render();
diff --git a/webapp/channels/src/components/file_attachment/file_attachment.test.tsx b/webapp/channels/src/components/file_attachment/file_attachment.test.tsx
index d706013e4e3..3fffcb2deee 100644
--- a/webapp/channels/src/components/file_attachment/file_attachment.test.tsx
+++ b/webapp/channels/src/components/file_attachment/file_attachment.test.tsx
@@ -1,13 +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 {screen} from '@testing-library/react';
import React from 'react';
import type {GlobalState} from '@mattermost/types/store';
import type {DeepPartial} from '@mattermost/types/utilities';
-import {renderWithContext} from 'tests/react_testing_utils';
+import {renderWithContext, userEvent} from 'tests/react_testing_utils';
import {TestHelper} from 'utils/test_helper';
import FileAttachment from './file_attachment';
@@ -168,13 +168,13 @@ describe('FileAttachment', () => {
expect(container).toMatchSnapshot();
});
- test('should blur file attachment link after click', () => {
+ test('should blur file attachment link after click', async () => {
const props = {...baseProps, compactDisplay: true};
renderWithContext();
const link = screen.getByText(baseProps.fileInfo.name);
const blur = jest.spyOn(link, 'blur');
- fireEvent.click(link);
+ await userEvent.click(link);
expect(blur).toHaveBeenCalled();
});
diff --git a/webapp/channels/src/components/flag_message_modal/flag_post_modal.test.tsx b/webapp/channels/src/components/flag_message_modal/flag_post_modal.test.tsx
index d5a576b280d..3d5c898ac2f 100644
--- a/webapp/channels/src/components/flag_message_modal/flag_post_modal.test.tsx
+++ b/webapp/channels/src/components/flag_message_modal/flag_post_modal.test.tsx
@@ -1,15 +1,13 @@
// 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 {DeepPartial} from '@mattermost/types/utilities';
import {Client4} from 'mattermost-redux/client';
-import {renderWithContext} from 'tests/react_testing_utils';
+import {renderWithContext, screen, userEvent, waitFor} from 'tests/react_testing_utils';
import {TestHelper} from 'utils/test_helper';
import type {GlobalState} from 'types/store';
diff --git a/webapp/channels/src/components/info_toast/info_toast.test.tsx b/webapp/channels/src/components/info_toast/info_toast.test.tsx
index 3ae6decc0eb..44c1793c679 100644
--- a/webapp/channels/src/components/info_toast/info_toast.test.tsx
+++ b/webapp/channels/src/components/info_toast/info_toast.test.tsx
@@ -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 type {ComponentProps} from 'react';
import {CheckIcon} from '@mattermost/compass-icons/components';
+import {render, screen, userEvent} from 'tests/react_testing_utils';
+
import InfoToast from './info_toast';
describe('components/InfoToast', () => {
@@ -25,18 +26,18 @@ describe('components/InfoToast', () => {
expect(container).toMatchSnapshot();
});
- test('should close the toast on undo', () => {
+ test('should close the toast on undo', async () => {
render();
- fireEvent.click(screen.getByText(/undo/i));
+ await userEvent.click(screen.getByText(/undo/i));
expect(baseProps.content.undo).toHaveBeenCalled();
expect(baseProps.onExited).toHaveBeenCalled();
});
- test('should close the toast on close button click', () => {
+ test('should close the toast on close button click', async () => {
render();
- fireEvent.click(screen.getByRole('button', {name: /close/i}));
+ await userEvent.click(screen.getByRole('button', {name: /close/i}));
expect(baseProps.onExited).toHaveBeenCalled();
});
});
diff --git a/webapp/channels/src/components/invitation_modal/overage_users_banner_notice/overage_users_banner_notice.test.tsx b/webapp/channels/src/components/invitation_modal/overage_users_banner_notice/overage_users_banner_notice.test.tsx
index 8bd8b703e93..b6b11897ae6 100644
--- a/webapp/channels/src/components/invitation_modal/overage_users_banner_notice/overage_users_banner_notice.test.tsx
+++ b/webapp/channels/src/components/invitation_modal/overage_users_banner_notice/overage_users_banner_notice.test.tsx
@@ -9,9 +9,9 @@ import {savePreferences} from 'mattermost-redux/actions/preferences';
import {General} from 'mattermost-redux/constants';
import {
- fireEvent,
renderWithContext,
screen,
+ userEvent,
} from 'tests/react_testing_utils';
import {LicenseLinks, OverActiveUserLimits, Preferences, SelfHostedProducts, StatTypes} from 'utils/constants';
import {TestHelper} from 'utils/test_helper';
@@ -199,7 +199,7 @@ describe('components/invitation_modal/overage_users_banner_notice', () => {
expect(screen.getByText(notifyText, {exact: false})).toBeInTheDocument();
});
- it('should track if the admin click Contact Sales CTA in a 5% overage state', () => {
+ it('should track if the admin click Contact Sales CTA in a 5% overage state', async () => {
const store: GlobalState = JSON.parse(JSON.stringify(initialState));
store.entities.admin = {
@@ -218,7 +218,7 @@ describe('components/invitation_modal/overage_users_banner_notice', () => {
store,
);
- fireEvent.click(screen.getByText(contactSalesTextLink));
+ await userEvent.click(screen.getByText(contactSalesTextLink));
expect(screen.getByRole('link')).toHaveAttribute(
'href',
LicenseLinks.CONTACT_SALES +
@@ -255,7 +255,7 @@ describe('components/invitation_modal/overage_users_banner_notice', () => {
expect(screen.getByText(notifyText, {exact: false})).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: GlobalState = JSON.parse(JSON.stringify(initialState));
store.entities.admin = {
@@ -270,7 +270,7 @@ describe('components/invitation_modal/overage_users_banner_notice', () => {
store,
);
- fireEvent.click(screen.getByRole('button'));
+ await userEvent.click(screen.getByRole('button'));
expect(savePreferences).toHaveBeenCalledTimes(1);
expect(savePreferences).toHaveBeenCalledWith(store.entities.users.profiles.current_user.id, [{
@@ -300,7 +300,7 @@ describe('components/invitation_modal/overage_users_banner_notice', () => {
expect(screen.getByText(notifyText, {exact: false})).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: GlobalState = JSON.parse(JSON.stringify(initialState));
store.entities.admin = {
@@ -319,7 +319,7 @@ describe('components/invitation_modal/overage_users_banner_notice', () => {
store,
);
- fireEvent.click(screen.getByText(contactSalesTextLink));
+ await userEvent.click(screen.getByText(contactSalesTextLink));
expect(screen.getByRole('link')).toHaveAttribute(
'href',
LicenseLinks.CONTACT_SALES +
@@ -385,7 +385,7 @@ describe('components/invitation_modal/overage_users_banner_notice', () => {
expect(screen.queryByText(notifyText, {exact: false})).not.toBeInTheDocument();
});
- it('should save preferences for the banner because we are over 10% and we don\'t have preferences', () => {
+ it('should save preferences for the banner because we are over 10% and we don\'t have preferences', async () => {
const store: GlobalState = JSON.parse(JSON.stringify(initialState));
store.entities.admin = {
@@ -400,7 +400,7 @@ describe('components/invitation_modal/overage_users_banner_notice', () => {
store,
);
- fireEvent.click(screen.getByRole('button'));
+ await userEvent.click(screen.getByRole('button'));
expect(savePreferences).toHaveBeenCalledTimes(1);
expect(savePreferences).toHaveBeenCalledWith(store.entities.users.profiles.current_user.id, [{
diff --git a/webapp/channels/src/components/login/login.test.tsx b/webapp/channels/src/components/login/login.test.tsx
index c8b8bba03af..2f901fb0890 100644
--- a/webapp/channels/src/components/login/login.test.tsx
+++ b/webapp/channels/src/components/login/login.test.tsx
@@ -112,10 +112,6 @@ describe('components/login/Login', () => {
LocalStorageStore.setWasLoggedIn(false);
});
- afterEach(() => {
- jest.clearAllMocks();
- });
-
it('should match snapshot', () => {
renderWithContext(
,
diff --git a/webapp/channels/src/components/markdown_image/markdown_image.test.tsx b/webapp/channels/src/components/markdown_image/markdown_image.test.tsx
index de88f9ec8f9..ad062e508dd 100644
--- a/webapp/channels/src/components/markdown_image/markdown_image.test.tsx
+++ b/webapp/channels/src/components/markdown_image/markdown_image.test.tsx
@@ -77,7 +77,7 @@ describe('components/MarkdownImage', () => {
expect(img).toBeInTheDocument();
expect(img).not.toHaveClass('broken-image');
- // Simulate load failure
+ // Simulate image error event - fireEvent used because userEvent doesn't support image loading events
fireEvent.error(img!);
// After load failure, image should have broken-image class
@@ -101,7 +101,6 @@ describe('components/MarkdownImage', () => {
const img = container.querySelector('img');
- // Simulate load failure
fireEvent.error(img!);
expect(container.querySelector('img')).toHaveClass('broken-image');
@@ -161,7 +160,7 @@ describe('components/MarkdownImage', () => {
Object.defineProperty(img, 'naturalHeight', {value: 90, configurable: true});
Object.defineProperty(img, 'naturalWidth', {value: 1041, configurable: true});
- // Simulate successful load
+ // Simulate image load event - fireEvent used because userEvent doesn't support image loading events
fireEvent.load(img!);
// After load, should not have loading class and onImageLoaded should be called
@@ -186,7 +185,6 @@ describe('components/MarkdownImage', () => {
Object.defineProperty(img, 'naturalHeight', {value: 90, configurable: true});
Object.defineProperty(img, 'naturalWidth', {value: 100, configurable: true});
- // Simulate load
fireEvent.load(img!);
expect(container).toMatchSnapshot();
@@ -204,7 +202,6 @@ describe('components/MarkdownImage', () => {
Object.defineProperty(img, 'naturalHeight', {value: 90, configurable: true});
Object.defineProperty(img, 'naturalWidth', {value: 1041, configurable: true});
- // Simulate load
fireEvent.load(img!);
// After load, should have hover and cursor classes for clickable preview
@@ -226,7 +223,6 @@ describe('components/MarkdownImage', () => {
Object.defineProperty(img, 'naturalHeight', {value: 90, configurable: true});
Object.defineProperty(img, 'naturalWidth', {value: 1041, configurable: true});
- // Simulate load
fireEvent.load(img!);
// When imageIsLink, should have no-border class and not cursor--pointer
@@ -248,7 +244,6 @@ describe('components/MarkdownImage', () => {
Object.defineProperty(img, 'naturalHeight', {value: 90, configurable: true});
Object.defineProperty(img, 'naturalWidth', {value: 1041, configurable: true});
- // Simulate load
fireEvent.load(img!);
// Click the image to trigger showModal
@@ -269,7 +264,6 @@ describe('components/MarkdownImage', () => {
Object.defineProperty(img, 'naturalHeight', {value: 90, configurable: true});
Object.defineProperty(img, 'naturalWidth', {value: 1041, configurable: true});
- // Simulate load
fireEvent.load(img!);
// After load, should have scaled-down class
@@ -300,7 +294,6 @@ describe('components/MarkdownImage', () => {
Object.defineProperty(img, 'naturalHeight', {value: 76, configurable: true});
Object.defineProperty(img, 'naturalWidth', {value: 50, configurable: true});
- // Simulate load to get final state
fireEvent.load(img!);
expect(img).toHaveAttribute('width', '50');
@@ -331,7 +324,6 @@ describe('components/MarkdownImage', () => {
Object.defineProperty(img, 'naturalHeight', {value: 250, configurable: true});
Object.defineProperty(img, 'naturalWidth', {value: 50, configurable: true});
- // Simulate load
fireEvent.load(img!);
expect(container).toMatchSnapshot();
@@ -360,7 +352,6 @@ describe('components/MarkdownImage', () => {
Object.defineProperty(img, 'naturalHeight', {value: 250, configurable: true});
Object.defineProperty(img, 'naturalWidth', {value: 50, configurable: true});
- // Simulate load
fireEvent.load(img!);
expect(container).toMatchSnapshot();
diff --git a/webapp/channels/src/components/more_direct_channels/list_item/user_details/user_details.test.tsx b/webapp/channels/src/components/more_direct_channels/list_item/user_details/user_details.test.tsx
index 40c0bf94e80..b0b251b15e8 100644
--- a/webapp/channels/src/components/more_direct_channels/list_item/user_details/user_details.test.tsx
+++ b/webapp/channels/src/components/more_direct_channels/list_item/user_details/user_details.test.tsx
@@ -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 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 UserDetails from './user_details';
@@ -246,6 +245,5 @@ describe('components/more_direct_channels/list_item/user_details/UserDetails', (
afterEach(() => {
jest.clearAllTimers();
jest.useRealTimers();
- jest.clearAllMocks();
});
});
diff --git a/webapp/channels/src/components/new_channel_modal/new_channel_modal.test.tsx b/webapp/channels/src/components/new_channel_modal/new_channel_modal.test.tsx
index 59eb1bcaeb6..b0cc6bd1399 100644
--- a/webapp/channels/src/components/new_channel_modal/new_channel_modal.test.tsx
+++ b/webapp/channels/src/components/new_channel_modal/new_channel_modal.test.tsx
@@ -267,9 +267,11 @@ describe('components/new_channel_modal', () => {
const ChannelPurposeTextArea = screen.getByLabelText('Channel Purpose');
expect(ChannelPurposeTextArea).toBeInTheDocument();
+ // Simulate user interaction with purpose field including focus/blur for validation - fireEvent used because userEvent doesn't have direct focus/blur methods
await act(async () => {
fireEvent.focus(ChannelPurposeTextArea);
- fireEvent.change(ChannelPurposeTextArea, {target: {value}});
+ await userEvent.clear(ChannelPurposeTextArea);
+ await userEvent.type(ChannelPurposeTextArea, value);
fireEvent.blur(ChannelPurposeTextArea);
});
diff --git a/webapp/channels/src/components/new_search/new_search.test.tsx b/webapp/channels/src/components/new_search/new_search.test.tsx
index 1cd8336f130..4d5a2f6a0cd 100644
--- a/webapp/channels/src/components/new_search/new_search.test.tsx
+++ b/webapp/channels/src/components/new_search/new_search.test.tsx
@@ -96,6 +96,7 @@ describe('components/new_search/NewSearch', () => {
expect(screen.queryByText('Messages')).not.toBeInTheDocument();
+ // Trigger global keyboard shortcut (Ctrl+Shift+F) to open search from any element - fireEvent used because userEvent.keyboard requires element focus
await act(() => fireEvent.keyDown(
screen.getByText('Outside'),
{key: 'f', code: 'KeyF', keyCode: 70, charCode: 70, ctrlKey: true, shiftKey: true},
diff --git a/webapp/channels/src/components/new_search/search_box.test.tsx b/webapp/channels/src/components/new_search/search_box.test.tsx
index 2027f4fa392..f90477686dd 100644
--- a/webapp/channels/src/components/new_search/search_box.test.tsx
+++ b/webapp/channels/src/components/new_search/search_box.test.tsx
@@ -8,7 +8,6 @@ import type {Team} from '@mattermost/types/teams';
import {
renderWithContext,
screen,
- fireEvent,
userEvent,
} from 'tests/react_testing_utils';
@@ -51,28 +50,32 @@ describe('components/new_search/SearchBox', () => {
expect(screen.getByText('Ext:')).toBeInTheDocument();
});
- test('should call close on esc keydown', () => {
+ test('should call close on esc keydown', async () => {
renderWithContext();
- fireEvent.keyDown(screen.getByPlaceholderText('Search messages'), {key: 'Escape', code: 'Escape'});
+ const input = screen.getByPlaceholderText('Search messages');
+ input.focus();
+ await userEvent.keyboard('{Escape}');
expect(baseProps.onClose).toHaveBeenCalledTimes(1);
});
- test('should call search on enter keydown', () => {
+ test('should call search on enter keydown', async () => {
renderWithContext();
- fireEvent.keyDown(screen.getByPlaceholderText('Search messages'), {key: 'Enter', code: 'Enter'});
+ const input = screen.getByPlaceholderText('Search messages');
+ input.focus();
+ await userEvent.keyboard('{Enter}');
expect(baseProps.onSearch).toHaveBeenCalledTimes(1);
});
test('should be able to select with the up and down arrows', async () => {
renderWithContext();
await userEvent.click(screen.getByText('Files'));
- fireEvent.change(screen.getByPlaceholderText('Search files'), {target: {value: 'ext:'}});
+ await userEvent.type(screen.getByPlaceholderText('Search files'), 'ext:');
expect(screen.getByText('Text file')).toHaveClass('selected');
expect(screen.getByText('Word Document')).not.toHaveClass('selected');
- fireEvent.keyDown(screen.getByPlaceholderText('Search files'), {key: 'ArrowDown', code: 'ArrowDown'});
+ await userEvent.keyboard('{ArrowDown}');
expect(screen.getByText('Text file')).not.toHaveClass('selected');
expect(screen.getByText('Word Document')).toHaveClass('selected');
- fireEvent.keyDown(screen.getByPlaceholderText('Search files'), {key: 'ArrowUp', code: 'ArrowUp'});
+ await userEvent.keyboard('{ArrowUp}');
expect(screen.getByText('Text file')).toHaveClass('selected');
expect(screen.getByText('Word Document')).not.toHaveClass('selected');
});
diff --git a/webapp/channels/src/components/new_search/search_box_hints.test.tsx b/webapp/channels/src/components/new_search/search_box_hints.test.tsx
index 3627f3acfe7..d5745253406 100644
--- a/webapp/channels/src/components/new_search/search_box_hints.test.tsx
+++ b/webapp/channels/src/components/new_search/search_box_hints.test.tsx
@@ -6,7 +6,7 @@ import React from 'react';
import {
renderWithContext,
screen,
- fireEvent,
+ userEvent,
} from 'tests/react_testing_utils';
import SearchBoxHints from './search_box_hints';
@@ -56,9 +56,9 @@ describe('components/new_search/SearchBoxHints', () => {
expect(screen.getByText('From:')).toBeInTheDocument();
});
- test('should change the search term and focus on click', () => {
+ test('should change the search term and focus on click', async () => {
renderWithContext();
- fireEvent.click(screen.getByText('From:'));
+ await userEvent.click(screen.getByText('From:'));
expect(baseProps.setSearchTerms).toHaveBeenCalledWith('From:');
expect(baseProps.focus).toHaveBeenCalledWith(5);
});
diff --git a/webapp/channels/src/components/new_search/search_box_input.test.tsx b/webapp/channels/src/components/new_search/search_box_input.test.tsx
index 75ba798d09b..df8881a2bac 100644
--- a/webapp/channels/src/components/new_search/search_box_input.test.tsx
+++ b/webapp/channels/src/components/new_search/search_box_input.test.tsx
@@ -6,7 +6,7 @@ import React from 'react';
import {
renderWithContext,
screen,
- fireEvent,
+ userEvent,
} from 'tests/react_testing_utils';
import SearchBoxInput from './search_box_input';
@@ -44,31 +44,37 @@ describe('components/new_search/SearchBoxInput', () => {
expect(screen.getByPlaceholderText('Search messages')).toHaveValue('test-value');
});
- test('should call on key down when there is a key down event on the input field', () => {
+ test('should call on key down when there is a key down event on the input field', async () => {
const props = {...baseProps};
renderWithContext();
- fireEvent.keyDown(screen.getByPlaceholderText('Search messages'), {key: 'Enter'});
+ const input = screen.getByPlaceholderText('Search messages');
+ input.focus();
+ await userEvent.keyboard('{Enter}');
expect(props.onKeyDown).toHaveBeenCalledTimes(1);
});
- test('should call on key down when there is a key down event on the input field', () => {
+ test('should call on key down when there is a key down event on the input field with Escape', async () => {
const props = {...baseProps};
renderWithContext();
- fireEvent.keyDown(screen.getByPlaceholderText('Search messages'), {key: 'Enter'});
+ const input = screen.getByPlaceholderText('Search messages');
+ input.focus();
+ await userEvent.keyboard('{Escape}');
expect(props.onKeyDown).toHaveBeenCalledTimes(1);
});
- test('should update the search term on change', () => {
+ test('should update the search term on change', async () => {
const props = {...baseProps};
renderWithContext();
- fireEvent.change(screen.getByPlaceholderText('Search messages'), {target: {value: 'new-value'}});
+ const input = screen.getByPlaceholderText('Search messages');
+ await userEvent.clear(input);
+ await userEvent.type(input, 'new-value');
expect(props.setSearchTerms).toHaveBeenCalledWith('new-value');
});
- test('should clear the terms and focus in the input whenever click the clear button', () => {
+ test('should clear the terms and focus in the input whenever click the clear button', async () => {
const props = {...baseProps, searchTerms: 'test-value'};
renderWithContext();
- fireEvent.click(screen.getByText('Clear'));
+ await userEvent.click(screen.getByText('Clear'));
expect(props.setSearchTerms).toHaveBeenCalledWith('');
expect(props.focus).toHaveBeenCalledWith(0);
});
diff --git a/webapp/channels/src/components/new_search/search_box_suggestions.test.tsx b/webapp/channels/src/components/new_search/search_box_suggestions.test.tsx
index ed901479d86..012ea7439ed 100644
--- a/webapp/channels/src/components/new_search/search_box_suggestions.test.tsx
+++ b/webapp/channels/src/components/new_search/search_box_suggestions.test.tsx
@@ -7,6 +7,7 @@ import {
renderWithContext,
screen,
fireEvent,
+ userEvent,
} from 'tests/react_testing_utils';
import SearchBoxSuggestions from './search_box_suggestions';
@@ -62,24 +63,27 @@ describe('components/new_search/SearchBoxSuggestions', () => {
expect(screen.getByText('user2')).toBeInTheDocument();
});
- test('should call the onSuggestionSelected on click', () => {
+ test('should call the onSuggestionSelected on click', async () => {
renderWithContext();
- fireEvent.click(screen.getByText('test-username1'));
+ await userEvent.click(screen.getByText('test-username1'));
expect(baseProps.onSuggestionSelected).toHaveBeenCalledWith('test-username1', '');
});
- test('should call the onSuggestionSelected on click with matchedPretext and previous text', () => {
+ test('should call the onSuggestionSelected on click with matchedPretext and previous text', async () => {
const props = {...baseProps, searchTerms: 'something from:test-user', results: {...baseProps.results, matchedPretext: 'test-user'}};
renderWithContext();
- fireEvent.click(screen.getByText('test-username1'));
+ await userEvent.click(screen.getByText('test-username1'));
expect(baseProps.onSuggestionSelected).toHaveBeenCalledWith('test-username1', 'test-user');
});
test('should change the selected option on mousemove', () => {
const props = {...baseProps};
renderWithContext();
+
+ // Simulate mouse move to change selection - fireEvent used because userEvent.hover only triggers mouseEnter/mouseOver, not mouseMove
fireEvent.mouseMove(screen.getByText('test-username2'));
expect(baseProps.setSelectedTerm).toHaveBeenCalledWith('user2');
+
fireEvent.mouseMove(screen.getByText('test-username1'));
expect(baseProps.setSelectedTerm).toHaveBeenCalledWith('user1');
});
diff --git a/webapp/channels/src/components/popout_button.test.tsx b/webapp/channels/src/components/popout_button.test.tsx
index 1f2178d3e40..007d2359330 100644
--- a/webapp/channels/src/components/popout_button.test.tsx
+++ b/webapp/channels/src/components/popout_button.test.tsx
@@ -1,11 +1,9 @@
// 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 {renderWithContext} from 'tests/react_testing_utils';
+import {renderWithContext, screen, userEvent, waitFor} from 'tests/react_testing_utils';
import PopoutButton from './popout_button';
@@ -28,8 +26,6 @@ describe('PopoutButton', () => {
};
beforeEach(() => {
- jest.clearAllMocks();
-
mockCanPopout = true;
});
diff --git a/webapp/channels/src/components/popout_controller/popout_controller.test.tsx b/webapp/channels/src/components/popout_controller/popout_controller.test.tsx
index 963d223d447..47b95033062 100644
--- a/webapp/channels/src/components/popout_controller/popout_controller.test.tsx
+++ b/webapp/channels/src/components/popout_controller/popout_controller.test.tsx
@@ -89,8 +89,6 @@ const baseRouteProps: RouteComponentProps = {
describe('PopoutController', () => {
beforeEach(() => {
- jest.clearAllMocks();
-
// Reset document.body classes
document.body.className = '';
diff --git a/webapp/channels/src/components/post_edit_history/edited_post_item/edited_post_item.test.tsx b/webapp/channels/src/components/post_edit_history/edited_post_item/edited_post_item.test.tsx
index a74520c0665..026aefeba7d 100644
--- a/webapp/channels/src/components/post_edit_history/edited_post_item/edited_post_item.test.tsx
+++ b/webapp/channels/src/components/post_edit_history/edited_post_item/edited_post_item.test.tsx
@@ -1,11 +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 {screen} from '@testing-library/react';
import React from 'react';
import type {ComponentProps} from 'react';
-import {renderWithContext} from 'tests/react_testing_utils';
+import {renderWithContext, userEvent} from 'tests/react_testing_utils';
import {ModalIdentifiers} from 'utils/constants';
import {TestHelper} from 'utils/test_helper';
@@ -45,12 +45,12 @@ describe('components/post_edit_history/edited_post_item', () => {
expect(container).toMatchSnapshot();
});
- test('clicking on the restore button should call openRestorePostModal', () => {
+ test('clicking on the restore button should call openRestorePostModal', async () => {
renderWithContext();
// find the button with restore icon and click it
const restoreButton = screen.getByRole('button', {name: /restore/i});
- fireEvent.click(restoreButton);
+ await userEvent.click(restoreButton);
expect(baseProps.actions.openModal).toHaveBeenCalledWith(
expect.objectContaining({
diff --git a/webapp/channels/src/components/post_view/burn_on_read_badge/burn_on_read_badge.test.tsx b/webapp/channels/src/components/post_view/burn_on_read_badge/burn_on_read_badge.test.tsx
index e777e2a6eb4..085e8b78c87 100644
--- a/webapp/channels/src/components/post_view/burn_on_read_badge/burn_on_read_badge.test.tsx
+++ b/webapp/channels/src/components/post_view/burn_on_read_badge/burn_on_read_badge.test.tsx
@@ -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 {TestHelper} from 'utils/test_helper';
import BurnOnReadBadge from './burn_on_read_badge';
@@ -105,7 +104,7 @@ describe('BurnOnReadBadge', () => {
expect(badge).toHaveClass('BurnOnReadBadge');
});
- it('should call onSenderDelete when sender clicks badge', () => {
+ it('should call onSenderDelete when sender clicks badge', async () => {
const onSenderDelete = jest.fn();
renderWithContext(
{
);
const badge = screen.getByTestId('burn-on-read-badge-post123');
- fireEvent.click(badge);
+ await userEvent.click(badge);
expect(onSenderDelete).toHaveBeenCalledTimes(1);
});
- it('should not call onSenderDelete when recipient clicks badge', () => {
+ it('should not call onSenderDelete when recipient clicks badge', async () => {
const onSenderDelete = jest.fn();
const onReveal = jest.fn();
renderWithContext(
@@ -135,7 +134,7 @@ describe('BurnOnReadBadge', () => {
);
const badge = screen.getByTestId('burn-on-read-badge-post123');
- fireEvent.click(badge);
+ await userEvent.click(badge);
expect(onSenderDelete).not.toHaveBeenCalled();
expect(onReveal).toHaveBeenCalledWith('post123');
diff --git a/webapp/channels/src/components/post_view/burn_on_read_concealed_placeholder/burn_on_read_concealed_placeholder.test.tsx b/webapp/channels/src/components/post_view/burn_on_read_concealed_placeholder/burn_on_read_concealed_placeholder.test.tsx
index f5ef9308355..b84212e1d16 100644
--- a/webapp/channels/src/components/post_view/burn_on_read_concealed_placeholder/burn_on_read_concealed_placeholder.test.tsx
+++ b/webapp/channels/src/components/post_view/burn_on_read_concealed_placeholder/burn_on_read_concealed_placeholder.test.tsx
@@ -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 BurnOnReadConcealedPlaceholder from './burn_on_read_concealed_placeholder';
@@ -14,10 +14,6 @@ describe('BurnOnReadConcealedPlaceholder', () => {
onReveal: jest.fn(),
};
- beforeEach(() => {
- jest.clearAllMocks();
- });
-
it('should render with concealed placeholder text', () => {
renderWithContext(
,
@@ -28,47 +24,50 @@ describe('BurnOnReadConcealedPlaceholder', () => {
expect(screen.getByRole('button')).toHaveClass('BurnOnReadConcealedPlaceholder');
});
- it('should call onReveal when clicked', () => {
+ it('should call onReveal when clicked', async () => {
renderWithContext(
,
);
const placeholder = screen.getByRole('button');
- fireEvent.click(placeholder);
+ await userEvent.click(placeholder);
expect(baseProps.onReveal).toHaveBeenCalledWith('post123');
expect(baseProps.onReveal).toHaveBeenCalledTimes(1);
});
- it('should call onReveal when Enter key is pressed', () => {
+ it('should call onReveal when Enter key is pressed', async () => {
renderWithContext(
,
);
const placeholder = screen.getByRole('button');
- fireEvent.keyDown(placeholder, {key: 'Enter'});
+ placeholder.focus();
+ await userEvent.keyboard('{Enter}');
expect(baseProps.onReveal).toHaveBeenCalledWith('post123');
});
- it('should call onReveal when Space key is pressed', () => {
+ it('should call onReveal when Space key is pressed', async () => {
renderWithContext(
,
);
const placeholder = screen.getByRole('button');
- fireEvent.keyDown(placeholder, {key: ' '});
+ placeholder.focus();
+ await userEvent.keyboard(' ');
expect(baseProps.onReveal).toHaveBeenCalledWith('post123');
});
- it('should not call onReveal when other keys are pressed', () => {
+ it('should not call onReveal when other keys are pressed', async () => {
renderWithContext(
,
);
const placeholder = screen.getByRole('button');
- fireEvent.keyDown(placeholder, {key: 'a'});
+ placeholder.focus();
+ await userEvent.keyboard('a');
expect(baseProps.onReveal).not.toHaveBeenCalled();
});
@@ -85,7 +84,7 @@ describe('BurnOnReadConcealedPlaceholder', () => {
expect(screen.queryByText('Click to Reveal')).not.toBeInTheDocument();
});
- it('should not trigger onReveal when loading', () => {
+ it('should not trigger onReveal when loading', async () => {
renderWithContext(
{
);
const placeholder = screen.getByRole('button');
- fireEvent.click(placeholder);
+ await userEvent.click(placeholder);
expect(baseProps.onReveal).not.toHaveBeenCalled();
});
diff --git a/webapp/channels/src/components/post_view/burn_on_read_timer_chip/burn_on_read_timer_chip.test.tsx b/webapp/channels/src/components/post_view/burn_on_read_timer_chip/burn_on_read_timer_chip.test.tsx
index 1f3a309401a..4fe5359568f 100644
--- a/webapp/channels/src/components/post_view/burn_on_read_timer_chip/burn_on_read_timer_chip.test.tsx
+++ b/webapp/channels/src/components/post_view/burn_on_read_timer_chip/burn_on_read_timer_chip.test.tsx
@@ -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, fireEvent} from 'tests/react_testing_utils';
import BurnOnReadTimerChip from './burn_on_read_timer_chip';
@@ -16,7 +15,6 @@ describe('BurnOnReadTimerChip', () => {
beforeEach(() => {
jest.useFakeTimers();
- jest.clearAllMocks();
});
afterEach(() => {
@@ -40,6 +38,8 @@ describe('BurnOnReadTimerChip', () => {
);
const chip = screen.getByRole('button');
+
+ // Click the timer chip to verify onClick handler is called - fireEvent used because userEvent doesn't work well with fake timers
fireEvent.click(chip);
expect(onClick).toHaveBeenCalledTimes(1);
@@ -55,6 +55,8 @@ describe('BurnOnReadTimerChip', () => {
);
const chip = screen.getByRole('button');
+
+ // Press Enter key to verify keyboard accessibility for the timer chip - fireEvent used because userEvent doesn't work well with fake timers
fireEvent.keyDown(chip, {key: 'Enter', code: 'Enter'});
expect(onClick).toHaveBeenCalled();
diff --git a/webapp/channels/src/components/post_view/post_time/post_time.test.tsx b/webapp/channels/src/components/post_view/post_time/post_time.test.tsx
index facfc91af5e..5af9d696a0b 100644
--- a/webapp/channels/src/components/post_view/post_time/post_time.test.tsx
+++ b/webapp/channels/src/components/post_view/post_time/post_time.test.tsx
@@ -1,10 +1,9 @@
// 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 {renderWithContext, screen, waitFor, act} from 'tests/react_testing_utils';
+import {renderWithContext, screen, waitFor, act, userEvent} from 'tests/react_testing_utils';
import PostTime from './post_time';
diff --git a/webapp/channels/src/components/preparing_workspace/invite_members.test.tsx b/webapp/channels/src/components/preparing_workspace/invite_members.test.tsx
index 1bde6290135..b1b1288b1f3 100644
--- a/webapp/channels/src/components/preparing_workspace/invite_members.test.tsx
+++ b/webapp/channels/src/components/preparing_workspace/invite_members.test.tsx
@@ -5,7 +5,7 @@ import React from 'react';
import type {ComponentProps} from 'react';
import {withIntl} from 'tests/helpers/intl-test-helper';
-import {fireEvent, render, screen} from 'tests/react_testing_utils';
+import {render, screen, userEvent} from 'tests/react_testing_utils';
import InviteMembers from './invite_members';
@@ -78,11 +78,11 @@ describe('InviteMembers component', () => {
expect(button).toBeDisabled();
});
- it('invokes next prop on button click', () => {
+ it('invokes next prop on button click', async () => {
const component = withIntl();
render(component);
const button = screen.getByRole('button', {name: 'Finish setup'});
- fireEvent.click(button);
+ await userEvent.click(button);
expect(defaultProps.next).toHaveBeenCalled();
});
diff --git a/webapp/channels/src/components/preparing_workspace/invite_members_link.test.tsx b/webapp/channels/src/components/preparing_workspace/invite_members_link.test.tsx
index 5e9d479b366..b02d5d9e99b 100644
--- a/webapp/channels/src/components/preparing_workspace/invite_members_link.test.tsx
+++ b/webapp/channels/src/components/preparing_workspace/invite_members_link.test.tsx
@@ -4,7 +4,7 @@
import React from 'react';
import {withIntl} from 'tests/helpers/intl-test-helper';
-import {fireEvent, render, screen} from 'tests/react_testing_utils';
+import {render, screen, userEvent} from 'tests/react_testing_utils';
import InviteMembersLink from './invite_members_link';
@@ -63,7 +63,7 @@ describe('components/preparing-workspace/invite_members_link', () => {
expect(button).toBeInTheDocument();
});
- it('changes the button text to "Link Copied" when the URL is copied', () => {
+ it('changes the button text to "Link Copied" when the URL is copied', async () => {
const component = withIntl();
render(component);
const button = screen.getByRole('button', {name: /copy link/i});
@@ -71,7 +71,7 @@ describe('components/preparing-workspace/invite_members_link', () => {
const linkCopiedText = 'Link Copied';
expect(button).toHaveTextContent(originalText);
- fireEvent.click(button);
+ await userEvent.click(button);
expect(button).toHaveTextContent(linkCopiedText);
});
diff --git a/webapp/channels/src/components/profile_popover/profile_popover_email.test.tsx b/webapp/channels/src/components/profile_popover/profile_popover_email.test.tsx
index 05674f3eeb7..c593d49b5f5 100644
--- a/webapp/channels/src/components/profile_popover/profile_popover_email.test.tsx
+++ b/webapp/channels/src/components/profile_popover/profile_popover_email.test.tsx
@@ -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 ProfilePopoverEmail from './profile_popover_email';
@@ -48,26 +47,25 @@ describe('components/ProfilePopoverEmail', () => {
expect(emailLink.tagName).toBe('A');
});
- test('should open email client when clicked', () => {
+ test('should open email client when clicked', async () => {
renderWithContext();
const email = 'test@example.com';
const emailLink = screen.getByText(email);
- fireEvent.click(emailLink);
+ await userEvent.click(emailLink);
expect(mockWindowOpen).toHaveBeenCalledWith('mailto:test@example.com');
});
- test('should prevent default click behavior', () => {
+ test('should prevent default click behavior', async () => {
renderWithContext();
const email = 'test@example.com';
const emailLink = screen.getByText(email);
- const clickEvent = fireEvent.click(emailLink);
+ await userEvent.click(emailLink);
- expect(clickEvent).toBe(false); // fireEvent.click returns false when preventDefault was called
expect(mockWindowOpen).toHaveBeenCalledWith('mailto:test@example.com');
});
});
diff --git a/webapp/channels/src/components/profile_popover/profile_popover_phone.test.tsx b/webapp/channels/src/components/profile_popover/profile_popover_phone.test.tsx
index ee7a5b1be13..97c8d0c0b14 100644
--- a/webapp/channels/src/components/profile_popover/profile_popover_phone.test.tsx
+++ b/webapp/channels/src/components/profile_popover/profile_popover_phone.test.tsx
@@ -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 {renderWithContext, screen, userEvent} from 'tests/react_testing_utils';
import ProfilePopoverPhone from './profile_popover_phone';
@@ -104,26 +103,25 @@ describe('components/ProfilePopoverPhone', () => {
expect(phoneLink.tagName).toBe('A');
});
- test('should open phone dialer when clicked', () => {
+ test('should open phone dialer when clicked', async () => {
renderWithContext();
const phone = '+1 (555) 123-4567';
const phoneLink = screen.getByText(phone);
- fireEvent.click(phoneLink);
+ await userEvent.click(phoneLink);
expect(mockWindowOpen).toHaveBeenCalledWith('tel:+1 (555) 123-4567');
});
- test('should prevent default click behavior', () => {
+ test('should prevent default click behavior', async () => {
renderWithContext();
const phone = '+1 (555) 123-4567';
const phoneLink = screen.getByText(phone);
- const clickEvent = fireEvent.click(phoneLink);
+ await userEvent.click(phoneLink);
- expect(clickEvent).toBe(false); // fireEvent.click returns false when preventDefault was called
expect(mockWindowOpen).toHaveBeenCalledWith('tel:+1 (555) 123-4567');
});
});
diff --git a/webapp/channels/src/components/properties_card_view/propertyValueRenderer/channel_property_renderer/channel_property_renderer.test.tsx b/webapp/channels/src/components/properties_card_view/propertyValueRenderer/channel_property_renderer/channel_property_renderer.test.tsx
index 57fcea8b43d..2ddf48fd2d4 100644
--- a/webapp/channels/src/components/properties_card_view/propertyValueRenderer/channel_property_renderer/channel_property_renderer.test.tsx
+++ b/webapp/channels/src/components/properties_card_view/propertyValueRenderer/channel_property_renderer/channel_property_renderer.test.tsx
@@ -29,10 +29,6 @@ describe('ChannelPropertyRenderer', () => {
value: 'channel-id-123',
} as PropertyValue;
- beforeEach(() => {
- jest.clearAllMocks();
- });
-
it('should render channel name and icon when channel exists', () => {
mockUseChannel.mockReturnValue(mockChannel);
diff --git a/webapp/channels/src/components/recaps/recap_channel_card.test.tsx b/webapp/channels/src/components/recaps/recap_channel_card.test.tsx
index 5539ba864ff..ae10a525c41 100644
--- a/webapp/channels/src/components/recaps/recap_channel_card.test.tsx
+++ b/webapp/channels/src/components/recaps/recap_channel_card.test.tsx
@@ -92,10 +92,6 @@ describe('RecapChannelCard', () => {
create_at: 1000,
};
- beforeEach(() => {
- jest.clearAllMocks();
- });
-
test('should render channel name', () => {
renderWithContext(
,
diff --git a/webapp/channels/src/components/recaps/recap_menu.test.tsx b/webapp/channels/src/components/recaps/recap_menu.test.tsx
index 1f396a364e0..a4a222520f1 100644
--- a/webapp/channels/src/components/recaps/recap_menu.test.tsx
+++ b/webapp/channels/src/components/recaps/recap_menu.test.tsx
@@ -57,10 +57,6 @@ describe('RecapMenu', () => {
},
];
- beforeEach(() => {
- jest.clearAllMocks();
- });
-
test('should render menu button', () => {
renderWithContext();
diff --git a/webapp/channels/src/components/recaps/recaps_list.test.tsx b/webapp/channels/src/components/recaps/recaps_list.test.tsx
index 2aab378860a..7ab66f4b9f8 100644
--- a/webapp/channels/src/components/recaps/recaps_list.test.tsx
+++ b/webapp/channels/src/components/recaps/recaps_list.test.tsx
@@ -44,10 +44,6 @@ describe('RecapsList', () => {
},
];
- beforeEach(() => {
- jest.clearAllMocks();
- });
-
test('should render empty state when no recaps', () => {
renderWithContext();
diff --git a/webapp/channels/src/components/rhs_plugin_popout/rhs_plugin_popout.test.tsx b/webapp/channels/src/components/rhs_plugin_popout/rhs_plugin_popout.test.tsx
index bbdaf79c814..7cea07e54c1 100644
--- a/webapp/channels/src/components/rhs_plugin_popout/rhs_plugin_popout.test.tsx
+++ b/webapp/channels/src/components/rhs_plugin_popout/rhs_plugin_popout.test.tsx
@@ -66,7 +66,6 @@ const baseState = {
describe('RhsPluginPopout', () => {
beforeEach(() => {
mockUseParams.mockReturnValue({pluginId});
- jest.clearAllMocks();
});
it('should render LoadingScreen when plugin is not found', () => {
diff --git a/webapp/channels/src/components/rhs_popout/rhs_popout.test.tsx b/webapp/channels/src/components/rhs_popout/rhs_popout.test.tsx
index 089185f696c..f05ee0784ed 100644
--- a/webapp/channels/src/components/rhs_popout/rhs_popout.test.tsx
+++ b/webapp/channels/src/components/rhs_popout/rhs_popout.test.tsx
@@ -68,7 +68,6 @@ describe('RhsPopout', () => {
const channel1 = TestHelper.getChannelMock({id: 'channel1', name: 'channel1'});
beforeEach(() => {
- jest.clearAllMocks();
mockDispatch.mockReturnValue({type: 'MOCK_ACTION'});
mockUseDispatch.mockReturnValue(mockDispatch);
mockUseParams.mockReturnValue({team: 'team1', identifier: 'channel1'});
diff --git a/webapp/channels/src/components/section_notice/index.test.tsx b/webapp/channels/src/components/section_notice/index.test.tsx
index 35c2a735a97..ab0ccad2d7c 100644
--- a/webapp/channels/src/components/section_notice/index.test.tsx
+++ b/webapp/channels/src/components/section_notice/index.test.tsx
@@ -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 type {ComponentProps} from 'react';
import React from 'react';
-import {renderWithContext} from 'tests/react_testing_utils';
+import {renderWithContext, screen, userEvent} from 'tests/react_testing_utils';
import SectionNotice from '.';
@@ -38,7 +37,7 @@ function getBaseProps(): Props {
}
describe('PluginAction', () => {
- it('does show the correct information', () => {
+ it('does show the correct information', async () => {
const props = getBaseProps();
renderWithContext();
const primaryButton = screen.getByText(props.primaryButton!.text);
@@ -54,15 +53,15 @@ describe('PluginAction', () => {
expect(closeButton).toBeInTheDocument();
expect(screen.queryByText(props.text as string)).toBeInTheDocument();
expect(screen.queryByText(props.title as string)).toBeInTheDocument();
- fireEvent.click(primaryButton);
+ await userEvent.click(primaryButton);
expect(props.primaryButton?.onClick).toHaveBeenCalledTimes(1);
- fireEvent.click(secondaryButton);
+ await userEvent.click(secondaryButton);
expect(props.secondaryButton?.onClick).toHaveBeenCalledTimes(1);
- fireEvent.click(tertiaryButton);
+ await userEvent.click(tertiaryButton);
expect(props.tertiaryButton?.onClick).toHaveBeenCalledTimes(1);
- fireEvent.click(linkButton);
+ await userEvent.click(linkButton);
expect(props.linkButton?.onClick).toHaveBeenCalledTimes(1);
- fireEvent.click(closeButton);
+ await userEvent.click(closeButton);
expect(props.onDismissClick).toHaveBeenCalledTimes(1);
});
diff --git a/webapp/channels/src/components/setting_picture.test.tsx b/webapp/channels/src/components/setting_picture.test.tsx
index 2ed4570211a..48440b1282f 100644
--- a/webapp/channels/src/components/setting_picture.test.tsx
+++ b/webapp/channels/src/components/setting_picture.test.tsx
@@ -7,7 +7,7 @@ import {FormattedMessage} from 'react-intl';
import SettingPicture from 'components/setting_picture';
-import {renderWithContext, screen, fireEvent, userEvent} from 'tests/react_testing_utils';
+import {renderWithContext, screen, userEvent} from 'tests/react_testing_utils';
const helpText: ReactNode = (
{
// Trigger file change
const fileInput = screen.getByTestId('uploadPicture');
- fireEvent.change(fileInput, {target: {files: [mockFile]}});
+ await userEvent.upload(fileInput, mockFile);
expect(props.onFileChange).toHaveBeenCalledTimes(1);
diff --git a/webapp/channels/src/components/shared_channel_indicator.test.tsx b/webapp/channels/src/components/shared_channel_indicator.test.tsx
index 811888b1fb8..cb3c590ff89 100644
--- a/webapp/channels/src/components/shared_channel_indicator.test.tsx
+++ b/webapp/channels/src/components/shared_channel_indicator.test.tsx
@@ -1,10 +1,9 @@
// 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 {renderWithContext, screen, waitFor} from 'tests/react_testing_utils';
+import {renderWithContext, screen, userEvent, waitFor} from 'tests/react_testing_utils';
import SharedChannelIndicator from './shared_channel_indicator';
diff --git a/webapp/channels/src/components/shared_user_indicator.test.tsx b/webapp/channels/src/components/shared_user_indicator.test.tsx
index 14dbf1776c3..d37d8f28ab1 100644
--- a/webapp/channels/src/components/shared_user_indicator.test.tsx
+++ b/webapp/channels/src/components/shared_user_indicator.test.tsx
@@ -1,11 +1,10 @@
// 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 * as reactIntl from 'react-intl';
-import {renderWithContext, screen, waitFor} from 'tests/react_testing_utils';
+import {renderWithContext, screen, userEvent, waitFor} from 'tests/react_testing_utils';
import SharedUserIndicator from './shared_user_indicator';
diff --git a/webapp/channels/src/components/sidebar/sidebar.test.tsx b/webapp/channels/src/components/sidebar/sidebar.test.tsx
index 2810fda21e2..69c2f9ca300 100644
--- a/webapp/channels/src/components/sidebar/sidebar.test.tsx
+++ b/webapp/channels/src/components/sidebar/sidebar.test.tsx
@@ -301,6 +301,7 @@ describe('components/sidebar', () => {
expect(document.getElementById('SidebarContainer')).toBeInTheDocument();
// Test with backslash key (should not trigger the modal)
+ // fireEvent on document used because userEvent.keyboard requires element focus
fireEvent.keyDown(document, {
key: '\\',
code: 'Backslash',
@@ -310,6 +311,7 @@ describe('components/sidebar', () => {
expect(openModalSpy).not.toHaveBeenCalled();
// Test with 'ù' key but with forward slash keyCode (should trigger the modal)
+ // fireEvent on document used because userEvent.keyboard requires element focus
fireEvent.keyDown(document, {
key: 'ù',
code: 'Slash',
@@ -324,6 +326,7 @@ describe('components/sidebar', () => {
openModalSpy.mockClear();
// Test with '/' key but with seven keyCode (should trigger the modal)
+ // fireEvent on document used because userEvent.keyboard requires element focus
fireEvent.keyDown(document, {
key: '/',
code: 'Digit7',
@@ -338,6 +341,7 @@ describe('components/sidebar', () => {
openModalSpy.mockClear();
// Test with forward slash key (should trigger the modal)
+ // fireEvent on document used because userEvent.keyboard requires element focus
fireEvent.keyDown(document, {
key: '/',
code: 'Slash',
@@ -371,6 +375,7 @@ describe('components/sidebar', () => {
expect(document.getElementById('SidebarContainer')).toBeInTheDocument();
// Test with forward slash key (should close the modal since it's already open)
+ // fireEvent on document used because userEvent.keyboard requires element focus
fireEvent.keyDown(document, {
key: '/',
code: 'Slash',
diff --git a/webapp/channels/src/components/sidebar/sidebar_header/sidebar_team_menu.test.tsx b/webapp/channels/src/components/sidebar/sidebar_header/sidebar_team_menu.test.tsx
index cfe11b1d07c..45f8bddb2ab 100644
--- a/webapp/channels/src/components/sidebar/sidebar_header/sidebar_team_menu.test.tsx
+++ b/webapp/channels/src/components/sidebar/sidebar_header/sidebar_team_menu.test.tsx
@@ -102,10 +102,6 @@ describe('components/sidebar/sidebar_header/sidebar_team_menu', () => {
currentTeam,
};
- beforeEach(() => {
- jest.clearAllMocks();
- });
-
test('should open team menu when clicked', async () => {
renderWithContext(
,
diff --git a/webapp/channels/src/components/single_image_view/single_image_view.test.tsx b/webapp/channels/src/components/single_image_view/single_image_view.test.tsx
index 3363e71b27b..50b9b08778d 100644
--- a/webapp/channels/src/components/single_image_view/single_image_view.test.tsx
+++ b/webapp/channels/src/components/single_image_view/single_image_view.test.tsx
@@ -34,6 +34,8 @@ describe('components/SingleImageView', () => {
expect(img).toBeInTheDocument();
Object.defineProperty(img, 'naturalHeight', {value: 100, configurable: true});
Object.defineProperty(img, 'naturalWidth', {value: 100, configurable: true});
+
+ // Simulate image load event - fireEvent used because userEvent doesn't support image loading events
fireEvent.load(img!);
expect(container).toMatchSnapshot();
});
@@ -56,6 +58,7 @@ describe('components/SingleImageView', () => {
expect(img).toBeInTheDocument();
Object.defineProperty(img, 'naturalHeight', {value: 100, configurable: true});
Object.defineProperty(img, 'naturalWidth', {value: 100, configurable: true});
+
fireEvent.load(img!);
expect(container).toMatchSnapshot();
});
@@ -71,6 +74,7 @@ describe('components/SingleImageView', () => {
// Simulate loaded state
Object.defineProperty(img, 'naturalHeight', {value: 100, configurable: true});
Object.defineProperty(img, 'naturalWidth', {value: 100, configurable: true});
+
fireEvent.load(img!);
// Click the image
@@ -110,6 +114,7 @@ describe('components/SingleImageView', () => {
expect(img).toBeInTheDocument();
Object.defineProperty(img, 'naturalHeight', {value: 100, configurable: true});
Object.defineProperty(img, 'naturalWidth', {value: 100, configurable: true});
+
fireEvent.load(img!);
// After load, should have image-fade-in class (loaded = true)
diff --git a/webapp/channels/src/components/system_policy_indicator/system_policy_indicator.test.tsx b/webapp/channels/src/components/system_policy_indicator/system_policy_indicator.test.tsx
index f6cf8347144..676dc9eec50 100644
--- a/webapp/channels/src/components/system_policy_indicator/system_policy_indicator.test.tsx
+++ b/webapp/channels/src/components/system_policy_indicator/system_policy_indicator.test.tsx
@@ -5,7 +5,7 @@ import React from 'react';
import type {AccessControlPolicy} from '@mattermost/types/access_control';
-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 SystemPolicyIndicator from './system_policy_indicator';
@@ -224,7 +224,7 @@ describe('components/system_policy_indicator/SystemPolicyIndicator', () => {
});
// Test more button functionality
- test('should call onMorePoliciesClick when more button is clicked', () => {
+ test('should call onMorePoliciesClick when more button is clicked', async () => {
const mockPolicy3: AccessControlPolicy = {
id: 'policy3',
name: 'Test Policy 3',
@@ -248,12 +248,12 @@ describe('components/system_policy_indicator/SystemPolicyIndicator', () => {
);
const moreButton = screen.getByText('1 more');
- fireEvent.click(moreButton);
+ await userEvent.click(moreButton);
expect(onMorePoliciesClick).toHaveBeenCalledTimes(1);
});
- test('should call onMorePoliciesClick when more button is activated with Enter key', () => {
+ test('should call onMorePoliciesClick when more button is activated with Enter key', async () => {
const mockPolicy3: AccessControlPolicy = {
id: 'policy3',
name: 'Test Policy 3',
@@ -277,7 +277,8 @@ describe('components/system_policy_indicator/SystemPolicyIndicator', () => {
);
const moreButton = screen.getByText('1 more');
- fireEvent.keyDown(moreButton, {key: 'Enter', code: 'Enter'});
+ moreButton.focus();
+ await userEvent.keyboard('{Enter}');
expect(onMorePoliciesClick).toHaveBeenCalledTimes(1);
});
@@ -315,7 +316,7 @@ describe('components/system_policy_indicator/SystemPolicyIndicator', () => {
expect(screen.getByText('policy1')).toBeInTheDocument();
});
- test('should prevent default action and stop propagation on click', () => {
+ test('should prevent default action and stop propagation on click', async () => {
const mockPolicy3: AccessControlPolicy = {
id: 'policy3',
name: 'Test Policy 3',
@@ -329,8 +330,6 @@ describe('components/system_policy_indicator/SystemPolicyIndicator', () => {
};
const onMorePoliciesClick = jest.fn();
- const mockPreventDefault = jest.fn();
- const mockStopPropagation = jest.fn();
renderWithContext(
{
const moreButton = screen.getByText('1 more');
- fireEvent.click(moreButton, {
- preventDefault: mockPreventDefault,
- stopPropagation: mockStopPropagation,
- });
+ await userEvent.click(moreButton);
expect(onMorePoliciesClick).toHaveBeenCalledTimes(1);
});
diff --git a/webapp/channels/src/components/team_settings/team_access_tab/open_invite.test.tsx b/webapp/channels/src/components/team_settings/team_access_tab/open_invite.test.tsx
index 183a6ac5856..f30fe407fd1 100644
--- a/webapp/channels/src/components/team_settings/team_access_tab/open_invite.test.tsx
+++ b/webapp/channels/src/components/team_settings/team_access_tab/open_invite.test.tsx
@@ -1,10 +1,9 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
-import {fireEvent, screen} from '@testing-library/react';
import React, {type ComponentProps} from 'react';
-import {renderWithContext} from 'tests/react_testing_utils';
+import {renderWithContext, screen, userEvent} from 'tests/react_testing_utils';
import OpenInvite from './open_invite';
@@ -41,12 +40,12 @@ describe('components/TeamSettings/OpenInvite', () => {
expect(checkbox).toBeChecked();
});
- test('should call setAllowOpenInvite when the checkbox is clicked', () => {
+ test('should call setAllowOpenInvite when the checkbox is clicked', async () => {
renderWithContext();
const checkbox = screen.getByRole('checkbox');
expect(checkbox).toBeInTheDocument();
expect(checkbox).not.toBeChecked();
- fireEvent.click(checkbox);
+ await userEvent.click(checkbox);
expect(setAllowOpenInvite).toHaveBeenCalledTimes(1);
expect(setAllowOpenInvite).toHaveBeenCalledWith(true);
});
diff --git a/webapp/channels/src/components/thread_popout/thread_popout.test.tsx b/webapp/channels/src/components/thread_popout/thread_popout.test.tsx
index 7524eb96a92..1bed4cb378f 100644
--- a/webapp/channels/src/components/thread_popout/thread_popout.test.tsx
+++ b/webapp/channels/src/components/thread_popout/thread_popout.test.tsx
@@ -127,7 +127,6 @@ describe('ThreadPopout', () => {
};
beforeEach(() => {
- jest.clearAllMocks();
Object.defineProperty(window, 'isActive', {
writable: true,
value: false,
diff --git a/webapp/channels/src/components/three_days_left_trial_modal/three_days_left_trial_modal.test.tsx b/webapp/channels/src/components/three_days_left_trial_modal/three_days_left_trial_modal.test.tsx
index 49ee385fcce..1f3d24ee3a1 100644
--- a/webapp/channels/src/components/three_days_left_trial_modal/three_days_left_trial_modal.test.tsx
+++ b/webapp/channels/src/components/three_days_left_trial_modal/three_days_left_trial_modal.test.tsx
@@ -72,10 +72,6 @@ describe('components/three_days_left_trial_modal/three_days_left_trial_modal', (
limitsOverpassed: false,
};
- beforeEach(() => {
- jest.clearAllMocks();
- });
-
test('should render the modal with header, subtitle, feature cards, and view plans button', () => {
renderWithContext(
,
diff --git a/webapp/channels/src/components/toast_wrapper/toast_wrapper.test.tsx b/webapp/channels/src/components/toast_wrapper/toast_wrapper.test.tsx
index 3a0973cd42c..c4275191850 100644
--- a/webapp/channels/src/components/toast_wrapper/toast_wrapper.test.tsx
+++ b/webapp/channels/src/components/toast_wrapper/toast_wrapper.test.tsx
@@ -1,7 +1,6 @@
// 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 {ComponentProps} from 'react';
@@ -12,7 +11,7 @@ import {HINT_TOAST_TESTID} from 'components/hint-toast/hint_toast';
import {SCROLL_TO_BOTTOM_DISMISS_BUTTON_TESTID, SCROLL_TO_BOTTOM_TOAST_TESTID} from 'components/scroll_to_bottom_toast/scroll_to_bottom_toast';
import {shallowWithIntl} from 'tests/helpers/intl-test-helper';
-import {renderWithContext} from 'tests/react_testing_utils';
+import {renderWithContext, screen, userEvent} from 'tests/react_testing_utils';
import {getHistory} from 'utils/browser_history';
import {PostListRowListIds} from 'utils/constants';
@@ -692,7 +691,7 @@ describe('components/ToastWrapper', () => {
expect(hintToast).toBeInTheDocument();
});
- test('should call scrollToLatestMessages on click, and hide this toast (do not call dismiss function)', () => {
+ test('should call scrollToLatestMessages on click, and hide this toast (do not call dismiss function)', async () => {
const props = {
...baseProps,
showScrollToBottomToast: true,
@@ -700,7 +699,7 @@ describe('components/ToastWrapper', () => {
renderWithContext();
const scrollToBottomToast = screen.getByTestId(SCROLL_TO_BOTTOM_TOAST_TESTID);
- fireEvent.click(scrollToBottomToast);
+ await userEvent.click(scrollToBottomToast);
expect(baseProps.scrollToLatestMessages).toHaveBeenCalledTimes(1);
@@ -709,7 +708,7 @@ describe('components/ToastWrapper', () => {
expect(baseProps.hideScrollToBottomToast).toHaveBeenCalledTimes(1);
});
- test('should call the dismiss callback', () => {
+ test('should call the dismiss callback', async () => {
const props = {
...baseProps,
showScrollToBottomToast: true,
@@ -717,7 +716,7 @@ describe('components/ToastWrapper', () => {
renderWithContext();
const scrollToBottomToastDismiss = screen.getByTestId(SCROLL_TO_BOTTOM_DISMISS_BUTTON_TESTID);
- fireEvent.click(scrollToBottomToastDismiss);
+ await userEvent.click(scrollToBottomToastDismiss);
expect(baseProps.onScrollToBottomToastDismiss).toHaveBeenCalledTimes(1);
});
diff --git a/webapp/channels/src/components/user_settings/general/user_settings_general.test.tsx b/webapp/channels/src/components/user_settings/general/user_settings_general.test.tsx
index b8b7caca9a4..998e7d38375 100644
--- a/webapp/channels/src/components/user_settings/general/user_settings_general.test.tsx
+++ b/webapp/channels/src/components/user_settings/general/user_settings_general.test.tsx
@@ -771,7 +771,7 @@ describe('components/user_settings/general/UserSettingsGeneral', () => {
// Type the invalid value
await userEvent.type(input, 'ftp://invalid-scheme');
- // Focus and blur explicitly to trigger validation without relatedTarget
+ // Trigger validation - fireEvent used because userEvent doesn't have direct focus/blur methods
await act(async () => {
fireEvent.focus(input);
fireEvent.blur(input, {relatedTarget: null});
@@ -815,7 +815,6 @@ describe('components/user_settings/general/UserSettingsGeneral', () => {
// Type the invalid value
await userEvent.type(input, 'invalid-email');
- // Focus and blur explicitly to trigger validation without relatedTarget
await act(async () => {
fireEvent.focus(input);
fireEvent.blur(input, {relatedTarget: null});
diff --git a/webapp/channels/src/components/user_settings/headers/setting_mobile_header.test.tsx b/webapp/channels/src/components/user_settings/headers/setting_mobile_header.test.tsx
index b6e7f0441c5..3f9617a9549 100644
--- a/webapp/channels/src/components/user_settings/headers/setting_mobile_header.test.tsx
+++ b/webapp/channels/src/components/user_settings/headers/setting_mobile_header.test.tsx
@@ -1,11 +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 {screen} from '@testing-library/react';
import type {ComponentProps} from 'react';
import React from 'react';
-import {renderWithContext} from 'tests/react_testing_utils';
+import {renderWithContext, userEvent} from 'tests/react_testing_utils';
import SettingMobileHeader from './setting_mobile_header';
@@ -18,15 +18,15 @@ const baseProps: Props = {
};
describe('plugin tab', () => {
- it('calls closeModal on hitting close', () => {
+ it('calls closeModal on hitting close', async () => {
renderWithContext();
- fireEvent.click(screen.getByText('×'));
+ await userEvent.click(screen.getByText('×'));
expect(baseProps.closeModal).toHaveBeenCalled();
});
- it('calls collapseModal on hitting back', () => {
+ it('calls collapseModal on hitting back', async () => {
renderWithContext();
- fireEvent.click(screen.getByLabelText('Collapse Icon'));
+ await userEvent.click(screen.getByLabelText('Collapse Icon'));
expect(baseProps.collapseModal).toHaveBeenCalled();
});
diff --git a/webapp/channels/src/components/user_settings/plugin/plugin_action.test.tsx b/webapp/channels/src/components/user_settings/plugin/plugin_action.test.tsx
index 0ef5103534e..ea1d697ae3b 100644
--- a/webapp/channels/src/components/user_settings/plugin/plugin_action.test.tsx
+++ b/webapp/channels/src/components/user_settings/plugin/plugin_action.test.tsx
@@ -1,11 +1,10 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
-import {fireEvent, render, screen} from '@testing-library/react';
import type {ComponentProps} from 'react';
import React from 'react';
-import {renderWithContext} from 'tests/react_testing_utils';
+import {render, renderWithContext, screen, userEvent} from 'tests/react_testing_utils';
import PluginAction from './plugin_action';
@@ -28,14 +27,14 @@ describe('PluginAction', () => {
expect(container.firstChild).toBeNull();
});
- it('does show the correct information', () => {
+ it('does show the correct information', async () => {
const props = getBaseProps();
renderWithContext();
const button = screen.getByText(props.action!.buttonText);
expect(button).toBeInTheDocument();
expect(screen.queryByText(props.action!.text)).toBeInTheDocument();
expect(screen.queryByText(props.action!.title)).toBeInTheDocument();
- fireEvent.click(button);
+ await userEvent.click(button);
expect(props.action?.onClick).toHaveBeenCalled();
});
});
diff --git a/webapp/channels/src/components/user_settings/plugin/plugin_setting.test.tsx b/webapp/channels/src/components/user_settings/plugin/plugin_setting.test.tsx
index f99917f4f44..447aad00981 100644
--- a/webapp/channels/src/components/user_settings/plugin/plugin_setting.test.tsx
+++ b/webapp/channels/src/components/user_settings/plugin/plugin_setting.test.tsx
@@ -1,7 +1,7 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
-import {fireEvent, screen} from '@testing-library/react';
+import {screen} from '@testing-library/react';
import type {ComponentProps} from 'react';
import React from 'react';
@@ -78,13 +78,13 @@ describe('plugin setting', () => {
expect(screen.queryByText(OPTION_1_TEXT)).toBeInTheDocument();
});
- it('isDisabled is respected', () => {
+ it('isDisabled is respected', async () => {
const props = getBaseProps();
props.section.disabled = true;
renderWithContext();
expect(screen.queryByText('Edit')).not.toBeInTheDocument();
expect(screen.queryByText(SECTION_TITLE)).toBeInTheDocument();
- fireEvent.click(screen.getByText(SECTION_TITLE));
+ await userEvent.click(screen.getByText(SECTION_TITLE));
expect(screen.queryByText(OPTION_1_TEXT)).not.toBeInTheDocument();
});
@@ -149,39 +149,39 @@ describe('plugin setting', () => {
},
]);
});
- it('does not update anything if nothing has changed', () => {
+ it('does not update anything if nothing has changed', async () => {
const mockSavePreferences = jest.spyOn(preferencesActions, 'savePreferences');
const props = getBaseProps();
props.activeSection = SECTION_TITLE;
renderWithContext();
- fireEvent.click(screen.getByText(SAVE_TEXT));
+ await userEvent.click(screen.getByText(SAVE_TEXT));
expect(props.section.onSubmit).not.toHaveBeenCalled();
expect(props.updateSection).toHaveBeenCalledWith('');
expect(mockSavePreferences).not.toHaveBeenCalled();
});
- it('does not consider anything changed after moving back and forth between sections', () => {
+ it('does not consider anything changed after moving back and forth between sections', async () => {
const mockSavePreferences = jest.spyOn(preferencesActions, 'savePreferences');
const props = getBaseProps();
props.activeSection = SECTION_TITLE;
const {rerender} = renderWithContext();
- fireEvent.click(screen.getByText(OPTION_1_TEXT));
+ await userEvent.click(screen.getByText(OPTION_1_TEXT));
props.activeSection = '';
rerender();
props.activeSection = SECTION_TITLE;
rerender();
- fireEvent.click(screen.getByText(SAVE_TEXT));
+ await userEvent.click(screen.getByText(SAVE_TEXT));
expect(props.section.onSubmit).not.toHaveBeenCalled();
expect(props.updateSection).toHaveBeenCalledWith('');
expect(mockSavePreferences).not.toHaveBeenCalled();
- fireEvent.click(screen.getByText(OPTION_1_TEXT));
+ await userEvent.click(screen.getByText(OPTION_1_TEXT));
props.activeSection = 'other section';
rerender();
props.activeSection = SECTION_TITLE;
rerender();
- fireEvent.click(screen.getByText(SAVE_TEXT));
+ await userEvent.click(screen.getByText(SAVE_TEXT));
expect(props.section.onSubmit).not.toHaveBeenCalled();
expect(props.updateSection).toHaveBeenCalledWith('');
expect(mockSavePreferences).not.toHaveBeenCalled();
diff --git a/webapp/channels/src/components/user_settings/plugin/radio.test.tsx b/webapp/channels/src/components/user_settings/plugin/radio.test.tsx
index 9450e6c02ec..69084bf255d 100644
--- a/webapp/channels/src/components/user_settings/plugin/radio.test.tsx
+++ b/webapp/channels/src/components/user_settings/plugin/radio.test.tsx
@@ -1,7 +1,6 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
-import {screen, fireEvent} from '@testing-library/react';
import type {ComponentProps} from 'react';
import React from 'react';
@@ -9,7 +8,7 @@ import type {DeepPartial} from '@mattermost/types/utilities';
import {getPreferenceKey} from 'mattermost-redux/utils/preference_utils';
-import {renderWithContext} from 'tests/react_testing_utils';
+import {renderWithContext, screen, userEvent} from 'tests/react_testing_utils';
import {getPluginPreferenceKey} from 'utils/plugins/preferences';
import type {GlobalState} from 'types/store';
@@ -57,11 +56,11 @@ describe('radio', () => {
expect(screen.queryByText(props.setting.title!)).toBeInTheDocument();
});
- it('inform change is called', () => {
+ it('inform change is called', async () => {
const props = getBaseProps();
renderWithContext();
- fireEvent.click(screen.getByText(OPTION_1_TEXT));
+ await userEvent.click(screen.getByText(OPTION_1_TEXT));
expect(props.informChange).toHaveBeenCalledWith(SETTING_NAME, '1');
});
@@ -122,7 +121,7 @@ describe('radio', () => {
expect((option1Radio as HTMLInputElement).checked).toBeTruthy();
});
- it('properly persist changes', () => {
+ it('properly persist changes', async () => {
renderWithContext();
const option0Radio = screen.getByText(OPTION_0_TEXT).children[0];
@@ -132,7 +131,7 @@ describe('radio', () => {
expect((option0Radio as HTMLInputElement).checked).toBeTruthy();
expect((option1Radio as HTMLInputElement).checked).toBeFalsy();
- fireEvent.click(option1Radio);
+ await userEvent.click(option1Radio);
expect((option0Radio as HTMLInputElement).checked).toBeFalsy();
expect((option1Radio as HTMLInputElement).checked).toBeTruthy();
});
diff --git a/webapp/channels/src/components/user_settings/plugin/radio_option.test.tsx b/webapp/channels/src/components/user_settings/plugin/radio_option.test.tsx
index d60fdb3f5ed..924a701b98f 100644
--- a/webapp/channels/src/components/user_settings/plugin/radio_option.test.tsx
+++ b/webapp/channels/src/components/user_settings/plugin/radio_option.test.tsx
@@ -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 type {ComponentProps} from 'react';
import React from 'react';
-import {renderWithContext} from 'tests/react_testing_utils';
+import {renderWithContext, screen, userEvent} from 'tests/react_testing_utils';
import RadioOption from './radio_option';
@@ -33,11 +32,11 @@ describe('radio option', () => {
expect(screen.queryByText(props.option.helpText!)).toBeInTheDocument();
});
- it('onSelected is properly called', () => {
+ it('onSelected is properly called', async () => {
const props = getBaseProps();
renderWithContext();
- fireEvent.click(screen.getByText(props.option.text));
+ await userEvent.click(screen.getByText(props.option.text));
expect(props.onSelected).toHaveBeenCalledWith(props.option.value);
});
diff --git a/webapp/channels/src/components/widgets/admin_console/admin_panel.test.tsx b/webapp/channels/src/components/widgets/admin_console/admin_panel.test.tsx
index e9636e96c50..83a7c661cfb 100644
--- a/webapp/channels/src/components/widgets/admin_console/admin_panel.test.tsx
+++ b/webapp/channels/src/components/widgets/admin_console/admin_panel.test.tsx
@@ -1,10 +1,9 @@
// 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 {renderWithContext, screen} from 'tests/react_testing_utils';
+import {renderWithContext, screen, userEvent} from 'tests/react_testing_utils';
import AdminPanel from './admin_panel';
diff --git a/webapp/channels/src/components/widgets/admin_console/admin_panel_with_button.test.tsx b/webapp/channels/src/components/widgets/admin_console/admin_panel_with_button.test.tsx
index d13103e714d..cc22f186376 100644
--- a/webapp/channels/src/components/widgets/admin_console/admin_panel_with_button.test.tsx
+++ b/webapp/channels/src/components/widgets/admin_console/admin_panel_with_button.test.tsx
@@ -1,10 +1,9 @@
// 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 {renderWithContext, screen} from 'tests/react_testing_utils';
+import {renderWithContext, screen, userEvent} from 'tests/react_testing_utils';
import AdminPanelWithButton from './admin_panel_with_button';
diff --git a/webapp/channels/src/components/widgets/admin_console/admin_panel_with_link.test.tsx b/webapp/channels/src/components/widgets/admin_console/admin_panel_with_link.test.tsx
index 5e951c3dca3..335e31662f6 100644
--- a/webapp/channels/src/components/widgets/admin_console/admin_panel_with_link.test.tsx
+++ b/webapp/channels/src/components/widgets/admin_console/admin_panel_with_link.test.tsx
@@ -1,10 +1,9 @@
// 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 {renderWithContext, screen} from 'tests/react_testing_utils';
+import {renderWithContext, screen, userEvent} from 'tests/react_testing_utils';
import AdminPanelWithLink from './admin_panel_with_link';
diff --git a/webapp/channels/src/components/widgets/advanced_textbox/advanced_textbox.test.tsx b/webapp/channels/src/components/widgets/advanced_textbox/advanced_textbox.test.tsx
index 0689081dcef..1506dcc599f 100644
--- a/webapp/channels/src/components/widgets/advanced_textbox/advanced_textbox.test.tsx
+++ b/webapp/channels/src/components/widgets/advanced_textbox/advanced_textbox.test.tsx
@@ -1,11 +1,11 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
-import {render, screen, fireEvent} from '@testing-library/react';
-import userEvent from '@testing-library/user-event';
import React from 'react';
import type {ComponentProps} from 'react';
+import {fireEvent, render, screen, userEvent} from 'tests/react_testing_utils';
+
import AdvancedTextbox from './advanced_textbox';
// Mock dependencies
@@ -52,10 +52,6 @@ describe('AdvancedTextbox', () => {
descriptionMessage: 'This is a description',
};
- beforeEach(() => {
- jest.clearAllMocks();
- });
-
test('renders correctly with all props', () => {
render();
@@ -274,6 +270,8 @@ describe('AdvancedTextbox', () => {
// Focus the textbox
const textbox = screen.getByTestId('mock-textbox');
+
+ // Simulate focus event - fireEvent used because userEvent doesn't have direct focus/blur methods
fireEvent.focus(textbox);
// Label should now have active class
@@ -286,13 +284,14 @@ describe('AdvancedTextbox', () => {
// Focus the textbox
const textbox = screen.getByTestId('mock-textbox');
+
fireEvent.focus(textbox);
// Label should have active class
let label = document.querySelector('.AdvancedTextbox__label');
expect(label).toHaveClass('AdvancedTextbox__label--active');
- // Blur the textbox
+ // Simulate blur event - fireEvent used because userEvent doesn't have direct focus/blur methods
fireEvent.blur(textbox);
// Label should not have active class
@@ -305,13 +304,13 @@ describe('AdvancedTextbox', () => {
// Focus the textbox
const textbox = screen.getByTestId('mock-textbox');
+
fireEvent.focus(textbox);
// Label should have active class
let label = document.querySelector('.AdvancedTextbox__label');
expect(label).toHaveClass('AdvancedTextbox__label--active');
- // Blur the textbox
fireEvent.blur(textbox);
// Label should still have active class because there's a value
diff --git a/webapp/channels/src/components/widgets/inputs/input/input.test.tsx b/webapp/channels/src/components/widgets/inputs/input/input.test.tsx
index d21158bb629..8b3e01e4fd7 100644
--- a/webapp/channels/src/components/widgets/inputs/input/input.test.tsx
+++ b/webapp/channels/src/components/widgets/inputs/input/input.test.tsx
@@ -1,11 +1,9 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
-import {act, screen, fireEvent} from '@testing-library/react';
-import userEvent from '@testing-library/user-event';
import React from 'react';
-import {renderWithContext} from 'tests/react_testing_utils';
+import {act, fireEvent, renderWithContext, screen, userEvent} from 'tests/react_testing_utils';
import Input from './input';
@@ -74,6 +72,7 @@ describe('components/widgets/inputs/Input', () => {
const input = container.querySelector('input') as HTMLInputElement;
+ // Trigger validation on blur - fireEvent used because userEvent doesn't have direct focus/blur methods
await act(async () => {
fireEvent.focus(input);
fireEvent.blur(input);
@@ -119,7 +118,7 @@ describe('components/widgets/inputs/Input', () => {
// Click the button
await act(async () => {
- fireEvent.click(button);
+ await userEvent.click(button);
});
// Should validate after click
diff --git a/webapp/channels/src/components/widgets/menu/menu.test.tsx b/webapp/channels/src/components/widgets/menu/menu.test.tsx
index 65f38503bad..9e51c99e8a6 100644
--- a/webapp/channels/src/components/widgets/menu/menu.test.tsx
+++ b/webapp/channels/src/components/widgets/menu/menu.test.tsx
@@ -3,7 +3,7 @@
import React from 'react';
-import {fireEvent, render, screen} from 'tests/react_testing_utils';
+import {render, screen, userEvent} from 'tests/react_testing_utils';
import Menu from './menu';
@@ -239,7 +239,7 @@ describe('components/Menu', () => {
expect(dividers[0]).toHaveStyle({display: 'block'});
});
- test('should keep menu open when clicking empty space but allow closing from menu items', () => {
+ test('should keep menu open when clicking empty space but allow closing from menu items', async () => {
const TestComponent = () => {
const [isMenuOpen, setIsMenuOpen] = React.useState(true);
@@ -273,14 +273,14 @@ describe('components/Menu', () => {
expect(screen.queryByTestId('menu-closed')).not.toBeInTheDocument();
// Clicking empty space in menu should NOT close it
- fireEvent.click(menu);
+ await userEvent.click(menu);
menu = screen.getByRole('menu');
expect(menu).toBeInTheDocument();
expect(screen.queryByTestId('menu-closed')).not.toBeInTheDocument();
// But clicking a menu item SHOULD close it (event bubbles normally)
const menuItem = screen.getByRole('button', {name: 'Close Menu'});
- fireEvent.click(menuItem);
+ await userEvent.click(menuItem);
expect(screen.queryByRole('menu')).not.toBeInTheDocument();
expect(screen.getByTestId('menu-closed')).toBeInTheDocument();
});
diff --git a/webapp/channels/src/components/widgets/menu/menu_group.test.tsx b/webapp/channels/src/components/widgets/menu/menu_group.test.tsx
index 0d8bfa1c0da..e9adccedfe7 100644
--- a/webapp/channels/src/components/widgets/menu/menu_group.test.tsx
+++ b/webapp/channels/src/components/widgets/menu/menu_group.test.tsx
@@ -3,7 +3,7 @@
import React from 'react';
-import {fireEvent, render, screen} from 'tests/react_testing_utils';
+import {render, screen, userEvent} from 'tests/react_testing_utils';
import MenuGroup from './menu_group';
@@ -29,13 +29,13 @@ describe('components/MenuItem', () => {
expect(screen.queryByRole('separator')).not.toBeInTheDocument();
});
- test('should prevent default and stop propagation when divider is clicked', () => {
+ test('should prevent default and stop propagation when divider is clicked', async () => {
render({'text'});
const separator = screen.getByRole('separator');
// Fire click event on separator
- fireEvent.click(separator);
+ await userEvent.click(separator);
// Verify the element exists and is clickable
expect(separator).toBeInTheDocument();
diff --git a/webapp/channels/src/components/widgets/menu/menu_modals/submenu_modal/submenu_modal.test.tsx b/webapp/channels/src/components/widgets/menu/menu_modals/submenu_modal/submenu_modal.test.tsx
index b7ad233a87c..470c4587346 100644
--- a/webapp/channels/src/components/widgets/menu/menu_modals/submenu_modal/submenu_modal.test.tsx
+++ b/webapp/channels/src/components/widgets/menu/menu_modals/submenu_modal/submenu_modal.test.tsx
@@ -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 {shallow} from 'enzyme';
import React from 'react';
import {Modal} from 'react-bootstrap';
@@ -65,7 +65,7 @@ describe('components/submenu_modal', () => {
screen.getByText('Text B');
screen.getByText('Text C');
- fireEvent.click(view.getByTestId('SubMenuModalBody'));
+ await userEvent.click(view.getByTestId('SubMenuModalBody'));
await waitForElementToBeRemoved(() => screen.getByText('Text A'));
expect(screen.queryAllByText('Text B').length).toBe(0);
diff --git a/webapp/channels/src/components/widgets/menu/menu_wrapper.test.tsx b/webapp/channels/src/components/widgets/menu/menu_wrapper.test.tsx
index 40a1ccc8195..16580bccbe9 100644
--- a/webapp/channels/src/components/widgets/menu/menu_wrapper.test.tsx
+++ b/webapp/channels/src/components/widgets/menu/menu_wrapper.test.tsx
@@ -1,10 +1,9 @@
// 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 {fireEvent, render} from 'tests/react_testing_utils';
+import {fireEvent, render, userEvent} from 'tests/react_testing_utils';
import MenuWrapper from './menu_wrapper';
@@ -160,6 +159,7 @@ describe('components/MenuWrapper', () => {
expect(wrapper).toHaveClass('MenuWrapper--open');
// Press ESC key
+ // fireEvent on document used because userEvent.keyboard requires element focus
fireEvent.keyUp(document, {key: 'Escape', code: 'Escape'});
// Menu should be closed
@@ -190,6 +190,8 @@ describe('components/MenuWrapper', () => {
// Simulate TAB key to an element outside the menu
const outsideButton = container.querySelectorAll('button')[2];
+
+ // fireEvent on document used because userEvent.keyboard requires element focus
fireEvent.keyUp(outsideButton, {key: 'Tab', code: 'Tab'});
// Menu should be closed
@@ -217,6 +219,8 @@ describe('components/MenuWrapper', () => {
// Simulate TAB key within the menu
const menuButton = container.querySelectorAll('button')[1];
+
+ // fireEvent on document used because userEvent.keyboard requires element focus
fireEvent.keyUp(menuButton, {key: 'Tab', code: 'Tab'});
// Menu should still be open
@@ -244,6 +248,7 @@ describe('components/MenuWrapper', () => {
onToggle.mockClear();
// Press ESC key
+ // fireEvent on document used because userEvent.keyboard requires element focus
fireEvent.keyUp(document, {key: 'Escape', code: 'Escape'});
// onToggle should be called with false
@@ -262,6 +267,7 @@ describe('components/MenuWrapper', () => {
const wrapper = container.querySelector('.MenuWrapper');
// Menu is closed by default, press ESC
+ // fireEvent on document used because userEvent.keyboard requires element focus
fireEvent.keyUp(document, {key: 'Escape', code: 'Escape'});
// onToggle should not be called since menu was already closed
diff --git a/webapp/channels/src/components/widgets/modals/components/react_select_item.test.tsx b/webapp/channels/src/components/widgets/modals/components/react_select_item.test.tsx
index 408390a6f3c..d5a1d84840c 100644
--- a/webapp/channels/src/components/widgets/modals/components/react_select_item.test.tsx
+++ b/webapp/channels/src/components/widgets/modals/components/react_select_item.test.tsx
@@ -16,10 +16,6 @@ const mockIntl = {
};
describe('getOptionLabel', () => {
- beforeEach(() => {
- jest.clearAllMocks();
- });
-
test('should return string label as-is', () => {
const option: SelectOption = {
value: 'test',
diff --git a/webapp/channels/src/components/widgets/settings/bool_setting.test.tsx b/webapp/channels/src/components/widgets/settings/bool_setting.test.tsx
index 4ac234fd310..32cc0337abe 100644
--- a/webapp/channels/src/components/widgets/settings/bool_setting.test.tsx
+++ b/webapp/channels/src/components/widgets/settings/bool_setting.test.tsx
@@ -1,10 +1,9 @@
// 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 {render, screen} from 'tests/react_testing_utils';
+import {render, screen, userEvent} from 'tests/react_testing_utils';
import BoolSetting from './bool_setting';
diff --git a/webapp/channels/src/components/widgets/settings/radio_setting.test.tsx b/webapp/channels/src/components/widgets/settings/radio_setting.test.tsx
index dcf0b0aabdc..99ab8ee69fb 100644
--- a/webapp/channels/src/components/widgets/settings/radio_setting.test.tsx
+++ b/webapp/channels/src/components/widgets/settings/radio_setting.test.tsx
@@ -1,10 +1,9 @@
// 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 {render, screen} from 'tests/react_testing_utils';
+import {render, screen, userEvent} from 'tests/react_testing_utils';
import RadioSetting from './radio_setting';
diff --git a/webapp/channels/src/components/widgets/settings/text_setting.test.tsx b/webapp/channels/src/components/widgets/settings/text_setting.test.tsx
index 7f370b7f2f9..7d6e74acd26 100644
--- a/webapp/channels/src/components/widgets/settings/text_setting.test.tsx
+++ b/webapp/channels/src/components/widgets/settings/text_setting.test.tsx
@@ -1,10 +1,9 @@
// 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 {render, screen} from 'tests/react_testing_utils';
+import {render, screen, userEvent} from 'tests/react_testing_utils';
import TextSetting from './text_setting';
diff --git a/webapp/channels/src/components/widgets/tag/alert_tag.test.tsx b/webapp/channels/src/components/widgets/tag/alert_tag.test.tsx
index 97a5cd6004a..63e8767f818 100644
--- a/webapp/channels/src/components/widgets/tag/alert_tag.test.tsx
+++ b/webapp/channels/src/components/widgets/tag/alert_tag.test.tsx
@@ -1,10 +1,10 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
-import {screen, render} from '@testing-library/react';
-import userEvent from '@testing-library/user-event';
import React from 'react';
+import {render, screen, userEvent} from 'tests/react_testing_utils';
+
import AlertTag from './alert_tag';
describe('components/widgets/tag/AlertTag', () => {
diff --git a/webapp/channels/src/components/widgets/tag/tag.test.tsx b/webapp/channels/src/components/widgets/tag/tag.test.tsx
index cf3ed9bcca4..56b1a7d5651 100644
--- a/webapp/channels/src/components/widgets/tag/tag.test.tsx
+++ b/webapp/channels/src/components/widgets/tag/tag.test.tsx
@@ -1,10 +1,10 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
-import {render, screen} from '@testing-library/react';
-import userEvent from '@testing-library/user-event';
import React from 'react';
+import {render, screen, userEvent} from 'tests/react_testing_utils';
+
import Tag from './tag';
describe('components/widgets/tag/Tag', () => {
diff --git a/webapp/channels/src/components/widgets/users/avatar/avatar.test.tsx b/webapp/channels/src/components/widgets/users/avatar/avatar.test.tsx
index 458e2cacbe2..fcf86d81b79 100644
--- a/webapp/channels/src/components/widgets/users/avatar/avatar.test.tsx
+++ b/webapp/channels/src/components/widgets/users/avatar/avatar.test.tsx
@@ -86,7 +86,7 @@ describe('components/widgets/users/Avatar', () => {
const avatar = screen.getByRole('img') as HTMLImageElement;
expect(avatar.src).toContain('userid123');
- // Simulate image load error
+ // Simulate image error event - fireEvent used because userEvent doesn't support image loading events
fireEvent.error(avatar);
// Should fall back to default user avatar (replace ?_= with /default)
@@ -103,7 +103,6 @@ describe('components/widgets/users/Avatar', () => {
const avatar = screen.getByRole('img') as HTMLImageElement;
const initialSrc = avatar.src;
- // Simulate image load error
fireEvent.error(avatar);
// Should change from the initial URL (bot icon set, even if empty in test environment)
@@ -124,7 +123,6 @@ describe('components/widgets/users/Avatar', () => {
const avatar = screen.getByRole('img') as HTMLImageElement;
const initialSrc = avatar.src;
- // Simulate image load error
fireEvent.error(avatar);
// Should not change src if it's already the fallback
diff --git a/webapp/channels/src/components/with_tooltip/index.test.tsx b/webapp/channels/src/components/with_tooltip/index.test.tsx
index e7d5dcedad0..1d51a96a11b 100644
--- a/webapp/channels/src/components/with_tooltip/index.test.tsx
+++ b/webapp/channels/src/components/with_tooltip/index.test.tsx
@@ -1,10 +1,9 @@
// 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 {renderWithContext, screen, waitFor} from 'tests/react_testing_utils';
+import {renderWithContext, screen, userEvent, waitFor} from 'tests/react_testing_utils';
import WithTooltip from './index';
diff --git a/webapp/channels/src/components/youtube_video/youtube_video.test.tsx b/webapp/channels/src/components/youtube_video/youtube_video.test.tsx
index 2206a6da905..4a7e3d92ebd 100644
--- a/webapp/channels/src/components/youtube_video/youtube_video.test.tsx
+++ b/webapp/channels/src/components/youtube_video/youtube_video.test.tsx
@@ -130,7 +130,7 @@ describe('YoutubeVideo', () => {
'https://img.youtube.com/vi/xqCoNej8Zxo/maxresdefault.jpg',
);
- // Simulate an image error
+ // Simulate thumbnail loading failure to test fallback behavior - fireEvent used because userEvent doesn't support image loading events
fireEvent.error(thumbnail!);
// Verify that hqdefault is used after error (useMaxResThumbnail is now false)
diff --git a/webapp/channels/src/hooks/useChannelAccessControlActions.test.ts b/webapp/channels/src/hooks/useChannelAccessControlActions.test.ts
index 7161bb3bdf8..97dae465321 100644
--- a/webapp/channels/src/hooks/useChannelAccessControlActions.test.ts
+++ b/webapp/channels/src/hooks/useChannelAccessControlActions.test.ts
@@ -25,10 +25,6 @@ const mockGetVisualAST = getVisualAST as jest.MockedFunction;
describe('useChannelAccessControlActions', () => {
- beforeEach(() => {
- jest.clearAllMocks();
- });
-
test('should have correct action imports', () => {
// Test that the required actions are imported and mocked correctly
expect(getAccessControlFields).toBeDefined();
diff --git a/webapp/channels/src/utils/popouts/popout_windows.test.ts b/webapp/channels/src/utils/popouts/popout_windows.test.ts
index a9948aab5e0..ebf26ef9896 100644
--- a/webapp/channels/src/utils/popouts/popout_windows.test.ts
+++ b/webapp/channels/src/utils/popouts/popout_windows.test.ts
@@ -46,7 +46,6 @@ const getMockSetupBrowserPopout = () => {
describe('popout_windows', () => {
beforeEach(() => {
- jest.clearAllMocks();
getMockSetupBrowserPopout().mockClear();
// Default: no subpath