mirror of
https://github.com/mattermost/mattermost.git
synced 2026-02-18 18:18:23 -05:00
(test): restructure system console page-object-model (#35185)
Co-authored-by: Mattermost Build <build@mattermost.com>
This commit is contained in:
parent
d09ab7173e
commit
e4bd8398ab
36 changed files with 3205 additions and 1336 deletions
|
|
@ -51,14 +51,7 @@ export {
|
|||
ScheduledDraftModal,
|
||||
ScheduledPost,
|
||||
SendMessageNowModal,
|
||||
SystemConsoleSidebar,
|
||||
SystemConsoleNavbar,
|
||||
SystemUsers,
|
||||
SystemUsersFilterPopover,
|
||||
SystemUsersFilterMenu,
|
||||
SystemUsersColumnToggleMenu,
|
||||
SystemConsoleFeatureDiscovery,
|
||||
SystemConsoleMobileSecurity,
|
||||
MessagePriority,
|
||||
UserProfilePopover,
|
||||
UserAccountMenu,
|
||||
|
|
|
|||
|
|
@ -1,157 +1,189 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import ChannelsHeader from './channels/header';
|
||||
import ChannelsAppBar from './channels/app_bar';
|
||||
import ChannelsPostCreate from './channels/post_create';
|
||||
import ChannelsPost from './channels/post';
|
||||
import ChannelsCenterView from './channels/center_view';
|
||||
import ChannelsSidebarLeft from './channels/sidebar_left';
|
||||
import ChannelsSidebarRight from './channels/sidebar_right';
|
||||
import ChannelSettingsModal from './channels/channel_settings/channel_settings_modal';
|
||||
import DeletePostModal from './channels/delete_post_modal';
|
||||
import FindChannelsModal from './channels/find_channels_modal';
|
||||
import InvitePeopleModal from './channels/invite_people_modal';
|
||||
import SettingsModal from './channels/settings/settings_modal';
|
||||
// Shared / Global Components
|
||||
import Footer from './footer';
|
||||
import GlobalHeader from './global_header';
|
||||
import SearchBox from './channels/search_box';
|
||||
import MainHeader from './main_header';
|
||||
import PostDotMenu from './channels/post_dot_menu';
|
||||
import PostReminderMenu from './channels/post_reminder_menu';
|
||||
import PostMenu from './channels/post_menu';
|
||||
import ThreadFooter from './channels/thread_footer';
|
||||
import EmojiGifPicker from './channels/emoji_gif_picker';
|
||||
import GenericConfirmModal from './channels/generic_confirm_modal';
|
||||
import MessagePriority from './channels/message_priority';
|
||||
import ScheduleMessageMenu from './channels/schedule_message_menu';
|
||||
import ScheduleMessageModal from './channels/schedule_message_modal';
|
||||
import ScheduledPostIndicator from './channels/scheduled_post_indicator';
|
||||
import ScheduledDraftModal from './channels/scheduled_draft_modal';
|
||||
import UserAccountMenu from './user_account_menu';
|
||||
import TeamMenu from './channels/team_menu';
|
||||
import TeamSettingsModal from './channels/team_settings/team_settings_modal';
|
||||
import ProfileModal from './channels/profile_modal';
|
||||
import UserProfilePopover from './channels/user_profile_popover';
|
||||
import SystemConsoleSidebar from './system_console/sidebar';
|
||||
import SystemConsoleNavbar from './system_console/navbar';
|
||||
import SystemUsers from './system_console/sections/system_users/system_users';
|
||||
import SystemUsersFilterPopover from './system_console/sections/system_users/filter_popover';
|
||||
import SystemUsersFilterMenu from './system_console/sections/system_users/filter_menu';
|
||||
import SystemUsersColumnToggleMenu from './system_console/sections/system_users/column_toggle_menu';
|
||||
// Channels Components
|
||||
import ChannelsAppBar from './channels/app_bar';
|
||||
import ChannelsCenterView from './channels/center_view';
|
||||
import ChannelsHeader from './channels/header';
|
||||
import ChannelsPost from './channels/post';
|
||||
import ChannelsPostCreate from './channels/post_create';
|
||||
import ChannelsPostEdit from './channels/post_edit';
|
||||
import ChannelSettingsModal from './channels/channel_settings/channel_settings_modal';
|
||||
import ChannelsSidebarLeft from './channels/sidebar_left';
|
||||
import ChannelsSidebarRight from './channels/sidebar_right';
|
||||
import DeletePostConfirmationDialog from './channels/delete_post_confirmation_dialog';
|
||||
import RestorePostConfirmationDialog from './channels/restore_post_confirmation_dialog';
|
||||
import SystemConsoleFeatureDiscovery from './system_console/sections/system_users/feature_discovery';
|
||||
import SystemConsoleMobileSecurity from './system_console/sections/system_users/mobile_security';
|
||||
import SystemConsoleNotifications from './system_console/sections/site_configuration/notifications';
|
||||
import ScheduledPost from './channels/scheduled_post';
|
||||
import SendMessageNowModal from './channels/send_message_now_modal';
|
||||
import DeletePostModal from './channels/delete_post_modal';
|
||||
import DeleteScheduledPostModal from './channels/delete_scheduled_post_modal';
|
||||
import DraftPost from './channels/draft_post';
|
||||
import EmojiGifPicker from './channels/emoji_gif_picker';
|
||||
import FindChannelsModal from './channels/find_channels_modal';
|
||||
import FlagPostConfirmationDialog from './channels/flag_post_confirmation_dialog';
|
||||
import GenericConfirmModal from './channels/generic_confirm_modal';
|
||||
import InvitePeopleModal from './channels/invite_people_modal';
|
||||
import MessagePriority from './channels/message_priority';
|
||||
import PostDotMenu from './channels/post_dot_menu';
|
||||
import PostMenu from './channels/post_menu';
|
||||
import PostReminderMenu from './channels/post_reminder_menu';
|
||||
import ProfileModal from './channels/profile_modal';
|
||||
import RestorePostConfirmationDialog from './channels/restore_post_confirmation_dialog';
|
||||
import ScheduledDraftModal from './channels/scheduled_draft_modal';
|
||||
import ScheduledPost from './channels/scheduled_post';
|
||||
import ScheduledPostIndicator from './channels/scheduled_post_indicator';
|
||||
import ScheduleMessageMenu from './channels/schedule_message_menu';
|
||||
import ScheduleMessageModal from './channels/schedule_message_modal';
|
||||
import SearchBox from './channels/search_box';
|
||||
import SendMessageNowModal from './channels/send_message_now_modal';
|
||||
import SettingsModal from './channels/settings/settings_modal';
|
||||
import TeamMenu from './channels/team_menu';
|
||||
import TeamSettingsModal from './channels/team_settings/team_settings_modal';
|
||||
import ThreadFooter from './channels/thread_footer';
|
||||
import UserProfilePopover from './channels/user_profile_popover';
|
||||
// System Console Components
|
||||
import {AdminSectionPanel, DropdownSetting, RadioSetting, TextInputSetting} from './system_console/base_components';
|
||||
import DelegatedGranularAdministration from './system_console/sections/user_management/delegated_granular_administration';
|
||||
import UserDetail from './system_console/sections/user_management/user_detail';
|
||||
import EditionAndLicense from './system_console/sections/about/edition_and_license';
|
||||
import MobileSecurity from './system_console/sections/environment/mobile_security';
|
||||
import Notifications from './system_console/sections/site_configuration/notifications';
|
||||
import SystemConsoleFeatureDiscovery from './system_console/sections/system_users/feature_discovery';
|
||||
import SystemConsoleHeader from './system_console/header';
|
||||
import SystemConsoleNavbar from './system_console/navbar';
|
||||
import SystemConsoleSidebar from './system_console/sidebar';
|
||||
import SystemConsoleSidebarHeader from './system_console/sidebar_header';
|
||||
import TeamStatistics from './system_console/sections/reporting/team_statistics';
|
||||
import Users from './system_console/sections/user_management/users';
|
||||
|
||||
const components = {
|
||||
// Shared / Global
|
||||
Footer,
|
||||
GlobalHeader,
|
||||
SearchBox,
|
||||
ChannelsCenterView,
|
||||
ChannelsSidebarLeft,
|
||||
ChannelsSidebarRight,
|
||||
MainHeader,
|
||||
UserAccountMenu,
|
||||
|
||||
// Channels
|
||||
ChannelsAppBar,
|
||||
ChannelsCenterView,
|
||||
ChannelsHeader,
|
||||
ChannelsPost,
|
||||
ChannelsPostCreate,
|
||||
ChannelsPostEdit,
|
||||
ChannelsPost,
|
||||
ChannelSettingsModal,
|
||||
DraftPost,
|
||||
FindChannelsModal,
|
||||
FlagPostConfirmationDialog,
|
||||
ChannelsSidebarLeft,
|
||||
ChannelsSidebarRight,
|
||||
DeletePostConfirmationDialog,
|
||||
DeletePostModal,
|
||||
DeleteScheduledPostModal,
|
||||
DraftPost,
|
||||
EmojiGifPicker,
|
||||
FindChannelsModal,
|
||||
FlagPostConfirmationDialog,
|
||||
GenericConfirmModal,
|
||||
InvitePeopleModal,
|
||||
SettingsModal,
|
||||
MessagePriority,
|
||||
PostDotMenu,
|
||||
PostMenu,
|
||||
ThreadFooter,
|
||||
Footer,
|
||||
MainHeader,
|
||||
PostReminderMenu,
|
||||
EmojiGifPicker,
|
||||
GenericConfirmModal,
|
||||
ScheduleMessageMenu,
|
||||
ScheduleMessageModal,
|
||||
ScheduledPostIndicator,
|
||||
ProfileModal,
|
||||
RestorePostConfirmationDialog,
|
||||
ScheduledDraftModal,
|
||||
ScheduledPost,
|
||||
ScheduledPostIndicator,
|
||||
ScheduleMessageMenu,
|
||||
ScheduleMessageModal,
|
||||
SearchBox,
|
||||
SendMessageNowModal,
|
||||
SystemConsoleSidebar,
|
||||
SystemConsoleNavbar,
|
||||
SystemUsers,
|
||||
SystemUsersFilterPopover,
|
||||
SystemUsersFilterMenu,
|
||||
SystemUsersColumnToggleMenu,
|
||||
SystemConsoleFeatureDiscovery,
|
||||
SystemConsoleMobileSecurity,
|
||||
SystemConsoleNotifications,
|
||||
MessagePriority,
|
||||
UserProfilePopover,
|
||||
UserAccountMenu,
|
||||
SettingsModal,
|
||||
TeamMenu,
|
||||
TeamSettingsModal,
|
||||
DeletePostConfirmationDialog,
|
||||
RestorePostConfirmationDialog,
|
||||
ProfileModal,
|
||||
ThreadFooter,
|
||||
UserProfilePopover,
|
||||
|
||||
// System Console
|
||||
AdminSectionPanel,
|
||||
DelegatedGranularAdministration,
|
||||
DropdownSetting,
|
||||
EditionAndLicense,
|
||||
MobileSecurity,
|
||||
Notifications,
|
||||
RadioSetting,
|
||||
SystemConsoleFeatureDiscovery,
|
||||
SystemConsoleHeader,
|
||||
SystemConsoleNavbar,
|
||||
SystemConsoleSidebar,
|
||||
SystemConsoleSidebarHeader,
|
||||
TeamStatistics,
|
||||
TextInputSetting,
|
||||
UserDetail,
|
||||
Users,
|
||||
};
|
||||
|
||||
export {
|
||||
components,
|
||||
|
||||
// Shared / Global
|
||||
Footer,
|
||||
GlobalHeader,
|
||||
SearchBox,
|
||||
ChannelsCenterView,
|
||||
ChannelsSidebarLeft,
|
||||
ChannelsSidebarRight,
|
||||
MainHeader,
|
||||
UserAccountMenu,
|
||||
|
||||
// Channels Page
|
||||
ChannelsAppBar,
|
||||
ChannelsCenterView,
|
||||
ChannelsHeader,
|
||||
ChannelsPost,
|
||||
ChannelsPostCreate,
|
||||
ChannelsPostEdit,
|
||||
ChannelsPost,
|
||||
ChannelSettingsModal,
|
||||
DraftPost,
|
||||
FindChannelsModal,
|
||||
FlagPostConfirmationDialog,
|
||||
ChannelsSidebarLeft,
|
||||
ChannelsSidebarRight,
|
||||
DeletePostConfirmationDialog,
|
||||
DeletePostModal,
|
||||
DeleteScheduledPostModal,
|
||||
DraftPost,
|
||||
EmojiGifPicker,
|
||||
FindChannelsModal,
|
||||
FlagPostConfirmationDialog,
|
||||
GenericConfirmModal,
|
||||
InvitePeopleModal,
|
||||
SettingsModal,
|
||||
MessagePriority,
|
||||
PostDotMenu,
|
||||
PostMenu,
|
||||
ThreadFooter,
|
||||
Footer,
|
||||
MainHeader,
|
||||
PostReminderMenu,
|
||||
EmojiGifPicker,
|
||||
GenericConfirmModal,
|
||||
ScheduleMessageMenu,
|
||||
ScheduleMessageModal,
|
||||
ScheduledPostIndicator,
|
||||
ProfileModal,
|
||||
RestorePostConfirmationDialog,
|
||||
ScheduledDraftModal,
|
||||
ScheduledPost,
|
||||
ScheduledPostIndicator,
|
||||
ScheduleMessageMenu,
|
||||
ScheduleMessageModal,
|
||||
SearchBox,
|
||||
SendMessageNowModal,
|
||||
SystemConsoleSidebar,
|
||||
SystemConsoleNavbar,
|
||||
SystemUsers,
|
||||
SystemUsersFilterPopover,
|
||||
SystemUsersFilterMenu,
|
||||
SystemUsersColumnToggleMenu,
|
||||
SystemConsoleFeatureDiscovery,
|
||||
SystemConsoleMobileSecurity,
|
||||
SystemConsoleNotifications,
|
||||
MessagePriority,
|
||||
UserProfilePopover,
|
||||
UserAccountMenu,
|
||||
SettingsModal,
|
||||
TeamMenu,
|
||||
TeamSettingsModal,
|
||||
DeletePostConfirmationDialog,
|
||||
RestorePostConfirmationDialog,
|
||||
ProfileModal,
|
||||
ThreadFooter,
|
||||
UserProfilePopover,
|
||||
|
||||
// System Console
|
||||
AdminSectionPanel,
|
||||
DelegatedGranularAdministration,
|
||||
DropdownSetting,
|
||||
EditionAndLicense,
|
||||
MobileSecurity,
|
||||
Notifications,
|
||||
RadioSetting,
|
||||
SystemConsoleFeatureDiscovery,
|
||||
SystemConsoleHeader,
|
||||
SystemConsoleNavbar,
|
||||
SystemConsoleSidebar,
|
||||
SystemConsoleSidebarHeader,
|
||||
TeamStatistics,
|
||||
TextInputSetting,
|
||||
UserDetail,
|
||||
Users,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -0,0 +1,145 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {Locator, expect} from '@playwright/test';
|
||||
|
||||
/**
|
||||
* Radio Setting - represents a true/false radio button group
|
||||
* Uses getByRole for radio buttons, getByText for help text
|
||||
*
|
||||
* Usage:
|
||||
* await setting.selectTrue();
|
||||
* await setting.toBeTrue();
|
||||
* await setting.toBeFalse();
|
||||
*/
|
||||
export class RadioSetting {
|
||||
readonly container: Locator;
|
||||
readonly trueOption: Locator;
|
||||
readonly falseOption: Locator;
|
||||
readonly helpText: Locator;
|
||||
|
||||
constructor(container: Locator) {
|
||||
this.container = container;
|
||||
this.trueOption = container.getByRole('radio', {name: 'True'});
|
||||
this.falseOption = container.getByRole('radio', {name: 'False'});
|
||||
this.helpText = container.locator('.help-text');
|
||||
}
|
||||
|
||||
/**
|
||||
* Select the True option
|
||||
*/
|
||||
async selectTrue() {
|
||||
await this.trueOption.check();
|
||||
}
|
||||
|
||||
/**
|
||||
* Select the False option
|
||||
*/
|
||||
async selectFalse() {
|
||||
await this.falseOption.check();
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that the setting is visible
|
||||
*/
|
||||
async toBeVisible() {
|
||||
await expect(this.container).toBeVisible();
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that the True option is selected
|
||||
*/
|
||||
async toBeTrue() {
|
||||
await expect(this.trueOption).toBeChecked();
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that the False option is selected (True is not checked)
|
||||
*/
|
||||
async toBeFalse() {
|
||||
await expect(this.falseOption).toBeChecked();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Text Input Setting - represents a text input field
|
||||
*/
|
||||
export class TextInputSetting {
|
||||
readonly container: Locator;
|
||||
readonly label: Locator;
|
||||
readonly input: Locator;
|
||||
readonly helpText: Locator;
|
||||
|
||||
constructor(container: Locator, labelText: string) {
|
||||
this.container = container;
|
||||
this.label = container.getByText(labelText);
|
||||
this.input = container.getByRole('textbox');
|
||||
this.helpText = container.locator('.help-text');
|
||||
}
|
||||
|
||||
async fill(value: string) {
|
||||
await this.input.fill(value);
|
||||
}
|
||||
|
||||
async getValue(): Promise<string> {
|
||||
return (await this.input.inputValue()) ?? '';
|
||||
}
|
||||
|
||||
async clear() {
|
||||
await this.input.clear();
|
||||
}
|
||||
|
||||
async toBeVisible() {
|
||||
await expect(this.container).toBeVisible();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Dropdown Setting - represents a select dropdown
|
||||
*/
|
||||
export class DropdownSetting {
|
||||
readonly container: Locator;
|
||||
readonly label: Locator;
|
||||
readonly dropdown: Locator;
|
||||
readonly helpText: Locator;
|
||||
|
||||
constructor(container: Locator, labelText: string) {
|
||||
this.container = container;
|
||||
this.label = container.getByText(labelText);
|
||||
this.dropdown = container.getByRole('combobox');
|
||||
this.helpText = container.locator('.help-text');
|
||||
}
|
||||
|
||||
async select(option: string) {
|
||||
await this.dropdown.selectOption(option);
|
||||
}
|
||||
|
||||
async getSelectedValue(): Promise<string> {
|
||||
return (await this.dropdown.inputValue()) ?? '';
|
||||
}
|
||||
|
||||
async toBeVisible() {
|
||||
await expect(this.container).toBeVisible();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Admin Section Panel - represents a collapsible section panel
|
||||
*/
|
||||
export class AdminSectionPanel {
|
||||
readonly container: Locator;
|
||||
readonly title: Locator;
|
||||
readonly description: Locator;
|
||||
readonly body: Locator;
|
||||
|
||||
constructor(container: Locator, titleText: string) {
|
||||
this.container = container;
|
||||
this.title = container.getByRole('heading', {name: titleText});
|
||||
this.description = container.locator('.AdminSectionPanel__description');
|
||||
this.body = container.locator('.AdminSectionPanel__body');
|
||||
}
|
||||
|
||||
async toBeVisible() {
|
||||
await expect(this.container).toBeVisible();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {Locator, expect} from '@playwright/test';
|
||||
|
||||
/**
|
||||
* Base modal component for System Console modals.
|
||||
* Can be extended or used directly for various modal dialogs.
|
||||
*/
|
||||
export default class BaseModal {
|
||||
readonly container: Locator;
|
||||
readonly title: Locator;
|
||||
readonly closeButton: Locator;
|
||||
readonly cancelButton: Locator;
|
||||
|
||||
constructor(container: Locator) {
|
||||
this.container = container;
|
||||
this.title = container.locator('.modal-title');
|
||||
this.closeButton = container.getByRole('button', {name: 'Close'});
|
||||
this.cancelButton = container.getByRole('button', {name: 'Cancel'});
|
||||
}
|
||||
|
||||
async toBeVisible() {
|
||||
await expect(this.container).toBeVisible();
|
||||
}
|
||||
|
||||
async close() {
|
||||
await this.closeButton.click();
|
||||
await expect(this.container).not.toBeVisible();
|
||||
}
|
||||
|
||||
async cancel() {
|
||||
await this.cancelButton.click();
|
||||
await expect(this.container).not.toBeVisible();
|
||||
}
|
||||
|
||||
async clickButton(name: string) {
|
||||
await this.container.getByRole('button', {name}).click();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Confirm modal with specific confirm button ID (#confirmModalButton)
|
||||
*/
|
||||
export class ConfirmModal extends BaseModal {
|
||||
readonly confirmButton: Locator;
|
||||
|
||||
constructor(container: Locator) {
|
||||
super(container);
|
||||
this.confirmButton = container.locator('#confirmModalButton');
|
||||
}
|
||||
|
||||
async confirm() {
|
||||
await this.confirmButton.click();
|
||||
await expect(this.container).not.toBeVisible();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {Locator, expect} from '@playwright/test';
|
||||
|
||||
/**
|
||||
* System Console section header component
|
||||
* Represents the header area that displays the current section title
|
||||
*/
|
||||
export default class SystemConsoleHeader {
|
||||
readonly container: Locator;
|
||||
readonly title: Locator;
|
||||
|
||||
constructor(container: Locator) {
|
||||
this.container = container;
|
||||
this.title = container.locator('.admin-console__header');
|
||||
}
|
||||
|
||||
async toBeVisible() {
|
||||
await expect(this.container).toBeVisible();
|
||||
}
|
||||
|
||||
async getTitle(): Promise<string> {
|
||||
return (await this.title.textContent()) ?? '';
|
||||
}
|
||||
|
||||
async toHaveTitle(expectedTitle: string) {
|
||||
await expect(this.title).toContainText(expectedTitle);
|
||||
}
|
||||
}
|
||||
|
|
@ -3,14 +3,27 @@
|
|||
|
||||
import {Locator, expect} from '@playwright/test';
|
||||
|
||||
/**
|
||||
* System Console Navbar component
|
||||
*/
|
||||
export default class SystemConsoleNavbar {
|
||||
readonly container: Locator;
|
||||
readonly backLink: Locator;
|
||||
|
||||
constructor(container: Locator) {
|
||||
this.container = container;
|
||||
this.backLink = container.getByRole('link', {name: /Back/});
|
||||
}
|
||||
|
||||
async toBeVisible() {
|
||||
await expect(this.container).toBeVisible();
|
||||
await expect(this.backLink).toBeVisible();
|
||||
}
|
||||
|
||||
/**
|
||||
* Click the back link to return to the team
|
||||
*/
|
||||
async clickBack() {
|
||||
await this.backLink.click();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,22 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {Locator, expect} from '@playwright/test';
|
||||
|
||||
/**
|
||||
* System Console -> About -> Edition and License
|
||||
*/
|
||||
export default class EditionAndLicense {
|
||||
readonly container: Locator;
|
||||
readonly header: Locator;
|
||||
|
||||
constructor(container: Locator) {
|
||||
this.container = container;
|
||||
this.header = container.getByText('Edition and License', {exact: true});
|
||||
}
|
||||
|
||||
async toBeVisible() {
|
||||
await expect(this.container).toBeVisible();
|
||||
await expect(this.header).toBeVisible();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,132 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {Locator, expect} from '@playwright/test';
|
||||
|
||||
import {RadioSetting, TextInputSetting, DropdownSetting, AdminSectionPanel} from '../../base_components';
|
||||
|
||||
/**
|
||||
* System Console -> Environment -> Mobile Security
|
||||
*/
|
||||
export default class MobileSecurity {
|
||||
readonly container: Locator;
|
||||
|
||||
// Header
|
||||
readonly header: Locator;
|
||||
|
||||
// Panels
|
||||
readonly generalMobileSecurity: GeneralMobileSecurityPanel;
|
||||
readonly microsoftIntune: MicrosoftIntunePanel;
|
||||
|
||||
// Save section
|
||||
readonly saveButton: Locator;
|
||||
readonly errorMessage: Locator;
|
||||
|
||||
constructor(container: Locator) {
|
||||
this.container = container;
|
||||
|
||||
this.header = container.getByText('Mobile Security', {exact: true});
|
||||
|
||||
this.generalMobileSecurity = new GeneralMobileSecurityPanel(
|
||||
container.locator('.AdminSectionPanel').filter({hasText: 'General Mobile Security'}),
|
||||
);
|
||||
this.microsoftIntune = new MicrosoftIntunePanel(
|
||||
container.locator('.AdminSectionPanel').filter({hasText: 'Microsoft Intune'}),
|
||||
);
|
||||
|
||||
this.saveButton = container.getByRole('button', {name: 'Save'});
|
||||
this.errorMessage = container.locator('.error-message');
|
||||
}
|
||||
|
||||
async toBeVisible() {
|
||||
await expect(this.container).toBeVisible();
|
||||
await expect(this.header).toBeVisible();
|
||||
}
|
||||
|
||||
async save() {
|
||||
await this.saveButton.click();
|
||||
}
|
||||
|
||||
// Convenience shortcuts for General Mobile Security settings
|
||||
get enableBiometricAuthentication() {
|
||||
return this.generalMobileSecurity.enableBiometricAuthentication;
|
||||
}
|
||||
get preventScreenCapture() {
|
||||
return this.generalMobileSecurity.preventScreenCapture;
|
||||
}
|
||||
get enableJailbreakProtection() {
|
||||
return this.generalMobileSecurity.enableJailbreakProtection;
|
||||
}
|
||||
get enableSecureFilePreviewMode() {
|
||||
return this.generalMobileSecurity.enableSecureFilePreviewMode;
|
||||
}
|
||||
get allowPdfLinkNavigation() {
|
||||
return this.generalMobileSecurity.allowPdfLinkNavigation;
|
||||
}
|
||||
|
||||
// Convenience shortcuts for Microsoft Intune settings
|
||||
get enableIntuneMAM() {
|
||||
return this.microsoftIntune.enableIntuneMAM;
|
||||
}
|
||||
get authProvider() {
|
||||
return this.microsoftIntune.authProvider;
|
||||
}
|
||||
get tenantId() {
|
||||
return this.microsoftIntune.tenantId;
|
||||
}
|
||||
get clientId() {
|
||||
return this.microsoftIntune.clientId;
|
||||
}
|
||||
}
|
||||
|
||||
class GeneralMobileSecurityPanel extends AdminSectionPanel {
|
||||
readonly enableBiometricAuthentication: RadioSetting;
|
||||
readonly preventScreenCapture: RadioSetting;
|
||||
readonly enableJailbreakProtection: RadioSetting;
|
||||
readonly enableSecureFilePreviewMode: RadioSetting;
|
||||
readonly allowPdfLinkNavigation: RadioSetting;
|
||||
|
||||
constructor(container: Locator) {
|
||||
super(container, 'General Mobile Security');
|
||||
|
||||
this.enableBiometricAuthentication = new RadioSetting(
|
||||
this.body.getByRole('group', {name: /Enable Biometric Authentication/}),
|
||||
);
|
||||
this.preventScreenCapture = new RadioSetting(this.body.getByRole('group', {name: /Prevent Screen Capture/}));
|
||||
this.enableJailbreakProtection = new RadioSetting(
|
||||
this.body.getByRole('group', {name: /Enable Jailbreak\/Root Protection/}),
|
||||
);
|
||||
this.enableSecureFilePreviewMode = new RadioSetting(
|
||||
this.body.getByRole('group', {name: /Enable Secure File Preview Mode/}),
|
||||
);
|
||||
this.allowPdfLinkNavigation = new RadioSetting(
|
||||
this.body.getByRole('group', {name: /Allow Link Navigation in Secure PDFs/}),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class MicrosoftIntunePanel extends AdminSectionPanel {
|
||||
readonly enableIntuneMAM: RadioSetting;
|
||||
readonly authProvider: DropdownSetting;
|
||||
readonly tenantId: TextInputSetting;
|
||||
readonly clientId: TextInputSetting;
|
||||
|
||||
constructor(container: Locator) {
|
||||
super(container, 'Microsoft Intune');
|
||||
|
||||
this.enableIntuneMAM = new RadioSetting(this.body.getByRole('group', {name: /Enable Microsoft Intune MAM/}));
|
||||
|
||||
this.authProvider = new DropdownSetting(
|
||||
this.body.locator('.form-group').filter({hasText: 'Auth Provider:'}),
|
||||
'Auth Provider:',
|
||||
);
|
||||
this.tenantId = new TextInputSetting(
|
||||
this.body.locator('.form-group').filter({hasText: 'Tenant ID:'}),
|
||||
'Tenant ID:',
|
||||
);
|
||||
this.clientId = new TextInputSetting(
|
||||
this.body.locator('.form-group').filter({hasText: 'Application (Client) ID:'}),
|
||||
'Application (Client) ID:',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,155 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {Locator, expect} from '@playwright/test';
|
||||
|
||||
/**
|
||||
* System Console -> Reporting -> Team Statistics
|
||||
*/
|
||||
export default class TeamStatistics {
|
||||
readonly container: Locator;
|
||||
readonly header: Locator;
|
||||
|
||||
// Team filter
|
||||
readonly teamFilterDropdown: Locator;
|
||||
|
||||
// Banner
|
||||
readonly banner: Locator;
|
||||
|
||||
// Statistics cards
|
||||
readonly totalActivatedUsers: StatCard;
|
||||
readonly publicChannels: StatCard;
|
||||
readonly privateChannels: StatCard;
|
||||
readonly totalPosts: StatCard;
|
||||
|
||||
// Charts
|
||||
readonly totalPostsChart: ChartSection;
|
||||
readonly activeUsersWithPostsChart: ChartSection;
|
||||
|
||||
// Tables
|
||||
readonly recentActiveUsers: TableSection;
|
||||
readonly newlyCreatedUsers: TableSection;
|
||||
|
||||
constructor(container: Locator) {
|
||||
this.container = container;
|
||||
this.header = container.locator('.team-statistics__header');
|
||||
|
||||
this.teamFilterDropdown = container.getByTestId('teamFilter');
|
||||
|
||||
this.banner = container.locator('.banner');
|
||||
|
||||
const gridStatistics = container.locator('.grid-statistics');
|
||||
this.totalActivatedUsers = new StatCard(
|
||||
gridStatistics.locator('.grid-statistics__card').filter({hasText: 'Total Activated Users'}),
|
||||
);
|
||||
this.publicChannels = new StatCard(
|
||||
gridStatistics.locator('.grid-statistics__card').filter({hasText: 'Public Channels'}),
|
||||
);
|
||||
this.privateChannels = new StatCard(
|
||||
gridStatistics.locator('.grid-statistics__card').filter({hasText: 'Private Channels'}),
|
||||
);
|
||||
this.totalPosts = new StatCard(
|
||||
gridStatistics.locator('.grid-statistics__card').filter({hasText: 'Total Posts'}),
|
||||
);
|
||||
|
||||
this.totalPostsChart = new ChartSection(
|
||||
container.locator('.total-count.by-day').filter({hasText: 'Total Posts'}),
|
||||
);
|
||||
this.activeUsersWithPostsChart = new ChartSection(
|
||||
container.locator('.total-count.by-day').filter({hasText: 'Active Users With Posts'}),
|
||||
);
|
||||
|
||||
this.recentActiveUsers = new TableSection(
|
||||
container.locator('.recent-active-users').filter({hasText: 'Recent Active Users'}),
|
||||
);
|
||||
this.newlyCreatedUsers = new TableSection(
|
||||
container.locator('.recent-active-users').filter({hasText: 'Newly Created Users'}),
|
||||
);
|
||||
}
|
||||
|
||||
async toBeVisible() {
|
||||
await expect(this.container).toBeVisible();
|
||||
await expect(this.header).toBeVisible();
|
||||
}
|
||||
|
||||
async selectTeam(teamName: string) {
|
||||
// Wait for the dropdown to be enabled (it may be disabled while loading)
|
||||
await expect(this.teamFilterDropdown).toBeEnabled();
|
||||
await this.teamFilterDropdown.selectOption({label: teamName});
|
||||
}
|
||||
|
||||
async selectTeamById(teamId: string) {
|
||||
// Wait for the dropdown to be enabled (it may be disabled while loading)
|
||||
await expect(this.teamFilterDropdown).toBeEnabled();
|
||||
await this.teamFilterDropdown.selectOption({value: teamId});
|
||||
}
|
||||
|
||||
async getSelectedTeam(): Promise<string> {
|
||||
return (await this.teamFilterDropdown.inputValue()) ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify the team statistics header shows the expected team name
|
||||
*/
|
||||
async toHaveTeamHeader(teamDisplayName: string) {
|
||||
const heading = this.container.getByText(`Team Statistics for ${teamDisplayName}`, {exact: true});
|
||||
await expect(heading).toBeVisible();
|
||||
}
|
||||
}
|
||||
|
||||
class StatCard {
|
||||
readonly container: Locator;
|
||||
readonly title: Locator;
|
||||
readonly value: Locator;
|
||||
|
||||
constructor(container: Locator) {
|
||||
this.container = container;
|
||||
this.title = container.locator('.title');
|
||||
this.value = container.locator('.content');
|
||||
}
|
||||
|
||||
async toBeVisible() {
|
||||
await expect(this.container).toBeVisible();
|
||||
}
|
||||
|
||||
async getValue(): Promise<string> {
|
||||
return (await this.value.textContent()) ?? '';
|
||||
}
|
||||
}
|
||||
|
||||
class ChartSection {
|
||||
readonly container: Locator;
|
||||
readonly title: Locator;
|
||||
readonly content: Locator;
|
||||
|
||||
constructor(container: Locator) {
|
||||
this.container = container;
|
||||
this.title = container.locator('.title');
|
||||
this.content = container.locator('.content');
|
||||
}
|
||||
|
||||
async toBeVisible() {
|
||||
await expect(this.container).toBeVisible();
|
||||
}
|
||||
|
||||
async hasNoData(): Promise<boolean> {
|
||||
const text = await this.content.textContent();
|
||||
return text?.includes('Not enough data') ?? false;
|
||||
}
|
||||
}
|
||||
|
||||
class TableSection {
|
||||
readonly container: Locator;
|
||||
readonly title: Locator;
|
||||
readonly table: Locator;
|
||||
|
||||
constructor(container: Locator) {
|
||||
this.container = container;
|
||||
this.title = container.locator('.title');
|
||||
this.table = container.locator('table');
|
||||
}
|
||||
|
||||
async toBeVisible() {
|
||||
await expect(this.container).toBeVisible();
|
||||
}
|
||||
}
|
||||
|
|
@ -3,75 +3,98 @@
|
|||
|
||||
import {Locator, expect} from '@playwright/test';
|
||||
|
||||
import {RadioSetting, TextInputSetting, DropdownSetting} from '../../base_components';
|
||||
|
||||
/**
|
||||
* System Console -> Site Configuration -> Notifications
|
||||
*/
|
||||
export default class SystemConsoleNotifications {
|
||||
export default class Notifications {
|
||||
readonly container: Locator;
|
||||
|
||||
// header
|
||||
// Header
|
||||
readonly header: Locator;
|
||||
|
||||
// Notification Display Name
|
||||
readonly notificationDisplayName: Locator;
|
||||
readonly notificationDisplayNameInput: Locator;
|
||||
readonly notificationDisplayNameHelpText: Locator;
|
||||
// Radio Settings
|
||||
readonly showMentionConfirmDialog: RadioSetting;
|
||||
readonly enableEmailNotifications: RadioSetting;
|
||||
readonly enablePreviewModeBanner: RadioSetting;
|
||||
readonly enableEmailBatching: RadioSetting;
|
||||
readonly enableNotificationMonitoring: RadioSetting;
|
||||
|
||||
// Notification From Address
|
||||
readonly notificationFromAddress: Locator;
|
||||
readonly notificationFromAddressInput: Locator;
|
||||
readonly notificationFromAddressHelpText: Locator;
|
||||
// Dropdown Settings
|
||||
readonly emailNotificationContents: DropdownSetting;
|
||||
readonly pushNotificationContents: DropdownSetting;
|
||||
|
||||
// Support Email Address
|
||||
readonly supportEmailAddress: Locator;
|
||||
readonly supportEmailAddressInput: Locator;
|
||||
readonly supportEmailHelpText: Locator;
|
||||
// Text Input Settings
|
||||
readonly notificationDisplayName: TextInputSetting;
|
||||
readonly notificationFromAddress: TextInputSetting;
|
||||
readonly supportEmailAddress: TextInputSetting;
|
||||
readonly notificationReplyToAddress: TextInputSetting;
|
||||
readonly notificationFooterMailingAddress: TextInputSetting;
|
||||
|
||||
// Push Notification Contents
|
||||
readonly pushNotificationContents: Locator;
|
||||
readonly pushNotificationContentsDropdown: Locator;
|
||||
readonly pushNotificationContentsHelpText: Locator;
|
||||
|
||||
// Save button
|
||||
// Save section
|
||||
readonly saveButton: Locator;
|
||||
readonly errorMessage: Locator;
|
||||
|
||||
constructor(container: Locator) {
|
||||
this.container = container;
|
||||
|
||||
// header
|
||||
this.header = this.container.locator('.admin-console__header').getByText('Notifications');
|
||||
this.header = container.getByText('Notifications', {exact: true});
|
||||
|
||||
// Notification Display Name
|
||||
this.notificationDisplayName = this.container.getByTestId('EmailSettings.FeedbackNameinput');
|
||||
this.notificationDisplayNameInput = this.container.getByTestId('EmailSettings.FeedbackNameinput');
|
||||
this.notificationDisplayNameHelpText = this.container.getByTestId('EmailSettings.FeedbackNamehelp-text');
|
||||
|
||||
// Notification From Address
|
||||
this.notificationFromAddress = this.container.getByLabel('Notification From Address:');
|
||||
this.notificationFromAddressInput = this.container.getByTestId('EmailSettings.FeedbackEmailinput');
|
||||
this.notificationFromAddressHelpText = this.container.getByTestId('EmailSettings.FeedbackEmailhelp-text');
|
||||
|
||||
// Support Email Address
|
||||
this.supportEmailAddress = this.container.getByLabel('Support Email Address:');
|
||||
this.supportEmailAddressInput = this.container.getByTestId('SupportSettings.SupportEmailinput');
|
||||
this.supportEmailHelpText = this.container.getByTestId('SupportSettings.SupportEmailhelp-text');
|
||||
|
||||
// Push Notification Contents
|
||||
this.pushNotificationContents = this.container.getByTestId('EmailSettings.PushNotificationContents');
|
||||
this.pushNotificationContentsDropdown = this.container.getByTestId(
|
||||
'EmailSettings.PushNotificationContentsdropdown',
|
||||
this.showMentionConfirmDialog = new RadioSetting(
|
||||
container.getByRole('group', {name: /Show @channel, @all, @here and group mention confirmation dialog/}),
|
||||
);
|
||||
this.pushNotificationContentsHelpText = this.container.getByTestId(
|
||||
'EmailSettings.PushNotificationContentshelp-text',
|
||||
this.enableEmailNotifications = new RadioSetting(
|
||||
container.getByRole('group', {name: /Enable Email Notifications/}),
|
||||
);
|
||||
this.enablePreviewModeBanner = new RadioSetting(
|
||||
container.getByRole('group', {name: /Enable Preview Mode Banner/}),
|
||||
);
|
||||
this.enableEmailBatching = new RadioSetting(container.getByRole('group', {name: /Enable Email Batching/}));
|
||||
this.enableNotificationMonitoring = new RadioSetting(
|
||||
container.getByRole('group', {name: /Enable Notification Monitoring/}),
|
||||
);
|
||||
|
||||
// Save button and error message
|
||||
this.saveButton = this.container.getByTestId('saveSetting');
|
||||
this.errorMessage = this.container.locator('.has-error');
|
||||
this.emailNotificationContents = new DropdownSetting(
|
||||
container.locator('.form-group').filter({hasText: 'Email Notification Contents:'}),
|
||||
'Email Notification Contents:',
|
||||
);
|
||||
this.pushNotificationContents = new DropdownSetting(
|
||||
container.locator('.form-group').filter({hasText: 'Push Notification Contents:'}),
|
||||
'Push Notification Contents:',
|
||||
);
|
||||
|
||||
this.notificationDisplayName = new TextInputSetting(
|
||||
container.locator('.form-group').filter({hasText: 'Notification Display Name:'}),
|
||||
'Notification Display Name:',
|
||||
);
|
||||
this.notificationFromAddress = new TextInputSetting(
|
||||
container.locator('.form-group').filter({hasText: 'Notification From Address:'}),
|
||||
'Notification From Address:',
|
||||
);
|
||||
this.supportEmailAddress = new TextInputSetting(
|
||||
container.locator('.form-group').filter({hasText: 'Support Email Address:'}),
|
||||
'Support Email Address:',
|
||||
);
|
||||
this.notificationReplyToAddress = new TextInputSetting(
|
||||
container.locator('.form-group').filter({hasText: 'Notification Reply-To Address:'}),
|
||||
'Notification Reply-To Address:',
|
||||
);
|
||||
this.notificationFooterMailingAddress = new TextInputSetting(
|
||||
container.locator('.form-group').filter({hasText: 'Notification Footer Mailing Address:'}),
|
||||
'Notification Footer Mailing Address:',
|
||||
);
|
||||
|
||||
this.saveButton = container.getByRole('button', {name: 'Save'});
|
||||
this.errorMessage = container.locator('.has-error');
|
||||
}
|
||||
|
||||
async toBeVisible() {
|
||||
await expect(this.container).toBeVisible();
|
||||
await expect(this.header).toBeVisible();
|
||||
}
|
||||
|
||||
async save() {
|
||||
await this.saveButton.click();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,50 +0,0 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {Locator, expect} from '@playwright/test';
|
||||
|
||||
export default class SystemUsersColumnToggleMenu {
|
||||
readonly container: Locator;
|
||||
|
||||
constructor(container: Locator) {
|
||||
this.container = container;
|
||||
}
|
||||
|
||||
async toBeVisible() {
|
||||
await expect(this.container).toBeVisible();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the locator for the menu item with the given name.
|
||||
*/
|
||||
async getMenuItem(menuItem: string) {
|
||||
const menuItemLocator = this.container.getByRole('menuitemcheckbox').filter({hasText: menuItem});
|
||||
await menuItemLocator.waitFor();
|
||||
|
||||
return menuItemLocator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of locators for all the menu items.
|
||||
*/
|
||||
async getAllMenuItems() {
|
||||
const menuItemLocators = this.container.getByRole('menuitemcheckbox');
|
||||
return menuItemLocators;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pass in the item name to check/uncheck the menu item.
|
||||
*/
|
||||
async clickMenuItem(menuItem: string) {
|
||||
const menuItemLocator = await this.getMenuItem(menuItem);
|
||||
await menuItemLocator.click();
|
||||
}
|
||||
|
||||
/**
|
||||
* Close column toggle menu.
|
||||
*/
|
||||
async close() {
|
||||
await this.container.press('Escape');
|
||||
await expect(this.container).not.toBeVisible();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,44 +0,0 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {Locator, expect} from '@playwright/test';
|
||||
|
||||
/**
|
||||
* The dropdown menu which appears for both Role and Status filter.
|
||||
*/
|
||||
export default class SystemUsersFilterMenu {
|
||||
readonly container: Locator;
|
||||
|
||||
constructor(container: Locator) {
|
||||
this.container = container;
|
||||
}
|
||||
|
||||
async toBeVisible() {
|
||||
await expect(this.container).toBeVisible();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the locator for the menu item with the given name.
|
||||
*/
|
||||
async getMenuItem(menuItem: string) {
|
||||
const menuItemLocator = this.container.getByText(menuItem);
|
||||
await menuItemLocator.waitFor();
|
||||
|
||||
return menuItemLocator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clicks on the menu item with the given name.
|
||||
*/
|
||||
async clickMenuItem(menuItem: string) {
|
||||
const menuItemLocator = await this.getMenuItem(menuItem);
|
||||
await menuItemLocator.click();
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the menu.
|
||||
*/
|
||||
async close() {
|
||||
await this.container.press('Escape');
|
||||
}
|
||||
}
|
||||
|
|
@ -1,68 +0,0 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {Locator, expect} from '@playwright/test';
|
||||
|
||||
export default class SystemUsersFilterPopover {
|
||||
readonly container: Locator;
|
||||
|
||||
readonly teamMenuInput: Locator;
|
||||
readonly roleMenuButton: Locator;
|
||||
readonly statusMenuButton: Locator;
|
||||
|
||||
readonly applyButton: Locator;
|
||||
|
||||
constructor(container: Locator) {
|
||||
this.container = container;
|
||||
|
||||
this.teamMenuInput = this.container.locator('#asyncTeamSelectInput');
|
||||
this.roleMenuButton = this.container.locator('#DropdownInput_filterRole');
|
||||
this.statusMenuButton = this.container.locator('#DropdownInput_filterStatus');
|
||||
|
||||
this.applyButton = this.container.getByText('Apply');
|
||||
}
|
||||
|
||||
async toBeVisible() {
|
||||
await expect(this.container).toBeVisible();
|
||||
await expect(this.applyButton).toBeVisible();
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the filter settings.
|
||||
*/
|
||||
async save() {
|
||||
await this.applyButton.click();
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows to type in the team filter for searching.
|
||||
*/
|
||||
async searchInTeamMenu(teamDisplayName: string) {
|
||||
expect(this.teamMenuInput).toBeVisible();
|
||||
await this.teamMenuInput.fill(teamDisplayName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens the role filter menu.
|
||||
*/
|
||||
async openRoleMenu() {
|
||||
expect(this.roleMenuButton).toBeVisible();
|
||||
await this.roleMenuButton.click();
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens the status filter menu.
|
||||
*/
|
||||
async openStatusMenu() {
|
||||
expect(this.statusMenuButton).toBeVisible();
|
||||
await this.statusMenuButton.click();
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the filter popover.
|
||||
*/
|
||||
async close() {
|
||||
await this.container.press('Escape');
|
||||
await expect(this.container).not.toBeVisible();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,185 +0,0 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {expect, Locator, Page} from '@playwright/test';
|
||||
|
||||
/**
|
||||
* System Console -> Environment -> Mobile Security
|
||||
*/
|
||||
export default class MobileSecurity {
|
||||
readonly page: Page;
|
||||
readonly container: Locator;
|
||||
|
||||
readonly enableBiometricAuthenticationToggleTrue: Locator;
|
||||
readonly enableBiometricAuthenticationToggleFalse: Locator;
|
||||
readonly preventScreenCaptureToggleTrue: Locator;
|
||||
readonly preventScreenCaptureToggleFalse: Locator;
|
||||
readonly jailbreakProtectionToggleTrue: Locator;
|
||||
readonly jailbreakProtectionToggleFalse: Locator;
|
||||
readonly enableSecureFilePreviewToggleTrue: Locator;
|
||||
readonly enableSecureFilePreviewToggleFalse: Locator;
|
||||
readonly allowPdfLinkNavigationToggleTrue: Locator;
|
||||
readonly allowPdfLinkNavigationToggleFalse: Locator;
|
||||
readonly enableIntuneMAMToggleTrue: Locator;
|
||||
readonly enableIntuneMAMToggleFalse: Locator;
|
||||
|
||||
// New IntuneSettings fields
|
||||
readonly enableIntuneToggleTrue: Locator;
|
||||
readonly enableIntuneToggleFalse: Locator;
|
||||
readonly intuneAuthServiceDropdown: Locator;
|
||||
readonly intuneTenantIdInput: Locator;
|
||||
readonly intuneClientIdInput: Locator;
|
||||
readonly intuneTenantIdRequiredError: Locator;
|
||||
|
||||
readonly saveButton: Locator;
|
||||
|
||||
constructor(container: Locator, page: Page) {
|
||||
this.container = container;
|
||||
this.page = page;
|
||||
|
||||
this.enableBiometricAuthenticationToggleTrue = this.container.getByTestId(
|
||||
'NativeAppSettings.MobileEnableBiometricstrue',
|
||||
);
|
||||
this.enableBiometricAuthenticationToggleFalse = this.container.getByTestId(
|
||||
'NativeAppSettings.MobileEnableBiometricsfalse',
|
||||
);
|
||||
|
||||
this.preventScreenCaptureToggleTrue = this.container.getByTestId(
|
||||
'NativeAppSettings.MobilePreventScreenCapturetrue',
|
||||
);
|
||||
this.preventScreenCaptureToggleFalse = this.container.getByTestId(
|
||||
'NativeAppSettings.MobilePreventScreenCapturefalse',
|
||||
);
|
||||
|
||||
this.jailbreakProtectionToggleTrue = this.container.getByTestId(
|
||||
'NativeAppSettings.MobileJailbreakProtectiontrue',
|
||||
);
|
||||
this.jailbreakProtectionToggleFalse = this.container.getByTestId(
|
||||
'NativeAppSettings.MobileJailbreakProtectionfalse',
|
||||
);
|
||||
|
||||
this.jailbreakProtectionToggleTrue = this.container.getByTestId(
|
||||
'NativeAppSettings.MobileJailbreakProtectiontrue',
|
||||
);
|
||||
this.jailbreakProtectionToggleFalse = this.container.getByTestId(
|
||||
'NativeAppSettings.MobileJailbreakProtectionfalse',
|
||||
);
|
||||
|
||||
this.enableSecureFilePreviewToggleTrue = this.container.getByTestId(
|
||||
'NativeAppSettings.MobileEnableSecureFilePreviewtrue',
|
||||
);
|
||||
this.enableSecureFilePreviewToggleFalse = this.container.getByTestId(
|
||||
'NativeAppSettings.MobileEnableSecureFilePreviewfalse',
|
||||
);
|
||||
|
||||
this.allowPdfLinkNavigationToggleTrue = this.container.getByTestId(
|
||||
'NativeAppSettings.MobileAllowPdfLinkNavigationtrue',
|
||||
);
|
||||
this.allowPdfLinkNavigationToggleFalse = this.container.getByTestId(
|
||||
'NativeAppSettings.MobileAllowPdfLinkNavigationfalse',
|
||||
);
|
||||
|
||||
// Legacy Intune toggle (will be removed in Phase 6)
|
||||
this.enableIntuneMAMToggleTrue = this.container.getByTestId('IntuneSettings.Enabletrue');
|
||||
this.enableIntuneMAMToggleFalse = this.container.getByTestId('IntuneSettings.Enablefalse');
|
||||
|
||||
// New IntuneSettings fields
|
||||
this.enableIntuneToggleTrue = this.container.getByTestId('IntuneSettings.Enabletrue');
|
||||
this.enableIntuneToggleFalse = this.container.getByTestId('IntuneSettings.Enablefalse');
|
||||
this.intuneAuthServiceDropdown = this.container.getByTestId('IntuneSettings.AuthServicedropdown');
|
||||
this.intuneTenantIdInput = this.container.getByTestId('IntuneSettings.TenantIdinput');
|
||||
this.intuneClientIdInput = this.container.getByTestId('IntuneSettings.ClientIdinput');
|
||||
this.intuneTenantIdRequiredError = this.container.getByTestId('errorMessage');
|
||||
|
||||
this.saveButton = this.container.getByRole('button', {name: 'Save'});
|
||||
}
|
||||
|
||||
async discardChanges() {
|
||||
this.page.getByRole('button', {name: 'Yes, Discard'}).click();
|
||||
}
|
||||
|
||||
async intuneTenantIdRequiredErrorToBeVisible() {
|
||||
await expect(this.intuneTenantIdRequiredError).toBeVisible();
|
||||
}
|
||||
|
||||
async toBeVisible() {
|
||||
await expect(this.container).toBeVisible();
|
||||
}
|
||||
|
||||
async clickEnableBiometricAuthenticationToggleTrue() {
|
||||
await this.enableBiometricAuthenticationToggleTrue.click();
|
||||
}
|
||||
|
||||
async clickEnableBiometricAuthenticationToggleFalse() {
|
||||
await this.enableBiometricAuthenticationToggleFalse.click();
|
||||
}
|
||||
|
||||
async clickPreventScreenCaptureToggleTrue() {
|
||||
await this.preventScreenCaptureToggleTrue.click();
|
||||
}
|
||||
|
||||
async clickPreventScreenCaptureToggleFalse() {
|
||||
await this.preventScreenCaptureToggleFalse.click();
|
||||
}
|
||||
|
||||
async clickJailbreakProtectionToggleTrue() {
|
||||
await this.jailbreakProtectionToggleTrue.click();
|
||||
}
|
||||
|
||||
async clickJailbreakProtectionToggleFalse() {
|
||||
await this.jailbreakProtectionToggleFalse.click();
|
||||
}
|
||||
|
||||
async clickEnableSecureFilePreviewToggleTrue() {
|
||||
await this.enableSecureFilePreviewToggleTrue.click();
|
||||
}
|
||||
|
||||
async clickEnableSecureFilePreviewToggleFalse() {
|
||||
await this.enableSecureFilePreviewToggleFalse.click();
|
||||
}
|
||||
|
||||
async clickAllowPdfLinkNavigationToggleTrue() {
|
||||
await this.allowPdfLinkNavigationToggleTrue.click();
|
||||
}
|
||||
|
||||
async clickAllowPdfLinkNavigationToggleFalse() {
|
||||
await this.allowPdfLinkNavigationToggleFalse.click();
|
||||
}
|
||||
|
||||
async clickEnableIntuneMAMToggleTrue() {
|
||||
await this.enableIntuneMAMToggleTrue.click();
|
||||
}
|
||||
|
||||
async selectAuthProvider(value: 'office365' | 'saml') {
|
||||
await this.intuneAuthServiceDropdown.selectOption(value);
|
||||
}
|
||||
|
||||
async clickEnableIntuneMAMToggleFalse() {
|
||||
await this.enableIntuneMAMToggleFalse.click();
|
||||
}
|
||||
|
||||
// New IntuneSettings methods
|
||||
async clickEnableIntuneToggleTrue() {
|
||||
await this.enableIntuneToggleTrue.click();
|
||||
}
|
||||
|
||||
async clickEnableIntuneToggleFalse() {
|
||||
await this.enableIntuneToggleFalse.click();
|
||||
}
|
||||
|
||||
async selectIntuneAuthService(value: 'office365' | 'saml') {
|
||||
await this.intuneAuthServiceDropdown.selectOption(value);
|
||||
}
|
||||
|
||||
async fillIntuneTenantId(value: string) {
|
||||
await this.intuneTenantIdInput.fill(value);
|
||||
}
|
||||
|
||||
async fillIntuneClientId(value: string) {
|
||||
await this.intuneClientIdInput.fill(value);
|
||||
}
|
||||
|
||||
async clickSaveButton() {
|
||||
await this.saveButton.click();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,132 +0,0 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {Locator, expect} from '@playwright/test';
|
||||
|
||||
/**
|
||||
* System Console -> User Management -> Users
|
||||
*/
|
||||
export default class SystemUsers {
|
||||
readonly container: Locator;
|
||||
|
||||
readonly searchInput: Locator;
|
||||
readonly saveRoleChange: Locator;
|
||||
readonly columnToggleMenuButton: Locator;
|
||||
readonly dateRangeSelectorMenuButton: Locator;
|
||||
readonly exportButton: Locator;
|
||||
readonly filterPopoverButton: Locator;
|
||||
readonly actionMenuButtons: Locator[];
|
||||
|
||||
readonly loadingSpinner: Locator;
|
||||
|
||||
constructor(container: Locator) {
|
||||
this.container = container;
|
||||
|
||||
this.searchInput = this.container.getByLabel('Search users');
|
||||
this.saveRoleChange = this.container.locator('button.btn-primary:has-text("Save")');
|
||||
this.columnToggleMenuButton = this.container.locator('#systemUsersColumnTogglerMenuButton');
|
||||
this.dateRangeSelectorMenuButton = this.container.locator('#systemUsersDateRangeSelectorMenuButton');
|
||||
this.exportButton = this.container.getByText('Export');
|
||||
this.filterPopoverButton = this.container.getByText(/Filters \(\d+\)/);
|
||||
this.actionMenuButtons = Array.from(Array(10).keys()).map((index) =>
|
||||
this.container.locator(`#actionMenuButton-systemUsersTable-${index}`),
|
||||
);
|
||||
|
||||
this.loadingSpinner = this.container.getByText('Loading');
|
||||
}
|
||||
|
||||
async toBeVisible() {
|
||||
await expect(this.container).toBeVisible();
|
||||
}
|
||||
|
||||
async isLoadingComplete() {
|
||||
await expect(this.loadingSpinner).toHaveCount(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the locator for the header of the given column.
|
||||
*/
|
||||
async getColumnHeader(columnName: string) {
|
||||
const columnHeader = this.container.getByRole('columnheader').filter({hasText: columnName});
|
||||
return columnHeader;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if given column exists in the table. By searching for the column header.
|
||||
*/
|
||||
async doesColumnExist(columnName: string) {
|
||||
const columnHeader = await this.getColumnHeader(columnName);
|
||||
return await columnHeader.isVisible();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clicks on the column header of the given column for sorting.
|
||||
*/
|
||||
async clickSortOnColumn(columnName: string) {
|
||||
const columnHeader = await this.getColumnHeader(columnName);
|
||||
await columnHeader.waitFor();
|
||||
await columnHeader.click();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the locator for the given row number. If '0' is passed, it will return the header row.
|
||||
*/
|
||||
async getNthRow(rowNumber: number) {
|
||||
const row = this.container.getByRole('row').nth(rowNumber);
|
||||
await row.waitFor();
|
||||
|
||||
return row;
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens the Filter popover
|
||||
*/
|
||||
async openFilterPopover() {
|
||||
expect(this.filterPopoverButton).toBeVisible();
|
||||
await this.filterPopoverButton.click();
|
||||
}
|
||||
|
||||
/**
|
||||
* Open the column toggle menu
|
||||
*/
|
||||
async openColumnToggleMenu() {
|
||||
expect(this.columnToggleMenuButton).toBeVisible();
|
||||
await this.columnToggleMenuButton.click();
|
||||
}
|
||||
|
||||
/**
|
||||
* Open the date range selector menu
|
||||
*/
|
||||
async openDateRangeSelectorMenu() {
|
||||
expect(this.dateRangeSelectorMenuButton).toBeVisible();
|
||||
await this.dateRangeSelectorMenuButton.click();
|
||||
}
|
||||
|
||||
/**
|
||||
* Enter the given search term in the search input
|
||||
*/
|
||||
async enterSearchText(searchText: string) {
|
||||
expect(this.searchInput).toBeVisible();
|
||||
await this.searchInput.fill(`${searchText}`);
|
||||
|
||||
await this.isLoadingComplete();
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches and verifies that the row with given text is found
|
||||
*/
|
||||
async verifyRowWithTextIsFound(text: string) {
|
||||
const foundUser = this.container.getByText(text);
|
||||
await foundUser.waitFor();
|
||||
|
||||
await expect(foundUser).toBeVisible();
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches and verifies that the row with given text is not found
|
||||
*/
|
||||
async verifyRowWithTextIsNotFound(text: string) {
|
||||
const foundUser = this.container.getByText(text);
|
||||
await expect(foundUser).not.toBeVisible();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,154 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {Locator, expect} from '@playwright/test';
|
||||
|
||||
import SystemRoles from './system_roles';
|
||||
|
||||
/**
|
||||
* System Console -> User Management -> Delegated Granular Administration
|
||||
*/
|
||||
export default class DelegatedGranularAdministration {
|
||||
readonly container: Locator;
|
||||
readonly header: Locator;
|
||||
|
||||
// Admin Roles Panel
|
||||
readonly adminRolesPanel: AdminRolesPanel;
|
||||
|
||||
// System Roles page (accessed by clicking Edit on a role row)
|
||||
readonly systemRoles: SystemRoles;
|
||||
|
||||
constructor(container: Locator) {
|
||||
this.container = container;
|
||||
this.header = container.getByText('Delegated Granular Administration', {exact: true});
|
||||
|
||||
this.adminRolesPanel = new AdminRolesPanel(container.locator('#SystemRoles'));
|
||||
|
||||
// System Roles page (click Edit on a role to navigate here)
|
||||
this.systemRoles = new SystemRoles(container);
|
||||
}
|
||||
|
||||
async toBeVisible() {
|
||||
await expect(this.container).toBeVisible();
|
||||
await expect(this.header).toBeVisible();
|
||||
}
|
||||
}
|
||||
|
||||
class AdminRolesPanel {
|
||||
readonly container: Locator;
|
||||
readonly title: Locator;
|
||||
readonly description: Locator;
|
||||
private readonly dataGrid: DataGrid;
|
||||
|
||||
constructor(container: Locator) {
|
||||
this.container = container;
|
||||
this.title = container.getByRole('heading', {name: 'Admin Roles'});
|
||||
this.description = container.getByText('Manage different levels of access to the system console.');
|
||||
this.dataGrid = new DataGrid(container.locator('.DataGrid'));
|
||||
}
|
||||
|
||||
async toBeVisible() {
|
||||
await expect(this.container).toBeVisible();
|
||||
await expect(this.title).toBeVisible();
|
||||
}
|
||||
|
||||
// Shortcuts to role rows
|
||||
get systemAdmin() {
|
||||
return this.dataGrid.systemAdmin;
|
||||
}
|
||||
get systemManager() {
|
||||
return this.dataGrid.systemManager;
|
||||
}
|
||||
get userManager() {
|
||||
return this.dataGrid.userManager;
|
||||
}
|
||||
get customGroupManager() {
|
||||
return this.dataGrid.customGroupManager;
|
||||
}
|
||||
get viewer() {
|
||||
return this.dataGrid.viewer;
|
||||
}
|
||||
}
|
||||
|
||||
class DataGrid {
|
||||
readonly container: Locator;
|
||||
readonly header: Locator;
|
||||
readonly rows: Locator;
|
||||
|
||||
// Role rows
|
||||
readonly systemAdmin: RoleRow;
|
||||
readonly systemManager: RoleRow;
|
||||
readonly userManager: RoleRow;
|
||||
readonly customGroupManager: RoleRow;
|
||||
readonly viewer: RoleRow;
|
||||
|
||||
constructor(container: Locator) {
|
||||
this.container = container;
|
||||
this.header = container.locator('.DataGrid_header');
|
||||
this.rows = container.locator('.DataGrid_rows');
|
||||
|
||||
// Individual role rows
|
||||
this.systemAdmin = new RoleRow(
|
||||
this.rows.locator('.DataGrid_row').filter({hasText: 'System Admin'}),
|
||||
'system_admin_edit',
|
||||
);
|
||||
this.systemManager = new RoleRow(
|
||||
this.rows.locator('.DataGrid_row').filter({hasText: 'System Manager'}),
|
||||
'system_manager_edit',
|
||||
);
|
||||
this.userManager = new RoleRow(
|
||||
this.rows.locator('.DataGrid_row').filter({hasText: 'User Manager'}),
|
||||
'system_user_manager_edit',
|
||||
);
|
||||
this.customGroupManager = new RoleRow(
|
||||
this.rows.locator('.DataGrid_row').filter({hasText: 'Custom Group Manager'}),
|
||||
'system_custom_group_admin_edit',
|
||||
);
|
||||
this.viewer = new RoleRow(
|
||||
this.rows.locator('.DataGrid_row').filter({hasText: 'Viewer'}),
|
||||
'system_read_only_admin_edit',
|
||||
);
|
||||
}
|
||||
|
||||
async toBeVisible() {
|
||||
await expect(this.container).toBeVisible();
|
||||
}
|
||||
}
|
||||
|
||||
class RoleRow {
|
||||
readonly container: Locator;
|
||||
readonly roleName: Locator;
|
||||
readonly description: Locator;
|
||||
readonly type: Locator;
|
||||
readonly editLink: Locator;
|
||||
|
||||
constructor(container: Locator, editTestId: string) {
|
||||
this.container = container;
|
||||
|
||||
const cells = container.locator('.DataGrid_cell');
|
||||
this.roleName = cells.nth(0);
|
||||
this.description = cells.nth(1);
|
||||
this.type = cells.nth(2);
|
||||
this.editLink = container.getByTestId(editTestId).getByRole('link', {name: 'Edit'});
|
||||
}
|
||||
|
||||
async toBeVisible() {
|
||||
await expect(this.container).toBeVisible();
|
||||
}
|
||||
|
||||
async clickEdit() {
|
||||
await this.editLink.click();
|
||||
}
|
||||
|
||||
async getRoleName(): Promise<string> {
|
||||
return (await this.roleName.textContent()) ?? '';
|
||||
}
|
||||
|
||||
async getDescription(): Promise<string> {
|
||||
return (await this.description.textContent()) ?? '';
|
||||
}
|
||||
|
||||
async getType(): Promise<string> {
|
||||
return (await this.type.textContent()) ?? '';
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,392 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {Locator, expect} from '@playwright/test';
|
||||
|
||||
/**
|
||||
* System Console -> User Management -> Delegated Granular Administration -> [Role] Edit
|
||||
* This page is shown when editing a specific role (e.g., System Manager, User Manager, etc.)
|
||||
*/
|
||||
export default class SystemRoles {
|
||||
readonly container: Locator;
|
||||
|
||||
// Header
|
||||
readonly backLink: Locator;
|
||||
readonly roleName: Locator;
|
||||
|
||||
// Privileges Panel
|
||||
readonly privilegesPanel: PrivilegesPanel;
|
||||
|
||||
// Assigned People Panel
|
||||
readonly assignedPeoplePanel: AssignedPeoplePanel;
|
||||
|
||||
// Save section
|
||||
readonly saveButton: Locator;
|
||||
readonly cancelButton: Locator;
|
||||
readonly errorMessage: Locator;
|
||||
|
||||
constructor(container: Locator) {
|
||||
this.container = container;
|
||||
|
||||
this.backLink = container.locator('.admin-console__header .back');
|
||||
this.roleName = container.locator('.admin-console__header span').last();
|
||||
|
||||
this.privilegesPanel = new PrivilegesPanel(container.locator('#SystemRolePermissions'));
|
||||
this.assignedPeoplePanel = new AssignedPeoplePanel(container.locator('#SystemRoleUsers'));
|
||||
|
||||
this.saveButton = container.getByTestId('saveSetting');
|
||||
this.cancelButton = container.getByRole('link', {name: 'Cancel'});
|
||||
this.errorMessage = container.locator('.error-message');
|
||||
}
|
||||
|
||||
async toBeVisible() {
|
||||
await expect(this.container).toBeVisible();
|
||||
await expect(this.roleName).toBeVisible();
|
||||
}
|
||||
|
||||
async goBack() {
|
||||
await this.backLink.click();
|
||||
}
|
||||
|
||||
async save() {
|
||||
await this.saveButton.click();
|
||||
}
|
||||
|
||||
async cancel() {
|
||||
await this.cancelButton.click();
|
||||
}
|
||||
|
||||
async getRoleName(): Promise<string> {
|
||||
return (await this.roleName.textContent()) ?? '';
|
||||
}
|
||||
}
|
||||
|
||||
class PrivilegesPanel {
|
||||
readonly container: Locator;
|
||||
readonly title: Locator;
|
||||
readonly description: Locator;
|
||||
|
||||
// Permission sections
|
||||
readonly about: PermissionSection;
|
||||
readonly reporting: PermissionSection;
|
||||
readonly userManagement: PermissionSection;
|
||||
readonly environment: PermissionSection;
|
||||
readonly siteConfiguration: PermissionSection;
|
||||
readonly authentication: PermissionSection;
|
||||
readonly plugins: PermissionSection;
|
||||
readonly integrations: PermissionSection;
|
||||
readonly compliance: PermissionSection;
|
||||
readonly experimental: PermissionSection;
|
||||
|
||||
constructor(container: Locator) {
|
||||
this.container = container;
|
||||
this.title = container.getByRole('heading', {name: 'Privileges'});
|
||||
this.description = container.getByText('Level of access to the system console.');
|
||||
|
||||
// Permission sections
|
||||
this.about = new PermissionSection(container, 'permission_section_about');
|
||||
this.reporting = new PermissionSection(container, 'permission_section_reporting');
|
||||
this.userManagement = new PermissionSection(container, 'permission_section_user_management');
|
||||
this.environment = new PermissionSection(container, 'permission_section_environment');
|
||||
this.siteConfiguration = new PermissionSection(container, 'permission_section_site');
|
||||
this.authentication = new PermissionSection(container, 'permission_section_authentication');
|
||||
this.plugins = new PermissionSection(container, 'permission_section_plugins');
|
||||
this.integrations = new PermissionSection(container, 'permission_section_integrations');
|
||||
this.compliance = new PermissionSection(container, 'permission_section_compliance');
|
||||
this.experimental = new PermissionSection(container, 'permission_section_experimental');
|
||||
}
|
||||
|
||||
async toBeVisible() {
|
||||
await expect(this.container).toBeVisible();
|
||||
await expect(this.title).toBeVisible();
|
||||
}
|
||||
}
|
||||
|
||||
class PermissionSection {
|
||||
readonly container: Locator;
|
||||
readonly row: Locator;
|
||||
readonly title: Locator;
|
||||
readonly description: Locator;
|
||||
readonly subsectionsToggle: Locator;
|
||||
readonly dropdownButton: Locator;
|
||||
readonly subsectionsContainer: Locator;
|
||||
|
||||
private readonly panelContainer: Locator;
|
||||
private readonly testId: string;
|
||||
private readonly sectionName: string;
|
||||
|
||||
constructor(panelContainer: Locator, testId: string) {
|
||||
this.panelContainer = panelContainer;
|
||||
this.testId = testId;
|
||||
// Extract section name from testId (e.g., 'permission_section_user_management' -> 'user_management')
|
||||
this.sectionName = testId.replace('permission_section_', '');
|
||||
|
||||
this.container = panelContainer.getByTestId(testId);
|
||||
// Use CSS :has() selector to find the row containing this section
|
||||
this.row = panelContainer.locator(`.PermissionRow:has([data-testid="${testId}"])`);
|
||||
this.title = this.container.locator('.PermissionSectionText_title');
|
||||
this.description = this.container.locator('.PermissionSection_description');
|
||||
this.subsectionsToggle = this.container.locator('.PermissionSubsectionsToggle button');
|
||||
// Use the dropdown button ID which is more reliable
|
||||
this.dropdownButton = panelContainer.page().locator(`#systemRolePermissionDropdown${this.sectionName}`);
|
||||
this.subsectionsContainer = this.row.locator('.PermissionSubsections');
|
||||
}
|
||||
|
||||
async toBeVisible() {
|
||||
await expect(this.container).toBeVisible();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current permission value (e.g., "Can edit", "Read only", "No access", "Mixed access")
|
||||
*/
|
||||
async getPermissionValue(): Promise<string> {
|
||||
return (await this.dropdownButton.locator('.PermissionSectionDropdownButton_text').textContent()) ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Set permission for this section
|
||||
* @param permission - "Can edit", "Read only", or "No access"
|
||||
*/
|
||||
async setPermission(permission: 'Can edit' | 'Read only' | 'No access') {
|
||||
await expect(this.dropdownButton).toBeVisible();
|
||||
await this.dropdownButton.click();
|
||||
|
||||
// Wait for the MenuWrapper to have --open class which indicates menu is open
|
||||
const menuWrapper = this.dropdownButton.locator('xpath=ancestor::div[contains(@class, "MenuWrapper")]');
|
||||
await expect(menuWrapper).toHaveClass(/MenuWrapper--open/);
|
||||
|
||||
// Find the menu items and click the one matching the permission
|
||||
const menuItem = menuWrapper.locator('.Menu__content li').filter({hasText: permission});
|
||||
await expect(menuItem).toBeVisible();
|
||||
await menuItem.click();
|
||||
|
||||
// Wait for menu to close
|
||||
await expect(menuWrapper).not.toHaveClass(/MenuWrapper--open/);
|
||||
}
|
||||
|
||||
/**
|
||||
* Expand subsections if they are collapsed
|
||||
*/
|
||||
async expandSubsections() {
|
||||
const hasToggle = await this.subsectionsToggle.isVisible();
|
||||
if (!hasToggle) {
|
||||
return;
|
||||
}
|
||||
|
||||
const buttonText = await this.subsectionsToggle.textContent();
|
||||
if (buttonText?.includes('Show')) {
|
||||
await this.subsectionsToggle.click();
|
||||
// Wait for subsections to be visible
|
||||
await expect(this.subsectionsContainer).toBeVisible();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Collapse subsections if they are expanded
|
||||
*/
|
||||
async collapseSubsections() {
|
||||
const hasToggle = await this.subsectionsToggle.isVisible();
|
||||
if (!hasToggle) {
|
||||
return;
|
||||
}
|
||||
|
||||
const buttonText = await this.subsectionsToggle.textContent();
|
||||
if (buttonText?.includes('Hide')) {
|
||||
await this.subsectionsToggle.click();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if subsections are visible
|
||||
*/
|
||||
async hasSubsections(): Promise<boolean> {
|
||||
return this.subsectionsToggle.isVisible();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a subsection by its testId suffix
|
||||
* @param subsectionName - The suffix of the subsection testId (e.g., "team_statistics" for "permission_section_reporting_team_statistics")
|
||||
*/
|
||||
getSubsection(subsectionName: string): PermissionSubsection {
|
||||
const subsectionTestId = `${this.testId}_${subsectionName}`;
|
||||
return new PermissionSubsection(this.panelContainer, subsectionTestId);
|
||||
}
|
||||
|
||||
// Reporting subsections shortcuts
|
||||
get siteStatistics() {
|
||||
return this.getSubsection('site_statistics');
|
||||
}
|
||||
get teamStatistics() {
|
||||
return this.getSubsection('team_statistics');
|
||||
}
|
||||
get serverLogs() {
|
||||
return this.getSubsection('server_logs');
|
||||
}
|
||||
|
||||
// User Management subsections shortcuts
|
||||
get users() {
|
||||
return this.getSubsection('users');
|
||||
}
|
||||
get groups() {
|
||||
return this.getSubsection('groups');
|
||||
}
|
||||
get teams() {
|
||||
return this.getSubsection('teams');
|
||||
}
|
||||
get channels() {
|
||||
return this.getSubsection('channels');
|
||||
}
|
||||
get permissions() {
|
||||
return this.getSubsection('permissions');
|
||||
}
|
||||
get systemRoles() {
|
||||
return this.getSubsection('system_roles');
|
||||
}
|
||||
}
|
||||
|
||||
class PermissionSubsection {
|
||||
readonly container: Locator;
|
||||
readonly title: Locator;
|
||||
readonly description: Locator;
|
||||
readonly dropdownButton: Locator;
|
||||
|
||||
private readonly sectionName: string;
|
||||
|
||||
constructor(panelContainer: Locator, testId: string) {
|
||||
this.container = panelContainer.getByTestId(testId);
|
||||
this.title = this.container.locator('.PermissionSectionText_title');
|
||||
this.description = this.container.locator('.PermissionSection_description');
|
||||
// Extract section name from testId (e.g., 'permission_section_user_management_teams' -> 'user_management_teams')
|
||||
this.sectionName = testId.replace('permission_section_', '');
|
||||
// Use the dropdown button ID which is more reliable
|
||||
this.dropdownButton = panelContainer.page().locator(`#systemRolePermissionDropdown${this.sectionName}`);
|
||||
}
|
||||
|
||||
async toBeVisible() {
|
||||
await expect(this.container).toBeVisible();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current permission value (e.g., "Can edit", "Read only", "No access")
|
||||
*/
|
||||
async getPermissionValue(): Promise<string> {
|
||||
return (await this.dropdownButton.locator('.PermissionSectionDropdownButton_text').textContent()) ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Set permission for this subsection
|
||||
* @param permission - "Can edit", "Read only", or "No access"
|
||||
*/
|
||||
async setPermission(permission: 'Can edit' | 'Read only' | 'No access') {
|
||||
// Wait for subsection to be visible
|
||||
await this.toBeVisible();
|
||||
|
||||
// Click the dropdown button to open the menu
|
||||
await expect(this.dropdownButton).toBeVisible();
|
||||
await this.dropdownButton.click();
|
||||
|
||||
// Wait for the MenuWrapper to have --open class which indicates menu is open
|
||||
const menuWrapper = this.dropdownButton.locator('xpath=ancestor::div[contains(@class, "MenuWrapper")]');
|
||||
await expect(menuWrapper).toHaveClass(/MenuWrapper--open/);
|
||||
|
||||
// Find the menu items and click the one matching the permission
|
||||
const menuItem = menuWrapper.locator('.Menu__content li').filter({hasText: permission});
|
||||
await expect(menuItem).toBeVisible();
|
||||
await menuItem.click();
|
||||
|
||||
// Wait for menu to close
|
||||
await expect(menuWrapper).not.toHaveClass(/MenuWrapper--open/);
|
||||
}
|
||||
}
|
||||
|
||||
class AssignedPeoplePanel {
|
||||
readonly container: Locator;
|
||||
readonly title: Locator;
|
||||
readonly description: Locator;
|
||||
readonly addPeopleButton: Locator;
|
||||
readonly searchInput: Locator;
|
||||
readonly userRows: Locator;
|
||||
readonly paginationInfo: Locator;
|
||||
readonly previousPageButton: Locator;
|
||||
readonly nextPageButton: Locator;
|
||||
|
||||
constructor(container: Locator) {
|
||||
this.container = container;
|
||||
this.title = container.getByRole('heading', {name: 'Assigned People'});
|
||||
this.description = container.getByText('List of people assigned to this system role.');
|
||||
this.addPeopleButton = container.getByRole('button', {name: 'Add People'});
|
||||
this.searchInput = container.getByTestId('searchInput');
|
||||
this.userRows = container.locator('.DataGrid_rows .DataGrid_row');
|
||||
this.paginationInfo = container.locator('.DataGrid_footer span');
|
||||
this.previousPageButton = container.locator('.DataGrid_footer .prev');
|
||||
this.nextPageButton = container.locator('.DataGrid_footer .next');
|
||||
}
|
||||
|
||||
async toBeVisible() {
|
||||
await expect(this.container).toBeVisible();
|
||||
await expect(this.title).toBeVisible();
|
||||
}
|
||||
|
||||
async clickAddPeople() {
|
||||
await this.addPeopleButton.click();
|
||||
}
|
||||
|
||||
async searchUsers(searchTerm: string) {
|
||||
await this.searchInput.fill(searchTerm);
|
||||
}
|
||||
|
||||
async clearSearch() {
|
||||
await this.searchInput.clear();
|
||||
}
|
||||
|
||||
async getUserCount(): Promise<number> {
|
||||
return this.userRows.count();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a user row by index (0-based)
|
||||
*/
|
||||
getUserRowByIndex(index: number): AssignedUserRow {
|
||||
return new AssignedUserRow(this.userRows.nth(index));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a user row by username
|
||||
*/
|
||||
getUserRowByUsername(username: string): AssignedUserRow {
|
||||
const row = this.userRows.filter({hasText: username});
|
||||
return new AssignedUserRow(row);
|
||||
}
|
||||
}
|
||||
|
||||
class AssignedUserRow {
|
||||
readonly container: Locator;
|
||||
readonly avatar: Locator;
|
||||
readonly name: Locator;
|
||||
readonly email: Locator;
|
||||
readonly removeLink: Locator;
|
||||
|
||||
constructor(container: Locator) {
|
||||
this.container = container;
|
||||
this.avatar = container.locator('.Avatar');
|
||||
this.name = container.locator('.UserGrid_name span').first();
|
||||
this.email = container.locator('.ug-email');
|
||||
this.removeLink = container.getByRole('link', {name: 'Remove'});
|
||||
}
|
||||
|
||||
async toBeVisible() {
|
||||
await expect(this.container).toBeVisible();
|
||||
}
|
||||
|
||||
async getName(): Promise<string> {
|
||||
return (await this.name.textContent()) ?? '';
|
||||
}
|
||||
|
||||
async getEmail(): Promise<string> {
|
||||
return (await this.email.textContent()) ?? '';
|
||||
}
|
||||
|
||||
async remove() {
|
||||
await this.removeLink.click();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,214 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {Locator, expect} from '@playwright/test';
|
||||
|
||||
/**
|
||||
* System Console -> User Management -> Users -> User Detail
|
||||
* Accessed by clicking on a user row in the Users list
|
||||
*/
|
||||
export default class UserDetail {
|
||||
readonly container: Locator;
|
||||
|
||||
// Header
|
||||
readonly backLink: Locator;
|
||||
readonly header: Locator;
|
||||
|
||||
// User Card
|
||||
readonly userCard: AdminUserCard;
|
||||
|
||||
// Team Membership Panel
|
||||
readonly teamMembershipPanel: TeamMembershipPanel;
|
||||
|
||||
// Save section
|
||||
readonly saveButton: Locator;
|
||||
readonly cancelButton: Locator;
|
||||
readonly errorMessage: Locator;
|
||||
|
||||
constructor(container: Locator) {
|
||||
this.container = container.locator('.SystemUserDetail');
|
||||
|
||||
// Header
|
||||
this.backLink = this.container.locator('.admin-console__header .back');
|
||||
this.header = this.container.getByText('User Configuration', {exact: true});
|
||||
|
||||
// User Card
|
||||
this.userCard = new AdminUserCard(this.container.locator('.AdminUserCard'));
|
||||
|
||||
// Team Membership Panel
|
||||
this.teamMembershipPanel = new TeamMembershipPanel(
|
||||
this.container.locator('.AdminPanel').filter({hasText: 'Team Membership'}),
|
||||
);
|
||||
|
||||
// Save section
|
||||
this.saveButton = this.container.getByTestId('saveSetting');
|
||||
this.cancelButton = this.container.getByRole('button', {name: 'Cancel'});
|
||||
this.errorMessage = this.container.locator('.error-message');
|
||||
}
|
||||
|
||||
async toBeVisible() {
|
||||
await expect(this.container).toBeVisible();
|
||||
await expect(this.header).toBeVisible();
|
||||
}
|
||||
|
||||
async goBack() {
|
||||
await this.backLink.click();
|
||||
}
|
||||
|
||||
async save() {
|
||||
await expect(this.saveButton).toBeEnabled();
|
||||
await this.saveButton.click();
|
||||
}
|
||||
|
||||
async cancel() {
|
||||
await expect(this.cancelButton).toBeVisible();
|
||||
await this.cancelButton.click();
|
||||
}
|
||||
|
||||
async waitForSaveComplete() {
|
||||
await expect(this.saveButton).toBeDisabled();
|
||||
}
|
||||
}
|
||||
|
||||
class AdminUserCard {
|
||||
readonly container: Locator;
|
||||
|
||||
// Header section
|
||||
readonly profileImage: Locator;
|
||||
readonly displayName: Locator;
|
||||
readonly nickname: Locator;
|
||||
readonly userId: Locator;
|
||||
|
||||
// Body section (two-column layout with fields)
|
||||
readonly body: Locator;
|
||||
readonly twoColumnLayout: Locator;
|
||||
readonly fieldRows: Locator;
|
||||
|
||||
// Footer section
|
||||
readonly resetPasswordButton: Locator;
|
||||
readonly deactivateButton: Locator;
|
||||
readonly manageUserSettingsButton: Locator;
|
||||
|
||||
constructor(container: Locator) {
|
||||
this.container = container;
|
||||
|
||||
// Header
|
||||
const header = container.locator('.AdminUserCard__header');
|
||||
this.profileImage = header.locator('.Avatar');
|
||||
this.displayName = header.locator('.AdminUserCard__user-info span').first();
|
||||
this.nickname = header.locator('.AdminUserCard__user-nickname');
|
||||
this.userId = header.locator('.AdminUserCard__user-id');
|
||||
|
||||
// Body
|
||||
this.body = container.locator('.AdminUserCard__body');
|
||||
this.twoColumnLayout = this.body.locator('.two-column-layout');
|
||||
this.fieldRows = this.body.locator('.field-row');
|
||||
|
||||
// Footer
|
||||
const footer = container.locator('.AdminUserCard__footer');
|
||||
this.resetPasswordButton = footer.getByRole('button', {name: 'Reset Password'});
|
||||
this.deactivateButton = footer.getByRole('button', {name: 'Deactivate'});
|
||||
this.manageUserSettingsButton = footer.getByRole('button', {name: 'Manage User Settings'});
|
||||
}
|
||||
|
||||
async toBeVisible() {
|
||||
await expect(this.container).toBeVisible();
|
||||
}
|
||||
|
||||
getFieldByLabel(labelText: string): Locator {
|
||||
return this.body.getByLabel(labelText);
|
||||
}
|
||||
|
||||
getSelectByLabel(labelText: string): Locator {
|
||||
return this.body.getByLabel(labelText);
|
||||
}
|
||||
|
||||
async fillField(labelText: string, value: string) {
|
||||
const input = this.getFieldByLabel(labelText);
|
||||
await input.clear();
|
||||
await input.fill(value);
|
||||
}
|
||||
|
||||
async getFieldValue(labelText: string): Promise<string> {
|
||||
const input = this.getFieldByLabel(labelText);
|
||||
return await input.inputValue();
|
||||
}
|
||||
|
||||
async getUserId(): Promise<string> {
|
||||
const text = (await this.userId.textContent()) ?? '';
|
||||
return text.replace('User ID: ', '');
|
||||
}
|
||||
}
|
||||
|
||||
class TeamMembershipPanel {
|
||||
readonly container: Locator;
|
||||
readonly title: Locator;
|
||||
readonly description: Locator;
|
||||
readonly addTeamButton: Locator;
|
||||
readonly teamRows: Locator;
|
||||
|
||||
constructor(container: Locator) {
|
||||
this.container = container;
|
||||
this.title = container.getByRole('heading', {name: 'Team Membership'});
|
||||
this.description = container.getByText('Teams to which this user belongs');
|
||||
this.addTeamButton = container.getByRole('button', {name: 'Add Team'});
|
||||
this.teamRows = container.locator('.TeamRow');
|
||||
}
|
||||
|
||||
async toBeVisible() {
|
||||
await expect(this.container).toBeVisible();
|
||||
await expect(this.title).toBeVisible();
|
||||
}
|
||||
|
||||
async clickAddTeam() {
|
||||
await this.addTeamButton.click();
|
||||
}
|
||||
|
||||
async getTeamCount(): Promise<number> {
|
||||
return this.teamRows.count();
|
||||
}
|
||||
|
||||
getTeamRowByIndex(index: number): TeamRow {
|
||||
return new TeamRow(this.teamRows.nth(index));
|
||||
}
|
||||
|
||||
getTeamRowByName(teamName: string): TeamRow {
|
||||
return new TeamRow(this.teamRows.filter({hasText: teamName}));
|
||||
}
|
||||
}
|
||||
|
||||
class TeamRow {
|
||||
readonly container: Locator;
|
||||
readonly teamName: Locator;
|
||||
readonly teamType: Locator;
|
||||
readonly role: Locator;
|
||||
readonly actionMenuButton: Locator;
|
||||
|
||||
constructor(container: Locator) {
|
||||
this.container = container;
|
||||
this.teamName = container.locator('.TeamRow__team-name b');
|
||||
this.teamType = container.locator('.TeamRow__description').first();
|
||||
this.role = container.locator('.TeamRow__description').last();
|
||||
this.actionMenuButton = container.locator('.TeamRow__actions button');
|
||||
}
|
||||
|
||||
async toBeVisible() {
|
||||
await expect(this.container).toBeVisible();
|
||||
}
|
||||
|
||||
async getTeamName(): Promise<string> {
|
||||
return (await this.teamName.textContent()) ?? '';
|
||||
}
|
||||
|
||||
async getTeamType(): Promise<string> {
|
||||
return (await this.teamType.textContent()) ?? '';
|
||||
}
|
||||
|
||||
async getRole(): Promise<string> {
|
||||
return (await this.role.textContent()) ?? '';
|
||||
}
|
||||
|
||||
async openActionMenu() {
|
||||
await this.actionMenuButton.click();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,213 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {Locator, expect} from '@playwright/test';
|
||||
|
||||
import UserDetail from '../user_detail';
|
||||
|
||||
import {ColumnToggleMenu, DateRangeMenu, FilterMenu, FilterPopover} from './menus';
|
||||
import {ManageRolesModal, ResetPasswordModal, UpdateEmailModal} from './modals';
|
||||
import {UsersTable} from './users_table';
|
||||
|
||||
import {ConfirmModal} from '@/ui/components/system_console/base_modal';
|
||||
|
||||
// Re-export sub-components for external use
|
||||
export {ColumnToggleMenu, DateRangeMenu, FilterMenu, FilterPopover} from './menus';
|
||||
export {ManageRolesModal, ResetPasswordModal, UpdateEmailModal} from './modals';
|
||||
export {UserActionMenu} from './user_action_menu';
|
||||
export {UserRow, UsersTable} from './users_table';
|
||||
|
||||
/**
|
||||
* System Console -> User Management -> Users
|
||||
*/
|
||||
export default class Users {
|
||||
readonly container: Locator;
|
||||
private readonly page;
|
||||
|
||||
// User Detail page (accessed by clicking on a user row)
|
||||
readonly userDetail: UserDetail;
|
||||
|
||||
// Modals (opened from user actions)
|
||||
readonly confirmModal: ConfirmModal;
|
||||
readonly manageRolesModal: ManageRolesModal;
|
||||
readonly resetPasswordModal: ResetPasswordModal;
|
||||
readonly updateEmailModal: UpdateEmailModal;
|
||||
|
||||
// Header
|
||||
readonly header: Locator;
|
||||
readonly revokeAllSessionsButton: Locator;
|
||||
|
||||
// Filters section
|
||||
readonly searchInput: Locator;
|
||||
readonly filtersButton: Locator;
|
||||
readonly columnToggleMenuButton: Locator;
|
||||
readonly dateRangeSelectorMenuButton: Locator;
|
||||
readonly exportButton: Locator;
|
||||
|
||||
// Loading indicator
|
||||
readonly loadingSpinner: Locator;
|
||||
|
||||
// Table
|
||||
readonly usersTable: UsersTable;
|
||||
|
||||
// Menus and Popovers (populated from page-level locators)
|
||||
readonly columnToggleMenu: ColumnToggleMenu;
|
||||
readonly filterPopover: FilterPopover;
|
||||
readonly roleFilterMenu: FilterMenu;
|
||||
readonly statusFilterMenu: FilterMenu;
|
||||
readonly dateRangeMenu: DateRangeMenu;
|
||||
|
||||
// Pagination
|
||||
readonly paginationInfo: Locator;
|
||||
readonly previousPageButton: Locator;
|
||||
readonly nextPageButton: Locator;
|
||||
readonly rowsPerPageSelector: Locator;
|
||||
|
||||
constructor(container: Locator) {
|
||||
this.container = container;
|
||||
this.page = container.page();
|
||||
|
||||
this.userDetail = new UserDetail(container);
|
||||
|
||||
// Modals
|
||||
this.confirmModal = new ConfirmModal(this.page.locator('#confirmModal'));
|
||||
this.manageRolesModal = new ManageRolesModal(this.page.locator('.manage-teams'));
|
||||
this.resetPasswordModal = new ResetPasswordModal(this.page.locator('#resetPasswordModal'));
|
||||
this.updateEmailModal = new UpdateEmailModal(this.page.locator('#resetEmailModal'));
|
||||
|
||||
this.header = container.getByText('Mattermost Users', {exact: true});
|
||||
this.revokeAllSessionsButton = container.getByRole('button', {name: 'Revoke All Sessions'});
|
||||
|
||||
this.searchInput = container.getByRole('textbox', {name: 'Search users'});
|
||||
this.filtersButton = container.getByRole('button', {name: /Filters/});
|
||||
this.columnToggleMenuButton = container.locator('#systemUsersColumnTogglerMenuButton');
|
||||
this.dateRangeSelectorMenuButton = container.locator('#systemUsersDateRangeSelectorMenuButton');
|
||||
this.exportButton = container.getByText('Export');
|
||||
|
||||
this.loadingSpinner = container.getByText('Loading');
|
||||
|
||||
this.usersTable = new UsersTable(container.locator('#systemUsersTable'));
|
||||
|
||||
this.columnToggleMenu = new ColumnToggleMenu(this.page.locator('#systemUsersColumnTogglerMenu'));
|
||||
this.filterPopover = new FilterPopover(this.page.locator('#systemUsersFilterPopover'));
|
||||
this.roleFilterMenu = new FilterMenu(this.page.locator('.DropDown__menu'));
|
||||
this.statusFilterMenu = new FilterMenu(this.page.locator('.DropDown__menu'));
|
||||
this.dateRangeMenu = new DateRangeMenu(this.page.locator('#systemUsersDateRangeSelectorMenu'));
|
||||
|
||||
const footer = container.locator('.adminConsoleListTabletOptionalFoot');
|
||||
this.paginationInfo = footer.locator('span').first();
|
||||
this.previousPageButton = footer.getByRole('button', {name: 'Go to previous page'});
|
||||
this.nextPageButton = footer.getByRole('button', {name: 'Go to next page'});
|
||||
this.rowsPerPageSelector = footer.locator('.adminConsoleListTablePageSize .react-select');
|
||||
}
|
||||
|
||||
async toBeVisible() {
|
||||
await expect(this.container).toBeVisible();
|
||||
await expect(this.header).toBeVisible();
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for loading to complete
|
||||
*/
|
||||
async isLoadingComplete() {
|
||||
await expect(this.loadingSpinner).toHaveCount(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for users by typing in the search input
|
||||
*/
|
||||
async searchUsers(searchTerm: string) {
|
||||
await this.searchInput.fill(searchTerm);
|
||||
await this.isLoadingComplete();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the search input
|
||||
*/
|
||||
async clearSearch() {
|
||||
await this.searchInput.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current filter count from the Filters button
|
||||
*/
|
||||
async getFilterCount(): Promise<number> {
|
||||
const buttonText = await this.filtersButton.textContent();
|
||||
const match = buttonText?.match(/Filters \((\d+)\)/);
|
||||
return match ? parseInt(match[1], 10) : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Open the column toggle menu
|
||||
*/
|
||||
async openColumnToggleMenu(): Promise<ColumnToggleMenu> {
|
||||
await expect(this.columnToggleMenuButton).toBeVisible();
|
||||
await this.columnToggleMenuButton.click();
|
||||
await this.columnToggleMenu.toBeVisible();
|
||||
return this.columnToggleMenu;
|
||||
}
|
||||
|
||||
/**
|
||||
* Open the filter popover
|
||||
*/
|
||||
async openFilterPopover(): Promise<FilterPopover> {
|
||||
await expect(this.filtersButton).toBeVisible();
|
||||
await this.filtersButton.click();
|
||||
await this.filterPopover.toBeVisible();
|
||||
return this.filterPopover;
|
||||
}
|
||||
|
||||
/**
|
||||
* Open the date range selector menu
|
||||
*/
|
||||
async openDateRangeSelectorMenu(): Promise<DateRangeMenu> {
|
||||
await expect(this.dateRangeSelectorMenuButton).toBeVisible();
|
||||
await this.dateRangeSelectorMenuButton.click();
|
||||
await this.dateRangeMenu.toBeVisible();
|
||||
return this.dateRangeMenu;
|
||||
}
|
||||
|
||||
/**
|
||||
* Click the Export button
|
||||
*/
|
||||
async clickExport() {
|
||||
await this.exportButton.click();
|
||||
}
|
||||
|
||||
/**
|
||||
* Click Revoke All Sessions button
|
||||
*/
|
||||
async clickRevokeAllSessions() {
|
||||
await this.revokeAllSessionsButton.click();
|
||||
}
|
||||
|
||||
/**
|
||||
* Go to next page
|
||||
*/
|
||||
async goToNextPage() {
|
||||
await this.nextPageButton.click();
|
||||
}
|
||||
|
||||
/**
|
||||
* Go to previous page
|
||||
*/
|
||||
async goToPreviousPage() {
|
||||
await this.previousPageButton.click();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the pagination info text (e.g., "Showing 1 - 10 of 212 users")
|
||||
*/
|
||||
async getPaginationInfo(): Promise<string> {
|
||||
return (await this.paginationInfo.textContent()) ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the total user count from pagination info
|
||||
*/
|
||||
async getTotalUserCount(): Promise<number> {
|
||||
const text = await this.getPaginationInfo();
|
||||
const match = text.match(/of (\d+) users/);
|
||||
return match ? parseInt(match[1], 10) : 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,196 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {Locator, expect} from '@playwright/test';
|
||||
|
||||
/**
|
||||
* Column toggle menu that appears when clicking the Columns button
|
||||
*/
|
||||
export class ColumnToggleMenu {
|
||||
readonly container: Locator;
|
||||
|
||||
constructor(container: Locator) {
|
||||
this.container = container;
|
||||
}
|
||||
|
||||
async toBeVisible() {
|
||||
await expect(this.container).toBeVisible();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a menu item by text
|
||||
*/
|
||||
async getMenuItem(menuItem: string): Promise<Locator> {
|
||||
const menuItemLocator = this.container.getByRole('menuitemcheckbox').filter({hasText: menuItem});
|
||||
await menuItemLocator.waitFor();
|
||||
return menuItemLocator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all menu items
|
||||
*/
|
||||
getAllMenuItems(): Locator {
|
||||
return this.container.getByRole('menuitemcheckbox');
|
||||
}
|
||||
|
||||
/**
|
||||
* Click a menu item to toggle it
|
||||
*/
|
||||
async clickMenuItem(menuItem: string) {
|
||||
const item = await this.getMenuItem(menuItem);
|
||||
await item.click();
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the menu
|
||||
*/
|
||||
async close() {
|
||||
await this.container.press('Escape');
|
||||
await expect(this.container).not.toBeVisible();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter popover that appears when clicking the Filters button
|
||||
*/
|
||||
export class FilterPopover {
|
||||
readonly container: Locator;
|
||||
readonly teamMenuInput: Locator;
|
||||
readonly roleMenuButton: Locator;
|
||||
readonly statusMenuButton: Locator;
|
||||
readonly applyButton: Locator;
|
||||
|
||||
constructor(container: Locator) {
|
||||
this.container = container;
|
||||
this.teamMenuInput = container.locator('#asyncTeamSelectInput');
|
||||
this.roleMenuButton = container.locator('#DropdownInput_filterRole');
|
||||
this.statusMenuButton = container.locator('#DropdownInput_filterStatus');
|
||||
this.applyButton = container.getByText('Apply');
|
||||
}
|
||||
|
||||
async toBeVisible() {
|
||||
await expect(this.container).toBeVisible();
|
||||
await expect(this.applyButton).toBeVisible();
|
||||
}
|
||||
|
||||
/**
|
||||
* Save/apply the filter settings and wait for popover to close
|
||||
*/
|
||||
async save() {
|
||||
await this.applyButton.click();
|
||||
// Apply button closes the popover, wait for it to close
|
||||
await expect(this.container).not.toBeVisible({timeout: 5000});
|
||||
}
|
||||
|
||||
/**
|
||||
* Search in the team filter and wait for dropdown options
|
||||
*/
|
||||
async searchInTeamMenu(teamDisplayName: string) {
|
||||
await expect(this.teamMenuInput).toBeVisible();
|
||||
await this.teamMenuInput.fill(teamDisplayName);
|
||||
// Wait a bit for async search results to appear
|
||||
await this.container.page().waitForTimeout(500);
|
||||
}
|
||||
|
||||
/**
|
||||
* Open the role filter menu
|
||||
*/
|
||||
async openRoleMenu() {
|
||||
await expect(this.roleMenuButton).toBeVisible();
|
||||
await this.roleMenuButton.click();
|
||||
}
|
||||
|
||||
/**
|
||||
* Open the status filter menu
|
||||
*/
|
||||
async openStatusMenu() {
|
||||
await expect(this.statusMenuButton).toBeVisible();
|
||||
await this.statusMenuButton.click();
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the popover (if still open)
|
||||
*/
|
||||
async close() {
|
||||
const isVisible = await this.container.isVisible();
|
||||
if (isVisible) {
|
||||
await this.container.press('Escape');
|
||||
await expect(this.container).not.toBeVisible();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic filter menu for role/status dropdowns (react-select dropdown)
|
||||
*/
|
||||
export class FilterMenu {
|
||||
readonly container: Locator;
|
||||
|
||||
constructor(container: Locator) {
|
||||
this.container = container;
|
||||
}
|
||||
|
||||
async toBeVisible() {
|
||||
await expect(this.container).toBeVisible();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a menu item by text
|
||||
*/
|
||||
async getMenuItem(menuItem: string): Promise<Locator> {
|
||||
const menuItemLocator = this.container.getByText(menuItem);
|
||||
await menuItemLocator.waitFor();
|
||||
return menuItemLocator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Click a menu item (this also closes the dropdown automatically)
|
||||
*/
|
||||
async clickMenuItem(menuItem: string) {
|
||||
const item = await this.getMenuItem(menuItem);
|
||||
await item.click();
|
||||
// Dropdown closes automatically after selection, wait for it
|
||||
await expect(this.container).not.toBeVisible({timeout: 5000});
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the menu (if still open)
|
||||
*/
|
||||
async close() {
|
||||
const isVisible = await this.container.isVisible();
|
||||
if (isVisible) {
|
||||
await this.container.press('Escape');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Date range selector menu
|
||||
*/
|
||||
export class DateRangeMenu {
|
||||
readonly container: Locator;
|
||||
|
||||
constructor(container: Locator) {
|
||||
this.container = container;
|
||||
}
|
||||
|
||||
async toBeVisible() {
|
||||
await expect(this.container).toBeVisible();
|
||||
}
|
||||
|
||||
/**
|
||||
* Click a menu item
|
||||
*/
|
||||
async clickMenuItem(menuItem: string) {
|
||||
const item = this.container.getByText(menuItem);
|
||||
await item.waitFor();
|
||||
await item.click();
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the menu
|
||||
*/
|
||||
async close() {
|
||||
await this.container.press('Escape');
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {Locator, expect} from '@playwright/test';
|
||||
|
||||
import BaseModal from '@/ui/components/system_console/base_modal';
|
||||
|
||||
/**
|
||||
* Manage Roles modal (System Console -> Users -> Action -> Manage roles)
|
||||
*/
|
||||
export class ManageRolesModal extends BaseModal {
|
||||
readonly saveButton: Locator;
|
||||
|
||||
constructor(container: Locator) {
|
||||
super(container);
|
||||
this.saveButton = container.getByRole('button', {name: 'Save'});
|
||||
}
|
||||
|
||||
async save() {
|
||||
await this.saveButton.click();
|
||||
await expect(this.container).not.toBeVisible();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset Password modal (System Console -> Users -> Action -> Reset password)
|
||||
*/
|
||||
export class ResetPasswordModal extends BaseModal {
|
||||
readonly resetButton: Locator;
|
||||
readonly passwordInput: Locator;
|
||||
|
||||
constructor(container: Locator) {
|
||||
super(container);
|
||||
this.resetButton = container.getByRole('button', {name: 'Reset'});
|
||||
this.passwordInput = container.locator('input[type="password"]');
|
||||
}
|
||||
|
||||
async reset() {
|
||||
await this.resetButton.click();
|
||||
await expect(this.container).not.toBeVisible();
|
||||
}
|
||||
|
||||
async fillPassword(password: string) {
|
||||
await this.passwordInput.fill(password);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update Email modal (System Console -> Users -> Action -> Update email)
|
||||
*/
|
||||
export class UpdateEmailModal extends BaseModal {
|
||||
readonly updateButton: Locator;
|
||||
readonly emailInput: Locator;
|
||||
|
||||
constructor(container: Locator) {
|
||||
super(container);
|
||||
this.updateButton = container.getByRole('button', {name: 'Update'});
|
||||
this.emailInput = container.locator('input[type="email"]');
|
||||
}
|
||||
|
||||
async update() {
|
||||
await this.updateButton.click();
|
||||
await expect(this.container).not.toBeVisible();
|
||||
}
|
||||
|
||||
async fillEmail(email: string) {
|
||||
await this.emailInput.fill(email);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {Locator, expect} from '@playwright/test';
|
||||
|
||||
/**
|
||||
* User action menu that appears when clicking the action button on a user row
|
||||
*/
|
||||
export class UserActionMenu {
|
||||
readonly container: Locator;
|
||||
|
||||
constructor(container: Locator) {
|
||||
this.container = container;
|
||||
}
|
||||
|
||||
async toBeVisible() {
|
||||
await expect(this.container).toBeVisible();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a menu item by text
|
||||
*/
|
||||
getMenuItem(text: string): Locator {
|
||||
return this.container.getByText(text, {exact: true});
|
||||
}
|
||||
|
||||
/**
|
||||
* Click a menu item by text
|
||||
*/
|
||||
async clickMenuItem(text: string) {
|
||||
const item = this.getMenuItem(text);
|
||||
await item.click();
|
||||
}
|
||||
|
||||
async clickDeactivate() {
|
||||
await this.clickMenuItem('Deactivate');
|
||||
}
|
||||
|
||||
async clickActivate() {
|
||||
await this.clickMenuItem('Activate');
|
||||
}
|
||||
|
||||
async clickManageRoles() {
|
||||
await this.clickMenuItem('Manage roles');
|
||||
}
|
||||
|
||||
async clickManageTeams() {
|
||||
await this.clickMenuItem('Manage teams');
|
||||
}
|
||||
|
||||
async clickResetPassword() {
|
||||
await this.clickMenuItem('Reset password');
|
||||
}
|
||||
|
||||
async clickUpdateEmail() {
|
||||
await this.clickMenuItem('Update email');
|
||||
}
|
||||
|
||||
async clickRevokeSessions() {
|
||||
await this.clickMenuItem('Revoke sessions');
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,209 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {Locator, expect} from '@playwright/test';
|
||||
|
||||
import {UserActionMenu} from './user_action_menu';
|
||||
|
||||
/**
|
||||
* Users table component
|
||||
*/
|
||||
export class UsersTable {
|
||||
readonly container: Locator;
|
||||
readonly headerRow: Locator;
|
||||
readonly bodyRows: Locator;
|
||||
|
||||
// Column headers
|
||||
readonly userDetailsHeader: Locator;
|
||||
readonly emailHeader: Locator;
|
||||
readonly memberSinceHeader: Locator;
|
||||
readonly lastLoginHeader: Locator;
|
||||
readonly lastActivityHeader: Locator;
|
||||
readonly lastPostHeader: Locator;
|
||||
readonly daysActiveHeader: Locator;
|
||||
readonly messagesPostedHeader: Locator;
|
||||
readonly actionsHeader: Locator;
|
||||
|
||||
constructor(container: Locator) {
|
||||
this.container = container;
|
||||
this.headerRow = container.locator('thead tr');
|
||||
this.bodyRows = container.locator('tbody tr');
|
||||
|
||||
// Column headers
|
||||
this.userDetailsHeader = container.locator('#systemUsersTable-header-usernameColumn');
|
||||
this.emailHeader = container.locator('#systemUsersTable-header-emailColumn');
|
||||
this.memberSinceHeader = container.locator('#systemUsersTable-header-createAtColumn');
|
||||
this.lastLoginHeader = container.locator('#systemUsersTable-header-lastLoginColumn');
|
||||
this.lastActivityHeader = container.locator('#systemUsersTable-header-lastStatusAtColumn');
|
||||
this.lastPostHeader = container.locator('#systemUsersTable-header-lastPostDateColumn');
|
||||
this.daysActiveHeader = container.locator('#systemUsersTable-header-daysActiveColumn');
|
||||
this.messagesPostedHeader = container.locator('#systemUsersTable-header-totalPostsColumn');
|
||||
this.actionsHeader = container.locator('#systemUsersTable-header-actionsColumn');
|
||||
}
|
||||
|
||||
async toBeVisible() {
|
||||
await expect(this.container).toBeVisible();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a user row by index (0-based)
|
||||
*/
|
||||
getRowByIndex(index: number): UserRow {
|
||||
return new UserRow(this.bodyRows.nth(index), index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a column header by display name
|
||||
*/
|
||||
getColumnHeader(columnName: string): Locator {
|
||||
const headerMap: Record<string, Locator> = {
|
||||
'User details': this.userDetailsHeader,
|
||||
Email: this.emailHeader,
|
||||
'Member since': this.memberSinceHeader,
|
||||
'Last login': this.lastLoginHeader,
|
||||
'Last activity': this.lastActivityHeader,
|
||||
'Last post': this.lastPostHeader,
|
||||
'Days active': this.daysActiveHeader,
|
||||
'Messages posted': this.messagesPostedHeader,
|
||||
Actions: this.actionsHeader,
|
||||
};
|
||||
const header = headerMap[columnName];
|
||||
if (!header) {
|
||||
throw new Error(`Unknown column: ${columnName}`);
|
||||
}
|
||||
return header;
|
||||
}
|
||||
|
||||
/**
|
||||
* Click on a column header to sort by that column
|
||||
*/
|
||||
async clickSortOnColumn(columnName: string) {
|
||||
const header = this.getColumnHeader(columnName);
|
||||
await header.click();
|
||||
}
|
||||
|
||||
/**
|
||||
* Click on a sortable column header and wait for sort to complete
|
||||
* @param columnName - The display name of the column
|
||||
* @returns The new sort direction after clicking
|
||||
*/
|
||||
async sortByColumn(columnName: string): Promise<'ascending' | 'descending' | 'none'> {
|
||||
const header = this.getColumnHeader(columnName);
|
||||
|
||||
// Get current sort direction
|
||||
const currentSort = await header.getAttribute('aria-sort');
|
||||
|
||||
// Click to sort
|
||||
await header.click();
|
||||
|
||||
// Wait for sort direction to change (or for it to be set if it wasn't before)
|
||||
if (currentSort) {
|
||||
// Wait for the attribute to change
|
||||
await expect(header).not.toHaveAttribute('aria-sort', currentSort);
|
||||
} else {
|
||||
// Wait for the attribute to be set
|
||||
await expect(header).toHaveAttribute('aria-sort');
|
||||
}
|
||||
|
||||
// Wait for table to stabilize
|
||||
await this.waitForLoadingComplete();
|
||||
|
||||
// Return the new sort direction
|
||||
const newSort = await header.getAttribute('aria-sort');
|
||||
return (newSort as 'ascending' | 'descending' | 'none') ?? 'none';
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for the table to finish loading (spinner to disappear)
|
||||
*/
|
||||
async waitForLoadingComplete() {
|
||||
// Wait for any loading spinners to disappear
|
||||
const loadingSpinner = this.container.locator('.loading-screen, .LoadingSpinner');
|
||||
await loadingSpinner.waitFor({state: 'detached', timeout: 10000}).catch(() => {
|
||||
// Spinner may not appear for fast loads, ignore timeout
|
||||
});
|
||||
// Also wait for at least one row to be visible
|
||||
await this.bodyRows.first().waitFor({state: 'visible'});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A single row in the users table
|
||||
*/
|
||||
export class UserRow {
|
||||
readonly container: Locator;
|
||||
readonly index: number;
|
||||
|
||||
// Cells
|
||||
readonly userDetailsCell: Locator;
|
||||
readonly emailCell: Locator;
|
||||
readonly memberSinceCell: Locator;
|
||||
readonly lastLoginCell: Locator;
|
||||
readonly lastActivityCell: Locator;
|
||||
readonly lastPostCell: Locator;
|
||||
readonly daysActiveCell: Locator;
|
||||
readonly messagesPostedCell: Locator;
|
||||
readonly actionsCell: Locator;
|
||||
|
||||
// User details components
|
||||
readonly profilePicture: Locator;
|
||||
readonly displayName: Locator;
|
||||
readonly userName: Locator;
|
||||
|
||||
// Action menu button
|
||||
readonly actionMenuButton: Locator;
|
||||
|
||||
// Action menu (populated after opening)
|
||||
private readonly actionMenu: UserActionMenu;
|
||||
|
||||
constructor(container: Locator, index: number) {
|
||||
this.container = container;
|
||||
this.index = index;
|
||||
|
||||
this.userDetailsCell = container.locator('.usernameColumn');
|
||||
this.emailCell = container.locator('.emailColumn');
|
||||
this.memberSinceCell = container.locator('.createAtColumn');
|
||||
this.lastLoginCell = container.locator('.lastLoginColumn');
|
||||
this.lastActivityCell = container.locator('.lastStatusAtColumn');
|
||||
this.lastPostCell = container.locator('.lastPostDateColumn');
|
||||
this.daysActiveCell = container.locator('.daysActiveColumn');
|
||||
this.messagesPostedCell = container.locator('.totalPostsColumn');
|
||||
this.actionsCell = container.locator('.actionsColumn');
|
||||
|
||||
this.profilePicture = this.userDetailsCell.locator('.profilePicture');
|
||||
this.displayName = this.userDetailsCell.locator('.displayName');
|
||||
this.userName = this.userDetailsCell.locator('.userName');
|
||||
|
||||
this.actionMenuButton = this.actionsCell.getByRole('button');
|
||||
|
||||
this.actionMenu = new UserActionMenu(container.page().locator(`#actionMenu-systemUsersTable-${index}`));
|
||||
}
|
||||
|
||||
async toBeVisible() {
|
||||
await expect(this.container).toBeVisible();
|
||||
}
|
||||
|
||||
/**
|
||||
* Click on the row to view user details
|
||||
*/
|
||||
async click() {
|
||||
await this.container.click();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the email
|
||||
*/
|
||||
async getEmail(): Promise<string> {
|
||||
return (await this.emailCell.textContent()) ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Click the action menu button to open the actions dropdown
|
||||
* Returns the action menu for further interactions
|
||||
*/
|
||||
async openActionMenu(): Promise<UserActionMenu> {
|
||||
await this.actionMenuButton.click();
|
||||
await this.actionMenu.toBeVisible();
|
||||
return this.actionMenu;
|
||||
}
|
||||
}
|
||||
|
|
@ -3,37 +3,342 @@
|
|||
|
||||
import {Locator, expect} from '@playwright/test';
|
||||
|
||||
import SystemConsoleSidebarHeader from './sidebar_header';
|
||||
|
||||
export default class SystemConsoleSidebar {
|
||||
readonly container: Locator;
|
||||
|
||||
readonly header: SystemConsoleSidebarHeader;
|
||||
readonly searchInput: Locator;
|
||||
|
||||
readonly about: AboutCategory;
|
||||
readonly reporting: ReportingCategory;
|
||||
readonly userManagement: UserManagementCategory;
|
||||
readonly systemAttributes: SystemAttributesCategory;
|
||||
readonly environment: EnvironmentCategory;
|
||||
readonly siteConfiguration: SiteConfigurationCategory;
|
||||
readonly authentication: AuthenticationCategory;
|
||||
readonly plugins: PluginsCategory;
|
||||
readonly integrations: IntegrationsCategory;
|
||||
readonly compliance: ComplianceCategory;
|
||||
readonly experimental: ExperimentalCategory;
|
||||
|
||||
constructor(container: Locator) {
|
||||
this.container = container;
|
||||
|
||||
this.header = new SystemConsoleSidebarHeader(container.locator('.AdminSidebarHeader'));
|
||||
this.searchInput = container.getByPlaceholder('Find settings');
|
||||
|
||||
this.about = new AboutCategory(container.getByTestId('about'));
|
||||
this.reporting = new ReportingCategory(container.getByTestId('reporting'));
|
||||
this.userManagement = new UserManagementCategory(container.getByTestId('user_management'));
|
||||
this.systemAttributes = new SystemAttributesCategory(container.getByTestId('system_attributes'));
|
||||
this.environment = new EnvironmentCategory(container.getByTestId('environment'));
|
||||
this.siteConfiguration = new SiteConfigurationCategory(container.getByTestId('site'));
|
||||
this.authentication = new AuthenticationCategory(container.getByTestId('authentication'));
|
||||
this.plugins = new PluginsCategory(container.getByTestId('plugins'));
|
||||
this.integrations = new IntegrationsCategory(container.getByTestId('integrations'));
|
||||
this.compliance = new ComplianceCategory(container.getByTestId('compliance'));
|
||||
this.experimental = new ExperimentalCategory(container.getByTestId('experimental'));
|
||||
}
|
||||
|
||||
async toBeVisible() {
|
||||
await expect(this.container).toBeVisible();
|
||||
await this.header.toBeVisible();
|
||||
await expect(this.searchInput).toBeVisible();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clicks on the sidebar section link with the given name. Pass the exact name of the section.
|
||||
* @param sectionName
|
||||
*/
|
||||
async goToItem(sectionName: string) {
|
||||
const section = this.container.getByText(sectionName, {exact: true});
|
||||
await section.waitFor();
|
||||
await section.click();
|
||||
async search(text: string) {
|
||||
await this.searchInput.fill(text);
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches for the given item in the sidebar search input.
|
||||
* @param itemName
|
||||
*/
|
||||
async searchForItem(itemName: string) {
|
||||
await this.searchInput.fill(itemName);
|
||||
async clearSearch() {
|
||||
await this.searchInput.clear();
|
||||
}
|
||||
|
||||
// Convenience shortcuts
|
||||
get editionAndLicense() {
|
||||
return this.about.editionAndLicense;
|
||||
}
|
||||
get users() {
|
||||
return this.userManagement.users;
|
||||
}
|
||||
get groups() {
|
||||
return this.userManagement.groups;
|
||||
}
|
||||
get teams() {
|
||||
return this.userManagement.teams;
|
||||
}
|
||||
get channels() {
|
||||
return this.userManagement.channels;
|
||||
}
|
||||
get permissions() {
|
||||
return this.userManagement.permissions;
|
||||
}
|
||||
get delegatedGranularAdministration() {
|
||||
return this.userManagement.delegatedGranularAdministration;
|
||||
}
|
||||
get mobileSecurity() {
|
||||
return this.environment.mobileSecurity;
|
||||
}
|
||||
get notifications() {
|
||||
return this.siteConfiguration.notifications;
|
||||
}
|
||||
get pluginManagement() {
|
||||
return this.plugins.pluginManagement;
|
||||
}
|
||||
}
|
||||
|
||||
class SidebarSection {
|
||||
readonly container: Locator;
|
||||
readonly link: Locator;
|
||||
|
||||
constructor(container: Locator, link: Locator) {
|
||||
this.container = container;
|
||||
this.link = link;
|
||||
}
|
||||
|
||||
async click() {
|
||||
await this.link.click();
|
||||
}
|
||||
|
||||
async isActive(): Promise<boolean> {
|
||||
const classAttr = await this.link.getAttribute('class');
|
||||
return classAttr?.includes('sidebar-section-title--active') ?? false;
|
||||
}
|
||||
|
||||
async toBeVisible() {
|
||||
await expect(this.container).toBeVisible();
|
||||
}
|
||||
}
|
||||
|
||||
class SidebarCategory {
|
||||
readonly container: Locator;
|
||||
readonly title: Locator;
|
||||
readonly sections: Locator;
|
||||
|
||||
constructor(container: Locator) {
|
||||
this.container = container;
|
||||
this.title = container.locator('.category-title');
|
||||
this.sections = container.locator('ul.sections');
|
||||
}
|
||||
|
||||
protected section(name: string): SidebarSection {
|
||||
const link = this.sections.getByRole('link', {name, exact: true});
|
||||
return new SidebarSection(this.sections, link);
|
||||
}
|
||||
|
||||
async toBeVisible() {
|
||||
await expect(this.container).toBeVisible();
|
||||
}
|
||||
}
|
||||
|
||||
class AboutCategory extends SidebarCategory {
|
||||
readonly editionAndLicense: SidebarSection;
|
||||
|
||||
constructor(container: Locator) {
|
||||
super(container);
|
||||
this.editionAndLicense = this.section('Edition and License');
|
||||
}
|
||||
}
|
||||
|
||||
class ReportingCategory extends SidebarCategory {
|
||||
readonly workspaceOptimization: SidebarSection;
|
||||
readonly siteStatistics: SidebarSection;
|
||||
readonly teamStatistics: SidebarSection;
|
||||
readonly serverLogs: SidebarSection;
|
||||
|
||||
constructor(container: Locator) {
|
||||
super(container);
|
||||
this.workspaceOptimization = this.section('Workspace Optimization');
|
||||
this.siteStatistics = this.section('Site Statistics');
|
||||
this.teamStatistics = this.section('Team Statistics');
|
||||
this.serverLogs = this.section('Server Logs');
|
||||
}
|
||||
}
|
||||
|
||||
class UserManagementCategory extends SidebarCategory {
|
||||
readonly users: SidebarSection;
|
||||
readonly groups: SidebarSection;
|
||||
readonly teams: SidebarSection;
|
||||
readonly channels: SidebarSection;
|
||||
readonly permissions: SidebarSection;
|
||||
readonly delegatedGranularAdministration: SidebarSection;
|
||||
|
||||
constructor(container: Locator) {
|
||||
super(container);
|
||||
this.users = this.section('Users');
|
||||
this.groups = this.section('Groups');
|
||||
this.teams = this.section('Teams');
|
||||
this.channels = this.section('Channels');
|
||||
this.permissions = this.section('Permissions');
|
||||
this.delegatedGranularAdministration = this.section('Delegated Granular Administration');
|
||||
}
|
||||
}
|
||||
|
||||
class SystemAttributesCategory extends SidebarCategory {
|
||||
readonly userAttributes: SidebarSection;
|
||||
readonly attributeBasedAccess: SidebarSection;
|
||||
|
||||
constructor(container: Locator) {
|
||||
super(container);
|
||||
this.userAttributes = this.section('User Attributes');
|
||||
this.attributeBasedAccess = this.section('Attribute-Based Access');
|
||||
}
|
||||
}
|
||||
|
||||
class EnvironmentCategory extends SidebarCategory {
|
||||
readonly webServer: SidebarSection;
|
||||
readonly database: SidebarSection;
|
||||
readonly elasticsearch: SidebarSection;
|
||||
readonly fileStorage: SidebarSection;
|
||||
readonly imageProxy: SidebarSection;
|
||||
readonly smtp: SidebarSection;
|
||||
readonly pushNotificationServer: SidebarSection;
|
||||
readonly highAvailability: SidebarSection;
|
||||
readonly cacheSettings: SidebarSection;
|
||||
readonly rateLimiting: SidebarSection;
|
||||
readonly logging: SidebarSection;
|
||||
readonly sessionLengths: SidebarSection;
|
||||
readonly performanceMonitoring: SidebarSection;
|
||||
readonly developer: SidebarSection;
|
||||
readonly mobileSecurity: SidebarSection;
|
||||
|
||||
constructor(container: Locator) {
|
||||
super(container);
|
||||
this.webServer = this.section('Web Server');
|
||||
this.database = this.section('Database');
|
||||
this.elasticsearch = this.section('Elasticsearch');
|
||||
this.fileStorage = this.section('File Storage');
|
||||
this.imageProxy = this.section('Image Proxy');
|
||||
this.smtp = this.section('SMTP');
|
||||
this.pushNotificationServer = this.section('Push Notification Server');
|
||||
this.highAvailability = this.section('High Availability');
|
||||
this.cacheSettings = this.section('Cache Settings');
|
||||
this.rateLimiting = this.section('Rate Limiting');
|
||||
this.logging = this.section('Logging');
|
||||
this.sessionLengths = this.section('Session Lengths');
|
||||
this.performanceMonitoring = this.section('Performance Monitoring');
|
||||
this.developer = this.section('Developer');
|
||||
this.mobileSecurity = this.section('Mobile Security');
|
||||
}
|
||||
}
|
||||
|
||||
class SiteConfigurationCategory extends SidebarCategory {
|
||||
readonly customization: SidebarSection;
|
||||
readonly localization: SidebarSection;
|
||||
readonly usersAndTeams: SidebarSection;
|
||||
readonly notifications: SidebarSection;
|
||||
readonly systemWideNotifications: SidebarSection;
|
||||
readonly emoji: SidebarSection;
|
||||
readonly posts: SidebarSection;
|
||||
readonly contentFlagging: SidebarSection;
|
||||
readonly moveThread: SidebarSection;
|
||||
readonly fileSharingAndDownloads: SidebarSection;
|
||||
readonly publicLinks: SidebarSection;
|
||||
readonly notices: SidebarSection;
|
||||
|
||||
constructor(container: Locator) {
|
||||
super(container);
|
||||
this.customization = this.section('Customization');
|
||||
this.localization = this.section('Localization');
|
||||
this.usersAndTeams = this.section('Users and Teams');
|
||||
this.notifications = this.section('Notifications');
|
||||
this.systemWideNotifications = this.section('System-wide Notifications');
|
||||
this.emoji = this.section('Emoji');
|
||||
this.posts = this.section('Posts');
|
||||
this.contentFlagging = this.section('Content Flagging');
|
||||
this.moveThread = this.section('Move Thread (Beta)');
|
||||
this.fileSharingAndDownloads = this.section('File Sharing and Downloads');
|
||||
this.publicLinks = this.section('Public Links');
|
||||
this.notices = this.section('Notices');
|
||||
}
|
||||
}
|
||||
|
||||
class AuthenticationCategory extends SidebarCategory {
|
||||
readonly signup: SidebarSection;
|
||||
readonly email: SidebarSection;
|
||||
readonly password: SidebarSection;
|
||||
readonly mfa: SidebarSection;
|
||||
readonly adLdap: SidebarSection;
|
||||
readonly saml: SidebarSection;
|
||||
readonly openIdConnect: SidebarSection;
|
||||
readonly guestAccess: SidebarSection;
|
||||
|
||||
constructor(container: Locator) {
|
||||
super(container);
|
||||
this.signup = this.section('Signup');
|
||||
this.email = this.section('Email');
|
||||
this.password = this.section('Password');
|
||||
this.mfa = this.section('MFA');
|
||||
this.adLdap = this.section('AD/LDAP');
|
||||
this.saml = this.section('SAML 2.0');
|
||||
this.openIdConnect = this.section('OpenID Connect');
|
||||
this.guestAccess = this.section('Guest Access');
|
||||
}
|
||||
}
|
||||
|
||||
class PluginsCategory extends SidebarCategory {
|
||||
readonly pluginManagement: SidebarSection;
|
||||
readonly agents: SidebarSection;
|
||||
readonly calls: SidebarSection;
|
||||
readonly playbooks: SidebarSection;
|
||||
readonly boards: SidebarSection;
|
||||
|
||||
constructor(container: Locator) {
|
||||
super(container);
|
||||
this.pluginManagement = this.section('Plugin Management');
|
||||
this.agents = this.section('Agents');
|
||||
this.calls = this.section('Calls');
|
||||
this.playbooks = this.section('Playbooks');
|
||||
this.boards = this.section('Mattermost Boards');
|
||||
}
|
||||
|
||||
getPlugin(pluginName: string): SidebarSection {
|
||||
const link = this.sections.getByRole('link', {name: pluginName, exact: true});
|
||||
return new SidebarSection(this.sections, link);
|
||||
}
|
||||
}
|
||||
|
||||
class IntegrationsCategory extends SidebarCategory {
|
||||
readonly integrationManagement: SidebarSection;
|
||||
readonly botAccounts: SidebarSection;
|
||||
readonly gif: SidebarSection;
|
||||
readonly cors: SidebarSection;
|
||||
readonly embedding: SidebarSection;
|
||||
|
||||
constructor(container: Locator) {
|
||||
super(container);
|
||||
this.integrationManagement = this.section('Integration Management');
|
||||
this.botAccounts = this.section('Bot Accounts');
|
||||
this.gif = this.section('GIF');
|
||||
this.cors = this.section('CORS');
|
||||
this.embedding = this.section('Embedding');
|
||||
}
|
||||
}
|
||||
|
||||
class ComplianceCategory extends SidebarCategory {
|
||||
readonly dataRetentionPolicies: SidebarSection;
|
||||
readonly complianceExport: SidebarSection;
|
||||
readonly complianceMonitoring: SidebarSection;
|
||||
readonly auditLogging: SidebarSection;
|
||||
readonly customTermsOfService: SidebarSection;
|
||||
|
||||
constructor(container: Locator) {
|
||||
super(container);
|
||||
this.dataRetentionPolicies = this.section('Data Retention Policies');
|
||||
this.complianceExport = this.section('Compliance Export');
|
||||
this.complianceMonitoring = this.section('Compliance Monitoring');
|
||||
this.auditLogging = this.section('Audit Logging');
|
||||
this.customTermsOfService = this.section('Custom Terms of Service');
|
||||
}
|
||||
}
|
||||
|
||||
class ExperimentalCategory extends SidebarCategory {
|
||||
readonly features: SidebarSection;
|
||||
readonly featureFlags: SidebarSection;
|
||||
|
||||
constructor(container: Locator) {
|
||||
super(container);
|
||||
this.features = this.section('Features');
|
||||
this.featureFlags = this.section('Feature Flags');
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,28 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {Locator, expect} from '@playwright/test';
|
||||
|
||||
/**
|
||||
* System Console Sidebar Header component
|
||||
*/
|
||||
export default class SystemConsoleSidebarHeader {
|
||||
readonly container: Locator;
|
||||
readonly headerInfo: Locator;
|
||||
readonly title: Locator;
|
||||
readonly userName: Locator;
|
||||
readonly menuButton: Locator;
|
||||
|
||||
constructor(container: Locator) {
|
||||
this.container = container;
|
||||
this.headerInfo = container.locator('.header__info');
|
||||
this.title = container.getByText('System Console');
|
||||
this.userName = container.getByText(/^@/);
|
||||
this.menuButton = container.getByRole('button', {name: 'Menu Icon'});
|
||||
}
|
||||
|
||||
async toBeVisible() {
|
||||
await expect(this.container).toBeVisible();
|
||||
await expect(this.title).toBeVisible();
|
||||
}
|
||||
}
|
||||
|
|
@ -3,101 +3,81 @@
|
|||
|
||||
import {Page} from '@playwright/test';
|
||||
|
||||
import {components} from '@/ui/components';
|
||||
import SystemConsoleNavbar from '@/ui/components/system_console/navbar';
|
||||
import SystemConsoleSidebar from '@/ui/components/system_console/sidebar';
|
||||
import SystemConsoleHeader from '@/ui/components/system_console/header';
|
||||
import EditionAndLicense from '@/ui/components/system_console/sections/about/edition_and_license';
|
||||
import TeamStatistics from '@/ui/components/system_console/sections/reporting/team_statistics';
|
||||
import Users from '@/ui/components/system_console/sections/user_management/users';
|
||||
import DelegatedGranularAdministration from '@/ui/components/system_console/sections/user_management/delegated_granular_administration';
|
||||
import MobileSecurity from '@/ui/components/system_console/sections/environment/mobile_security';
|
||||
import Notifications from '@/ui/components/system_console/sections/site_configuration/notifications';
|
||||
import FeatureDiscovery from '@/ui/components/system_console/sections/system_users/feature_discovery';
|
||||
|
||||
export default class SystemConsolePage {
|
||||
readonly page: Page;
|
||||
|
||||
readonly sidebar;
|
||||
readonly navbar;
|
||||
// Layout
|
||||
readonly navbar: SystemConsoleNavbar;
|
||||
readonly sidebar: SystemConsoleSidebar;
|
||||
readonly header: SystemConsoleHeader;
|
||||
|
||||
// About
|
||||
readonly editionAndLicense: EditionAndLicense;
|
||||
|
||||
// Reporting
|
||||
readonly teamStatistics: TeamStatistics;
|
||||
|
||||
// User Management
|
||||
readonly users: Users;
|
||||
readonly delegatedGranularAdministration: DelegatedGranularAdministration;
|
||||
|
||||
// Environment
|
||||
readonly mobileSecurity: MobileSecurity;
|
||||
|
||||
// Site Configuration
|
||||
readonly notifications: Notifications;
|
||||
|
||||
// System Console > Notifications
|
||||
readonly notifications;
|
||||
|
||||
/**
|
||||
* System Console -> User Management -> Users
|
||||
*/
|
||||
readonly systemUsers;
|
||||
readonly systemUsersFilterPopover;
|
||||
readonly systemUsersRoleMenu;
|
||||
readonly systemUsersStatusMenu;
|
||||
readonly systemUsersDateRangeMenu;
|
||||
readonly systemUsersColumnToggleMenu;
|
||||
readonly systemUsersActionMenus;
|
||||
|
||||
readonly mobileSecurity;
|
||||
|
||||
readonly featureDiscovery;
|
||||
|
||||
// modal
|
||||
readonly confirmModal;
|
||||
readonly exportModal;
|
||||
readonly saveChangesModal;
|
||||
// Feature Discovery (license-gated features)
|
||||
readonly featureDiscovery: FeatureDiscovery;
|
||||
|
||||
constructor(page: Page) {
|
||||
this.page = page;
|
||||
|
||||
// Layout
|
||||
this.navbar = new SystemConsoleNavbar(page.locator('.backstage-navbar'));
|
||||
this.sidebar = new SystemConsoleSidebar(page.locator('.admin-sidebar'));
|
||||
|
||||
const adminConsoleWrapper = page.locator('#adminConsoleWrapper');
|
||||
this.header = new SystemConsoleHeader(adminConsoleWrapper);
|
||||
|
||||
// About
|
||||
this.editionAndLicense = new EditionAndLicense(adminConsoleWrapper);
|
||||
|
||||
// Reporting
|
||||
this.teamStatistics = new TeamStatistics(adminConsoleWrapper);
|
||||
|
||||
// User Management
|
||||
this.users = new Users(adminConsoleWrapper);
|
||||
this.delegatedGranularAdministration = new DelegatedGranularAdministration(adminConsoleWrapper);
|
||||
|
||||
// Environment
|
||||
this.mobileSecurity = new MobileSecurity(adminConsoleWrapper);
|
||||
|
||||
// Site Configuration
|
||||
// System Console > Notifications
|
||||
this.notifications = new components.SystemConsoleNotifications(
|
||||
page.getByTestId('sysconsole_section_notifications'),
|
||||
);
|
||||
this.notifications = new Notifications(adminConsoleWrapper);
|
||||
|
||||
// Areas of the page
|
||||
this.navbar = new components.SystemConsoleNavbar(page.locator('.backstage-navbar'));
|
||||
this.sidebar = new components.SystemConsoleSidebar(page.locator('.admin-sidebar'));
|
||||
|
||||
// Sections and sub-sections
|
||||
this.systemUsers = new components.SystemUsers(page.getByTestId('systemUsersSection'));
|
||||
this.mobileSecurity = new components.SystemConsoleMobileSecurity(
|
||||
page.getByTestId('sysconsole_section_MobileSecuritySettings'),
|
||||
this.page,
|
||||
);
|
||||
this.featureDiscovery = new components.SystemConsoleFeatureDiscovery(page.getByTestId('featureDiscovery'));
|
||||
|
||||
// Menus & Popovers
|
||||
this.systemUsersFilterPopover = new components.SystemUsersFilterPopover(
|
||||
page.locator('#systemUsersFilterPopover'),
|
||||
);
|
||||
this.systemUsersRoleMenu = new components.SystemUsersFilterMenu(page.locator('#DropdownInput_filterRole'));
|
||||
this.systemUsersStatusMenu = new components.SystemUsersFilterMenu(page.locator('#DropdownInput_filterStatus'));
|
||||
this.systemUsersColumnToggleMenu = new components.SystemUsersColumnToggleMenu(
|
||||
page.locator('#systemUsersColumnTogglerMenu'),
|
||||
);
|
||||
this.systemUsersDateRangeMenu = new components.SystemUsersFilterMenu(
|
||||
page.locator('#systemUsersDateRangeSelectorMenu'),
|
||||
);
|
||||
this.systemUsersActionMenus = Array.from(Array(10).keys()).map(
|
||||
(index) => new components.SystemUsersFilterMenu(page.locator(`#actionMenu-systemUsersTable-${index}`)),
|
||||
);
|
||||
|
||||
this.confirmModal = new components.GenericConfirmModal(page.locator('#confirmModal'));
|
||||
this.exportModal = new components.GenericConfirmModal(page.getByRole('dialog', {name: 'Export user data'}));
|
||||
this.saveChangesModal = new components.SystemUsers(page.locator('div.modal-content'));
|
||||
// Feature Discovery
|
||||
this.featureDiscovery = new FeatureDiscovery(adminConsoleWrapper);
|
||||
}
|
||||
|
||||
async toBeVisible() {
|
||||
await this.page.waitForLoadState('networkidle');
|
||||
|
||||
await this.sidebar.toBeVisible();
|
||||
await this.navbar.toBeVisible();
|
||||
await this.sidebar.toBeVisible();
|
||||
}
|
||||
|
||||
async goto() {
|
||||
await this.page.goto('/admin_console');
|
||||
}
|
||||
|
||||
async saveRoleChange() {
|
||||
await this.saveChangesModal.container.locator('button.btn-primary:has-text("Save")').click();
|
||||
}
|
||||
|
||||
async clickResetButton() {
|
||||
await this.saveChangesModal.container.locator('button.btn-primary:has-text("Reset")').click();
|
||||
}
|
||||
|
||||
async clickUpdateEmailButton() {
|
||||
await this.saveChangesModal.container.locator('button.btn-primary:has-text("Update")').click();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,18 +33,18 @@ test('Push Notification Contents setting displays correctly and saves all option
|
|||
// # Visit Notifications admin console page
|
||||
await systemConsolePage.goto();
|
||||
await systemConsolePage.toBeVisible();
|
||||
await systemConsolePage.sidebar.goToItem('Notifications');
|
||||
await systemConsolePage.sidebar.notifications.click();
|
||||
|
||||
// # Wait for Notifications section to load
|
||||
const notifications = systemConsolePage.notifications;
|
||||
await notifications.toBeVisible();
|
||||
|
||||
// * Verify that setting is visible and matches text content
|
||||
await notifications.pushNotificationContents.scrollIntoViewIfNeeded();
|
||||
await expect(notifications.pushNotificationContents).toBeVisible();
|
||||
await notifications.pushNotificationContents.container.scrollIntoViewIfNeeded();
|
||||
await notifications.pushNotificationContents.toBeVisible();
|
||||
|
||||
// * Verify that the help text is visible and matches text content
|
||||
const helpText = notifications.pushNotificationContentsHelpText;
|
||||
const helpText = notifications.pushNotificationContents.helpText;
|
||||
await expect(helpText).toBeVisible();
|
||||
|
||||
const contents = [
|
||||
|
|
@ -69,7 +69,7 @@ test('Push Notification Contents setting displays correctly and saves all option
|
|||
await expect(strongElements.nth(4)).toHaveText(contents[8]);
|
||||
|
||||
// * Verify that the option/dropdown is visible and has default value
|
||||
const dropdown = notifications.pushNotificationContentsDropdown;
|
||||
const dropdown = notifications.pushNotificationContents.dropdown;
|
||||
await expect(dropdown).toBeVisible();
|
||||
await expect(dropdown).toHaveValue('full');
|
||||
|
||||
|
|
@ -86,7 +86,7 @@ test('Push Notification Contents setting displays correctly and saves all option
|
|||
await dropdown.selectOption({label: option.label});
|
||||
await expect(dropdown).toHaveValue(option.value);
|
||||
|
||||
await notifications.saveButton.click();
|
||||
await notifications.save();
|
||||
|
||||
// * Verify config is saved
|
||||
const {adminClient} = await pw.getAdminClient();
|
||||
|
|
@ -111,31 +111,30 @@ test('MM-T1210 Can change Support Email setting', async ({pw}) => {
|
|||
// # Visit Notifications admin console page
|
||||
await systemConsolePage.goto();
|
||||
await systemConsolePage.toBeVisible();
|
||||
await systemConsolePage.sidebar.goToItem('Notifications');
|
||||
await systemConsolePage.sidebar.notifications.click();
|
||||
|
||||
// # Wait for Notifications section to load
|
||||
const notifications = systemConsolePage.notifications;
|
||||
await notifications.toBeVisible();
|
||||
|
||||
// # Scroll Support Email section into view and verify that it's visible
|
||||
const supportEmailSetting = notifications.supportEmailAddress;
|
||||
await supportEmailSetting.scrollIntoViewIfNeeded();
|
||||
await expect(supportEmailSetting).toBeVisible();
|
||||
await notifications.supportEmailAddress.container.scrollIntoViewIfNeeded();
|
||||
await notifications.supportEmailAddress.toBeVisible();
|
||||
|
||||
// * Verify that the help text is visible and matches text content
|
||||
await expect(notifications.supportEmailHelpText).toBeVisible();
|
||||
await expect(notifications.supportEmailHelpText).toHaveText('Email address displayed on support emails.');
|
||||
await expect(notifications.supportEmailAddress.helpText).toBeVisible();
|
||||
await expect(notifications.supportEmailAddress.helpText).toHaveText('Email address displayed on support emails.');
|
||||
|
||||
// # Clear and type new email
|
||||
const newEmail = 'changed_for_test_support@example.com';
|
||||
await notifications.supportEmailAddressInput.clear();
|
||||
await notifications.supportEmailAddressInput.fill(newEmail);
|
||||
await notifications.supportEmailAddress.clear();
|
||||
await notifications.supportEmailAddress.fill(newEmail);
|
||||
|
||||
// * Verify that set value is visible and matches text
|
||||
await expect(notifications.supportEmailAddressInput).toHaveValue(newEmail);
|
||||
await expect(notifications.supportEmailAddress.input).toHaveValue(newEmail);
|
||||
|
||||
// # Save setting
|
||||
await notifications.saveButton.click();
|
||||
await notifications.save();
|
||||
|
||||
// * Verify that the config is correctly saved in the server
|
||||
const {adminClient} = await pw.getAdminClient();
|
||||
|
|
@ -158,29 +157,29 @@ test('MM-41671 cannot save the notifications page if mandatory fields are missin
|
|||
// # Visit Notifications admin console page
|
||||
await systemConsolePage.goto();
|
||||
await systemConsolePage.toBeVisible();
|
||||
await systemConsolePage.sidebar.goToItem('Notifications');
|
||||
await systemConsolePage.sidebar.notifications.click();
|
||||
|
||||
// # Wait for Notifications section to load
|
||||
const notifications = systemConsolePage.notifications;
|
||||
await notifications.toBeVisible();
|
||||
|
||||
const tests = [
|
||||
{name: 'Support Email Address', fieldInput: notifications.supportEmailAddressInput},
|
||||
{name: 'Notification Display Name', fieldInput: notifications.notificationDisplayNameInput},
|
||||
{name: 'Notification From Address', fieldInput: notifications.notificationFromAddressInput},
|
||||
{name: 'Support Email Address', field: notifications.supportEmailAddress},
|
||||
{name: 'Notification Display Name', field: notifications.notificationDisplayName},
|
||||
{name: 'Notification From Address', field: notifications.notificationFromAddress},
|
||||
];
|
||||
|
||||
for (const testCase of tests) {
|
||||
// # Clear the field
|
||||
await expect(testCase.fieldInput).toBeVisible();
|
||||
await testCase.fieldInput.clear();
|
||||
await testCase.field.toBeVisible();
|
||||
await testCase.field.clear();
|
||||
|
||||
// * Error message is shown and save button is disabled
|
||||
await expect(notifications.errorMessage).toHaveText(`"${testCase.name}" is required`);
|
||||
await expect(notifications.saveButton).toBeDisabled();
|
||||
|
||||
// # Insert something in the field
|
||||
await testCase.fieldInput.fill('anything');
|
||||
await testCase.field.fill('anything');
|
||||
|
||||
// * Ensure no error message is shown and the save button is not disabled
|
||||
await expect(notifications.errorMessage).toHaveCount(0);
|
||||
|
|
|
|||
|
|
@ -25,135 +25,140 @@ test('should be able to enable mobile security settings when licensed', async ({
|
|||
await systemConsolePage.toBeVisible();
|
||||
|
||||
// # Go to Mobile Security section
|
||||
await systemConsolePage.sidebar.goToItem('Mobile Security');
|
||||
await systemConsolePage.sidebar.mobileSecurity.click();
|
||||
await systemConsolePage.mobileSecurity.toBeVisible();
|
||||
|
||||
// # Enable Biometric Authentication
|
||||
await systemConsolePage.mobileSecurity.clickEnableBiometricAuthenticationToggleTrue();
|
||||
await systemConsolePage.mobileSecurity.enableBiometricAuthentication.selectTrue();
|
||||
|
||||
// * Verify only Biometric Authentication is enabled
|
||||
expect(await systemConsolePage.mobileSecurity.enableBiometricAuthenticationToggleTrue.isChecked()).toBe(true);
|
||||
expect(await systemConsolePage.mobileSecurity.preventScreenCaptureToggleTrue.isChecked()).toBe(false);
|
||||
expect(await systemConsolePage.mobileSecurity.jailbreakProtectionToggleTrue.isChecked()).toBe(false);
|
||||
await systemConsolePage.mobileSecurity.enableBiometricAuthentication.toBeTrue();
|
||||
await systemConsolePage.mobileSecurity.preventScreenCapture.toBeFalse();
|
||||
await systemConsolePage.mobileSecurity.enableJailbreakProtection.toBeFalse();
|
||||
|
||||
// # Save settings
|
||||
await systemConsolePage.mobileSecurity.clickSaveButton();
|
||||
await systemConsolePage.mobileSecurity.save();
|
||||
// # Wait until the save button has settled
|
||||
await pw.waitUntil(async () => (await systemConsolePage.mobileSecurity.saveButton.textContent()) === 'Save');
|
||||
|
||||
// # Go to any other section and come back to Mobile Security
|
||||
await systemConsolePage.sidebar.goToItem('Users');
|
||||
await systemConsolePage.systemUsers.toBeVisible();
|
||||
await systemConsolePage.sidebar.users.click();
|
||||
await systemConsolePage.users.toBeVisible();
|
||||
|
||||
await systemConsolePage.sidebar.goToItem('Mobile Security');
|
||||
await systemConsolePage.sidebar.mobileSecurity.click();
|
||||
await systemConsolePage.mobileSecurity.toBeVisible();
|
||||
|
||||
// * Verify Biometric Authentication is still enabled
|
||||
expect(await systemConsolePage.mobileSecurity.enableBiometricAuthenticationToggleTrue.isChecked()).toBe(true);
|
||||
expect(await systemConsolePage.mobileSecurity.preventScreenCaptureToggleTrue.isChecked()).toBe(false);
|
||||
expect(await systemConsolePage.mobileSecurity.jailbreakProtectionToggleTrue.isChecked()).toBe(false);
|
||||
await systemConsolePage.mobileSecurity.enableBiometricAuthentication.toBeTrue();
|
||||
await systemConsolePage.mobileSecurity.preventScreenCapture.toBeFalse();
|
||||
await systemConsolePage.mobileSecurity.enableJailbreakProtection.toBeFalse();
|
||||
|
||||
// # Enable Prevent Screen Capture
|
||||
await systemConsolePage.mobileSecurity.clickPreventScreenCaptureToggleTrue();
|
||||
await systemConsolePage.mobileSecurity.preventScreenCapture.selectTrue();
|
||||
|
||||
// * Verify only Biometric Authentication and Prevent Screen Capture are enabled
|
||||
expect(await systemConsolePage.mobileSecurity.enableBiometricAuthenticationToggleTrue.isChecked()).toBe(true);
|
||||
expect(await systemConsolePage.mobileSecurity.preventScreenCaptureToggleTrue.isChecked()).toBe(true);
|
||||
expect(await systemConsolePage.mobileSecurity.jailbreakProtectionToggleTrue.isChecked()).toBe(false);
|
||||
await systemConsolePage.mobileSecurity.enableBiometricAuthentication.toBeTrue();
|
||||
await systemConsolePage.mobileSecurity.preventScreenCapture.toBeTrue();
|
||||
await systemConsolePage.mobileSecurity.enableJailbreakProtection.toBeFalse();
|
||||
|
||||
// # Save settings
|
||||
await systemConsolePage.mobileSecurity.clickSaveButton();
|
||||
await systemConsolePage.mobileSecurity.save();
|
||||
// # Wait until the save button has settled
|
||||
await pw.waitUntil(async () => (await systemConsolePage.mobileSecurity.saveButton.textContent()) === 'Save');
|
||||
|
||||
// # Go to any other section and come back to Mobile Security
|
||||
await systemConsolePage.sidebar.goToItem('Users');
|
||||
await systemConsolePage.systemUsers.toBeVisible();
|
||||
await systemConsolePage.sidebar.users.click();
|
||||
await systemConsolePage.users.toBeVisible();
|
||||
|
||||
await systemConsolePage.sidebar.goToItem('Mobile Security');
|
||||
await systemConsolePage.sidebar.mobileSecurity.click();
|
||||
await systemConsolePage.mobileSecurity.toBeVisible();
|
||||
|
||||
// * Verify Biometric Authentication and Prevent Screen Capture are still enabled
|
||||
expect(await systemConsolePage.mobileSecurity.enableBiometricAuthenticationToggleTrue.isChecked()).toBe(true);
|
||||
expect(await systemConsolePage.mobileSecurity.preventScreenCaptureToggleTrue.isChecked()).toBe(true);
|
||||
expect(await systemConsolePage.mobileSecurity.jailbreakProtectionToggleTrue.isChecked()).toBe(false);
|
||||
await systemConsolePage.mobileSecurity.enableBiometricAuthentication.toBeTrue();
|
||||
await systemConsolePage.mobileSecurity.preventScreenCapture.toBeTrue();
|
||||
await systemConsolePage.mobileSecurity.enableJailbreakProtection.toBeFalse();
|
||||
|
||||
// # Enable Jailbreak Protection
|
||||
await systemConsolePage.mobileSecurity.clickJailbreakProtectionToggleTrue();
|
||||
await systemConsolePage.mobileSecurity.enableJailbreakProtection.selectTrue();
|
||||
|
||||
// * Verify all toggles are enabled
|
||||
expect(await systemConsolePage.mobileSecurity.enableBiometricAuthenticationToggleTrue.isChecked()).toBe(true);
|
||||
expect(await systemConsolePage.mobileSecurity.preventScreenCaptureToggleTrue.isChecked()).toBe(true);
|
||||
expect(await systemConsolePage.mobileSecurity.jailbreakProtectionToggleTrue.isChecked()).toBe(true);
|
||||
await systemConsolePage.mobileSecurity.enableBiometricAuthentication.toBeTrue();
|
||||
await systemConsolePage.mobileSecurity.preventScreenCapture.toBeTrue();
|
||||
await systemConsolePage.mobileSecurity.enableJailbreakProtection.toBeTrue();
|
||||
|
||||
// # Save settings
|
||||
await systemConsolePage.mobileSecurity.clickSaveButton();
|
||||
await systemConsolePage.mobileSecurity.save();
|
||||
// # Wait until the save button has settled
|
||||
await pw.waitUntil(async () => (await systemConsolePage.mobileSecurity.saveButton.textContent()) === 'Save');
|
||||
|
||||
// # Go to any other section and come back to Mobile Security
|
||||
await systemConsolePage.sidebar.goToItem('Users');
|
||||
await systemConsolePage.systemUsers.toBeVisible();
|
||||
await systemConsolePage.sidebar.users.click();
|
||||
await systemConsolePage.users.toBeVisible();
|
||||
|
||||
await systemConsolePage.sidebar.goToItem('Mobile Security');
|
||||
await systemConsolePage.sidebar.mobileSecurity.click();
|
||||
await systemConsolePage.mobileSecurity.toBeVisible();
|
||||
|
||||
// * Verify all toggles are still enabled
|
||||
expect(await systemConsolePage.mobileSecurity.enableBiometricAuthenticationToggleTrue.isChecked()).toBe(true);
|
||||
expect(await systemConsolePage.mobileSecurity.preventScreenCaptureToggleTrue.isChecked()).toBe(true);
|
||||
expect(await systemConsolePage.mobileSecurity.jailbreakProtectionToggleTrue.isChecked()).toBe(true);
|
||||
await systemConsolePage.mobileSecurity.enableBiometricAuthentication.toBeTrue();
|
||||
await systemConsolePage.mobileSecurity.preventScreenCapture.toBeTrue();
|
||||
await systemConsolePage.mobileSecurity.enableJailbreakProtection.toBeTrue();
|
||||
|
||||
if (license.SkuShortName === 'advanced') {
|
||||
// # Enable Secure File Preview
|
||||
await systemConsolePage.mobileSecurity.clickEnableSecureFilePreviewToggleTrue();
|
||||
await systemConsolePage.mobileSecurity.enableSecureFilePreviewMode.selectTrue();
|
||||
|
||||
// * Verify all toggles are enabled
|
||||
expect(await systemConsolePage.mobileSecurity.enableBiometricAuthenticationToggleTrue.isChecked()).toBe(true);
|
||||
expect(await systemConsolePage.mobileSecurity.preventScreenCaptureToggleTrue.isChecked()).toBe(true);
|
||||
expect(await systemConsolePage.mobileSecurity.jailbreakProtectionToggleTrue.isChecked()).toBe(true);
|
||||
expect(await systemConsolePage.mobileSecurity.enableSecureFilePreviewToggleTrue.isChecked()).toBe(true);
|
||||
expect(await systemConsolePage.mobileSecurity.allowPdfLinkNavigationToggleTrue.isChecked()).toBe(false);
|
||||
await systemConsolePage.mobileSecurity.enableBiometricAuthentication.toBeTrue();
|
||||
await systemConsolePage.mobileSecurity.preventScreenCapture.toBeTrue();
|
||||
await systemConsolePage.mobileSecurity.enableJailbreakProtection.toBeTrue();
|
||||
await systemConsolePage.mobileSecurity.enableSecureFilePreviewMode.toBeTrue();
|
||||
await systemConsolePage.mobileSecurity.allowPdfLinkNavigation.toBeFalse();
|
||||
|
||||
// # Save settings
|
||||
await systemConsolePage.mobileSecurity.clickSaveButton();
|
||||
await systemConsolePage.mobileSecurity.save();
|
||||
// # Wait until the save button has settled
|
||||
await pw.waitUntil(async () => (await systemConsolePage.mobileSecurity.saveButton.textContent()) === 'Save');
|
||||
|
||||
// # Go to any other section and come back to Mobile Security
|
||||
await systemConsolePage.sidebar.goToItem('Users');
|
||||
await systemConsolePage.systemUsers.toBeVisible();
|
||||
await systemConsolePage.sidebar.goToItem('Mobile Security');
|
||||
await systemConsolePage.sidebar.users.click();
|
||||
await systemConsolePage.users.toBeVisible();
|
||||
await systemConsolePage.sidebar.mobileSecurity.click();
|
||||
await systemConsolePage.mobileSecurity.toBeVisible();
|
||||
|
||||
// * Verify all toggles are still enabled
|
||||
expect(await systemConsolePage.mobileSecurity.enableBiometricAuthenticationToggleTrue.isChecked()).toBe(true);
|
||||
expect(await systemConsolePage.mobileSecurity.preventScreenCaptureToggleTrue.isChecked()).toBe(true);
|
||||
expect(await systemConsolePage.mobileSecurity.jailbreakProtectionToggleTrue.isChecked()).toBe(true);
|
||||
expect(await systemConsolePage.mobileSecurity.enableSecureFilePreviewToggleTrue.isChecked()).toBe(true);
|
||||
expect(await systemConsolePage.mobileSecurity.allowPdfLinkNavigationToggleTrue.isChecked()).toBe(false);
|
||||
await systemConsolePage.mobileSecurity.enableBiometricAuthentication.toBeTrue();
|
||||
await systemConsolePage.mobileSecurity.preventScreenCapture.toBeTrue();
|
||||
await systemConsolePage.mobileSecurity.enableJailbreakProtection.toBeTrue();
|
||||
await systemConsolePage.mobileSecurity.enableSecureFilePreviewMode.toBeTrue();
|
||||
await systemConsolePage.mobileSecurity.allowPdfLinkNavigation.toBeFalse();
|
||||
|
||||
// # Enable Allow PDF Link Navigation
|
||||
await systemConsolePage.mobileSecurity.clickAllowPdfLinkNavigationToggleTrue();
|
||||
await systemConsolePage.mobileSecurity.allowPdfLinkNavigation.selectTrue();
|
||||
|
||||
// * Verify all toggles are enabled
|
||||
expect(await systemConsolePage.mobileSecurity.enableBiometricAuthenticationToggleTrue.isChecked()).toBe(true);
|
||||
expect(await systemConsolePage.mobileSecurity.preventScreenCaptureToggleTrue.isChecked()).toBe(true);
|
||||
expect(await systemConsolePage.mobileSecurity.jailbreakProtectionToggleTrue.isChecked()).toBe(true);
|
||||
expect(await systemConsolePage.mobileSecurity.enableSecureFilePreviewToggleTrue.isChecked()).toBe(true);
|
||||
expect(await systemConsolePage.mobileSecurity.allowPdfLinkNavigationToggleTrue.isChecked()).toBe(true);
|
||||
await systemConsolePage.mobileSecurity.enableBiometricAuthentication.toBeTrue();
|
||||
await systemConsolePage.mobileSecurity.preventScreenCapture.toBeTrue();
|
||||
await systemConsolePage.mobileSecurity.enableJailbreakProtection.toBeTrue();
|
||||
await systemConsolePage.mobileSecurity.enableSecureFilePreviewMode.toBeTrue();
|
||||
await systemConsolePage.mobileSecurity.allowPdfLinkNavigation.toBeTrue();
|
||||
|
||||
// # Save settings
|
||||
await systemConsolePage.mobileSecurity.clickSaveButton();
|
||||
await systemConsolePage.mobileSecurity.save();
|
||||
// # Wait until the save button has settled
|
||||
await pw.waitUntil(async () => (await systemConsolePage.mobileSecurity.saveButton.textContent()) === 'Save');
|
||||
|
||||
// # Go to any other section and come back to Mobile Security
|
||||
await systemConsolePage.sidebar.goToItem('Users');
|
||||
await systemConsolePage.systemUsers.toBeVisible();
|
||||
await systemConsolePage.sidebar.goToItem('Mobile Security');
|
||||
await systemConsolePage.sidebar.users.click();
|
||||
await systemConsolePage.users.toBeVisible();
|
||||
await systemConsolePage.sidebar.mobileSecurity.click();
|
||||
await systemConsolePage.mobileSecurity.toBeVisible();
|
||||
|
||||
// * Verify all toggles are still enabled
|
||||
expect(await systemConsolePage.mobileSecurity.enableBiometricAuthenticationToggleTrue.isChecked()).toBe(true);
|
||||
expect(await systemConsolePage.mobileSecurity.preventScreenCaptureToggleTrue.isChecked()).toBe(true);
|
||||
expect(await systemConsolePage.mobileSecurity.jailbreakProtectionToggleTrue.isChecked()).toBe(true);
|
||||
expect(await systemConsolePage.mobileSecurity.enableSecureFilePreviewToggleTrue.isChecked()).toBe(true);
|
||||
expect(await systemConsolePage.mobileSecurity.allowPdfLinkNavigationToggleTrue.isChecked()).toBe(true);
|
||||
await systemConsolePage.mobileSecurity.enableBiometricAuthentication.toBeTrue();
|
||||
await systemConsolePage.mobileSecurity.preventScreenCapture.toBeTrue();
|
||||
await systemConsolePage.mobileSecurity.enableJailbreakProtection.toBeTrue();
|
||||
await systemConsolePage.mobileSecurity.enableSecureFilePreviewMode.toBeTrue();
|
||||
await systemConsolePage.mobileSecurity.allowPdfLinkNavigation.toBeTrue();
|
||||
}
|
||||
});
|
||||
|
||||
|
|
@ -179,7 +184,7 @@ test('should show mobile security upsell when not licensed', async ({pw}) => {
|
|||
await systemConsolePage.toBeVisible();
|
||||
|
||||
// # Go to Mobile Security section
|
||||
await systemConsolePage.sidebar.goToItem('Mobile Security');
|
||||
await systemConsolePage.sidebar.mobileSecurity.click();
|
||||
await systemConsolePage.featureDiscovery.toBeVisible();
|
||||
|
||||
// * Verify title is correct
|
||||
|
|
@ -213,38 +218,39 @@ test('should show and enable Intune MAM when Enterprise Advanced licensed and Of
|
|||
await systemConsolePage.toBeVisible();
|
||||
|
||||
// # Go to Mobile Security section
|
||||
await systemConsolePage.sidebar.goToItem('Mobile Security');
|
||||
await systemConsolePage.sidebar.mobileSecurity.click();
|
||||
|
||||
// * Verify Intune MAM toggle is visible
|
||||
await expect(systemConsolePage.mobileSecurity.enableIntuneMAMToggleTrue).toBeVisible();
|
||||
await expect(systemConsolePage.mobileSecurity.enableIntuneMAMToggleFalse).toBeVisible();
|
||||
await expect(systemConsolePage.mobileSecurity.enableIntuneMAM.trueOption).toBeVisible();
|
||||
await expect(systemConsolePage.mobileSecurity.enableIntuneMAM.falseOption).toBeVisible();
|
||||
|
||||
// # Enable Intune MAM
|
||||
await systemConsolePage.mobileSecurity.clickEnableIntuneMAMToggleTrue();
|
||||
await systemConsolePage.mobileSecurity.enableIntuneMAM.selectTrue();
|
||||
|
||||
// * Verify Intune MAM is enabled
|
||||
await expect(await systemConsolePage.mobileSecurity.enableIntuneMAMToggleTrue.isChecked()).toBe(true);
|
||||
await systemConsolePage.mobileSecurity.enableIntuneMAM.toBeTrue();
|
||||
|
||||
await systemConsolePage.mobileSecurity.selectIntuneAuthService('office365');
|
||||
await systemConsolePage.mobileSecurity.authProvider.select('office365');
|
||||
|
||||
// # Fill in Intune configuration
|
||||
await systemConsolePage.mobileSecurity.fillIntuneTenantId('12345678-1234-1234-1234-123456789012');
|
||||
await systemConsolePage.mobileSecurity.fillIntuneClientId('87654321-4321-4321-4321-210987654321');
|
||||
await systemConsolePage.mobileSecurity.tenantId.fill('12345678-1234-1234-1234-123456789012');
|
||||
await systemConsolePage.mobileSecurity.clientId.fill('87654321-4321-4321-4321-210987654321');
|
||||
|
||||
// # Save settings
|
||||
await systemConsolePage.mobileSecurity.clickSaveButton();
|
||||
await systemConsolePage.mobileSecurity.save();
|
||||
|
||||
// # Wait until the save button has settled
|
||||
await pw.waitUntil(async () => (await systemConsolePage.mobileSecurity.saveButton.textContent()) === 'Save');
|
||||
|
||||
// # Go to any other section and come back to Mobile Security
|
||||
await systemConsolePage.sidebar.goToItem('Users');
|
||||
await systemConsolePage.systemUsers.toBeVisible();
|
||||
await systemConsolePage.sidebar.users.click();
|
||||
await systemConsolePage.users.toBeVisible();
|
||||
|
||||
await systemConsolePage.sidebar.goToItem('Mobile Security');
|
||||
await systemConsolePage.sidebar.mobileSecurity.click();
|
||||
await systemConsolePage.mobileSecurity.toBeVisible();
|
||||
|
||||
// * Verify Intune MAM is still enabled
|
||||
await expect(await systemConsolePage.mobileSecurity.enableIntuneMAMToggleTrue.isChecked()).toBe(true);
|
||||
await systemConsolePage.mobileSecurity.enableIntuneMAM.toBeTrue();
|
||||
});
|
||||
|
||||
test('should hide Intune MAM when Office365 is not configured', async ({pw}) => {
|
||||
|
|
@ -271,12 +277,12 @@ test('should hide Intune MAM when Office365 is not configured', async ({pw}) =>
|
|||
await systemConsolePage.toBeVisible();
|
||||
|
||||
// # Go to Mobile Security section
|
||||
await systemConsolePage.sidebar.goToItem('Mobile Security');
|
||||
await systemConsolePage.sidebar.mobileSecurity.click();
|
||||
|
||||
// * Verify Intune MAM toggle is visible
|
||||
await expect(systemConsolePage.mobileSecurity.enableIntuneMAMToggleTrue).toBeVisible();
|
||||
await expect(systemConsolePage.mobileSecurity.enableIntuneMAMToggleFalse).toBeVisible();
|
||||
await expect(systemConsolePage.mobileSecurity.intuneAuthServiceDropdown).toBeDisabled();
|
||||
await expect(systemConsolePage.mobileSecurity.enableIntuneMAM.trueOption).toBeVisible();
|
||||
await expect(systemConsolePage.mobileSecurity.enableIntuneMAM.falseOption).toBeVisible();
|
||||
await expect(systemConsolePage.mobileSecurity.authProvider.dropdown).toBeDisabled();
|
||||
});
|
||||
|
||||
test('should configure new IntuneSettings with Office365 auth provider', async ({pw}) => {
|
||||
|
|
@ -307,45 +313,42 @@ test('should configure new IntuneSettings with Office365 auth provider', async (
|
|||
await systemConsolePage.toBeVisible();
|
||||
|
||||
// # Go to Mobile Security section
|
||||
await systemConsolePage.sidebar.goToItem('Mobile Security');
|
||||
await systemConsolePage.sidebar.mobileSecurity.click();
|
||||
|
||||
// * Verify new Intune toggle is visible
|
||||
await expect(systemConsolePage.mobileSecurity.enableIntuneToggleTrue).toBeVisible();
|
||||
await expect(systemConsolePage.mobileSecurity.enableIntuneToggleFalse).toBeVisible();
|
||||
await expect(systemConsolePage.mobileSecurity.enableIntuneMAM.trueOption).toBeVisible();
|
||||
await expect(systemConsolePage.mobileSecurity.enableIntuneMAM.falseOption).toBeVisible();
|
||||
|
||||
// # Enable Intune
|
||||
await systemConsolePage.mobileSecurity.clickEnableIntuneToggleTrue();
|
||||
await systemConsolePage.mobileSecurity.enableIntuneMAM.selectTrue();
|
||||
|
||||
// * Verify Intune is enabled
|
||||
expect(await systemConsolePage.mobileSecurity.enableIntuneToggleTrue.isChecked()).toBe(true);
|
||||
await systemConsolePage.mobileSecurity.enableIntuneMAM.toBeTrue();
|
||||
|
||||
// # Select Office365 as auth provider
|
||||
await systemConsolePage.mobileSecurity.selectIntuneAuthService('office365');
|
||||
await systemConsolePage.mobileSecurity.authProvider.select('office365');
|
||||
|
||||
// # Fill in Intune configuration
|
||||
await systemConsolePage.mobileSecurity.fillIntuneTenantId('12345678-1234-1234-1234-123456789012');
|
||||
await systemConsolePage.mobileSecurity.fillIntuneClientId('87654321-4321-4321-4321-210987654321');
|
||||
await systemConsolePage.mobileSecurity.tenantId.fill('12345678-1234-1234-1234-123456789012');
|
||||
await systemConsolePage.mobileSecurity.clientId.fill('87654321-4321-4321-4321-210987654321');
|
||||
|
||||
// # Save settings
|
||||
await systemConsolePage.mobileSecurity.clickSaveButton();
|
||||
await systemConsolePage.mobileSecurity.save();
|
||||
|
||||
// # Wait until the save button has settled
|
||||
await pw.waitUntil(async () => (await systemConsolePage.mobileSecurity.saveButton.textContent()) === 'Save');
|
||||
|
||||
// # Go to any other section and come back to Mobile Security
|
||||
await systemConsolePage.sidebar.goToItem('Users');
|
||||
await systemConsolePage.systemUsers.toBeVisible();
|
||||
await systemConsolePage.sidebar.users.click();
|
||||
await systemConsolePage.users.toBeVisible();
|
||||
|
||||
await systemConsolePage.sidebar.goToItem('Mobile Security');
|
||||
await systemConsolePage.sidebar.mobileSecurity.click();
|
||||
await systemConsolePage.mobileSecurity.toBeVisible();
|
||||
|
||||
// * Verify Intune is still enabled and configured
|
||||
expect(await systemConsolePage.mobileSecurity.enableIntuneToggleTrue.isChecked()).toBe(true);
|
||||
expect(await systemConsolePage.mobileSecurity.intuneTenantIdInput.inputValue()).toBe(
|
||||
'12345678-1234-1234-1234-123456789012',
|
||||
);
|
||||
expect(await systemConsolePage.mobileSecurity.intuneClientIdInput.inputValue()).toBe(
|
||||
'87654321-4321-4321-4321-210987654321',
|
||||
);
|
||||
await systemConsolePage.mobileSecurity.enableIntuneMAM.toBeTrue();
|
||||
expect(await systemConsolePage.mobileSecurity.tenantId.getValue()).toBe('12345678-1234-1234-1234-123456789012');
|
||||
expect(await systemConsolePage.mobileSecurity.clientId.getValue()).toBe('87654321-4321-4321-4321-210987654321');
|
||||
});
|
||||
|
||||
test('should configure new IntuneSettings with SAML auth provider', async ({pw}) => {
|
||||
|
|
@ -365,7 +368,7 @@ test('should configure new IntuneSettings with SAML auth provider', async ({pw})
|
|||
const serverUrl = process.env.MM_SERVER_URL || 'http://localhost:8065';
|
||||
|
||||
// # Upload a valid SAML IdP certificate using fetch
|
||||
const idpCert = `-----BEGIN CERTIFICATE-----\nMIIDXTCCAkWgAwIBAgIJAKC1r6Qw3v6OMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNVBAYTAlVTMRYwFAYDVQQIDA1Tb21lLVN0YXRlMRYwFAYDVQQKDA1FeGFtcGxlIEluYy4wHhcNMTkwMTAxMDAwMDAwWhcNMjkwMTAxMDAwMDAwWjBFMQswCQYDVQQGEwJVUzEWMBQGA1UECAwNU29tZS1TdGF0ZTEWMBQGA1UECgwNRXhhbXBsZSBJbmMuMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu6Qw3v6OMC1r6Qw3v6OMC1r6Qw3v6OMC1r6Qw3v6OMC1r6Qw3v6OMC1r6Qw3v6OMC1r6Qw3v6OMC1r6Qw3v6OMC1r6Qw3v6OMC1r6Qw3v6OMC1r6Qw3v6OMC1r6Qw3v6OMC1r6Qw3v6OMC1r6Qw3v6OMC1r6Qw3v6OMC1r6Qw3v6OMC1r6Qw3v6OMC1r6Qw3v6OMC1r6QwIDAQABo1AwTjAdBgNVHQ4EFgQU6Qw3v6OMC1r6Qw3v6OMC1r6Qw3v6OMAwGA1UdEwQFMAMBAf8wHwYDVR0jBBgwFoAU6Qw3v6OMC1r6Qw3v6OMC1r6Qw3v6OMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAKQw3v6OMC1r6Qw3v6OMC1r6Qw3v6OMC1r6Qw3v6OMC1r6Qw3v6OMC1r6Qw3v6OMC1r6Qw3v6OMC1r6Qw3v6OMC1r6Qw3v6OMC1r6Qw3v6OMC1r6Qw3v6OMC1r6Qw3v6OMC1r6Qw3v6OMC1r6Qw3v6OMC1r6Qw3v6OMC1r6Qw3v6OMC1r6Qw3v6OMC1r6Qw3v6OMC1r6Qw=\n-----END CERTIFICATE-----\n`;
|
||||
const idpCert = `-----BEGIN CERTIFICATE-----\nMIIDXTCCAkWgAwIBAgIJAKC1r6Qw3v6OMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNVBAYTAlVTMRYwFAYDVQQIDA1Tb21lLVN0YXRlMRYwFAYDVQQKDA1FeGFtcGxlIEluYy4wHhcNMTkwMTAxMDAwMDAwWhcNMjkwMTAxMDAwMDAwWjBFMQswCQYDVQQGEwJVUzEWMBQGA1UECAwNU29tZS1TdGF0ZTEWMBQGA1UECgwNRXhhbXBsZSBJbmMuMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu6Qw3v6OMC1r6Qw3v6OMC1r6Qw3v6OMC1r6Qw3v6OMC1r6Qw3v6OMC1r6Qw3v6OMC1r6Qw3v6OMC1r6Qw3v6OMC1r6Qw3v6OMC1r6Qw3v6OMC1r6Qw3v6OMC1r6Qw3v6OMC1r6Qw3v6OMC1r6Qw3v6OMC1r6Qw3v6OMC1r6Qw3v6OMC1r6Qw3v6OMC1r6QwIDAQABo1AwTjAdBgNVHQ4EFgQU6Qw3v6OMC1r6Qw3v6OMC1r6Qw3v6OMAwGA1UdEwQFMAMBAf8wHwYDVR0jBBgwFoAU6Qw3v6OMC1r6Qw3v6OMC1r6Qw3v6OMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAKQw3v6OMC1r6Qw3v6OMC1r6Qw3v6OMC1r6Qw3v6OMC1r6Qw3v6OMC1r6Qw3v6OMC1r6Qw3v6OMC1r6Qw3v6OMC1r6Qw3v6OMC1r6Qw3v6OMC1r6Qw3v6OMC1r6Qw3v6OMC1r6Qw3v6OMC1r6Qw3v6OMC1r6Qw3v6OMC1r6Qw3v6OMC1r6Qw3v6OMC1r6Qw=\n-----END CERTIFICATE-----\n`;
|
||||
const idpFormData = new FormData();
|
||||
idpFormData.append(
|
||||
'certificate',
|
||||
|
|
@ -413,41 +416,38 @@ test('should configure new IntuneSettings with SAML auth provider', async ({pw})
|
|||
await systemConsolePage.toBeVisible();
|
||||
|
||||
// # Go to Mobile Security section
|
||||
await systemConsolePage.sidebar.goToItem('Mobile Security');
|
||||
await systemConsolePage.sidebar.mobileSecurity.click();
|
||||
|
||||
// * Verify new Intune toggle is visible
|
||||
await expect(systemConsolePage.mobileSecurity.enableIntuneToggleTrue).toBeVisible();
|
||||
await expect(systemConsolePage.mobileSecurity.enableIntuneMAM.trueOption).toBeVisible();
|
||||
|
||||
// # Enable Intune
|
||||
await systemConsolePage.mobileSecurity.clickEnableIntuneToggleTrue();
|
||||
await systemConsolePage.mobileSecurity.enableIntuneMAM.selectTrue();
|
||||
|
||||
// # Select SAML as auth provider
|
||||
await systemConsolePage.mobileSecurity.selectIntuneAuthService('saml');
|
||||
await systemConsolePage.mobileSecurity.authProvider.select('saml');
|
||||
|
||||
// # Fill in Intune configuration
|
||||
await systemConsolePage.mobileSecurity.fillIntuneTenantId('abcdef01-2345-6789-abcd-ef0123456789');
|
||||
await systemConsolePage.mobileSecurity.fillIntuneClientId('fedcba98-7654-3210-fedc-ba9876543210');
|
||||
await systemConsolePage.mobileSecurity.tenantId.fill('abcdef01-2345-6789-abcd-ef0123456789');
|
||||
await systemConsolePage.mobileSecurity.clientId.fill('fedcba98-7654-3210-fedc-ba9876543210');
|
||||
|
||||
// # Save settings
|
||||
await systemConsolePage.mobileSecurity.clickSaveButton();
|
||||
await systemConsolePage.mobileSecurity.save();
|
||||
|
||||
// # Wait until the save button has settled
|
||||
await pw.waitUntil(async () => (await systemConsolePage.mobileSecurity.saveButton.textContent()) === 'Save');
|
||||
|
||||
// # Go to any other section and come back to Mobile Security
|
||||
await systemConsolePage.sidebar.goToItem('Users');
|
||||
await systemConsolePage.systemUsers.toBeVisible();
|
||||
await systemConsolePage.sidebar.users.click();
|
||||
await systemConsolePage.users.toBeVisible();
|
||||
|
||||
await systemConsolePage.sidebar.goToItem('Mobile Security');
|
||||
await systemConsolePage.sidebar.mobileSecurity.click();
|
||||
await systemConsolePage.mobileSecurity.toBeVisible();
|
||||
|
||||
// * Verify Intune is still enabled and configured with SAML
|
||||
expect(await systemConsolePage.mobileSecurity.enableIntuneToggleTrue.isChecked()).toBe(true);
|
||||
expect(await systemConsolePage.mobileSecurity.intuneTenantIdInput.inputValue()).toBe(
|
||||
'abcdef01-2345-6789-abcd-ef0123456789',
|
||||
);
|
||||
expect(await systemConsolePage.mobileSecurity.intuneClientIdInput.inputValue()).toBe(
|
||||
'fedcba98-7654-3210-fedc-ba9876543210',
|
||||
);
|
||||
await systemConsolePage.mobileSecurity.enableIntuneMAM.toBeTrue();
|
||||
expect(await systemConsolePage.mobileSecurity.tenantId.getValue()).toBe('abcdef01-2345-6789-abcd-ef0123456789');
|
||||
expect(await systemConsolePage.mobileSecurity.clientId.getValue()).toBe('fedcba98-7654-3210-fedc-ba9876543210');
|
||||
});
|
||||
|
||||
test('should disable Intune inputs when toggle is off', async ({pw}) => {
|
||||
|
|
@ -477,18 +477,18 @@ test('should disable Intune inputs when toggle is off', async ({pw}) => {
|
|||
await systemConsolePage.toBeVisible();
|
||||
|
||||
// # Go to Mobile Security section
|
||||
await systemConsolePage.sidebar.goToItem('Mobile Security');
|
||||
await systemConsolePage.sidebar.mobileSecurity.click();
|
||||
|
||||
// * Verify Intune inputs are disabled when toggle is off
|
||||
expect(await systemConsolePage.mobileSecurity.intuneAuthServiceDropdown.isDisabled()).toBe(true);
|
||||
expect(await systemConsolePage.mobileSecurity.intuneTenantIdInput.isDisabled()).toBe(true);
|
||||
expect(await systemConsolePage.mobileSecurity.intuneClientIdInput.isDisabled()).toBe(true);
|
||||
expect(await systemConsolePage.mobileSecurity.authProvider.dropdown.isDisabled()).toBe(true);
|
||||
expect(await systemConsolePage.mobileSecurity.tenantId.input.isDisabled()).toBe(true);
|
||||
expect(await systemConsolePage.mobileSecurity.clientId.input.isDisabled()).toBe(true);
|
||||
|
||||
// # Enable Intune
|
||||
await systemConsolePage.mobileSecurity.clickEnableIntuneToggleTrue();
|
||||
await systemConsolePage.mobileSecurity.enableIntuneMAM.selectTrue();
|
||||
|
||||
// * Verify Intune inputs are now enabled
|
||||
expect(await systemConsolePage.mobileSecurity.intuneAuthServiceDropdown.isDisabled()).toBe(false);
|
||||
expect(await systemConsolePage.mobileSecurity.intuneTenantIdInput.isDisabled()).toBe(false);
|
||||
expect(await systemConsolePage.mobileSecurity.intuneClientIdInput.isDisabled()).toBe(false);
|
||||
expect(await systemConsolePage.mobileSecurity.authProvider.dropdown.isDisabled()).toBe(false);
|
||||
expect(await systemConsolePage.mobileSecurity.tenantId.input.isDisabled()).toBe(false);
|
||||
expect(await systemConsolePage.mobileSecurity.clientId.input.isDisabled()).toBe(false);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -3,81 +3,7 @@
|
|||
|
||||
import {UserProfile} from '@mattermost/types/users';
|
||||
|
||||
import {expect, PlaywrightExtended, test} from '@mattermost/playwright-lib';
|
||||
|
||||
// setupSystemManagerRole configures the system manager with the given permission ("Can Edit", "Read only", "No access")
|
||||
// for the given section and subsection (e.g. "permission_section_reporting_site_statistics" and "permission_section_reporting_team_statistics").
|
||||
//
|
||||
// We do this via the system console and not the API because this page has multiple queries to build up the
|
||||
// final API call that are all ultimately part of the spec, and we want to test the effects of those, not
|
||||
// merely a hand-created version of the same.
|
||||
const setupDefaultSystemManagerRole = async (
|
||||
pw: PlaywrightExtended,
|
||||
adminUser: UserProfile,
|
||||
sectionTestId: string,
|
||||
subsectionTestId: string,
|
||||
permissionText: string,
|
||||
) => {
|
||||
// Login as admin and navigate to System Console
|
||||
const {systemConsolePage: adminConsolePage} = await pw.testBrowser.login(adminUser);
|
||||
|
||||
// Go to System Console
|
||||
await adminConsolePage.goto();
|
||||
|
||||
// Login to the System Console and navigate to Delegated Granular Administration
|
||||
await adminConsolePage.sidebar.goToItem('Delegated Granular Administration');
|
||||
|
||||
// Find the System Manager row in the table
|
||||
const systemManagerText = adminConsolePage.page.getByText('System Manager', {exact: true}).first();
|
||||
await expect(systemManagerText).toBeVisible();
|
||||
|
||||
// Click on the System Manager text to go to its settings page
|
||||
await systemManagerText.click();
|
||||
|
||||
// Expand the section
|
||||
const sectionReporting = adminConsolePage.page.locator(`data-testid=${sectionTestId}`);
|
||||
const hideSubsectionsLink = sectionReporting.getByRole('button').filter({hasText: 'Hide'}).first();
|
||||
const showSubsectionsLink = sectionReporting.getByRole('button').filter({hasText: 'Show'}).first();
|
||||
|
||||
// Check which one is visible and click if needed
|
||||
const isHideVisible = await hideSubsectionsLink.isVisible();
|
||||
const isShowVisible = !isHideVisible && (await showSubsectionsLink.isVisible());
|
||||
|
||||
if (isShowVisible) {
|
||||
// Need to expand
|
||||
await showSubsectionsLink.click();
|
||||
}
|
||||
|
||||
// Get the whole row
|
||||
const rowReporting = adminConsolePage.page.locator('.PermissionRow').filter({has: sectionReporting});
|
||||
await rowReporting.click();
|
||||
|
||||
// Find the sub section
|
||||
const subsectionTeamStatistics = rowReporting.locator(`data-testid=${subsectionTestId}`);
|
||||
|
||||
await subsectionTeamStatistics.click();
|
||||
|
||||
// Look for dropdown button
|
||||
const dropdownButton = subsectionTeamStatistics.locator('button').first();
|
||||
|
||||
// Click the button to open the dropdown menu
|
||||
await dropdownButton.click();
|
||||
|
||||
// Click on the desired option in the dropdown
|
||||
const permissionOption = subsectionTeamStatistics.locator('.dropdown-menu').getByText(permissionText).first();
|
||||
await permissionOption.click();
|
||||
|
||||
// Click Save button
|
||||
const saveButton = adminConsolePage.page.getByRole('button', {name: 'Save'}).first();
|
||||
await saveButton.click();
|
||||
|
||||
// Wait for save operation to complete
|
||||
await adminConsolePage.page.waitForLoadState('networkidle');
|
||||
|
||||
// Go back to the main console
|
||||
await adminConsolePage.goto();
|
||||
await adminConsolePage.page.waitForLoadState('networkidle');
|
||||
};
|
||||
import {expect, PlaywrightExtended, SystemConsolePage, test} from '@mattermost/playwright-lib';
|
||||
|
||||
test(
|
||||
'MM-63378 System Manager without team access permissions cannot view team details',
|
||||
|
|
@ -97,88 +23,38 @@ test(
|
|||
// Create another team of which the user is not a member.
|
||||
const otherTeam = await adminClient.createTeam(await pw.random.team());
|
||||
|
||||
// Login as the user
|
||||
const {systemConsolePage} = await pw.testBrowser.login(systemManagerUser);
|
||||
// Configure the system manager with the default permissions (as admin).
|
||||
await setupSystemManagerPermission(pw, adminUser, 'reporting', 'team_statistics', 'Can edit');
|
||||
await setupSystemManagerPermission(pw, adminUser, 'userManagement', 'teams', 'Can edit');
|
||||
|
||||
// Configure the system manager with the default permissions.
|
||||
await setupDefaultSystemManagerRole(
|
||||
pw,
|
||||
adminUser,
|
||||
'permission_section_reporting',
|
||||
'permission_section_reporting_team_statistics',
|
||||
'Can edit',
|
||||
);
|
||||
await setupDefaultSystemManagerRole(
|
||||
pw,
|
||||
adminUser,
|
||||
'permission_section_user_management',
|
||||
'permission_section_user_management_teams',
|
||||
'Can edit',
|
||||
);
|
||||
// Re-login as the system manager (the admin login above replaced the page context)
|
||||
const {systemConsolePage} = await pw.testBrowser.login(systemManagerUser);
|
||||
|
||||
// Verify the system manager has access to the site statistics for all teams
|
||||
await systemConsolePage.goto();
|
||||
|
||||
// Navigate to Team Statistics
|
||||
await systemConsolePage.sidebar.goToItem('Team Statistics');
|
||||
// Navigate to Team Statistics and verify access to user's team
|
||||
await verifyTeamStatisticsAccess(systemConsolePage, team.id, team.display_name);
|
||||
|
||||
// Wait for page to fully load
|
||||
await systemConsolePage.page.waitForLoadState('networkidle');
|
||||
|
||||
// Find the team filter dropdown
|
||||
let teamFilterSelect = systemConsolePage.page.getByTestId('teamFilter');
|
||||
await expect(teamFilterSelect).toBeVisible();
|
||||
|
||||
// Select the team by value
|
||||
await teamFilterSelect.selectOption({value: team.id});
|
||||
|
||||
// Verify the text shows "Team Statistics for <team name>"
|
||||
let teamStatsHeading = systemConsolePage.page.getByText(`Team Statistics for ${team.display_name}`, {
|
||||
exact: true,
|
||||
});
|
||||
await expect(teamStatsHeading).toBeVisible();
|
||||
|
||||
// Select the other team by value
|
||||
await teamFilterSelect.selectOption({value: otherTeam.id});
|
||||
|
||||
// Verify the text shows "Team Statistics for <team name>"
|
||||
const otherTeamStatsHeading = systemConsolePage.page.getByText(
|
||||
`Team Statistics for ${otherTeam.display_name}`,
|
||||
{
|
||||
exact: true,
|
||||
},
|
||||
);
|
||||
await expect(otherTeamStatsHeading).toBeVisible();
|
||||
// Select the other team by value and verify access
|
||||
await systemConsolePage.teamStatistics.selectTeamById(otherTeam.id);
|
||||
await systemConsolePage.teamStatistics.toHaveTeamHeader(otherTeam.display_name);
|
||||
|
||||
// Verify the user has API access to the otherTeam.
|
||||
const fetchedOtherTeam = await systemManagerClient.getTeam(otherTeam.id);
|
||||
expect(fetchedOtherTeam.id).toEqual(otherTeam.id);
|
||||
|
||||
// Configure the system manager without access to team user management
|
||||
await setupDefaultSystemManagerRole(
|
||||
pw,
|
||||
adminUser,
|
||||
'permission_section_user_management',
|
||||
'permission_section_user_management_teams',
|
||||
'No access',
|
||||
);
|
||||
await setupSystemManagerPermission(pw, adminUser, 'userManagement', 'teams', 'No access');
|
||||
|
||||
// Re-login as the system manager again after permission change
|
||||
const {systemConsolePage: systemConsolePage2} = await pw.testBrowser.login(systemManagerUser);
|
||||
|
||||
// Verify the system manager only has access to the site statistics for the team they belong to
|
||||
await systemConsolePage.goto();
|
||||
await systemConsolePage2.goto();
|
||||
|
||||
// Navigate to Team Statistics
|
||||
await systemConsolePage.sidebar.goToItem('Team Statistics');
|
||||
|
||||
// Find the team filter dropdown
|
||||
teamFilterSelect = systemConsolePage.page.getByTestId('teamFilter');
|
||||
await expect(teamFilterSelect).toBeVisible();
|
||||
|
||||
// Select the team by value
|
||||
await teamFilterSelect.selectOption({value: team.id});
|
||||
|
||||
// Verify the text shows "Team Statistics for <team name>"
|
||||
teamStatsHeading = systemConsolePage.page.getByText(`Team Statistics for ${team.display_name}`, {exact: true});
|
||||
await expect(teamStatsHeading).toBeVisible();
|
||||
// Navigate to Team Statistics and verify access to user's team
|
||||
await verifyTeamStatisticsAccess(systemConsolePage2, team.id, team.display_name);
|
||||
|
||||
// Verify the user has no API access to the otherTeam.
|
||||
let apiError: Error | null = null;
|
||||
|
|
@ -191,3 +67,69 @@ test(
|
|||
expect(apiError?.message).toContain('You do not have the appropriate permissions');
|
||||
},
|
||||
);
|
||||
|
||||
// Helper function to navigate to Team Statistics and verify team access
|
||||
const verifyTeamStatisticsAccess = async (
|
||||
systemConsolePage: SystemConsolePage,
|
||||
teamId: string,
|
||||
teamDisplayName: string,
|
||||
) => {
|
||||
// Navigate to Team Statistics
|
||||
await systemConsolePage.sidebar.reporting.teamStatistics.click();
|
||||
await systemConsolePage.teamStatistics.toBeVisible();
|
||||
|
||||
// Select the team by value
|
||||
await systemConsolePage.teamStatistics.selectTeamById(teamId);
|
||||
|
||||
// Verify the text shows "Team Statistics for <team name>"
|
||||
await systemConsolePage.teamStatistics.toHaveTeamHeader(teamDisplayName);
|
||||
};
|
||||
|
||||
type PermissionValue = 'Can edit' | 'Read only' | 'No access';
|
||||
|
||||
// setupSystemManagerRole configures the system manager with the given permission ("Can edit", "Read only", "No access")
|
||||
// for the given section and subsection.
|
||||
//
|
||||
// We do this via the system console and not the API because this page has multiple queries to build up the
|
||||
// final API call that are all ultimately part of the spec, and we want to test the effects of those, not
|
||||
// merely a hand-created version of the same.
|
||||
const setupSystemManagerPermission = async (
|
||||
pw: PlaywrightExtended,
|
||||
adminUser: UserProfile,
|
||||
sectionName: 'reporting' | 'userManagement',
|
||||
subsectionName: string,
|
||||
permission: PermissionValue,
|
||||
) => {
|
||||
// Login as admin and navigate to System Console
|
||||
const {systemConsolePage} = await pw.testBrowser.login(adminUser);
|
||||
|
||||
// Go to System Console
|
||||
await systemConsolePage.goto();
|
||||
|
||||
// Navigate to Delegated Granular Administration
|
||||
await systemConsolePage.sidebar.delegatedGranularAdministration.click();
|
||||
await systemConsolePage.delegatedGranularAdministration.toBeVisible();
|
||||
|
||||
// Click on the System Manager row to go to its settings page
|
||||
await systemConsolePage.delegatedGranularAdministration.adminRolesPanel.systemManager.clickEdit();
|
||||
await systemConsolePage.delegatedGranularAdministration.systemRoles.toBeVisible();
|
||||
|
||||
// Get the section from privileges panel
|
||||
const section = systemConsolePage.delegatedGranularAdministration.systemRoles.privilegesPanel[sectionName];
|
||||
|
||||
// Expand subsections if needed
|
||||
await section.expandSubsections();
|
||||
|
||||
// Get the subsection and set permission
|
||||
const subsection = section.getSubsection(subsectionName);
|
||||
await subsection.setPermission(permission);
|
||||
|
||||
// Save
|
||||
await systemConsolePage.delegatedGranularAdministration.systemRoles.save();
|
||||
|
||||
// Wait for save to complete - successful save redirects to system_roles list
|
||||
await systemConsolePage.page.waitForURL('**/admin_console/user_management/system_roles');
|
||||
|
||||
// Wait for the page to fully load
|
||||
await systemConsolePage.page.waitForLoadState('networkidle');
|
||||
};
|
||||
|
|
|
|||
|
|
@ -3,10 +3,153 @@
|
|||
|
||||
import {type PlaywrightExtended, expect, test} from '@mattermost/playwright-lib';
|
||||
|
||||
test('MM-T5520-1 should activate and deactivate users', async ({pw}) => {
|
||||
const {getUser, systemConsolePage} = await setupAndGetRandomUser(pw);
|
||||
|
||||
const userRow = systemConsolePage.users.usersTable.getRowByIndex(0);
|
||||
|
||||
// # Open menu and deactivate the user
|
||||
const actionMenu = await userRow.openActionMenu();
|
||||
await actionMenu.clickDeactivate();
|
||||
|
||||
// # Press confirm on the modal
|
||||
await systemConsolePage.users.confirmModal.confirm();
|
||||
|
||||
// * Verify user is deactivated
|
||||
await expect(userRow.container.getByText('Deactivated')).toBeVisible();
|
||||
expect((await getUser()).delete_at).toBeGreaterThan(0);
|
||||
|
||||
// # Open menu and reactivate the user
|
||||
const actionMenu2 = await userRow.openActionMenu();
|
||||
await actionMenu2.clickActivate();
|
||||
|
||||
// * Verify user is activated
|
||||
await expect(userRow.container.getByText('Member')).toBeVisible();
|
||||
});
|
||||
|
||||
test('MM-T5520-2 should change user roles', async ({pw}) => {
|
||||
const {getUser, systemConsolePage} = await setupAndGetRandomUser(pw);
|
||||
|
||||
const userRow = systemConsolePage.users.usersTable.getRowByIndex(0);
|
||||
|
||||
// # Open menu and click Manage roles
|
||||
const actionMenu = await userRow.openActionMenu();
|
||||
await actionMenu.clickManageRoles();
|
||||
|
||||
// # Change to System Admin and click Save
|
||||
const systemAdmin = systemConsolePage.page.locator('input[name="systemadmin"]');
|
||||
await systemAdmin.waitFor();
|
||||
await systemAdmin.click();
|
||||
await systemConsolePage.users.manageRolesModal.save();
|
||||
|
||||
// * Verify that the role was updated
|
||||
await expect(userRow.container.getByText('System Admin')).toBeVisible();
|
||||
expect((await getUser()).roles).toContain('system_admin');
|
||||
|
||||
// # Open menu and click Manage roles
|
||||
const actionMenu2 = await userRow.openActionMenu();
|
||||
await actionMenu2.clickManageRoles();
|
||||
|
||||
// # Change to Member and click Save
|
||||
const systemMember = systemConsolePage.page.locator('input[name="systemmember"]');
|
||||
await systemMember.waitFor();
|
||||
await systemMember.click();
|
||||
await systemConsolePage.users.manageRolesModal.save();
|
||||
|
||||
// * Verify that the role was updated
|
||||
await expect(userRow.container.getByText('Member')).toBeVisible();
|
||||
expect((await getUser()).roles).toContain('system_user');
|
||||
});
|
||||
|
||||
test('MM-T5520-3 should be able to manage teams', async ({pw}) => {
|
||||
const {systemConsolePage} = await setupAndGetRandomUser(pw);
|
||||
|
||||
const userRow = systemConsolePage.users.usersTable.getRowByIndex(0);
|
||||
|
||||
// # Open menu and click Manage teams
|
||||
const actionMenu = await userRow.openActionMenu();
|
||||
await actionMenu.clickManageTeams();
|
||||
|
||||
// # Click Make Team Admin
|
||||
const team = systemConsolePage.page.locator('div.manage-teams__team');
|
||||
const teamDropdown = team.locator('div.MenuWrapper');
|
||||
await teamDropdown.click();
|
||||
const makeTeamAdmin = teamDropdown.getByText('Make Team Admin');
|
||||
await makeTeamAdmin.click();
|
||||
|
||||
// * Verify role is updated
|
||||
await expect(team.getByText('Team Admin')).toBeVisible();
|
||||
|
||||
// # Change back to Team Member
|
||||
await teamDropdown.click();
|
||||
const makeTeamMember = teamDropdown.getByText('Make Team Member');
|
||||
await makeTeamMember.click();
|
||||
|
||||
// * Verify role is updated
|
||||
await expect(team.getByText('Team Member')).toBeVisible();
|
||||
|
||||
// # Click Remove From Team
|
||||
await teamDropdown.click();
|
||||
const removeFromTeam = teamDropdown.getByText('Remove From Team');
|
||||
await removeFromTeam.click();
|
||||
|
||||
// * The team should be detached
|
||||
await team.waitFor({state: 'detached'});
|
||||
await expect(team).not.toBeVisible();
|
||||
});
|
||||
|
||||
test('MM-T5520-4 should reset the users password', async ({pw}) => {
|
||||
const {systemConsolePage} = await setupAndGetRandomUser(pw);
|
||||
|
||||
const userRow = systemConsolePage.users.usersTable.getRowByIndex(0);
|
||||
|
||||
// # Open menu and click Reset Password
|
||||
const actionMenu = await userRow.openActionMenu();
|
||||
await actionMenu.clickResetPassword();
|
||||
|
||||
// # Enter a random password and click Reset
|
||||
await systemConsolePage.users.resetPasswordModal.fillPassword(await pw.random.id());
|
||||
await systemConsolePage.users.resetPasswordModal.reset();
|
||||
});
|
||||
|
||||
test('MM-T5520-5 should change the users email', async ({pw}) => {
|
||||
const {getUser, systemConsolePage} = await setupAndGetRandomUser(pw);
|
||||
const newEmail = `${await pw.random.id()}@example.com`;
|
||||
|
||||
const userRow = systemConsolePage.users.usersTable.getRowByIndex(0);
|
||||
|
||||
// # Open menu and click Update Email
|
||||
const actionMenu = await userRow.openActionMenu();
|
||||
await actionMenu.clickUpdateEmail();
|
||||
|
||||
// # Enter new email and click Update
|
||||
await systemConsolePage.users.updateEmailModal.fillEmail(newEmail);
|
||||
await systemConsolePage.users.updateEmailModal.update();
|
||||
|
||||
// * Verify that the email updated
|
||||
await expect(userRow.container.getByText(newEmail)).toBeVisible();
|
||||
expect((await getUser()).email).toEqual(newEmail);
|
||||
});
|
||||
|
||||
test('MM-T5520-6 should revoke sessions', async ({pw}) => {
|
||||
const {systemConsolePage} = await setupAndGetRandomUser(pw);
|
||||
|
||||
const userRow = systemConsolePage.users.usersTable.getRowByIndex(0);
|
||||
|
||||
// # Open menu and revoke sessions
|
||||
const actionMenu = await userRow.openActionMenu();
|
||||
await actionMenu.clickRevokeSessions();
|
||||
|
||||
// # Press confirm on the modal
|
||||
await systemConsolePage.users.confirmModal.confirm();
|
||||
|
||||
// * Verify no error is displayed
|
||||
await expect(userRow.container.locator('.error')).not.toBeVisible();
|
||||
});
|
||||
|
||||
/**
|
||||
* Setup a new random user, and search for it such that it's the first row in the list
|
||||
* @param pw
|
||||
* @param pages
|
||||
* @returns A function to get the refreshed user, and the System Console page for navigation
|
||||
*/
|
||||
async function setupAndGetRandomUser(pw: PlaywrightExtended) {
|
||||
|
|
@ -19,7 +162,7 @@ async function setupAndGetRandomUser(pw: PlaywrightExtended) {
|
|||
// # Log in as admin
|
||||
const {systemConsolePage} = await pw.testBrowser.login(adminUser);
|
||||
|
||||
// # Create a random user to edit for
|
||||
// # Create a random user to edit
|
||||
const user = await adminClient.createUser(await pw.random.user(), '', '');
|
||||
const team = await adminClient.createTeam(await pw.random.team());
|
||||
await adminClient.addToTeam(team.id, user.id);
|
||||
|
|
@ -29,174 +172,15 @@ async function setupAndGetRandomUser(pw: PlaywrightExtended) {
|
|||
await systemConsolePage.toBeVisible();
|
||||
|
||||
// # Go to Users section
|
||||
await systemConsolePage.sidebar.goToItem('Users');
|
||||
await systemConsolePage.systemUsers.toBeVisible();
|
||||
await systemConsolePage.sidebar.users.click();
|
||||
await systemConsolePage.users.toBeVisible();
|
||||
|
||||
// # Search for user-1
|
||||
await systemConsolePage.systemUsers.enterSearchText(user.email);
|
||||
const userRow = await systemConsolePage.systemUsers.getNthRow(1);
|
||||
await userRow.getByText(user.email).waitFor();
|
||||
const innerText = await userRow.innerText();
|
||||
expect(innerText).toContain(user.email);
|
||||
// # Search for the user
|
||||
await systemConsolePage.users.searchUsers(user.email);
|
||||
|
||||
// Wait for search results
|
||||
const userRow = systemConsolePage.users.usersTable.getRowByIndex(0);
|
||||
await expect(userRow.container.getByText(user.email)).toBeVisible();
|
||||
|
||||
return {getUser: () => adminClient.getUser(user.id), systemConsolePage};
|
||||
}
|
||||
|
||||
test('MM-T5520-1 should activate and deactivate users', async ({pw}) => {
|
||||
const {getUser, systemConsolePage} = await setupAndGetRandomUser(pw);
|
||||
|
||||
// # Open menu and deactivate the user
|
||||
await systemConsolePage.systemUsers.actionMenuButtons[0].click();
|
||||
const deactivate = await systemConsolePage.systemUsersActionMenus[0].getMenuItem('Deactivate');
|
||||
await deactivate.click();
|
||||
|
||||
// # Press confirm on the modal
|
||||
await systemConsolePage.confirmModal.confirm();
|
||||
|
||||
// * Verify user is deactivated
|
||||
const firstRow = await systemConsolePage.systemUsers.getNthRow(1);
|
||||
await firstRow.getByText('Deactivated').waitFor();
|
||||
expect(await firstRow.innerText()).toContain('Deactivated');
|
||||
expect((await getUser()).delete_at).toBeGreaterThan(0);
|
||||
|
||||
// # Open menu and reactivate the user
|
||||
await systemConsolePage.systemUsers.actionMenuButtons[0].click();
|
||||
const activate = await systemConsolePage.systemUsersActionMenus[0].getMenuItem('Activate');
|
||||
await activate.click();
|
||||
|
||||
// * Verify user is activated
|
||||
await firstRow.getByText('Member').waitFor();
|
||||
expect(await firstRow.innerText()).toContain('Member');
|
||||
});
|
||||
|
||||
test('MM-T5520-2 should change user roles', async ({pw}) => {
|
||||
const {getUser, systemConsolePage} = await setupAndGetRandomUser(pw);
|
||||
|
||||
// # Open menu and click Manage roles
|
||||
await systemConsolePage.systemUsers.actionMenuButtons[0].click();
|
||||
let manageRoles = await systemConsolePage.systemUsersActionMenus[0].getMenuItem('Manage roles');
|
||||
await manageRoles.click();
|
||||
|
||||
// # Change to System Admin and click Save
|
||||
const systemAdmin = systemConsolePage.page.locator('input[name="systemadmin"]');
|
||||
await systemAdmin.waitFor();
|
||||
await systemAdmin.click();
|
||||
systemConsolePage.saveRoleChange();
|
||||
|
||||
// * Verify that the modal closed and no error showed
|
||||
await systemAdmin.waitFor({state: 'detached'});
|
||||
|
||||
// * Verify that the role was updated
|
||||
const firstRow = await systemConsolePage.systemUsers.getNthRow(1);
|
||||
expect(await firstRow.innerText()).toContain('System Admin');
|
||||
expect((await getUser()).roles).toContain('system_admin');
|
||||
|
||||
// # Open menu and click Manage roles
|
||||
await systemConsolePage.systemUsers.actionMenuButtons[0].click();
|
||||
manageRoles = await systemConsolePage.systemUsersActionMenus[0].getMenuItem('Manage roles');
|
||||
await manageRoles.click();
|
||||
|
||||
// # Change to Member and click Save
|
||||
const systemMember = systemConsolePage.page.locator('input[name="systemmember"]');
|
||||
await systemMember.waitFor();
|
||||
await systemMember.click();
|
||||
await systemConsolePage.saveRoleChange();
|
||||
|
||||
// * Verify that the modal closed and no error showed
|
||||
await systemMember.waitFor({state: 'detached'});
|
||||
|
||||
// * Verify that the role was updated
|
||||
expect(await firstRow.innerText()).toContain('Member');
|
||||
expect((await getUser()).roles).toContain('system_user');
|
||||
});
|
||||
|
||||
test('MM-T5520-3 should be able to manage teams', async ({pw}) => {
|
||||
const {systemConsolePage} = await setupAndGetRandomUser(pw);
|
||||
|
||||
// # Open menu and click Manage teams
|
||||
await systemConsolePage.systemUsers.actionMenuButtons[0].click();
|
||||
const manageTeams = await systemConsolePage.systemUsersActionMenus[0].getMenuItem('Manage teams');
|
||||
await manageTeams.click();
|
||||
|
||||
// # Click Make Team Admin
|
||||
const team = systemConsolePage.page.locator('div.manage-teams__team');
|
||||
const teamDropdown = team.locator('div.MenuWrapper');
|
||||
await teamDropdown.click();
|
||||
const makeTeamAdmin = teamDropdown.getByText('Make Team Admin');
|
||||
await makeTeamAdmin.click();
|
||||
|
||||
// * Verify role is updated
|
||||
expect(await team.innerText()).toContain('Team Admin');
|
||||
|
||||
// # Change back to Team Member
|
||||
await teamDropdown.click();
|
||||
const makeTeamMember = teamDropdown.getByText('Make Team Member');
|
||||
await makeTeamMember.click();
|
||||
|
||||
// * Verify role is updated
|
||||
expect(await team.innerText()).toContain('Team Member');
|
||||
|
||||
// # Click Remove From Team
|
||||
await teamDropdown.click();
|
||||
const removeFromTeam = teamDropdown.getByText('Remove From Team');
|
||||
await removeFromTeam.click();
|
||||
|
||||
// * The team should be detached
|
||||
await team.waitFor({state: 'detached'});
|
||||
expect(team).not.toBeVisible();
|
||||
});
|
||||
|
||||
test('MM-T5520-4 should reset the users password', async ({pw}) => {
|
||||
const {systemConsolePage} = await setupAndGetRandomUser(pw);
|
||||
|
||||
// # Open menu and click Reset Password
|
||||
await systemConsolePage.systemUsers.actionMenuButtons[0].click();
|
||||
const resetPassword = await systemConsolePage.systemUsersActionMenus[0].getMenuItem('Reset password');
|
||||
await resetPassword.click();
|
||||
|
||||
// # Enter a random password and click Save
|
||||
const passwordInput = systemConsolePage.page.locator('input[type="password"]');
|
||||
await passwordInput.fill(await pw.random.id());
|
||||
await systemConsolePage.clickResetButton();
|
||||
|
||||
// * Verify that the modal closed and no error showed
|
||||
await passwordInput.waitFor({state: 'detached'});
|
||||
});
|
||||
|
||||
test('MM-T5520-5 should change the users email', async ({pw}) => {
|
||||
const {getUser, systemConsolePage} = await setupAndGetRandomUser(pw);
|
||||
const newEmail = `${await pw.random.id()}@example.com`;
|
||||
|
||||
// # Open menu and click Update Email
|
||||
await systemConsolePage.systemUsers.actionMenuButtons[0].click();
|
||||
const updateEmail = await systemConsolePage.systemUsersActionMenus[0].getMenuItem('Update email');
|
||||
await updateEmail.click();
|
||||
|
||||
// # Enter new email and click Update
|
||||
const emailInput = systemConsolePage.page.locator('input[type="email"]');
|
||||
await emailInput.fill(newEmail);
|
||||
await systemConsolePage.clickUpdateEmailButton();
|
||||
|
||||
// * Verify that the modal closed
|
||||
await emailInput.waitFor({state: 'detached'});
|
||||
|
||||
// * Verify that the email updated
|
||||
const firstRow = await systemConsolePage.systemUsers.getNthRow(1);
|
||||
expect(await firstRow.innerText()).toContain(newEmail);
|
||||
expect((await getUser()).email).toEqual(newEmail);
|
||||
});
|
||||
|
||||
test('MM-T5520-6 should revoke sessions', async ({pw}) => {
|
||||
const {systemConsolePage} = await setupAndGetRandomUser(pw);
|
||||
|
||||
// # Open menu and revoke sessions
|
||||
await systemConsolePage.systemUsers.actionMenuButtons[0].click();
|
||||
const removeSessions = await systemConsolePage.systemUsersActionMenus[0].getMenuItem('Revoke sessions');
|
||||
await removeSessions.click();
|
||||
|
||||
// # Press confirm on the modal
|
||||
await systemConsolePage.confirmModal.confirm();
|
||||
|
||||
const firstRow = await systemConsolePage.systemUsers.getNthRow(1);
|
||||
expect(await firstRow.innerHTML()).not.toContain('class="error"');
|
||||
});
|
||||
|
|
|
|||
|
|
@ -23,28 +23,36 @@ test('MM-T5523-1 Sortable columns should sort the list when clicked', async ({pw
|
|||
await systemConsolePage.toBeVisible();
|
||||
|
||||
// # Go to Users section
|
||||
await systemConsolePage.sidebar.goToItem('Users');
|
||||
await systemConsolePage.systemUsers.toBeVisible();
|
||||
await systemConsolePage.sidebar.users.click();
|
||||
await systemConsolePage.users.toBeVisible();
|
||||
|
||||
// * Verify that 'Email' column has aria-sort attribute
|
||||
const userDetailsColumnHeader = await systemConsolePage.systemUsers.getColumnHeader('Email');
|
||||
expect(await userDetailsColumnHeader.isVisible()).toBe(true);
|
||||
expect(userDetailsColumnHeader).toHaveAttribute('aria-sort');
|
||||
const emailColumnHeader = systemConsolePage.users.usersTable.getColumnHeader('Email');
|
||||
await expect(emailColumnHeader).toBeVisible();
|
||||
await expect(emailColumnHeader).toHaveAttribute('aria-sort');
|
||||
|
||||
// # Store the first row's email before sorting
|
||||
const firstRowWithoutSort = await systemConsolePage.systemUsers.getNthRow(1);
|
||||
const firstRowEmailWithoutSort = await firstRowWithoutSort.getByText(pw.simpleEmailRe).allInnerTexts();
|
||||
// # Store all emails before sorting to compare order
|
||||
const rowsBeforeSort = await systemConsolePage.users.usersTable.bodyRows.count();
|
||||
const emailsBeforeSort: string[] = [];
|
||||
for (let i = 0; i < rowsBeforeSort; i++) {
|
||||
const row = systemConsolePage.users.usersTable.getRowByIndex(i);
|
||||
const email = await row.getEmail();
|
||||
emailsBeforeSort.push(email);
|
||||
}
|
||||
|
||||
// # Click on the 'Email' column header to sort
|
||||
await systemConsolePage.systemUsers.clickSortOnColumn('Email');
|
||||
await systemConsolePage.systemUsers.isLoadingComplete();
|
||||
// # Click on the 'Email' column header to sort and wait for sort to complete
|
||||
await systemConsolePage.users.usersTable.sortByColumn('Email');
|
||||
|
||||
// # Store the first row's email after sorting
|
||||
const firstRowWithSort = await systemConsolePage.systemUsers.getNthRow(1);
|
||||
const firstRowEmailWithSort = await firstRowWithSort.getByText(pw.simpleEmailRe).allInnerTexts();
|
||||
// # Store all emails after sorting
|
||||
const emailsAfterSort: string[] = [];
|
||||
for (let i = 0; i < rowsBeforeSort; i++) {
|
||||
const row = systemConsolePage.users.usersTable.getRowByIndex(i);
|
||||
const email = await row.getEmail();
|
||||
emailsAfterSort.push(email);
|
||||
}
|
||||
|
||||
// * Verify that the first row is now different
|
||||
expect(firstRowEmailWithoutSort).not.toBe(firstRowEmailWithSort);
|
||||
// * Verify that the order has changed (emails array is different)
|
||||
expect(emailsBeforeSort).not.toEqual(emailsAfterSort);
|
||||
});
|
||||
|
||||
test('MM-T5523-2 Non sortable columns should not sort the list when clicked', async ({pw}) => {
|
||||
|
|
@ -67,24 +75,24 @@ test('MM-T5523-2 Non sortable columns should not sort the list when clicked', as
|
|||
await systemConsolePage.toBeVisible();
|
||||
|
||||
// # Go to Users section
|
||||
await systemConsolePage.sidebar.goToItem('Users');
|
||||
await systemConsolePage.systemUsers.toBeVisible();
|
||||
await systemConsolePage.sidebar.users.click();
|
||||
await systemConsolePage.users.toBeVisible();
|
||||
|
||||
// * Verify that 'Last login' column does not have aria-sort attribute
|
||||
const userDetailsColumnHeader = await systemConsolePage.systemUsers.getColumnHeader('Last login');
|
||||
expect(await userDetailsColumnHeader.isVisible()).toBe(true);
|
||||
expect(userDetailsColumnHeader).not.toHaveAttribute('aria-sort');
|
||||
const lastLoginColumnHeader = systemConsolePage.users.usersTable.getColumnHeader('Last login');
|
||||
await expect(lastLoginColumnHeader).toBeVisible();
|
||||
await expect(lastLoginColumnHeader).not.toHaveAttribute('aria-sort');
|
||||
|
||||
// # Store the first row's email without sorting
|
||||
const firstRowWithoutSort = await systemConsolePage.systemUsers.getNthRow(1);
|
||||
const firstRowEmailWithoutSort = await firstRowWithoutSort.getByText(pw.simpleEmailRe).allInnerTexts();
|
||||
const firstRowWithoutSort = systemConsolePage.users.usersTable.getRowByIndex(0);
|
||||
const firstRowEmailWithoutSort = await firstRowWithoutSort.container.getByText(pw.simpleEmailRe).allInnerTexts();
|
||||
|
||||
// # Try to click on the 'Last login' column header to sort
|
||||
await systemConsolePage.systemUsers.clickSortOnColumn('Last login');
|
||||
await systemConsolePage.users.usersTable.clickSortOnColumn('Last login');
|
||||
|
||||
// # Store the first row's email after sorting
|
||||
const firstRowWithSort = await systemConsolePage.systemUsers.getNthRow(1);
|
||||
const firstRowEmailWithSort = await firstRowWithSort.getByText(pw.simpleEmailRe).allInnerTexts();
|
||||
const firstRowWithSort = systemConsolePage.users.usersTable.getRowByIndex(0);
|
||||
const firstRowEmailWithSort = await firstRowWithSort.container.getByText(pw.simpleEmailRe).allInnerTexts();
|
||||
|
||||
// * Verify that the first row's email is still the same
|
||||
expect(firstRowEmailWithoutSort).toEqual(firstRowEmailWithSort);
|
||||
|
|
|
|||
|
|
@ -18,15 +18,14 @@ test('MM-T5523-3 Should list the column names with checkboxes in the correct ord
|
|||
await systemConsolePage.toBeVisible();
|
||||
|
||||
// # Go to Users section
|
||||
await systemConsolePage.sidebar.goToItem('Users');
|
||||
await systemConsolePage.systemUsers.toBeVisible();
|
||||
await systemConsolePage.sidebar.users.click();
|
||||
await systemConsolePage.users.toBeVisible();
|
||||
|
||||
// # Open the column toggle menu
|
||||
await systemConsolePage.systemUsers.openColumnToggleMenu();
|
||||
await systemConsolePage.systemUsersColumnToggleMenu.toBeVisible();
|
||||
const columnToggleMenu = await systemConsolePage.users.openColumnToggleMenu();
|
||||
|
||||
// # Get all the menu items
|
||||
const menuItems = await systemConsolePage.systemUsersColumnToggleMenu.getAllMenuItems();
|
||||
const menuItems = columnToggleMenu.getAllMenuItems();
|
||||
const menuItemsTexts = await menuItems.allInnerTexts();
|
||||
|
||||
// * Verify menu items exists in the correct order
|
||||
|
|
@ -59,23 +58,22 @@ test('MM-T5523-4 Should allow certain columns to be checked and others to be dis
|
|||
await systemConsolePage.toBeVisible();
|
||||
|
||||
// # Go to Users section
|
||||
await systemConsolePage.sidebar.goToItem('Users');
|
||||
await systemConsolePage.systemUsers.toBeVisible();
|
||||
await systemConsolePage.sidebar.users.click();
|
||||
await systemConsolePage.users.toBeVisible();
|
||||
|
||||
// # Open the column toggle menu
|
||||
await systemConsolePage.systemUsers.openColumnToggleMenu();
|
||||
await systemConsolePage.systemUsersColumnToggleMenu.toBeVisible();
|
||||
const columnToggleMenu = await systemConsolePage.users.openColumnToggleMenu();
|
||||
|
||||
// * Verify that 'Display Name' is disabled
|
||||
const displayNameMenuItem = await systemConsolePage.systemUsersColumnToggleMenu.getMenuItem('User details');
|
||||
const displayNameMenuItem = await columnToggleMenu.getMenuItem('User details');
|
||||
expect(displayNameMenuItem).toBeDisabled();
|
||||
|
||||
// * Verify that 'Actions' is disabled
|
||||
const actionsMenuItem = await systemConsolePage.systemUsersColumnToggleMenu.getMenuItem('Actions');
|
||||
const actionsMenuItem = await columnToggleMenu.getMenuItem('Actions');
|
||||
expect(actionsMenuItem).toBeDisabled();
|
||||
|
||||
// * Verify that 'Email' however is enabled
|
||||
const emailMenuItem = await systemConsolePage.systemUsersColumnToggleMenu.getMenuItem('Email');
|
||||
const emailMenuItem = await columnToggleMenu.getMenuItem('Email');
|
||||
expect(emailMenuItem).not.toBeDisabled();
|
||||
});
|
||||
|
||||
|
|
@ -94,36 +92,35 @@ test('MM-T5523-5 Should show/hide the columns which are toggled on/off', async (
|
|||
await systemConsolePage.toBeVisible();
|
||||
|
||||
// # Go to Users section
|
||||
await systemConsolePage.sidebar.goToItem('Users');
|
||||
await systemConsolePage.systemUsers.toBeVisible();
|
||||
await systemConsolePage.sidebar.users.click();
|
||||
await systemConsolePage.users.toBeVisible();
|
||||
|
||||
// # Open the column toggle menu
|
||||
await systemConsolePage.systemUsers.openColumnToggleMenu();
|
||||
await systemConsolePage.systemUsersColumnToggleMenu.toBeVisible();
|
||||
let columnToggleMenu = await systemConsolePage.users.openColumnToggleMenu();
|
||||
|
||||
// # Uncheck the Email and Last login columns to hide them
|
||||
await systemConsolePage.systemUsersColumnToggleMenu.clickMenuItem('Email');
|
||||
await systemConsolePage.systemUsersColumnToggleMenu.clickMenuItem('Last login');
|
||||
await columnToggleMenu.clickMenuItem('Email');
|
||||
await columnToggleMenu.clickMenuItem('Last login');
|
||||
|
||||
// * Close the column toggle menu
|
||||
await systemConsolePage.systemUsersColumnToggleMenu.close();
|
||||
await columnToggleMenu.close();
|
||||
|
||||
// * Verify that Email column and Last login column are hidden
|
||||
expect(await systemConsolePage.systemUsers.doesColumnExist('Email')).toBe(false);
|
||||
expect(await systemConsolePage.systemUsers.doesColumnExist('Last login')).toBe(false);
|
||||
await expect(systemConsolePage.users.container.getByRole('columnheader', {name: 'Email'})).not.toBeVisible();
|
||||
await expect(systemConsolePage.users.container.getByRole('columnheader', {name: 'Last login'})).not.toBeVisible();
|
||||
|
||||
// # Now open the column toggle menu again
|
||||
await systemConsolePage.systemUsers.openColumnToggleMenu();
|
||||
columnToggleMenu = await systemConsolePage.users.openColumnToggleMenu();
|
||||
|
||||
// # Check the Email column to show it
|
||||
await systemConsolePage.systemUsersColumnToggleMenu.clickMenuItem('Email');
|
||||
await columnToggleMenu.clickMenuItem('Email');
|
||||
|
||||
// * Close the column toggle menu
|
||||
await systemConsolePage.systemUsersColumnToggleMenu.close();
|
||||
await columnToggleMenu.close();
|
||||
|
||||
// * Verify that Email column is now shown
|
||||
expect(await systemConsolePage.systemUsers.doesColumnExist('Email')).toBe(true);
|
||||
await expect(systemConsolePage.users.container.getByRole('columnheader', {name: 'Email'})).toBeVisible();
|
||||
|
||||
// * Verify that however Last login column is still hidden as we did not check it on
|
||||
expect(await systemConsolePage.systemUsers.doesColumnExist('Last login')).toBe(false);
|
||||
await expect(systemConsolePage.users.container.getByRole('columnheader', {name: 'Last login'})).not.toBeVisible();
|
||||
});
|
||||
|
|
|
|||
|
|
@ -22,28 +22,28 @@ test.fixme('MM-T5522 Should begin export of data when export button is pressed',
|
|||
await systemConsolePage.toBeVisible();
|
||||
|
||||
// # Go to Users section
|
||||
await systemConsolePage.sidebar.goToItem('Users');
|
||||
await systemConsolePage.systemUsers.toBeVisible();
|
||||
await systemConsolePage.sidebar.users.click();
|
||||
await systemConsolePage.users.toBeVisible();
|
||||
|
||||
// # Change the export pw.duration to 30 days
|
||||
await systemConsolePage.systemUsers.dateRangeSelectorMenuButton.click();
|
||||
await systemConsolePage.systemUsersDateRangeMenu.clickMenuItem('All time');
|
||||
// # Change the export duration to All time
|
||||
const dateRangeMenu = await systemConsolePage.users.openDateRangeSelectorMenu();
|
||||
await dateRangeMenu.clickMenuItem('All time');
|
||||
|
||||
// # Click Export button and confirm the modal
|
||||
await systemConsolePage.systemUsers.exportButton.click();
|
||||
await systemConsolePage.exportModal.confirm();
|
||||
await systemConsolePage.users.clickExport();
|
||||
await systemConsolePage.users.confirmModal.confirm();
|
||||
|
||||
// # Change the export pw.duration to all time
|
||||
await systemConsolePage.systemUsers.dateRangeSelectorMenuButton.click();
|
||||
await systemConsolePage.systemUsersDateRangeMenu.clickMenuItem('Last 30 days');
|
||||
// # Change the export duration to Last 30 days
|
||||
const dateRangeMenu2 = await systemConsolePage.users.openDateRangeSelectorMenu();
|
||||
await dateRangeMenu2.clickMenuItem('Last 30 days');
|
||||
|
||||
// # Click Export button and confirm the modal
|
||||
await systemConsolePage.systemUsers.exportButton.click();
|
||||
await systemConsolePage.exportModal.confirm();
|
||||
await systemConsolePage.users.clickExport();
|
||||
await systemConsolePage.users.confirmModal.confirm();
|
||||
|
||||
// # Click Export again button and confirm the modal
|
||||
await systemConsolePage.systemUsers.exportButton.click();
|
||||
await systemConsolePage.exportModal.confirm();
|
||||
await systemConsolePage.users.clickExport();
|
||||
await systemConsolePage.users.confirmModal.confirm();
|
||||
|
||||
// * Verify that we are told that one is already running
|
||||
expect(page.getByText('Export is in progress')).toBeVisible();
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {test} from '@mattermost/playwright-lib';
|
||||
import {expect, test} from '@mattermost/playwright-lib';
|
||||
|
||||
test('MM-T5521-7 Should be able to filter users with team filter', async ({pw}) => {
|
||||
const {adminUser, adminClient} = await pw.initSetup();
|
||||
|
|
@ -28,27 +28,26 @@ test('MM-T5521-7 Should be able to filter users with team filter', async ({pw})
|
|||
await systemConsolePage.toBeVisible();
|
||||
|
||||
// # Go to Users section
|
||||
await systemConsolePage.sidebar.goToItem('Users');
|
||||
await systemConsolePage.systemUsers.toBeVisible();
|
||||
await systemConsolePage.sidebar.users.click();
|
||||
await systemConsolePage.users.toBeVisible();
|
||||
|
||||
// # Open the filter's popover
|
||||
await systemConsolePage.systemUsers.openFilterPopover();
|
||||
await systemConsolePage.systemUsersFilterPopover.toBeVisible();
|
||||
const filterPopover = await systemConsolePage.users.openFilterPopover();
|
||||
|
||||
// # Enter the team name of the first user and select it
|
||||
await systemConsolePage.systemUsersFilterPopover.searchInTeamMenu(team1.display_name);
|
||||
await systemConsolePage.systemUsersFilterPopover.teamMenuInput.press('Enter');
|
||||
await filterPopover.searchInTeamMenu(team1.display_name);
|
||||
await filterPopover.teamMenuInput.press('Enter');
|
||||
|
||||
// # Save the filter and close the popover
|
||||
await systemConsolePage.systemUsersFilterPopover.save();
|
||||
await systemConsolePage.systemUsersFilterPopover.close();
|
||||
await systemConsolePage.systemUsers.isLoadingComplete();
|
||||
await filterPopover.save();
|
||||
await filterPopover.close();
|
||||
await systemConsolePage.users.isLoadingComplete();
|
||||
|
||||
// * Verify that the user corresponding to the first team is visible as team-1 filter was applied
|
||||
await systemConsolePage.systemUsers.verifyRowWithTextIsFound(user1.email);
|
||||
await expect(systemConsolePage.users.container.getByText(user1.email)).toBeVisible();
|
||||
|
||||
// * Verify that the user corresponding to the second team is not visible as team-2 filter was not applied
|
||||
await systemConsolePage.systemUsers.verifyRowWithTextIsNotFound(user2.email);
|
||||
await expect(systemConsolePage.users.container.getByText(user2.email)).not.toBeVisible();
|
||||
});
|
||||
|
||||
test('MM-T5521-8 Should be able to filter users with role filter', async ({pw}) => {
|
||||
|
|
@ -73,37 +72,35 @@ test('MM-T5521-8 Should be able to filter users with role filter', async ({pw})
|
|||
await systemConsolePage.toBeVisible();
|
||||
|
||||
// # Go to Users section
|
||||
await systemConsolePage.sidebar.goToItem('Users');
|
||||
await systemConsolePage.systemUsers.toBeVisible();
|
||||
await systemConsolePage.sidebar.users.click();
|
||||
await systemConsolePage.users.toBeVisible();
|
||||
|
||||
// # Open the filter popover
|
||||
await systemConsolePage.systemUsers.openFilterPopover();
|
||||
await systemConsolePage.systemUsersFilterPopover.toBeVisible();
|
||||
const filterPopover = await systemConsolePage.users.openFilterPopover();
|
||||
|
||||
// # Open the role filter in the popover
|
||||
await systemConsolePage.systemUsersFilterPopover.openRoleMenu();
|
||||
await systemConsolePage.systemUsersRoleMenu.toBeVisible();
|
||||
|
||||
// # Select the Guest role from the role filter
|
||||
await systemConsolePage.systemUsersRoleMenu.clickMenuItem('Guest');
|
||||
await systemConsolePage.systemUsersRoleMenu.close();
|
||||
// # Open the role filter in the popover and select Guest
|
||||
await filterPopover.openRoleMenu();
|
||||
// Wait for dropdown options and click on Guest
|
||||
const guestOption = systemConsolePage.page.getByText('Guest', {exact: true});
|
||||
await guestOption.waitFor();
|
||||
await guestOption.click();
|
||||
|
||||
// # Save the filter and close the popover
|
||||
await systemConsolePage.systemUsersFilterPopover.save();
|
||||
await systemConsolePage.systemUsersFilterPopover.close();
|
||||
await systemConsolePage.systemUsers.isLoadingComplete();
|
||||
await filterPopover.save();
|
||||
await filterPopover.close();
|
||||
await systemConsolePage.users.isLoadingComplete();
|
||||
|
||||
// # Search for the guest user with the filter already applied
|
||||
await systemConsolePage.systemUsers.enterSearchText(guestUser.email);
|
||||
await systemConsolePage.users.searchUsers(guestUser.email);
|
||||
|
||||
// * Verify that guest user is visible as a 'Guest' role filter was applied
|
||||
await systemConsolePage.systemUsers.verifyRowWithTextIsFound(guestUser.email);
|
||||
await expect(systemConsolePage.users.container.getByText(guestUser.email)).toBeVisible();
|
||||
|
||||
// # Search for the regular user with the filter already applied
|
||||
await systemConsolePage.systemUsers.enterSearchText(regularUser.email);
|
||||
await systemConsolePage.users.searchUsers(regularUser.email);
|
||||
|
||||
// * Verify that regular user is not visible as 'Guest' role filter was applied
|
||||
await systemConsolePage.systemUsers.verifyRowWithTextIsFound('No data');
|
||||
await expect(systemConsolePage.users.container.getByText('No data')).toBeVisible();
|
||||
});
|
||||
|
||||
test('MM-T5521-9 Should be able to filter users with status filter', async ({pw}) => {
|
||||
|
|
@ -128,35 +125,32 @@ test('MM-T5521-9 Should be able to filter users with status filter', async ({pw}
|
|||
await systemConsolePage.toBeVisible();
|
||||
|
||||
// # Go to Users section
|
||||
await systemConsolePage.sidebar.goToItem('Users');
|
||||
await systemConsolePage.systemUsers.toBeVisible();
|
||||
await systemConsolePage.sidebar.users.click();
|
||||
await systemConsolePage.users.toBeVisible();
|
||||
|
||||
// # Open the filter popover
|
||||
await systemConsolePage.systemUsers.openFilterPopover();
|
||||
await systemConsolePage.systemUsersFilterPopover.toBeVisible();
|
||||
const filterPopover = await systemConsolePage.users.openFilterPopover();
|
||||
|
||||
// # Open the status filter in the popover
|
||||
await systemConsolePage.systemUsersFilterPopover.openStatusMenu();
|
||||
await systemConsolePage.systemUsersStatusMenu.toBeVisible();
|
||||
await systemConsolePage.systemUsers.isLoadingComplete();
|
||||
|
||||
// # Select the Deactivated users from the status filter
|
||||
await systemConsolePage.systemUsersStatusMenu.clickMenuItem('Deactivated users');
|
||||
await systemConsolePage.systemUsersStatusMenu.close();
|
||||
// # Open the status filter in the popover and select Deactivated users
|
||||
await filterPopover.openStatusMenu();
|
||||
// Wait for dropdown options and click on Deactivated users
|
||||
const deactivatedOption = systemConsolePage.page.getByText('Deactivated users', {exact: true});
|
||||
await deactivatedOption.waitFor();
|
||||
await deactivatedOption.click();
|
||||
|
||||
// # Save the filter and close the popover
|
||||
await systemConsolePage.systemUsersFilterPopover.save();
|
||||
await systemConsolePage.systemUsersFilterPopover.close();
|
||||
await filterPopover.save();
|
||||
await filterPopover.close();
|
||||
|
||||
// # Search for the deactivated user with the filter already applied
|
||||
await systemConsolePage.systemUsers.enterSearchText(deactivatedUser.email);
|
||||
await systemConsolePage.users.searchUsers(deactivatedUser.email);
|
||||
|
||||
// * Verify that deactivated user is visible as a 'Deactivated' status filter was applied
|
||||
await systemConsolePage.systemUsers.verifyRowWithTextIsFound(deactivatedUser.email);
|
||||
await expect(systemConsolePage.users.container.getByText(deactivatedUser.email)).toBeVisible();
|
||||
|
||||
// # Search for the regular user with the filter already applied
|
||||
await systemConsolePage.systemUsers.enterSearchText(regularUser.email);
|
||||
await systemConsolePage.users.searchUsers(regularUser.email);
|
||||
|
||||
// * Verify that regular user is not visible as 'Deactivated' status filter was applied
|
||||
await systemConsolePage.systemUsers.verifyRowWithTextIsFound('No data');
|
||||
await expect(systemConsolePage.users.container.getByText('No data')).toBeVisible();
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {test} from '@mattermost/playwright-lib';
|
||||
import {expect, test} from '@mattermost/playwright-lib';
|
||||
|
||||
test('MM-T5521-1 Should be able to search users with their first names', async ({pw}) => {
|
||||
const {adminUser, adminClient} = await pw.initSetup();
|
||||
|
|
@ -22,17 +22,17 @@ test('MM-T5521-1 Should be able to search users with their first names', async (
|
|||
await systemConsolePage.toBeVisible();
|
||||
|
||||
// # Go to Users section
|
||||
await systemConsolePage.sidebar.goToItem('Users');
|
||||
await systemConsolePage.systemUsers.toBeVisible();
|
||||
await systemConsolePage.sidebar.users.click();
|
||||
await systemConsolePage.users.toBeVisible();
|
||||
|
||||
// # Enter the 'First Name' of the first user in the search box
|
||||
await systemConsolePage.systemUsers.enterSearchText(user1.first_name);
|
||||
await systemConsolePage.users.searchUsers(user1.first_name);
|
||||
|
||||
// * Verify that the searched user i.e first user is found in the list
|
||||
await systemConsolePage.systemUsers.verifyRowWithTextIsFound(user1.email);
|
||||
await expect(systemConsolePage.users.container.getByText(user1.email)).toBeVisible();
|
||||
|
||||
// * Verify that the second user doesnt appear in the list
|
||||
await systemConsolePage.systemUsers.verifyRowWithTextIsNotFound(user2.email);
|
||||
await expect(systemConsolePage.users.container.getByText(user2.email)).not.toBeVisible();
|
||||
});
|
||||
|
||||
test('MM-T5521-2 Should be able to search users with their last names', async ({pw}) => {
|
||||
|
|
@ -54,17 +54,17 @@ test('MM-T5521-2 Should be able to search users with their last names', async ({
|
|||
await systemConsolePage.toBeVisible();
|
||||
|
||||
// # Go to Users section
|
||||
await systemConsolePage.sidebar.goToItem('Users');
|
||||
await systemConsolePage.systemUsers.toBeVisible();
|
||||
await systemConsolePage.sidebar.users.click();
|
||||
await systemConsolePage.users.toBeVisible();
|
||||
|
||||
// # Enter the 'Last Name' of the user in the search box
|
||||
await systemConsolePage.systemUsers.enterSearchText(user1.last_name);
|
||||
await systemConsolePage.users.searchUsers(user1.last_name);
|
||||
|
||||
// * Verify that the searched user i.e first user is found in the list
|
||||
await systemConsolePage.systemUsers.verifyRowWithTextIsFound(user1.email);
|
||||
await expect(systemConsolePage.users.container.getByText(user1.email)).toBeVisible();
|
||||
|
||||
// * Verify that the second user doesnt appear in the list
|
||||
await systemConsolePage.systemUsers.verifyRowWithTextIsNotFound(user2.email);
|
||||
await expect(systemConsolePage.users.container.getByText(user2.email)).not.toBeVisible();
|
||||
});
|
||||
|
||||
test('MM-T5521-3 Should be able to search users with their emails', async ({pw}) => {
|
||||
|
|
@ -86,17 +86,17 @@ test('MM-T5521-3 Should be able to search users with their emails', async ({pw})
|
|||
await systemConsolePage.toBeVisible();
|
||||
|
||||
// # Go to Users section
|
||||
await systemConsolePage.sidebar.goToItem('Users');
|
||||
await systemConsolePage.systemUsers.toBeVisible();
|
||||
await systemConsolePage.sidebar.users.click();
|
||||
await systemConsolePage.users.toBeVisible();
|
||||
|
||||
// * Enter the 'Email' of the first user in the search box
|
||||
await systemConsolePage.systemUsers.enterSearchText(user1.email);
|
||||
await systemConsolePage.users.searchUsers(user1.email);
|
||||
|
||||
// * Verify that the searched user i.e first user is found in the list
|
||||
await systemConsolePage.systemUsers.verifyRowWithTextIsFound(user1.email);
|
||||
await expect(systemConsolePage.users.container.getByText(user1.email)).toBeVisible();
|
||||
|
||||
// * Verify that the second user doesnt appear in the list
|
||||
await systemConsolePage.systemUsers.verifyRowWithTextIsNotFound(user2.email);
|
||||
await expect(systemConsolePage.users.container.getByText(user2.email)).not.toBeVisible();
|
||||
});
|
||||
|
||||
test('MM-T5521-4 Should be able to search users with their usernames', async ({pw}) => {
|
||||
|
|
@ -118,17 +118,17 @@ test('MM-T5521-4 Should be able to search users with their usernames', async ({p
|
|||
await systemConsolePage.toBeVisible();
|
||||
|
||||
// # Go to Users section
|
||||
await systemConsolePage.sidebar.goToItem('Users');
|
||||
await systemConsolePage.systemUsers.toBeVisible();
|
||||
await systemConsolePage.sidebar.users.click();
|
||||
await systemConsolePage.users.toBeVisible();
|
||||
|
||||
// # Enter the 'Username' of the first user in the search box
|
||||
await systemConsolePage.systemUsers.enterSearchText(user1.username);
|
||||
await systemConsolePage.users.searchUsers(user1.username);
|
||||
|
||||
// * Verify that the searched user i.e first user is found in the list
|
||||
await systemConsolePage.systemUsers.verifyRowWithTextIsFound(user1.email);
|
||||
await expect(systemConsolePage.users.container.getByText(user1.email)).toBeVisible();
|
||||
|
||||
// * Verify that the another user is not visible
|
||||
await systemConsolePage.systemUsers.verifyRowWithTextIsNotFound(user2.email);
|
||||
await expect(systemConsolePage.users.container.getByText(user2.email)).not.toBeVisible();
|
||||
});
|
||||
|
||||
test('MM-T5521-5 Should be able to search users with their nick names', async ({pw}) => {
|
||||
|
|
@ -150,16 +150,16 @@ test('MM-T5521-5 Should be able to search users with their nick names', async ({
|
|||
await systemConsolePage.toBeVisible();
|
||||
|
||||
// # Go to Users section
|
||||
await systemConsolePage.sidebar.goToItem('Users');
|
||||
await systemConsolePage.sidebar.users.click();
|
||||
|
||||
// # Enter the 'Nickname' of the first user in the search box
|
||||
await systemConsolePage.systemUsers.enterSearchText(user1.nickname);
|
||||
await systemConsolePage.users.searchUsers(user1.nickname);
|
||||
|
||||
// * Verify that the searched user i.e first user is found in the list
|
||||
await systemConsolePage.systemUsers.verifyRowWithTextIsFound(user1.email);
|
||||
await expect(systemConsolePage.users.container.getByText(user1.email)).toBeVisible();
|
||||
|
||||
// * Verify that the second user doesnt appear in the list
|
||||
await systemConsolePage.systemUsers.verifyRowWithTextIsNotFound(user2.email);
|
||||
await expect(systemConsolePage.users.container.getByText(user2.email)).not.toBeVisible();
|
||||
});
|
||||
|
||||
test('MM-T5521-6 Should show no user is found when user doesnt exists', async ({pw}) => {
|
||||
|
|
@ -177,10 +177,10 @@ test('MM-T5521-6 Should show no user is found when user doesnt exists', async ({
|
|||
await systemConsolePage.toBeVisible();
|
||||
|
||||
// # Go to Users section
|
||||
await systemConsolePage.sidebar.goToItem('Users');
|
||||
await systemConsolePage.sidebar.users.click();
|
||||
|
||||
// # Enter random text in the search box
|
||||
await systemConsolePage.systemUsers.enterSearchText(`!${pw.random.id(15)}_^^^_${pw.random.id(15)}!`);
|
||||
await systemConsolePage.users.searchUsers(`!${pw.random.id(15)}_^^^_${pw.random.id(15)}!`);
|
||||
|
||||
await systemConsolePage.systemUsers.verifyRowWithTextIsFound('No data');
|
||||
await expect(systemConsolePage.users.container.getByText('No data')).toBeVisible();
|
||||
});
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ import {UserProfile} from '@mattermost/types/users';
|
|||
import {Client4} from '@mattermost/client';
|
||||
import {UserPropertyField} from '@mattermost/types/properties';
|
||||
|
||||
import {expect, test} from '@mattermost/playwright-lib';
|
||||
import {expect, test, SystemConsolePage} from '@mattermost/playwright-lib';
|
||||
|
||||
import {
|
||||
CustomProfileAttribute,
|
||||
|
|
@ -87,7 +87,7 @@ let adminUser: UserProfile;
|
|||
let testUser: UserProfile;
|
||||
let attributeFieldsMap: Record<string, UserPropertyField>;
|
||||
let adminClient: Client4;
|
||||
let systemConsolePage: any;
|
||||
let systemConsolePage: SystemConsolePage;
|
||||
|
||||
test.describe('System Console - Admin User Profile Editing', () => {
|
||||
test.beforeEach(async ({pw}) => {
|
||||
|
|
@ -119,13 +119,13 @@ test.describe('System Console - Admin User Profile Editing', () => {
|
|||
// Navigate to system console users
|
||||
await systemConsolePage.goto();
|
||||
await systemConsolePage.toBeVisible();
|
||||
await systemConsolePage.sidebar.goToItem('Users');
|
||||
await systemConsolePage.systemUsers.toBeVisible();
|
||||
await systemConsolePage.sidebar.users.click();
|
||||
await systemConsolePage.users.toBeVisible();
|
||||
|
||||
// Search for target user and navigate to user detail page
|
||||
await systemConsolePage.systemUsers.enterSearchText(testUser.email);
|
||||
const userRow = await systemConsolePage.systemUsers.getNthRow(1);
|
||||
await userRow.getByText(testUser.email).click();
|
||||
await systemConsolePage.users.searchUsers(testUser.email);
|
||||
const userRow = systemConsolePage.users.usersTable.getRowByIndex(0);
|
||||
await userRow.container.getByText(testUser.email).click();
|
||||
|
||||
// Wait for user detail page to load
|
||||
await systemConsolePage.page.waitForURL(`**/admin_console/user_management/user/${testUser.id}`);
|
||||
|
|
|
|||
Loading…
Reference in a new issue