[MM-55294] Migrate jest v26 to v29 to speed up "web app CI PR / test" (#25192)

This commit is contained in:
M-ZubairAhmed 2023-11-07 11:41:26 +05:30 committed by GitHub
parent 4dbf1f8c26
commit f733dc58fa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
33 changed files with 8913 additions and 495 deletions

View File

@ -41,14 +41,20 @@ const config = {
'node_modules/(?!react-native|react-router|p-queue|p-timeout|@mattermost/compass-components|@mattermost/compass-icons)',
],
setupFiles: ['jest-canvas-mock'],
setupFilesAfterEnv: ['<rootDir>/src/tests/setup.ts'],
setupFilesAfterEnv: ['<rootDir>/src/tests/setup_jest.ts'],
testEnvironment: 'jsdom',
testTimeout: 60000,
testURL: 'http://localhost:8065',
testEnvironmentOptions: {
url: 'http://localhost:8065',
},
watchPlugins: [
'jest-watch-typeahead/filename',
'jest-watch-typeahead/testname',
],
snapshotFormat: {
escapeString: true,
printBasicPrototype: true,
},
};
module.exports = config;

View File

@ -110,7 +110,7 @@
"@types/bootstrap": "4.5.0",
"@types/country-list": "2.1.0",
"@types/enzyme": "3.10.11",
"@types/jest": "26.0.24",
"@types/jest": "28.1.8",
"@types/katex": "0.11.0",
"@types/lodash": "4.14.182",
"@types/luxon": "3.0.2",
@ -125,7 +125,7 @@
"@types/react-dom": "17.0.2",
"@types/react-is": "17.0.2",
"@types/react-overlays": "1.1.3",
"@types/react-redux": "7.1.16",
"@types/react-redux": "7.1.26",
"@types/react-router-dom": "5.3.3",
"@types/react-select": "3.0.19",
"@types/react-transition-group": "4.4.5",
@ -157,12 +157,13 @@
"identity-obj-proxy": "3.0.0",
"image-webpack-loader": "8.1.0",
"isomorphic-fetch": "3.0.0",
"jest": "27.1.0",
"jest-canvas-mock": "2.4.0",
"jest-cli": "27.1.0",
"jest-junit": "12.2.0",
"jest-styled-components": "7.1.1",
"jest-watch-typeahead": "0.6.4",
"jest": "29.7.0",
"jest-canvas-mock": "2.5.0",
"jest-cli": "29.7.0",
"jest-environment-jsdom": "29.7.0",
"jest-junit": "16.0.0",
"jest-styled-components": "7.2.0",
"jest-watch-typeahead": "2.2.2",
"mmjstool": "github:mattermost/mattermost-utilities#83b1b311972b8f5e750aae4019457a40abb5aa44",
"nock": "13.2.8",
"prettier": "2.3.2",

View File

