diff --git a/docs/site/static/images/anyone-can-join-a-team.png b/docs/site/static/images/anyone-can-join-a-team.png index d1ab30707dd..f1e789cb876 100644 Binary files a/docs/site/static/images/anyone-can-join-a-team.png and b/docs/site/static/images/anyone-can-join-a-team.png differ diff --git a/docs/site/static/images/set-a-channel-to-public-or-private.png b/docs/site/static/images/set-a-channel-to-public-or-private.png index 477311d2acc..e49721ed9e7 100644 Binary files a/docs/site/static/images/set-a-channel-to-public-or-private.png and b/docs/site/static/images/set-a-channel-to-public-or-private.png differ diff --git a/docs/site/static/images/specific-email-domains-can-join-a-team.png b/docs/site/static/images/specific-email-domains-can-join-a-team.png index ae4755982d0..f85a93e2083 100644 Binary files a/docs/site/static/images/specific-email-domains-can-join-a-team.png and b/docs/site/static/images/specific-email-domains-can-join-a-team.png differ diff --git a/docs/site/static/images/sync-group-members-in-a-channel.png b/docs/site/static/images/sync-group-members-in-a-channel.png index 72c00ea852c..24b020842c3 100644 Binary files a/docs/site/static/images/sync-group-members-in-a-channel.png and b/docs/site/static/images/sync-group-members-in-a-channel.png differ diff --git a/docs/site/static/images/sync-group-members-in-a-team.png b/docs/site/static/images/sync-group-members-in-a-team.png index 341220f21dd..efaa4d31770 100644 Binary files a/docs/site/static/images/sync-group-members-in-a-team.png and b/docs/site/static/images/sync-group-members-in-a-team.png differ diff --git a/e2e-tests/cypress/tests/integration/channels/enterprise/group_mentions/helpers.ts b/e2e-tests/cypress/tests/integration/channels/enterprise/group_mentions/helpers.ts index bf7bcd7cfec..28fd39405d4 100644 --- a/e2e-tests/cypress/tests/integration/channels/enterprise/group_mentions/helpers.ts +++ b/e2e-tests/cypress/tests/integration/channels/enterprise/group_mentions/helpers.ts @@ -14,12 +14,10 @@ export function enableGroupMention(groupName: string, groupID: string, userEmail } cy.get('#group_profile').scrollIntoView().wait(TIMEOUTS.TWO_SEC); - // # Click the allow reference button - cy.findByTestId('allowReferenceSwitch').then((el) => { - const button = el.find('button'); - const classAttribute = button[0]?.getAttribute('class') ?? ''; - if (!classAttribute.includes('active')) { - button[0].click(); + // # Enable group mentions if not already on + cy.findByTestId('allowReferenceSwitch-button').then(($input) => { + if (!$input.prop('checked')) { + cy.wrap($input).click({force: true}); } }); diff --git a/e2e-tests/cypress/tests/integration/channels/enterprise/ldap/ldap_group_sync_spec.ts b/e2e-tests/cypress/tests/integration/channels/enterprise/ldap/ldap_group_sync_spec.ts index b55a36625f6..73d075606e2 100644 --- a/e2e-tests/cypress/tests/integration/channels/enterprise/ldap/ldap_group_sync_spec.ts +++ b/e2e-tests/cypress/tests/integration/channels/enterprise/ldap/ldap_group_sync_spec.ts @@ -131,9 +131,8 @@ context('ldap', () => { cy.wait(TIMEOUTS.TWO_SEC); // # Turn on sync group members - cy.findByTestId('syncGroupSwitch'). + cy.findByTestId('syncGroupSwitch-button'). scrollIntoView(). - findByRole('button'). click({force: true}); // # Add board group to team @@ -211,17 +210,21 @@ context('ldap', () => { cy.wait(TIMEOUTS.TWO_SEC); // Make it private and then cancel - cy.findByTestId('allow-all-toggle').click(); + cy.findByTestId('allow-all-toggle-private').click({force: true}); cy.get('#cancelButtonSettings').click(); cy.get('#confirmModalButton').click(); cy.visit(`/admin_console/user_management/channels/${testChannel.id}`); cy.get('.admin-console__header', {timeout: TIMEOUTS.ONE_MIN}).should('be.visible').and('have.text', 'Channel Configuration'); // * Ensure it still public - cy.findByTestId('allow-all-toggle').should('has.have.text', 'Public'); + cy.findByTestId('allow-all-toggle').within(() => { + cy.findByText('Public channel or private channel').should('be.visible'); + }); + cy.findByTestId('allow-all-toggle-public').should('have.attr', 'aria-pressed', 'true'); + cy.findByTestId('allow-all-toggle-private').should('have.attr', 'aria-pressed', 'false'); // Make it private and save - cy.findByTestId('allow-all-toggle').click(); + cy.findByTestId('allow-all-toggle-private').click({force: true}); cy.get('#saveSetting').should('be.enabled').click(); cy.get('#confirmModalButton').click(); @@ -230,7 +233,11 @@ context('ldap', () => { cy.get('.admin-console__header', {timeout: TIMEOUTS.ONE_MIN}).should('be.visible').and('have.text', 'Channel Configuration'); // * Ensure it is Private - cy.findByTestId('allow-all-toggle').should('has.have.text', 'Private'); + cy.findByTestId('allow-all-toggle').within(() => { + cy.findByText('Public channel or private channel').should('be.visible'); + }); + cy.findByTestId('allow-all-toggle-public').should('have.attr', 'aria-pressed', 'false'); + cy.findByTestId('allow-all-toggle-private').should('have.attr', 'aria-pressed', 'true'); // # Go to team page to look for this channel in public channel directory cy.visit(`/${testTeam.name}`); @@ -256,7 +263,7 @@ context('ldap', () => { cy.get('.admin-console__header', {timeout: TIMEOUTS.ONE_MIN}).should('be.visible').and('have.text', 'Channel Configuration'); // Make it public and then cancel - cy.findByTestId('allow-all-toggle').click(); + cy.findByTestId('allow-all-toggle-public').click({force: true}); cy.get('#cancelButtonSettings').click(); cy.get('#confirmModalButton').click(); cy.get('.admin-console__header', {timeout: TIMEOUTS.ONE_MIN}).should('be.visible').and('have.text', 'Mattermost Channels'); @@ -268,7 +275,11 @@ context('ldap', () => { // Make it public and save // * Ensure it still showing the channel as private - cy.findByTestId('allow-all-toggle').should('has.have.text', 'Private').click(); + cy.findByTestId('allow-all-toggle').within(() => { + cy.findByText('Public channel or private channel').should('be.visible'); + }); + cy.findByTestId('allow-all-toggle-private').should('have.attr', 'aria-pressed', 'true'); + cy.findByTestId('allow-all-toggle-public').click({force: true}); cy.get('#saveSetting').should('be.enabled').click(); cy.get('#confirmModalButton').click(); cy.get('.admin-console__header', {timeout: TIMEOUTS.ONE_MIN}).should('be.visible').and('have.text', 'Mattermost Channels'); @@ -277,8 +288,12 @@ context('ldap', () => { cy.visit(`/admin_console/user_management/channels/${privateChannel.id}`); cy.get('.admin-console__header', {timeout: TIMEOUTS.ONE_MIN}).should('be.visible').and('have.text', 'Channel Configuration'); - // * Ensure it still showing the channel as private - cy.findByTestId('allow-all-toggle').should('has.have.text', 'Public'); + // * Ensure it is showing the channel as public + cy.findByTestId('allow-all-toggle').within(() => { + cy.findByText('Public channel or private channel').should('be.visible'); + }); + cy.findByTestId('allow-all-toggle-public').should('have.attr', 'aria-pressed', 'true'); + cy.findByTestId('allow-all-toggle-private').should('have.attr', 'aria-pressed', 'false'); // # Ensure the last message in the message says that it was converted to a public channel cy.visit(`/${testTeam.name}/channels/${privateChannel.name}`); @@ -303,7 +318,8 @@ context('ldap', () => { cy.get('.admin-console__header', {timeout: TIMEOUTS.ONE_MIN}).should('be.visible').and('have.text', 'Channel Configuration'); // * Ensure the toggle to private/public is disabled - cy.findByTestId('allow-all-toggle-button').should('be.disabled'); + cy.findByTestId('allow-all-toggle-public').should('be.disabled'); + cy.findByTestId('allow-all-toggle-private').should('be.disabled'); }); }); diff --git a/e2e-tests/cypress/tests/integration/channels/enterprise/ldap/ldap_guest_spec.ts b/e2e-tests/cypress/tests/integration/channels/enterprise/ldap/ldap_guest_spec.ts index 616b223e6c9..8d4602f0d77 100644 --- a/e2e-tests/cypress/tests/integration/channels/enterprise/ldap/ldap_guest_spec.ts +++ b/e2e-tests/cypress/tests/integration/channels/enterprise/ldap/ldap_guest_spec.ts @@ -200,7 +200,7 @@ describe('LDAP guest', () => { cy.get('.admin-console__header', {timeout: TIMEOUTS.ONE_MIN}).should('be.visible').and('have.text', 'Team Configuration'); // # Turn on sync group members - cy.findByTestId('syncGroupSwitch').scrollIntoView().click(); + cy.findByTestId('syncGroupSwitch-button').scrollIntoView().click({force: true}); // # Add board group to team cy.get('#addGroupsToTeamToggle').scrollIntoView().click(); diff --git a/e2e-tests/cypress/tests/integration/channels/enterprise/ldap_group/channel_modes_spec.ts b/e2e-tests/cypress/tests/integration/channels/enterprise/ldap_group/channel_modes_spec.ts index 68595c56a7a..dfbd2ea44e2 100644 --- a/e2e-tests/cypress/tests/integration/channels/enterprise/ldap_group/channel_modes_spec.ts +++ b/e2e-tests/cypress/tests/integration/channels/enterprise/ldap_group/channel_modes_spec.ts @@ -35,7 +35,7 @@ describe('LDAP Group Sync - Test channel public/private toggle', () => { assert(channel.type === 'O'); cy.visit(`/admin_console/user_management/channels/${channel.id}`); cy.get('#channel_profile').contains(channel.display_name); - cy.get('#channel_manage .group-teams-and-channels--body').find('button').eq(1).click(); + cy.findByTestId('allow-all-toggle-private').click({force: true}); cy.get('#saveSetting').click(); cy.get('#confirmModalButton').click(); return cy.apiGetChannel(channel.id); @@ -43,7 +43,7 @@ describe('LDAP Group Sync - Test channel public/private toggle', () => { assert(channel.type === 'P'); cy.visit(`/admin_console/user_management/channels/${channel.id}`); cy.get('#channel_profile').contains(channel.display_name); - cy.get('#channel_manage .group-teams-and-channels--body').find('button').eq(1).click(); + cy.findByTestId('allow-all-toggle-public').click({force: true}); cy.get('#saveSetting').click(); cy.get('#confirmModalButton').click(); return cy.apiGetChannel(channel.id); @@ -57,13 +57,20 @@ describe('LDAP Group Sync - Test channel public/private toggle', () => { assert(channel.type === 'O'); cy.visit(`/admin_console/user_management/channels/${channel.id}`); cy.get('#channel_profile').contains(channel.display_name); - cy.get('#channel_manage .group-teams-and-channels--body').find('button').eq(0).click(); - cy.get('#channel_manage .group-teams-and-channels--body').find('button').eq(0).click(); - cy.get('#channel_manage .group-teams-and-channels--body').find('button').eq(1).contains('Public'); - cy.get('#channel_manage .group-teams-and-channels--body').find('button').eq(1).click(); - cy.get('#channel_manage .group-teams-and-channels--body').find('button').eq(0).click(); - cy.get('#channel_manage .group-teams-and-channels--body').find('button').eq(0).click(); - cy.get('#channel_manage .group-teams-and-channels--body').find('button').eq(1).contains('Private'); + cy.findByTestId('syncGroupSwitch-button').click({force: true}); + cy.findByTestId('syncGroupSwitch-button').click({force: true}); + cy.findByTestId('allow-all-toggle').within(() => { + cy.findByText('Public channel or private channel').should('be.visible'); + }); + cy.findByTestId('allow-all-toggle-public').should('have.attr', 'aria-pressed', 'true'); + cy.findByTestId('allow-all-toggle-private').click({force: true}); + cy.findByTestId('syncGroupSwitch-button').click({force: true}); + cy.findByTestId('syncGroupSwitch-button').click({force: true}); + cy.findByTestId('allow-all-toggle').within(() => { + cy.findByText('Public channel or private channel').should('be.visible'); + }); + cy.findByTestId('allow-all-toggle-public').should('have.attr', 'aria-pressed', 'false'); + cy.findByTestId('allow-all-toggle-private').should('have.attr', 'aria-pressed', 'true'); }); }); @@ -73,13 +80,14 @@ describe('LDAP Group Sync - Test channel public/private toggle', () => { cy.visit(`/admin_console/user_management/channels/${id}`); cy.get('#channel_profile').contains('Town Square'); cy.get('#channel_manage').scrollIntoView().should('be.visible').within(() => { - cy.get('.line-switch').first().within(() => { + cy.findByTestId('syncGroupSwitch').within(() => { cy.findByText('Sync Group Members').should('be.visible'); cy.findByTestId('syncGroupSwitch-button').should('be.disabled'); }); - cy.get('.line-switch').last().within(() => { + cy.findByTestId('allow-all-toggle').within(() => { cy.findByText('Public channel or private channel').should('be.visible'); - cy.findByTestId('allow-all-toggle-button').should('be.disabled'); + cy.findByTestId('allow-all-toggle-public').should('be.disabled'); + cy.findByTestId('allow-all-toggle-private').should('be.disabled'); }); }); }); diff --git a/e2e-tests/cypress/tests/integration/channels/enterprise/ldap_group/group_mentions_spec.ts b/e2e-tests/cypress/tests/integration/channels/enterprise/ldap_group/group_mentions_spec.ts index 14680b379d7..af7c9760226 100644 --- a/e2e-tests/cypress/tests/integration/channels/enterprise/ldap_group/group_mentions_spec.ts +++ b/e2e-tests/cypress/tests/integration/channels/enterprise/ldap_group/group_mentions_spec.ts @@ -187,33 +187,29 @@ describe('System Console', () => { // # Login as sysadmin and navigate to board group page navigateToGroup(groupID); - // # Click the allow reference button - cy.findByTestId('allowReferenceSwitch').then((el) => { - el.find('button').click(); + // # Enable group mentions + cy.findByTestId('allowReferenceSwitch-button').click({force: true}); - // # Give the group a custom name different from its DisplayName attribute - cy.get('#groupMention').find('input').clear().type(groupName); + // # Give the group a custom name different from its DisplayName attribute + cy.get('#groupMention').find('input').clear().type(groupName); - // # Click save button - saveConfig(); + // # Click save button + saveConfig(); - // * Assert that the group mention works as expected since the group is enabled and sysadmin always has permission to mention - assertGroupMentionEnabled(groupName); + // * Assert that the group mention works as expected since the group is enabled and sysadmin always has permission to mention + assertGroupMentionEnabled(groupName); - // # Login as sysadmin and navigate to board group page - navigateToGroup(groupID); + // # Login as sysadmin and navigate to board group page + navigateToGroup(groupID); - // # Click the allow reference button - cy.findByTestId('allowReferenceSwitch').then((elSwitch) => { - elSwitch.find('button').click(); + // # Disable group mentions + cy.findByTestId('allowReferenceSwitch-button').click({force: true}); - // # Click save button - saveConfig(); + // # Click save button + saveConfig(); - // * Assert that the group mention does not do anything since the group is disabled even though sysadmin has permission to mention - assertGroupMentionDisabled(groupName); - }); - }); + // * Assert that the group mention does not do anything since the group is disabled even though sysadmin has permission to mention + assertGroupMentionDisabled(groupName); }); it('MM-23937 - Can restrict users from mentioning a group through the use_group_mentions permission', () => { diff --git a/e2e-tests/cypress/tests/integration/channels/enterprise/system_console/channel_members_spec.js b/e2e-tests/cypress/tests/integration/channels/enterprise/system_console/channel_members_spec.js index 8e103145f06..8308edb56a5 100644 --- a/e2e-tests/cypress/tests/integration/channels/enterprise/system_console/channel_members_spec.js +++ b/e2e-tests/cypress/tests/integration/channels/enterprise/system_console/channel_members_spec.js @@ -49,9 +49,8 @@ describe('Channel members test', () => { cy.get('#channelMembers').scrollIntoView().should('be.visible'); // # Click the sync group members switch - cy.findByTestId('syncGroupSwitch'). + cy.findByTestId('syncGroupSwitch-button'). scrollIntoView(). - findByRole('button'). click({force: true}); // * Assert that the members block is no longer visible diff --git a/e2e-tests/cypress/tests/integration/channels/enterprise/system_console/channel_moderation/higher_scoped_scheme_spec.ts b/e2e-tests/cypress/tests/integration/channels/enterprise/system_console/channel_moderation/higher_scoped_scheme_spec.ts index 84a15efc734..7ee6a3b2de4 100644 --- a/e2e-tests/cypress/tests/integration/channels/enterprise/system_console/channel_moderation/higher_scoped_scheme_spec.ts +++ b/e2e-tests/cypress/tests/integration/channels/enterprise/system_console/channel_moderation/higher_scoped_scheme_spec.ts @@ -182,27 +182,39 @@ describe('MM-23102 - Channel Moderation - Higher Scoped Scheme', () => { // # Visit Channel page and Search for the channel. // * Ensure message is disabled and manage members for members is disabled visitChannelConfigPage(testChannel); - cy.findByTestId('allow-all-toggle').should('has.have.text', 'Public'); + cy.findByTestId('allow-all-toggle').within(() => { + cy.findByText('Public channel or private channel').should('be.visible'); + }); + cy.findByTestId('allow-all-toggle-public').should('have.attr', 'aria-pressed', 'true'); + cy.findByTestId('allow-all-toggle-private').should('have.attr', 'aria-pressed', 'false'); cy.findByTestId('admin-channel_settings-channel_moderation-manageMembers-disabledMember'). should('have.text', `Manage members for members are disabled in ${teamOverrideSchemeName} Team Scheme.`); cy.findByTestId(checkboxesTitleToIdMap.MANAGE_MEMBERS_MEMBERS).should('be.disabled'); // # Turn channel into a private channel - cy.findByTestId('allow-all-toggle').click(); + cy.findByTestId('allow-all-toggle-private').click({force: true}); saveConfigForChannel(testChannel.display_name, true); // * Ensure it is private and no error message is shown and that manage members for members is not disabled - cy.findByTestId('allow-all-toggle').should('has.have.text', 'Private'); + cy.findByTestId('allow-all-toggle').within(() => { + cy.findByText('Public channel or private channel').should('be.visible'); + }); + cy.findByTestId('allow-all-toggle-public').should('have.attr', 'aria-pressed', 'false'); + cy.findByTestId('allow-all-toggle-private').should('have.attr', 'aria-pressed', 'true'); cy.findByTestId('admin-channel_settings-channel_moderation-manageMembers-disabledMember'). should('not.have.text', `Manage members for members are disabled in ${teamOverrideSchemeName} Team Scheme.`); cy.findByTestId(checkboxesTitleToIdMap.MANAGE_MEMBERS_MEMBERS).should('not.be.disabled'); // # Turn channel back to public channel - cy.findByTestId('allow-all-toggle').click(); + cy.findByTestId('allow-all-toggle-public').click({force: true}); saveConfigForChannel(testChannel.display_name, true); // * ensure it got reverted back to a Public channel - cy.findByTestId('allow-all-toggle').should('has.have.text', 'Public'); + cy.findByTestId('allow-all-toggle').within(() => { + cy.findByText('Public channel or private channel').should('be.visible'); + }); + cy.findByTestId('allow-all-toggle-public').should('have.attr', 'aria-pressed', 'true'); + cy.findByTestId('allow-all-toggle-private').should('have.attr', 'aria-pressed', 'false'); }); it('MM-T1579 Manage Members removed for Private Channels / Permissions inherited when channel converted from Public to Private', () => { @@ -220,27 +232,39 @@ describe('MM-23102 - Channel Moderation - Higher Scoped Scheme', () => { visitChannelConfigPage(testChannel); // * Ensure that error message is not displayed and manage members for members is not disabled - cy.findByTestId('allow-all-toggle').should('has.have.text', 'Public'); + cy.findByTestId('allow-all-toggle').within(() => { + cy.findByText('Public channel or private channel').should('be.visible'); + }); + cy.findByTestId('allow-all-toggle-public').should('have.attr', 'aria-pressed', 'true'); + cy.findByTestId('allow-all-toggle-private').should('have.attr', 'aria-pressed', 'false'); cy.findByTestId('admin-channel_settings-channel_moderation-manageMembers-disabledMember'). should('not.have.text', `Manage members for members are disabled in ${teamOverrideSchemeName} Team Scheme.`); cy.findByTestId(checkboxesTitleToIdMap.MANAGE_MEMBERS_MEMBERS).should('not.be.disabled'); // # Turn it into a private channel - cy.findByTestId('allow-all-toggle').click(); + cy.findByTestId('allow-all-toggle-private').click({force: true}); saveConfigForChannel(testChannel.display_name, true); // * Ensure it is a private channel and that a message is disabled and also manage members for members is disabled - cy.findByTestId('allow-all-toggle').should('has.have.text', 'Private'); + cy.findByTestId('allow-all-toggle').within(() => { + cy.findByText('Public channel or private channel').should('be.visible'); + }); + cy.findByTestId('allow-all-toggle-public').should('have.attr', 'aria-pressed', 'false'); + cy.findByTestId('allow-all-toggle-private').should('have.attr', 'aria-pressed', 'true'); cy.findByTestId('admin-channel_settings-channel_moderation-manageMembers-disabledMember'). should('have.text', `Manage members for members are disabled in ${teamOverrideSchemeName} Team Scheme.`); cy.findByTestId(checkboxesTitleToIdMap.MANAGE_MEMBERS_MEMBERS).should('be.disabled'); // # Turn channel back to public channel - cy.findByTestId('allow-all-toggle').click(); + cy.findByTestId('allow-all-toggle-public').click({force: true}); saveConfigForChannel(testChannel.display_name, true); // * Ensure it got reset back to a public channel - cy.findByTestId('allow-all-toggle').should('has.have.text', 'Public'); + cy.findByTestId('allow-all-toggle').within(() => { + cy.findByText('Public channel or private channel').should('be.visible'); + }); + cy.findByTestId('allow-all-toggle-public').should('have.attr', 'aria-pressed', 'true'); + cy.findByTestId('allow-all-toggle-private').should('have.attr', 'aria-pressed', 'false'); }); it('MM-T1581 Check if user is allowed to Edit or Delete their own posts on a Read-Only channel', () => { diff --git a/e2e-tests/cypress/tests/integration/channels/enterprise/system_console/team_members_spec.js b/e2e-tests/cypress/tests/integration/channels/enterprise/system_console/team_members_spec.js index d7d5c7ab0ca..33df5f0ab9e 100644 --- a/e2e-tests/cypress/tests/integration/channels/enterprise/system_console/team_members_spec.js +++ b/e2e-tests/cypress/tests/integration/channels/enterprise/system_console/team_members_spec.js @@ -57,9 +57,8 @@ describe('Team members test', () => { cy.get('#teamMembers').scrollIntoView().should('be.visible'); // # Click the sync group members switch - cy.findByTestId('syncGroupSwitch'). + cy.findByTestId('syncGroupSwitch-button'). scrollIntoView(). - findByRole('button'). click({force: true}); // * Assert that the members block is no longer visible diff --git a/e2e-tests/cypress/tests/integration/channels/plugins/plugin_install_spec.js b/e2e-tests/cypress/tests/integration/channels/plugins/plugin_install_spec.js index dbc5accc051..63c441da4bc 100644 --- a/e2e-tests/cypress/tests/integration/channels/plugins/plugin_install_spec.js +++ b/e2e-tests/cypress/tests/integration/channels/plugins/plugin_install_spec.js @@ -106,7 +106,7 @@ describe('Plugins Management', () => { // * Verify the enable toggle reflects the running state cy.findByTestId('plugin-metadata-panel', {timeout: TIMEOUTS.ONE_MIN}).should('be.visible'); cy.findByTestId(pluginEnableToggleTestId(demoPlugin.id)). - should('have.attr', 'aria-pressed', 'true'). + should('have.attr', 'aria-checked', 'true'). and('have.attr', 'aria-label', 'Disable plugin'); // # Disable the plugin from the settings page @@ -115,7 +115,7 @@ describe('Plugins Management', () => { // * Verify it disables in place, without needing Save cy.findByTestId('plugin-metadata-status').should('contain.text', 'Not running'); cy.findByTestId(pluginEnableToggleTestId(demoPlugin.id)). - should('have.attr', 'aria-pressed', 'false'). + should('have.attr', 'aria-checked', 'false'). and('have.attr', 'aria-label', 'Enable plugin'); // # Re-enable the plugin from the settings page @@ -151,7 +151,7 @@ describe('Plugins Management', () => { // * Verify the action is blocked with the expected warning, and the plugin stays enabled cy.findByText('Please save unsaved changes first').should('be.visible'); - cy.findByTestId(pluginEnableToggleTestId(demoPlugin.id)).should('have.attr', 'aria-pressed', 'true'); + cy.findByTestId(pluginEnableToggleTestId(demoPlugin.id)).should('have.attr', 'aria-checked', 'true'); // # Attempt to uninstall the plugin while unsaved changes exist cy.get(`#plugin-actions-menu-button-${demoPlugin.id}`).click(); diff --git a/e2e-tests/playwright/lib/src/ui/components/channels/channel_settings/configuration_settings.ts b/e2e-tests/playwright/lib/src/ui/components/channels/channel_settings/configuration_settings.ts index be32638b9ea..1d09a566df0 100644 --- a/e2e-tests/playwright/lib/src/ui/components/channels/channel_settings/configuration_settings.ts +++ b/e2e-tests/playwright/lib/src/ui/components/channels/channel_settings/configuration_settings.ts @@ -61,33 +61,29 @@ export default class ConfigurationSettings { async enableChannelBanner() { const toggleButton = this.container.getByTestId('channelBannerToggle-button'); - const classes = await toggleButton.getAttribute('class'); - if (!classes?.includes('active')) { - await toggleButton.click(); + if (!(await toggleButton.isChecked())) { + await toggleButton.check({force: true}); } } async disableChannelBanner() { const toggleButton = this.container.getByTestId('channelBannerToggle-button'); - const classes = await toggleButton.getAttribute('class'); - if (classes?.includes('active')) { - await toggleButton.click(); + if (await toggleButton.isChecked()) { + await toggleButton.uncheck({force: true}); } } async enableChannelAutotranslation() { const toggleButton = this.container.getByTestId('channelTranslationToggle-button'); - const classes = await toggleButton.getAttribute('class'); - if (!classes?.includes('active')) { - await toggleButton.click(); + if (!(await toggleButton.isChecked())) { + await toggleButton.check({force: true}); } } async disableChannelAutotranslation() { const toggleButton = this.container.getByTestId('channelTranslationToggle-button'); - const classes = await toggleButton.getAttribute('class'); - if (classes?.includes('active')) { - await toggleButton.click(); + if (await toggleButton.isChecked()) { + await toggleButton.uncheck({force: true}); } } @@ -110,17 +106,15 @@ export default class ConfigurationSettings { async enableJoinLeaveMessages() { const toggleButton = this.container.getByTestId('channelJoinLeaveMessagesToggle-button'); - const classes = await toggleButton.getAttribute('class'); - if (!classes?.includes('active')) { - await toggleButton.click(); + if (!(await toggleButton.isChecked())) { + await toggleButton.check({force: true}); } } async disableJoinLeaveMessages() { const toggleButton = this.container.getByTestId('channelJoinLeaveMessagesToggle-button'); - const classes = await toggleButton.getAttribute('class'); - if (classes?.includes('active')) { - await toggleButton.click(); + if (await toggleButton.isChecked()) { + await toggleButton.uncheck({force: true}); } } @@ -200,19 +194,15 @@ export default class ConfigurationSettings { async enableShareWithWorkspaces() { const toggle = this.shareWithWorkspacesToggle; - const ariaPressed = await toggle.getAttribute('aria-pressed'); - const classes = await toggle.getAttribute('class'); - if (ariaPressed !== 'true' && !classes?.includes('active')) { - await toggle.click(); + if (!(await toggle.isChecked())) { + await toggle.check({force: true}); } } async disableShareWithWorkspaces() { const toggle = this.shareWithWorkspacesToggle; - const ariaPressed = await toggle.getAttribute('aria-pressed'); - const classes = await toggle.getAttribute('class'); - if (ariaPressed === 'true' || classes?.includes('active')) { - await toggle.click(); + if (await toggle.isChecked()) { + await toggle.uncheck({force: true}); } } diff --git a/e2e-tests/playwright/lib/src/ui/components/system_console/sections/site_configuration/localization.ts b/e2e-tests/playwright/lib/src/ui/components/system_console/sections/site_configuration/localization.ts index d0826c443e3..d3de2ac4d54 100644 --- a/e2e-tests/playwright/lib/src/ui/components/system_console/sections/site_configuration/localization.ts +++ b/e2e-tests/playwright/lib/src/ui/components/system_console/sections/site_configuration/localization.ts @@ -29,7 +29,7 @@ export default class Localization { this.header = container.getByText('Localization', {exact: true}); this.featureDiscoveryBlock = container.getByText('Remove language barriers with auto-translation'); this.autoTranslationSection = container.getByTestId('autotranslation-section-header'); - this.autoTranslationToggle = container.getByTestId('autotranslation-section-toggle').locator('button'); + this.autoTranslationToggle = container.getByTestId('autotranslation-section-toggle').getByRole('switch'); this.providerDropdown = container.getByTestId('Providerdropdown'); this.mattermostAgentsInactiveNotice = container.getByText( 'LLMs must first be configured in the Agents plugin.', @@ -56,7 +56,7 @@ export default class Localization { async turnOnAutoTranslation() { const on = await this.isToggleOn(); if (!on) { - await this.autoTranslationToggle.click(); + await this.autoTranslationToggle.check({force: true}); } } diff --git a/e2e-tests/playwright/lib/src/ui/pages/recaps.ts b/e2e-tests/playwright/lib/src/ui/pages/recaps.ts index de9046f8c27..5107d4eada0 100644 --- a/e2e-tests/playwright/lib/src/ui/pages/recaps.ts +++ b/e2e-tests/playwright/lib/src/ui/pages/recaps.ts @@ -55,8 +55,8 @@ class CreateRecapModal { async enableRunOnce() { const runOnce = this.container.locator('#run-once-toggle'); await expect(runOnce).toBeVisible(); - if ((await runOnce.getAttribute('aria-pressed')) !== 'true') { - await runOnce.click(); + if (!(await runOnce.isChecked())) { + await runOnce.check({force: true}); } } @@ -236,7 +236,7 @@ class ScheduledRecapItem { ) { this.menuButton = container.getByRole('button', {name: /Options for /}); this.schedulePattern = container.locator('.schedule-pattern'); - this.toggleButton = container.locator('.scheduled-recap-toggle button'); + this.toggleButton = container.locator('.scheduled-recap-toggle').getByRole('switch'); } async toBeVisible() { @@ -253,24 +253,27 @@ class ScheduledRecapItem { } async expectActive() { - await expect(this.toggleButton).toHaveAttribute('aria-pressed', 'true'); + await expect(this.toggleButton).toBeChecked(); await expect(this.toggleButton).toHaveAccessibleName('Active - click to pause'); } async expectPaused() { - await expect(this.toggleButton).toHaveAttribute('aria-pressed', 'false'); + await expect(this.toggleButton).not.toBeChecked(); await expect(this.toggleButton).toHaveAccessibleName('Paused - click to resume'); } async pause() { await this.expectActive(); - await this.toggleButton.click(); + // Click instead of uncheck: the Switch is controlled by async Redux/API + // updates, so Playwright's checked-state verification fails before the + // store refreshes. expectPaused() polls until aria-checked flips. + await this.toggleButton.click({force: true}); await this.expectPaused(); } async resume() { await this.expectPaused(); - await this.toggleButton.click(); + await this.toggleButton.click({force: true}); await this.expectActive(); } diff --git a/e2e-tests/playwright/specs/functional/channels/channel_attributes/channel_attribute_banner.spec.ts b/e2e-tests/playwright/specs/functional/channels/channel_attributes/channel_attribute_banner.spec.ts index ac48dbc3600..0973c82f447 100644 --- a/e2e-tests/playwright/specs/functional/channels/channel_attributes/channel_attribute_banner.spec.ts +++ b/e2e-tests/playwright/specs/functional/channels/channel_attributes/channel_attribute_banner.spec.ts @@ -164,10 +164,7 @@ test.describe('Channel attribute banner composition', {tag: ['@channel_attribute const settings = await channelsPage.openChannelSettings(); const configuration = await settings.openConfigurationTab(); - await expect(configuration.container.getByTestId('channelBannerToggle-button')).toHaveAttribute( - 'aria-pressed', - 'true', - ); + await expect(configuration.container.getByTestId('channelBannerToggle-button')).toBeChecked(); await expect(configuration.bannerTextEditor).toBeVisible(); // * Opening the tab changes nothing, so it must not offer to save diff --git a/e2e-tests/playwright/specs/functional/channels/channel_attributes/channel_attribute_banner_settings.spec.ts b/e2e-tests/playwright/specs/functional/channels/channel_attributes/channel_attribute_banner_settings.spec.ts index a05de812ebb..6b1067819bc 100644 --- a/e2e-tests/playwright/specs/functional/channels/channel_attributes/channel_attribute_banner_settings.spec.ts +++ b/e2e-tests/playwright/specs/functional/channels/channel_attributes/channel_attribute_banner_settings.spec.ts @@ -255,10 +255,7 @@ test.describe('Channel attribute banner settings', {tag: ['@channel_attributes'] // # Switch the banner off let settings = await channelsPage.openChannelSettings(); let configuration = await settings.openConfigurationTab(); - await expect(configuration.container.getByTestId('channelBannerToggle-button')).toHaveAttribute( - 'aria-pressed', - 'true', - ); + await expect(configuration.container.getByTestId('channelBannerToggle-button')).toBeChecked(); await configuration.disableChannelBanner(); await configuration.save(); await settings.close(); @@ -270,10 +267,7 @@ test.describe('Channel attribute banner settings', {tag: ['@channel_attributes'] // # Switch it back on settings = await channelsPage.openChannelSettings(); configuration = await settings.openConfigurationTab(); - await expect(configuration.container.getByTestId('channelBannerToggle-button')).toHaveAttribute( - 'aria-pressed', - 'false', - ); + await expect(configuration.container.getByTestId('channelBannerToggle-button')).not.toBeChecked(); await configuration.enableChannelBanner(); await configuration.save(); await settings.close(); diff --git a/e2e-tests/playwright/specs/functional/channels/channel_classification/channel_classification.spec.ts b/e2e-tests/playwright/specs/functional/channels/channel_classification/channel_classification.spec.ts index 6bffbeed1a5..63fd3bec83a 100644 --- a/e2e-tests/playwright/specs/functional/channels/channel_classification/channel_classification.spec.ts +++ b/e2e-tests/playwright/specs/functional/channels/channel_classification/channel_classification.spec.ts @@ -81,7 +81,7 @@ test.describe('Channel Classification - New channel creation', () => { // Enable classification toggle const classificationToggle = channelsPage.page.getByTestId('channelClassificationToggle-button'); - await classificationToggle.click(); + await classificationToggle.check({force: true}); // Create button should be disabled (no classification level selected, no banner text) await expect(newChannelModal.createButton).toBeDisabled(); @@ -98,7 +98,7 @@ test.describe('Channel Classification - New channel creation', () => { // Enable classification toggle const classificationToggle = channelsPage.page.getByTestId('channelClassificationToggle-button'); - await classificationToggle.click(); + await classificationToggle.check({force: true}); // Open the classification dropdown const dropdownContainer = channelsPage.page.getByTestId('channelClassificationLevel'); @@ -126,7 +126,7 @@ test.describe('Channel Classification - New channel creation', () => { // Enable classification toggle const classificationToggle = channelsPage.page.getByTestId('channelClassificationToggle-button'); - await classificationToggle.click(); + await classificationToggle.check({force: true}); // Select a classification level const dropdownContainer = channelsPage.page.getByTestId('channelClassificationLevel'); @@ -164,7 +164,7 @@ test.describe('Channel Classification - New channel creation', () => { // Enable classification toggle const classificationToggle = channelsPage.page.getByTestId('channelClassificationToggle-button'); - await classificationToggle.click(); + await classificationToggle.check({force: true}); // Select the classification level const dropdownContainer = channelsPage.page.getByTestId('channelClassificationLevel'); @@ -220,13 +220,12 @@ test.describe('Channel Classification - Existing channel settings', () => { await expect(classificationToggle).toBeVisible(); // Toggle it on - const classes = await classificationToggle.getAttribute('class'); - if (!classes?.includes('active')) { - await classificationToggle.click(); + if (!(await classificationToggle.isChecked())) { + await classificationToggle.check({force: true}); } // Toggle should now be active - await expect(classificationToggle).toHaveClass(/active/); + await expect(classificationToggle).toBeChecked(); }); test('Classification level can be set once toggle is enabled', async ({pw}) => { @@ -246,7 +245,7 @@ test.describe('Channel Classification - Existing channel settings', () => { // Enable classification toggle const classificationToggle = channelsPage.page.getByTestId('channelClassificationToggle-button'); - await classificationToggle.click(); + await classificationToggle.check({force: true}); // Classification level dropdown should be visible const dropdownContainer = channelsPage.page.getByTestId('channelClassificationLevel'); @@ -282,7 +281,7 @@ test.describe('Channel Classification - Existing channel settings', () => { // Enable classification and select a level const classificationToggle = channelsPage.page.getByTestId('channelClassificationToggle-button'); - await classificationToggle.click(); + await classificationToggle.check({force: true}); const dropdownContainer = channelsPage.page.getByTestId('channelClassificationLevel'); await dropdownContainer.click(); @@ -295,7 +294,7 @@ test.describe('Channel Classification - Existing channel settings', () => { // The channel banner toggle should now be forced active and disabled const bannerToggle = channelsPage.page.getByTestId('channelBannerToggle-button'); await expect(bannerToggle).toBeVisible(); - await expect(bannerToggle).toHaveClass(/active/); + await expect(bannerToggle).toBeChecked(); await expect(bannerToggle).toBeDisabled(); // Banner color input should be locked to the classification color @@ -324,7 +323,7 @@ test.describe('Channel Classification - Existing channel settings', () => { const configurationTab = await channelSettingsModal.openConfigurationTab(); const classificationToggle = channelsPage.page.getByTestId('channelClassificationToggle-button'); - await classificationToggle.click(); + await classificationToggle.check({force: true}); const dropdownContainer = channelsPage.page.getByTestId('channelClassificationLevel'); await dropdownContainer.click(); @@ -337,7 +336,7 @@ test.describe('Channel Classification - Existing channel settings', () => { // longer auto-enables banner_info.enabled when classification is on, so the banner // section body (and its color input) is hidden after toggling classification off // until a manual banner is enabled. - await classificationToggle.click(); + await classificationToggle.uncheck({force: true}); await configurationTab.enableChannelBanner(); const customColor = 'aa00aa'; await configurationTab.setChannelBannerBackgroundColor(customColor); @@ -350,7 +349,7 @@ test.describe('Channel Classification - Existing channel settings', () => { expect(persisted.banner_info?.background_color?.toLowerCase().replace('#', '')).toBe(customColor); // Symptom 2 guard: re-enable classification → Save button reappears (panel transitions out of 'saved') - await classificationToggle.click(); + await classificationToggle.check({force: true}); const saveButton = channelsPage.page.getByTestId('SaveChangesPanel__save-btn'); await expect(saveButton).toBeVisible(); await expect(saveButton).toBeEnabled(); @@ -375,7 +374,7 @@ test.describe('Channel Classification - Existing channel settings', () => { // Enable classification and select a level const classificationToggle = channelsPage.page.getByTestId('channelClassificationToggle-button'); - await classificationToggle.click(); + await classificationToggle.check({force: true}); const dropdownContainer = channelsPage.page.getByTestId('channelClassificationLevel'); await dropdownContainer.click(); diff --git a/e2e-tests/playwright/specs/functional/channels/channel_settings/join_leave_messages.spec.ts b/e2e-tests/playwright/specs/functional/channels/channel_settings/join_leave_messages.spec.ts index 81ab2825dab..6bd453106b1 100644 --- a/e2e-tests/playwright/specs/functional/channels/channel_settings/join_leave_messages.spec.ts +++ b/e2e-tests/playwright/specs/functional/channels/channel_settings/join_leave_messages.spec.ts @@ -6,8 +6,8 @@ * the Configuration tab toggle in Channel Settings. * * The toggle controls `DisableJoinLeaveMessages` on the channel: - * - Toggle ON (active class) → messages shown (DisableJoinLeaveMessages = false) - * - Toggle OFF (no active class) → messages hidden (DisableJoinLeaveMessages = true) + * - Toggle ON (aria-checked=true) → messages shown (DisableJoinLeaveMessages = false) + * - Toggle OFF (aria-checked=false) → messages hidden (DisableJoinLeaveMessages = true) * * Join system posts are generated server-side when a user is added to a * channel, so tests use `adminClient.addToChannel()` to produce them. @@ -45,9 +45,8 @@ test.describe('Channel Settings Modal - Join/Leave System Messages', () => { // * Toggle is visible await expect(configSettings.joinLeaveMessagesToggle).toBeVisible(); - // * Toggle defaults to ON (active class present = messages shown) - const classes = await configSettings.joinLeaveMessagesToggle.getAttribute('class'); - expect(classes).toContain('active'); + // * Toggle defaults to ON (messages shown) + await expect(configSettings.joinLeaveMessagesToggle).toBeChecked(); await channelSettings.close(); }); diff --git a/e2e-tests/playwright/specs/functional/channels/shared_channel_configuration/shared_channel_configuration.spec.ts b/e2e-tests/playwright/specs/functional/channels/shared_channel_configuration/shared_channel_configuration.spec.ts index cdbeca573fa..a6737b7efb9 100644 --- a/e2e-tests/playwright/specs/functional/channels/shared_channel_configuration/shared_channel_configuration.spec.ts +++ b/e2e-tests/playwright/specs/functional/channels/shared_channel_configuration/shared_channel_configuration.spec.ts @@ -199,7 +199,7 @@ test.describe('Shared channel configuration', () => { await expect(configurationTab.shareWithWorkspacesToggle).toBeVisible(); // When sharing is disabled and no workspaces are configured, the toggle is simply off. - await expect(configurationTab.shareWithWorkspacesToggle).toHaveAttribute('aria-pressed', 'false'); + await expect(configurationTab.shareWithWorkspacesToggle).not.toBeChecked(); await channelSettingsModal.close(); }); @@ -311,7 +311,7 @@ test.describe('Shared channel configuration', () => { await channelsPage.toBeVisible(); channelSettingsModal = await channelsPage.openChannelSettings(); configurationTab = await channelSettingsModal.openConfigurationTab(); - await expect(configurationTab.shareWithWorkspacesToggle).toHaveAttribute('aria-pressed', 'true'); + await expect(configurationTab.shareWithWorkspacesToggle).toBeChecked(); await channelSettingsModal.close(); // Disable sharing via API (uninvite workspaces) to avoid async UI race conditions. @@ -331,7 +331,7 @@ test.describe('Shared channel configuration', () => { await channelsPage.toBeVisible(); channelSettingsModal = await channelsPage.openChannelSettings(); configurationTab = await channelSettingsModal.openConfigurationTab(); - await expect(configurationTab.shareWithWorkspacesToggle).toHaveAttribute('aria-pressed', 'false'); + await expect(configurationTab.shareWithWorkspacesToggle).not.toBeChecked(); await channelSettingsModal.close(); }); diff --git a/e2e-tests/playwright/specs/functional/system_console/abac/policies/channel_integration.spec.ts b/e2e-tests/playwright/specs/functional/system_console/abac/policies/channel_integration.spec.ts index 412c8c74916..ac5bbd9d41e 100644 --- a/e2e-tests/playwright/specs/functional/system_console/abac/policies/channel_integration.spec.ts +++ b/e2e-tests/playwright/specs/functional/system_console/abac/policies/channel_integration.spec.ts @@ -110,9 +110,8 @@ test.describe('ABAC Policies - Channel Integration', () => { const abacToggle = systemConsolePage.page.locator('[data-testid="policy-enforce-toggle-button"]'); await abacToggle.waitFor({state: 'visible', timeout: 5000}); - const isEnabled = await abacToggle.getAttribute('aria-pressed'); - if (isEnabled !== 'true') { - await abacToggle.click(); + if (!(await abacToggle.isChecked())) { + await abacToggle.check({force: true}); } await systemConsolePage.page.waitForTimeout(500); diff --git a/e2e-tests/playwright/specs/functional/system_console/abac/teams/team_integration.spec.ts b/e2e-tests/playwright/specs/functional/system_console/abac/teams/team_integration.spec.ts index 80c93e68352..b76a13d1dcd 100644 --- a/e2e-tests/playwright/specs/functional/system_console/abac/teams/team_integration.spec.ts +++ b/e2e-tests/playwright/specs/functional/system_console/abac/teams/team_integration.spec.ts @@ -102,9 +102,10 @@ test.describe('ABAC - Team Membership console', {tag: ['@abac', '@team_membershi async function setToggle(page: Page, on: boolean): Promise { const toggle = page.locator('[data-testid="policy-enforce-toggle-button"]'); await toggle.waitFor({state: 'visible', timeout: 10000}); - const pressed = (await toggle.getAttribute('aria-pressed')) === 'true'; - if (pressed !== on) { - await toggle.click(); + if (on) { + await toggle.check({force: true}); + } else { + await toggle.uncheck({force: true}); } } @@ -285,10 +286,7 @@ test.describe('ABAC - Team Membership console', {tag: ['@abac', '@team_membershi await expect(disconnectModal).not.toBeVisible({timeout: 5000}); // * Custom rule still governs, so enforcement stays on - await expect(page.locator('[data-testid="policy-enforce-toggle-button"]')).toHaveAttribute( - 'aria-pressed', - 'true', - ); + await expect(page.locator('[data-testid="policy-enforce-toggle-button"]')).toBeChecked(); // * Save goes straight through: removal is not new criteria, so no apply modal await page.getByRole('button', {name: 'Save'}).click(); diff --git a/webapp/channels/jest.config.js b/webapp/channels/jest.config.js index c4e290222cb..925bd249392 100644 --- a/webapp/channels/jest.config.js +++ b/webapp/channels/jest.config.js @@ -29,6 +29,8 @@ const config = { '^.+\\.(jpg|jpeg|png|apng|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$': '/src/tests/image_url_mock.json', '^.+\\.(css|less|scss)$': 'identity-obj-proxy', + // Stabilize Compass Switch CSS-module hashes across environments. + 'Switch\\.module\\.scss\\.(js|cjs)$': '/src/tests/mocks/compass_switch_styles.js', '^.*i18n.*\\.(json)$': '/src/tests/i18n_mock.json', }, moduleDirectories: ['node_modules'], diff --git a/webapp/channels/src/components/admin_console/content_flagging/content_reviewers/team_reviewers_section/team_reviewers_section.test.tsx b/webapp/channels/src/components/admin_console/content_flagging/content_reviewers/team_reviewers_section/team_reviewers_section.test.tsx index 092b84b258f..efe4fe56083 100644 --- a/webapp/channels/src/components/admin_console/content_flagging/content_reviewers/team_reviewers_section/team_reviewers_section.test.tsx +++ b/webapp/channels/src/components/admin_console/content_flagging/content_reviewers/team_reviewers_section/team_reviewers_section.test.tsx @@ -189,7 +189,7 @@ describe('TeamReviewersSection', () => { expect(teamNameCells[1]).toHaveTextContent('Team Two'); }); - const toggle = screen.getByRole('button', {name: /enable or disable content reviewers for team Team One/i}); + const toggle = screen.getByRole('switch', {name: /enable or disable content reviewers for team Team One/i}); await userEvent.click(toggle); expect(onChange).toHaveBeenCalledWith({ @@ -207,8 +207,8 @@ describe('TeamReviewersSection', () => { expect(mockSearchTeams).toHaveBeenCalledWith('', {page: 0, per_page: 10}); }); - expect(await screen.findByRole('button', {name: 'Enable or disable content reviewers for team Team One'})).toBeInTheDocument(); - expect(screen.getByRole('button', {name: 'Enable or disable content reviewers for team Team Two'})).toBeInTheDocument(); + expect(await screen.findByRole('switch', {name: 'Enable or disable content reviewers for team Team One'})).toBeInTheDocument(); + expect(screen.getByRole('switch', {name: 'Enable or disable content reviewers for team Team Two'})).toBeInTheDocument(); }); test('should handle toggle functionality with existing settings', async () => { @@ -241,7 +241,7 @@ describe('TeamReviewersSection', () => { expect(teamNameCells[1]).toHaveTextContent('Team Two'); }); - const toggle = screen.getByRole('button', {name: /enable or disable content reviewers for team Team One/i}); + const toggle = screen.getByRole('switch', {name: /enable or disable content reviewers for team Team One/i}); await userEvent.click(toggle); expect(onChange).toHaveBeenCalledWith({ @@ -395,7 +395,7 @@ describe('TeamReviewersSection', () => { expect(teamNameCells[1]).toHaveTextContent('Team Two'); }); - const toggle = screen.getByRole('button', {name: /enable or disable content reviewers for team Team One/i}); + const toggle = screen.getByRole('switch', {name: /enable or disable content reviewers for team Team One/i}); // First click - enable await userEvent.click(toggle); @@ -423,7 +423,7 @@ describe('TeamReviewersSection', () => { expect(mockSearchTeams).toHaveBeenCalledWith('', {page: 0, per_page: 10}); }); - const updatedToggle = screen.getAllByRole('button', {name: /enable or disable content reviewers for team Team One/i})[0]; + const updatedToggle = screen.getAllByRole('switch', {name: /enable or disable content reviewers for team Team One/i})[0]; // Second click - disable await userEvent.click(updatedToggle); diff --git a/webapp/channels/src/components/admin_console/content_flagging/content_reviewers/team_reviewers_section/team_reviewers_section.tsx b/webapp/channels/src/components/admin_console/content_flagging/content_reviewers/team_reviewers_section/team_reviewers_section.tsx index 6682c563d2f..8c310633ebb 100644 --- a/webapp/channels/src/components/admin_console/content_flagging/content_reviewers/team_reviewers_section/team_reviewers_section.tsx +++ b/webapp/channels/src/components/admin_console/content_flagging/content_reviewers/team_reviewers_section/team_reviewers_section.tsx @@ -5,13 +5,13 @@ import React, {useCallback, useEffect, useMemo, useState, type JSX} from 'react' import {useIntl} from 'react-intl'; import {useDispatch} from 'react-redux'; +import {Switch} from '@mattermost/compass-ui/components/switch'; import type {TeamReviewerSetting} from '@mattermost/types/config'; import type {Team, TeamSearchOpts} from '@mattermost/types/teams'; import {searchTeams} from 'mattermost-redux/actions/teams'; import DataGrid from 'components/admin_console/data_grid/data_grid'; -import Toggle from 'components/toggle'; import {TeamIcon} from 'components/widgets/team_icon/team_icon'; import * as Utils from 'utils/utils'; @@ -151,13 +151,15 @@ export default function TeamReviewers({teamReviewersSetting, onChange, disabled} /> ), enabled: ( - ), }, diff --git a/webapp/channels/src/components/admin_console/custom_plugin_settings/enable_plugin_button.test.tsx b/webapp/channels/src/components/admin_console/custom_plugin_settings/enable_plugin_button.test.tsx index 16d997d338d..5c03d15ec80 100644 --- a/webapp/channels/src/components/admin_console/custom_plugin_settings/enable_plugin_button.test.tsx +++ b/webapp/channels/src/components/admin_console/custom_plugin_settings/enable_plugin_button.test.tsx @@ -28,11 +28,13 @@ describe('components/admin_console/custom_plugin_settings/PluginEnableButton', ( ); expect(screen.getByText('Disabled')).toBeInTheDocument(); - await userEvent.click(screen.getByRole('button', {name: 'Enable plugin'})); + const enableSwitch = screen.getByRole('switch', {name: 'Enable plugin'}); + expect(enableSwitch.closest('label')?.className).toMatch(/switch--size-medium/); + await userEvent.click(enableSwitch); expect(enablePlugin).toHaveBeenCalledWith('com.mattermost.calls'); expect(disablePlugin).not.toHaveBeenCalled(); - expect(screen.getByRole('button', {name: 'Enable plugin'}).closest('.col-sm-offset-4')).toBeNull(); + expect(screen.getByRole('switch', {name: 'Enable plugin'}).closest('.col-sm-offset-4')).toBeNull(); }); it('disables the plugin when clicked while enabled', async () => { @@ -50,11 +52,11 @@ describe('components/admin_console/custom_plugin_settings/PluginEnableButton', ( ); expect(screen.getByText('Enabled')).toBeInTheDocument(); - await userEvent.click(screen.getByRole('button', {name: 'Disable plugin'})); + await userEvent.click(screen.getByRole('switch', {name: 'Disable plugin'})); expect(disablePlugin).toHaveBeenCalledWith('com.mattermost.calls'); expect(enablePlugin).not.toHaveBeenCalled(); - expect(screen.getByRole('button', {name: 'Disable plugin'})).toHaveAttribute('aria-pressed', 'true'); + expect(screen.getByRole('switch', {name: 'Disable plugin'})).toBeChecked(); await userEvent.click(screen.getByRole('button', {name: 'Plugin actions'})); expect(screen.getByRole('menuitem', {name: 'Uninstall plugin'})).toBeInTheDocument(); @@ -107,11 +109,11 @@ describe('components/admin_console/custom_plugin_settings/PluginEnableButton', ( />, ); - await userEvent.click(screen.getByRole('button', {name: 'Enable plugin'})); + await userEvent.click(screen.getByRole('switch', {name: 'Enable plugin'})); expect(screen.getByText('Enabling')).toBeInTheDocument(); expect(screen.getByTestId('loadingSpinner')).toBeInTheDocument(); - expect(screen.getByRole('button', {name: 'Enable plugin'})).toBeDisabled(); + expect(screen.getByRole('switch', {name: 'Enable plugin'})).toBeDisabled(); expect(screen.getByRole('button', {name: 'Plugin actions'})).toBeDisabled(); expect(screen.queryByText('Enabled')).not.toBeInTheDocument(); @@ -120,7 +122,7 @@ describe('components/admin_console/custom_plugin_settings/PluginEnableButton', ( await waitFor(() => { expect(screen.queryByText('Enabling')).not.toBeInTheDocument(); }); - expect(screen.getByRole('button', {name: 'Enable plugin'})).toBeEnabled(); + expect(screen.getByRole('switch', {name: 'Enable plugin'})).toBeEnabled(); expect(screen.getByText('Disabled')).toBeInTheDocument(); }); @@ -138,7 +140,7 @@ describe('components/admin_console/custom_plugin_settings/PluginEnableButton', ( />, ); - await userEvent.click(screen.getByRole('button', {name: 'Enable plugin'})); + await userEvent.click(screen.getByRole('switch', {name: 'Enable plugin'})); await waitFor(() => { expect(screen.getByText('Unable to enable plugin')).toBeInTheDocument(); @@ -160,7 +162,7 @@ describe('components/admin_console/custom_plugin_settings/PluginEnableButton', ( />, ); - await userEvent.click(screen.getByRole('button', {name: 'Enable plugin'})); + await userEvent.click(screen.getByRole('switch', {name: 'Enable plugin'})); expect(screen.getByText('Please save unsaved changes first')).toBeInTheDocument(); expect(enablePlugin).not.toHaveBeenCalled(); diff --git a/webapp/channels/src/components/admin_console/custom_plugin_settings/enable_plugin_button.tsx b/webapp/channels/src/components/admin_console/custom_plugin_settings/enable_plugin_button.tsx index a51aea95d45..2a04e2a9556 100644 --- a/webapp/channels/src/components/admin_console/custom_plugin_settings/enable_plugin_button.tsx +++ b/webapp/channels/src/components/admin_console/custom_plugin_settings/enable_plugin_button.tsx @@ -8,13 +8,13 @@ import {bindActionCreators} from 'redux'; import type {Dispatch} from 'redux'; import {DotsHorizontalIcon, OpenInNewIcon, TrashCanOutlineIcon} from '@mattermost/compass-icons/components'; +import {Switch} from '@mattermost/compass-ui/components/switch'; import {disablePlugin, enablePlugin, removePlugin} from 'mattermost-redux/actions/admin'; import type {ActionResult} from 'mattermost-redux/types/actions'; import ConfirmModal from 'components/confirm_modal'; import * as Menu from 'components/menu'; -import Toggle from 'components/toggle'; import LoadingSpinner from 'components/widgets/loading/loading_spinner'; import {getHistory} from 'utils/browser_history'; @@ -195,14 +195,15 @@ export function PluginEnableButton({actions, disabled, homepageUrl, id, saveNeed defaultMessage={pluginEnabled ? 'Enabled' : 'Disabled'} /> )} - { const expectPluginActionsInMetadataPanel = () => { const wrapper = document.querySelector('.PluginMetadataPanel__actionsPanel'); - const toggleButton = screen.queryByRole('button', {name: 'Enable plugin'}) || screen.getByRole('button', {name: 'Disable plugin'}); + const toggleButton = screen.queryByRole('switch', {name: 'Enable plugin'}) || screen.getByRole('switch', {name: 'Disable plugin'}); expect(wrapper).toContainElement(toggleButton); expect(wrapper).toContainElement(screen.getByRole('button', {name: 'Plugin actions'})); }; @@ -112,7 +112,7 @@ describe('custom plugin sections and settings', () => { {...baseState}); expectPluginPageTitle('testplugin', 'testplugin'); - expect(screen.getByRole('button', {name: 'Disable plugin'})).toBeInTheDocument(); + expect(screen.getByRole('switch', {name: 'Disable plugin'})).toBeInTheDocument(); expect(screen.getByRole('button', {name: 'Plugin actions'})).toBeInTheDocument(); expectPluginActionsInMetadataPanel(); const runningBadge = screen.getByTestId('plugin-metadata-status'); @@ -564,7 +564,7 @@ describe('custom plugin sections and settings', () => { {...state}); expectPluginPageTitle('testplugin', 'testplugin'); - expect(screen.getByRole('button', {name: 'Enable plugin'})).toBeInTheDocument(); + expect(screen.getByRole('switch', {name: 'Enable plugin'})).toBeInTheDocument(); expect(screen.getByRole('button', {name: 'Plugin actions'})).toBeInTheDocument(); expect(screen.queryByTestId('PluginSettings.PluginStates.testplugin.Enabletrue')).not.toBeInTheDocument(); expect(screen.queryByTestId('PluginSettings.PluginStates.testplugin.Enablefalse')).not.toBeInTheDocument(); @@ -653,7 +653,7 @@ describe('custom plugin sections and settings', () => { {...state}); expectPluginPageTitle('testplugin', 'testplugin'); - expect(screen.getByRole('button', {name: 'Enable plugin'})).toBeInTheDocument(); + expect(screen.getByRole('switch', {name: 'Enable plugin'})).toBeInTheDocument(); expect(screen.getByRole('button', {name: 'Plugin actions'})).toBeInTheDocument(); expect(screen.queryByTestId('PluginSettings.PluginStates.testplugin.Enabletrue')).not.toBeInTheDocument(); expect(screen.queryByTestId('PluginSettings.PluginStates.testplugin.Enablefalse')).not.toBeInTheDocument(); @@ -708,7 +708,7 @@ describe('custom plugin sections and settings', () => { state, ); - expect(screen.getByRole('button', {name: 'Enable plugin'})).toBeInTheDocument(); + expect(screen.getByRole('switch', {name: 'Enable plugin'})).toBeInTheDocument(); updateStoreState({ entities: { @@ -742,8 +742,8 @@ describe('custom plugin sections and settings', () => { />, ); - expect(screen.queryByRole('button', {name: 'Enable plugin'})).not.toBeInTheDocument(); - expect(screen.getByRole('button', {name: 'Disable plugin'})).toBeInTheDocument(); + expect(screen.queryByRole('switch', {name: 'Enable plugin'})).not.toBeInTheDocument(); + expect(screen.getByRole('switch', {name: 'Disable plugin'})).toBeInTheDocument(); expect(screen.getByRole('button', {name: 'Plugin actions'})).toBeInTheDocument(); expect(screen.queryByTestId('PluginSettings.PluginStates.testplugin.Enabletrue')).not.toBeInTheDocument(); }); @@ -1001,11 +1001,11 @@ describe('custom plugin sections and settings', () => { {...state}); expectPluginPageTitle('testplugin', 'testplugin'); - expect(screen.getByRole('button', {name: 'Disable plugin'})).toBeInTheDocument(); + expect(screen.getByRole('switch', {name: 'Disable plugin'})).toBeInTheDocument(); expect(screen.getByRole('button', {name: 'Plugin actions'})).toBeInTheDocument(); expect(screen.queryByTestId('PluginSettings.PluginStates.testplugin.Enabletrue')).not.toBeInTheDocument(); expect(screen.queryByTestId('PluginSettings.PluginStates.testplugin.Enablefalse')).not.toBeInTheDocument(); - expect(screen.queryByRole('button', {name: 'Enable plugin'})).not.toBeInTheDocument(); + expect(screen.queryByRole('switch', {name: 'Enable plugin'})).not.toBeInTheDocument(); expect(screen.queryByText('In order to view and configure plugin settings, enable the plugin.')).not.toBeInTheDocument(); expect(screen.getByText('Custom Component Section 1')).toBeInTheDocument(); expect(screen.getByText('Custom Component Section 2')).toBeInTheDocument(); diff --git a/webapp/channels/src/components/admin_console/group_settings/group_details/__snapshots__/group_details.test.tsx.snap b/webapp/channels/src/components/admin_console/group_settings/group_details/__snapshots__/group_details.test.tsx.snap index 61ebe11a097..085c2e680f1 100644 --- a/webapp/channels/src/components/admin_console/group_settings/group_details/__snapshots__/group_details.test.tsx.snap +++ b/webapp/channels/src/components/admin_console/group_settings/group_details/__snapshots__/group_details.test.tsx.snap @@ -94,46 +94,45 @@ exports[`components/admin_console/group_settings/group_details/GroupDetails shou class="separator__hr" /> -
-
+
-
-
-
+ When enabled, this group can be mentioned in other channels and teams. This may result in the group member list being visible to all users. -
-
-
+ + + + + +
@@ -505,46 +504,45 @@ exports[`components/admin_console/group_settings/group_details/GroupDetails shou class="separator__hr" /> -
-
+
-
-
-
+ When enabled, this group can be mentioned in other channels and teams. This may result in the group member list being visible to all users. -
-
-
+ + + + + +
@@ -914,46 +912,45 @@ exports[`components/admin_console/group_settings/group_details/GroupDetails shou class="separator__hr" /> -
-
+
-
-
-
+ When enabled, this group can be mentioned in other channels and teams. This may result in the group member list being visible to all users. -
-
-
+ + + + + +
@@ -1323,46 +1320,45 @@ exports[`components/admin_console/group_settings/group_details/GroupDetails shou class="separator__hr" /> -
-
+
-
-
-
+ When enabled, this group can be mentioned in other channels and teams. This may result in the group member list being visible to all users. -
-
-
+ + + + + +
diff --git a/webapp/channels/src/components/admin_console/group_settings/group_details/__snapshots__/group_profile_and_settings.test.tsx.snap b/webapp/channels/src/components/admin_console/group_settings/group_details/__snapshots__/group_profile_and_settings.test.tsx.snap index d9f8969fcae..0143d26b742 100644 --- a/webapp/channels/src/components/admin_console/group_settings/group_details/__snapshots__/group_profile_and_settings.test.tsx.snap +++ b/webapp/channels/src/components/admin_console/group_settings/group_details/__snapshots__/group_profile_and_settings.test.tsx.snap @@ -62,46 +62,45 @@ exports[`components/admin_console/group_settings/group_details/GroupProfileAndSe class="separator__hr" /> -
-
+
-
-
-
+ When enabled, this group can be mentioned in other channels and teams. This may result in the group member list being visible to all users. -
-
-
+ + + + + +
@@ -171,46 +170,46 @@ exports[`components/admin_console/group_settings/group_details/GroupProfileAndSe class="separator__hr" /> -
-
+
-
-
-
+ When enabled, this group can be mentioned in other channels and teams. This may result in the group member list being visible to all users. -
-
-
+ + + + + +
diff --git a/webapp/channels/src/components/admin_console/group_settings/group_details/group_profile_and_settings.tsx b/webapp/channels/src/components/admin_console/group_settings/group_details/group_profile_and_settings.tsx index 7c2c301ca8b..44093993824 100644 --- a/webapp/channels/src/components/admin_console/group_settings/group_details/group_profile_and_settings.tsx +++ b/webapp/channels/src/components/admin_console/group_settings/group_details/group_profile_and_settings.tsx @@ -5,7 +5,7 @@ import React from 'react'; import {FormattedMessage, defineMessage} from 'react-intl'; import GroupProfile from 'components/admin_console/group_settings/group_details/group_profile'; -import LineSwitch from 'components/admin_console/team_channel_settings/line_switch'; +import AdminSettingsSwitch from 'components/admin_console/team_channel_settings/admin_settings_switch'; import AdminPanel from 'components/widgets/admin_console/admin_panel'; type GroupSettingsToggleProps = { @@ -21,31 +21,29 @@ const GroupSettingsToggle = ({ onToggle, isDisabled, }: GroupSettingsToggleProps) => ( - { + onChange={() => { if (isDefault) { return; } onToggle(!allowReference); }} - singleLine={false} - title={ - - } - subTitle={ + secondaryLabel={ } - /> + > + + ); type GroupProfileAndSettingsProps = { diff --git a/webapp/channels/src/components/admin_console/ip_filtering/enable_section.test.tsx b/webapp/channels/src/components/admin_console/ip_filtering/enable_section.test.tsx index 7e30072751c..1bda1c14c55 100644 --- a/webapp/channels/src/components/admin_console/ip_filtering/enable_section.test.tsx +++ b/webapp/channels/src/components/admin_console/ip_filtering/enable_section.test.tsx @@ -31,7 +31,7 @@ describe('EnableSectionContent', () => { expect(screen.getByText('Enable IP Filtering')).toBeInTheDocument(); expect(screen.getByText('Limit access to your workspace by IP address.')).toBeInTheDocument(); expect(screen.getByTestId('filterToggle-button')).toBeInTheDocument(); - expect(screen.getByRole('button', {pressed: true})).toBeInTheDocument(); + expect(screen.getByRole('switch', {checked: true})).toBeInTheDocument(); }); test('clicking the toggle calls setFilterToggle', async () => { @@ -47,6 +47,19 @@ describe('EnableSectionContent', () => { expect(setFilterToggle).toHaveBeenCalledWith(false); }); + test('clicking the toggle when off calls setFilterToggle with true', async () => { + renderWithContext( + , + ); + + await userEvent.click(screen.getByTestId('filterToggle-button')); + + expect(setFilterToggle).toHaveBeenCalledWith(true); + }); + test('renders the component, with toggle not pressed if filterToggle is false', () => { renderWithContext( { expect(screen.getByText('Enable IP Filtering')).toBeInTheDocument(); expect(screen.getByText('Limit access to your workspace by IP address.')).toBeInTheDocument(); expect(screen.getByTestId('filterToggle-button')).toBeInTheDocument(); - expect(screen.getByRole('button', {pressed: false})).toBeInTheDocument(); + expect(screen.getByRole('switch', {checked: false})).toBeInTheDocument(); }); }); diff --git a/webapp/channels/src/components/admin_console/ip_filtering/enable_section.tsx b/webapp/channels/src/components/admin_console/ip_filtering/enable_section.tsx index 96022512a9f..5d45f4e7209 100644 --- a/webapp/channels/src/components/admin_console/ip_filtering/enable_section.tsx +++ b/webapp/channels/src/components/admin_console/ip_filtering/enable_section.tsx @@ -4,8 +4,9 @@ import React from 'react'; import {FormattedMessage, useIntl} from 'react-intl'; +import {Switch} from '@mattermost/compass-ui/components/switch'; + import ExternalLink from 'components/external_link'; -import Toggle from 'components/toggle'; type Props = { filterToggle: boolean; @@ -40,13 +41,15 @@ const EnableSectionContent: React.FC = ({filterToggle, setFilterToggle})
- setFilterToggle(!filterToggle)} - toggled={filterToggle} - toggleClassName='btn-toggle-primary' + onChange={(e) => setFilterToggle(e.target.checked)} + checked={filterToggle} + data-testid='filterToggle-button' + tabIndex={0} + aria-label={formatMessage({id: 'admin.ip_filtering.enable_ip_filtering', defaultMessage: 'Enable IP Filtering'})} />
diff --git a/webapp/channels/src/components/admin_console/ip_filtering/ip_filtering.scss b/webapp/channels/src/components/admin_console/ip_filtering/ip_filtering.scss index bd5c1fb25d7..d957fc9b686 100644 --- a/webapp/channels/src/components/admin_console/ip_filtering/ip_filtering.scss +++ b/webapp/channels/src/components/admin_console/ip_filtering/ip_filtering.scss @@ -64,9 +64,18 @@ } .SwitchSelector { + display: flex; width: 32px; height: 20px; flex-shrink: 0; + align-items: center; + + // Compass Switch root is a