MM61173 - settings modal base creation (#30338)
* MM-61173 - channel settings modal: base modal, initial commit, file creation and base component * new enhancements to the base modal creation * revert changes on textbox_links and edit channel header * fix types and add back unintentioned deleted value * add the preview textbox component * extract logic for info tab into its own component * add the purpose input to the window * move other component logic to its own component and code clean up * ability to update channel type * more advances on the archive channel tab * fix unit test in textbox * fix translations * do not show the archive modal in default channel * fix issue with url editor not being resetted on undo action * adjust text and styling for the header and purpose inputs * remove textboxlinks and use button eye icon * adjust test and preview button style * add unit test to channel patch * move logic from parent modal to info tab component * fix border issues and focus back to preview textareas * prevent saving changes when pressing enter when selecting an icon * enhance input component to cover limits validations and enhances tests * set default error message for save changes panel * add props to provide custom value to the buttons * remove channel input errors on reset button click * create new component settings textbox * rename component to advanced textbox and add unit tests * styling of the info tab and add error state to advanced textbox * add logic to prevent tab switch with unsaved changes * adjust url error logic and code clean up * code clean up and enhance comments * add char min length to advanced textbox logic * add the channel settings modal to the new menu * add new test files and fix reset error * remove unused error variables * adjust translations and remove unncesary import * enhance permissions for archive channels and manage channel settings * Adjust permission tree so channel admins can convert from private to public * enhance the test suit around channel conversion type * fix some e2e tests and solve channel input name issue * fix unit test by interacting first with the input element * adjust e2e tests to channel settings modal changes * remove commented tests and implement pr feedback * adjust more pr feedback to the code * more pr feedback enhancements * further enhancements to tab navigation, and adjust more e2e tests * remove unused components and fix e2e tests * revert unnecessary permissions changes * Add name label to textboxes * adjust e2e and unit tests * revert min lenght change value and adjust tests and snapshots * Channel banner settings (#30721) * Added channel banner setting header * Updated section styling * handled animation * handled min and max lengths * cleanup * color change fix * general improvements * Fixed API test * removed unused param className * added e2e tests * test: add channel settings configuration tab test file * Based on the context, here's a concise commit message for this change: feat: Add comprehensive tests for ChannelSettingsConfigurationTab * added some more tests * CI * reverted package-lock.json changes in Playwright * remove extra border from advaced textbox * adjust styling for name label in advance texbox and restart preview state on modal close * sync package.lock in playwright --------- Co-authored-by: Mattermost Build <build@mattermost.com> Co-authored-by: Harshil Sharma <harshilsharma63@gmail.com> Co-authored-by: Harshil Sharma <18575143+harshilsharma63@users.noreply.github.com>
Этот коммит содержится в:
@@ -88,12 +88,14 @@ describe('Verify Accessibility Support in different sections in Settings and Pro
|
||||
});
|
||||
|
||||
it('MM-T1465_1 Verify Label & Tab behavior in section links', () => {
|
||||
// * Verify aria-label and tab support in section of Account settings modal
|
||||
// * Verify tab selection and keyboard navigation in Account settings modal
|
||||
cy.uiOpenProfileModal('Profile Settings');
|
||||
cy.findByRole('tab', {name: 'profile settings'}).should('be.visible').focus().should('be.focused');
|
||||
['profile settings', 'security'].forEach((text) => {
|
||||
// * Verify aria-label on each tab and it supports navigating to the next tab with arrow keys
|
||||
cy.focused().should('have.attr', 'aria-label', text).type('{downarrow}');
|
||||
// * Verify each tab is correctly selected and supports navigating to the next tab with arrow keys
|
||||
cy.findByRole('tab', {name: text}).
|
||||
should('have.attr', 'aria-selected', 'true').
|
||||
type('{downarrow}');
|
||||
});
|
||||
cy.uiClose();
|
||||
|
||||
@@ -101,8 +103,10 @@ describe('Verify Accessibility Support in different sections in Settings and Pro
|
||||
cy.uiOpenSettingsModal();
|
||||
cy.findByRole('tab', {name: 'notifications'}).should('be.visible').focus().should('be.focused');
|
||||
['notifications', 'display', 'sidebar', 'advanced'].forEach((text) => {
|
||||
// * Verify aria-label on each tab and it supports navigating to the next tab with arrow keys
|
||||
cy.focused().should('have.attr', 'aria-label', text).type('{downarrow}');
|
||||
// * Verify each tab is correctly selected and supports navigating to the next tab with arrow keys
|
||||
cy.findByRole('tab', {name: text}).
|
||||
should('have.attr', 'aria-selected', 'true').
|
||||
type('{downarrow}');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -29,30 +29,39 @@ describe('Channel Settings - Channel Header', () => {
|
||||
// # Visit the newly created channel
|
||||
cy.visit(`/${testTeam.name}/channels/${channel.name}`);
|
||||
|
||||
// # Click on the channel name in the channel header to open the channel menu options
|
||||
cy.get(`[aria-label="${channel.display_name.split('-').join(' ').toLowerCase()} channel menu"]`).click();
|
||||
|
||||
// # Select the "Edit Channel Header" option from the dropdown
|
||||
cy.findByText('Channel Settings').should('be.visible').trigger('mouseover');
|
||||
cy.findByText('Edit Channel Header').click();
|
||||
cy.get('#channelHeaderDropdownButton').click();
|
||||
cy.findByText('Channel Settings').click();
|
||||
|
||||
// * Verify modal is open
|
||||
cy.get('.ChannelSettingsModal').should('be.visible');
|
||||
cy.get('#genericModalLabel').should('contain', 'Channel Settings');
|
||||
|
||||
// # Type something in the header edit box
|
||||
cy.get('textarea[placeholder="Edit the Channel Header..."]').clear().type('This is the new header content');
|
||||
cy.get('#channel_settings_header_textbox').clear().type('This is the new header content');
|
||||
|
||||
// * Verify the "Preview" button exists
|
||||
cy.findByText('Preview').should('be.visible');
|
||||
// * Verify the "Preview" button exists and is not active
|
||||
cy.get('#channel_settings_header_textbox').
|
||||
parents('.AdvancedTextbox').
|
||||
find('#PreviewInputTextButton').
|
||||
should('not.have.class', 'active');
|
||||
|
||||
// * Verify that before hitting the preview button, the style on the textbox is `display: block`
|
||||
cy.get('textarea[placeholder="Edit the Channel Header..."]').should('have.css', 'display', 'block');
|
||||
cy.get('#channel_settings_header_textbox').should('have.css', 'display', 'block');
|
||||
|
||||
// # Click the "Preview" button
|
||||
cy.findByText('Preview').click();
|
||||
|
||||
// * Verify the "Preview" button label has changed to "Edit"
|
||||
cy.findByText('Edit').should('be.visible');
|
||||
cy.get('#channel_settings_header_textbox').
|
||||
parents('.AdvancedTextbox').
|
||||
find('#PreviewInputTextButton').click();
|
||||
|
||||
// * Verify that the display is now none on the textbox element
|
||||
cy.get('textarea[placeholder="Edit the Channel Header..."]').should('have.css', 'display', 'none');
|
||||
cy.get('#channel_settings_header_textbox').should('have.css', 'display', 'none');
|
||||
|
||||
// * Verify the "Preview" button has class active
|
||||
cy.get('#channel_settings_header_textbox').
|
||||
parents('.AdvancedTextbox').
|
||||
find('#PreviewInputTextButton').
|
||||
should('have.class', 'active');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -0,0 +1,361 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
// ***************************************************************
|
||||
// - [#] indicates a test step (e.g. # Go to a page)
|
||||
// - [*] indicates an assertion (e.g. * Check the title)
|
||||
// - Use element ID when selecting an element. Create one if none.
|
||||
// ***************************************************************
|
||||
|
||||
// Stage: @prod
|
||||
// Group: @channels @channel @channel_settings
|
||||
|
||||
import {Team} from '@mattermost/types/teams';
|
||||
import {Channel} from '@mattermost/types/channels';
|
||||
import {UserProfile} from '@mattermost/types/users';
|
||||
|
||||
describe('Channel Settings Modal', () => {
|
||||
let testTeam: Team;
|
||||
let testUser: UserProfile;
|
||||
let testChannel: Channel;
|
||||
let originalTestChannel: Channel;
|
||||
|
||||
before(() => {
|
||||
// Setup test data
|
||||
cy.apiInitSetup().then(({team, user}) => {
|
||||
testTeam = team;
|
||||
testUser = user;
|
||||
|
||||
// Create a test channel
|
||||
cy.apiCreateChannel(testTeam.id, 'test-channel', 'Test Channel').then(({channel}) => {
|
||||
testChannel = channel;
|
||||
originalTestChannel = {...channel};
|
||||
cy.apiAddUserToChannel(channel.id, user.id);
|
||||
});
|
||||
|
||||
cy.apiLogin(testUser);
|
||||
});
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
// Visit the channel before each test
|
||||
cy.visit(`/${testTeam.name}/channels/${testChannel.name}`);
|
||||
});
|
||||
|
||||
// 2DO: update tests ids once QA has defined the test plan and zephyr tests
|
||||
it('MM-T1: Can open and close the channel settings modal', () => {
|
||||
// # Open channel settings modal from channel header dropdown
|
||||
cy.get('#channelHeaderDropdownButton').click();
|
||||
cy.findByText('Channel Settings').click();
|
||||
|
||||
// * Verify modal is open
|
||||
cy.get('.ChannelSettingsModal').should('be.visible');
|
||||
cy.get('#genericModalLabel').should('contain', 'Channel Settings');
|
||||
|
||||
// # Close the modal
|
||||
cy.get('.GenericModal .modal-header button[aria-label="Close"]').click();
|
||||
|
||||
// * Verify modal is closed
|
||||
cy.get('.ChannelSettingsModal').should('not.exist');
|
||||
});
|
||||
|
||||
it('MM-T2: Can navigate between tabs', () => {
|
||||
// # Open channel settings modal
|
||||
cy.get('#channelHeaderDropdownButton').click();
|
||||
cy.findByText('Channel Settings').click();
|
||||
|
||||
// * Verify Info tab is active by default
|
||||
cy.get('#infoButton').should('have.class', 'active');
|
||||
cy.get('.ChannelSettingsModal__infoTab').should('be.visible');
|
||||
|
||||
// # Click on Archive tab
|
||||
cy.get('#archiveButton').click();
|
||||
|
||||
// * Verify Archive tab is active
|
||||
cy.get('#archiveButton').should('have.class', 'active');
|
||||
cy.get('.ChannelSettingsModal__archiveTab').should('be.visible');
|
||||
|
||||
// # Click back on Info tab
|
||||
cy.get('#infoButton').click();
|
||||
|
||||
// * Verify Info tab is active again
|
||||
cy.get('#infoButton').should('have.class', 'active');
|
||||
cy.get('.ChannelSettingsModal__infoTab').should('be.visible');
|
||||
});
|
||||
|
||||
it('MM-T3: Can edit channel name and URL', () => {
|
||||
// # Open channel settings modal
|
||||
cy.get('#channelHeaderDropdownButton').click();
|
||||
cy.findByText('Channel Settings').click();
|
||||
|
||||
// # Get original channel name, url and alias it
|
||||
cy.get('#input_channel-settings-name').invoke('val').as('originalName');
|
||||
cy.get('.url-input-label').invoke('val').as('originalUrl');
|
||||
|
||||
// # Edit channel name
|
||||
cy.get('#input_channel-settings-name').clear().type('Updated Channel Name');
|
||||
|
||||
// * Verify URL is updated automatically
|
||||
cy.get('.url-input-label').should('contain', 'updated-channel-name');
|
||||
|
||||
// # Click Save
|
||||
cy.get('[data-testid="SaveChangesPanel__save-btn"]').click();
|
||||
|
||||
// * Verify changes are saved
|
||||
cy.get('.SaveChangesPanel').should('contain', 'Settings saved');
|
||||
|
||||
// # Close the modal
|
||||
cy.get('.GenericModal .modal-header button[aria-label="Close"]').click();
|
||||
|
||||
// * Verify channel header shows updated name
|
||||
cy.get('#channelHeaderTitle').should('contain', 'Updated Channel Name');
|
||||
|
||||
// # Open channel settings modal to restore original values
|
||||
cy.get('#channelHeaderDropdownButton').click();
|
||||
cy.findByText('Channel Settings').click();
|
||||
|
||||
// * Verify the channel name is reset to the original value
|
||||
cy.get('#input_channel-settings-name').clear().type(originalTestChannel.display_name);
|
||||
|
||||
// # Try to change URL to match the original url
|
||||
cy.get('.url-input-button').click();
|
||||
cy.get('.url-input-container input').clear().type(originalTestChannel.name);
|
||||
cy.get('.url-input-container button.url-input-button').click();
|
||||
|
||||
// # Save changes
|
||||
cy.get('[data-testid="SaveChangesPanel__save-btn"]').click();
|
||||
|
||||
// * Verify changes are saved
|
||||
cy.get('.SaveChangesPanel').should('contain', 'Settings saved');
|
||||
|
||||
// # Close the modal
|
||||
cy.get('.GenericModal .modal-header button[aria-label="Close"]').click();
|
||||
|
||||
// * Verify channel header shows updated name
|
||||
cy.get('#channelHeaderTitle').should('contain', originalTestChannel.display_name);
|
||||
});
|
||||
|
||||
it('MM-T4: Shows error for invalid channel name', () => {
|
||||
// # Open channel settings modal
|
||||
cy.get('#channelHeaderDropdownButton').click();
|
||||
cy.findByText('Channel Settings').click();
|
||||
|
||||
// # Set empty channel name
|
||||
cy.get('#input_channel-settings-name').clear();
|
||||
|
||||
// # Try Save changes
|
||||
cy.get('[data-testid="SaveChangesPanel__save-btn"]').click();
|
||||
|
||||
// * Verify error is shown
|
||||
cy.get('.Input_fieldset').should('have.class', 'Input_fieldset___error');
|
||||
cy.get('.SaveChangesPanel').should('contain', 'There are errors in the form above');
|
||||
});
|
||||
|
||||
it('MM-T6: Can edit channel purpose and header', () => {
|
||||
// # Open channel settings modal
|
||||
cy.get('#channelHeaderDropdownButton').click();
|
||||
cy.findByText('Channel Settings').click();
|
||||
|
||||
// # Edit channel purpose
|
||||
cy.get('#channel_settings_purpose_textbox').clear().type('This is a test purpose');
|
||||
|
||||
// # Edit channel header
|
||||
cy.get('#channel_settings_header_textbox').clear().type('This is a test header');
|
||||
|
||||
// # Save changes
|
||||
cy.get('[data-testid="SaveChangesPanel__save-btn"]').click();
|
||||
|
||||
// * Verify changes are saved
|
||||
cy.get('.SaveChangesPanel').should('contain', 'Settings saved');
|
||||
|
||||
// # Close the modal
|
||||
cy.get('.GenericModal .modal-header button[aria-label="Close"]').click();
|
||||
|
||||
// * Verify channel header shows updated header
|
||||
cy.get('#channelHeaderDescription').should('contain', 'This is a test header');
|
||||
});
|
||||
|
||||
it('MM-T7: Shows error when purpose exceeds character limit', () => {
|
||||
// # Open channel settings modal
|
||||
cy.get('#channelHeaderDropdownButton').click();
|
||||
cy.findByText('Channel Settings').click();
|
||||
|
||||
// # Enter purpose that exceeds character limit (250 characters)
|
||||
const longPurpose = 'a'.repeat(260);
|
||||
cy.get('#channel_settings_purpose_textbox').clear().type(longPurpose);
|
||||
|
||||
// * Verify error is shown
|
||||
cy.findAllByTestId('channel_settings_purpose_textbox').should('have.class', 'textarea--has-errors');
|
||||
cy.get('.SaveChangesPanel').should('contain', 'There are errors in the form above');
|
||||
});
|
||||
|
||||
it('MM-T8: Shows error when header exceeds character limit', () => {
|
||||
// # Open channel settings modal
|
||||
cy.get('#channelHeaderDropdownButton').click();
|
||||
cy.findByText('Channel Settings').click();
|
||||
|
||||
// # Enter header that exceeds character limit (1024 characters)
|
||||
const longHeader = 'a'.repeat(1050);
|
||||
cy.findByTestId('channel_settings_header_textbox').clear().type(longHeader);
|
||||
|
||||
// * Verify error is shown
|
||||
cy.findByTestId('channel_settings_header_textbox').should('have.class', 'textarea--has-errors');
|
||||
cy.get('.SaveChangesPanel').should('contain', 'There are errors in the form above');
|
||||
});
|
||||
|
||||
it('MM-T9: Can archive a channel and redirect to previous visited channel', () => {
|
||||
// # Create a new channel for this test
|
||||
cy.apiCreateChannel(testTeam.id, 'first-channel', 'First Channel').then(({channel: channel1}) => {
|
||||
cy.apiCreateChannel(testTeam.id, 'second-channel', 'Second Channel').then(({channel}) => {
|
||||
// # visit town square
|
||||
cy.visit(`/${testTeam.name}/channels/${channel1.name}`);
|
||||
|
||||
// # visit just created channel
|
||||
cy.visit(`/${testTeam.name}/channels/${channel.name}`);
|
||||
|
||||
// # Open channel settings modal
|
||||
cy.get('#channelHeaderDropdownButton').click();
|
||||
cy.findByText('Channel Settings').click();
|
||||
|
||||
// # Click on Archive tab
|
||||
cy.get('#archiveButton').click();
|
||||
|
||||
// # Click Archive button
|
||||
cy.get('#channelSettingsArchiveChannelButton').click();
|
||||
|
||||
// * Verify confirmation modal appears
|
||||
cy.get('#archiveChannelConfirmModal').should('be.visible');
|
||||
|
||||
// # Confirm archive
|
||||
cy.findByRole('button', {name: 'Confirm'}).click();
|
||||
|
||||
// * Verify redirect to Town Square
|
||||
cy.url().should('include', channel1.name);
|
||||
|
||||
// * Verify channel is no longer in sidebar
|
||||
cy.get('.SidebarChannel').contains('Archive Test').should('not.exist');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T10: Warns when switching tabs with unsaved changes', () => {
|
||||
// # Create a new channel for this test
|
||||
cy.apiCreateChannel(testTeam.id, 'unsaved-test', 'Unsaved Test').then(({channel}) => {
|
||||
cy.visit(`/${testTeam.name}/channels/${channel.name}`);
|
||||
|
||||
// # Open channel settings modal
|
||||
cy.get('#channelHeaderDropdownButton').click();
|
||||
cy.findByText('Channel Settings').click();
|
||||
|
||||
// # Make a change to the channel name
|
||||
cy.get('#input_channel-settings-name').clear().type('Changed Name');
|
||||
|
||||
// # Try to switch to Archive tab
|
||||
cy.get('#archiveButton').click();
|
||||
|
||||
// * Verify we're still on the Info tab due to unsaved changes
|
||||
cy.get('#infoButton').should('have.class', 'active');
|
||||
|
||||
// * Verify save changes panel shows error
|
||||
cy.get('.SaveChangesPanel').should('have.class', 'error');
|
||||
});
|
||||
});
|
||||
|
||||
// MM-T11: Can reset changes without saving
|
||||
it('MM-T11: Can reset changes without saving', () => {
|
||||
// # Create a new channel for this test
|
||||
cy.apiCreateChannel(testTeam.id, 'reset-test', 'Reset Test').then(({channel}) => {
|
||||
// # Visit the channel page using the channel name returned from the API
|
||||
cy.visit(`/${testTeam.name}/channels/${channel.name}`);
|
||||
|
||||
// # Open channel settings modal
|
||||
cy.get('#channelHeaderDropdownButton').click();
|
||||
cy.findByText('Channel Settings').click();
|
||||
|
||||
// # Get original channel name and alias it
|
||||
cy.get('#input_channel-settings-name').invoke('val').as('originalName');
|
||||
|
||||
// # Change the channel name
|
||||
cy.get('#input_channel-settings-name').clear().type('Temporary Name');
|
||||
|
||||
// # Click the Reset button in the SaveChangesPanel
|
||||
cy.get('.SaveChangesPanel button').contains('Reset').click();
|
||||
|
||||
// * Verify the channel name is reset to the original value
|
||||
cy.get('@originalName').then((originalName) => {
|
||||
cy.get('#input_channel-settings-name').should('have.value', originalName);
|
||||
});
|
||||
|
||||
// * Verify the SaveChangesPanel is no longer visible
|
||||
cy.get('.SaveChangesPanel').should('not.exist');
|
||||
});
|
||||
});
|
||||
|
||||
// MM-T12: Can preview purpose and header with markdown
|
||||
it('MM-T12: Can preview purpose and header with markdown', () => {
|
||||
// # Create a new channel for this test
|
||||
cy.apiCreateChannel(testTeam.id, 'markdown-test', 'Markdown Test').then(({channel}) => {
|
||||
// # Visit the channel page using the channel name returned from the API
|
||||
cy.visit(`/${testTeam.name}/channels/${channel.name}`);
|
||||
|
||||
// # Open channel settings modal
|
||||
cy.get('#channelHeaderDropdownButton').click();
|
||||
cy.findByText('Channel Settings').click();
|
||||
|
||||
// # Add markdown to purpose
|
||||
cy.get('#channel_settings_purpose_textbox').clear().type('This is **bold** and _italic_ text');
|
||||
|
||||
// # Click preview button for purpose (assumes preview button is inside the AdvancedTextbox container)
|
||||
cy.get('#channel_settings_purpose_textbox').
|
||||
parents('.AdvancedTextbox').
|
||||
find('#PreviewInputTextButton').
|
||||
click();
|
||||
|
||||
// * Verify that markdown is rendered in preview: check for bold and italic formatting
|
||||
cy.get('.textbox-preview-area').
|
||||
should('contain', 'This is').
|
||||
find('strong').
|
||||
should('contain', 'bold');
|
||||
cy.get('.textbox-preview-area').
|
||||
find('em').
|
||||
should('contain', 'italic');
|
||||
|
||||
// # Add markdown to header
|
||||
cy.get('#channel_settings_header_textbox').clear().type('Visit [Mattermost](https://mattermost.com)');
|
||||
|
||||
// # Click preview button for header
|
||||
cy.get('#channel_settings_header_textbox').
|
||||
parents('.AdvancedTextbox').
|
||||
find('#PreviewInputTextButton').
|
||||
click();
|
||||
|
||||
// * Verify that markdown is rendered in preview: check for a link with text "Mattermost"
|
||||
cy.get('.textbox-preview-area').
|
||||
should('contain', 'Visit').
|
||||
find('a').
|
||||
should('contain', 'Mattermost');
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T13: Validates URL when editing channel name', () => {
|
||||
// # Create two channels to test URL conflict error
|
||||
cy.apiCreateChannel(testTeam.id, 'first-channel', 'First Channel').then(({channel: channel1}) => {
|
||||
cy.apiCreateChannel(testTeam.id, 'second-channel', 'Second Channel').then(({channel}) => {
|
||||
cy.visit(`/${testTeam.name}/channels/${channel.name}`);
|
||||
|
||||
// # Open channel settings modal
|
||||
cy.get('#channelHeaderDropdownButton').click();
|
||||
cy.findByText('Channel Settings').click();
|
||||
|
||||
// # Try to change URL to match the first channel
|
||||
cy.get('.url-input-button').click();
|
||||
cy.get('.url-input-container input').clear().type(channel1.name);
|
||||
cy.get('.url-input-container button.url-input-button').click();
|
||||
|
||||
// * Verify error is shown
|
||||
cy.get('[data-testid="SaveChangesPanel__save-btn"]').click();
|
||||
cy.get('.SaveChangesPanel').should('contain', 'There are errors in the form above');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -37,22 +37,23 @@ describe('Channel Settings', () => {
|
||||
// # Go to test channel
|
||||
cy.visit(`/${testTeam.name}/channels/${channel.name}`);
|
||||
|
||||
// # Go to channel dropdown > Rename channel
|
||||
cy.get('#channelHeaderTitle').click();
|
||||
cy.findByText('Channel Settings').should('be.visible').trigger('mouseover');
|
||||
cy.findByText('Rename Channel').click();
|
||||
// # Go to channel dropdown > Channel Settings Modal
|
||||
cy.get('#channelHeaderDropdownButton').click();
|
||||
cy.findByText('Channel Settings').click();
|
||||
|
||||
// # Try to enter existing URL and save
|
||||
cy.get('#channel_name').clear().type('town-square');
|
||||
cy.get('#save-button').click();
|
||||
cy.get('#input_channel-settings-name').clear().type('town-square');
|
||||
cy.get('[data-testid="SaveChangesPanel__save-btn"]').click();
|
||||
|
||||
// # Error is displayed and URL is unchanged
|
||||
cy.get('.has-error').should('be.visible').and('contain', 'A channel with that name already exists on the same team.');
|
||||
cy.get('.SaveChangesPanel').should('contain', 'There are errors in the form above');
|
||||
cy.get('.url-input-error').should('be.visible').and('contain.text', 'A channel with that name already exists on the same team.');
|
||||
|
||||
cy.url().should('include', `/${testTeam.name}/channels/${channel.name}`);
|
||||
|
||||
// # Enter a new URL and save
|
||||
cy.get('#channel_name').clear().type('another-town-square');
|
||||
cy.get('#save-button').click();
|
||||
cy.get('#input_channel-settings-name').clear().type('another-town-square');
|
||||
cy.get('[data-testid="SaveChangesPanel__save-btn"]').click();
|
||||
|
||||
// * URL is updated and no errors are displayed
|
||||
cy.url().should('include', `/${testTeam.name}/channels/another-town-square`);
|
||||
|
||||
@@ -1,179 +0,0 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {Team} from '@mattermost/types/teams';
|
||||
import {UserProfile} from '@mattermost/types/users';
|
||||
|
||||
// ***************************************************************
|
||||
// - [#] indicates a test step (e.g. # Go to a page)
|
||||
// - [*] indicates an assertion (e.g. * Check the title)
|
||||
// - Use element ID when selecting an element. Create one if none.
|
||||
// ***************************************************************
|
||||
|
||||
// Stage: @prod
|
||||
// Group: @channels @channel
|
||||
|
||||
describe('Channels', () => {
|
||||
let testUser: UserProfile;
|
||||
let testTeam: Team;
|
||||
|
||||
before(() => {
|
||||
cy.apiInitSetup().then(({team, user}) => {
|
||||
testUser = user;
|
||||
testTeam = team;
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T3348 - Convert to private channel should only be shown to users with permission', () => {
|
||||
// # Reset permissions to default
|
||||
resetPermissionsToDefault();
|
||||
|
||||
// # Enable convert public channels to private for all users
|
||||
enablePermission('all_users-public_channel-convert_public_channel_to_private-checkbox');
|
||||
saveConfig();
|
||||
|
||||
// # Login as a regular user
|
||||
cy.apiLogin(testUser);
|
||||
|
||||
// # Create new test channel
|
||||
cy.apiCreateChannel(testTeam.id, 'channel-test', 'Channel').then(({channel}) => {
|
||||
// # Go to test channel
|
||||
cy.visit(`/${testTeam.name}/channels/${channel.name}`);
|
||||
|
||||
// # Click the channel header dropdown
|
||||
cy.get('#channelHeaderTitle').click();
|
||||
|
||||
// open ChannelSettings submenu
|
||||
cy.findByRole('menuitem', {name: 'Channel Settings'}).trigger('mouseover');
|
||||
|
||||
// * Channel convert to private should be visible and confirm
|
||||
cy.get('#channelConvertToPrivate').should('be.visible').click();
|
||||
cy.findByTestId('convertChannelConfirm').should('be.visible').click();
|
||||
|
||||
// # Click the channel header dropdown
|
||||
cy.get('#channelHeaderTitle').click();
|
||||
|
||||
// open ChannelSettings submenu
|
||||
cy.findByRole('menuitem', {name: 'Channel Settings'}).trigger('mouseover');
|
||||
|
||||
// * Channel convert to private should no longer be visible
|
||||
cy.get('#channelConvertToPrivate').should('not.exist');
|
||||
});
|
||||
|
||||
// # Reset permissions to default
|
||||
resetPermissionsToDefault();
|
||||
|
||||
// # Login as a regular user
|
||||
cy.apiLogin(testUser);
|
||||
|
||||
// # Create new test channel
|
||||
cy.apiCreateChannel(testTeam.id, 'channel-test', 'Channel').then(({channel}) => {
|
||||
// # Go to test channel
|
||||
cy.visit(`/${testTeam.name}/channels/${channel.name}`);
|
||||
|
||||
// # Click the channel header dropdown
|
||||
cy.get('#channelHeaderTitle').click();
|
||||
|
||||
// open ChannelSettings submenu
|
||||
cy.findByRole('menuitem', {name: 'Channel Settings'}).trigger('mouseover');
|
||||
|
||||
// * Channel convert to private should no longer be visible
|
||||
cy.get('#channelConvertToPrivate').should('not.exist');
|
||||
});
|
||||
|
||||
// # Reset permissions to default
|
||||
resetPermissionsToDefault();
|
||||
|
||||
// # Remove permission from team admins
|
||||
removePermission('team_admin-public_channel-convert_public_channel_to_private-checkbox');
|
||||
saveConfig();
|
||||
|
||||
// # Promote user to team admin
|
||||
cy.apiUpdateTeamMemberSchemeRole(testTeam.id, testUser.id, {scheme_admin: true, scheme_user: true});
|
||||
|
||||
// # Login as the now team admin user
|
||||
cy.apiLogin(testUser);
|
||||
|
||||
// # Create new test channel
|
||||
cy.apiCreateChannel(testTeam.id, 'channel-test', 'Channel').then(({channel}) => {
|
||||
// # Go to test channel
|
||||
cy.visit(`/${testTeam.name}/channels/${channel.name}`);
|
||||
|
||||
// # Click the channel header dropdown
|
||||
cy.get('#channelHeaderTitle').click();
|
||||
|
||||
// open ChannelSettings submenu
|
||||
cy.findByRole('menuitem', {name: 'Channel Settings'}).trigger('mouseover');
|
||||
|
||||
// * Channel convert to private should not be visible
|
||||
cy.get('#channelConvertToPrivate').should('not.exist');
|
||||
});
|
||||
|
||||
// # Reset permissions to default
|
||||
resetPermissionsToDefault();
|
||||
|
||||
// # Login as the team admin user
|
||||
cy.apiLogin(testUser);
|
||||
|
||||
// # Create new test channel
|
||||
cy.apiCreateChannel(testTeam.id, 'channel-test', 'Channel').then(({channel}) => {
|
||||
// # Go to test channel
|
||||
cy.visit(`/${testTeam.name}/channels/${channel.name}`);
|
||||
|
||||
// # Click the channel header dropdown
|
||||
cy.get('#channelHeaderTitle').click();
|
||||
|
||||
// open ChannelSettings submenu
|
||||
cy.findByRole('menuitem', {name: 'Channel Settings'}).trigger('mouseover');
|
||||
|
||||
// * Channel convert to private should be visible and confirm
|
||||
cy.get('#channelConvertToPrivate').should('be.visible').click();
|
||||
cy.findByTestId('convertChannelConfirm').should('be.visible').click();
|
||||
|
||||
// # Click the channel header dropdown
|
||||
cy.get('#channelHeaderTitle').click();
|
||||
|
||||
// open ChannelSettings submenu
|
||||
cy.findByRole('menuitem', {name: 'Channel Settings'}).trigger('mouseover');
|
||||
|
||||
// * Channel convert to private should no longer be visible
|
||||
cy.get('#channelConvertToPrivate').should('not.exist');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
const saveConfig = () => {
|
||||
cy.get('#saveSetting').click();
|
||||
cy.waitUntil(() => cy.get('#saveSetting').then((el) => {
|
||||
return el[0].innerText === 'Save';
|
||||
}));
|
||||
};
|
||||
|
||||
const enablePermission = (permissionCheckBoxTestId) => {
|
||||
cy.findByTestId(permissionCheckBoxTestId).then((el) => {
|
||||
if (!el.hasClass('checked')) {
|
||||
el.click();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const removePermission = (permissionCheckBoxTestId) => {
|
||||
cy.findByTestId(permissionCheckBoxTestId).then((el) => {
|
||||
if (el.hasClass('checked')) {
|
||||
el.click();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const resetPermissionsToDefault = () => {
|
||||
// # Login as sysadmin and navigate to system scheme page
|
||||
cy.apiAdminLogin();
|
||||
cy.visit('/admin_console/user_management/permissions/system_scheme');
|
||||
|
||||
// # Click reset to defaults and confirm
|
||||
cy.findByTestId('resetPermissionsToDefault').click();
|
||||
cy.get('#confirmModalButton').click();
|
||||
|
||||
// # Save
|
||||
saveConfig();
|
||||
};
|
||||
@@ -0,0 +1,567 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {Team} from '@mattermost/types/teams';
|
||||
import {UserProfile} from '@mattermost/types/users';
|
||||
import {Channel} from '@mattermost/types/channels';
|
||||
import {getAdminAccount} from '../../../support/env';
|
||||
|
||||
// ***************************************************************
|
||||
// - [#] indicates a test step (e.g. # Go to a page)
|
||||
// - [*] indicates an assertion (e.g. * Check the title)
|
||||
// - Use element ID when selecting an element. Create one if none.
|
||||
// ***************************************************************
|
||||
|
||||
// Stage: @prod
|
||||
// Group: @channels @channel
|
||||
|
||||
describe('Channel Type Conversion (Public to Private Only)', () => {
|
||||
let testUser: UserProfile;
|
||||
let testTeam: Team;
|
||||
const admin = getAdminAccount();
|
||||
|
||||
// Helper functions for permission management
|
||||
const saveConfig = () => {
|
||||
cy.waitUntil(() =>
|
||||
cy.get('#saveSetting').then((button) => {
|
||||
// Check if the button text is exactly "Save"
|
||||
if (button.text().trim() === 'Save') {
|
||||
button.click();
|
||||
return true; // signals waitUntil that it succeeded
|
||||
}
|
||||
return false;
|
||||
}),
|
||||
);
|
||||
};
|
||||
|
||||
const enablePermission = (permissionCheckBoxTestId: string) => {
|
||||
cy.findByTestId(permissionCheckBoxTestId).then((el) => {
|
||||
if (!el.hasClass('checked')) {
|
||||
el.click();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const removePermission = (permissionCheckBoxTestId: string) => {
|
||||
cy.findByTestId(permissionCheckBoxTestId).then((el) => {
|
||||
if (el.hasClass('checked')) {
|
||||
el.click();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const promoteToChannelAdmin = (userId, channelId, admin) => {
|
||||
cy.externalRequest({
|
||||
user: admin,
|
||||
method: 'put',
|
||||
path: `channels/${channelId}/members/${userId}/schemeRoles`,
|
||||
data: {
|
||||
scheme_user: true,
|
||||
scheme_admin: true,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const resetPermissionsToDefault = () => {
|
||||
// # Login as sysadmin and navigate to system scheme page
|
||||
cy.apiAdminLogin();
|
||||
cy.visit('/admin_console/user_management/permissions/system_scheme');
|
||||
|
||||
// # Click reset to defaults and confirm
|
||||
cy.findByTestId('resetPermissionsToDefault').click();
|
||||
cy.get('#confirmModalButton').click();
|
||||
|
||||
// # Save
|
||||
saveConfig();
|
||||
cy.wait(1000);
|
||||
cy.visit('/admin_console/user_management/permissions/system_scheme');
|
||||
};
|
||||
|
||||
// Helper functions for permission setup
|
||||
const setupPermissions = (config: {
|
||||
resetToDefault?: boolean;
|
||||
publicToPrivate?: boolean;
|
||||
removeFromTeamAdmin?: boolean;
|
||||
}) => {
|
||||
if (config.resetToDefault) {
|
||||
resetPermissionsToDefault();
|
||||
}
|
||||
|
||||
// Public to private conversion permissions
|
||||
if (config.publicToPrivate) {
|
||||
enablePermission('all_users-public_channel-convert_public_channel_to_private-checkbox');
|
||||
} else if (config.publicToPrivate === false) {
|
||||
removePermission('all_users-public_channel-convert_public_channel_to_private-checkbox');
|
||||
}
|
||||
|
||||
// Remove public to private conversion from team admin if specified
|
||||
if (config.removeFromTeamAdmin) {
|
||||
removePermission('team_admin-public_channel-convert_public_channel_to_private-checkbox');
|
||||
}
|
||||
|
||||
cy.wait(1000);
|
||||
|
||||
saveConfig();
|
||||
};
|
||||
|
||||
// Helper functions for channel management
|
||||
const createAndVisitPublicChannel = (teamName: string, channelId: string, displayName: string): Cypress.Chainable<Channel> => {
|
||||
return cy.apiCreateChannel(testTeam.id, channelId, displayName).then(({channel}) => {
|
||||
cy.apiAddUserToChannel(channel.id, testUser.id);
|
||||
cy.visit(`/${teamName}/channels/${channel.name}`);
|
||||
return cy.wrap(channel);
|
||||
});
|
||||
};
|
||||
|
||||
const createAndVisitPrivateChannel = (teamName: string, channelId: string, displayName: string): Cypress.Chainable<Channel> => {
|
||||
return cy.apiCreateChannel(testTeam.id, channelId, displayName, 'P').then(({channel}) => {
|
||||
cy.apiAddUserToChannel(channel.id, testUser.id);
|
||||
cy.visit(`/${teamName}/channels/${channel.name}`);
|
||||
return cy.wrap(channel);
|
||||
});
|
||||
};
|
||||
|
||||
const visitChannel = (teamName: string, channelName: string) => {
|
||||
cy.visit(`/${teamName}/channels/${channelName}`);
|
||||
};
|
||||
|
||||
// Helper functions for UI interaction
|
||||
const openChannelSettingsModal = () => {
|
||||
cy.get('#channelHeaderDropdownButton').click();
|
||||
cy.findByText('Channel Settings').click();
|
||||
cy.get('.ChannelSettingsModal').should('be.visible');
|
||||
};
|
||||
|
||||
const closeChannelSettingsModal = () => {
|
||||
cy.get('.GenericModal .modal-header button[aria-label="Close"]').click();
|
||||
cy.get('.ChannelSettingsModal').should('not.exist');
|
||||
};
|
||||
|
||||
// Helper functions for UI interaction
|
||||
const saveChannelSettings = () => {
|
||||
cy.get('[data-testid="SaveChangesPanel__save-btn"]').click();
|
||||
};
|
||||
|
||||
const verifySettingsSaved = () => {
|
||||
cy.get('.SaveChangesPanel').should('contain', 'Settings saved');
|
||||
};
|
||||
|
||||
// Helper functions for channel conversion
|
||||
const convertChannelToPrivate = () => {
|
||||
// Select private channel type
|
||||
cy.get('#public-private-selector-button-P').click();
|
||||
cy.get('#public-private-selector-button-P').should('have.class', 'selected');
|
||||
|
||||
// Save changes - this will trigger the confirmation modal
|
||||
saveChannelSettings();
|
||||
|
||||
// Handle the confirmation modal that appears when converting from public to private
|
||||
cy.get('#confirmModal').should('be.visible');
|
||||
cy.get('#confirmModalButton').click();
|
||||
|
||||
// Verify settings were saved
|
||||
verifySettingsSaved();
|
||||
};
|
||||
|
||||
// Function kept for potential future use but not used in current tests
|
||||
// since private to public conversion is no longer allowed
|
||||
// const convertChannelToPublic = () => {
|
||||
// cy.get('#public-private-selector-button-O').click();
|
||||
// cy.get('#public-private-selector-button-O').should('have.class', 'selected');
|
||||
// };
|
||||
|
||||
// Helper functions for verification
|
||||
const verifyChannelIsPrivate = (channelName: string) => {
|
||||
cy.get('.SidebarChannel').contains(channelName).parent().find('.icon-lock-outline').should('exist');
|
||||
};
|
||||
|
||||
// Function kept for potential future use but not used in current tests
|
||||
// since private to public conversion is no longer allowed
|
||||
// const verifyChannelIsPublic = (channelName: string) => {
|
||||
// cy.get('.SidebarChannel').contains(channelName).parent().find('.icon-lock-outline').should('not.exist');
|
||||
// };
|
||||
|
||||
const verifyConversionOptionDisabled = (toPrivate = true) => {
|
||||
if (toPrivate) {
|
||||
// Wait for the UI to fully load and stabilize
|
||||
cy.wait(500);
|
||||
|
||||
// Check if the button is disabled - it might have a disabled attribute or a disabled class
|
||||
cy.get('#public-private-selector-button-P').then(($el) => {
|
||||
const isDisabled = $el.hasClass('disabled') || $el.prop('disabled') === true || $el.attr('aria-disabled') === 'true';
|
||||
expect(isDisabled).to.be.true;
|
||||
});
|
||||
} else {
|
||||
// Wait for the UI to fully load and stabilize
|
||||
cy.wait(500);
|
||||
|
||||
// Check if the button is disabled - it might have a disabled attribute or a disabled class
|
||||
cy.get('#public-private-selector-button-O').then(($el) => {
|
||||
const isDisabled = $el.hasClass('disabled') || $el.prop('disabled') === true || $el.attr('aria-disabled') === 'true';
|
||||
expect(isDisabled).to.be.true;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const verifyConversionOptionEnabled = (toPrivate = true) => {
|
||||
if (toPrivate) {
|
||||
// Wait for the UI to fully load and stabilize
|
||||
cy.wait(500);
|
||||
|
||||
// Check if the button is enabled - it should not have disabled attributes or classes
|
||||
cy.get('#public-private-selector-button-P').then(($el) => {
|
||||
const isDisabled = $el.hasClass('disabled') || $el.prop('disabled') === true || $el.attr('aria-disabled') === 'true';
|
||||
expect(isDisabled).to.be.false;
|
||||
});
|
||||
} else {
|
||||
// Wait for the UI to fully load and stabilize
|
||||
cy.wait(500);
|
||||
|
||||
// Check if the button is enabled - it should not have disabled attributes or classes
|
||||
cy.get('#public-private-selector-button-O').then(($el) => {
|
||||
const isDisabled = $el.hasClass('disabled') || $el.prop('disabled') === true || $el.attr('aria-disabled') === 'true';
|
||||
expect(isDisabled).to.be.false;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// Helper function to make user a channel admin
|
||||
const makeUserChannelAdmin = (channelId: string, userId: string) => {
|
||||
cy.apiAddUserToChannel(channelId, userId);
|
||||
promoteToChannelAdmin(userId, channelId, admin);
|
||||
};
|
||||
|
||||
// Helper function to make user a team admin
|
||||
const makeUserTeamAdmin = (teamId: string, userId: string) => {
|
||||
cy.apiUpdateTeamMemberSchemeRole(teamId, userId, {scheme_admin: true, scheme_user: true});
|
||||
};
|
||||
|
||||
before(() => {
|
||||
cy.apiInitSetup().then(({team, user}) => {
|
||||
testUser = user;
|
||||
testTeam = team;
|
||||
});
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
// Reset to a clean state before each test
|
||||
cy.apiLogin(testUser);
|
||||
});
|
||||
|
||||
describe('Basic Conversion Functionality', () => {
|
||||
it('MM-T3348-1 - Can convert a public channel to private', () => {
|
||||
// # Setup permissions
|
||||
setupPermissions({resetToDefault: true, publicToPrivate: true});
|
||||
|
||||
// # Create and visit a public channel
|
||||
createAndVisitPublicChannel(testTeam.name, 'public-to-private', 'Public To Private').then((channel) => {
|
||||
// # Open channel settings modal
|
||||
openChannelSettingsModal();
|
||||
|
||||
// # Convert to private
|
||||
convertChannelToPrivate();
|
||||
|
||||
// # Close the modal
|
||||
closeChannelSettingsModal();
|
||||
|
||||
// * Verify channel is now private
|
||||
verifyChannelIsPrivate(channel.display_name);
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T3348-5 - Cannot convert a private channel back to public', () => {
|
||||
// # Setup permissions
|
||||
setupPermissions({resetToDefault: true, publicToPrivate: true});
|
||||
|
||||
// # Create and visit a public channel
|
||||
createAndVisitPublicChannel(testTeam.name, 'private-stays-private', 'Private Stays Private').then((channel) => {
|
||||
// # Open channel settings modal
|
||||
openChannelSettingsModal();
|
||||
|
||||
// # Convert to private
|
||||
convertChannelToPrivate();
|
||||
|
||||
// # Close the modal
|
||||
closeChannelSettingsModal();
|
||||
|
||||
// * Verify channel is now private
|
||||
verifyChannelIsPrivate(channel.display_name);
|
||||
|
||||
// # Open channel settings modal again
|
||||
openChannelSettingsModal();
|
||||
|
||||
// * Verify conversion option to public is disabled
|
||||
verifyConversionOptionDisabled(false);
|
||||
|
||||
// # Close the modal
|
||||
closeChannelSettingsModal();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Role-Based Channel Type Conversion', () => {
|
||||
it('MM-T3350-1 - System admin cannot convert a private channel to public', () => {
|
||||
// # Reset permissions to default
|
||||
resetPermissionsToDefault();
|
||||
|
||||
// # Login as system admin
|
||||
cy.apiAdminLogin();
|
||||
|
||||
// # Create and visit a private channel
|
||||
createAndVisitPrivateChannel(testTeam.name, 'sysadmin-private-stays-private', 'SysAdmin Private Channel').then(() => {
|
||||
// # Open channel settings modal
|
||||
openChannelSettingsModal();
|
||||
|
||||
// * Verify conversion option to public is disabled
|
||||
verifyConversionOptionDisabled(false);
|
||||
|
||||
// # Close the modal
|
||||
closeChannelSettingsModal();
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T3350-2 - Channel admin cannot convert a private channel to public', () => {
|
||||
// # Reset permissions to default
|
||||
setupPermissions({resetToDefault: true});
|
||||
|
||||
// # Login as regular user
|
||||
cy.apiLogin(testUser);
|
||||
|
||||
// # Create and visit a private channel
|
||||
createAndVisitPrivateChannel(testTeam.name, 'channel-admin-private', 'Channel Admin Private').then((channel) => {
|
||||
// # Make test user a channel admin
|
||||
makeUserChannelAdmin(channel.id, testUser.id);
|
||||
|
||||
// # Visit the channel again after role change
|
||||
visitChannel(testTeam.name, channel.name);
|
||||
|
||||
// # Open channel settings modal
|
||||
openChannelSettingsModal();
|
||||
|
||||
// * Verify conversion option to public is disabled
|
||||
verifyConversionOptionDisabled(false);
|
||||
|
||||
// # Close the modal
|
||||
closeChannelSettingsModal();
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T3350-3 - Team admin cannot convert a private channel to public', () => {
|
||||
// # Reset permissions to default
|
||||
setupPermissions({resetToDefault: true});
|
||||
|
||||
// # Make test user a team admin
|
||||
makeUserTeamAdmin(testTeam.id, testUser.id);
|
||||
|
||||
// # Login as team admin
|
||||
cy.apiLogin(testUser);
|
||||
|
||||
// # Create and visit a private channel
|
||||
createAndVisitPrivateChannel(testTeam.name, 'team-admin-private', 'Team Admin Private').then(() => {
|
||||
// # Open channel settings modal
|
||||
openChannelSettingsModal();
|
||||
|
||||
// * Verify conversion option to public is disabled
|
||||
verifyConversionOptionDisabled(false);
|
||||
|
||||
// # Close the modal
|
||||
closeChannelSettingsModal();
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T3350-4 - Regular user cannot convert a private channel to public', () => {
|
||||
// # Reset permissions to default
|
||||
resetPermissionsToDefault();
|
||||
|
||||
// # Create a new regular user specifically for this test
|
||||
cy.apiCreateUser().then(({user: regularUser}) => {
|
||||
// # Add user to the team
|
||||
cy.apiAddUserToTeam(testTeam.id, regularUser.id);
|
||||
|
||||
// # Have admin create a private channel
|
||||
cy.apiAdminLogin();
|
||||
cy.apiCreateChannel(testTeam.id, 'admin-created-private', 'Admin Created Private', 'P').then(({channel}) => {
|
||||
// # Add the regular user to the channel (as a regular member, not admin)
|
||||
cy.apiAddUserToChannel(channel.id, regularUser.id);
|
||||
|
||||
// # Login as the regular user
|
||||
cy.apiLogin(regularUser);
|
||||
|
||||
// # Visit the channel
|
||||
cy.visit(`/${testTeam.name}/channels/${channel.name}`);
|
||||
|
||||
// # Open channel settings modal
|
||||
openChannelSettingsModal();
|
||||
|
||||
// * Verify conversion option is disabled
|
||||
verifyConversionOptionDisabled(false);
|
||||
|
||||
// # Close the modal
|
||||
closeChannelSettingsModal();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Permission-Based Tests', () => {
|
||||
it('MM-T3348-2 - Regular user without permission cannot convert public to private', () => {
|
||||
// # Setup permissions - remove public to private conversion permission
|
||||
setupPermissions({resetToDefault: true, publicToPrivate: false});
|
||||
|
||||
// # Create a new regular user specifically for this test
|
||||
cy.apiCreateUser().then(({user: regularUser}) => {
|
||||
// # Add user to the team
|
||||
cy.apiAddUserToTeam(testTeam.id, regularUser.id);
|
||||
|
||||
// # Have admin create a public channel
|
||||
cy.apiAdminLogin();
|
||||
cy.apiCreateChannel(testTeam.id, 'admin-created-public', 'Admin Created Public').then(({channel}) => {
|
||||
// # Add the regular user to the channel (as a regular member, not admin)
|
||||
cy.apiAddUserToChannel(channel.id, regularUser.id);
|
||||
|
||||
// # Login as the regular user
|
||||
cy.apiLogin(regularUser);
|
||||
|
||||
// # Visit the channel
|
||||
cy.visit(`/${testTeam.name}/channels/${channel.name}`);
|
||||
|
||||
// # Open channel settings modal
|
||||
openChannelSettingsModal();
|
||||
|
||||
// * Verify conversion option is disabled
|
||||
verifyConversionOptionDisabled(true);
|
||||
|
||||
// # Close the modal
|
||||
closeChannelSettingsModal();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T3348-3 - Team admin can convert public to private by default', () => {
|
||||
// # Setup permissions - reset to default
|
||||
setupPermissions({resetToDefault: true});
|
||||
|
||||
// # Make test user a team admin
|
||||
makeUserTeamAdmin(testTeam.id, testUser.id);
|
||||
|
||||
// # Create and visit a public channel
|
||||
createAndVisitPublicChannel(testTeam.name, 'team-admin-convert', 'Team Admin Convert').then((channel) => {
|
||||
// # Open channel settings modal
|
||||
openChannelSettingsModal();
|
||||
|
||||
// * Verify conversion option is enabled
|
||||
verifyConversionOptionEnabled(true);
|
||||
|
||||
// # Convert to private
|
||||
convertChannelToPrivate();
|
||||
|
||||
// # Close the modal
|
||||
closeChannelSettingsModal();
|
||||
|
||||
// * Verify channel is now private
|
||||
verifyChannelIsPrivate(channel.display_name);
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T3348-4 - Team admin cannot convert when permission is removed', () => {
|
||||
// # Setup permissions - remove permission from team admin
|
||||
setupPermissions({
|
||||
resetToDefault: true,
|
||||
removeFromTeamAdmin: true,
|
||||
});
|
||||
|
||||
// # Make test user a team admin
|
||||
makeUserTeamAdmin(testTeam.id, testUser.id);
|
||||
|
||||
// # Have admin create a public channel
|
||||
cy.apiAdminLogin();
|
||||
cy.apiCreateChannel(testTeam.id, 'admin-created-team-admin-no-perm', 'Admin Created Team Admin No Permission').then(({channel}) => {
|
||||
// # Add the team admin user to the channel (as a regular member, not channel admin)
|
||||
cy.apiAddUserToChannel(channel.id, testUser.id);
|
||||
|
||||
// # Login as the team admin user
|
||||
cy.apiLogin(testUser);
|
||||
|
||||
// # Visit the channel
|
||||
cy.visit(`/${testTeam.name}/channels/${channel.name}`);
|
||||
|
||||
// # Open channel settings modal
|
||||
openChannelSettingsModal();
|
||||
|
||||
// * Verify conversion option is disabled
|
||||
verifyConversionOptionDisabled(true);
|
||||
|
||||
// # Close the modal
|
||||
closeChannelSettingsModal();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Channel Admin Tests', () => {
|
||||
it('MM-T3349-1 - Channel admin can convert public to private when permission is enabled', () => {
|
||||
// # Setup permissions - enable public to private conversion permission
|
||||
setupPermissions({resetToDefault: true, publicToPrivate: true});
|
||||
|
||||
// # Create and visit a public channel
|
||||
createAndVisitPublicChannel(testTeam.name, 'channel-admin-pub', 'Channel Admin Public').then((channel) => {
|
||||
// # Make test user a channel admin
|
||||
makeUserChannelAdmin(channel.id, testUser.id);
|
||||
|
||||
// # Visit the channel again after role change
|
||||
visitChannel(testTeam.name, channel.name);
|
||||
|
||||
// # Open channel settings modal
|
||||
openChannelSettingsModal();
|
||||
|
||||
// * Verify conversion option is enabled
|
||||
verifyConversionOptionEnabled(true);
|
||||
|
||||
// # Convert to private
|
||||
convertChannelToPrivate();
|
||||
|
||||
// # Close the modal
|
||||
closeChannelSettingsModal();
|
||||
|
||||
// * Verify channel is now private
|
||||
verifyChannelIsPrivate(channel.display_name);
|
||||
});
|
||||
});
|
||||
|
||||
it('MM-T3349-2 - Channel admin cannot convert public to private when permission is removed', () => {
|
||||
// Generate a unique channel name with timestamp to avoid conflicts
|
||||
const timestamp = Date.now();
|
||||
const channelId = `channel-admin-no-perm-${timestamp}`;
|
||||
const displayName = `Channel Admin No Permission ${timestamp}`;
|
||||
|
||||
// # Setup permissions - remove public to private conversion permission
|
||||
setupPermissions({resetToDefault: true, publicToPrivate: false, removeFromTeamAdmin: true});
|
||||
|
||||
// # Create and visit a public channel
|
||||
createAndVisitPublicChannel(testTeam.name, channelId, displayName).then((channel) => {
|
||||
// # Make test user a channel admin
|
||||
makeUserChannelAdmin(channel.id, testUser.id);
|
||||
|
||||
// # Log back in as the test user after making channel admin
|
||||
cy.apiLogin(testUser);
|
||||
|
||||
// # Wait for login to complete
|
||||
cy.wait(500);
|
||||
|
||||
// # Visit the channel again after role change
|
||||
visitChannel(testTeam.name, channel.name);
|
||||
|
||||
// # Wait for channel to load
|
||||
cy.wait(500);
|
||||
|
||||
// # Open channel settings modal
|
||||
openChannelSettingsModal();
|
||||
|
||||
// * Verify conversion option is disabled
|
||||
verifyConversionOptionDisabled(true);
|
||||
|
||||
// # Close the modal
|
||||
closeChannelSettingsModal();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -58,19 +58,7 @@ describe('Leave and Archive channel actions display as destructive', () => {
|
||||
cy.get('#channelMembers').should('be.visible');
|
||||
|
||||
// * Channel Settings menu option should be visible
|
||||
cy.findByText('Channel Settings').should('be.visible').trigger('mouseover');
|
||||
|
||||
// * Edit Channel Header menu option should be visible
|
||||
cy.get('#channelEditHeader').should('be.visible');
|
||||
|
||||
// * Edit Channel Purpose menu option should be visible
|
||||
cy.get('#channelEditPurpose').should('be.visible');
|
||||
|
||||
// * Rename Channel menu option should be visible
|
||||
cy.get('#channelRename').should('be.visible');
|
||||
|
||||
// * Channel Settings close menu option
|
||||
cy.findByText('Channel Settings').should('be.visible').trigger('mouseout');
|
||||
cy.findByText('Channel Settings').should('be.visible');
|
||||
|
||||
// * Archive Channel menu option should be visible and have a background-color (destructive)
|
||||
cy.get('#channelArchiveChannel').should('be.visible').focus().should('have.css', 'background-color', 'rgb(210, 75, 78)');
|
||||
|
||||
@@ -14,15 +14,13 @@ import * as TIMEOUTS from '../../../fixtures/timeouts';
|
||||
import {getRandomId} from '../../../utils';
|
||||
|
||||
describe('Channel routing', () => {
|
||||
let testTeam: Cypress.Team;
|
||||
let testUser: Cypress.UserProfile;
|
||||
let testChannel: Cypress.Channel;
|
||||
let testTeam: any;
|
||||
let testUser: any;
|
||||
|
||||
before(() => {
|
||||
cy.apiInitSetup().then(({team, user, channel}) => {
|
||||
cy.apiInitSetup().then(({team, user}) => {
|
||||
testTeam = team;
|
||||
testUser = user;
|
||||
testChannel = channel;
|
||||
|
||||
// # Login as test user and go to town square
|
||||
cy.apiLogin(testUser);
|
||||
@@ -34,24 +32,25 @@ describe('Channel routing', () => {
|
||||
// # Create new test channel
|
||||
cy.uiCreateChannel({name: 'Test__Channel'});
|
||||
|
||||
// # Click on channel menu and press rename channel
|
||||
cy.get('#channelHeaderTitle').click();
|
||||
// # Open channel settings modal from channel header dropdown
|
||||
cy.get('#channelHeaderDropdownButton').click();
|
||||
cy.findByText('Channel Settings').click();
|
||||
|
||||
// * Channel Settings menu option should be visible
|
||||
cy.findByText('Channel Settings').should('be.visible').trigger('mouseover');
|
||||
cy.findByText('Rename Channel').click();
|
||||
// # Assert if the channel settings modal is present
|
||||
cy.get('.ChannelSettingsModal').should('be.visible');
|
||||
|
||||
// # Assert if the rename modal present
|
||||
cy.get('[aria-labelledby="renameChannelModalLabel"').should('be.visible').within(() => {
|
||||
// # type the two 26 character strings with 2 underscores between them and click on save
|
||||
cy.get('#channel_name').clear().type('uzsfmtmniifsjgesce4u7yznyh__uzsfmtmniifsjgesce5u7yznyh', {force: true}).wait(TIMEOUTS.HALF_SEC);
|
||||
cy.get('#save-button').should('be.visible').click();
|
||||
// # Click on the URL input button to edit the URL
|
||||
cy.get('.url-input-button').should('be.visible').click({force: true});
|
||||
|
||||
// # Assert the error occurred with the appropriate message
|
||||
cy.get('.input__help').should('have.class', 'error');
|
||||
cy.get('.input__help').should('have.text', 'User IDs are not allowed in channel URLs.');
|
||||
cy.findByText('Cancel').click();
|
||||
});
|
||||
// # Type the two 26 character strings with 2 underscores between them
|
||||
cy.get('.url-input-container input').clear().type('uzsfmtmniifsjgesce4u7yznyh__uzsfmtmniifsjgesce5u7yznyh', {force: true}).wait(TIMEOUTS.HALF_SEC);
|
||||
|
||||
// # Assert the error occurred with the appropriate message
|
||||
cy.get('.SaveChangesPanel').should('contain', 'There are errors in the form above');
|
||||
cy.get('.url-input-error').should('contain', 'User IDs are not allowed in channel URLs.');
|
||||
|
||||
// # Close the modal
|
||||
cy.get('.GenericModal .modal-header button[aria-label="Close"]').click();
|
||||
});
|
||||
|
||||
it('MM-T884_2 Creating new channel validates against two user IDs being used as channel name', () => {
|
||||
@@ -97,42 +96,34 @@ describe('Channel routing', () => {
|
||||
it('MM-T883 Channel URL validation for spaces between characters', () => {
|
||||
const firstWord = getRandomId(26);
|
||||
const secondWord = getRandomId(26);
|
||||
const channelName = 'test-channel-' + getRandomId(8);
|
||||
|
||||
// # In a test channel, click the "v" to the right of the channel name in the header
|
||||
cy.findByText(`${testChannel.display_name}`).click();
|
||||
cy.get('#channelHeaderTitle').click();
|
||||
// # Create a new test channel and navigate to it
|
||||
cy.apiCreateChannel(testTeam.id, channelName, 'Test Channel for URL Validation').then(({channel}) => {
|
||||
cy.apiAddUserToChannel(channel.id, testUser.id);
|
||||
cy.visit(`/${testTeam.name}/channels/${channel.name}`);
|
||||
});
|
||||
|
||||
// * Channel Settings menu option should be visible
|
||||
cy.findByText('Channel Settings').should('be.visible').trigger('mouseover');
|
||||
|
||||
// # Select "Rename Channel"
|
||||
cy.findByText('Rename Channel').click();
|
||||
// # Open channel settings modal from channel header dropdown
|
||||
cy.get('#channelHeaderDropdownButton').click();
|
||||
cy.findByText('Channel Settings').click();
|
||||
|
||||
// # Change the channel name to {26 alphanumeric characters}[insert 2 spaces]{26 alphanumeric characters}
|
||||
// i.e. a total of 54 characters separated by 2 spaces
|
||||
cy.get('#display_name').clear().type(`${firstWord}${Cypress._.repeat(' ', 2)}${secondWord}`);
|
||||
cy.get('#input_channel-settings-name').clear().type(`${firstWord}${Cypress._.repeat(' ', 2)}${secondWord}`);
|
||||
|
||||
// # Hit Save
|
||||
cy.findByText('Save').click();
|
||||
// # Save changes
|
||||
cy.get('[data-testid="SaveChangesPanel__save-btn"]').click();
|
||||
|
||||
// * Verify changes are saved
|
||||
cy.get('.SaveChangesPanel').should('contain', 'Settings saved');
|
||||
|
||||
// # Close the modal
|
||||
cy.get('.GenericModal .modal-header button[aria-label="Close"]').click();
|
||||
|
||||
// * The channel name should be updated to the characters you typed with only 1 space between the characters (extra spaces are trimmed)
|
||||
cy.get('#channelHeaderTitle').contains(`${firstWord} ${secondWord}`);
|
||||
|
||||
// # In a test channel, click the "v" to the right of the channel name in the header
|
||||
cy.get('#channelHeaderTitle').click();
|
||||
|
||||
// * Channel Settings menu option should be visible
|
||||
cy.findByText('Channel Settings').should('be.visible').trigger('mouseover');
|
||||
|
||||
// # Select "Rename Channel"
|
||||
cy.findByText('Rename Channel').click();
|
||||
|
||||
// # Change the URL to {26 alphanumeric characters}--{26 alphanumeric characters}
|
||||
cy.get('#channel_name').clear().type(`${firstWord}${Cypress._.repeat('-', 2)}${secondWord}`);
|
||||
|
||||
// # Hit Save
|
||||
cy.findByText('Save').click();
|
||||
|
||||
// * The channel URL should be updated to the characters you typed, separated by 2 dashes
|
||||
cy.url().should('equal', `${Cypress.config('baseUrl')}/${testTeam.name}/channels/${firstWord}${Cypress._.repeat('-', 2)}${secondWord}`);
|
||||
});
|
||||
|
||||
@@ -202,22 +202,33 @@ describe('Team Permissions', () => {
|
||||
// # Visit the `Off-Topic` channel in the new team
|
||||
cy.visit(`/${team.name}/channels/off-topic`);
|
||||
|
||||
// # Open channel header menu
|
||||
cy.uiOpenChannelMenu().wait(TIMEOUTS.HALF_SEC);
|
||||
// # Open channel header dropdown
|
||||
cy.get('#channelHeaderDropdownButton').click();
|
||||
|
||||
// * Verify dropdown opens
|
||||
cy.get('#channelHeaderDropdownMenu').should('be.visible');
|
||||
cy.findByText('Channel Settings').should('be.visible').trigger('mouseover');
|
||||
// * Verify Channel Settings option is visible
|
||||
cy.findByText('Channel Settings').should('be.visible');
|
||||
|
||||
// * Verify `Edit Channel Header` menu item is visible
|
||||
cy.get('#channelEditHeader').should('be.visible');
|
||||
// # Click on Channel Settings
|
||||
cy.findByText('Channel Settings').click();
|
||||
|
||||
// * Verify `Edit Channel Purpose` menu item is visible
|
||||
cy.get('#channelEditPurpose').should('be.visible');
|
||||
// * Verify Channel Settings modal opens
|
||||
cy.get('.ChannelSettingsModal').should('be.visible');
|
||||
|
||||
// * Verify `Rename Channel` menu item is visible
|
||||
cy.get('#channelRename').should('be.visible');
|
||||
// * Verify user can edit channel name
|
||||
cy.get('#input_channel-settings-name').should('be.visible').and('not.be.disabled');
|
||||
|
||||
// * Verify user can edit channel URL
|
||||
cy.get('.url-input-button').should('be.visible').and('not.be.disabled');
|
||||
|
||||
// * Verify user can edit channel purpose
|
||||
cy.get('#channel_settings_purpose_textbox').should('be.visible').and('not.be.disabled');
|
||||
|
||||
// * Verify user can edit channel header
|
||||
cy.get('#channel_settings_header_textbox').should('be.visible').and('not.be.disabled');
|
||||
|
||||
// # Close the modal
|
||||
cy.get('.GenericModal .modal-header button[aria-label="Close"]').click();
|
||||
cy.get('.ChannelSettingsModal').should('not.exist');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -114,13 +114,15 @@ describe('Keyboard shortcut CTRL/CMD+Shift+\\ for adding reaction to last messag
|
||||
cy.uiOpenProfileModal('Profile Settings');
|
||||
verifyEmojiPickerNotOpen();
|
||||
|
||||
['Edit Channel Header', 'Rename Channel'].forEach((modal) => {
|
||||
// # Click on the channel name in the channel header to open the channel menu options
|
||||
cy.get('#channelHeaderTitle').click();
|
||||
// # Open Channel Settings Modal
|
||||
cy.uiOpenChannelMenu('Channel Settings');
|
||||
verifyEmojiPickerNotOpen();
|
||||
|
||||
// # Select the "Edit Channel Header" option from the dropdown
|
||||
cy.findByText('Channel Settings').should('be.visible').trigger('mouseover');
|
||||
cy.findByText(modal).click();
|
||||
['Channel Purpose', 'Channel Header'].forEach((modal) => {
|
||||
// # Open channel menu and click View Info
|
||||
cy.uiOpenChannelMenu('View Info');
|
||||
|
||||
cy.findByText(modal).parent().findAllByRole('button', {name: 'Edit'}).click();
|
||||
|
||||
doReactToLastMessageShortcut();
|
||||
|
||||
@@ -129,6 +131,9 @@ describe('Keyboard shortcut CTRL/CMD+Shift+\\ for adding reaction to last messag
|
||||
|
||||
// # Close the modal
|
||||
pressEscapeKey();
|
||||
|
||||
// # Close channel info
|
||||
cy.uiOpenChannelMenu('Close Info');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -53,7 +53,7 @@ describe('Onboarding', () => {
|
||||
// # Enable any user with an account on the server to join the team
|
||||
cy.get('input.mm-modal-generic-section-item__input-checkbox').last().should('be.visible').click();
|
||||
|
||||
cy.findAllByTestId('mm-save-changes-panel__save-btn').should('be.visible').click();
|
||||
cy.get('[data-testid="SaveChangesPanel__save-btn"]').should('be.visible').click();
|
||||
|
||||
// # Close the modal
|
||||
cy.findByLabelText('Close').should('be.visible').click();
|
||||
|
||||
@@ -102,11 +102,19 @@ describe('channels > run', {testIsolation: true}, () => {
|
||||
cy.startPlaybookRunWithSlashCommand('Playbook', playbookRunName);
|
||||
cy.verifyPlaybookRunActive(testTeam.id, playbookRunName);
|
||||
|
||||
// # Open the channel header
|
||||
cy.get('#channelHeaderTitle').click();
|
||||
cy.findByText('Channel Settings').should('be.visible').trigger('mouseover');
|
||||
// # Open channel header dropdown
|
||||
cy.get('#channelHeaderDropdownButton').click();
|
||||
|
||||
// # Click on Channel Settings
|
||||
cy.findByText('Channel Settings').should('be.visible').click();
|
||||
|
||||
// * Verify Channel Settings modal opens
|
||||
cy.get('.ChannelSettingsModal').should('be.visible');
|
||||
|
||||
// * Verify the ability to edit the channel header exists
|
||||
cy.get('#channelEditHeader').should('exist');
|
||||
cy.get('#channel_settings_header_textbox').should('be.visible').and('not.be.disabled');
|
||||
|
||||
// # Close the modal
|
||||
cy.get('.GenericModal .modal-header button[aria-label="Close"]').click();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -462,20 +462,35 @@ function getCurrentChannelId(): ChainableT<string> {
|
||||
Cypress.Commands.add('getCurrentChannelId', getCurrentChannelId);
|
||||
|
||||
function updateChannelHeader(text: string) {
|
||||
cy.get('#channelHeaderTitle').
|
||||
should('be.visible').
|
||||
click();
|
||||
cy.get('#channelHeaderDropdownMenu').
|
||||
should('be.visible');
|
||||
// # Open channel header dropdown
|
||||
cy.get('#channelHeaderDropdownButton').click();
|
||||
|
||||
// * Channel Settings menu option should be visible
|
||||
cy.findByText('Channel Settings').should('be.visible').trigger('mouseover');
|
||||
cy.findByText('Edit Channel Header').click();
|
||||
cy.get('#edit_textbox').
|
||||
// # Click on Channel Settings
|
||||
cy.findByText('Channel Settings').should('be.visible').click();
|
||||
|
||||
// * Verify Channel Settings modal opens
|
||||
cy.get('.ChannelSettingsModal').should('be.visible');
|
||||
|
||||
// # Edit channel header in the modal
|
||||
cy.get('#channel_settings_header_textbox').
|
||||
should('be.visible').
|
||||
clear().
|
||||
type(text).
|
||||
type('{enter}').
|
||||
wait(TIMEOUTS.HALF_SEC);
|
||||
type(text);
|
||||
|
||||
// # Save changes
|
||||
cy.get('[data-testid="SaveChangesPanel__save-btn"]').click();
|
||||
|
||||
// * Verify changes are saved
|
||||
cy.get('.SaveChangesPanel').should('contain', 'Settings saved');
|
||||
|
||||
// # Close the modal
|
||||
cy.get('.GenericModal .modal-header button[aria-label="Close"]').click();
|
||||
|
||||
// * Verify modal is closed
|
||||
cy.get('.ChannelSettingsModal').should('not.exist');
|
||||
|
||||
// Wait for UI to stabilize
|
||||
cy.wait(TIMEOUTS.HALF_SEC);
|
||||
}
|
||||
|
||||
Cypress.Commands.add('updateChannelHeader', updateChannelHeader);
|
||||
|
||||
Ссылка в новой задаче
Block a user