MM-68021 H10-17 Enzyme to RTL bulk migration (#35735)

* (test): h10-17 enzyme to rtl bulk migration

* address comments and fix lint

* update per comments
This commit is contained in:
sabril
2026-03-27 01:30:16 +08:00
committed by GitHub
parent 58dd9e1bb4
commit c0dcaf2cd6
58 changed files with 12226 additions and 8143 deletions
@@ -1,185 +1,159 @@
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
exports[`components/admin_console/CustomTermsOfServiceSettings should match snapshot 1`] = `
<form
className="form-horizontal"
onSubmit={[Function]}
role="form"
>
<div
className="wrapper--fixed"
<div>
<form
class="form-horizontal"
role="form"
>
<AdminHeader>
<MemoizedFormattedMessage
defaultMessage="Custom Terms of Service"
id="admin.support.termsOfServiceTitle"
/>
</AdminHeader>
<LoadingScreen />
<div
className="admin-console-save"
class="wrapper--fixed"
>
<SaveButton
disabled={true}
onClick={[Function]}
saving={false}
savingMessage={
<Memo(MemoizedFormattedMessage)
defaultMessage="Saving Config..."
id="admin.saving"
/>
}
/>
<WithTooltip
title=""
<div
class="admin-console__header"
>
Custom Terms of Service
</div>
<div
class="admin-console__wrapper"
>
<div
className="error-message"
class="admin-console__content"
>
<Memo(FormError)
error={null}
/>
<fieldset
class="form-group"
data-testid="SupportSettings.CustomTermsOfServiceEnabled"
id="SupportSettings.CustomTermsOfServiceEnabled"
>
<legend
class="control-label form-legend col-sm-4"
>
Enable Custom Terms of Service
</legend>
<div
class="col-sm-8"
>
<label
class="Label-eJcoMl iShgPr"
>
<input
checked=""
data-testid="SupportSettings.CustomTermsOfServiceEnabledtrue"
id="SupportSettings.CustomTermsOfServiceEnabledtrue"
name="SupportSettings.CustomTermsOfServiceEnabled"
type="radio"
value="true"
/>
True
</label>
<label
class="Label-eJcoMl iShgPr"
>
<input
data-testid="SupportSettings.CustomTermsOfServiceEnabledfalse"
id="SupportSettings.CustomTermsOfServiceEnabledfalse"
name="SupportSettings.CustomTermsOfServiceEnabled"
type="radio"
value="false"
/>
False
</label>
<div
class="help-text"
data-testid="SupportSettings.CustomTermsOfServiceEnabledhelp-text"
>
When true, new users must accept the terms of service before accessing any Mattermost teams on desktop, web or mobile. Existing users must accept them after login or a page refresh. To update terms of service link displayed in account creation and login pages, go to
<a
href="/admin_console/site_config/customization"
>
Site Configuration &gt; Customization
</a>
</div>
</div>
</fieldset>
<div
class="form-group"
data-testid="SupportSettings.CustomTermsOfServiceText"
>
<label
class="control-label col-sm-4"
data-testid="SupportSettings.CustomTermsOfServiceTextlabel"
for="SupportSettings.CustomTermsOfServiceText"
>
Custom Terms of Service Text
</label>
<div
class="col-sm-8"
>
<textarea
class="form-control"
data-testid="SupportSettings.CustomTermsOfServiceTextinput"
dir="auto"
id="SupportSettings.CustomTermsOfServiceText"
maxlength="16383"
rows="5"
>
tos_text
</textarea>
<div
class="help-text"
data-testid="SupportSettings.CustomTermsOfServiceTexthelp-text"
>
Text that will appear in your custom Terms of Service. Supports Markdown-formatted text.
</div>
</div>
</div>
<div
class="form-group"
data-testid="SupportSettings.CustomTermsOfServiceReAcceptancePeriod"
>
<label
class="control-label col-sm-4"
data-testid="SupportSettings.CustomTermsOfServiceReAcceptancePeriodlabel"
for="SupportSettings.CustomTermsOfServiceReAcceptancePeriod"
>
Re-Acceptance Period
</label>
<div
class="col-sm-8"
>
<input
class="form-control"
data-testid="SupportSettings.CustomTermsOfServiceReAcceptancePeriodnumber"
id="SupportSettings.CustomTermsOfServiceReAcceptancePeriod"
maxlength="-1"
type="number"
value="365"
/>
<div
class="help-text"
data-testid="SupportSettings.CustomTermsOfServiceReAcceptancePeriodhelp-text"
>
The number of days before Terms of Service acceptance expires, and the terms must be re-accepted.
</div>
</div>
</div>
</div>
</WithTooltip>
</div>
</div>
</form>
`;
exports[`components/admin_console/CustomTermsOfServiceSettings should match snapshot 2`] = `
<form
className="form-horizontal"
onSubmit={[Function]}
role="form"
>
<div
className="wrapper--fixed"
>
<AdminHeader>
<MemoizedFormattedMessage
defaultMessage="Custom Terms of Service"
id="admin.support.termsOfServiceTitle"
/>
</AdminHeader>
<LoadingScreen />
<div
className="admin-console-save"
>
<SaveButton
disabled={true}
onClick={[Function]}
saving={false}
savingMessage={
<Memo(MemoizedFormattedMessage)
defaultMessage="Saving Config..."
id="admin.saving"
/>
}
/>
<WithTooltip
title=""
</div>
<div
class="admin-console-save"
>
<div
className="error-message"
<button
class="btn btn-primary"
data-testid="saveSetting"
disabled=""
id="saveSetting"
type="submit"
>
<Memo(FormError)
error={null}
/>
</div>
</WithTooltip>
</div>
</div>
</form>
`;
exports[`components/admin_console/CustomTermsOfServiceSettings should match snapshot 3`] = `
<form
className="form-horizontal"
onSubmit={[Function]}
role="form"
>
<div
className="wrapper--fixed"
>
<AdminHeader>
<MemoizedFormattedMessage
defaultMessage="Custom Terms of Service"
id="admin.support.termsOfServiceTitle"
/>
</AdminHeader>
<LoadingScreen />
<div
className="admin-console-save"
>
<SaveButton
disabled={true}
onClick={[Function]}
saving={false}
savingMessage={
<Memo(MemoizedFormattedMessage)
defaultMessage="Saving Config..."
id="admin.saving"
/>
}
/>
<WithTooltip
title=""
>
<span>
Save
</span>
</button>
<div
className="error-message"
>
<Memo(FormError)
error={null}
/>
</div>
</WithTooltip>
class="error-message"
/>
</div>
</div>
</div>
</form>
`;
exports[`components/admin_console/CustomTermsOfServiceSettings should match snapshot 4`] = `
<form
className="form-horizontal"
onSubmit={[Function]}
role="form"
>
<div
className="wrapper--fixed"
>
<AdminHeader>
<MemoizedFormattedMessage
defaultMessage="Custom Terms of Service"
id="admin.support.termsOfServiceTitle"
/>
</AdminHeader>
<LoadingScreen />
<div
className="admin-console-save"
>
<SaveButton
disabled={true}
onClick={[Function]}
saving={false}
savingMessage={
<Memo(MemoizedFormattedMessage)
defaultMessage="Saving Config..."
id="admin.saving"
/>
}
/>
<WithTooltip
title=""
>
<div
className="error-message"
>
<Memo(FormError)
error={null}
/>
</div>
</WithTooltip>
</div>
</div>
</form>
</form>
</div>
`;
@@ -1,15 +1,17 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {shallow} from 'enzyme';
import {screen, waitFor} from '@testing-library/react';
import React from 'react';
import type {AdminConfig} from '@mattermost/types/config';
import CustomTermsOfServiceSettings from 'components/admin_console/custom_terms_of_service_settings/custom_terms_of_service_settings';
import {renderWithContext, userEvent} from 'tests/react_testing_utils';
describe('components/admin_console/CustomTermsOfServiceSettings', () => {
const baseProps = {
const getBaseProps = () => ({
actions: {
createTermsOfService: jest.fn(),
getTermsOfService: jest.fn().mockResolvedValue({data: {id: 'tos_id', text: 'tos_text'}}),
@@ -26,24 +28,99 @@ describe('components/admin_console/CustomTermsOfServiceSettings', () => {
},
setNavigationBlocked: jest.fn(),
patchConfig: jest.fn(),
};
});
test('should match snapshot', () => {
const wrapper = shallow(
async function renderLoaded(props: ReturnType<typeof getBaseProps>) {
const view = renderWithContext(
<CustomTermsOfServiceSettings
{...baseProps}
{...props}
/>,
);
expect(await screen.findByText('Enable Custom Terms of Service')).toBeInTheDocument();
return view;
}
expect(wrapper).toMatchSnapshot();
test('should match snapshot', async () => {
const props = getBaseProps();
const {container} = await renderLoaded(props);
wrapper.setProps({saveNeeded: true});
expect(wrapper).toMatchSnapshot();
expect(container).toMatchSnapshot();
});
wrapper.setProps({saveNeeded: false, saving: true});
expect(wrapper).toMatchSnapshot();
test('save button is disabled until a setting is changed, then enabled after edit', async () => {
const user = userEvent.setup();
const props = getBaseProps();
await renderLoaded(props);
wrapper.setProps({saving: false, serverError: 'error'});
expect(wrapper).toMatchSnapshot();
const saveButton = screen.getByTestId('saveSetting');
expect(saveButton).toBeDisabled();
const periodInput = screen.getByTestId('SupportSettings.CustomTermsOfServiceReAcceptancePeriodnumber');
await user.clear(periodInput);
await user.type(periodInput, '364');
await waitFor(() => {
expect(saveButton).not.toBeDisabled();
});
});
test('shows saving state on the save button while patchConfig is in progress', async () => {
const user = userEvent.setup();
const props = getBaseProps();
let resolvePatch!: (value: {data: AdminConfig; error?: undefined}) => void;
props.patchConfig = jest.fn(
() =>
new Promise((resolve) => {
resolvePatch = resolve;
}),
);
await renderLoaded(props);
const periodInput = screen.getByTestId('SupportSettings.CustomTermsOfServiceReAcceptancePeriodnumber');
await user.clear(periodInput);
await user.type(periodInput, '364');
await user.click(screen.getByTestId('saveSetting'));
expect(await screen.findByText('Saving Config...')).toBeInTheDocument();
const savedConfig = JSON.parse(JSON.stringify(props.config)) as AdminConfig;
savedConfig.SupportSettings!.CustomTermsOfServiceReAcceptancePeriod = 364;
resolvePatch({data: savedConfig});
await waitFor(() => {
expect(screen.queryByText('Saving Config...')).not.toBeInTheDocument();
});
expect(props.patchConfig).toHaveBeenCalledTimes(1);
});
test('shows server error when patchConfig returns an error', async () => {
const user = userEvent.setup();
const props = getBaseProps();
props.patchConfig = jest.fn().mockResolvedValue({
data: undefined,
error: {
message: 'error',
server_error_id: 'test.patch_config.error',
},
});
await renderLoaded(props);
const periodInput = screen.getByTestId('SupportSettings.CustomTermsOfServiceReAcceptancePeriodnumber');
await user.clear(periodInput);
await user.type(periodInput, '364');
await user.click(screen.getByTestId('saveSetting'));
expect(await screen.findByText('error')).toBeInTheDocument();
await waitFor(() => {
expect(screen.queryByText('Saving Config...')).not.toBeInTheDocument();
});
});
});
@@ -32,8 +32,9 @@ export type FilterOption = {
// Key value map of filter values with keys matching the keys above
values: FilterValues;
// Filter Component type, optional parameter defaults to FilterCheckbox
type?: React.ElementType;
// Filter component constructor (use ComponentType, not ElementType: babel-plugin-typescript-to-proptypes maps
// ElementType to PropTypes.node, which breaks runtime validation for custom filter UIs such as TeamFilterDropdown).
type?: React.ComponentType<any>;
}
export type FilterOptions = {
@@ -0,0 +1,50 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {screen} from '@testing-library/react';
import React from 'react';
import {renderWithContext} from 'tests/react_testing_utils';
import type {FilterOption} from './filter';
import FilterList from './filter_list';
describe('admin_console/filter/FilterList', () => {
const baseOption: FilterOption = {
name: 'Test Filter',
keys: ['opt1', 'opt2'],
values: {
opt1: {name: 'Option 1', value: true},
opt2: {name: 'Option 2', value: false},
},
};
test('should render filter name and labels', () => {
renderWithContext(
<FilterList
option={baseOption}
optionKey='test'
updateValues={jest.fn()}
/>,
);
expect(screen.getByText('Test Filter')).toBeInTheDocument();
expect(screen.getByText('Option 1')).toBeInTheDocument();
expect(screen.getByText('Option 2')).toBeInTheDocument();
});
test('should render checkboxes matching boolean values', () => {
renderWithContext(
<FilterList
option={baseOption}
optionKey='test'
updateValues={jest.fn()}
/>,
);
const checkboxes = screen.getAllByRole('checkbox');
expect(checkboxes).toHaveLength(2);
expect(checkboxes[0]).toBeChecked();
expect(checkboxes[1]).not.toBeChecked();
});
});
@@ -43,7 +43,7 @@ const FilterList = ({
<FilterItem
key={index}
name={optionKey}
checked={value}
checked={value as boolean}
label={name}
updateOption={updateOption}
/>
@@ -0,0 +1,122 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {screen, waitFor} from '@testing-library/react';
import React from 'react';
import {renderWithContext} from 'tests/react_testing_utils';
import TeamFilterDropdown from './team_filter_dropdown';
import type {FilterOption} from '../filter';
describe('admin_console/filter/team_filter_dropdown/TeamFilterDropdown', () => {
const getBaseProps = () => ({
getTeams: jest.fn().mockResolvedValue({data: {teams: [
{id: 'team-1', display_name: 'Alpha Team'},
{id: 'team-2', display_name: 'Beta Team'},
]}}),
searchTeams: jest.fn().mockResolvedValue({data: {teams: []}}),
updateValues: jest.fn(),
});
test('should render filter name and load teams on mount', async () => {
const props = getBaseProps();
const option: FilterOption = {
name: 'Teams',
keys: ['team_ids'],
values: {
team_ids: {name: 'Teams', value: [] as string[]},
},
};
renderWithContext(
<TeamFilterDropdown
{...props}
option={option}
/>,
);
expect(screen.getByText('Teams')).toBeInTheDocument();
expect(screen.getByText('Search and select teams')).toBeInTheDocument();
await waitFor(() => {
expect(props.getTeams).toHaveBeenCalledTimes(1);
});
});
test('should show selected teams when team_ids match loaded teams', async () => {
const props = getBaseProps();
const option: FilterOption = {
name: 'Teams',
keys: ['team_ids'],
values: {
team_ids: {name: 'Teams', value: ['team-1']},
},
};
renderWithContext(
<TeamFilterDropdown
{...props}
option={option}
/>,
);
await waitFor(() => {
expect(props.getTeams).toHaveBeenCalledTimes(1);
});
expect(screen.getByText('Alpha Team')).toBeInTheDocument();
});
test('should show no selected teams when team_ids value is undefined', async () => {
const props = getBaseProps();
const option: FilterOption = {
name: 'Teams',
keys: ['team_ids'],
values: {},
};
renderWithContext(
<TeamFilterDropdown
{...props}
option={option}
/>,
);
await waitFor(() => {
expect(props.getTeams).toHaveBeenCalledTimes(1);
});
expect(screen.queryByText('Alpha Team')).not.toBeInTheDocument();
expect(screen.queryByText('Beta Team')).not.toBeInTheDocument();
expect(screen.getByText('Search and select teams')).toBeInTheDocument();
});
test('should show no selected teams when team_ids value is a non-array', async () => {
const props = getBaseProps();
const option: FilterOption = {
name: 'Teams',
keys: ['team_ids'],
values: {
team_ids: {name: 'Teams', value: true},
},
};
renderWithContext(
<TeamFilterDropdown
{...props}
option={option}
/>,
);
await waitFor(() => {
expect(props.getTeams).toHaveBeenCalledTimes(1);
});
// Non-array falls back to [], so no teams selected despite teams being loaded
expect(screen.queryByText('Alpha Team')).not.toBeInTheDocument();
expect(screen.queryByText('Beta Team')).not.toBeInTheDocument();
expect(screen.getByText('Search and select teams')).toBeInTheDocument();
});
});
@@ -22,6 +22,9 @@ type TeamSelectOption = {label: string; value: string}
export interface Props extends PropsFromRedux {
option: FilterOption;
/** Passed by `Filter` for all filter list components; unused here. */
optionKey?: string;
updateValues: (values: FilterValues, optionKey: string) => void;
}
@@ -99,7 +102,8 @@ function TeamFilterDropdown(props: Props) {
loadListInPageNumber(0);
}, []);
const optionValues = props.option.values?.team_ids?.value as string[];
const rawTeamIds = props.option.values?.team_ids?.value;
const optionValues = Array.isArray(rawTeamIds) ? rawTeamIds : [];
const selectedValues = list.filter((item) => optionValues.includes(item.value));
return (
@@ -1,108 +1,59 @@
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
exports[`admin_console/system_roles should match snapshot 1`] = `
<div
className="wrapper--fixed"
>
<AdminHeader>
<MemoizedFormattedMessage
defaultMessage="Delegated Granular Administration"
id="admin.permissions.systemRoles"
/>
</AdminHeader>
<div>
<div
className="admin-console__wrapper"
class="wrapper--fixed"
>
<div
className="admin-console__content"
class="admin-console__header"
>
<AdminPanel
id="SystemRoles"
subtitle={
Object {
"defaultMessage": "Manage different levels of access to the system console.",
"id": "admin.permissions.systemRolesBannerText",
}
}
title={
Object {
"defaultMessage": "Admin Roles",
"id": "admin.permissions.systemRolesBannerTitle",
}
}
Delegated Granular Administration
</div>
<div
class="admin-console__wrapper"
>
<div
class="admin-console__content"
>
<div
className="SystemRoles"
class="AdminPanel clearfix "
id="SystemRoles"
>
<DataGrid
columns={
Array [
Object {
"field": "role",
"name": "Role",
"width": 2,
},
Object {
"field": "description",
"name": "Description",
"width": 3,
},
Object {
"field": "type",
"name": "Type",
"width": 2,
},
Object {
"field": "edit",
"name": "",
"textAlign": "right",
"width": 1,
},
]
}
endCount={1}
loading={false}
nextPage={[Function]}
previousPage={[Function]}
rows={
Array [
Object {
"cells": Object {
"description": <Memo(MemoizedFormattedMessage)
defaultMessage="Access to modifying everything."
id="admin.permissions.roles.system_admin.description"
/>,
"edit": <span
className="SystemRoles_editRow"
data-testid="system_admin_edit"
>
<Link
to="/admin_console/user_management/system_roles/system_admin"
>
<Memo(MemoizedFormattedMessage)
defaultMessage="Edit"
id="admin.permissions.roles.edit"
/>
</Link>
</span>,
"role": <Memo(MemoizedFormattedMessage)
defaultMessage="System Admin"
id="admin.permissions.roles.system_admin.name"
/>,
"type": <Memo(MemoizedFormattedMessage)
defaultMessage="System Role"
id="admin.permissions.roles.system_admin.type"
/>,
},
"onClick": [Function],
},
]
}
startCount={0}
term=""
/>
<div
class="header"
>
<div>
<h3>
Admin Roles
</h3>
<div
class="mt-2"
>
Manage different levels of access to the system console.
</div>
</div>
</div>
<div
class="SystemRoles"
>
<div
class="DataGrid"
>
<div
class="DataGrid_header"
/>
<div
class="DataGrid_rows"
>
<div
class="DataGrid_row"
/>
</div>
</div>
</div>
</div>
</AdminPanel>
</div>
</div>
</div>
</div>
@@ -1,125 +1,127 @@
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
exports[`admin_console/system_role should match snapshot 1`] = `
<div
className="wrapper--fixed"
>
<AdminHeader
withBackButton={true}
>
<div>
<Connect(Component)
className="fa fa-angle-left back"
to="/admin_console/user_management/system_roles"
/>
role_name
</div>
</AdminHeader>
<div>
<div
className="admin-console__wrapper"
class="wrapper--fixed"
>
<div
className="admin-console__content"
class="admin-console__header with-back"
>
<SystemRolePermissions
isLicensedForCloud={false}
permissionsToUpdate={Object {}}
readOnly={false}
role={
Object {
"built_in": false,
"create_at": 0,
"delete_at": 0,
"description": "role_description",
"display_name": "role_display_name",
"id": "role_id",
"name": "role_name",
"permissions": Array [],
"scheme_managed": false,
"update_at": 0,
}
}
updatePermissions={[Function]}
/>
<Connect(SystemRoleUsers)
key="0"
onAddCallback={[Function]}
onRemoveCallback={[Function]}
readOnly={false}
roleName="role_name"
usersToAdd={Object {}}
usersToRemove={Object {}}
<div>
<a
class="fa fa-angle-left back"
href="/admin_console/user_management/system_roles"
/>
role_name
</div>
</div>
<div
class="admin-console__wrapper"
>
<div
class="admin-console__content"
>
<div
data-testid="mock-system-role-permissions"
>
Permissions for role_name
</div>
<div
data-testid="mock-system-role-users"
>
Users for role_name
</div>
</div>
</div>
<div
class="admin-console-save"
>
<button
class="btn btn-primary"
data-testid="saveSetting"
disabled=""
id="saveSetting"
type="submit"
>
<span>
Save
</span>
</button>
<a
class="btn btn-quaternary"
href="/admin_console/user_management/system_roles"
id="cancelButtonSettings"
>
Cancel
</a>
<div
class="error-message"
/>
</div>
</div>
<SaveChangesPanel
cancelLink="/admin_console/user_management/system_roles"
isDisabled={false}
onClick={[Function]}
saveNeeded={false}
saving={false}
/>
</div>
`;
exports[`admin_console/system_role should match snapshot with isLicensedForCloud = true 1`] = `
<div
className="wrapper--fixed"
>
<AdminHeader
withBackButton={true}
>
<div>
<Connect(Component)
className="fa fa-angle-left back"
to="/admin_console/user_management/system_roles"
/>
role_name
</div>
</AdminHeader>
<div>
<div
className="admin-console__wrapper"
class="wrapper--fixed"
>
<div
className="admin-console__content"
class="admin-console__header with-back"
>
<SystemRolePermissions
isLicensedForCloud={true}
permissionsToUpdate={Object {}}
readOnly={false}
role={
Object {
"built_in": false,
"create_at": 0,
"delete_at": 0,
"description": "role_description",
"display_name": "role_display_name",
"id": "role_id",
"name": "role_name",
"permissions": Array [],
"scheme_managed": false,
"update_at": 0,
}
}
updatePermissions={[Function]}
/>
<Connect(SystemRoleUsers)
key="0"
onAddCallback={[Function]}
onRemoveCallback={[Function]}
readOnly={false}
roleName="role_name"
usersToAdd={Object {}}
usersToRemove={Object {}}
<div>
<a
class="fa fa-angle-left back"
href="/admin_console/user_management/system_roles"
/>
role_name
</div>
</div>
<div
class="admin-console__wrapper"
>
<div
class="admin-console__content"
>
<div
data-testid="mock-system-role-permissions"
>
Permissions for role_name
</div>
<div
data-testid="mock-system-role-users"
>
Users for role_name
</div>
</div>
</div>
<div
class="admin-console-save"
>
<button
class="btn btn-primary"
data-testid="saveSetting"
disabled=""
id="saveSetting"
type="submit"
>
<span>
Save
</span>
</button>
<a
class="btn btn-quaternary"
href="/admin_console/user_management/system_roles"
id="cancelButtonSettings"
>
Cancel
</a>
<div
class="error-message"
/>
</div>
</div>
<SaveChangesPanel
cancelLink="/admin_console/user_management/system_roles"
isDisabled={false}
onClick={[Function]}
saveNeeded={false}
saving={false}
/>
</div>
`;
@@ -1,50 +1,58 @@
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
exports[`admin_console/system_role_permission should match snapshot 1`] = `
<div
className="PermissionRow"
>
<div>
<div
className="PermissionSection"
data-testid="permission_section_environment"
key="environment"
class="PermissionRow"
>
<div
className="PermissionSectionText"
class="PermissionSection"
data-testid="permission_section_environment"
>
<div
className="PermissionSectionText_title"
class="PermissionSectionText"
>
<MemoizedFormattedMessage
defaultMessage="Environment"
id="admin.permissions.sysconsole_section_environment.name"
/>
<div
class="PermissionSectionText_title"
>
Environment
</div>
<div
class="PermissionSection_description"
>
Review server environment configuration such as URLs, database and performance.
</div>
</div>
<div
className="PermissionSection_description"
class="PermissionSectionDropdown"
>
<MemoizedFormattedMessage
defaultMessage="Review server environment configuration such as URLs, database and performance."
id="admin.permissions.sysconsole_section_environment.description"
/>
<div
class="MenuWrapper "
disabled=""
>
<button
aria-expanded="true"
class="PermissionSectionDropdownButton dropdown-toggle theme"
id="systemRolePermissionDropdownenvironment"
type="button"
>
<div
class="PermissionSectionDropdownButton_text"
>
Read only
</div>
<div
class="PermissionSectionDropdownButton_icon"
>
<i
class="fa fa-angle-down"
title="Dropdown Icon"
/>
</div>
</button>
</div>
</div>
</div>
<div
className="PermissionSectionDropdown"
>
<SystemRolePermissionDropdown
access="read"
isDisabled={true}
section={
Object {
"hasDescription": true,
"name": "environment",
"subsections": Array [],
}
}
updatePermissions={[MockFunction]}
/>
</div>
</div>
</div>
`;
@@ -1,223 +1,60 @@
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
exports[`admin_console/system_role_permission_dropdown should match snapshot 1`] = `
<MenuWrapper
animationComponent={[Function]}
className=""
isDisabled={false}
>
<button
aria-expanded="true"
className="PermissionSectionDropdownButton dropdown-toggle theme"
id="systemRolePermissionDropdownenvironemnt"
type="button"
<div>
<div
class="MenuWrapper "
>
<div
className="PermissionSectionDropdownButton_text"
<button
aria-expanded="true"
class="PermissionSectionDropdownButton dropdown-toggle theme"
id="systemRolePermissionDropdownenvironemnt"
type="button"
>
<MemoizedFormattedMessage
defaultMessage="Read only"
id="admin.permissions.system_role_permissions.read.title"
/>
</div>
<div
className="PermissionSectionDropdownButton_icon"
>
<DropdownIcon />
</div>
</button>
<Menu
ariaLabel="Change role access on a system console section"
>
<MenuItemAction
onClick={[Function]}
show={true}
text={
<div
className="PermissionSectionDropdownOptions"
>
<div
className="PermissionSectionDropdownOptions_label"
>
<Memo(MemoizedFormattedMessage)
defaultMessage="Can edit"
id="admin.permissions.system_role_permissions.write.title"
/>
</div>
<div
className="PermissionSectionDropdownOptions_description"
>
<Memo(MemoizedFormattedMessage)
defaultMessage="Can add, edit and delete anything in this section."
id="admin.permissions.system_role_permissions.write.description"
/>
</div>
</div>
}
/>
<MenuItemAction
onClick={[Function]}
show={true}
text={
<div
className="PermissionSectionDropdownOptions"
>
<div
className="PermissionSectionDropdownOptions_label"
>
<Memo(MemoizedFormattedMessage)
defaultMessage="Read only"
id="admin.permissions.system_role_permissions.read.title"
/>
</div>
<div
className="PermissionSectionDropdownOptions_description"
>
<Memo(MemoizedFormattedMessage)
defaultMessage="Can view this section but can't edit anything in it"
id="admin.permissions.system_role_permissions.read.description"
/>
</div>
</div>
}
/>
<MenuItemAction
onClick={[Function]}
show={true}
text={
<div
className="PermissionSectionDropdownOptions"
>
<div
className="PermissionSectionDropdownOptions_label"
>
<Memo(MemoizedFormattedMessage)
defaultMessage="No access"
id="admin.permissions.system_role_permissions.no_access.title"
/>
</div>
<div
className="PermissionSectionDropdownOptions_description"
>
<Memo(MemoizedFormattedMessage)
defaultMessage="No access to this section and it will be hidden in the navigation."
id="admin.permissions.system_role_permissions.no_access.description"
/>
</div>
</div>
}
/>
</Menu>
</MenuWrapper>
<div
class="PermissionSectionDropdownButton_text"
>
Read only
</div>
<div
class="PermissionSectionDropdownButton_icon"
>
<i
class="fa fa-angle-down"
title="Dropdown Icon"
/>
</div>
</button>
</div>
</div>
`;
exports[`admin_console/system_role_permission_dropdown should match snapshot with isDisabledTrue 1`] = `
<MenuWrapper
animationComponent={[Function]}
className=""
isDisabled={true}
>
<button
aria-expanded="true"
className="PermissionSectionDropdownButton dropdown-toggle theme"
id="systemRolePermissionDropdownenvironemnt"
type="button"
<div>
<div
class="MenuWrapper "
disabled=""
>
<div
className="PermissionSectionDropdownButton_text"
<button
aria-expanded="true"
class="PermissionSectionDropdownButton dropdown-toggle theme"
id="systemRolePermissionDropdownenvironemnt"
type="button"
>
<MemoizedFormattedMessage
defaultMessage="Read only"
id="admin.permissions.system_role_permissions.read.title"
/>
</div>
<div
className="PermissionSectionDropdownButton_icon"
>
<DropdownIcon />
</div>
</button>
<Menu
ariaLabel="Change role access on a system console section"
>
<MenuItemAction
onClick={[Function]}
show={true}
text={
<div
className="PermissionSectionDropdownOptions"
>
<div
className="PermissionSectionDropdownOptions_label"
>
<Memo(MemoizedFormattedMessage)
defaultMessage="Can edit"
id="admin.permissions.system_role_permissions.write.title"
/>
</div>
<div
className="PermissionSectionDropdownOptions_description"
>
<Memo(MemoizedFormattedMessage)
defaultMessage="Can add, edit and delete anything in this section."
id="admin.permissions.system_role_permissions.write.description"
/>
</div>
</div>
}
/>
<MenuItemAction
onClick={[Function]}
show={true}
text={
<div
className="PermissionSectionDropdownOptions"
>
<div
className="PermissionSectionDropdownOptions_label"
>
<Memo(MemoizedFormattedMessage)
defaultMessage="Read only"
id="admin.permissions.system_role_permissions.read.title"
/>
</div>
<div
className="PermissionSectionDropdownOptions_description"
>
<Memo(MemoizedFormattedMessage)
defaultMessage="Can view this section but can't edit anything in it"
id="admin.permissions.system_role_permissions.read.description"
/>
</div>
</div>
}
/>
<MenuItemAction
onClick={[Function]}
show={true}
text={
<div
className="PermissionSectionDropdownOptions"
>
<div
className="PermissionSectionDropdownOptions_label"
>
<Memo(MemoizedFormattedMessage)
defaultMessage="No access"
id="admin.permissions.system_role_permissions.no_access.title"
/>
</div>
<div
className="PermissionSectionDropdownOptions_description"
>
<Memo(MemoizedFormattedMessage)
defaultMessage="No access to this section and it will be hidden in the navigation."
id="admin.permissions.system_role_permissions.no_access.description"
/>
</div>
</div>
}
/>
</Menu>
</MenuWrapper>
<div
class="PermissionSectionDropdownButton_text"
>
Read only
</div>
<div
class="PermissionSectionDropdownButton_icon"
>
<i
class="fa fa-angle-down"
title="Dropdown Icon"
/>
</div>
</button>
</div>
</div>
`;
@@ -1,13 +1,28 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {shallow} from 'enzyme';
import React from 'react';
import {renderWithContext} from 'tests/react_testing_utils';
import {TestHelper} from 'utils/test_helper';
import SystemRole from './system_role';
jest.mock('./system_role_permissions', () => {
return function MockSystemRolePermissions(props: {role: {name: string}}) {
return <div data-testid='mock-system-role-permissions'>{`Permissions for ${props.role.name}`}</div>;
};
});
jest.mock('./system_role_users', () => {
return {
__esModule: true,
default: function MockSystemRoleUsers(props: {roleName: string}) {
return <div data-testid='mock-system-role-users'>{`Users for ${props.roleName}`}</div>;
},
};
});
describe('admin_console/system_role', () => {
const props = {
role: TestHelper.getRoleMock(),
@@ -21,21 +36,23 @@ describe('admin_console/system_role', () => {
};
test('should match snapshot', () => {
const wrapper = shallow(
const {container} = renderWithContext(
<SystemRole
{...props}
/>);
/>,
);
expect(wrapper).toMatchSnapshot();
expect(container).toMatchSnapshot();
});
test('should match snapshot with isLicensedForCloud = true', () => {
const wrapper = shallow(
const {container} = renderWithContext(
<SystemRole
{...props}
isLicensedForCloud={true}
/>);
/>,
);
expect(wrapper).toMatchSnapshot();
expect(container).toMatchSnapshot();
});
});
@@ -1,10 +1,9 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {shallow} from 'enzyme';
import React from 'react';
import {TestHelper} from 'utils/test_helper';
import {renderWithContext} from 'tests/react_testing_utils';
import SystemRolePermission from './system_role_permission';
import {readAccess} from './types';
@@ -27,16 +26,14 @@ describe('admin_console/system_role_permission', () => {
environment: readAccess,
},
updatePermissions: jest.fn(),
roles: {
system_admin: TestHelper.getRoleMock(),
},
};
const wrapper = shallow(
const {container} = renderWithContext(
<SystemRolePermission
{...props}
/>);
/>,
);
expect(wrapper).toMatchSnapshot();
expect(container).toMatchSnapshot();
});
});
@@ -1,9 +1,10 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {shallow} from 'enzyme';
import React from 'react';
import {renderWithContext} from 'tests/react_testing_utils';
import SystemRolePermissionDropdown from './system_role_permission_dropdown';
import {readAccess} from './types';
@@ -20,21 +21,23 @@ describe('admin_console/system_role_permission_dropdown', () => {
};
test('should match snapshot', () => {
const wrapper = shallow(
const {container} = renderWithContext(
<SystemRolePermissionDropdown
{...props}
/>);
/>,
);
expect(wrapper).toMatchSnapshot();
expect(container).toMatchSnapshot();
});
test('should match snapshot with isDisabledTrue', () => {
const wrapper = shallow(
const {container} = renderWithContext(
<SystemRolePermissionDropdown
{...props}
isDisabled={true}
/>);
/>,
);
expect(wrapper).toMatchSnapshot();
expect(container).toMatchSnapshot();
});
});
@@ -1,12 +1,12 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {shallow} from 'enzyme';
import {screen} from '@testing-library/react';
import React from 'react';
import {renderWithContext} from 'tests/react_testing_utils';
import {TestHelper} from 'utils/test_helper';
import SystemRolePermission from './system_role_permission';
import SystemRolePermissions from './system_role_permissions';
import {readAccess, writeAccess} from './types';
@@ -23,38 +23,49 @@ describe('admin_console/system_role_permissions', () => {
};
test('should match snapshot', () => {
const wrapper = shallow(
const {container} = renderWithContext(
<SystemRolePermissions
{...props}
/>);
/>,
);
expect(wrapper).toMatchSnapshot();
expect(container).toMatchSnapshot();
});
test('should match snapshot with isLicensedForCloud = true', () => {
const wrapper = shallow(
const {container} = renderWithContext(
<SystemRolePermissions
{...props}
isLicensedForCloud={true}
/>);
/>,
);
expect(wrapper).toMatchSnapshot();
expect(container).toMatchSnapshot();
});
test('ensure that when you change a prop and component is re-rendered, SystemRolePermission is not being deleted due to isLicensedForCloud being false (test for bug MM-31403)', () => {
const wrapper = shallow(
const {rerender} = renderWithContext(
<SystemRolePermissions
{...props}
/>);
/>,
);
const expectedLength = 8;
let systemRolePermissionLength = wrapper.find(SystemRolePermission).length;
expect(systemRolePermissionLength).toEqual(expectedLength);
wrapper.setProps({permissionToUpdate: {
environment: writeAccess,
plugins: readAccess,
}});
systemRolePermissionLength = wrapper.find(SystemRolePermission).length;
expect(systemRolePermissionLength).toEqual(expectedLength);
// Count the permission sections rendered
const getSectionCount = () => screen.getAllByTestId(/^permission_section_/).length;
const expectedLength = getSectionCount();
// Re-render with updated permissions
rerender(
<SystemRolePermissions
{...props}
permissionsToUpdate={{
environment: writeAccess,
plugins: readAccess,
}}
/>,
);
expect(getSectionCount()).toEqual(expectedLength);
});
});
@@ -1,15 +1,16 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {shallow} from 'enzyme';
import {screen, waitFor} from '@testing-library/react';
import React from 'react';
import {renderWithContext} from 'tests/react_testing_utils';
import {TestHelper} from 'utils/test_helper';
import SystemRoleUsers from './system_role_users';
describe('admin_console/system_role_users', () => {
const props = {
const getBaseProps = () => ({
users: [TestHelper.getUserMock()],
role: TestHelper.getRoleMock(),
totalCount: 5,
@@ -24,30 +25,43 @@ describe('admin_console/system_role_users', () => {
onAddCallback: jest.fn(),
onRemoveCallback: jest.fn(),
actions: {
getFilteredUsersStats: jest.fn(),
getProfiles: jest.fn(),
searchProfiles: jest.fn(),
getFilteredUsersStats: jest.fn().mockResolvedValue({data: {}}),
getProfiles: jest.fn().mockResolvedValue({data: []}),
searchProfiles: jest.fn().mockResolvedValue({data: []}),
setUserGridSearch: jest.fn(),
},
readOnly: false,
};
test('should match snapshot', () => {
const wrapper = shallow(
<SystemRoleUsers
{...props}
/>);
expect(wrapper).toMatchSnapshot();
});
test('should match snapshot with readOnly true', () => {
const wrapper = shallow(
test('should match snapshot', async () => {
const props = getBaseProps();
const {container} = renderWithContext(
<SystemRoleUsers
{...props}
/>,
);
await waitFor(() => {
expect(props.actions.getProfiles).toHaveBeenCalledTimes(1);
});
expect(container).toMatchSnapshot();
});
test('should match snapshot with readOnly true', async () => {
const props = getBaseProps();
const {container} = renderWithContext(
<SystemRoleUsers
{...props}
readOnly={true}
/>);
/>,
);
expect(wrapper).toMatchSnapshot();
await waitFor(() => {
expect(props.actions.getProfiles).toHaveBeenCalledTimes(1);
});
expect(screen.getByRole('button', {name: 'Add People'})).toBeDisabled();
expect(container).toMatchSnapshot();
});
});
@@ -1,9 +1,9 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {shallow} from 'enzyme';
import React from 'react';
import {renderWithContext} from 'tests/react_testing_utils';
import {TestHelper} from 'utils/test_helper';
import SystemRoles from './system_roles';
@@ -18,11 +18,12 @@ describe('admin_console/system_roles', () => {
}),
};
const wrapper = shallow(
const {container} = renderWithContext(
<SystemRoles
roles={roles}
/>);
/>,
);
expect(wrapper).toMatchSnapshot();
expect(container).toMatchSnapshot();
});
});
@@ -1,127 +1,146 @@
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
exports[`admin_console/team_channel_settings/AbstractList should match snapshot, no headers 1`] = `
<div
className="groups-list groups-list-no-padding"
>
<div>
<div
className="groups-list--body"
id="groups-list--body"
class="groups-list groups-list-no-padding"
>
<div
className="groups-list-empty"
class="groups-list--body"
id="groups-list--body"
>
<MemoizedFormattedMessage
defaultMessage="test"
id="test"
/>
<div
class="groups-list-empty"
>
test
</div>
</div>
</div>
</div>
`;
exports[`admin_console/team_channel_settings/AbstractList should match snapshot, with data 1`] = `
<div
className="groups-list groups-list-no-padding"
>
<div>
<div
className="groups-list--header"
class="groups-list groups-list-no-padding"
>
<div
className="group-name adjusted"
>
<MemoizedFormattedMessage
defaultMessage="Name"
id="admin.channel_settings.channel_list.nameHeader"
/>
</div>
<div
className="group-content"
class="groups-list--header"
>
<div
className="group-description"
class="group-name adjusted"
>
<MemoizedFormattedMessage
defaultMessage="Team"
id="admin.channel_settings.channel_list.teamHeader"
/>
Name
</div>
<div
className="group-description adjusted"
class="group-content"
>
<MemoizedFormattedMessage
defaultMessage="Management"
id="admin.channel_settings.channel_list.managementHeader"
<div
class="group-description"
>
Team
</div>
<div
class="group-description adjusted"
>
Management
</div>
<div
class="group-actions"
/>
</div>
<div
className="group-actions"
/>
</div>
</div>
<div
className="groups-list--body"
id="groups-list--body"
>
<GroupRow
group={
Object {
"allow_open_invite": false,
"allowed_domains": "",
"company_name": "",
"create_at": 0,
"delete_at": 0,
"description": "",
"display_name": "DN",
"email": "",
"group_constrained": false,
"id": "123",
"invite_id": "",
"name": "DN",
"scheme_id": "id",
"type": "O",
"update_at": 0,
}
}
key="123"
removeGroup={[MockFunction]}
setNewGroupRole={[MockFunction]}
type="channel"
/>
</div>
<div
className="groups-list--footer"
>
<div
className="counter"
class="groups-list--body"
id="groups-list--body"
>
<MemoizedFormattedMessage
defaultMessage="{startCount, number} - {endCount, number} of {total, number}"
id="admin.team_channel_settings.list.paginatorCount"
values={
Object {
"endCount": 1,
"startCount": 1,
"total": 1,
}
}
/>
<div
class="group"
id="group"
>
<div
class="group-row"
id="group-row"
>
<span
class="group-name row-content"
>
DN
</span>
<span
class="group-description row-content"
>
<button
class="style--none color--link"
id="DNMembersToggle"
>
NaN members
</button>
</span>
<div
class="group-description row-content roles"
>
<div
class="MenuWrapper "
>
<div>
<a
data-testid="current-role"
>
<span>
Member
</span>
<span
class="caret"
/>
</a>
</div>
</div>
</div>
<span
class="group-actions"
id="group-actions"
>
<a
class=""
href="#"
>
Remove
</a>
</span>
</div>
</div>
</div>
<button
className="btn btn-tertiary prev disabled"
disabled={true}
type="button"
<div
class="groups-list--footer"
>
<Memo(PreviousIcon) />
</button>
<button
className="btn btn-tertiary next disabled"
data-testid="page-link-next"
disabled={true}
type="button"
>
<Memo(NextIcon) />
</button>
<div
class="counter"
>
1 - 1 of 1
</div>
<button
class="btn btn-tertiary prev disabled"
disabled=""
type="button"
>
<i
class="icon icon-chevron-left"
title="Previous Icon"
/>
</button>
<button
class="btn btn-tertiary next disabled"
data-testid="page-link-next"
disabled=""
type="button"
>
<i
class="icon icon-chevron-right"
title="Next Icon"
/>
</button>
</div>
</div>
</div>
`;
@@ -1,12 +1,12 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {shallow} from 'enzyme';
import React from 'react';
import {FormattedMessage} from 'react-intl';
import type {Channel} from '@mattermost/types/channels';
import {renderWithContext, waitFor} from 'tests/react_testing_utils';
import {TestHelper} from 'utils/test_helper';
import AbstractList from './abstract_list';
@@ -40,7 +40,7 @@ describe('admin_console/team_channel_settings/AbstractList', () => {
</div>
</div>);
test('should match snapshot, no headers', () => {
test('should match snapshot, no headers', async () => {
const testChannels: Channel[] = [];
const actions = {
@@ -49,7 +49,7 @@ describe('admin_console/team_channel_settings/AbstractList', () => {
removeGroup: jest.fn(),
};
const wrapper = shallow(
const {container} = renderWithContext(
<AbstractList
onPageChangedCallback={jest.fn()}
total={0}
@@ -60,13 +60,17 @@ describe('admin_console/team_channel_settings/AbstractList', () => {
defaultMessage: 'test',
}}
actions={actions}
/>);
/>,
);
wrapper.setState({loading: false});
expect(wrapper).toMatchSnapshot();
await waitFor(() => {
expect(actions.getData).toHaveBeenCalled();
});
expect(container).toMatchSnapshot();
});
test('should match snapshot, with data', () => {
test('should match snapshot, with data', async () => {
const testTeams: TeamWithMembership[] = [TestHelper.getTeamMock({
id: '123',
display_name: 'DN',
@@ -78,7 +82,7 @@ describe('admin_console/team_channel_settings/AbstractList', () => {
removeGroup: jest.fn(),
};
const wrapper = shallow(
const {container} = renderWithContext(
<AbstractList
data={testTeams}
onPageChangedCallback={jest.fn()}
@@ -90,10 +94,14 @@ describe('admin_console/team_channel_settings/AbstractList', () => {
defaultMessage: 'test',
}}
actions={actions}
/>);
/>,
);
wrapper.setState({loading: false});
expect(wrapper).toMatchSnapshot();
await waitFor(() => {
expect(actions.getData).toHaveBeenCalled();
});
expect(container).toMatchSnapshot();
});
const renderRow = jest.fn((item) => {
@@ -1,50 +1,44 @@
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
exports[`admin_console/team_channel_settings/channel/ChannelSettings should match snapshot 1`] = `
<div
className="wrapper--fixed"
>
<AdminHeader>
<MemoizedFormattedMessage
defaultMessage="{siteName} Channels"
id="admin.channel_settings.groupsPageTitle"
values={
Object {
"siteName": "site",
}
}
/>
</AdminHeader>
<div>
<div
className="admin-console__wrapper"
class="wrapper--fixed"
>
<div
className="admin-console__content"
class="admin-console__header"
>
<AdminPanel
id="channels"
subtitle={
Object {
"defaultMessage": "Manage channel settings.",
"id": "admin.channel_settings.description",
}
}
subtitleValues={
Object {
"endCount": 1,
"startCount": 0,
"total": 0,
}
}
title={
Object {
"defaultMessage": "Channels",
"id": "admin.channel_settings.title",
}
}
site Channels
</div>
<div
class="admin-console__wrapper"
>
<div
class="admin-console__content"
>
<Connect(ChannelList) />
</AdminPanel>
<div
class="AdminPanel clearfix "
id="channels"
>
<div
class="header"
>
<div>
<h3>
Channels
</h3>
<div
class="mt-2"
>
Manage channel settings.
</div>
</div>
</div>
<div>
ChannelsList
</div>
</div>
</div>
</div>
</div>
</div>
@@ -1,18 +1,21 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {shallow} from 'enzyme';
import React from 'react';
import {renderWithContext} from 'tests/react_testing_utils';
import {ChannelsSettings} from './channel_settings';
jest.mock('components/admin_console/team_channel_settings/channel/list', () => () => <div>{'ChannelsList'}</div>);
describe('admin_console/team_channel_settings/channel/ChannelSettings', () => {
test('should match snapshot', () => {
const wrapper = shallow(
const {container} = renderWithContext(
<ChannelsSettings
siteName='site'
/>,
);
expect(wrapper).toMatchSnapshot();
expect(container).toMatchSnapshot();
});
});
@@ -1,88 +1,107 @@
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
exports[`admin_console/team_channel_settings/channel/ChannelGroups should match snapshot 1`] = `
<AdminPanel
button={
<ToggleModalButton
className="btn btn-primary"
dialogProps={
Object {
"channel": Object {
"group_constrained": false,
"id": "123",
"name": "DN",
"team_name": "team",
"type": "O",
},
"excludeGroups": Array [
Object {
"display_name": "DN",
"id": "123",
"member_count": 3,
},
],
"includeGroups": Array [],
"onAddCallback": [MockFunction],
"skipCommit": true,
}
}
dialogType={
Object {
"$$typeof": Symbol(react.memo),
"WrappedComponent": [Function],
"compare": null,
"type": [Function],
}
}
disabled={false}
id="addGroupsToChannelToggle"
modalId="add_groups_to_channel"
<div>
<div
class="AdminPanel clearfix "
id="channel_groups"
>
<div
class="header"
>
<Memo(MemoizedFormattedMessage)
defaultMessage="Add Group"
id="admin.channel_settings.channel_details.add_group"
/>
</ToggleModalButton>
}
id="channel_groups"
subtitle={
Object {
"defaultMessage": "Add and remove channel members based on their group membership.",
"id": "admin.channel_settings.channel_detail.syncedGroupsDescription",
}
}
title={
Object {
"defaultMessage": "Synced Groups",
"id": "admin.channel_settings.channel_detail.syncedGroupsTitle",
}
}
>
<Connect(Component)
channel={
Object {
"group_constrained": false,
"id": "123",
"name": "DN",
"team_name": "team",
"type": "O",
}
}
groups={
Array [
Object {
"display_name": "DN",
"id": "123",
"member_count": 3,
},
]
}
isDisabled={false}
isModeSync={true}
onGroupRemoved={[MockFunction]}
setNewGroupRole={[MockFunction]}
totalGroups={1}
type="channel"
/>
</AdminPanel>
<div>
<h3>
Synced Groups
</h3>
<div
class="mt-2"
>
Add and remove channel members based on their group membership.
</div>
</div>
<div
class="button"
>
<button
class="style--none btn btn-primary"
id="addGroupsToChannelToggle"
>
Add Group
</button>
</div>
</div>
<div
class="groups-list groups-list-no-padding"
>
<div
class="groups-list--header"
>
<div
class="group-name group-name-adjusted"
>
Group Name
</div>
<div
class="group-content"
>
<div
class="group-description group-description-adjusted"
>
Member Count
</div>
<div
class="group-description group-description-adjusted"
>
Roles
</div>
<div
class="group-actions"
/>
</div>
</div>
<div
class="groups-list--body"
id="groups-list--body"
>
<div
class="groups-list-loading"
>
<i
class="fa fa-spinner fa-pulse fa-2x"
/>
</div>
</div>
<div
class="groups-list--footer"
>
<div
class="counter"
>
1 - 1 of 1
</div>
<button
class="btn btn-tertiary prev disabled"
disabled=""
type="button"
>
<i
class="icon icon-chevron-left"
title="Previous Icon"
/>
</button>
<button
class="btn btn-tertiary next disabled"
data-testid="page-link-next"
disabled=""
type="button"
>
<i
class="icon icon-chevron-right"
title="Next Icon"
/>
</button>
</div>
</div>
</div>
</div>
`;
@@ -1,82 +1,235 @@
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
exports[`admin_console/team_channel_settings/channel/ChannelModes should match snapshot - not licensed for Group 1`] = `
<AdminPanel
id="channel_manage"
subtitle={
Object {
"defaultMessage": "Choose between inviting members manually or syncing members automatically from groups.",
"id": "admin.channel_settings.channel_detail.manageDescription",
}
}
title={
Object {
"defaultMessage": "Channel Management",
"id": "admin.channel_settings.channel_detail.manageTitle",
}
}
>
<div>
<div
className="group-teams-and-channels"
class="AdminPanel clearfix "
id="channel_manage"
>
<div
className="group-teams-and-channels--body"
class="header"
>
<AllowAllToggle
isDefault={false}
isDisabled={false}
isPublic={true}
isSynced={false}
onToggle={[MockFunction]}
policyEnforced={false}
policyEnforcedToggleAvailable={false}
/>
<div>
<h3>
Channel Management
</h3>
<div
class="mt-2"
>
Choose between inviting members manually or syncing members automatically from groups.
</div>
</div>
</div>
<div
class="group-teams-and-channels"
>
<div
class="group-teams-and-channels--body"
>
<div>
<div
class="line-switch d-flex flex-sm-column flex-md-row align-items-sm-start align-items-center"
>
<label
class="line-switch__label"
>
Public channel or private channel
</label>
<div
class="line-switch__toggle"
data-testid="allow-all-toggle"
>
<button
aria-pressed="true"
class="btn btn-lg btn-toggle active"
data-testid="allow-all-toggle-button"
id="allow-all-toggle"
tabindex="0"
type="button"
>
<div
class="handle"
/>
<div
class="bg-text on"
>
Public
</div>
</button>
</div>
</div>
<div
class="row"
>
<div
class="col-sm-10"
>
<div
class="help-text-small help-text-no-padding "
>
Select Public for a channel any user can find and join.
<br />
Select Private to require channel invitations to join.
<br />
Use this switch to change this channel from public to private or from private to public.
</div>
</div>
</div>
<div
class="section-separator"
>
<hr
class="separator__hr"
/>
</div>
</div>
</div>
</div>
</div>
</AdminPanel>
</div>
`;
exports[`admin_console/team_channel_settings/channel/ChannelModes should match snapshot 1`] = `
<AdminPanel
id="channel_manage"
subtitle={
Object {
"defaultMessage": "Choose between inviting members manually or syncing members automatically from groups.",
"id": "admin.channel_settings.channel_detail.manageDescription",
}
}
title={
Object {
"defaultMessage": "Channel Management",
"id": "admin.channel_settings.channel_detail.manageTitle",
}
}
>
<div>
<div
className="group-teams-and-channels"
class="AdminPanel clearfix "
id="channel_manage"
>
<div
className="group-teams-and-channels--body"
class="header"
>
<SyncGroupsToggle
isDefault={false}
isDisabled={false}
isPublic={true}
isSynced={false}
onToggle={[MockFunction]}
policyEnforced={false}
policyEnforcedToggleAvailable={false}
/>
<AllowAllToggle
isDefault={false}
isDisabled={false}
isPublic={true}
isSynced={false}
onToggle={[MockFunction]}
policyEnforced={false}
policyEnforcedToggleAvailable={false}
/>
<div>
<h3>
Channel Management
</h3>
<div
class="mt-2"
>
Choose between inviting members manually or syncing members automatically from groups.
</div>
</div>
</div>
<div
class="group-teams-and-channels"
>
<div
class="group-teams-and-channels--body"
>
<div>
<div
class="line-switch d-flex flex-sm-column flex-md-row align-items-sm-start align-items-center"
>
<label
class="line-switch__label"
>
Sync Group Members
</label>
<div
class="line-switch__toggle"
data-testid="syncGroupSwitch"
>
<button
aria-pressed="false"
class="btn btn-lg btn-toggle"
data-testid="syncGroupSwitch-button"
id="syncGroupSwitch"
tabindex="0"
type="button"
>
<div
class="handle"
/>
</button>
</div>
</div>
<div
class="row"
>
<div
class="col-sm-10"
>
<div
class="help-text-small help-text-no-padding "
>
When enabled, adding and removing users from groups will add or remove them from this channel. The only way of inviting members to this channel is by adding the groups they belong to.
<a
href="https://www.mattermost.com/pl/default-ldap-group-constrained-team-channel.html?utm_source=mattermost&utm_medium=in-product&utm_content=channel_modes&uid=&sid=&edition=team&server_version="
location="channel_modes"
rel="noopener noreferrer"
target="_blank"
>
Learn More
</a>
</div>
</div>
</div>
<div
class="section-separator"
>
<hr
class="separator__hr"
/>
</div>
</div>
<div>
<div
class="line-switch d-flex flex-sm-column flex-md-row align-items-sm-start align-items-center"
>
<label
class="line-switch__label"
>
Public channel or private channel
</label>
<div
class="line-switch__toggle"
data-testid="allow-all-toggle"
>
<button
aria-pressed="true"
class="btn btn-lg btn-toggle active"
data-testid="allow-all-toggle-button"
id="allow-all-toggle"
tabindex="0"
type="button"
>
<div
class="handle"
/>
<div
class="bg-text on"
>
Public
</div>
</button>
</div>
</div>
<div
class="row"
>
<div
class="col-sm-10"
>
<div
class="help-text-small help-text-no-padding "
>
Select Public for a channel any user can find and join.
<br />
Select Private to require channel invitations to join.
<br />
Use this switch to change this channel from public to private or from private to public.
</div>
</div>
</div>
<div
class="section-separator"
>
<hr
class="separator__hr"
/>
</div>
</div>
</div>
</div>
</div>
</AdminPanel>
</div>
`;
@@ -1,153 +1,140 @@
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
exports[`admin_console/team_channel_settings/channel/ChannelProfile should match snapshot 1`] = `
<AdminPanel
id="channel_profile"
subtitle={
Object {
"defaultMessage": "Summary of the channel, including the channel name.",
"id": "admin.channel_settings.channel_detail.profileDescription",
}
}
title={
Object {
"defaultMessage": "Channel Profile",
"id": "admin.channel_settings.channel_detail.profileTitle",
}
}
>
<div>
<div
className="group-teams-and-channels AdminChannelDetails"
class="AdminPanel clearfix "
id="channel_profile"
>
<div
className="group-teams-and-channels--body channel-desc-col"
class="header"
>
<div>
<h3>
Channel Profile
</h3>
<div
class="mt-2"
>
Summary of the channel, including the channel name.
</div>
</div>
</div>
<div
class="group-teams-and-channels AdminChannelDetails"
>
<div
className="channel-name"
class="group-teams-and-channels--body channel-desc-col"
>
<b>
<MemoizedFormattedMessage
defaultMessage="Name"
id="admin.channelSettings.channelDetail.channelName"
/>
</b>
<br />
test
</div>
<div
className="channel-team"
>
<b>
<MemoizedFormattedMessage
defaultMessage="Team"
id="admin.channelSettings.channelDetail.channelTeam"
/>
</b>
<br />
test
</div>
<div
className="AdminChannelDetails_archiveContainer"
>
<button
className="btn btn-secondary btn-danger"
type="button"
<div
class="channel-name"
>
<i
className="icon icon-archive-outline"
/>
<MemoizedFormattedMessage
defaultMessage="Archive Channel"
id="admin.channel_settings.channel_details.archiveChannel"
/>
</button>
<b>
Name
</b>
<br />
test
</div>
<div
class="channel-team"
>
<b>
Team
</b>
<br />
test
</div>
<div
class="AdminChannelDetails_archiveContainer"
>
<button
class="btn btn-secondary btn-danger"
type="button"
>
<i
class="icon icon-archive-outline"
/>
Archive Channel
</button>
</div>
</div>
</div>
</div>
</AdminPanel>
</div>
`;
exports[`admin_console/team_channel_settings/channel/ChannelProfile should match snapshot for a shared channel 1`] = `
<AdminPanel
id="channel_profile"
subtitle={
Object {
"defaultMessage": "Summary of the channel, including the channel name.",
"id": "admin.channel_settings.channel_detail.profileDescription",
}
}
title={
Object {
"defaultMessage": "Channel Profile",
"id": "admin.channel_settings.channel_detail.profileTitle",
}
}
>
<div>
<div
className="group-teams-and-channels AdminChannelDetails"
class="AdminPanel clearfix "
id="channel_profile"
>
<div
className="group-teams-and-channels--body channel-desc-col"
class="header"
>
<div>
<h3>
Channel Profile
</h3>
<div
class="mt-2"
>
Summary of the channel, including the channel name.
</div>
</div>
</div>
<div
class="group-teams-and-channels AdminChannelDetails"
>
<div
className="channel-name"
class="group-teams-and-channels--body channel-desc-col"
>
<b>
<MemoizedFormattedMessage
defaultMessage="Name"
id="admin.channelSettings.channelDetail.channelName"
/>
</b>
<br />
test
</div>
<div
className="channel-team"
>
<b>
<MemoizedFormattedMessage
defaultMessage="Team"
id="admin.channelSettings.channelDetail.channelTeam"
/>
</b>
<br />
test
</div>
<div
className="channel-organizations"
>
<b>
<MemoizedFormattedMessage
defaultMessage="Organizations"
id="admin.channelSettings.channelDetail.channel_organizations"
/>
</b>
<br />
<SharedChannelIndicator
className="shared-channel-icon"
/>
<MemoizedFormattedMessage
defaultMessage="Shared with trusted organizations"
id="admin.channel_settings.channel_detail.channelOrganizationsMessage"
/>
</div>
<div
className="AdminChannelDetails_archiveContainer"
>
<button
className="btn btn-secondary btn-danger"
type="button"
<div
class="channel-name"
>
<b>
Name
</b>
<br />
test
</div>
<div
class="channel-team"
>
<b>
Team
</b>
<br />
test
</div>
<div
class="channel-organizations"
>
<b>
Organizations
</b>
<br />
<i
className="icon icon-archive-outline"
class="shared-channel-icon icon-circle-multiple-outline"
data-testid="SharedChannelIcon"
/>
<MemoizedFormattedMessage
defaultMessage="Archive Channel"
id="admin.channel_settings.channel_details.archiveChannel"
/>
</button>
Shared with trusted organizations
</div>
<div
class="AdminChannelDetails_archiveContainer"
>
<button
class="btn btn-secondary btn-danger"
type="button"
>
<i
class="icon icon-archive-outline"
/>
Archive Channel
</button>
</div>
</div>
</div>
</div>
</AdminPanel>
</div>
`;
@@ -1,116 +1,122 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {shallow} from 'enzyme';
import React from 'react';
import type {Channel} from '@mattermost/types/channels';
import type {Group} from '@mattermost/types/groups';
import type {Scheme} from '@mattermost/types/schemes';
import {renderWithContext} from 'tests/react_testing_utils';
import {TestHelper} from 'utils/test_helper';
import ChannelDetails from './channel_details';
jest.mock('utils/browser_history', () => ({
getHistory: jest.fn(() => ({push: jest.fn(), listen: jest.fn()})),
}));
jest.mock('./channel_members', () => () => <div>{'ChannelMembers'}</div>);
describe('admin_console/team_channel_settings/channel/ChannelDetails', () => {
const groups: Group[] = [{
id: '123',
name: 'name',
display_name: 'DN',
description: 'descript',
source: 'A',
remote_id: 'id',
create_at: 0,
update_at: 0,
delete_at: 0,
has_syncables: false,
member_count: 3,
scheme_admin: false,
allow_reference: false,
}];
const allGroups = {
123: groups[0],
};
const testChannel: Channel & {team_name: string} = {
id: '123',
team_name: 'team',
create_at: 0,
update_at: 0,
delete_at: 0,
team_id: 'id_123',
type: 'O',
display_name: 'name',
name: 'DN',
header: 'header',
purpose: 'purpose',
last_post_at: 0,
last_root_post_at: 0,
creator_id: 'id',
scheme_id: 'id',
group_constrained: false,
};
const team = TestHelper.getTeamMock({
display_name: 'test',
});
const teamScheme: Scheme = {
id: 'asdf',
name: 'asdf',
description: 'asdf',
display_name: 'asdf',
create_at: 0,
update_at: 0,
delete_at: 0,
scope: 'team',
default_team_admin_role: 'asdf',
default_team_user_role: 'asdf',
default_team_guest_role: 'asdf',
default_channel_admin_role: 'asdf',
default_channel_user_role: 'asdf',
default_channel_guest_role: 'asdf',
default_playbook_admin_role: 'asdf',
default_playbook_member_role: 'asdf',
default_run_member_role: 'asdf',
};
const actions = {
getChannel: jest.fn().mockResolvedValue([]),
getTeam: jest.fn().mockResolvedValue([]),
linkGroupSyncable: jest.fn(),
conver: jest.fn(),
patchChannel: jest.fn(),
setNavigationBlocked: jest.fn(),
unlinkGroupSyncable: jest.fn(),
getGroups: jest.fn().mockResolvedValue([]),
membersMinusGroupMembers: jest.fn(),
updateChannelPrivacy: jest.fn(),
patchGroupSyncable: jest.fn(),
getChannelModerations: jest.fn().mockResolvedValue([]),
patchChannelModerations: jest.fn(),
loadScheme: jest.fn(),
addChannelMember: jest.fn(),
removeChannelMember: jest.fn(),
updateChannelMemberSchemeRoles: jest.fn(),
deleteChannel: jest.fn(),
unarchiveChannel: jest.fn(),
getAccessControlPolicy: jest.fn().mockResolvedValue({data: null}),
deleteAccessControlPolicy: jest.fn(),
assignChannelToAccessControlPolicy: jest.fn(),
unassignChannelsFromAccessControlPolicy: jest.fn(),
searchPolicies: jest.fn(),
// Channel-level access rules actions
getAccessControlFields: jest.fn().mockResolvedValue({data: []}),
getVisualAST: jest.fn().mockResolvedValue({data: {}}),
saveChannelAccessPolicy: jest.fn().mockResolvedValue({data: {}}),
validateChannelExpression: jest.fn().mockResolvedValue({data: {}}),
createAccessControlSyncJob: jest.fn().mockResolvedValue({data: {}}),
updateAccessControlPoliciesActive: jest.fn().mockResolvedValue({data: {}}),
searchUsersForExpression: jest.fn().mockResolvedValue({data: {users: [], total: 0}}),
getChannelMembers: jest.fn().mockResolvedValue({data: []}),
getProfilesByIds: jest.fn().mockResolvedValue({data: []}),
};
test('should match snapshot', () => {
const groups: Group[] = [{
id: '123',
name: 'name',
display_name: 'DN',
description: 'descript',
source: 'A',
remote_id: 'id',
create_at: 0,
update_at: 0,
delete_at: 0,
has_syncables: false,
member_count: 3,
scheme_admin: false,
allow_reference: false,
}];
const allGroups = {
123: groups[0],
};
const testChannel: Channel & {team_name: string} = {
id: '123',
team_name: 'team',
create_at: 0,
update_at: 0,
delete_at: 0,
team_id: 'id_123',
type: 'O',
display_name: 'name',
name: 'DN',
header: 'header',
purpose: 'purpose',
last_post_at: 0,
last_root_post_at: 0,
creator_id: 'id',
scheme_id: 'id',
group_constrained: false,
};
const team = TestHelper.getTeamMock({
display_name: 'test',
});
const teamScheme: Scheme = {
id: 'asdf',
name: 'asdf',
description: 'asdf',
display_name: 'asdf',
create_at: 0,
update_at: 0,
delete_at: 0,
scope: 'team',
default_team_admin_role: 'asdf',
default_team_user_role: 'asdf',
default_team_guest_role: 'asdf',
default_channel_admin_role: 'asdf',
default_channel_user_role: 'asdf',
default_channel_guest_role: 'asdf',
default_playbook_admin_role: 'asdf',
default_playbook_member_role: 'asdf',
default_run_member_role: 'asdf',
};
const actions = {
getChannel: jest.fn().mockResolvedValue([]),
getTeam: jest.fn().mockResolvedValue([]),
linkGroupSyncable: jest.fn(),
conver: jest.fn(),
patchChannel: jest.fn(),
setNavigationBlocked: jest.fn(),
unlinkGroupSyncable: jest.fn(),
getGroups: jest.fn().mockResolvedValue([]),
membersMinusGroupMembers: jest.fn(),
updateChannelPrivacy: jest.fn(),
patchGroupSyncable: jest.fn(),
getChannelModerations: jest.fn().mockResolvedValue([]),
patchChannelModerations: jest.fn(),
loadScheme: jest.fn(),
addChannelMember: jest.fn(),
removeChannelMember: jest.fn(),
updateChannelMemberSchemeRoles: jest.fn(),
deleteChannel: jest.fn(),
unarchiveChannel: jest.fn(),
getAccessControlPolicy: jest.fn().mockResolvedValue({data: null}),
deleteAccessControlPolicy: jest.fn(),
assignChannelToAccessControlPolicy: jest.fn(),
unassignChannelsFromAccessControlPolicy: jest.fn(),
searchPolicies: jest.fn(),
// Channel-level access rules actions
getAccessControlFields: jest.fn().mockResolvedValue({data: []}),
getVisualAST: jest.fn().mockResolvedValue({data: {}}),
saveChannelAccessPolicy: jest.fn().mockResolvedValue({data: {}}),
validateChannelExpression: jest.fn().mockResolvedValue({data: {}}),
createAccessControlSyncJob: jest.fn().mockResolvedValue({data: {}}),
updateAccessControlPoliciesActive: jest.fn().mockResolvedValue({data: {}}),
searchUsersForExpression: jest.fn().mockResolvedValue({data: {users: [], total: 0}}),
getChannelMembers: jest.fn().mockResolvedValue({data: []}),
getProfilesByIds: jest.fn().mockResolvedValue({data: []}),
};
const additionalProps = {
channelPermissions: [],
guestAccountsEnabled: true,
@@ -120,11 +126,8 @@ describe('admin_console/team_channel_settings/channel/ChannelDetails', () => {
isDisabled: false,
};
if (!testChannel.id) {
return;
}
let wrapper = shallow(
let container;
({container} = renderWithContext(
<ChannelDetails
teamScheme={teamScheme}
groups={groups}
@@ -136,10 +139,10 @@ describe('admin_console/team_channel_settings/channel/ChannelDetails', () => {
allGroups={allGroups}
{...additionalProps}
/>,
);
expect(wrapper).toMatchSnapshot();
));
expect(container).toMatchSnapshot();
wrapper = shallow(
({container} = renderWithContext(
<ChannelDetails
teamScheme={teamScheme}
groups={groups}
@@ -151,107 +154,10 @@ describe('admin_console/team_channel_settings/channel/ChannelDetails', () => {
allGroups={allGroups}
{...additionalProps}
/>,
);
expect(wrapper).toMatchSnapshot();
));
expect(container).toMatchSnapshot();
});
test('should match snapshot for Professional', () => {
const groups: Group[] = [{
id: '123',
name: 'name',
display_name: 'DN',
description: 'descript',
source: 'A',
remote_id: 'id',
create_at: 0,
update_at: 0,
delete_at: 0,
has_syncables: false,
member_count: 3,
scheme_admin: false,
allow_reference: false,
}];
const allGroups = {
123: groups[0],
};
const testChannel: Channel & {team_name: string} = {
id: '123',
team_name: 'team',
create_at: 0,
update_at: 0,
delete_at: 0,
team_id: 'id_123',
type: 'O',
display_name: 'name',
name: 'DN',
header: 'header',
purpose: 'purpose',
last_post_at: 0,
last_root_post_at: 0,
creator_id: 'id',
scheme_id: 'id',
group_constrained: false,
};
const team = TestHelper.getTeamMock({
display_name: 'test',
});
const teamScheme: Scheme = {
id: 'asdf',
name: 'asdf',
description: 'asdf',
display_name: 'asdf',
create_at: 0,
update_at: 0,
delete_at: 0,
scope: 'team',
default_team_admin_role: 'asdf',
default_team_user_role: 'asdf',
default_team_guest_role: 'asdf',
default_channel_admin_role: 'asdf',
default_channel_user_role: 'asdf',
default_channel_guest_role: 'asdf',
default_playbook_admin_role: 'asdf',
default_playbook_member_role: 'asdf',
default_run_member_role: 'asdf',
};
const actions = {
getChannel: jest.fn().mockResolvedValue([]),
getTeam: jest.fn().mockResolvedValue([]),
linkGroupSyncable: jest.fn(),
conver: jest.fn(),
patchChannel: jest.fn(),
setNavigationBlocked: jest.fn(),
unlinkGroupSyncable: jest.fn(),
getGroups: jest.fn().mockResolvedValue([]),
membersMinusGroupMembers: jest.fn(),
updateChannelPrivacy: jest.fn(),
patchGroupSyncable: jest.fn(),
getChannelModerations: jest.fn().mockResolvedValue([]),
patchChannelModerations: jest.fn(),
loadScheme: jest.fn(),
addChannelMember: jest.fn(),
removeChannelMember: jest.fn(),
updateChannelMemberSchemeRoles: jest.fn(),
deleteChannel: jest.fn(),
unarchiveChannel: jest.fn(),
getAccessControlPolicy: jest.fn().mockResolvedValue({data: null}),
deleteAccessControlPolicy: jest.fn(),
assignChannelToAccessControlPolicy: jest.fn(),
unassignChannelsFromAccessControlPolicy: jest.fn(),
searchPolicies: jest.fn(),
// Channel-level access rules actions
getAccessControlFields: jest.fn().mockResolvedValue({data: []}),
getVisualAST: jest.fn().mockResolvedValue({data: {}}),
saveChannelAccessPolicy: jest.fn().mockResolvedValue({data: {}}),
validateChannelExpression: jest.fn().mockResolvedValue({data: {}}),
createAccessControlSyncJob: jest.fn().mockResolvedValue({data: {}}),
updateAccessControlPoliciesActive: jest.fn().mockResolvedValue({data: {}}),
searchUsersForExpression: jest.fn().mockResolvedValue({data: {users: [], total: 0}}),
getChannelMembers: jest.fn().mockResolvedValue({data: []}),
getProfilesByIds: jest.fn().mockResolvedValue({data: []}),
};
const additionalProps = {
channelPermissions: [],
guestAccountsEnabled: true,
@@ -261,11 +167,8 @@ describe('admin_console/team_channel_settings/channel/ChannelDetails', () => {
abacSupported: false,
};
if (!testChannel.id) {
return;
}
let wrapper = shallow(
let container;
({container} = renderWithContext(
<ChannelDetails
teamScheme={teamScheme}
groups={groups}
@@ -277,10 +180,10 @@ describe('admin_console/team_channel_settings/channel/ChannelDetails', () => {
allGroups={allGroups}
{...additionalProps}
/>,
);
expect(wrapper).toMatchSnapshot();
));
expect(container).toMatchSnapshot();
wrapper = shallow(
({container} = renderWithContext(
<ChannelDetails
teamScheme={teamScheme}
groups={groups}
@@ -292,108 +195,11 @@ describe('admin_console/team_channel_settings/channel/ChannelDetails', () => {
allGroups={allGroups}
{...additionalProps}
/>,
);
expect(wrapper).toMatchSnapshot();
));
expect(container).toMatchSnapshot();
});
test('should match snapshot for Enterprise', () => {
const groups: Group[] = [{
id: '123',
name: 'name',
display_name: 'DN',
description: 'descript',
source: 'A',
remote_id: 'id',
create_at: 0,
update_at: 0,
delete_at: 0,
has_syncables: false,
member_count: 3,
scheme_admin: false,
allow_reference: false,
}];
const allGroups = {
123: groups[0],
};
const testChannel: Channel & {team_name: string} = {
id: '123',
team_name: 'team',
create_at: 0,
update_at: 0,
delete_at: 0,
team_id: 'id_123',
type: 'O',
display_name: 'name',
name: 'DN',
header: 'header',
purpose: 'purpose',
last_post_at: 0,
last_root_post_at: 0,
creator_id: 'id',
scheme_id: 'id',
group_constrained: false,
};
const team = TestHelper.getTeamMock({
display_name: 'test',
});
const teamScheme: Scheme = {
id: 'asdf',
name: 'asdf',
description: 'asdf',
display_name: 'asdf',
create_at: 0,
update_at: 0,
delete_at: 0,
scope: 'team',
default_team_admin_role: 'asdf',
default_team_user_role: 'asdf',
default_team_guest_role: 'asdf',
default_channel_admin_role: 'asdf',
default_channel_user_role: 'asdf',
default_channel_guest_role: 'asdf',
default_playbook_admin_role: 'asdf',
default_playbook_member_role: 'asdf',
default_run_member_role: 'asdf',
};
const actions = {
getChannel: jest.fn().mockResolvedValue([]),
getTeam: jest.fn().mockResolvedValue([]),
linkGroupSyncable: jest.fn(),
conver: jest.fn(),
patchChannel: jest.fn(),
setNavigationBlocked: jest.fn(),
unlinkGroupSyncable: jest.fn(),
getGroups: jest.fn().mockResolvedValue([]),
membersMinusGroupMembers: jest.fn(),
updateChannelPrivacy: jest.fn(),
patchGroupSyncable: jest.fn(),
getChannelModerations: jest.fn().mockResolvedValue([]),
patchChannelModerations: jest.fn(),
loadScheme: jest.fn(),
addChannelMember: jest.fn(),
removeChannelMember: jest.fn(),
updateChannelMemberSchemeRoles: jest.fn(),
deleteChannel: jest.fn(),
unarchiveChannel: jest.fn(),
getAccessControlPolicy: jest.fn().mockResolvedValue({data: null}),
deleteAccessControlPolicy: jest.fn(),
assignChannelToAccessControlPolicy: jest.fn(),
unassignChannelsFromAccessControlPolicy: jest.fn(),
searchPolicies: jest.fn(),
// Channel-level access rules actions
getAccessControlFields: jest.fn().mockResolvedValue({data: []}),
getVisualAST: jest.fn().mockResolvedValue({data: {}}),
saveChannelAccessPolicy: jest.fn().mockResolvedValue({data: {}}),
validateChannelExpression: jest.fn().mockResolvedValue({data: {}}),
createAccessControlSyncJob: jest.fn().mockResolvedValue({data: {}}),
updateAccessControlPoliciesActive: jest.fn().mockResolvedValue({data: {}}),
searchUsersForExpression: jest.fn().mockResolvedValue({data: {users: [], total: 0}}),
getChannelMembers: jest.fn().mockResolvedValue({data: []}),
getProfilesByIds: jest.fn().mockResolvedValue({data: []}),
};
const additionalProps = {
channelPermissions: [],
guestAccountsEnabled: true,
@@ -403,11 +209,8 @@ describe('admin_console/team_channel_settings/channel/ChannelDetails', () => {
abacSupported: true,
};
if (!testChannel.id) {
return;
}
let wrapper = shallow(
let container;
({container} = renderWithContext(
<ChannelDetails
teamScheme={teamScheme}
groups={groups}
@@ -419,10 +222,10 @@ describe('admin_console/team_channel_settings/channel/ChannelDetails', () => {
allGroups={allGroups}
{...additionalProps}
/>,
);
expect(wrapper).toMatchSnapshot();
));
expect(container).toMatchSnapshot();
wrapper = shallow(
({container} = renderWithContext(
<ChannelDetails
teamScheme={teamScheme}
groups={groups}
@@ -434,7 +237,7 @@ describe('admin_console/team_channel_settings/channel/ChannelDetails', () => {
allGroups={allGroups}
{...additionalProps}
/>,
);
expect(wrapper).toMatchSnapshot();
));
expect(container).toMatchSnapshot();
});
});
@@ -1,12 +1,13 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {shallow} from 'enzyme';
import React from 'react';
import type {Channel} from '@mattermost/types/channels';
import type {Group} from '@mattermost/types/groups';
import {renderWithContext} from 'tests/react_testing_utils';
import {ChannelGroups} from './channel_groups';
describe('admin_console/team_channel_settings/channel/ChannelGroups', () => {
@@ -24,7 +25,7 @@ describe('admin_console/team_channel_settings/channel/ChannelGroups', () => {
group_constrained: false,
name: 'DN',
};
const wrapper = shallow(
const {container} = renderWithContext(
<ChannelGroups
synced={true}
onAddCallback={jest.fn()}
@@ -37,6 +38,6 @@ describe('admin_console/team_channel_settings/channel/ChannelGroups', () => {
isDisabled={false}
/>,
);
expect(wrapper).toMatchSnapshot();
expect(container).toMatchSnapshot();
});
});
@@ -1,454 +1,466 @@
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
exports[`admin_console/team_channel_settings/channel/ChannelMembers should match snapshot 1`] = `
<AdminPanel
button={
<ToggleModalButton
className="btn btn-primary"
dialogProps={
Object {
"channel": Object {
"create_at": 0,
"creator_id": "id",
"delete_at": 0,
"display_name": "name",
"group_constrained": false,
"header": "header",
"id": "channel-1",
"last_post_at": 0,
"last_root_post_at": 0,
"name": "DN",
"purpose": "purpose",
"scheme_id": "id",
"team_id": "team_id",
"type": "O",
"update_at": 0,
},
"channelId": "channel-1",
"excludeUsers": Object {},
"includeUsers": Object {},
"onAddCallback": [Function],
"skipCommit": true,
"teamId": "team_id",
}
}
dialogType={
Object {
"$$typeof": Symbol(react.memo),
"WrappedComponent": [Function],
"compare": null,
"type": [Function],
}
}
id="addChannelMembers"
modalId="channel_invite"
<div>
<div
class="AdminPanel clearfix "
id="channelMembers"
>
<div
class="header"
>
<Memo(MemoizedFormattedMessage)
defaultMessage="Add Members"
id="admin.team_settings.team_details.add_members"
/>
</ToggleModalButton>
}
id="channelMembers"
subtitle={
Object {
"defaultMessage": "A list of users who are currently in the channel right now",
"id": "admin.channel_settings.channel_detail.membersDescription",
}
}
title={
Object {
"defaultMessage": "Members",
"id": "admin.channel_settings.channel_detail.membersTitle",
}
}
>
<UserGrid
excludeUsers={Object {}}
filterProps={
Object {
"keys": Array [
"role",
],
"onFilter": [Function],
"options": Object {
"role": Object {
"keys": Array [
"system_guest",
"channel_user",
"channel_admin",
"system_admin",
],
"name": <Memo(MemoizedFormattedMessage)
defaultMessage="Role"
id="admin.user_grid.role"
/>,
"values": Object {
"channel_admin": Object {
"name": <Memo(MemoizedFormattedMessage)
defaultMessage="Channel Admin"
id="admin.user_grid.channel_admin"
/>,
"value": false,
},
"channel_user": Object {
"name": <Memo(MemoizedFormattedMessage)
defaultMessage="Member"
id="admin.user_item.member"
/>,
"value": false,
},
"system_admin": Object {
"name": <Memo(MemoizedFormattedMessage)
defaultMessage="System Admin"
id="admin.user_grid.system_admin"
/>,
"value": false,
},
"system_guest": Object {
"name": <Memo(MemoizedFormattedMessage)
defaultMessage="Guest"
id="admin.user_grid.guest"
/>,
"value": false,
},
},
},
},
}
}
includeUsers={Object {}}
loadPage={[Function]}
loading={true}
memberships={
Object {
"user-1": Object {
"channel_id": "channel_id",
"last_update_at": 0,
"last_viewed_at": 0,
"mention_count": 0,
"mention_count_root": 0,
"msg_count": 0,
"msg_count_root": 0,
"notify_props": Object {
"channel_auto_follow_threads": "off",
"desktop": "default",
"email": "default",
"ignore_channel_mentions": "default",
"mark_unread": "all",
"push": "default",
},
"roles": "channel_user",
"scheme_admin": false,
"scheme_user": true,
"urgent_mention_count": 0,
"user_id": "user-1",
},
"user-2": Object {
"channel_id": "channel_id",
"last_update_at": 0,
"last_viewed_at": 0,
"mention_count": 0,
"mention_count_root": 0,
"msg_count": 0,
"msg_count_root": 0,
"notify_props": Object {
"channel_auto_follow_threads": "off",
"desktop": "default",
"email": "default",
"ignore_channel_mentions": "default",
"mark_unread": "all",
"push": "default",
},
"roles": "channel_user",
"scheme_admin": false,
"scheme_user": true,
"urgent_mention_count": 0,
"user_id": "user-2",
},
"user-3": Object {
"channel_id": "channel_id",
"last_update_at": 0,
"last_viewed_at": 0,
"mention_count": 0,
"mention_count_root": 0,
"msg_count": 0,
"msg_count_root": 0,
"notify_props": Object {
"channel_auto_follow_threads": "off",
"desktop": "default",
"email": "default",
"ignore_channel_mentions": "default",
"mark_unread": "all",
"push": "default",
},
"roles": "channel_user",
"scheme_admin": false,
"scheme_user": true,
"urgent_mention_count": 0,
"user_id": "user-3",
},
}
}
onSearch={[Function]}
removeUser={[Function]}
scope="channel"
term=""
totalCount={3}
updateMembership={[Function]}
users={
Array [
Object {
"auth_service": "",
"bot_description": "",
"create_at": 0,
"delete_at": 0,
"email": "",
"first_name": "",
"id": "user-1",
"is_bot": false,
"last_activity_at": 0,
"last_name": "",
"last_password_update": 0,
"last_picture_update": 0,
"locale": "",
"mfa_active": false,
"nickname": "",
"notify_props": Object {
"calls_desktop_sound": "true",
"channel": "false",
"comments": "never",
"desktop": "default",
"desktop_sound": "false",
"email": "false",
"first_name": "false",
"highlight_keys": "",
"mark_unread": "mention",
"mention_keys": "",
"push": "none",
"push_status": "offline",
},
"password": "",
"position": "",
"props": Object {},
"roles": "",
"terms_of_service_create_at": 0,
"terms_of_service_id": "",
"update_at": 0,
"username": "some-user",
},
Object {
"auth_service": "",
"bot_description": "",
"create_at": 0,
"delete_at": 0,
"email": "",
"first_name": "",
"id": "user-2",
"is_bot": false,
"last_activity_at": 0,
"last_name": "",
"last_password_update": 0,
"last_picture_update": 0,
"locale": "",
"mfa_active": false,
"nickname": "",
"notify_props": Object {
"calls_desktop_sound": "true",
"channel": "false",
"comments": "never",
"desktop": "default",
"desktop_sound": "false",
"email": "false",
"first_name": "false",
"highlight_keys": "",
"mark_unread": "mention",
"mention_keys": "",
"push": "none",
"push_status": "offline",
},
"password": "",
"position": "",
"props": Object {},
"roles": "",
"terms_of_service_create_at": 0,
"terms_of_service_id": "",
"update_at": 0,
"username": "some-user",
},
Object {
"auth_service": "",
"bot_description": "",
"create_at": 0,
"delete_at": 0,
"email": "",
"first_name": "",
"id": "user-3",
"is_bot": false,
"last_activity_at": 0,
"last_name": "",
"last_password_update": 0,
"last_picture_update": 0,
"locale": "",
"mfa_active": false,
"nickname": "",
"notify_props": Object {
"calls_desktop_sound": "true",
"channel": "false",
"comments": "never",
"desktop": "default",
"desktop_sound": "false",
"email": "false",
"first_name": "false",
"highlight_keys": "",
"mark_unread": "mention",
"mention_keys": "",
"push": "none",
"push_status": "offline",
},
"password": "",
"position": "",
"props": Object {},
"roles": "",
"terms_of_service_create_at": 0,
"terms_of_service_id": "",
"update_at": 0,
"username": "some-user",
},
]
}
/>
</AdminPanel>
<div>
<h3>
Members
</h3>
<div
class="mt-2"
>
A list of users who are currently in the channel right now
</div>
</div>
<div
class="button"
>
<button
class="style--none btn btn-primary"
id="addChannelMembers"
>
Add Members
</button>
</div>
</div>
<div
class="DataGrid"
>
<div
class="DataGrid_search"
>
<div
class="DataGrid_searchBar"
>
<span
aria-hidden="true"
class="DataGrid_searchIcon"
>
<i
class="fa fa-search"
title="Search Icon"
/>
</span>
<input
data-testid="searchInput"
placeholder="Search"
type="text"
value=""
/>
<i
class="DataGrid_clearButton fa fa-times-circle hidden"
data-testid="clear-search"
/>
</div>
<div
class="Filter"
>
<button
class="Filter_button"
type="button"
>
<i
class="Icon icon-filter-variant"
/>
Filters
</button>
<div
class="Filter_content"
>
<div
class="Filter_header"
>
<div
class="Filter_title"
>
Filter by
</div>
<a
class="Filter_reset"
>
Reset filters
</a>
</div>
<hr />
<div
class="Filter_lists"
>
<div
class="FilterList"
>
<div
class="FilterList_name"
>
Role
</div>
<div
class="FilterList_item"
>
<div
class="FilterList_checkbox"
>
<label>
<input
id="system_guest"
name="system_guest"
type="checkbox"
/>
Guest
</label>
</div>
</div>
<div
class="FilterList_item"
>
<div
class="FilterList_checkbox"
>
<label>
<input
id="channel_user"
name="channel_user"
type="checkbox"
/>
Member
</label>
</div>
</div>
<div
class="FilterList_item"
>
<div
class="FilterList_checkbox"
>
<label>
<input
id="channel_admin"
name="channel_admin"
type="checkbox"
/>
Channel Admin
</label>
</div>
</div>
<div
class="FilterList_item"
>
<div
class="FilterList_checkbox"
>
<label>
<input
id="system_admin"
name="system_admin"
type="checkbox"
/>
System Admin
</label>
</div>
</div>
</div>
</div>
<button
class="btn btn-primary btn-sm Filter_apply"
disabled=""
type="button"
>
Apply
</button>
</div>
</div>
</div>
<div
class="DataGrid_header"
>
<div
class="DataGrid_cell"
style="flex-grow: 3;"
>
Name
</div>
<div
class="DataGrid_cell"
/>
<div
class="DataGrid_cell"
/>
</div>
<div
class="DataGrid_rows"
style="min-height: 240px;"
>
<div
class="DataGrid_loading"
>
<span
class="LoadingSpinner"
data-testid="loadingSpinner"
id="loadingSpinner"
>
<span
class="fa fa-spinner fa-fw fa-pulse spinner"
title="Loading Icon"
/>
</span>
Loading
</div>
</div>
<div
class="DataGrid_footer"
>
<div
class="DataGrid_cell"
>
1 - 3 of 3
<button
aria-label="Previous page"
class="btn btn-quaternary btn-icon btn-sm ml-2 prev disabled"
disabled=""
type="button"
>
<i
class="icon icon-chevron-left"
title="Previous Icon"
/>
</button>
<button
aria-label="Next page"
class="btn btn-quaternary btn-icon btn-sm next disabled"
disabled=""
type="button"
>
<i
class="icon icon-chevron-right"
title="Next Icon"
/>
</button>
</div>
</div>
</div>
</div>
</div>
`;
exports[`admin_console/team_channel_settings/channel/ChannelMembers should match snapshot loading no users 1`] = `
<AdminPanel
button={
<ToggleModalButton
className="btn btn-primary"
dialogProps={
Object {
"channel": Object {
"create_at": 0,
"creator_id": "id",
"delete_at": 0,
"display_name": "name",
"group_constrained": false,
"header": "header",
"id": "channel-1",
"last_post_at": 0,
"last_root_post_at": 0,
"name": "DN",
"purpose": "purpose",
"scheme_id": "id",
"team_id": "team_id",
"type": "O",
"update_at": 0,
},
"channelId": "channel-1",
"excludeUsers": Object {},
"includeUsers": Object {},
"onAddCallback": [Function],
"skipCommit": true,
"teamId": "team_id",
}
}
dialogType={
Object {
"$$typeof": Symbol(react.memo),
"WrappedComponent": [Function],
"compare": null,
"type": [Function],
}
}
id="addChannelMembers"
modalId="channel_invite"
<div>
<div
class="AdminPanel clearfix "
id="channelMembers"
>
<div
class="header"
>
<Memo(MemoizedFormattedMessage)
defaultMessage="Add Members"
id="admin.team_settings.team_details.add_members"
/>
</ToggleModalButton>
}
id="channelMembers"
subtitle={
Object {
"defaultMessage": "A list of users who are currently in the channel right now",
"id": "admin.channel_settings.channel_detail.membersDescription",
}
}
title={
Object {
"defaultMessage": "Members",
"id": "admin.channel_settings.channel_detail.membersTitle",
}
}
>
<UserGrid
excludeUsers={Object {}}
filterProps={
Object {
"keys": Array [
"role",
],
"onFilter": [Function],
"options": Object {
"role": Object {
"keys": Array [
"system_guest",
"channel_user",
"channel_admin",
"system_admin",
],
"name": <Memo(MemoizedFormattedMessage)
defaultMessage="Role"
id="admin.user_grid.role"
/>,
"values": Object {
"channel_admin": Object {
"name": <Memo(MemoizedFormattedMessage)
defaultMessage="Channel Admin"
id="admin.user_grid.channel_admin"
/>,
"value": false,
},
"channel_user": Object {
"name": <Memo(MemoizedFormattedMessage)
defaultMessage="Member"
id="admin.user_item.member"
/>,
"value": false,
},
"system_admin": Object {
"name": <Memo(MemoizedFormattedMessage)
defaultMessage="System Admin"
id="admin.user_grid.system_admin"
/>,
"value": false,
},
"system_guest": Object {
"name": <Memo(MemoizedFormattedMessage)
defaultMessage="Guest"
id="admin.user_grid.guest"
/>,
"value": false,
},
},
},
},
}
}
includeUsers={Object {}}
loadPage={[Function]}
loading={true}
memberships={Object {}}
onSearch={[Function]}
removeUser={[Function]}
scope="channel"
term=""
totalCount={0}
updateMembership={[Function]}
users={Array []}
/>
</AdminPanel>
<div>
<h3>
Members
</h3>
<div
class="mt-2"
>
A list of users who are currently in the channel right now
</div>
</div>
<div
class="button"
>
<button
class="style--none btn btn-primary"
id="addChannelMembers"
>
Add Members
</button>
</div>
</div>
<div
class="DataGrid"
>
<div
class="DataGrid_search"
>
<div
class="DataGrid_searchBar"
>
<span
aria-hidden="true"
class="DataGrid_searchIcon"
>
<i
class="fa fa-search"
title="Search Icon"
/>
</span>
<input
data-testid="searchInput"
placeholder="Search"
type="text"
value=""
/>
<i
class="DataGrid_clearButton fa fa-times-circle hidden"
data-testid="clear-search"
/>
</div>
<div
class="Filter"
>
<button
class="Filter_button"
type="button"
>
<i
class="Icon icon-filter-variant"
/>
Filters
</button>
<div
class="Filter_content"
>
<div
class="Filter_header"
>
<div
class="Filter_title"
>
Filter by
</div>
<a
class="Filter_reset"
>
Reset filters
</a>
</div>
<hr />
<div
class="Filter_lists"
>
<div
class="FilterList"
>
<div
class="FilterList_name"
>
Role
</div>
<div
class="FilterList_item"
>
<div
class="FilterList_checkbox"
>
<label>
<input
id="system_guest"
name="system_guest"
type="checkbox"
/>
Guest
</label>
</div>
</div>
<div
class="FilterList_item"
>
<div
class="FilterList_checkbox"
>
<label>
<input
id="channel_user"
name="channel_user"
type="checkbox"
/>
Member
</label>
</div>
</div>
<div
class="FilterList_item"
>
<div
class="FilterList_checkbox"
>
<label>
<input
id="channel_admin"
name="channel_admin"
type="checkbox"
/>
Channel Admin
</label>
</div>
</div>
<div
class="FilterList_item"
>
<div
class="FilterList_checkbox"
>
<label>
<input
id="system_admin"
name="system_admin"
type="checkbox"
/>
System Admin
</label>
</div>
</div>
</div>
</div>
<button
class="btn btn-primary btn-sm Filter_apply"
disabled=""
type="button"
>
Apply
</button>
</div>
</div>
</div>
<div
class="DataGrid_header"
>
<div
class="DataGrid_cell"
style="flex-grow: 3;"
>
Name
</div>
<div
class="DataGrid_cell"
/>
<div
class="DataGrid_cell"
/>
</div>
<div
class="DataGrid_rows"
style="min-height: 0px;"
>
<div
class="DataGrid_loading"
>
<span
class="LoadingSpinner"
data-testid="loadingSpinner"
id="loadingSpinner"
>
<span
class="fa fa-spinner fa-fw fa-pulse spinner"
title="Loading Icon"
/>
</span>
Loading
</div>
</div>
</div>
</div>
</div>
`;
@@ -1,12 +1,12 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {shallow} from 'enzyme';
import React from 'react';
import type {Channel, ChannelMembership} from '@mattermost/types/channels';
import type {UserProfile} from '@mattermost/types/users';
import {renderWithContext} from 'tests/react_testing_utils';
import {TestHelper} from 'utils/test_helper';
import ChannelMembers from './channel_members';
@@ -40,24 +40,24 @@ describe('admin_console/team_channel_settings/channel/ChannelMembers', () => {
searchTerm: '',
enableGuestAccounts: true,
actions: {
getChannelStats: jest.fn(),
loadProfilesAndReloadChannelMembers: jest.fn(),
searchProfilesAndChannelMembers: jest.fn(),
getFilteredUsersStats: jest.fn(),
getChannelStats: jest.fn().mockResolvedValue({}),
loadProfilesAndReloadChannelMembers: jest.fn().mockResolvedValue({}),
searchProfilesAndChannelMembers: jest.fn().mockResolvedValue({}),
getFilteredUsersStats: jest.fn().mockResolvedValue({}),
setUserGridSearch: jest.fn(),
setUserGridFilters: jest.fn(),
},
};
test('should match snapshot', () => {
const wrapper = shallow(
const {container} = renderWithContext(
<ChannelMembers {...baseProps}/>,
);
expect(wrapper).toMatchSnapshot();
expect(container).toMatchSnapshot();
});
test('should match snapshot loading no users', () => {
const wrapper = shallow(
const {container} = renderWithContext(
<ChannelMembers
{...baseProps}
users={[]}
@@ -66,6 +66,6 @@ describe('admin_console/team_channel_settings/channel/ChannelMembers', () => {
loading={true}
/>,
);
expect(wrapper).toMatchSnapshot();
expect(container).toMatchSnapshot();
});
});
@@ -1,11 +1,12 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {shallow} from 'enzyme';
import React from 'react';
import type {ChannelModeration as ChannelPermissions} from '@mattermost/types/channels';
import {renderWithContext, screen} from 'tests/react_testing_utils';
import ChannelModeration, {ChannelModerationTableRow} from './channel_moderation';
describe('admin_console/team_channel_settings/channel/ChannelModeration', () => {
@@ -26,13 +27,12 @@ describe('admin_console/team_channel_settings/channel/ChannelModeration', () =>
},
},
}];
const onChannelPermissionsChanged = () => {
jest.fn();
};
const onChannelPermissionsChanged = jest.fn();
const teamSchemeID = 'id';
const teamSchemeDisplayName = 'dp';
test('Should match first Snapshot', () => {
const wrapper = shallow(
const {container} = renderWithContext(
<ChannelModeration
channelPermissions={channelPermissions}
onChannelPermissionsChanged={onChannelPermissionsChanged}
@@ -43,24 +43,27 @@ describe('admin_console/team_channel_settings/channel/ChannelModeration', () =>
isPublic={true}
/>,
);
expect(wrapper).toMatchSnapshot();
expect(container).toMatchSnapshot();
});
test('Should match second Snapshot', () => {
const wrapper = shallow(
<ChannelModerationTableRow
key={channelPermissions[0].name}
name={channelPermissions[0].name}
guests={channelPermissions[0].roles.guests?.value}
guestsDisabled={!channelPermissions[0].roles.guests?.enabled}
members={channelPermissions[0].roles.members.value}
membersDisabled={!channelPermissions[0].roles.members.enabled}
onClick={onChannelPermissionsChanged}
errorMessages={jest.fn().mockResolvedValue([])}
guestAccountsEnabled={true}
/>,
const {container} = renderWithContext(
<table>
<tbody>
<ChannelModerationTableRow
name={channelPermissions[0].name}
guests={channelPermissions[0].roles.guests?.value}
guestsDisabled={!channelPermissions[0].roles.guests?.enabled}
members={channelPermissions[0].roles.members.value}
membersDisabled={!channelPermissions[0].roles.members.enabled}
onClick={onChannelPermissionsChanged}
errorMessages={null}
guestAccountsEnabled={true}
/>
</tbody>
</table>,
);
expect(wrapper).toMatchSnapshot();
expect(container).toMatchSnapshot();
});
test('Should match third Snapshot', () => {
@@ -100,7 +103,7 @@ describe('admin_console/team_channel_settings/channel/ChannelModeration', () =>
},
},
];
const wrapper = shallow(
const {container} = renderWithContext(
<ChannelModeration
channelPermissions={channelPermissionsCustom}
onChannelPermissionsChanged={onChannelPermissionsChanged}
@@ -111,7 +114,7 @@ describe('admin_console/team_channel_settings/channel/ChannelModeration', () =>
readOnly={false}
/>,
);
expect(wrapper).toMatchSnapshot();
expect(container).toMatchSnapshot();
});
test('Should match fourth Snapshot', () => {
@@ -151,7 +154,7 @@ describe('admin_console/team_channel_settings/channel/ChannelModeration', () =>
},
},
];
const wrapper = shallow(
const {container} = renderWithContext(
<ChannelModeration
channelPermissions={channelPermissionsCustom}
onChannelPermissionsChanged={onChannelPermissionsChanged}
@@ -162,7 +165,7 @@ describe('admin_console/team_channel_settings/channel/ChannelModeration', () =>
readOnly={false}
/>,
);
expect(wrapper).toMatchSnapshot();
expect(container).toMatchSnapshot();
});
test('Should match fifth Snapshot', () => {
@@ -202,7 +205,7 @@ describe('admin_console/team_channel_settings/channel/ChannelModeration', () =>
},
},
];
const wrapper = shallow(
const {container} = renderWithContext(
<ChannelModeration
channelPermissions={channelPermissionsCustom}
onChannelPermissionsChanged={onChannelPermissionsChanged}
@@ -213,10 +216,10 @@ describe('admin_console/team_channel_settings/channel/ChannelModeration', () =>
readOnly={false}
/>,
);
expect(wrapper).toMatchSnapshot();
expect(container).toMatchSnapshot();
});
test('Should match sixth Snapshot', () => {
test('Should match snapshot with create_post guests off and members on, private channel', () => {
const channelPermissionsCustom: ChannelPermissions[] = [
{
name: 'create_post',
@@ -253,7 +256,7 @@ describe('admin_console/team_channel_settings/channel/ChannelModeration', () =>
},
},
];
const wrapper = shallow(
const {container} = renderWithContext(
<ChannelModeration
channelPermissions={channelPermissionsCustom}
onChannelPermissionsChanged={onChannelPermissionsChanged}
@@ -264,11 +267,11 @@ describe('admin_console/team_channel_settings/channel/ChannelModeration', () =>
readOnly={false}
/>,
);
expect(wrapper).toMatchSnapshot();
expect(container).toMatchSnapshot();
});
test('Should match sixth Snapshot', () => {
const wrapper = shallow(
test('Should match snapshot with no team scheme and guest accounts disabled', () => {
const {container} = renderWithContext(
<ChannelModeration
channelPermissions={channelPermissions}
onChannelPermissionsChanged={onChannelPermissionsChanged}
@@ -279,29 +282,32 @@ describe('admin_console/team_channel_settings/channel/ChannelModeration', () =>
readOnly={false}
/>,
);
expect(wrapper).toMatchSnapshot();
expect(container).toMatchSnapshot();
});
test('Should match seventh Snapshot', () => {
const wrapper = shallow(
<ChannelModerationTableRow
key={channelPermissions[0].name}
name={channelPermissions[0].name}
guests={channelPermissions[0].roles.guests?.value}
guestsDisabled={!channelPermissions[0].roles.guests?.enabled}
members={channelPermissions[0].roles.members.value}
membersDisabled={!channelPermissions[0].roles.members.enabled}
onClick={onChannelPermissionsChanged}
errorMessages={jest.fn().mockResolvedValue([])}
guestAccountsEnabled={false}
/>,
test('Should match snapshot for ChannelModerationTableRow with guest accounts disabled', () => {
const {container} = renderWithContext(
<table>
<tbody>
<ChannelModerationTableRow
name={channelPermissions[0].name}
guests={channelPermissions[0].roles.guests?.value}
guestsDisabled={!channelPermissions[0].roles.guests?.enabled}
members={channelPermissions[0].roles.members.value}
membersDisabled={!channelPermissions[0].roles.members.enabled}
onClick={onChannelPermissionsChanged}
errorMessages={null}
guestAccountsEnabled={false}
/>
</tbody>
</table>,
);
expect(wrapper).toMatchSnapshot();
expect(container).toMatchSnapshot();
});
describe('errorMessages function', () => {
test('Should not return any error messages', () => {
const wrapper = shallow(
renderWithContext(
<ChannelModeration
channelPermissions={channelPermissions}
onChannelPermissionsChanged={onChannelPermissionsChanged}
@@ -312,28 +318,15 @@ describe('admin_console/team_channel_settings/channel/ChannelModeration', () =>
readOnly={false}
/>,
);
const instance: any = wrapper.instance();
const input: ChannelPermissions = channelPermissions[0];
const output: any = [];
const result = instance.errorMessagesToDisplay(input);
expect(result.length).toEqual(0);
expect(result).toEqual(output);
// No error messages should be present for create_post when all roles are enabled
expect(screen.queryByTestId('admin-channel_settings-channel_moderation-createPosts-disabledGuest')).not.toBeInTheDocument();
expect(screen.queryByTestId('admin-channel_settings-channel_moderation-createPosts-disabledMember')).not.toBeInTheDocument();
expect(screen.queryByTestId('admin-channel_settings-channel_moderation-createPosts-disabledBoth')).not.toBeInTheDocument();
});
test('Should return error message when create_post guests disabled', () => {
const wrapper = shallow(
<ChannelModeration
channelPermissions={channelPermissions}
onChannelPermissionsChanged={onChannelPermissionsChanged}
teamSchemeID={teamSchemeID}
teamSchemeDisplayName={teamSchemeDisplayName}
guestAccountsEnabled={true}
isPublic={false}
readOnly={false}
/>,
);
const instance: any = wrapper.instance();
const input: ChannelPermissions = {
const channelPermissionsWithGuestsDisabled: ChannelPermissions[] = [{
name: 'create_post',
roles: {
guests: {
@@ -349,25 +342,25 @@ describe('admin_console/team_channel_settings/channel/ChannelModeration', () =>
enabled: true,
},
},
};
const result = instance.errorMessagesToDisplay(input);
expect(result.length).toEqual(1);
}];
renderWithContext(
<ChannelModeration
channelPermissions={channelPermissionsWithGuestsDisabled}
onChannelPermissionsChanged={onChannelPermissionsChanged}
teamSchemeID={teamSchemeID}
teamSchemeDisplayName={teamSchemeDisplayName}
guestAccountsEnabled={true}
isPublic={false}
readOnly={false}
/>,
);
expect(screen.getByTestId('admin-channel_settings-channel_moderation-createPosts-disabledGuest')).toBeInTheDocument();
});
test('Should return error message when create_post members disabled', () => {
const wrapper = shallow(
<ChannelModeration
channelPermissions={channelPermissions}
onChannelPermissionsChanged={onChannelPermissionsChanged}
teamSchemeID={teamSchemeID}
teamSchemeDisplayName={teamSchemeDisplayName}
guestAccountsEnabled={true}
isPublic={false}
readOnly={false}
/>,
);
const instance: any = wrapper.instance();
const input: ChannelPermissions = {
const channelPermissionsWithMembersDisabled: ChannelPermissions[] = [{
name: 'create_post',
roles: {
guests: {
@@ -383,25 +376,25 @@ describe('admin_console/team_channel_settings/channel/ChannelModeration', () =>
enabled: true,
},
},
};
const result = instance.errorMessagesToDisplay(input);
expect(result.length).toEqual(1);
}];
renderWithContext(
<ChannelModeration
channelPermissions={channelPermissionsWithMembersDisabled}
onChannelPermissionsChanged={onChannelPermissionsChanged}
teamSchemeID={teamSchemeID}
teamSchemeDisplayName={teamSchemeDisplayName}
guestAccountsEnabled={true}
isPublic={false}
readOnly={false}
/>,
);
expect(screen.getByTestId('admin-channel_settings-channel_moderation-createPosts-disabledMember')).toBeInTheDocument();
});
test('Should return 1 error message when create_post members and guests disabled', () => {
const wrapper = shallow(
<ChannelModeration
channelPermissions={channelPermissions}
onChannelPermissionsChanged={onChannelPermissionsChanged}
teamSchemeID={teamSchemeID}
teamSchemeDisplayName={teamSchemeDisplayName}
guestAccountsEnabled={true}
isPublic={false}
readOnly={false}
/>,
);
const instance: any = wrapper.instance();
const input: ChannelPermissions = {
const channelPermissionsWithBothDisabled: ChannelPermissions[] = [{
name: 'create_post',
roles: {
guests: {
@@ -417,12 +410,24 @@ describe('admin_console/team_channel_settings/channel/ChannelModeration', () =>
enabled: true,
},
},
};
const result = instance.errorMessagesToDisplay(input);
expect(result.length).toEqual(1);
}];
renderWithContext(
<ChannelModeration
channelPermissions={channelPermissionsWithBothDisabled}
onChannelPermissionsChanged={onChannelPermissionsChanged}
teamSchemeID={teamSchemeID}
teamSchemeDisplayName={teamSchemeDisplayName}
guestAccountsEnabled={true}
isPublic={false}
readOnly={false}
/>,
);
expect(screen.getByTestId('admin-channel_settings-channel_moderation-createPosts-disabledBoth')).toBeInTheDocument();
});
test('Should return not error messages for use_channel_mentions', () => {
test('Should not return error messages for use_channel_mentions', () => {
const channelPermissionsCustom: ChannelPermissions[] = [
{
name: 'create_post',
@@ -459,7 +464,8 @@ describe('admin_console/team_channel_settings/channel/ChannelModeration', () =>
},
},
];
const wrapper = shallow(
renderWithContext(
<ChannelModeration
channelPermissions={channelPermissionsCustom}
onChannelPermissionsChanged={onChannelPermissionsChanged}
@@ -470,13 +476,16 @@ describe('admin_console/team_channel_settings/channel/ChannelModeration', () =>
readOnly={false}
/>,
);
const instance: any = wrapper.instance();
const input: ChannelPermissions = channelPermissionsCustom[1];
const result = instance.errorMessagesToDisplay(input);
expect(result.length).toEqual(0);
expect(screen.queryByTestId('admin-channel_settings-channel_moderation-channelMentions-disabledGuest')).not.toBeInTheDocument();
expect(screen.queryByTestId('admin-channel_settings-channel_moderation-channelMentions-disabledMember')).not.toBeInTheDocument();
expect(screen.queryByTestId('admin-channel_settings-channel_moderation-channelMentions-disabledBoth')).not.toBeInTheDocument();
expect(screen.queryByTestId('admin-channel_settings-channel_moderation-channelMentions-disabledGuestsDueToCreatePosts')).not.toBeInTheDocument();
expect(screen.queryByTestId('admin-channel_settings-channel_moderation-channelMentions-disabledMemberDueToCreatePosts')).not.toBeInTheDocument();
expect(screen.queryByTestId('admin-channel_settings-channel_moderation-channelMentions-disabledBothDueToCreatePosts')).not.toBeInTheDocument();
});
test('Should return 2 error messages for use_channel_mentions', () => {
test('Should return 2 error messages for use_channel_mentions when guests blocked by create_post and members disabled in scheme', () => {
const channelPermissionsCustom: ChannelPermissions[] = [
{
name: 'create_post',
@@ -513,7 +522,8 @@ describe('admin_console/team_channel_settings/channel/ChannelModeration', () =>
},
},
];
const wrapper = shallow(
renderWithContext(
<ChannelModeration
channelPermissions={channelPermissionsCustom}
onChannelPermissionsChanged={onChannelPermissionsChanged}
@@ -524,13 +534,15 @@ describe('admin_console/team_channel_settings/channel/ChannelModeration', () =>
readOnly={false}
/>,
);
const instance: any = wrapper.instance();
const input: ChannelPermissions = channelPermissionsCustom[1];
const result = instance.errorMessagesToDisplay(input);
expect(result.length).toEqual(2);
// Error 1: guests can't use channel mentions because create_post guests value is false
expect(screen.getByTestId('admin-channel_settings-channel_moderation-channelMentions-disabledGuestsDueToCreatePosts')).toBeInTheDocument();
// Error 2: members disabled in scheme (members.enabled=false and createPostsKey is not 'disabledMembersDueToCreatePosts')
expect(screen.getByTestId('admin-channel_settings-channel_moderation-channelMentions-disabledMember')).toBeInTheDocument();
});
test('Should return 1 error messages for use_channel_mentions', () => {
test('Should return 1 error message for use_channel_mentions when both create_post off, public channel', () => {
const channelPermissionsCustom: ChannelPermissions[] = [
{
name: 'create_post',
@@ -567,7 +579,8 @@ describe('admin_console/team_channel_settings/channel/ChannelModeration', () =>
},
},
];
const wrapper = shallow(
renderWithContext(
<ChannelModeration
channelPermissions={channelPermissionsCustom}
onChannelPermissionsChanged={onChannelPermissionsChanged}
@@ -578,13 +591,12 @@ describe('admin_console/team_channel_settings/channel/ChannelModeration', () =>
readOnly={false}
/>,
);
const instance: any = wrapper.instance();
const input: ChannelPermissions = channelPermissionsCustom[1];
const result = instance.errorMessagesToDisplay(input);
expect(result.length).toEqual(1);
// Both create_post values are false, so only disabledBothDueToCreatePosts is shown (returns early)
expect(screen.getByTestId('admin-channel_settings-channel_moderation-channelMentions-disabledBothDueToCreatePosts')).toBeInTheDocument();
});
test('Should return 2 error messages for use_channel_mentions', () => {
test('Should return 2 error messages for use_channel_mentions when members blocked by create_post and guests disabled in scheme', () => {
const channelPermissionsCustom: ChannelPermissions[] = [
{
name: 'create_post',
@@ -621,7 +633,8 @@ describe('admin_console/team_channel_settings/channel/ChannelModeration', () =>
},
},
];
const wrapper = shallow(
renderWithContext(
<ChannelModeration
channelPermissions={channelPermissionsCustom}
onChannelPermissionsChanged={onChannelPermissionsChanged}
@@ -632,13 +645,15 @@ describe('admin_console/team_channel_settings/channel/ChannelModeration', () =>
readOnly={false}
/>,
);
const instance: any = wrapper.instance();
const input: ChannelPermissions = channelPermissionsCustom[1];
const result = instance.errorMessagesToDisplay(input);
expect(result.length).toEqual(2);
// Error 1: members can't use channel mentions because create_post members value is false
expect(screen.getByTestId('admin-channel_settings-channel_moderation-channelMentions-disabledMemberDueToCreatePosts')).toBeInTheDocument();
// Error 2: guests disabled in scheme (guests.enabled=false and createPostsKey is not 'disabledGuestsDueToCreatePosts')
expect(screen.getByTestId('admin-channel_settings-channel_moderation-channelMentions-disabledGuest')).toBeInTheDocument();
});
test('Should return 1 error messages for use_channel_mention when create_posts is checked and use_channel_mentions is disabled', () => {
test('Should return 1 error message for use_channel_mention when create_posts is checked and use_channel_mentions is disabled', () => {
const channelPermissionsCustom: ChannelPermissions[] = [
{
name: 'create_post',
@@ -675,7 +690,8 @@ describe('admin_console/team_channel_settings/channel/ChannelModeration', () =>
},
},
];
const wrapper = shallow(
renderWithContext(
<ChannelModeration
channelPermissions={channelPermissionsCustom}
onChannelPermissionsChanged={onChannelPermissionsChanged}
@@ -686,10 +702,9 @@ describe('admin_console/team_channel_settings/channel/ChannelModeration', () =>
readOnly={false}
/>,
);
const instance: any = wrapper.instance();
const input: ChannelPermissions = channelPermissionsCustom[1];
const result = instance.errorMessagesToDisplay(input);
expect(result.length).toEqual(1);
// Both guests and members are disabled in scheme, and no createPosts errors, so disabledBoth is shown
expect(screen.getByTestId('admin-channel_settings-channel_moderation-channelMentions-disabledBoth')).toBeInTheDocument();
});
});
});
@@ -1,14 +1,15 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {shallow} from 'enzyme';
import React from 'react';
import {renderWithContext} from 'tests/react_testing_utils';
import {ChannelModes} from './channel_modes';
describe('admin_console/team_channel_settings/channel/ChannelModes', () => {
test('should match snapshot', () => {
const wrapper = shallow(
const {container} = renderWithContext(
<ChannelModes
onToggle={jest.fn()}
isPublic={true}
@@ -20,11 +21,11 @@ describe('admin_console/team_channel_settings/channel/ChannelModes', () => {
policyEnforcedToggleAvailable={false}
/>,
);
expect(wrapper).toMatchSnapshot();
expect(container).toMatchSnapshot();
});
test('should match snapshot - not licensed for Group', () => {
const wrapper = shallow(
const {container} = renderWithContext(
<ChannelModes
onToggle={jest.fn()}
isPublic={true}
@@ -36,6 +37,6 @@ describe('admin_console/team_channel_settings/channel/ChannelModes', () => {
policyEnforcedToggleAvailable={false}
/>,
);
expect(wrapper).toMatchSnapshot();
expect(container).toMatchSnapshot();
});
});
@@ -1,11 +1,11 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {shallow} from 'enzyme';
import React from 'react';
import type {Channel} from '@mattermost/types/channels';
import {renderWithContext} from 'tests/react_testing_utils';
import {TestHelper} from 'utils/test_helper';
import {ChannelProfile} from './channel_profile';
@@ -14,14 +14,14 @@ describe('admin_console/team_channel_settings/channel/ChannelProfile', () => {
test('should match snapshot', () => {
const testTeam = TestHelper.getTeamMock({display_name: 'test'});
const testChannel: Partial<Channel> = {display_name: 'test'};
const wrapper = shallow(
const {container} = renderWithContext(
<ChannelProfile
isArchived={false}
team={testTeam}
channel={testChannel}
/>,
);
expect(wrapper).toMatchSnapshot();
expect(container).toMatchSnapshot();
});
test('should match snapshot for a shared channel', () => {
@@ -31,13 +31,13 @@ describe('admin_console/team_channel_settings/channel/ChannelProfile', () => {
type: 'O',
shared: true,
};
const wrapper = shallow(
const {container} = renderWithContext(
<ChannelProfile
isArchived={false}
team={testTeam}
channel={testChannel}
/>,
);
expect(wrapper).toMatchSnapshot();
expect(container).toMatchSnapshot();
});
});
@@ -1,13 +1,13 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {shallow} from 'enzyme';
import React from 'react';
import type {Channel, ChannelWithTeamData} from '@mattermost/types/channels';
import {General} from 'mattermost-redux/constants';
import {renderWithContext, waitFor} from 'tests/react_testing_utils';
import {TestHelper} from 'utils/test_helper';
import ChannelList from './channel_list';
@@ -15,7 +15,7 @@ import ChannelList from './channel_list';
describe('admin_console/team_channel_settings/channel/ChannelList', () => {
const channel: Channel = Object.assign(TestHelper.getChannelMock({id: 'channel-1'}));
test('should match snapshot', () => {
test('should match snapshot', async () => {
const testChannels = [{
...channel,
id: '123',
@@ -30,18 +30,22 @@ describe('admin_console/team_channel_settings/channel/ChannelList', () => {
searchAllChannels: jest.fn().mockResolvedValue(testChannels),
};
const wrapper = shallow(
const {container} = renderWithContext(
<ChannelList
data={testChannels}
total={testChannels.length}
actions={actions}
/>);
/>,
);
wrapper.setState({loading: false});
expect(wrapper).toMatchSnapshot();
await waitFor(() => {
expect(actions.getData).toHaveBeenCalled();
});
expect(container).toMatchSnapshot();
});
test('should match snapshot with shared channel', () => {
test('should match snapshot with shared channel', async () => {
const testChannels = [{
...channel,
shared: true,
@@ -57,19 +61,23 @@ describe('admin_console/team_channel_settings/channel/ChannelList', () => {
searchAllChannels: jest.fn().mockResolvedValue(testChannels),
};
const wrapper = shallow(
const {container} = renderWithContext(
<ChannelList
data={testChannels}
total={testChannels.length}
actions={actions}
/>);
/>,
);
wrapper.setState({loading: false});
expect(wrapper).toMatchSnapshot();
await waitFor(() => {
expect(actions.getData).toHaveBeenCalled();
});
expect(container).toMatchSnapshot();
});
test('should match snapshot with paging', () => {
const testChannels = [];
test('should match snapshot with paging', async () => {
const testChannels: ChannelWithTeamData[] = [];
for (let i = 0; i < 30; i++) {
testChannels.push({
...channel,
@@ -81,21 +89,26 @@ describe('admin_console/team_channel_settings/channel/ChannelList', () => {
});
}
const actions = {
getData: jest.fn().mockResolvedValue(Promise.resolve(testChannels)),
searchAllChannels: jest.fn().mockResolvedValue(Promise.resolve(testChannels)),
getData: jest.fn().mockResolvedValue(testChannels),
searchAllChannels: jest.fn().mockResolvedValue(testChannels),
};
const wrapper = shallow(
const {container} = renderWithContext(
<ChannelList
data={testChannels}
total={30}
actions={actions}
/>);
wrapper.setState({loading: false});
expect(wrapper).toMatchSnapshot();
/>,
);
await waitFor(() => {
expect(actions.getData).toHaveBeenCalled();
});
expect(container).toMatchSnapshot();
});
test('should render correct icon for archived public channel', () => {
test('should render correct icon for archived public channel', async () => {
const archivedPublicChannel: ChannelWithTeamData[] = [{
...channel,
id: 'archived-public',
@@ -112,18 +125,22 @@ describe('admin_console/team_channel_settings/channel/ChannelList', () => {
searchAllChannels: jest.fn().mockResolvedValue(archivedPublicChannel),
};
const wrapper = shallow(
const {container} = renderWithContext(
<ChannelList
data={archivedPublicChannel}
total={1}
actions={actions}
/>);
/>,
);
wrapper.setState({loading: false});
expect(wrapper).toMatchSnapshot();
await waitFor(() => {
expect(actions.getData).toHaveBeenCalled();
});
expect(container).toMatchSnapshot();
});
test('should render correct icon for archived private channel', () => {
test('should render correct icon for archived private channel', async () => {
const archivedPrivateChannel: ChannelWithTeamData[] = [{
...channel,
id: 'archived-private',
@@ -140,14 +157,18 @@ describe('admin_console/team_channel_settings/channel/ChannelList', () => {
searchAllChannels: jest.fn().mockResolvedValue(archivedPrivateChannel),
};
const wrapper = shallow(
const {container} = renderWithContext(
<ChannelList
data={archivedPrivateChannel}
total={1}
actions={actions}
/>);
/>,
);
wrapper.setState({loading: false});
expect(wrapper).toMatchSnapshot();
await waitFor(() => {
expect(actions.getData).toHaveBeenCalled();
});
expect(container).toMatchSnapshot();
});
});
@@ -1,73 +1,135 @@
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
exports[`admin_console/team_channel_settings/group/GroupList should match snapshot while visible 1`] = `
<Modal
animation={true}
aria-labelledby="groupMemberModalLabel"
autoFocus={true}
backdrop={true}
bsClass="modal"
dialogClassName="a11y__modal settings-modal"
dialogComponentClass={[Function]}
enforceFocus={true}
id="groupMembersModal"
keyboard={true}
manager={
ModalManager {
"add": [Function],
"containers": Array [],
"data": Array [],
"handleContainerOverflow": true,
"hideSiblingNodes": true,
"isTopModal": [Function],
"modals": Array [],
"remove": [Function],
}
}
onExited={[Function]}
onHide={[Function]}
renderBackdrop={[Function]}
restoreFocus={true}
role="none"
show={true}
<body
class="modal-open"
style="padding-right: 0px;"
>
<ModalHeader
bsClass="modal-header"
closeButton={true}
closeLabel="Close"
<div
aria-hidden="true"
/>
<div
role="none"
>
<ModalTitle
bsClass="modal-title"
componentClass="h1"
id="groupMemberModalLabel"
>
group_display_name
</ModalTitle>
</ModalHeader>
<ModalBody
bsClass="modal-body"
componentClass="div"
>
<Connect(MemberListGroup)
groupID="group_id"
<div
class="fade modal-backdrop in"
/>
</ModalBody>
<ModalFooter
bsClass="modal-footer"
componentClass="div"
>
<button
autoFocus={true}
className="btn btn-primary"
id="closeModalButton"
onClick={[Function]}
type="button"
<div
aria-labelledby="groupMemberModalLabel"
class="fade in modal"
id="groupMembersModal"
role="dialog"
style="display: block; padding-right: 0px;"
tabindex="-1"
>
<MemoizedFormattedMessage
defaultMessage="Close"
id="admin.team_channel_settings.groupMembers.close"
/>
</button>
</ModalFooter>
</Modal>
<div
class="a11y__modal settings-modal modal-dialog"
>
<div
class="modal-content"
role="document"
>
<div
class="modal-header"
>
<button
aria-label="Close"
class="close"
type="button"
>
<span
aria-hidden="true"
>
×
</span>
<span
class="sr-only"
>
Close
</span>
</button>
<h1
class="modal-title"
id="groupMemberModalLabel"
>
group_display_name
</h1>
</div>
<div
class="modal-body"
>
<div
class="MemberListGroup"
>
<div
class="DataGrid"
>
<div
class="DataGrid_search"
>
<div
class="DataGrid_searchBar"
>
<span
aria-hidden="true"
class="DataGrid_searchIcon"
>
<i
class="fa fa-search"
title="Search Icon"
/>
</span>
<input
data-testid="searchInput"
placeholder="Search"
type="text"
value=""
/>
<i
class="DataGrid_clearButton fa fa-times-circle hidden"
data-testid="clear-search"
/>
</div>
</div>
<div
class="DataGrid_header"
/>
<div
class="DataGrid_rows"
>
<div
class="DataGrid_loading"
>
<span
class="LoadingSpinner"
data-testid="loadingSpinner"
id="loadingSpinner"
>
<span
class="fa fa-spinner fa-fw fa-pulse spinner"
title="Loading Icon"
/>
</span>
Loading
</div>
</div>
</div>
</div>
</div>
<div
class="modal-footer"
>
<button
class="btn btn-primary"
id="closeModalButton"
type="button"
>
Close
</button>
</div>
</div>
</div>
</div>
</div>
</body>
`;
@@ -1,106 +1,62 @@
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
exports[`admin_console/team_channel_settings/group/GroupRow should match snapshot 1`] = `
<div
className="group"
id="group"
>
<div>
<div
className="group-row"
id="group-row"
class="group"
id="group"
>
<span
className="group-name row-content"
>
DN
</span>
<span
className="group-description row-content"
>
<ToggleModalButton
className="color--link"
dialogProps={
Object {
"group": Object {
"display_name": "DN",
"id": "123",
"member_count": 3,
},
}
}
dialogType={
Object {
"$$typeof": Symbol(react.memo),
"compare": null,
"type": [Function],
}
}
id="DNMembersToggle"
modalId="group_members"
>
<MemoizedFormattedMessage
defaultMessage="{memberCount, number} {memberCount, plural, one {member} other {members}}"
id="admin.team_channel_settings.group_row.members"
values={
Object {
"memberCount": 3,
}
}
/>
</ToggleModalButton>
</span>
<div
className="group-description row-content roles"
class="group-row"
id="group-row"
>
<MenuWrapper
animationComponent={[Function]}
className=""
<span
class="group-name row-content"
>
<div>
<a
data-testid="current-role"
>
<span>
<MemoizedFormattedMessage
defaultMessage="Member"
id="admin.team_channel_settings.group_row.member"
/>
</span>
<span
className="caret"
/>
</a>
</div>
<Menu
ariaLabel="Member Role"
id="role-to-be-menu"
openLeft={true}
openUp={false}
DN
</span>
<span
class="group-description row-content"
>
<button
class="style--none color--link"
id="DNMembersToggle"
>
<MenuItemAction
id="role-to-be"
onClick={[Function]}
show={true}
text="Channel Admin"
/>
</Menu>
</MenuWrapper>
</div>
<span
className="group-actions"
id="group-actions"
>
<a
className=""
href="#"
onClick={[Function]}
3 members
</button>
</span>
<div
class="group-description row-content roles"
>
<MemoizedFormattedMessage
defaultMessage="Remove"
id="admin.team_channel_settings.group_row.remove"
/>
</a>
</span>
<div
class="MenuWrapper "
>
<div>
<a
data-testid="current-role"
>
<span>
Member
</span>
<span
class="caret"
/>
</a>
</div>
</div>
</div>
<span
class="group-actions"
id="group-actions"
>
<a
class=""
href="#"
>
Remove
</a>
</span>
</div>
</div>
</div>
`;
@@ -1,17 +1,17 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {shallow} from 'enzyme';
import React from 'react';
import type {Group} from '@mattermost/types/groups';
import {renderWithContext, waitFor} from 'tests/react_testing_utils';
import {TestHelper} from 'utils/test_helper';
import GroupList from './group_list';
describe('admin_console/team_channel_settings/group/GroupList', () => {
test('should match snapshot', () => {
test('should match snapshot', async () => {
const testGroups: Group[] = [TestHelper.getGroupMock({
id: '123',
display_name: 'DN',
@@ -22,25 +22,30 @@ describe('admin_console/team_channel_settings/group/GroupList', () => {
getData: jest.fn().mockResolvedValue(testGroups),
};
const wrapper = shallow(
const {container} = renderWithContext(
<GroupList
data={testGroups}
groups={[]}
onGroupRemoved={jest.fn()}
isModeSync={false}
totalGroups={0}
groups={testGroups}
onPageChangedCallback={jest.fn()}
total={testGroups.length}
totalGroups={testGroups.length}
actions={actions}
removeGroup={jest.fn()}
onGroupRemoved={jest.fn()}
type='team'
setNewGroupRole={jest.fn()}
/>);
isModeSync={false}
/>,
);
expect(wrapper).toMatchSnapshot();
await waitFor(() => {
expect(actions.getData).toHaveBeenCalled();
});
expect(container).toMatchSnapshot();
});
test('should match snapshot with paging', () => {
test('should match snapshot with paging', async () => {
const testGroups: Group[] = [];
for (let i = 0; i < 30; i++) {
testGroups.push(TestHelper.getGroupMock({
@@ -53,21 +58,26 @@ describe('admin_console/team_channel_settings/group/GroupList', () => {
getData: jest.fn().mockResolvedValue(Promise.resolve(testGroups)),
};
const wrapper = shallow(
const {container} = renderWithContext(
<GroupList
data={testGroups}
groups={[]}
onGroupRemoved={jest.fn()}
isModeSync={false}
totalGroups={0}
groups={testGroups}
onPageChangedCallback={jest.fn()}
total={30}
totalGroups={30}
actions={actions}
type='team'
removeGroup={jest.fn()}
onGroupRemoved={jest.fn()}
setNewGroupRole={jest.fn()}
/>);
isModeSync={false}
/>,
);
expect(wrapper).toMatchSnapshot();
await waitFor(() => {
expect(actions.getData).toHaveBeenCalled();
});
expect(container).toMatchSnapshot();
});
});
@@ -1,9 +1,9 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {shallow} from 'enzyme';
import React from 'react';
import {renderWithContext, screen} from 'tests/react_testing_utils';
import {TestHelper} from 'utils/test_helper';
import GroupMembersModal from './group_members_modal';
@@ -12,13 +12,14 @@ describe('admin_console/team_channel_settings/group/GroupList', () => {
test('should match snapshot while visible', () => {
const group = TestHelper.getGroupMock({});
const wrapper = shallow(
const {baseElement} = renderWithContext(
<GroupMembersModal
group={group}
onExited={jest.fn()}
/>,
);
expect(wrapper.find('Modal').prop('show')).toBe(true);
expect(wrapper).toMatchSnapshot();
expect(screen.getByRole('heading', {name: group.display_name})).toBeInTheDocument();
expect(baseElement).toMatchSnapshot();
});
});
@@ -1,9 +1,10 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {shallow} from 'enzyme';
import React from 'react';
import {renderWithContext} from 'tests/react_testing_utils';
import GroupRow from './group_row';
describe('admin_console/team_channel_settings/group/GroupRow', () => {
@@ -13,7 +14,7 @@ describe('admin_console/team_channel_settings/group/GroupRow', () => {
member_count: 3,
};
test('should match snapshot', () => {
const wrapper = shallow(
const {container} = renderWithContext(
<GroupRow
group={testGroup}
removeGroup={() => {}}
@@ -21,6 +22,7 @@ describe('admin_console/team_channel_settings/group/GroupRow', () => {
type='channel'
/>,
);
expect(wrapper).toMatchSnapshot();
expect(container).toMatchSnapshot();
});
});
@@ -1,49 +1,35 @@
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
exports[`components/admin_console/team_channel_settings/group/UsersToRemoveGroups should match snapshot with 0 groups 1`] = `
<div
className="UsersToRemoveGroups"
>
<MemoizedFormattedMessage
defaultMessage="{amount, number} {amount, plural, one {Group} other {Groups}}"
id="team_channel_settings.group.group_user_row.numberOfGroups"
values={
Object {
"amount": 0,
}
}
/>
<div>
<div
class="UsersToRemoveGroups"
>
0 Groups
</div>
</div>
`;
exports[`components/admin_console/team_channel_settings/group/UsersToRemoveGroups should match snapshot with 1 group 1`] = `
<div
className="UsersToRemoveGroups"
>
group1
<div>
<div
class="UsersToRemoveGroups"
>
group1
</div>
</div>
`;
exports[`components/admin_console/team_channel_settings/group/UsersToRemoveGroups should match snapshot with 3 groups 1`] = `
<div
className="UsersToRemoveGroups"
>
<WithTooltip
title="group1, group2, group3"
<div>
<div
class="UsersToRemoveGroups"
>
<a
href="#"
>
<MemoizedFormattedMessage
defaultMessage="{amount, number} {amount, plural, one {Group} other {Groups}}"
id="team_channel_settings.group.group_user_row.numberOfGroups"
values={
Object {
"amount": 3,
}
}
/>
3 Groups
</a>
</WithTooltip>
</div>
</div>
`;
@@ -1,37 +1,18 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {shallow} from 'enzyme';
import React from 'react';
import type {TeamMembership} from '@mattermost/types/teams';
import type {UserProfile} from '@mattermost/types/users';
import {renderWithContext, waitFor} from 'tests/react_testing_utils';
import {TestHelper} from 'utils/test_helper';
import UsersToRemove from './users_to_remove';
describe('components/admin_console/team_channel_settings/group/UsersToRemove', () => {
function createUser(id: string, username: string, bot: boolean): UserProfile {
return TestHelper.getUserMock({
id,
username,
is_bot: bot,
});
}
function createMembership(userId: string, admin: boolean): TeamMembership {
return TestHelper.getTeamMembershipMock({
user_id: userId,
roles: admin ? 'team_user team_admin' : 'team_user',
scheme_admin: admin,
});
}
const user1 = createUser('userid1', 'user-1', false);
const membership1 = createMembership('userId1', false);
const user2 = createUser('userid2', 'user-2', false);
const membership2 = createMembership('userId2', true);
const user1 = TestHelper.getUserMock({id: 'userid1', username: 'user-1', is_bot: false});
const membership1 = TestHelper.getTeamMembershipMock({user_id: 'userid1', roles: 'team_user', scheme_admin: false});
const user2 = TestHelper.getUserMock({id: 'userid2', username: 'user-2', is_bot: false});
const membership2 = TestHelper.getTeamMembershipMock({user_id: 'userid2', roles: 'team_user team_admin', scheme_admin: true});
const scope: 'team' | 'channel' = 'team';
const baseProps = {
members: [user1, user2],
@@ -44,40 +25,58 @@ describe('components/admin_console/team_channel_settings/group/UsersToRemove', (
filters: {},
actions: {
loadTeamMembersForProfilesList: jest.fn(),
loadChannelMembersForProfilesList: jest.fn(),
loadTeamMembersForProfilesList: jest.fn().mockResolvedValue({}),
loadChannelMembersForProfilesList: jest.fn().mockResolvedValue({}),
setModalSearchTerm: jest.fn(),
setModalFilters: jest.fn(),
},
};
test('should match snapshot with 2 users', () => {
const wrapper = shallow(
test('should match snapshot with 2 users', async () => {
const {container} = renderWithContext(
<UsersToRemove
{...baseProps}
/>,
);
expect(wrapper).toMatchSnapshot();
await waitFor(() => {
expect(container.querySelector('.DataGrid_loading')).not.toBeInTheDocument();
});
expect(container).toMatchSnapshot();
});
test('should match snapshot with guests disabled', () => {
const wrapper = shallow(
test('should match snapshot with guests disabled', async () => {
const {container} = renderWithContext(
<UsersToRemove
{...baseProps}
enableGuestAccounts={false}
/>,
);
expect(wrapper).toMatchSnapshot();
await waitFor(() => {
expect(container.querySelector('.DataGrid_loading')).not.toBeInTheDocument();
});
expect(container).toMatchSnapshot();
});
test('should match snapshot loading', () => {
const wrapper = shallow(
const props = {
...baseProps,
actions: {
...baseProps.actions,
loadTeamMembersForProfilesList: jest.fn().mockReturnValue(new Promise(() => {})),
loadChannelMembersForProfilesList: jest.fn().mockReturnValue(new Promise(() => {})),
},
};
const {container} = renderWithContext(
<UsersToRemove
{...baseProps}
{...props}
/>,
);
wrapper.setState({loading: true});
expect(wrapper).toMatchSnapshot();
expect(container).toMatchSnapshot();
});
});
@@ -1,12 +1,12 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {shallow} from 'enzyme';
import React from 'react';
import type {Group} from '@mattermost/types/groups';
import type {UserProfile} from '@mattermost/types/users';
import {renderWithContext} from 'tests/react_testing_utils';
import {TestHelper} from 'utils/test_helper';
import UsersToRemoveGroups from './users_to_remove_groups';
@@ -25,29 +25,32 @@ describe('components/admin_console/team_channel_settings/group/UsersToRemoveGrou
const group3 = TestHelper.getGroupMock({id: 'group3', display_name: 'group3'});
test('should match snapshot with 0 groups', () => {
const wrapper = shallow(
const {container} = renderWithContext(
<UsersToRemoveGroups
user={userWithGroups(user, [])}
/>,
);
expect(wrapper).toMatchSnapshot();
expect(container).toMatchSnapshot();
});
test('should match snapshot with 1 group', () => {
const wrapper = shallow(
const {container} = renderWithContext(
<UsersToRemoveGroups
user={userWithGroups(user, [group1])}
/>,
);
expect(wrapper).toMatchSnapshot();
expect(container).toMatchSnapshot();
});
test('should match snapshot with 3 groups', () => {
const wrapper = shallow(
const {container} = renderWithContext(
<UsersToRemoveGroups
user={userWithGroups(user, [group1, group2, group3])}
/>,
);
expect(wrapper).toMatchSnapshot();
expect(container).toMatchSnapshot();
});
});
@@ -1,43 +1,44 @@
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
exports[`admin_console/team_channel_settings/team/TeamSettings should match snapshot 1`] = `
<div
className="wrapper--fixed"
>
<AdminHeader>
<MemoizedFormattedMessage
defaultMessage="{siteName} Teams"
id="admin.team_settings.groupsPageTitle"
values={
Object {
"siteName": "site",
}
}
/>
</AdminHeader>
<div>
<div
className="admin-console__wrapper"
class="wrapper--fixed"
>
<div
className="admin-console__content"
class="admin-console__header"
>
<AdminPanel
id="teams"
subtitle={
Object {
"defaultMessage": "Manage team settings.",
"id": "admin.team_settings.description",
}
}
title={
Object {
"defaultMessage": "Teams",
"id": "admin.team_settings.title",
}
}
site Teams
</div>
<div
class="admin-console__wrapper"
>
<div
class="admin-console__content"
>
<Connect(TeamList) />
</AdminPanel>
<div
class="AdminPanel clearfix "
id="teams"
>
<div
class="header"
>
<div>
<h3>
Teams
</h3>
<div
class="mt-2"
>
Manage team settings.
</div>
</div>
</div>
<div>
TeamList
</div>
</div>
</div>
</div>
</div>
</div>
@@ -1,187 +1,243 @@
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
exports[`admin_console/team_channel_settings/team/TeamDetails should match snapshot 1`] = `
<div
className="wrapper--fixed"
>
<AdminHeader
withBackButton={true}
>
<div>
<Connect(Component)
className="fa fa-angle-left back"
to="/admin_console/user_management/teams"
/>
<MemoizedFormattedMessage
defaultMessage="Team Configuration"
id="admin.team_settings.team_detail.group_configuration"
/>
</div>
</AdminHeader>
<div>
<div
className="admin-console__wrapper"
class="wrapper--fixed"
>
<div
className="admin-console__content"
class="admin-console__header with-back"
>
<TeamProfile
isArchived={false}
onToggleArchive={[Function]}
saveNeeded={false}
team={
Object {
"allow_open_invite": false,
"allowed_domains": "",
"company_name": "",
"create_at": 0,
"delete_at": 0,
"description": "",
"display_name": "team",
"email": "",
"group_constrained": false,
"id": "123",
"invite_id": "",
"name": "DN",
"scheme_id": "id",
"type": "O",
"update_at": 0,
}
}
/>
<Memo(ConfirmModal)
confirmButtonText={
<Memo(MemoizedFormattedMessage)
defaultMessage="Archive"
id="admin.team_settings.team_detail.archive_confirm.button"
/>
}
message={
<Memo(MemoizedFormattedMessage)
defaultMessage="Archiving will remove the team from the user interface but it's contents remain in the database and may still be accessible with the API. Are you sure you wish to save and archive this team?"
id="admin.team_settings.team_detail.archive_confirm.message"
/>
}
onCancel={[Function]}
onConfirm={[Function]}
show={false}
title={
<Memo(MemoizedFormattedMessage)
defaultMessage="Save and Archive Team"
id="admin.team_settings.team_detail.archive_confirm.title"
/>
}
/>
<RemoveConfirmModal
amount={0}
inChannel={false}
onCancel={[Function]}
onConfirm={[Function]}
show={false}
/>
<TeamModes
allAllowedChecked={false}
allowedDomains=""
allowedDomainsChecked={false}
onToggle={[Function]}
syncChecked={false}
/>
<Connect(TeamMembers)
onAddCallback={[Function]}
onRemoveCallback={[Function]}
teamId="123"
updateRole={[Function]}
usersToAdd={Object {}}
usersToRemove={Object {}}
<div>
<a
class="fa fa-angle-left back"
href="/admin_console/user_management/teams"
/>
Team Configuration
</div>
</div>
<div
class="admin-console__wrapper"
>
<div
class="admin-console__content"
>
<div>
TeamProfile
</div>
<div
class="AdminPanel clearfix "
id="team_manage"
>
<div
class="header"
>
<div>
<h3>
Team Management
</h3>
<div
class="mt-2"
>
Choose between inviting members manually or syncing members automatically from groups.
</div>
</div>
</div>
<div
class="group-teams-and-channels"
>
<div
class="group-teams-and-channels--body"
>
<div>
<div
class="line-switch d-flex flex-sm-column flex-md-row align-items-sm-start align-items-center"
>
<label
class="line-switch__label"
>
Anyone can join this team
</label>
<div
class="line-switch__toggle"
data-testid="allowAllToggleSwitch"
>
<button
aria-pressed="false"
class="btn btn-lg btn-toggle"
data-testid="allowAllToggleSwitch-button"
id="allowAllToggleSwitch"
tabindex="0"
type="button"
>
<div
class="handle"
/>
</button>
</div>
</div>
<div
class="row"
>
<div
class="col-sm-10"
>
<div
class="help-text-small help-text-no-padding help-text-single-line"
>
This team can be discovered allowing anyone with an account to join this team.
</div>
</div>
</div>
<div
class="section-separator"
>
<hr
class="separator__hr"
/>
</div>
</div>
<div>
<div
class="line-switch d-flex flex-sm-column flex-md-row align-items-sm-start align-items-center"
>
<label
class="line-switch__label"
>
Only specific email domains can join this team
</label>
<div
class="line-switch__toggle"
data-testid="allowedDomainsToggleSwitch"
>
<button
aria-pressed="false"
class="btn btn-lg btn-toggle"
data-testid="allowedDomainsToggleSwitch-button"
id="allowedDomainsToggleSwitch"
tabindex="0"
type="button"
>
<div
class="handle"
/>
</button>
</div>
</div>
<div
class="row"
>
<div
class="col-sm-10"
>
<div
class="help-text-small help-text-no-padding help-text-single-line"
>
Users can only join the team if their email matches one of the specified domains
</div>
</div>
</div>
<div
class="help-text csvDomains"
>
Comma Separated Email Domain List
</div>
<input
class="form-control"
placeholder="mattermost.com"
type="text"
value=""
/>
</div>
</div>
</div>
</div>
<div>
TeamMembers
</div>
</div>
</div>
<div
class="admin-console-save"
>
<button
class="btn btn-primary"
data-testid="saveSetting"
disabled=""
id="saveSetting"
type="submit"
>
<span>
Save
</span>
</button>
<a
class="btn btn-quaternary"
href="/admin_console/user_management/teams"
id="cancelButtonSettings"
>
Cancel
</a>
<div
class="error-message"
/>
</div>
</div>
<SaveChangesPanel
cancelLink="/admin_console/user_management/teams"
onClick={[Function]}
saveNeeded={false}
saving={false}
/>
</div>
`;
exports[`admin_console/team_channel_settings/team/TeamDetails should match snapshot with isLocalArchived true 1`] = `
<div
className="wrapper--fixed"
>
<AdminHeader
withBackButton={true}
>
<div>
<Connect(Component)
className="fa fa-angle-left back"
to="/admin_console/user_management/teams"
/>
<MemoizedFormattedMessage
defaultMessage="Team Configuration"
id="admin.team_settings.team_detail.group_configuration"
/>
</div>
</AdminHeader>
<div>
<div
className="admin-console__wrapper"
class="wrapper--fixed"
>
<div
className="admin-console__content"
class="admin-console__header with-back"
>
<TeamProfile
isArchived={true}
onToggleArchive={[Function]}
saveNeeded={false}
team={
Object {
"allow_open_invite": false,
"allowed_domains": "",
"company_name": "",
"create_at": 0,
"delete_at": 16465313,
"description": "",
"display_name": "team",
"email": "",
"group_constrained": false,
"id": "123",
"invite_id": "",
"name": "DN",
"scheme_id": "id",
"type": "O",
"update_at": 0,
}
}
/>
<Memo(ConfirmModal)
confirmButtonText={
<Memo(MemoizedFormattedMessage)
defaultMessage="Archive"
id="admin.team_settings.team_detail.archive_confirm.button"
/>
}
message={
<Memo(MemoizedFormattedMessage)
defaultMessage="Archiving will remove the team from the user interface but it's contents remain in the database and may still be accessible with the API. Are you sure you wish to save and archive this team?"
id="admin.team_settings.team_detail.archive_confirm.message"
/>
}
onCancel={[Function]}
onConfirm={[Function]}
show={false}
title={
<Memo(MemoizedFormattedMessage)
defaultMessage="Save and Archive Team"
id="admin.team_settings.team_detail.archive_confirm.title"
/>
}
<div>
<a
class="fa fa-angle-left back"
href="/admin_console/user_management/teams"
/>
Team Configuration
</div>
</div>
<div
class="admin-console__wrapper"
>
<div
class="admin-console__content"
>
<div>
TeamProfile
</div>
</div>
</div>
<div
class="admin-console-save"
>
<button
class="btn btn-primary"
data-testid="saveSetting"
disabled=""
id="saveSetting"
type="submit"
>
<span>
Save
</span>
</button>
<a
class="btn btn-quaternary"
href="/admin_console/user_management/teams"
id="cancelButtonSettings"
>
Cancel
</a>
<div
class="error-message"
/>
</div>
</div>
<SaveChangesPanel
cancelLink="/admin_console/user_management/teams"
onClick={[Function]}
saveNeeded={false}
saving={false}
/>
</div>
`;
@@ -1,126 +1,107 @@
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
exports[`admin_console/team_channel_settings/team/TeamGroups should match snapshot 1`] = `
<AdminPanel
button={
<ToggleModalButton
className="btn btn-primary"
dialogProps={
Object {
"excludeGroups": Array [
Object {
"allow_reference": true,
"create_at": 1,
"delete_at": 0,
"description": "",
"display_name": "DN",
"has_syncables": false,
"id": "123",
"member_count": 3,
"name": "group_name",
"remote_id": "",
"scheme_admin": false,
"source": "",
"update_at": 1,
},
],
"includeGroups": Array [],
"onAddCallback": [MockFunction],
"skipCommit": true,
"team": Object {
"allow_open_invite": false,
"allowed_domains": "",
"company_name": "",
"create_at": 0,
"delete_at": 0,
"description": "",
"display_name": "team",
"email": "",
"group_constrained": false,
"id": "123",
"invite_id": "",
"name": "DN",
"scheme_id": "id",
"type": "O",
"update_at": 0,
},
}
}
dialogType={
Object {
"$$typeof": Symbol(react.memo),
"WrappedComponent": [Function],
"compare": null,
"type": [Function],
}
}
id="addGroupsToTeamToggle"
modalId="add_groups_to_team"
<div>
<div
class="AdminPanel clearfix "
id="team_groups"
>
<div
class="header"
>
<Memo(MemoizedFormattedMessage)
defaultMessage="Add Group"
id="admin.team_settings.team_details.add_group"
/>
</ToggleModalButton>
}
id="team_groups"
subtitle={
Object {
"defaultMessage": "Add and remove team members based on their group membership.",
"id": "admin.team_settings.team_detail.syncedGroupsDescription",
}
}
title={
Object {
"defaultMessage": "Synced Groups",
"id": "admin.team_settings.team_detail.syncedGroupsTitle",
}
}
>
<Connect(Component)
groups={
Array [
Object {
"allow_reference": true,
"create_at": 1,
"delete_at": 0,
"description": "",
"display_name": "DN",
"has_syncables": false,
"id": "123",
"member_count": 3,
"name": "group_name",
"remote_id": "",
"scheme_admin": false,
"source": "",
"update_at": 1,
},
]
}
isModeSync={true}
onGroupRemoved={[MockFunction]}
setNewGroupRole={[MockFunction]}
team={
Object {
"allow_open_invite": false,
"allowed_domains": "",
"company_name": "",
"create_at": 0,
"delete_at": 0,
"description": "",
"display_name": "team",
"email": "",
"group_constrained": false,
"id": "123",
"invite_id": "",
"name": "DN",
"scheme_id": "id",
"type": "O",
"update_at": 0,
}
}
totalGroups={1}
type="team"
/>
</AdminPanel>
<div>
<h3>
Synced Groups
</h3>
<div
class="mt-2"
>
Add and remove team members based on their group membership.
</div>
</div>
<div
class="button"
>
<button
class="style--none btn btn-primary"
id="addGroupsToTeamToggle"
>
Add Group
</button>
</div>
</div>
<div
class="groups-list groups-list-no-padding"
>
<div
class="groups-list--header"
>
<div
class="group-name group-name-adjusted"
>
Group Name
</div>
<div
class="group-content"
>
<div
class="group-description group-description-adjusted"
>
Member Count
</div>
<div
class="group-description group-description-adjusted"
>
Roles
</div>
<div
class="group-actions"
/>
</div>
</div>
<div
class="groups-list--body"
id="groups-list--body"
>
<div
class="groups-list-loading"
>
<i
class="fa fa-spinner fa-pulse fa-2x"
/>
</div>
</div>
<div
class="groups-list--footer"
>
<div
class="counter"
>
1 - 1 of 1
</div>
<button
class="btn btn-tertiary prev disabled"
disabled=""
type="button"
>
<i
class="icon icon-chevron-left"
title="Previous Icon"
/>
</button>
<button
class="btn btn-tertiary next disabled"
data-testid="page-link-next"
disabled=""
type="button"
>
<i
class="icon icon-chevron-right"
title="Next Icon"
/>
</button>
</div>
</div>
</div>
</div>
`;
@@ -1,42 +1,133 @@
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
exports[`admin_console/team_channel_settings/team/TeamModes should match snapshot 1`] = `
<AdminPanel
id="team_manage"
subtitle={
Object {
"defaultMessage": "Choose between inviting members manually or syncing members automatically from groups.",
"id": "admin.team_settings.team_detail.manageDescription",
}
}
title={
Object {
"defaultMessage": "Team Management",
"id": "admin.team_settings.team_detail.manageTitle",
}
}
>
<div>
<div
className="group-teams-and-channels"
class="AdminPanel clearfix "
id="team_manage"
>
<div
className="group-teams-and-channels--body"
class="header"
>
<AllowAllToggle
allAllowedChecked={false}
allowedDomains=""
allowedDomainsChecked={true}
onToggle={[MockFunction]}
syncChecked={false}
/>
<AllowedDomainsToggle
allAllowedChecked={false}
allowedDomains=""
allowedDomainsChecked={true}
onToggle={[MockFunction]}
syncChecked={false}
/>
<div>
<h3>
Team Management
</h3>
<div
class="mt-2"
>
Choose between inviting members manually or syncing members automatically from groups.
</div>
</div>
</div>
<div
class="group-teams-and-channels"
>
<div
class="group-teams-and-channels--body"
>
<div>
<div
class="line-switch d-flex flex-sm-column flex-md-row align-items-sm-start align-items-center"
>
<label
class="line-switch__label"
>
Anyone can join this team
</label>
<div
class="line-switch__toggle"
data-testid="allowAllToggleSwitch"
>
<button
aria-pressed="false"
class="btn btn-lg btn-toggle"
data-testid="allowAllToggleSwitch-button"
id="allowAllToggleSwitch"
tabindex="0"
type="button"
>
<div
class="handle"
/>
</button>
</div>
</div>
<div
class="row"
>
<div
class="col-sm-10"
>
<div
class="help-text-small help-text-no-padding help-text-single-line"
>
This team can be discovered allowing anyone with an account to join this team.
</div>
</div>
</div>
<div
class="section-separator"
>
<hr
class="separator__hr"
/>
</div>
</div>
<div>
<div
class="line-switch d-flex flex-sm-column flex-md-row align-items-sm-start align-items-center"
>
<label
class="line-switch__label"
>
Only specific email domains can join this team
</label>
<div
class="line-switch__toggle"
data-testid="allowedDomainsToggleSwitch"
>
<button
aria-pressed="true"
class="btn btn-lg btn-toggle active"
data-testid="allowedDomainsToggleSwitch-button"
id="allowedDomainsToggleSwitch"
tabindex="0"
type="button"
>
<div
class="handle"
/>
</button>
</div>
</div>
<div
class="row"
>
<div
class="col-sm-10"
>
<div
class="help-text-small help-text-no-padding help-text-single-line"
>
Users can only join the team if their email matches one of the specified domains
</div>
</div>
</div>
<div
class="help-text csvDomains"
>
Comma Separated Email Domain List
</div>
<input
class="form-control"
placeholder="mattermost.com"
type="text"
value=""
/>
</div>
</div>
</div>
</div>
</AdminPanel>
</div>
`;
@@ -1,13 +1,21 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {shallow} from 'enzyme';
import React from 'react';
import {renderWithContext} from 'tests/react_testing_utils';
import {TestHelper} from 'utils/test_helper';
import TeamDetails from './team_details';
jest.mock('./team_members/index', () => {
return () => <div>{'TeamMembers'}</div>;
});
jest.mock('./team_profile', () => ({
TeamProfile: () => <div>{'TeamProfile'}</div>,
}));
describe('admin_console/team_channel_settings/team/TeamDetails', () => {
const groups = [TestHelper.getGroupMock({
id: '123',
@@ -50,12 +58,12 @@ describe('admin_console/team_channel_settings/team/TeamDetails', () => {
};
test('should match snapshot', () => {
const wrapper = shallow(
const {container} = renderWithContext(
<TeamDetails
{...baseProps}
/>,
);
expect(wrapper).toMatchSnapshot();
expect(container).toMatchSnapshot();
});
test('should match snapshot with isLocalArchived true', () => {
@@ -66,11 +74,11 @@ describe('admin_console/team_channel_settings/team/TeamDetails', () => {
delete_at: 16465313,
},
};
const wrapper = shallow(
const {container} = renderWithContext(
<TeamDetails
{...props}
/>,
);
expect(wrapper).toMatchSnapshot();
expect(container).toMatchSnapshot();
});
});
@@ -1,9 +1,9 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {shallow} from 'enzyme';
import React from 'react';
import {renderWithContext} from 'tests/react_testing_utils';
import {TestHelper} from 'utils/test_helper';
import {TeamGroups} from './team_groups';
@@ -23,7 +23,7 @@ describe('admin_console/team_channel_settings/team/TeamGroups', () => {
group_constrained: false,
display_name: 'team',
});
const wrapper = shallow(
const {container} = renderWithContext(
<TeamGroups
syncChecked={true}
onAddCallback={jest.fn()}
@@ -35,6 +35,6 @@ describe('admin_console/team_channel_settings/team/TeamGroups', () => {
totalGroups={1}
/>,
);
expect(wrapper).toMatchSnapshot();
expect(container).toMatchSnapshot();
});
});
@@ -1,425 +1,466 @@
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
exports[`admin_console/team_channel_settings/team/TeamMembers should match snapshot 1`] = `
<AdminPanel
button={
<ToggleModalButton
className="btn btn-primary"
dialogProps={
Object {
"excludeUsers": Object {},
"filterExcludeGuests": true,
"includeUsers": Object {},
"onAddCallback": [Function],
"skipCommit": true,
"team": Object {
"allow_open_invite": false,
"allowed_domains": "",
"company_name": "",
"create_at": 0,
"delete_at": 0,
"description": "",
"display_name": "name",
"email": "",
"group_constrained": false,
"id": "team-1",
"invite_id": "",
"name": "DN",
"scheme_id": "id",
"type": "O",
"update_at": 0,
},
}
}
dialogType={
Object {
"$$typeof": Symbol(react.memo),
"WrappedComponent": [Function],
"compare": null,
"type": [Function],
}
}
id="addTeamMembers"
modalId="add_user_to_team"
<div>
<div
class="AdminPanel clearfix "
id="teamMembers"
>
<div
class="header"
>
<Memo(MemoizedFormattedMessage)
defaultMessage="Add Members"
id="admin.team_settings.team_details.add_members"
/>
</ToggleModalButton>
}
id="teamMembers"
subtitle={
Object {
"defaultMessage": "A list of users who are currently in the team right now",
"id": "admin.team_settings.team_detail.membersDescription",
}
}
title={
Object {
"defaultMessage": "Members",
"id": "admin.team_settings.team_detail.membersTitle",
}
}
>
<UserGrid
excludeUsers={Object {}}
filterProps={
Object {
"keys": Array [
"role",
],
"onFilter": [Function],
"options": Object {
"role": Object {
"keys": Array [
"system_guest",
"team_user",
"team_admin",
"system_admin",
],
"name": <Memo(MemoizedFormattedMessage)
defaultMessage="Role"
id="admin.user_grid.role"
/>,
"values": Object {
"system_admin": Object {
"name": <Memo(MemoizedFormattedMessage)
defaultMessage="System Admin"
id="admin.user_grid.system_admin"
/>,
"value": false,
},
"system_guest": Object {
"name": <Memo(MemoizedFormattedMessage)
defaultMessage="Guest"
id="admin.user_grid.guest"
/>,
"value": false,
},
"team_admin": Object {
"name": <Memo(MemoizedFormattedMessage)
defaultMessage="Team Admin"
id="admin.user_grid.team_admin"
/>,
"value": false,
},
"team_user": Object {
"name": <Memo(MemoizedFormattedMessage)
defaultMessage="Member"
id="admin.user_item.member"
/>,
"value": false,
},
},
},
},
}
}
includeUsers={Object {}}
loadPage={[Function]}
loading={true}
memberships={
Object {
"user-1": Object {
"delete_at": 0,
"mention_count": 0,
"mention_count_root": 0,
"msg_count": 0,
"msg_count_root": 0,
"roles": "team_user",
"scheme_admin": false,
"scheme_guest": false,
"scheme_user": true,
"team_id": "team_id",
"user_id": "user-1",
},
"user-2": Object {
"delete_at": 0,
"mention_count": 0,
"mention_count_root": 0,
"msg_count": 0,
"msg_count_root": 0,
"roles": "team_user",
"scheme_admin": false,
"scheme_guest": false,
"scheme_user": true,
"team_id": "team_id",
"user_id": "user-2",
},
"user-3": Object {
"delete_at": 0,
"mention_count": 0,
"mention_count_root": 0,
"msg_count": 0,
"msg_count_root": 0,
"roles": "team_user",
"scheme_admin": false,
"scheme_guest": false,
"scheme_user": true,
"team_id": "team_id",
"user_id": "user-3",
},
}
}
onSearch={[Function]}
removeUser={[Function]}
scope="team"
term=""
totalCount={3}
updateMembership={[Function]}
users={
Array [
Object {
"auth_service": "",
"bot_description": "",
"create_at": 0,
"delete_at": 0,
"email": "",
"first_name": "",
"id": "user-1",
"is_bot": false,
"last_activity_at": 0,
"last_name": "",
"last_password_update": 0,
"last_picture_update": 0,
"locale": "",
"mfa_active": false,
"nickname": "",
"notify_props": Object {
"calls_desktop_sound": "true",
"channel": "false",
"comments": "never",
"desktop": "default",
"desktop_sound": "false",
"email": "false",
"first_name": "false",
"highlight_keys": "",
"mark_unread": "mention",
"mention_keys": "",
"push": "none",
"push_status": "offline",
},
"password": "",
"position": "",
"props": Object {},
"roles": "",
"terms_of_service_create_at": 0,
"terms_of_service_id": "",
"update_at": 0,
"username": "some-user",
},
Object {
"auth_service": "",
"bot_description": "",
"create_at": 0,
"delete_at": 0,
"email": "",
"first_name": "",
"id": "user-2",
"is_bot": false,
"last_activity_at": 0,
"last_name": "",
"last_password_update": 0,
"last_picture_update": 0,
"locale": "",
"mfa_active": false,
"nickname": "",
"notify_props": Object {
"calls_desktop_sound": "true",
"channel": "false",
"comments": "never",
"desktop": "default",
"desktop_sound": "false",
"email": "false",
"first_name": "false",
"highlight_keys": "",
"mark_unread": "mention",
"mention_keys": "",
"push": "none",
"push_status": "offline",
},
"password": "",
"position": "",
"props": Object {},
"roles": "",
"terms_of_service_create_at": 0,
"terms_of_service_id": "",
"update_at": 0,
"username": "some-user",
},
Object {
"auth_service": "",
"bot_description": "",
"create_at": 0,
"delete_at": 0,
"email": "",
"first_name": "",
"id": "user-3",
"is_bot": false,
"last_activity_at": 0,
"last_name": "",
"last_password_update": 0,
"last_picture_update": 0,
"locale": "",
"mfa_active": false,
"nickname": "",
"notify_props": Object {
"calls_desktop_sound": "true",
"channel": "false",
"comments": "never",
"desktop": "default",
"desktop_sound": "false",
"email": "false",
"first_name": "false",
"highlight_keys": "",
"mark_unread": "mention",
"mention_keys": "",
"push": "none",
"push_status": "offline",
},
"password": "",
"position": "",
"props": Object {},
"roles": "",
"terms_of_service_create_at": 0,
"terms_of_service_id": "",
"update_at": 0,
"username": "some-user",
},
]
}
/>
</AdminPanel>
<div>
<h3>
Members
</h3>
<div
class="mt-2"
>
A list of users who are currently in the team right now
</div>
</div>
<div
class="button"
>
<button
class="style--none btn btn-primary"
id="addTeamMembers"
>
Add Members
</button>
</div>
</div>
<div
class="DataGrid"
>
<div
class="DataGrid_search"
>
<div
class="DataGrid_searchBar"
>
<span
aria-hidden="true"
class="DataGrid_searchIcon"
>
<i
class="fa fa-search"
title="Search Icon"
/>
</span>
<input
data-testid="searchInput"
placeholder="Search"
type="text"
value=""
/>
<i
class="DataGrid_clearButton fa fa-times-circle hidden"
data-testid="clear-search"
/>
</div>
<div
class="Filter"
>
<button
class="Filter_button"
type="button"
>
<i
class="Icon icon-filter-variant"
/>
Filters
</button>
<div
class="Filter_content"
>
<div
class="Filter_header"
>
<div
class="Filter_title"
>
Filter by
</div>
<a
class="Filter_reset"
>
Reset filters
</a>
</div>
<hr />
<div
class="Filter_lists"
>
<div
class="FilterList"
>
<div
class="FilterList_name"
>
Role
</div>
<div
class="FilterList_item"
>
<div
class="FilterList_checkbox"
>
<label>
<input
id="system_guest"
name="system_guest"
type="checkbox"
/>
Guest
</label>
</div>
</div>
<div
class="FilterList_item"
>
<div
class="FilterList_checkbox"
>
<label>
<input
id="team_user"
name="team_user"
type="checkbox"
/>
Member
</label>
</div>
</div>
<div
class="FilterList_item"
>
<div
class="FilterList_checkbox"
>
<label>
<input
id="team_admin"
name="team_admin"
type="checkbox"
/>
Team Admin
</label>
</div>
</div>
<div
class="FilterList_item"
>
<div
class="FilterList_checkbox"
>
<label>
<input
id="system_admin"
name="system_admin"
type="checkbox"
/>
System Admin
</label>
</div>
</div>
</div>
</div>
<button
class="btn btn-primary btn-sm Filter_apply"
disabled=""
type="button"
>
Apply
</button>
</div>
</div>
</div>
<div
class="DataGrid_header"
>
<div
class="DataGrid_cell"
style="flex-grow: 3;"
>
Name
</div>
<div
class="DataGrid_cell"
/>
<div
class="DataGrid_cell"
/>
</div>
<div
class="DataGrid_rows"
style="min-height: 240px;"
>
<div
class="DataGrid_loading"
>
<span
class="LoadingSpinner"
data-testid="loadingSpinner"
id="loadingSpinner"
>
<span
class="fa fa-spinner fa-fw fa-pulse spinner"
title="Loading Icon"
/>
</span>
Loading
</div>
</div>
<div
class="DataGrid_footer"
>
<div
class="DataGrid_cell"
>
1 - 3 of 3
<button
aria-label="Previous page"
class="btn btn-quaternary btn-icon btn-sm ml-2 prev disabled"
disabled=""
type="button"
>
<i
class="icon icon-chevron-left"
title="Previous Icon"
/>
</button>
<button
aria-label="Next page"
class="btn btn-quaternary btn-icon btn-sm next disabled"
disabled=""
type="button"
>
<i
class="icon icon-chevron-right"
title="Next Icon"
/>
</button>
</div>
</div>
</div>
</div>
</div>
`;
exports[`admin_console/team_channel_settings/team/TeamMembers should match snapshot loading no users 1`] = `
<AdminPanel
button={
<ToggleModalButton
className="btn btn-primary"
dialogProps={
Object {
"excludeUsers": Object {},
"filterExcludeGuests": true,
"includeUsers": Object {},
"onAddCallback": [Function],
"skipCommit": true,
"team": Object {
"allow_open_invite": false,
"allowed_domains": "",
"company_name": "",
"create_at": 0,
"delete_at": 0,
"description": "",
"display_name": "name",
"email": "",
"group_constrained": false,
"id": "team-1",
"invite_id": "",
"name": "DN",
"scheme_id": "id",
"type": "O",
"update_at": 0,
},
}
}
dialogType={
Object {
"$$typeof": Symbol(react.memo),
"WrappedComponent": [Function],
"compare": null,
"type": [Function],
}
}
id="addTeamMembers"
modalId="add_user_to_team"
<div>
<div
class="AdminPanel clearfix "
id="teamMembers"
>
<div
class="header"
>
<Memo(MemoizedFormattedMessage)
defaultMessage="Add Members"
id="admin.team_settings.team_details.add_members"
/>
</ToggleModalButton>
}
id="teamMembers"
subtitle={
Object {
"defaultMessage": "A list of users who are currently in the team right now",
"id": "admin.team_settings.team_detail.membersDescription",
}
}
title={
Object {
"defaultMessage": "Members",
"id": "admin.team_settings.team_detail.membersTitle",
}
}
>
<UserGrid
excludeUsers={Object {}}
filterProps={
Object {
"keys": Array [
"role",
],
"onFilter": [Function],
"options": Object {
"role": Object {
"keys": Array [
"system_guest",
"team_user",
"team_admin",
"system_admin",
],
"name": <Memo(MemoizedFormattedMessage)
defaultMessage="Role"
id="admin.user_grid.role"
/>,
"values": Object {
"system_admin": Object {
"name": <Memo(MemoizedFormattedMessage)
defaultMessage="System Admin"
id="admin.user_grid.system_admin"
/>,
"value": false,
},
"system_guest": Object {
"name": <Memo(MemoizedFormattedMessage)
defaultMessage="Guest"
id="admin.user_grid.guest"
/>,
"value": false,
},
"team_admin": Object {
"name": <Memo(MemoizedFormattedMessage)
defaultMessage="Team Admin"
id="admin.user_grid.team_admin"
/>,
"value": false,
},
"team_user": Object {
"name": <Memo(MemoizedFormattedMessage)
defaultMessage="Member"
id="admin.user_item.member"
/>,
"value": false,
},
},
},
},
}
}
includeUsers={Object {}}
loadPage={[Function]}
loading={true}
memberships={Object {}}
onSearch={[Function]}
removeUser={[Function]}
scope="team"
term=""
totalCount={0}
updateMembership={[Function]}
users={Array []}
/>
</AdminPanel>
<div>
<h3>
Members
</h3>
<div
class="mt-2"
>
A list of users who are currently in the team right now
</div>
</div>
<div
class="button"
>
<button
class="style--none btn btn-primary"
id="addTeamMembers"
>
Add Members
</button>
</div>
</div>
<div
class="DataGrid"
>
<div
class="DataGrid_search"
>
<div
class="DataGrid_searchBar"
>
<span
aria-hidden="true"
class="DataGrid_searchIcon"
>
<i
class="fa fa-search"
title="Search Icon"
/>
</span>
<input
data-testid="searchInput"
placeholder="Search"
type="text"
value=""
/>
<i
class="DataGrid_clearButton fa fa-times-circle hidden"
data-testid="clear-search"
/>
</div>
<div
class="Filter"
>
<button
class="Filter_button"
type="button"
>
<i
class="Icon icon-filter-variant"
/>
Filters
</button>
<div
class="Filter_content"
>
<div
class="Filter_header"
>
<div
class="Filter_title"
>
Filter by
</div>
<a
class="Filter_reset"
>
Reset filters
</a>
</div>
<hr />
<div
class="Filter_lists"
>
<div
class="FilterList"
>
<div
class="FilterList_name"
>
Role
</div>
<div
class="FilterList_item"
>
<div
class="FilterList_checkbox"
>
<label>
<input
id="system_guest"
name="system_guest"
type="checkbox"
/>
Guest
</label>
</div>
</div>
<div
class="FilterList_item"
>
<div
class="FilterList_checkbox"
>
<label>
<input
id="team_user"
name="team_user"
type="checkbox"
/>
Member
</label>
</div>
</div>
<div
class="FilterList_item"
>
<div
class="FilterList_checkbox"
>
<label>
<input
id="team_admin"
name="team_admin"
type="checkbox"
/>
Team Admin
</label>
</div>
</div>
<div
class="FilterList_item"
>
<div
class="FilterList_checkbox"
>
<label>
<input
id="system_admin"
name="system_admin"
type="checkbox"
/>
System Admin
</label>
</div>
</div>
</div>
</div>
<button
class="btn btn-primary btn-sm Filter_apply"
disabled=""
type="button"
>
Apply
</button>
</div>
</div>
</div>
<div
class="DataGrid_header"
>
<div
class="DataGrid_cell"
style="flex-grow: 3;"
>
Name
</div>
<div
class="DataGrid_cell"
/>
<div
class="DataGrid_cell"
/>
</div>
<div
class="DataGrid_rows"
style="min-height: 0px;"
>
<div
class="DataGrid_loading"
>
<span
class="LoadingSpinner"
data-testid="loadingSpinner"
id="loadingSpinner"
>
<span
class="fa fa-spinner fa-fw fa-pulse spinner"
title="Loading Icon"
/>
</span>
Loading
</div>
</div>
</div>
</div>
</div>
`;
@@ -1,12 +1,12 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {shallow} from 'enzyme';
import React from 'react';
import type {Team, TeamMembership} from '@mattermost/types/teams';
import type {UserProfile} from '@mattermost/types/users';
import {renderWithContext} from 'tests/react_testing_utils';
import {TestHelper} from 'utils/test_helper';
import TeamMembers from './team_members';
@@ -42,24 +42,24 @@ describe('admin_console/team_channel_settings/team/TeamMembers', () => {
updateRole: jest.fn(),
actions: {
getTeamStats: jest.fn(),
loadProfilesAndReloadTeamMembers: jest.fn(),
searchProfilesAndTeamMembers: jest.fn(),
getFilteredUsersStats: jest.fn(),
getTeamStats: jest.fn().mockResolvedValue({}),
loadProfilesAndReloadTeamMembers: jest.fn().mockResolvedValue({}),
searchProfilesAndTeamMembers: jest.fn().mockResolvedValue({}),
getFilteredUsersStats: jest.fn().mockResolvedValue({}),
setUserGridSearch: jest.fn(),
setUserGridFilters: jest.fn(),
},
};
test('should match snapshot', () => {
const wrapper = shallow(
const {container} = renderWithContext(
<TeamMembers {...baseProps}/>,
);
expect(wrapper).toMatchSnapshot();
expect(container).toMatchSnapshot();
});
test('should match snapshot loading no users', () => {
const wrapper = shallow(
const {container} = renderWithContext(
<TeamMembers
{...baseProps}
users={[]}
@@ -68,6 +68,6 @@ describe('admin_console/team_channel_settings/team/TeamMembers', () => {
loading={true}
/>,
);
expect(wrapper).toMatchSnapshot();
expect(container).toMatchSnapshot();
});
});
@@ -1,14 +1,15 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {shallow} from 'enzyme';
import React from 'react';
import {renderWithContext} from 'tests/react_testing_utils';
import {TeamModes} from './team_modes';
describe('admin_console/team_channel_settings/team/TeamModes', () => {
test('should match snapshot', () => {
const wrapper = shallow(
const {container} = renderWithContext(
<TeamModes
onToggle={jest.fn()}
syncChecked={false}
@@ -17,6 +18,6 @@ describe('admin_console/team_channel_settings/team/TeamModes', () => {
allowedDomainsChecked={true}
/>,
);
expect(wrapper).toMatchSnapshot();
expect(container).toMatchSnapshot();
});
});
@@ -1,18 +1,21 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {shallow} from 'enzyme';
import React from 'react';
import {renderWithContext} from 'tests/react_testing_utils';
import {TeamsSettings} from './team_settings';
jest.mock('components/admin_console/team_channel_settings/team/list', () => () => <div>{'TeamList'}</div>);
describe('admin_console/team_channel_settings/team/TeamSettings', () => {
test('should match snapshot', () => {
const wrapper = shallow(
const {container} = renderWithContext(
<TeamsSettings
siteName='site'
/>,
);
expect(wrapper).toMatchSnapshot();
expect(container).toMatchSnapshot();
});
});
@@ -14,6 +14,8 @@
- **No Snapshots**: Write explicit assertions with `expect(...).toBeVisible()`.
- **Accessible Selectors**: Prefer `getByRole` > `getByText` > `getByLabelText` > `getByTestId`.
- **userEvent**: Use `userEvent` over `fireEvent`, always await.
- **Props Factory**: Use `getBaseProps()` (not `makeProps` or other names) when creating fresh props per test to avoid shared mock state leaking between tests.
- **No `act()` wrapping render calls**: RTL's `render` and `renderHook` (and their context wrappers like `renderWithContext`, `renderHookWithContext`) already run inside `act`. For async effects on mount, render normally and use `waitFor` to assert the effect completed.
## renderWithContext
Always use `renderWithContext` for components that need Redux, Router, or I18n context:
@@ -34,6 +36,20 @@ describe('MyComponent', () => {
});
```
## Async Components
For components that trigger async effects on mount (e.g., data fetching), render normally and use `waitFor` to assert the effect completed before making assertions:
```typescript
const {container} = renderWithContext(<MyComponent actions={actions} />);
await waitFor(() => {
expect(actions.getData).toHaveBeenCalled();
});
expect(container).toMatchSnapshot();
```
## Adding Helpers
- Place reusable mocks under `helpers/` (e.g., `intl-test-helper.tsx`, `match_media.mock.ts`).
- Document custom utilities with inline comments.