@ -199,7 +199,7 @@ describe('rhs view actions', () => {
const draft = {message: 'test msg', fileInfos: [{id: 1}], uploadsInProgress: [2, 3]};
test('it calls setGlobalItem action correctly', () => {
jest.useFakeTimers('modern');
jest.useFakeTimers();
jest.setSystemTime(42);
store.dispatch(updateCommentDraft(rootId, draft));
@ -220,7 +220,7 @@ describe('rhs view actions', () => {
describe('makeOnMoveHistoryIndex', () => {
beforeAll(() => {
jest.useFakeTimers('modern');
jest.useFakeTimers();
jest.setSystemTime(42);
});

View File

@ -137,7 +137,7 @@ describe('draft actions', () => {
const draft = {message: 'test', channelId, fileInfos: [{id: 1}], uploadsInProgress: [2, 3]} as unknown as PostDraft;
it('calls setGlobalItem action correctly', async () => {
jest.useFakeTimers('modern');
jest.useFakeTimers();
jest.setSystemTime(42);
await store.dispatch(updateDraft(key, draft, '', false));

View File

@ -882,7 +882,7 @@ describe('rhs view actions', () => {
const post3 = {id: '44'} as Post;
beforeEach(() => {
jest.useFakeTimers('modern');
jest.useFakeTimers();
jest.setSystemTime(POST_CREATED_TIME);
});

View File

@ -23,7 +23,6 @@ exports[`components/TextBox should match snapshot with additional, optional prop
/>
</div>
<Connect(SuggestionBox)
channelId="channelId"
className="form-control custom-textarea textbox-edit-area custom-textarea--emoji-picker bad-connection"
contextId="channelId"
disabled={true}
@ -153,7 +152,6 @@ exports[`components/TextBox should match snapshot with required props 1`] = `
/>
</div>
<Connect(SuggestionBox)
channelId="channelId"
className="form-control custom-textarea textbox-edit-area"
contextId="channelId"
id="someid"
@ -278,7 +276,6 @@ exports[`components/TextBox should throw error when new property is too long 1`]
/>
</div>
<Connect(SuggestionBox)
channelId="channelId"
className="form-control custom-textarea textbox-edit-area"
contextId="channelId"
id="someid"
@ -403,7 +400,6 @@ exports[`components/TextBox should throw error when value is too long 1`] = `
/>
</div>
<Connect(SuggestionBox)
channelId="channelId"
className="form-control custom-textarea textbox-edit-area"
contextId="channelId"
id="someid"

View File

@ -258,6 +258,8 @@ export default class AddUserToChannelModal extends React.PureComponent<Props, St
const content = (
<SuggestionBox
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
ref={this.setSearchBoxRef}
className='form-control focused'
onChange={this.onInputChange}

View File

@ -2,7 +2,6 @@
// See LICENSE.txt for license information.
import {shallow} from 'enzyme';
import expect from 'expect';
import moment from 'moment';
import React from 'react';
import type {ComponentProps} from 'react';

View File

@ -140,7 +140,7 @@ function advancedCreatePost(props?: Partial<Props>) {
}
describe('components/advanced_create_post', () => {
jest.useFakeTimers('legacy');
jest.useFakeTimers({legacyFakeTimers: true});
let spy: jest.SpyInstance;
beforeEach(() => {

View File

@ -156,8 +156,10 @@ export default class AutocompleteSelector extends React.PureComponent<Props, Sta
{labelContent}
<div className={inputClassName}>
<SuggestionBox
placeholder={placeholder}
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
ref={this.setSuggestionRef}
placeholder={placeholder}
listComponent={listComponent}
className='form-control'
containerClass='select-suggestion-container'

View File

@ -15,7 +15,7 @@ import SearchableChannelList from 'components/searchable_channel_list';
import {getHistory} from 'utils/browser_history';
import {TestHelper} from 'utils/test_helper';
jest.useFakeTimers('legacy');
jest.useFakeTimers({legacyFakeTimers: true});
describe('components/BrowseChannels', () => {
const searchResults = {

View File

@ -8,7 +8,7 @@ import {getHistory} from 'utils/browser_history';
import ChannelIdentifierRouter from './channel_identifier_router';
jest.useFakeTimers('legacy');
jest.useFakeTimers({legacyFakeTimers: true});
describe('components/channel_layout/CenterChannel', () => {
const baseProps = {

View File

@ -14,10 +14,10 @@ import AnyTeamPermissionGate from 'components/permissions_gates/any_team_permiss
import DeleteEmojiButton from './delete_emoji_button';
export type Props = {
emoji: CustomEmoji;
emoji?: CustomEmoji;
emojiId?: string;
currentUserId: string;
creatorDisplayName: string;
currentUserId?: string;
creatorDisplayName?: string;
creatorUsername?: string;
onDelete?: (emojiId: string) => void;
actions: {
@ -33,6 +33,10 @@ export default class EmojiListItem extends React.PureComponent<Props> {
};
handleDelete = (): void => {
if (!this.props.emoji) {
return;
}
if (this.props.onDelete) {
this.props.onDelete(this.props.emoji.id);
}
@ -41,7 +45,7 @@ export default class EmojiListItem extends React.PureComponent<Props> {
};
render(): JSX.Element {
const emoji = this.props.emoji;
const emoji = this.props.emoji as CustomEmoji;
const creatorUsername = this.props.creatorUsername;
let creatorDisplayName = this.props.creatorDisplayName;

View File

@ -135,7 +135,7 @@ describe('components/MoreDirectChannels', () => {
});
test('should call on search', () => {
jest.useFakeTimers('modern');
jest.useFakeTimers();
const props = {...baseProps, actions: {...baseProps.actions, setModalSearchTerm: jest.fn()}};
const wrapper = shallow<MoreDirectChannels>(<MoreDirectChannels {...props}/>);
wrapper.instance().search('user_search');
@ -178,7 +178,7 @@ describe('components/MoreDirectChannels', () => {
});
test('should open a DM', (done) => {
jest.useFakeTimers('legacy');
jest.useFakeTimers({legacyFakeTimers: true});
const user: UserProfile = {
...mockedUser,
id: 'user_id_1',
@ -203,7 +203,7 @@ describe('components/MoreDirectChannels', () => {
});
test('should open a GM', (done) => {
jest.useFakeTimers('legacy');
jest.useFakeTimers({legacyFakeTimers: true});
const wrapper = shallow<MoreDirectChannels>(<MoreDirectChannels {...baseProps}/>);
const handleHide = jest.fn();
const exitToChannel = '';

View File

@ -39,11 +39,10 @@ function CommentedOn({post, parentPostUser, onCommentClick}: Props) {
};
const message = makeCommentedOnMessage();
const parentPostUserId = parentPostUser?.id || '';
const parentPostUserId = parentPostUser?.id ?? '';
const parentUserProfile = (
<UserProfile
user={parentPostUser}
userId={parentPostUserId}
hasMention={true}
disablePopover={false}

View File

@ -173,7 +173,7 @@ const PostMessagePreview = (props: Props) => {
</div>
<div className={classNames('col col__name', 'permalink--username')}>
<UserProfileComponent
userId={user?.id}
userId={user?.id ?? ''}
hasMention={true}
disablePopover={true}
overwriteName={previewPost.props?.override_username || ''}

View File

@ -77,7 +77,7 @@ exports[`components/QuickSwitchModal should match snapshot 1`] = `
id="quickSwitchInput"
listComponent={[Function]}
listPosition="bottom"
maxLength={64}
maxLength="64"
onChange={[Function]}
onItemSelected={[Function]}
onSuggestionsReceived={[Function]}

View File

@ -216,16 +216,18 @@ export default class QuickSwitchModal extends React.PureComponent<Props, State>
<div className='channel-switcher__suggestion-box'>
<i className='icon icon-magnify icon-16'/>
<SuggestionBox
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
ref={this.setSwitchBoxRef}
id='quickSwitchInput'
aria-label={Utils.localizeMessage('quick_switch_modal.input', 'quick switch input')}
ref={this.setSwitchBoxRef}
className='form-control focused'
onChange={this.onChange}
value={this.state.text}
onItemSelected={this.handleSubmit}
listComponent={SuggestionList}
listPosition='bottom'
maxLength={64}
maxLength='64'
providers={providers}
completeOnTab={false}
spellCheck='false'

View File

@ -150,6 +150,8 @@ const SearchBar: React.FunctionComponent<Props> = (props: Props): JSX.Element =>
</div>
)}
<SuggestionBox
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
ref={getSearch}
id={props.isSideBarRight ? 'sbrSearchBox' : 'searchBox'}
tabIndex='0'

View File

@ -21,7 +21,7 @@ export default class SuggestionBox extends React.PureComponent {
/**
* The list component to render, usually SuggestionList
*/
listComponent: PropTypes.func.isRequired,
listComponent: PropTypes.any.isRequired,
/**
* Where the list will be displayed relative to the input box, defaults to 'top'
@ -36,7 +36,7 @@ export default class SuggestionBox extends React.PureComponent {
/**
* The date component to render
*/
dateComponent: PropTypes.func,
dateComponent: PropTypes.any,
/**
* The value of in the input
@ -152,6 +152,26 @@ export default class SuggestionBox extends React.PureComponent {
actions: PropTypes.shape({
addMessageIntoHistory: PropTypes.func.isRequired,
}).isRequired,
/**
* Props for input
*/
id: PropTypes.string,
className: PropTypes.string,
placeholder: PropTypes.string,
maxLength: PropTypes.string,
delayInputUpdate: PropTypes.bool,
spellCheck: PropTypes.string,
onMouseUp: PropTypes.func,
onKeyUp: PropTypes.func,
onHeightChange: PropTypes.func,
onWidthChange: PropTypes.func,
onPaste: PropTypes.func,
style: PropTypes.object,
tabIndex: PropTypes.string,
type: PropTypes.string,
clearable: PropTypes.bool,
onClear: PropTypes.func,
};
static defaultProps = {

View File

@ -295,8 +295,10 @@ export default class Textbox extends React.PureComponent<Props> {
/>
</div>
<SuggestionBox
id={this.props.id}
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
ref={this.message}
id={this.props.id}
className={textboxClassName}
spellCheck='true'
placeholder={this.props.createMessage}
@ -316,7 +318,6 @@ export default class Textbox extends React.PureComponent<Props> {
listComponent={this.props.suggestionList}
listPosition={this.props.suggestionListPosition}
providers={this.suggestionProviders}
channelId={this.props.channelId}
value={this.props.value}
renderDividers={ALL}
disabled={this.props.disabled}

View File

@ -123,7 +123,7 @@ describe('components/threading/ThreadViewer', () => {
});
test('should call updateThreadLastOpened on mount', () => {
jest.useFakeTimers('modern').setSystemTime(400);
jest.useFakeTimers().setSystemTime(400);
const {actions} = baseProps;
const userThread = {
id: 'id',
@ -146,7 +146,7 @@ describe('components/threading/ThreadViewer', () => {
});
test('should call updateThreadLastOpened and updateThreadRead on mount when unread replies', () => {
jest.useFakeTimers('modern').setSystemTime(400);
jest.useFakeTimers().setSystemTime(400);
const {actions} = baseProps;
const userThread = {
id: 'id',

View File

@ -2,12 +2,12 @@
exports[`components/three_days_left_trial_modal/three_days_left_trial_modal should match snapshot 1`] = `
"<ContextProvider value={{...}}>
<ThreeDaysLeftTrialModal onExited={[Function: mockConstructor] { _isMockFunction: true, getMockImplementation: [Function (anonymous)], mock: Object [Object: null prototype] { calls: [], instances: [], invocationCallOrder: [], results: [] }, mockClear: [Function (anonymous)], mockReset: [Function (anonymous)], mockRestore: [Function (anonymous)], mockReturnValueOnce: [Function (anonymous)], mockResolvedValueOnce: [Function (anonymous)], mockRejectedValueOnce: [Function (anonymous)], mockReturnValue: [Function (anonymous)], mockResolvedValue: [Function (anonymous)], mockRejectedValue: [Function (anonymous)], mockImplementationOnce: [Function (anonymous)], mockImplementation: [Function (anonymous)], mockReturnThis: [Function (anonymous)], mockName: [Function (anonymous)], getMockName: [Function (anonymous)] }} limitsOverpassed={false} />
<ThreeDaysLeftTrialModal onExited={[Function: mockConstructor] { _isMockFunction: true, getMockImplementation: [Function (anonymous)], mock: Object [Object: null prototype] { calls: [], contexts: [], instances: [], invocationCallOrder: [], results: [] }, mockClear: [Function (anonymous)], mockReset: [Function (anonymous)], mockRestore: [Function (anonymous)], mockReturnValueOnce: [Function (anonymous)], mockResolvedValueOnce: [Function (anonymous)], mockRejectedValueOnce: [Function (anonymous)], mockReturnValue: [Function (anonymous)], mockResolvedValue: [Function (anonymous)], mockRejectedValue: [Function (anonymous)], mockImplementationOnce: [Function (anonymous)], withImplementation: [Function: bound withImplementation], mockImplementation: [Function (anonymous)], mockReturnThis: [Function (anonymous)], mockName: [Function (anonymous)], getMockName: [Function (anonymous)] }} limitsOverpassed={false} />
</ContextProvider>"
`;
exports[`components/three_days_left_trial_modal/three_days_left_trial_modal should match snapshot when limits are overpassed and show the limits panel 1`] = `
"<ContextProvider value={{...}}>
<ThreeDaysLeftTrialModal onExited={[Function: mockConstructor] { _isMockFunction: true, getMockImplementation: [Function (anonymous)], mock: Object [Object: null prototype] { calls: [], instances: [], invocationCallOrder: [], results: [] }, mockClear: [Function (anonymous)], mockReset: [Function (anonymous)], mockRestore: [Function (anonymous)], mockReturnValueOnce: [Function (anonymous)], mockResolvedValueOnce: [Function (anonymous)], mockRejectedValueOnce: [Function (anonymous)], mockReturnValue: [Function (anonymous)], mockResolvedValue: [Function (anonymous)], mockRejectedValue: [Function (anonymous)], mockImplementationOnce: [Function (anonymous)], mockImplementation: [Function (anonymous)], mockReturnThis: [Function (anonymous)], mockName: [Function (anonymous)], getMockName: [Function (anonymous)] }} limitsOverpassed={true} />
<ThreeDaysLeftTrialModal onExited={[Function: mockConstructor] { _isMockFunction: true, getMockImplementation: [Function (anonymous)], mock: Object [Object: null prototype] { calls: [], contexts: [], instances: [], invocationCallOrder: [], results: [] }, mockClear: [Function (anonymous)], mockReset: [Function (anonymous)], mockRestore: [Function (anonymous)], mockReturnValueOnce: [Function (anonymous)], mockResolvedValueOnce: [Function (anonymous)], mockRejectedValueOnce: [Function (anonymous)], mockReturnValue: [Function (anonymous)], mockResolvedValue: [Function (anonymous)], mockRejectedValue: [Function (anonymous)], mockImplementationOnce: [Function (anonymous)], withImplementation: [Function: bound withImplementation], mockImplementation: [Function (anonymous)], mockReturnThis: [Function (anonymous)], mockName: [Function (anonymous)], getMockName: [Function (anonymous)] }} limitsOverpassed={true} />
</ContextProvider>"
`;

View File

@ -19,14 +19,14 @@ import {imageURLForUser} from 'utils/utils';
import {generateColor} from './utils';
export type UserProfileProps = {
export type Props = {
user?: UserProfileType;
userId: string;
displayName?: string;
isBusy?: boolean;
isShared?: boolean;
overwriteName?: React.ReactNode;
overwriteIcon?: string;
user?: UserProfileType;
disablePopover?: boolean;
displayUsername?: boolean;
colorize?: boolean;
@ -38,10 +38,10 @@ export type UserProfileProps = {
theme?: Theme;
}
export default class UserProfile extends PureComponent<UserProfileProps> {
export default class UserProfile extends PureComponent<Props> {
private overlay?: BaseOverlayTrigger;
static defaultProps: Partial<UserProfileProps> = {
static defaultProps: Partial<Props> = {
disablePopover: false,
displayUsername: false,
hasMention: false,

View File

@ -1,8 +1,6 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import expect from 'expect';
import type {Post, PostOrderBlock} from '@mattermost/types/posts';
import {

View File

@ -7,6 +7,7 @@ import {configure} from 'enzyme';
import Adapter from 'enzyme-adapter-react-17-updated';
import '@testing-library/jest-dom';
import 'isomorphic-fetch';
import './redux-persist_mock';
import './react-intl_mock';
@ -14,7 +15,6 @@ import './react-router-dom_mock';
import './react-tippy_mock';
global.performance = {} as any;
require('isomorphic-fetch');
configure({adapter: new (Adapter as any)()});

9264
webapp/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -7,5 +7,5 @@ module.exports = {
moduleNameMapper: {
'^@mattermost/types/(.*)$': '<rootDir>/../types/src/$1',
},
setupFiles: ['<rootDir>/src/setupTests.ts'],
setupFiles: ['<rootDir>/setup_jest.ts'],
};

View File

@ -15,7 +15,7 @@ const config = {
'^.+\\.(css|scss)$': 'identity-obj-proxy',
},
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'],
setupFilesAfterEnv: ['<rootDir>/src/setupTests.ts'],
setupFilesAfterEnv: ['<rootDir>/setup_jest.ts'],
};
module.exports = config;

View File

@ -18,6 +18,7 @@
"@rollup/plugin-commonjs": "^21.0.2",
"@rollup/plugin-node-resolve": "^13.1.3",
"@rollup/plugin-typescript": "^8.3.1",
"@testing-library/jest-dom": "5.16.4",
"@types/lodash": "^4.14.178",
"@types/react": "^17.0.2",
"@types/react-bootstrap": "^0.32.22",

View File

@ -14,5 +14,8 @@
"outDir": "dist",
"rootDir": "src",
"composite": true
}
},
"include": [
"./src/**/*"
],
}