Improve types of testing utilities and fix some types in unit test code (#26122)

* Improve type of DeepPartial and make mergeObjects handle Sets/Maps properly

* Fix linting

* Remove undefined fields from menu_cloud_trial.test

* Prevent importing the wrong version of DeepPartial
This commit is contained in:
Harrison Healey 2024-02-13 11:48:13 -05:00 committed by GitHub
parent bdce9f42d8
commit daab9d5ff5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
43 changed files with 303 additions and 292 deletions

View File

@ -114,13 +114,20 @@
{
"patterns": [
{
"group": ["react-bootstrap"],
"group": ["@mattermost/compass-components/*"],
"message": "compass-components is now archived."
}
],
"paths": [
{
"name": "react-bootstrap",
"importNames": ["OverlayTrigger"],
"message": "Please use OverlayTrigger from '/components/overlay_trigger' instead."
"message": "Use OverlayTrigger from '/components/overlay_trigger' instead."
},
{
"group": ["@mattermost/compass-components/*"],
"message": "compass-components is now archived"
"name": "redux",
"importNames": ["DeepPartial"],
"message": "Use DeepPartial from '@mattermost/types/utilities instead."
}
]
}

View File

@ -10,6 +10,7 @@ import {
import {loadProfilesForSidebar} from 'actions/user_actions';
import mockStore from 'tests/test_store';
import {TestHelper} from 'utils/test_helper';
const initialState = {
entities: {
@ -25,22 +26,22 @@ const initialState = {
},
},
channels: {
current_channel_id: {
current_channel_id: TestHelper.getChannelMock({
id: 'current_channel_id',
name: 'default-name',
display_name: 'Default',
delete_at: 0,
type: 'O',
team_id: 'team_id',
},
current_user_id__existingId: {
}),
current_user_id__existingId: TestHelper.getChannelMock({
id: 'current_user_id__existingId',
name: 'current_user_id__existingId',
display_name: 'Default',
delete_at: 0,
type: '0',
type: 'O',
team_id: 'team_id',
},
}),
},
channelsInTeam: {
'team-id': ['current_channel_id'],
@ -56,7 +57,7 @@ const initialState = {
'team-id': {
id: 'team_id',
name: 'team-1',
displayName: 'Team 1',
display_name: 'Team 1',
},
},
myMembers: {
@ -95,7 +96,7 @@ const initialState = {
general: {
license: {IsLicensed: 'false'},
serverVersion: '5.4.0',
config: {PostEditTimeLimit: -1},
config: {PostEditTimeLimit: '-1'},
},
},
};

View File

@ -90,8 +90,8 @@ describe('actions/global_actions', () => {
team2: {id: 'team2', display_name: 'Team 2', name: 'team2', delete_at: 0},
},
myMembers: {
team1: {id: 'team1'},
team2: {id: 'team2'},
team1: {team_id: 'team1'},
team2: {team_id: 'team2'},
},
},
channels: {
@ -164,8 +164,8 @@ describe('actions/global_actions', () => {
team2: {id: 'team2', display_name: 'Team 2', name: 'team2', delete_at: 0},
},
myMembers: {
team1: {id: 'team1'},
team2: {id: 'team2'},
team1: {team_id: 'team1'},
team2: {team_id: 'team2'},
},
},
channels: {
@ -237,8 +237,8 @@ describe('actions/global_actions', () => {
team2: {id: 'team2', display_name: 'Team 2', name: 'team2', delete_at: 0},
},
myMembers: {
team1: {id: 'team1'},
team2: {id: 'team2'},
team1: {team_id: 'team1'},
team2: {team_id: 'team2'},
},
},
channels: {
@ -303,8 +303,8 @@ describe('actions/global_actions', () => {
team2: {id: 'team2', display_name: 'Team 2', name: 'team2', delete_at: 0},
},
myMembers: {
team1: {id: 'team1'},
team2: {id: 'team2'},
team1: {team_id: 'team1'},
team2: {team_id: 'team2'},
},
},
users: {
@ -344,8 +344,8 @@ describe('actions/global_actions', () => {
team2: {id: 'team2', display_name: 'Team 2', name: 'team2', delete_at: 0},
},
myMembers: {
team1: {id: 'team1'},
team2: {id: 'team2'},
team1: {team_id: 'team1'},
team2: {team_id: 'team2'},
},
},
channels: {
@ -440,8 +440,8 @@ describe('actions/global_actions', () => {
team2: {id: 'team2', display_name: 'Team 2', name: 'team2', delete_at: 0},
},
myMembers: {
team1: {id: 'team1'},
team2: {id: 'team2'},
team1: {team_id: 'team1'},
team2: {team_id: 'team2'},
},
},
channels: {
@ -532,8 +532,8 @@ describe('actions/global_actions', () => {
team2: {id: 'team2', display_name: 'Team 2', name: 'team2', delete_at: 0},
},
myMembers: {
team1: {id: 'team1'},
team2: {id: 'team2'},
team1: {team_id: 'team1'},
team2: {team_id: 'team2'},
},
},
channels: {

View File

@ -8,6 +8,7 @@ import {sendMembersInvites, sendGuestsInvites} from 'actions/invite_actions';
import mockStore from 'tests/test_store';
import {ConsolePages} from 'utils/constants';
import {TestHelper} from 'utils/test_helper';
jest.mock('actions/team_actions', () => ({
addUsersToTeam: () => ({ // since we are using addUsersToTeamGracefully, this call will always succeed
@ -76,18 +77,18 @@ describe('actions/invite_actions', () => {
},
membersInTeam: {
correct: {
user1: {id: 'user1'},
user2: {id: 'user2'},
guest1: {id: 'guest1'},
guest2: {id: 'guest2'},
guest3: {id: 'guest3'},
user1: TestHelper.getTeamMembershipMock({user_id: 'user1', team_id: 'correct'}),
user2: TestHelper.getTeamMembershipMock({user_id: 'user2', team_id: 'correct'}),
guest1: TestHelper.getTeamMembershipMock({user_id: 'guest1', team_id: 'correct'}),
guest2: TestHelper.getTeamMembershipMock({user_id: 'guest2', team_id: 'correct'}),
guest3: TestHelper.getTeamMembershipMock({user_id: 'guest3', team_id: 'correct'}),
},
error: {
user1: {id: 'user1'},
user2: {id: 'user2'},
guest1: {id: 'guest1'},
guest2: {id: 'guest2'},
guest3: {id: 'guest3'},
user1: TestHelper.getTeamMembershipMock({user_id: 'user1', team_id: 'error'}),
user2: TestHelper.getTeamMembershipMock({user_id: 'user2', team_id: 'error'}),
guest1: TestHelper.getTeamMembershipMock({user_id: 'guest1', team_id: 'error'}),
guest2: TestHelper.getTeamMembershipMock({user_id: 'guest2', team_id: 'error'}),
guest3: TestHelper.getTeamMembershipMock({user_id: 'guest3', team_id: 'error'}),
},
},
myMembers: {},
@ -97,15 +98,15 @@ describe('actions/invite_actions', () => {
channels: {},
membersInChannel: {
correct: {
guest2: {id: 'guest2'},
guest3: {id: 'guest3'},
guest2: TestHelper.getChannelMembershipMock({user_id: 'guest2', channel_id: 'correct'}),
guest3: TestHelper.getChannelMembershipMock({user_id: 'guest3', channel_id: 'correct'}),
},
correct2: {
guest2: {id: 'guest2'},
guest2: TestHelper.getChannelMembershipMock({user_id: 'guest2', channel_id: 'correct2'}),
},
error: {
guest2: {id: 'guest2'},
guest3: {id: 'guest3'},
guest2: TestHelper.getChannelMembershipMock({user_id: 'guest2', channel_id: 'error'}),
guest3: TestHelper.getChannelMembershipMock({user_id: 'guest3', channel_id: 'error'}),
},
},
},

View File

@ -1,7 +1,7 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import type * as Redux from 'redux';
import type {AnyAction} from 'redux';
import {batchActions} from 'redux-batched-actions';
import type {Post} from '@mattermost/types/posts';
@ -48,7 +48,7 @@ export function completePostReceive(post: Post, websocketMessageProps: NewPostMe
return {error: result.error};
}
}
const actions: Redux.AnyAction[] = [];
const actions: AnyAction[] = [];
if (post.channel_id === getCurrentChannelId(getState())) {
actions.push({
@ -85,7 +85,7 @@ export function completePostReceive(post: Post, websocketMessageProps: NewPostMe
// setChannelReadAndViewed returns an array of actions to mark the channel read and viewed, and it dispatches an action
// to asynchronously mark the channel as read on the server if necessary.
export function setChannelReadAndViewed(dispatch: DispatchFunc, getState: GetStateFunc, post: Post, websocketMessageProps: NewPostMessageProps, fetchedChannelMember?: boolean): Redux.AnyAction[] {
export function setChannelReadAndViewed(dispatch: DispatchFunc, getState: GetStateFunc, post: Post, websocketMessageProps: NewPostMessageProps, fetchedChannelMember?: boolean): AnyAction[] {
const state = getState();
const currentUserId = getCurrentUserId(state);

View File

@ -71,7 +71,7 @@ jest.mock('actions/telemetry_actions.jsx', () => {
});
describe('Actions.User', () => {
const initialState: GlobalState = {
const initialState = {
entities: {
channels: {
currentChannelId: 'current_channel_id',
@ -100,12 +100,12 @@ describe('Actions.User', () => {
current_user_id: {channel_id: 'current_user_id'} as ChannelMembership,
},
},
} as unknown as GlobalState['entities']['channels'],
},
general: {
config: {
EnableUserStatuses: 'true',
},
} as GlobalState['entities']['general'],
},
preferences: {
myPreferences: {
'theme--team_1': {
@ -142,13 +142,13 @@ describe('Actions.User', () => {
current_user_id: {id: 'current_user_id'} as unknown as TeamMembership,
},
},
} as unknown as GlobalState['entities']['teams'],
},
users: {
currentUserId: 'current_user_id',
profilesInChannel: {
group_channel_2: ['user_1', 'user_2'],
group_channel_2: new Set(['user_1', 'user_2']),
},
},
} as unknown as GlobalState['entities']['users'],
posts: {
posts: {
sample_post_id: {
@ -161,25 +161,25 @@ describe('Actions.User', () => {
order: ['sample_post_id'],
},
]},
} as unknown as GlobalState['entities']['posts'],
} as unknown as GlobalState['entities'],
},
},
storage: {
storage: {},
initialized: true,
},
views: {
channel: {
} as GlobalState['views']['channel'],
},
channelSidebar: {
unreadFilterEnabled: false,
} as GlobalState['views']['channelSidebar'],
} as GlobalState['views'],
} as GlobalState;
},
},
};
test('loadProfilesAndTeamMembers', async () => {
const expectedActions = [{type: 'MOCK_GET_PROFILES_IN_TEAM', args: ['team_1', 0, 60, '', {}]}];
let testStore = mockStore({} as GlobalState);
let testStore = mockStore({});
await testStore.dispatch(UserActions.loadProfilesAndTeamMembers(0, 60, 'team_1', {}));
let actualActions = testStore.getActions();
expect(actualActions[0].args).toEqual(expectedActions[0].args);
@ -337,7 +337,6 @@ describe('Actions.User', () => {
entities: {
...initialState.entities,
channelCategories: {
...initialState.entities.channelCategories,
byId: {
dmsCategory,
},

View File

@ -24,7 +24,7 @@ describe('components/admin_console/license_settings/modals/confirm_license_remov
modals: {
modalState: {
confirm_license_removal: {
open: 'true',
open: true,
},
},
},

View File

@ -44,7 +44,7 @@ describe('components/admin_console/license_settings/modals/upload_license_modal'
modals: {
modalState: {
upload_license: {
open: 'true',
open: true,
},
},
},

View File

@ -63,7 +63,7 @@ describe('components/channel_invite_modal/team_warning_banner', () => {
profiles: {},
},
groups: {
myGroups: {},
myGroups: [],
groups: {},
},
emojis: {

View File

@ -48,10 +48,10 @@ jest.mock('utils/channel_utils', () => ({
describe('Actions', () => {
const channel1 = {id: 'channel_id1', name: 'achannel', team_id: 'team_id1'};
const channel2 = {id: 'channel_id2', name: 'achannel', team_id: 'team_id2'};
const channel3 = {id: 'channel_id3', name: 'achannel3', team_id: 'team_id1', type: 'O'};
const channel4 = {id: 'channel_id4', name: 'additional-abilities---community-systems', team_id: 'team_id1', type: 'O'};
const channel5 = {id: 'channel_id5', name: 'some-group-channel', team_id: 'team_id1', type: 'G'};
const channel6 = {id: 'channel_id6', name: '12345678901234567890123456', team_id: 'team_id1', type: 'O'};
const channel3 = {id: 'channel_id3', name: 'achannel3', team_id: 'team_id1', type: 'O' as const};
const channel4 = {id: 'channel_id4', name: 'additional-abilities---community-systems', team_id: 'team_id1', type: 'O' as const};
const channel5 = {id: 'channel_id5', name: 'some-group-channel', team_id: 'team_id1', type: 'G' as const};
const channel6 = {id: 'channel_id6', name: '12345678901234567890123456', team_id: 'team_id1', type: 'O' as const};
const initialState = {
entities: {

View File

@ -58,7 +58,7 @@ describe('components/cloud_start_trial_btn/cloud_start_trial_btn', () => {
modals: {
modalState: {
learn_more_trial_modal: {
open: 'true',
open: true,
},
},
},

View File

@ -40,7 +40,7 @@ describe('components/request_business_email_modal/request_business_email_modal',
modals: {
modalState: {
request_business_email_modal: {
open: 'true',
open: true,
},
},
},

View File

@ -34,7 +34,7 @@ describe('components/pricing_modal/downgrade_team_removal_modal', () => {
modals: {
modalState: {
success_modal: {
open: 'true',
open: true,
},
},
},

View File

@ -30,7 +30,7 @@ describe('components/pricing_modal/downgrade_team_removal_modal', () => {
modals: {
modalState: {
success_modal: {
open: 'true',
open: true,
},
},
},

View File

@ -76,7 +76,7 @@ describe('components/dot_menu/DotMenu', () => {
},
currentUserId: 'current_user_id',
profilesInChannel: {
current_user_id: ['user_1'],
current_user_id: new Set(['user_1']),
},
},
teams: {

View File

@ -4,7 +4,8 @@
import {mount} from 'enzyme';
import React from 'react';
import {Provider} from 'react-redux';
import type {DeepPartial} from 'redux';
import type {DeepPartial} from '@mattermost/types/utilities';
import {renderWithContext, screen} from 'tests/react_testing_utils';
import mockStore from 'tests/test_store';

View File

@ -64,7 +64,7 @@ describe('components/learn_more_trial_modal/learn_more_trial_modal', () => {
modals: {
modalState: {
learn_more_trial_modal: {
open: 'true',
open: true,
},
},
},

View File

@ -36,7 +36,7 @@ describe('components/learn_more_trial_modal/learn_more_trial_modal_step', () =>
modals: {
modalState: {
learn_more_trial_modal: {
open: 'true',
open: true,
},
},
},

View File

@ -64,7 +64,7 @@ describe('components/learn_more_trial_modal/start_trial_btn', () => {
modals: {
modalState: {
learn_more_trial_modal: {
open: 'true',
open: true,
},
},
},

View File

@ -80,7 +80,7 @@ describe('components/Menu', () => {
const defaultState = {
entities: {
channels: {
myMembers: [],
myMembers: {},
},
general: {
config: {},
@ -95,7 +95,7 @@ describe('components/Menu', () => {
team_id: 'team-id',
user_id: 'test-user-id',
roles: 'team_user',
scheme_user: 'true',
scheme_user: true,
},
},
},

View File

@ -9,6 +9,8 @@ import type {ComponentProps} from 'react';
import {act} from 'react-dom/test-utils';
import type {match} from 'react-router-dom';
import {CollapsedThreads} from '@mattermost/types/config';
import {getPostThread} from 'mattermost-redux/actions/posts';
import {Client4} from 'mattermost-redux/client';
import {Preferences} from 'mattermost-redux/constants';
@ -151,9 +153,9 @@ describe('components/PermalinkView', () => {
},
channels: {
channels: {
channelid1: {id: 'channelid1', name: 'channel1', type: 'O', team_id: 'current_team_id'},
dmchannelid: {id: 'dmchannelid', name: 'dmchannel__current_user_id', type: 'D', team_id: ''},
gmchannelid: {id: 'gmchannelid', name: 'gmchannel', type: 'G', team_id: ''},
channelid1: TestHelper.getChannelMock({id: 'channelid1', name: 'channel1', type: 'O', team_id: 'current_team_id'}),
dmchannelid: TestHelper.getChannelMock({id: 'dmchannelid', name: 'dmchannel__current_user_id', type: 'D', team_id: ''}),
gmchannelid: TestHelper.getChannelMock({id: 'gmchannelid', name: 'gmchannel', type: 'G', team_id: ''}),
},
myMembers: {channelid1: {channel_id: 'channelid1', user_id: 'current_user_id'}},
},
@ -335,7 +337,7 @@ describe('components/PermalinkView', () => {
...initialState.entities,
general: {
config: {
CollapsedThreads: 'default_on',
CollapsedThreads: CollapsedThreads.DEFAULT_ON,
},
},
},

View File

@ -18,7 +18,7 @@ describe('components/permissions_gates', () => {
channel_id: {channel_id: 'channel_id', roles: 'channel_role'},
},
roles: {
channel_id: ['channel_role'],
channel_id: new Set(['channel_role']),
},
},
teams: {

View File

@ -23,22 +23,17 @@ const preferenceKeys = {
};
const openGraphData = {
audios: null,
description: 'Mattermost is a secure, open source platform for communication, collaboration, and workflow orchestration across tools and teams.',
determiner: '',
images: [{
height: 1256,
secure_url: 'http://localhost:8065/api/v4/image?url=http%3A%2F%2Fmattermo…t.com%2Fwp-content%2Fuploads%2F2021%2F09%2FHomepage%402x.png',
type: 'image/png',
url: '',
width: 2400}],
locale: '',
locales_alternate: null,
site_name: 'Mattermost.com',
title: 'Mattermost | Open Source Collaboration for Developers',
type: 'website',
url: 'https://www.mattermost.com',
videos: null,
};
const initialState = {
@ -64,7 +59,9 @@ const initialState = {
},
posts: {
openGraph: {
post_id_1: openGraphData,
post_id_1: {
[openGraphData.url]: openGraphData,
},
},
},
},

View File

@ -4,6 +4,8 @@
import {mount} from 'enzyme';
import React from 'react';
import {CollapsedThreads} from '@mattermost/types/config';
import {Preferences} from 'mattermost-redux/constants';
import FollowButton from 'components/threading/common/follow_button';
@ -46,7 +48,7 @@ describe('rhs_header_post', () => {
general: {
config: {
FeatureFlagCollapsedThreads: 'true',
CollapsedThreads: 'default_off',
CollapsedThreads: CollapsedThreads.DEFAULT_OFF,
},
},
preferences: {
@ -58,27 +60,27 @@ describe('rhs_header_post', () => {
},
posts: {
posts: {
42: {
id: 42,
42: TestHelper.getPostMock({
id: '42',
message: 'where is @jessica.hyde?',
},
43: {
id: 43,
}),
43: TestHelper.getPostMock({
id: '43',
message: 'not a mention',
},
}),
},
},
threads: {
threads: {
42: {
id: 42,
id: '42',
reply_count: 0,
is_following: null,
is_following: null as any, // This is supposed to be boolean based on the type definitions, but this relies on this being null in some cases
},
43: {
id: 43,
id: '43',
reply_count: 0,
is_following: null,
is_following: null as any, // This is supposed to be boolean based on the type definitions, but this relies on this being null in some cases
},
},
},
@ -90,9 +92,6 @@ describe('rhs_header_post', () => {
browser: {
windowSize: WindowSizes.DESKTOP_VIEW,
},
channelSidebar: {
firstChannelName: 'town-square',
},
},
};

View File

@ -75,8 +75,6 @@ describe('components/select_results/SearchLimitsBanner', () => {
},
},
cloud: {
subscription: null,
products: null,
limits: {
limits: {},
limitsLoaded: false,
@ -106,8 +104,6 @@ describe('components/select_results/SearchLimitsBanner', () => {
},
},
cloud: {
subscription: null,
products: null,
limits: {
limits: {},
limitsLoaded: false,

View File

@ -15,11 +15,6 @@ describe('components/sidebar/invite_members_button', () => {
// required state to mount using the provider
const state = {
entities: {
general: {
config: {
FeatureFlagInviteMembersButton: 'user_icon',
},
},
teams: {
teams: {
team_id: {id: 'team_id', delete_at: 0},
@ -40,7 +35,7 @@ describe('components/sidebar/invite_members_button', () => {
},
stats: {
total_users_count: 10,
},
} as any, // HARRISONTODO The defined type of entities.users.stats is incorrect
},
roles: {
roles: {

View File

@ -165,7 +165,7 @@ describe('components/sidebar', () => {
};
test('should not render unreads category when disabled by user preference', () => {
const testState = mergeObjects(baseState, {
const testState = {
entities: {
channels: {
messageCounts: {
@ -178,7 +178,7 @@ describe('components/sidebar', () => {
]),
},
},
});
};
renderWithContext(
<Sidebar {...baseProps}/>,

View File

@ -4,6 +4,7 @@
import store from 'stores/redux_store';
import mockStore from 'tests/test_store';
import {TestHelper} from 'utils/test_helper';
import SearchChannelWithPermissionsProvider from './search_channel_with_permissions_provider';
@ -40,54 +41,54 @@ describe('components/SearchChannelWithPermissionsProvider', () => {
},
},
roles: {
somePublicMemberChannelId: [],
somePrivateMemberChannelId: [],
someDirectConversation: [],
someGroupConversation: [],
somePublicMemberChannelId: new Set<string>(),
somePrivateMemberChannelId: new Set<string>(),
someDirectConversation: new Set<string>(),
someGroupConversation: new Set<string>(),
},
channels: {
somePublicMemberChannelId: {
somePublicMemberChannelId: TestHelper.getChannelMock({
id: 'somePublicMemberChannelId',
type: 'O',
name: 'some-public-member-channel',
display_name: 'Some Public Member Channel',
delete_at: 0,
},
somePrivateMemberChannelId: {
}),
somePrivateMemberChannelId: TestHelper.getChannelMock({
id: 'somePrivateMemberChannelId',
type: 'P',
name: 'some-private-member-channel',
display_name: 'Some Private Member Channel',
delete_at: 0,
},
somePublicNonMemberChannelId: {
}),
somePublicNonMemberChannelId: TestHelper.getChannelMock({
id: 'somePublicNonMemberChannelId',
type: 'O',
name: 'some-public-non-member-channel',
display_name: 'Some Public Non-Member Channel',
delete_at: 0,
},
somePrivateNonMemberChannelId: {
}),
somePrivateNonMemberChannelId: TestHelper.getChannelMock({
id: 'somePrivateNonMemberChannelId',
type: 'P',
name: 'some-private=non-member-channel',
display_name: 'Some Private Non-Member Channel',
delete_at: 0,
},
someDirectConversation: {
}),
someDirectConversation: TestHelper.getChannelMock({
id: 'someDirectConversation',
type: 'D',
name: 'some-direct-conversation',
display_name: 'Some Direct Conversation',
delete_at: 0,
},
someGroupConversation: {
}),
someGroupConversation: TestHelper.getChannelMock({
id: 'someGroupConversation',
type: 'GM',
type: 'G',
name: 'some-group-conversation',
display_name: 'Some Group Conversation',
delete_at: 0,
},
}),
},
channelsInTeam: {
someTeamId: [

View File

@ -1,6 +1,7 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {CollapsedThreads} from '@mattermost/types/config';
import type {UserProfile} from '@mattermost/types/users';
import {Preferences} from 'mattermost-redux/constants';
@ -68,11 +69,10 @@ describe('components/SwitchChannelProvider', () => {
},
},
channels: {
direct_other_user: {
direct_other_user: TestHelper.getChannelMock({
id: 'direct_other_user',
name: 'current_user_id__other_user',
},
myMembers: {},
}),
},
messageCounts: {
direct_other_user: {
@ -99,27 +99,26 @@ describe('components/SwitchChannelProvider', () => {
},
users: {
profiles: {
current_user_id: {roles: 'system_role'},
other_user1: {
current_user_id: TestHelper.getUserMock({roles: 'system_role'}),
other_user1: TestHelper.getUserMock({
id: 'other_user1',
display_name: 'other_user1',
username: 'other_user1',
},
}),
},
currentUserId: 'current_user_id',
profilesInChannel: {
current_user_id: ['user_1'],
current_user_id: new Set(['user_1']),
},
},
teams: {
currentTeamId: 'currentTeamId',
teams: {
currentTeamId: {
currentTeamId: TestHelper.getTeamMock({
id: 'currentTeamId',
display_name: 'test',
type: 'O',
delete_at: 0,
},
}),
},
},
posts: {
@ -294,7 +293,7 @@ describe('components/SwitchChannelProvider', () => {
},
currentUserId: 'current_user_id',
profilesInChannel: {
current_user_id: ['user_1'],
current_user_id: new Set(['user_1']),
},
},
},
@ -306,25 +305,29 @@ describe('components/SwitchChannelProvider', () => {
});
it('should sort results in aplhabetical order', () => {
const channels = [{
const channels = [
TestHelper.getChannelMock({
id: 'channel_other_user',
type: 'O',
name: 'blah_other_user',
display_name: 'blah_other_user',
delete_at: 0,
}, {
}),
TestHelper.getChannelMock({
id: 'direct_other_user1',
type: 'D',
name: 'current_user_id__other_user1',
display_name: 'other_user1',
delete_at: 0,
}, {
}),
TestHelper.getChannelMock({
id: 'direct_other_user2',
type: 'D',
name: 'current_user_id__other_user2',
display_name: 'other_user2',
delete_at: 0,
}];
}),
];
const users = [
TestHelper.getUserMock({
@ -411,31 +414,36 @@ describe('components/SwitchChannelProvider', () => {
}),
];
const channels = [{
const channels = [
TestHelper.getChannelMock({
id: 'channel_other_user',
type: 'O',
name: 'blah_other_user',
display_name: 'blah_other_user',
delete_at: 0,
}, {
}),
TestHelper.getChannelMock({
id: 'direct_other_user1',
type: 'D',
name: 'current_user_id__other_user1',
display_name: 'other_user1',
delete_at: 0,
}, {
}),
TestHelper.getChannelMock({
id: 'direct_other_user2',
type: 'D',
name: 'current_user_id__other_user2',
display_name: 'other_user2',
delete_at: 0,
}, {
}),
TestHelper.getChannelMock({
id: 'direct_other_user4',
type: 'D',
name: 'current_user_id__other_user4',
display_name: 'other_user4',
delete_at: 0,
}];
}),
];
const modifiedState = {
...defaultState,
@ -528,7 +536,7 @@ describe('components/SwitchChannelProvider', () => {
channels: {
channel_other_user: {
id: 'channel_other_user',
type: 'O',
type: 'O' as const,
name: 'other_user',
display_name: 'other_user',
delete_at: 0,
@ -536,16 +544,14 @@ describe('components/SwitchChannelProvider', () => {
},
other_gm_channel: {
id: 'other_gm_channel',
msg_count: 1,
last_viewed_at: 3,
type: 'G',
type: 'G' as const,
name: 'other_gm_channel',
delete_at: 0,
display_name: 'other_gm_channel',
},
other_user1: {
id: 'other_user1',
type: 'D',
type: 'D' as const,
name: 'current_user_id__other_user1',
display_name: 'current_user_id__other_user1',
},
@ -601,7 +607,7 @@ describe('components/SwitchChannelProvider', () => {
channels: {
channel_other_user: {
id: 'channel_other_user',
type: 'O',
type: 'O' as const,
name: 'other_user',
display_name: 'other_user',
delete_at: 0,
@ -609,16 +615,14 @@ describe('components/SwitchChannelProvider', () => {
},
other_gm_channel: {
id: 'other_gm_channel',
msg_count: 1,
last_viewed_at: 3,
type: 'G',
type: 'G' as const,
name: 'other_gm_channel',
delete_at: 0,
display_name: 'other.user1, other.user2',
},
other_user1: {
id: 'other_user1',
type: 'D',
type: 'D' as const,
name: 'current_user_id__other_user1',
display_name: 'other user1',
},
@ -635,7 +639,7 @@ describe('components/SwitchChannelProvider', () => {
},
currentUserId: 'current_user_id',
profilesInChannel: {
current_user_id: ['user_1'],
current_user_id: new Set(['user_1']),
},
},
},
@ -701,7 +705,7 @@ describe('components/SwitchChannelProvider', () => {
channels: {
channel_other_user: {
id: 'channel_other_user',
type: 'O',
type: 'O' as const,
name: 'other_user',
display_name: 'other_user',
delete_at: 0,
@ -709,16 +713,14 @@ describe('components/SwitchChannelProvider', () => {
},
other_gm_channel: {
id: 'other_gm_channel',
msg_count: 1,
last_viewed_at: 3,
type: 'G',
type: 'G' as const,
name: 'other_gm_channel',
delete_at: 0,
display_name: 'other_gm_channel',
},
other_user1: {
id: 'other_user1',
type: 'D',
type: 'D' as const,
name: 'current_user_id__other_user1',
display_name: 'current_user_id__other_user1',
},
@ -776,21 +778,19 @@ describe('components/SwitchChannelProvider', () => {
},
},
channels: {
other_gm_channel: {
other_gm_channel: TestHelper.getChannelMock({
id: 'other_gm_channel',
msg_count: 1,
last_viewed_at: 3,
type: 'G',
name: 'other_gm_channel',
delete_at: 0,
display_name: 'other_gm_channel',
},
other_user1: {
}),
other_user1: TestHelper.getChannelMock({
id: 'other_user1',
type: 'D',
name: 'current_user_id__other_user1',
display_name: 'current_user_id__other_user1',
},
}),
},
channelsInTeam: {
'': ['other_gm_channel'],
@ -860,22 +860,22 @@ describe('components/SwitchChannelProvider', () => {
channel_2: {},
},
channels: {
channel_1: {
channel_1: TestHelper.getChannelMock({
id: 'channel_1',
type: 'O',
name: 'channel_1',
display_name: 'channel 1',
delete_at: 0,
team_id: 'currentTeamId',
},
channel_2: {
}),
channel_2: TestHelper.getChannelMock({
id: 'channel_2',
type: 'O',
name: 'channel_2',
display_name: 'channel 2',
delete_at: 0,
team_id: 'archivedTeam',
},
}),
},
},
},
@ -905,7 +905,7 @@ describe('components/SwitchChannelProvider', () => {
...defaultState.entities,
general: {
config: {
CollapsedThreads: 'default_off',
CollapsedThreads: CollapsedThreads.DEFAULT_OFF,
},
},
threads: {
@ -953,9 +953,7 @@ describe('components/SwitchChannelProvider', () => {
channels: {
thread_gm_channel: {
id: 'thread_gm_channel',
msg_count: 1,
last_viewed_at: 3,
type: 'G',
type: 'G' as const,
name: 'thread_gm_channel',
delete_at: 0,
display_name: 'thread_gm_channel',

View File

@ -31,14 +31,6 @@ describe('components/team_controller/actions', () => {
myPreferences: {},
},
},
requests: {
channels: {
getChannelsMembersCategories: {
status: 'not_started',
error: null,
},
},
},
};
describe('joinTeam', () => {

View File

@ -66,7 +66,7 @@ describe('components/three_days_left_trial_modal/three_days_left_trial_modal', (
modals: {
modalState: {
three_days_left_trial_modal: {
open: 'true',
open: true,
},
},
},

View File

@ -52,7 +52,7 @@ describe('components/trial_benefits_modal/trial_benefits_modal', () => {
modals: {
modalState: {
trial_benefits_modal: {
open: 'true',
open: true,
},
},
},

View File

@ -84,7 +84,7 @@ describe('component/user_group_popover', () => {
},
users: {
profiles,
profilesInGroup,
profilesInGroup: profilesInGroup as any, // HARRISONTODO The type entities.users.profilesInGroup is incorrectly an array when it should be a Set
},
preferences: {
myPreferences: {},

View File

@ -38,7 +38,7 @@ describe('component/user_groups_modal/ad_ldap_upsell_banner', () => {
license: {
Cloud: 'false',
SkuShortName: LicenseSkus.Professional,
ExpiresAt: 100000000,
ExpiresAt: '100000000',
},
config: {},
},

View File

@ -110,10 +110,6 @@ describe('components/widgets/menu/menu_items/menu_cloud_trial', () => {
},
},
cloud: {
customer: null,
subscription: null,
products: null,
invoices: null,
limits,
},
usage,
@ -130,10 +126,6 @@ describe('components/widgets/menu/menu_items/menu_cloud_trial', () => {
users,
general: {},
cloud: {
customer: null,
subscription: null,
products: null,
invoices: null,
limits,
},
usage,

View File

@ -24,7 +24,7 @@ describe('components/widgets/menu/menu_items/menu_start_trial', () => {
},
general: {
config: {
EnableTutorial: true,
EnableTutorial: 'true',
},
license: {
IsLicensed: 'false',
@ -62,7 +62,7 @@ describe('components/widgets/menu/menu_items/menu_start_trial', () => {
},
general: {
config: {
EnableTutorial: true,
EnableTutorial: 'true',
},
license: {
IsLicensed: 'false',
@ -101,7 +101,7 @@ describe('components/widgets/menu/menu_items/menu_start_trial', () => {
},
general: {
config: {
EnableTutorial: true,
EnableTutorial: 'true',
},
license: {
IsLicensed: 'true',
@ -140,7 +140,7 @@ describe('components/widgets/menu/menu_items/menu_start_trial', () => {
},
general: {
config: {
EnableTutorial: true,
EnableTutorial: 'true',
},
license: {
IsLicensed: 'true',
@ -180,7 +180,7 @@ describe('components/widgets/menu/menu_items/menu_start_trial', () => {
},
general: {
config: {
EnableTutorial: true,
EnableTutorial: 'true',
},
license: {
IsLicensed: 'false',

View File

@ -39,7 +39,7 @@ describe('components/widgets/users/Avatars', () => {
nickname: 'nickname1',
first_name: 'First1',
last_name: 'Last1',
last_picture_update: '1620680333191',
last_picture_update: 1620680333191,
},
2: {
@ -48,7 +48,7 @@ describe('components/widgets/users/Avatars', () => {
nickname: 'nickname2',
first_name: 'First2',
last_name: 'Last2',
last_picture_update: '1620680333191',
last_picture_update: 1620680333191,
},
3: {
id: '3',
@ -56,7 +56,7 @@ describe('components/widgets/users/Avatars', () => {
nickname: 'nickname3',
first_name: 'First3',
last_name: 'Last3',
last_picture_update: '1620680333191',
last_picture_update: 1620680333191,
},
4: {
id: '4',
@ -64,7 +64,7 @@ describe('components/widgets/users/Avatars', () => {
nickname: 'nickname4',
first_name: 'First4',
last_name: 'Last4',
last_picture_update: '1620680333191',
last_picture_update: 1620680333191,
},
5: {
id: '5',
@ -72,7 +72,7 @@ describe('components/widgets/users/Avatars', () => {
nickname: 'nickname5',
first_name: 'First5',
last_name: 'Last5',
last_picture_update: '1620680333191',
last_picture_update: 1620680333191,
},
},
},

View File

@ -4,7 +4,8 @@
import {mount, shallow} from 'enzyme';
import React from 'react';
import {Provider} from 'react-redux';
import type {DeepPartial} from 'redux';
import type {DeepPartial} from '@mattermost/types/utilities';
import ExternalImage from 'components/external_image';

View File

@ -1018,9 +1018,9 @@ describe('Actions.Admin', () => {
const state = store.getState();
const metadataResponse = state.entities.admin.samlMetadataResponse;
expect(metadataResponse).toBeTruthy();
expect(metadataResponse.idp_url === samlIdpURL).toBeTruthy();
expect(metadataResponse.idp_descriptor_url === samlIdpDescriptorURL).toBeTruthy();
expect(metadataResponse.idp_public_certificate === samlIdpPublicCertificateText).toBeTruthy();
expect(metadataResponse!.idp_url === samlIdpURL).toBeTruthy();
expect(metadataResponse!.idp_descriptor_url === samlIdpDescriptorURL).toBeTruthy();
expect(metadataResponse!.idp_public_certificate === samlIdpPublicCertificateText).toBeTruthy();
});
it('setSamlIdpCertificateFromMetadata', async () => {

View File

@ -53,7 +53,8 @@ describe('Actions.Users', () => {
post('/users').
reply(201, {...userToCreate, id: TestHelper.generateId()});
const {data: user} = await store.dispatch(Actions.createUser(userToCreate, '', '', ''));
const response = await store.dispatch(Actions.createUser(userToCreate, '', '', ''));
const user = response.data!;
const state = store.getState();
const {profiles} = state.entities.users;
@ -122,10 +123,10 @@ describe('Actions.Users', () => {
await store.dispatch(Actions.updateMyTermsOfServiceStatus('1', false));
const {currentUserId, myAcceptedTermsOfServiceId} = store.getState().entities.users;
const {currentUserId, profiles} = store.getState().entities.users;
expect(currentUserId).toBeTruthy();
expect(myAcceptedTermsOfServiceId).not.toEqual('1');
expect(profiles[currentUserId]).not.toEqual('1');
});
it('logout', async () => {
@ -880,7 +881,7 @@ describe('Actions.Users', () => {
mention_keys: '',
user_id: currentUser.id,
},
} as UserProfile));
} as unknown as UserProfile));
const updateRequest = store.getState().requests.users.updateMe;
const {currentUserId, profiles} = store.getState().entities.users;
@ -933,7 +934,7 @@ describe('Actions.Users', () => {
mention_keys: '',
user_id: currentUser.id,
},
} as UserProfile));
} as unknown as UserProfile));
const {profiles} = store.getState().entities.users;
const updateNotifyProps = profiles[currentUserId].notify_props;
@ -1026,7 +1027,8 @@ describe('Actions.Users', () => {
post('/users').
reply(200, TestHelper.fakeUserWithId());
const {data: user} = await store.dispatch(Actions.createUser(TestHelper.fakeUser(), '', '', ''));
const response = await store.dispatch(Actions.createUser(TestHelper.fakeUser(), '', '', ''));
const user = response.data!;
const beforeTime = new Date().getTime();
@ -1186,7 +1188,8 @@ describe('Actions.Users', () => {
post(`/users/${currentUserId}/tokens`).
reply(201, {id: 'someid', token: 'sometoken', description: 'test token', user_id: currentUserId});
const {data} = await store.dispatch(Actions.createUserAccessToken(currentUserId, 'test token'));
const response = await store.dispatch(Actions.createUserAccessToken(currentUserId, 'test token'));
const data = response.data!;
const {myUserAccessTokens} = store.getState().entities.users;
const {userAccessTokensByUser} = store.getState().entities.admin;
@ -1195,9 +1198,9 @@ describe('Actions.Users', () => {
expect(myUserAccessTokens[data.id]).toBeTruthy();
expect(!myUserAccessTokens[data.id].token).toBeTruthy();
expect(userAccessTokensByUser).toBeTruthy();
expect(userAccessTokensByUser[currentUserId]).toBeTruthy();
expect(userAccessTokensByUser[currentUserId][data.id]).toBeTruthy();
expect(!userAccessTokensByUser[currentUserId][data.id].token).toBeTruthy();
expect(userAccessTokensByUser![currentUserId]).toBeTruthy();
expect(userAccessTokensByUser![currentUserId][data.id]).toBeTruthy();
expect(!userAccessTokensByUser![currentUserId][data.id].token).toBeTruthy();
done();
}
@ -1217,7 +1220,8 @@ describe('Actions.Users', () => {
post(`/users/${currentUserId}/tokens`).
reply(201, {id: 'someid', token: 'sometoken', description: 'test token', user_id: currentUserId});
const {data} = await store.dispatch(Actions.createUserAccessToken(currentUserId, 'test token'));
const response = await store.dispatch(Actions.createUserAccessToken(currentUserId, 'test token'));
const data = response.data!;
nock(Client4.getBaseRoute()).
get(`/users/tokens/${data.id}`).
@ -1232,9 +1236,9 @@ describe('Actions.Users', () => {
expect(myUserAccessTokens[data.id]).toBeTruthy();
expect(!myUserAccessTokens[data.id].token).toBeTruthy();
expect(userAccessTokensByUser).toBeTruthy();
expect(userAccessTokensByUser[currentUserId]).toBeTruthy();
expect(userAccessTokensByUser[currentUserId][data.id]).toBeTruthy();
expect(!userAccessTokensByUser[currentUserId][data.id].token).toBeTruthy();
expect(userAccessTokensByUser![currentUserId]).toBeTruthy();
expect(userAccessTokensByUser![currentUserId][data.id]).toBeTruthy();
expect(!userAccessTokensByUser![currentUserId][data.id].token).toBeTruthy();
expect(userAccessTokens).toBeTruthy();
expect(userAccessTokens[data.id]).toBeTruthy();
expect(!userAccessTokens[data.id].token).toBeTruthy();
@ -1253,7 +1257,8 @@ describe('Actions.Users', () => {
post(`/users/${currentUserId}/tokens`).
reply(201, {id: 'someid', token: 'sometoken', description: 'test token', user_id: currentUserId});
const {data} = await store.dispatch(Actions.createUserAccessToken(currentUserId, 'test token'));
const response = await store.dispatch(Actions.createUserAccessToken(currentUserId, 'test token'));
const data = response.data!;
nock(Client4.getBaseRoute()).
get(`/users/${currentUserId}/tokens`).
@ -1269,9 +1274,9 @@ describe('Actions.Users', () => {
expect(myUserAccessTokens[data.id]).toBeTruthy();
expect(!myUserAccessTokens[data.id].token).toBeTruthy();
expect(userAccessTokensByUser).toBeTruthy();
expect(userAccessTokensByUser[currentUserId]).toBeTruthy();
expect(userAccessTokensByUser[currentUserId][data.id]).toBeTruthy();
expect(!userAccessTokensByUser[currentUserId][data.id].token).toBeTruthy();
expect(userAccessTokensByUser![currentUserId]).toBeTruthy();
expect(userAccessTokensByUser![currentUserId][data.id]).toBeTruthy();
expect(!userAccessTokensByUser![currentUserId][data.id].token).toBeTruthy();
expect(userAccessTokens).toBeTruthy();
expect(userAccessTokens[data.id]).toBeTruthy();
expect(!userAccessTokens[data.id].token).toBeTruthy();
@ -1290,7 +1295,8 @@ describe('Actions.Users', () => {
post(`/users/${currentUserId}/tokens`).
reply(201, {id: 'someid', token: 'sometoken', description: 'test token', user_id: currentUserId});
const {data} = await store.dispatch(Actions.createUserAccessToken(currentUserId, 'test token'));
const response = await store.dispatch(Actions.createUserAccessToken(currentUserId, 'test token'));
const data = response.data!;
let {myUserAccessTokens} = store.getState().entities.users;
let {userAccessTokensByUser, userAccessTokens} = store.getState().entities.admin;
@ -1299,9 +1305,9 @@ describe('Actions.Users', () => {
expect(myUserAccessTokens[data.id]).toBeTruthy();
expect(!myUserAccessTokens[data.id].token).toBeTruthy();
expect(userAccessTokensByUser).toBeTruthy();
expect(userAccessTokensByUser[currentUserId]).toBeTruthy();
expect(userAccessTokensByUser[currentUserId][data.id]).toBeTruthy();
expect(!userAccessTokensByUser[currentUserId][data.id].token).toBeTruthy();
expect(userAccessTokensByUser![currentUserId]).toBeTruthy();
expect(userAccessTokensByUser![currentUserId][data.id]).toBeTruthy();
expect(!userAccessTokensByUser![currentUserId][data.id].token).toBeTruthy();
expect(userAccessTokens).toBeTruthy();
expect(userAccessTokens[data.id]).toBeTruthy();
expect(!userAccessTokens[data.id].token).toBeTruthy();
@ -1319,8 +1325,8 @@ describe('Actions.Users', () => {
expect(myUserAccessTokens).toBeTruthy();
expect(!myUserAccessTokens[data.id]).toBeTruthy();
expect(userAccessTokensByUser).toBeTruthy();
expect(userAccessTokensByUser[currentUserId]).toBeTruthy();
expect(!userAccessTokensByUser[currentUserId][data.id]).toBeTruthy();
expect(userAccessTokensByUser![currentUserId]).toBeTruthy();
expect(!userAccessTokensByUser![currentUserId][data.id]).toBeTruthy();
expect(userAccessTokens).toBeTruthy();
expect(!userAccessTokens[data.id]).toBeTruthy();
});
@ -1338,7 +1344,8 @@ describe('Actions.Users', () => {
post(`/users/${currentUserId}/tokens`).
reply(201, {id: 'someid', token: 'sometoken', description: 'test token', user_id: currentUserId});
const {data} = await store.dispatch(Actions.createUserAccessToken(currentUserId, 'test token'));
const response = await store.dispatch(Actions.createUserAccessToken(currentUserId, 'test token'));
const data = response.data!;
const testId = data.id;
let {myUserAccessTokens} = store.getState().entities.users;
@ -1348,9 +1355,9 @@ describe('Actions.Users', () => {
expect(myUserAccessTokens[testId]).toBeTruthy();
expect(!myUserAccessTokens[testId].token).toBeTruthy();
expect(userAccessTokensByUser).toBeTruthy();
expect(userAccessTokensByUser[currentUserId]).toBeTruthy();
expect(userAccessTokensByUser[currentUserId][testId]).toBeTruthy();
expect(!userAccessTokensByUser[currentUserId][testId].token).toBeTruthy();
expect(userAccessTokensByUser![currentUserId]).toBeTruthy();
expect(userAccessTokensByUser![currentUserId][testId]).toBeTruthy();
expect(!userAccessTokensByUser![currentUserId][testId].token).toBeTruthy();
expect(userAccessTokens).toBeTruthy();
expect(userAccessTokens[data.id]).toBeTruthy();
expect(!userAccessTokens[data.id].token).toBeTruthy();
@ -1370,10 +1377,10 @@ describe('Actions.Users', () => {
expect(!myUserAccessTokens[testId].is_active).toBeTruthy();
expect(!myUserAccessTokens[testId].token).toBeTruthy();
expect(userAccessTokensByUser).toBeTruthy();
expect(userAccessTokensByUser[currentUserId]).toBeTruthy();
expect(userAccessTokensByUser[currentUserId][testId]).toBeTruthy();
expect(!userAccessTokensByUser[currentUserId][testId].is_active).toBeTruthy();
expect(!userAccessTokensByUser[currentUserId][testId].token).toBeTruthy();
expect(userAccessTokensByUser![currentUserId]).toBeTruthy();
expect(userAccessTokensByUser![currentUserId][testId]).toBeTruthy();
expect(!userAccessTokensByUser![currentUserId][testId].is_active).toBeTruthy();
expect(!userAccessTokensByUser![currentUserId][testId].token).toBeTruthy();
expect(userAccessTokens).toBeTruthy();
expect(userAccessTokens[testId]).toBeTruthy();
expect(!userAccessTokens[testId].is_active).toBeTruthy();
@ -1393,7 +1400,8 @@ describe('Actions.Users', () => {
post(`/users/${currentUserId}/tokens`).
reply(201, {id: 'someid', token: 'sometoken', description: 'test token', user_id: currentUserId});
const {data} = await store.dispatch(Actions.createUserAccessToken(currentUserId, 'test token'));
const response = await store.dispatch(Actions.createUserAccessToken(currentUserId, 'test token'));
const data = response.data!;
const testId = data.id;
let {myUserAccessTokens} = store.getState().entities.users;
@ -1403,9 +1411,9 @@ describe('Actions.Users', () => {
expect(myUserAccessTokens[testId]).toBeTruthy();
expect(!myUserAccessTokens[testId].token).toBeTruthy();
expect(userAccessTokensByUser).toBeTruthy();
expect(userAccessTokensByUser[currentUserId]).toBeTruthy();
expect(userAccessTokensByUser[currentUserId][testId]).toBeTruthy();
expect(!userAccessTokensByUser[currentUserId][testId].token).toBeTruthy();
expect(userAccessTokensByUser![currentUserId]).toBeTruthy();
expect(userAccessTokensByUser![currentUserId][testId]).toBeTruthy();
expect(!userAccessTokensByUser![currentUserId][testId].token).toBeTruthy();
expect(userAccessTokens).toBeTruthy();
expect(userAccessTokens[testId]).toBeTruthy();
expect(!userAccessTokens[testId].token).toBeTruthy();
@ -1425,10 +1433,10 @@ describe('Actions.Users', () => {
expect(myUserAccessTokens[testId].is_active).toBeTruthy();
expect(!myUserAccessTokens[testId].token).toBeTruthy();
expect(userAccessTokensByUser).toBeTruthy();
expect(userAccessTokensByUser[currentUserId]).toBeTruthy();
expect(userAccessTokensByUser[currentUserId][testId]).toBeTruthy();
expect(userAccessTokensByUser[currentUserId][testId].is_active).toBeTruthy();
expect(!userAccessTokensByUser[currentUserId][testId].token).toBeTruthy();
expect(userAccessTokensByUser![currentUserId]).toBeTruthy();
expect(userAccessTokensByUser![currentUserId][testId]).toBeTruthy();
expect(userAccessTokensByUser![currentUserId][testId].is_active).toBeTruthy();
expect(!userAccessTokensByUser![currentUserId][testId].token).toBeTruthy();
expect(userAccessTokens).toBeTruthy();
expect(userAccessTokens[testId]).toBeTruthy();
expect(userAccessTokens[testId].is_active).toBeTruthy();

View File

@ -5,6 +5,14 @@ function isObject(obj: any): obj is Record<string, any> {
return Boolean(obj && typeof obj === 'object' && !Array.isArray(obj));
}
function isSet(obj: unknown): obj is Set<any> {
return Object.getPrototypeOf(obj) === Set.prototype;
}
function isMap(obj: unknown): obj is Map<any, any> {
return Object.getPrototypeOf(obj) === Map.prototype;
}
export default function mergeObjects(a: Record<string, any>, b: Record<string, any>, path = '.') {
if (a === null || a === undefined) {
return b;
@ -14,7 +22,15 @@ export default function mergeObjects(a: Record<string, any>, b: Record<string, a
let result: any;
if (isObject(a) && isObject(b)) {
if (isSet(a) && isSet(b)) {
result = b;
} else if (isSet(a) || isSet(b)) {
throw new Error(`Mismatched types: ${path} is a Set from one source but not the other`);
} else if (isMap(a) && isMap(b)) {
result = b;
} else if (isMap(a) || isMap(b)) {
throw new Error(`Mismatched types: ${path} is a Map from one source but not the other`);
} else if (isObject(a) && isObject(b)) {
result = {};
for (const key of Object.keys(a)) {

View File

@ -9,15 +9,17 @@ import configureStore from 'redux-mock-store';
import thunk from 'redux-thunk';
import type {ThunkDispatch} from 'redux-thunk';
import type {DeepPartial} from '@mattermost/types/utilities';
import type {GlobalState} from 'types/store';
import {defaultIntl} from './helpers/intl-test-helper';
export default function testConfigureStore(initialState = {}) {
return configureStore<GlobalState, ThunkDispatch<GlobalState, Record<string, never>, AnyAction>>([thunk])(initialState as GlobalState);
export default function testConfigureStore<State extends GlobalState>(initialState?: DeepPartial<State>) {
return configureStore<State, ThunkDispatch<State, Record<string, never>, AnyAction>>([thunk])(initialState as State);
}
export function mockStore(initialState = {}, intl = defaultIntl) {
export function mockStore<State extends GlobalState>(initialState?: DeepPartial<State>, intl = defaultIntl) {
const store = testConfigureStore(initialState);
return {
store,

View File

@ -16,6 +16,9 @@ export type IDMappedObjects<E extends {id: string}> = RelationOneToOne<E, E>;
export type DeepPartial<T> = {
// For each field of T, make it optional and...
[K in keyof T]?:
// If that field is a Set or a Map, don't go further
T[K] extends Set<any> ? T[K] :
T[K] extends Map<any, any> ? T[K] :
// If that field is an object, make it a deep partial object
T[K] extends object ? DeepPartial<T[K]> :
// Else if that field is an optional object, make that a deep partial object