diff --git a/apps/meteor/client/components/UserInfo/UserInfo.tsx b/apps/meteor/client/components/UserInfo/UserInfo.tsx index 59ddb7710a921..a89aba4e38474 100644 --- a/apps/meteor/client/components/UserInfo/UserInfo.tsx +++ b/apps/meteor/client/components/UserInfo/UserInfo.tsx @@ -14,7 +14,7 @@ import { } from '@rocket.chat/ui-client'; import type { TranslationKey } from '@rocket.chat/ui-contexts'; import type { ReactElement, ReactNode } from 'react'; -import { memo } from 'react'; +import { memo, useId } from 'react'; import { useTranslation } from 'react-i18next'; import { useTimeAgo } from '../../hooks/useTimeAgo'; @@ -84,6 +84,8 @@ const UserInfo = ({ const userDisplayName = useUserDisplayName({ name, username }); const userCustomFields = useUserCustomFields(customFields); + const usernameId = useId(); + return ( @@ -129,8 +131,12 @@ const UserInfo = ({ {username && username !== name && ( - {t('Username')} - {username} + + {t('Username')} + + + {username} + )} diff --git a/apps/meteor/client/views/teams/contextualBar/channels/AddExistingModal/AddExistingModal.tsx b/apps/meteor/client/views/teams/contextualBar/channels/AddExistingModal/AddExistingModal.tsx index c780a00a135f3..25ea5043d1d15 100644 --- a/apps/meteor/client/views/teams/contextualBar/channels/AddExistingModal/AddExistingModal.tsx +++ b/apps/meteor/client/views/teams/contextualBar/channels/AddExistingModal/AddExistingModal.tsx @@ -29,6 +29,7 @@ type AddExistingModalProps = { reload?: () => void; }; +// TODO: Use GenericModal instead of Modal const AddExistingModal = ({ teamId, onClose, reload }: AddExistingModalProps) => { const { t } = useTranslation(); const dispatchToastMessage = useToastMessageDispatch(); @@ -61,7 +62,10 @@ const AddExistingModal = ({ teamId, onClose, reload }: AddExistingModalProps) => ); return ( - }> + } + > {t('Team_Add_existing_channels')} diff --git a/apps/meteor/tests/e2e/account-profile.spec.ts b/apps/meteor/tests/e2e/account-profile.spec.ts index 809764ff507bf..9643d43970725 100644 --- a/apps/meteor/tests/e2e/account-profile.spec.ts +++ b/apps/meteor/tests/e2e/account-profile.spec.ts @@ -17,13 +17,12 @@ test.describe.serial('settings-account-profile', () => { poAccountProfile = new AccountProfile(page); }); - // FIXME: solve test intermitencies test.describe('Profile', () => { test.beforeEach(async ({ page }) => { await page.goto('/account/profile'); }); - test.skip('expect update profile with new name/username', async () => { + test('expect update profile with new name/username', async () => { const newName = faker.person.fullName(); const newUsername = faker.internet.userName({ firstName: newName }); @@ -37,9 +36,9 @@ test.describe.serial('settings-account-profile', () => { await expect(poHomeChannel.content.lastUserMessageNotSequential).toContainText(newUsername); await poHomeChannel.content.lastUserMessageNotSequential.locator('figure').click(); - await poHomeChannel.content.linkUserCard.click(); + await poHomeChannel.userCard.openUserInfo(); - await expect(poHomeChannel.tabs.userInfoUsername).toHaveText(newUsername); + await expect(poHomeChannel.tabs.userInfo.userName).toHaveText(newUsername); }); test.describe('Avatar', () => { diff --git a/apps/meteor/tests/e2e/avatar-settings.ts b/apps/meteor/tests/e2e/avatar-settings.ts index cf9527f2259f6..b6985f4edd4d1 100644 --- a/apps/meteor/tests/e2e/avatar-settings.ts +++ b/apps/meteor/tests/e2e/avatar-settings.ts @@ -91,7 +91,7 @@ test.describe('avatar-settings', () => { test('expect user card avatar to have provider prefix', async () => { await poHomeChannel.content.lastUserMessage.locator('.rcx-message-header__name-container').click(); - expect(poHomeChannel.content.userCard.locator('img').getAttribute('src')).toBe(avatarUrl); + expect(poHomeChannel.userCard.imgUserCard.getAttribute('src')).toBe(avatarUrl); }); }); }); diff --git a/apps/meteor/tests/e2e/channel-management.spec.ts b/apps/meteor/tests/e2e/channel-management.spec.ts index bd76bafb4ec16..81c9299a7a85c 100644 --- a/apps/meteor/tests/e2e/channel-management.spec.ts +++ b/apps/meteor/tests/e2e/channel-management.spec.ts @@ -61,8 +61,8 @@ test.describe.serial('channel-management', () => { await poHomeChannel.navbar.openChat(targetChannel); await poHomeChannel.roomToolbar.openRoomInfo(); await poHomeChannel.tabs.room.btnEdit.click(); - await poHomeChannel.tabs.room.inputTopic.fill('hello-topic-edited'); - await poHomeChannel.tabs.room.btnSave.click(); + await poHomeChannel.tabs.editRoom.inputTopic.fill('hello-topic-edited'); + await poHomeChannel.tabs.editRoom.btnSave.click(); await poHomeChannel.toastMessage.dismissToast(); await poHomeChannel.roomToolbar.openRoomInfo(); @@ -75,8 +75,8 @@ test.describe.serial('channel-management', () => { await poHomeChannel.navbar.openChat(targetChannel); await poHomeChannel.roomToolbar.openRoomInfo(); await poHomeChannel.tabs.room.btnEdit.click(); - await poHomeChannel.tabs.room.inputAnnouncement.fill('hello-announcement-edited'); - await poHomeChannel.tabs.room.btnSave.click(); + await poHomeChannel.tabs.editRoom.inputAnnouncement.fill('hello-announcement-edited'); + await poHomeChannel.tabs.editRoom.btnSave.click(); await poHomeChannel.toastMessage.dismissToast(); await poHomeChannel.roomToolbar.openRoomInfo(); @@ -88,8 +88,8 @@ test.describe.serial('channel-management', () => { await poHomeChannel.navbar.openChat(targetChannel); await poHomeChannel.roomToolbar.openRoomInfo(); await poHomeChannel.tabs.room.btnEdit.click(); - await poHomeChannel.tabs.room.inputDescription.fill('hello-description-edited'); - await poHomeChannel.tabs.room.btnSave.click(); + await poHomeChannel.tabs.editRoom.inputDescription.fill('hello-description-edited'); + await poHomeChannel.tabs.editRoom.btnSave.click(); await poHomeChannel.toastMessage.dismissToast(); await poHomeChannel.roomToolbar.openRoomInfo(); @@ -101,8 +101,8 @@ test.describe.serial('channel-management', () => { await poHomeChannel.navbar.openChat(targetChannel); await poHomeChannel.roomToolbar.openRoomInfo(); await poHomeChannel.tabs.room.btnEdit.click(); - await poHomeChannel.tabs.room.inputName.fill(`NAME-EDITED-${targetChannel}`); - await poHomeChannel.tabs.room.btnSave.click(); + await poHomeChannel.tabs.editRoom.inputName.fill(`NAME-EDITED-${targetChannel}`); + await poHomeChannel.tabs.editRoom.btnSave.click(); targetChannel = `NAME-EDITED-${targetChannel}`; await expect(page.locator(`role=main >> role=heading[name="${targetChannel}"]`)).toBeVisible(); @@ -116,8 +116,8 @@ test.describe.serial('channel-management', () => { await poHomeChannel.navbar.openChat(targetChannel); await poHomeChannel.roomToolbar.openRoomInfo(); await poHomeChannel.tabs.room.btnEdit.click(); - await poHomeChannel.tabs.room.inputName.fill(hugeName); - await poHomeChannel.tabs.room.btnSave.click(); + await poHomeChannel.tabs.editRoom.inputName.fill(hugeName); + await poHomeChannel.tabs.editRoom.btnSave.click(); targetChannel = hugeName; await page.setViewportSize({ width: 640, height: 460 }); @@ -165,8 +165,8 @@ test.describe.serial('channel-management', () => { test('should edit notification preferences of targetChannel', async () => { await poHomeChannel.navbar.openChat(targetChannel); - await poHomeChannel.tabs.kebab.click({ force: true }); - await poHomeChannel.tabs.btnNotificationPreferences.click({ force: true }); + await poHomeChannel.roomToolbar.openMoreOptions(); + await poHomeChannel.roomToolbar.menuItemNotificationsPreferences.click(); await poHomeChannel.tabs.notificationPreferences.updateAllNotificationPreferences(); await poHomeChannel.tabs.notificationPreferences.btnSave.click(); @@ -255,8 +255,8 @@ test.describe.serial('channel-management', () => { await poHomeChannel.tabs.members.showAllUsers(); await poHomeChannel.tabs.members.ignoreUser('user1'); - await poHomeChannel.tabs.members.openMoreActions(); - await expect(poHomeChannel.tabs.members.getMenuItemAction('Unignore')).toBeVisible(); + await poHomeChannel.tabs.members.userInfo.openMoreActions(); + await expect(poHomeChannel.tabs.members.userInfo.menu.getMenuItem('Unignore')).toBeVisible(); const user1Channel = new HomeChannel(user1Page); await user1Page.goto(`/channel/${targetChannel}`); @@ -294,8 +294,8 @@ test.describe.serial('channel-management', () => { await poHomeChannel.tabs.members.showAllUsers(); await poHomeChannel.tabs.members.unignoreUser('user1'); - await poHomeChannel.tabs.members.openMoreActions(); - await expect(poHomeChannel.tabs.members.getMenuItemAction('Ignore')).toBeVisible(); + await poHomeChannel.tabs.members.userInfo.openMoreActions(); + await expect(poHomeChannel.tabs.members.userInfo.menu.getMenuItem('Ignore')).toBeVisible(); await user1Channel.content.sendMessage('message after being unignored'); diff --git a/apps/meteor/tests/e2e/e2e-encryption/e2ee-encrypted-channels.spec.ts b/apps/meteor/tests/e2e/e2e-encryption/e2ee-encrypted-channels.spec.ts index 4e5708d56aa5d..d745d0d8aec00 100644 --- a/apps/meteor/tests/e2e/e2e-encryption/e2ee-encrypted-channels.spec.ts +++ b/apps/meteor/tests/e2e/e2e-encryption/e2ee-encrypted-channels.spec.ts @@ -51,10 +51,8 @@ test.describe('E2EE Encrypted Channels', () => { await expect(poHomeChannel.content.lastUserMessage.locator('.rcx-icon--name-key')).toBeVisible(); await toastMessages.dismissToast(); - await poHomeChannel.tabs.kebab.click({ force: true }); - - await expect(poHomeChannel.tabs.btnDisableE2E).toBeVisible(); - await poHomeChannel.tabs.btnDisableE2E.click({ force: true }); + await poHomeChannel.roomToolbar.openMoreOptions(); + await poHomeChannel.roomToolbar.menuItemDisabledE2EEncryption.click(); await expect(page.getByRole('dialog', { name: 'Disable encryption' })).toBeVisible(); await page.getByRole('button', { name: 'Disable encryption' }).click(); await poHomeChannel.toastMessage.dismissToast(); @@ -65,9 +63,9 @@ test.describe('E2EE Encrypted Channels', () => { await expect(poHomeChannel.content.lastUserMessageBody).toHaveText('hello world not encrypted'); await expect(poHomeChannel.content.lastUserMessage.locator('.rcx-icon--name-key')).not.toBeVisible(); - await poHomeChannel.tabs.kebab.click({ force: true }); - await expect(poHomeChannel.tabs.btnEnableE2E).toBeVisible(); - await poHomeChannel.tabs.btnEnableE2E.click({ force: true }); + await poHomeChannel.roomToolbar.openMoreOptions(); + await expect(poHomeChannel.roomToolbar.menuItemEnableE2EEncryption).toBeVisible(); + await poHomeChannel.roomToolbar.menuItemEnableE2EEncryption.click(); await expect(page.getByRole('dialog', { name: 'Enable encryption' })).toBeVisible(); await page.getByRole('button', { name: 'Enable encryption' }).click(); await poHomeChannel.toastMessage.dismissToast(); @@ -144,12 +142,12 @@ test.describe('E2EE Encrypted Channels', () => { await poHomeChannel.toastMessage.waitForDisplay(); await poHomeChannel.toastMessage.dismissToast(); - await poHomeChannel.tabs.kebab.click(); + await poHomeChannel.roomToolbar.openMoreOptions(); // TODO(@jessicaschelly/@dougfabris): fix this flaky behavior - if (!(await poHomeChannel.tabs.btnEnableE2E.isVisible())) { - await poHomeChannel.tabs.kebab.click(); + if (!(await poHomeChannel.roomToolbar.menuItemEnableE2EEncryption.isVisible())) { + await poHomeChannel.roomToolbar.openMoreOptions(); } - await poHomeChannel.tabs.btnEnableE2E.click(); + await poHomeChannel.roomToolbar.menuItemEnableE2EEncryption.click(); await expect(page.getByRole('dialog', { name: 'Enable encryption' })).toBeVisible(); await page.getByRole('button', { name: 'Enable encryption' }).click(); await page.waitForTimeout(1000); @@ -245,9 +243,9 @@ test.describe('E2EE Encrypted Channels', () => { await poHomeChannel.content.sendMessage('second unencrypted message'); // Encrypt channel - await poHomeChannel.tabs.kebab.click({ force: true }); - await expect(poHomeChannel.tabs.btnEnableE2E).toBeVisible(); - await poHomeChannel.tabs.btnEnableE2E.click({ force: true }); + await poHomeChannel.roomToolbar.openMoreOptions(); + await expect(poHomeChannel.roomToolbar.menuItemEnableE2EEncryption).toBeVisible(); + await poHomeChannel.roomToolbar.menuItemEnableE2EEncryption.click(); await expect(page.getByRole('dialog', { name: 'Enable encryption' })).toBeVisible(); await page.getByRole('button', { name: 'Enable encryption' }).click(); await page.waitForTimeout(1000); @@ -303,8 +301,8 @@ test.describe('E2EE Encrypted Channels', () => { await poHomeChannel.toastMessage.waitForDisplay(); await poHomeChannel.toastMessage.dismissToast(); - await poHomeChannel.tabs.kebab.click(); - await poHomeChannel.tabs.btnPinnedMessagesList.click(); + await poHomeChannel.roomToolbar.openMoreOptions(); + await poHomeChannel.roomToolbar.menuItemPinnedMessages.click(); await expect(page.getByRole('dialog', { name: 'Pinned Messages' })).toBeVisible(); @@ -316,9 +314,8 @@ test.describe('E2EE Encrypted Channels', () => { await expect(page.locator('role=menuitem[name="Copy link"]')).toHaveClass(/disabled/); await poHomeChannel.btnContextualbarClose.click(); - - await poHomeChannel.tabs.kebab.click(); - await poHomeChannel.tabs.btnStarredMessageList.click(); + await poHomeChannel.roomToolbar.openMoreOptions(); + await poHomeChannel.roomToolbar.menuItemStarredMessages.click(); const lastStarredMessage = page.getByRole('dialog', { name: 'Starred Messages' }).locator('[data-qa-type="message"]').last(); await expect(page.getByRole('dialog', { name: 'Starred Messages' })).toBeVisible(); diff --git a/apps/meteor/tests/e2e/e2e-encryption/e2ee-pdf-export.spec.ts b/apps/meteor/tests/e2e/e2e-encryption/e2ee-pdf-export.spec.ts index 8ce3b3685ea66..3574549178db2 100644 --- a/apps/meteor/tests/e2e/e2e-encryption/e2ee-pdf-export.spec.ts +++ b/apps/meteor/tests/e2e/e2e-encryption/e2ee-pdf-export.spec.ts @@ -3,7 +3,7 @@ import { faker } from '@faker-js/faker'; import { Users } from '../fixtures/userStates'; import { EncryptedRoomPage } from '../page-objects/encrypted-room'; import { Navbar } from '../page-objects/fragments'; -import { ExportMessagesTab } from '../page-objects/fragments/export-messages-tab'; +import { ExportMessagesFlexTab } from '../page-objects/fragments/flextabs'; import { LoginPage } from '../page-objects/login'; import { preserveSettings } from '../utils/preserveSettings'; import { test, expect } from '../utils/test'; @@ -43,7 +43,7 @@ test.describe('E2EE PDF Export', () => { test('should display only the download file method when exporting messages in an e2ee room', async ({ page }) => { const navbar = new Navbar(page); const encryptedRoomPage = new EncryptedRoomPage(page); - const exportMessagesTab = new ExportMessagesTab(page); + const exportMessagesTab = new ExportMessagesFlexTab(page); const channelName = faker.string.uuid(); @@ -59,7 +59,7 @@ test.describe('E2EE PDF Export', () => { test('should allow exporting messages as PDF in an encrypted room', async ({ page }) => { const navbar = new Navbar(page); const encryptedRoomPage = new EncryptedRoomPage(page); - const exportMessagesTab = new ExportMessagesTab(page); + const exportMessagesTab = new ExportMessagesFlexTab(page); const channelName = faker.string.uuid(); diff --git a/apps/meteor/tests/e2e/export-messages.spec.ts b/apps/meteor/tests/e2e/export-messages.spec.ts index 7338d15cb67b1..90edecaa91033 100644 --- a/apps/meteor/tests/e2e/export-messages.spec.ts +++ b/apps/meteor/tests/e2e/export-messages.spec.ts @@ -2,7 +2,6 @@ import { faker } from '@faker-js/faker'; import { Users } from './fixtures/userStates'; import { HomeChannel } from './page-objects'; -import { ExportMessagesTab } from './page-objects/fragments'; import { createTargetChannel, deleteChannel } from './utils'; import { test, expect } from './utils/test'; @@ -31,61 +30,56 @@ test.describe('export-messages', () => { ]); }); - test('should all export methods be available in targetChannel', async ({ page }) => { - const exportMessagesTab = new ExportMessagesTab(page); - + test('should all export methods be available in targetChannel', async () => { await poHomeChannel.navbar.openChat(targetChannel); - await poHomeChannel.tabs.kebab.click({ force: true }); - await poHomeChannel.tabs.btnExportMessages.click(); + await poHomeChannel.roomToolbar.openMoreOptions(); + await poHomeChannel.roomToolbar.menuItemExportMessages.click(); - await exportMessagesTab.exposeMethods(); - await expect(exportMessagesTab.getMethodOptionByName('Send email')).toBeVisible(); - await expect(exportMessagesTab.getMethodOptionByName('Send file via email')).toBeVisible(); - await expect(exportMessagesTab.getMethodOptionByName('Download file')).toBeVisible(); + await poHomeChannel.tabs.exportMessages.exposeMethods(); + await expect(poHomeChannel.tabs.exportMessages.getMethodOptionByName('Send email')).toBeVisible(); + await expect(poHomeChannel.tabs.exportMessages.getMethodOptionByName('Send file via email')).toBeVisible(); + await expect(poHomeChannel.tabs.exportMessages.getMethodOptionByName('Download file')).toBeVisible(); }); - test('should display export output format correctly depending on the selected method', async ({ page }) => { - const exportMessagesTab = new ExportMessagesTab(page); - + test('should display export output format correctly depending on the selected method', async () => { await poHomeChannel.navbar.openChat(targetChannel); - await poHomeChannel.tabs.kebab.click({ force: true }); - await poHomeChannel.tabs.btnExportMessages.click(); + await poHomeChannel.roomToolbar.openMoreOptions(); + await poHomeChannel.roomToolbar.menuItemExportMessages.click(); // TODO: Fix the base component to have a disabled statement and not only a class attribute // Here we are checking for a button because the internal select element is not accessible // and the higher component that is a button doesn't appear as disabled. - await expect(exportMessagesTab.outputFormat).toContainClass('disabled'); + await expect(poHomeChannel.tabs.exportMessages.outputFormat).toContainClass('disabled'); - await exportMessagesTab.setMethod('Send file via email'); + await poHomeChannel.tabs.exportMessages.setMethod('Send file via email'); - await exportMessagesTab.exposeOutputFormats(); - await expect(exportMessagesTab.getOutputFormatOptionByName('html')).toBeVisible(); - await expect(exportMessagesTab.getOutputFormatOptionByName('json')).toBeVisible(); - await expect(exportMessagesTab.getOutputFormatOptionByName('pdf')).not.toBeVisible(); + await poHomeChannel.tabs.exportMessages.exposeOutputFormats(); + await expect(poHomeChannel.tabs.exportMessages.getOutputFormatOptionByName('html')).toBeVisible(); + await expect(poHomeChannel.tabs.exportMessages.getOutputFormatOptionByName('json')).toBeVisible(); + await expect(poHomeChannel.tabs.exportMessages.getOutputFormatOptionByName('pdf')).not.toBeVisible(); - await exportMessagesTab.setOutputFormat('html'); + await poHomeChannel.tabs.exportMessages.setOutputFormat('html'); - await exportMessagesTab.setMethod('Download file'); + await poHomeChannel.tabs.exportMessages.setMethod('Download file'); - await exportMessagesTab.exposeOutputFormats(); - await expect(exportMessagesTab.getOutputFormatOptionByName('html')).not.toBeVisible(); - await expect(exportMessagesTab.getOutputFormatOptionByName('json')).toBeVisible(); - await expect(exportMessagesTab.getOutputFormatOptionByName('pdf')).toBeVisible(); + await poHomeChannel.tabs.exportMessages.exposeOutputFormats(); + await expect(poHomeChannel.tabs.exportMessages.getOutputFormatOptionByName('html')).not.toBeVisible(); + await expect(poHomeChannel.tabs.exportMessages.getOutputFormatOptionByName('json')).toBeVisible(); + await expect(poHomeChannel.tabs.exportMessages.getOutputFormatOptionByName('pdf')).toBeVisible(); }); test('should display an error when trying to send email without filling to users or to additional emails', async ({ page }) => { - const exportMessagesTab = new ExportMessagesTab(page); const testMessage = uniqueMessage(); await poHomeChannel.navbar.openChat(targetChannel); await poHomeChannel.content.sendMessage(testMessage); - await poHomeChannel.tabs.kebab.click({ force: true }); - await poHomeChannel.tabs.btnExportMessages.click(); + await poHomeChannel.roomToolbar.openMoreOptions(); + await poHomeChannel.roomToolbar.menuItemExportMessages.click(); await expect(poHomeChannel.btnContextualbarClose).toBeVisible(); await poHomeChannel.content.getMessageByText(testMessage).click(); - await exportMessagesTab.send(); + await poHomeChannel.tabs.exportMessages.send(); await expect( page.locator('[role="alert"]', { @@ -95,14 +89,12 @@ test.describe('export-messages', () => { }); test('should display an error when trying to send email without selecting any message', async ({ page }) => { - const exportMessagesTab = new ExportMessagesTab(page); - await poHomeChannel.navbar.openChat(targetChannel); - await poHomeChannel.tabs.kebab.click({ force: true }); - await poHomeChannel.tabs.btnExportMessages.click(); + await poHomeChannel.roomToolbar.openMoreOptions(); + await poHomeChannel.roomToolbar.menuItemExportMessages.click(); - await exportMessagesTab.setAdditionalEmail('mail@mail.com'); - await exportMessagesTab.send(); + await poHomeChannel.tabs.exportMessages.setAdditionalEmail('mail@mail.com'); + await poHomeChannel.tabs.exportMessages.send(); await expect( page.locator('[role="alert"]', { @@ -117,8 +109,8 @@ test.describe('export-messages', () => { await poHomeChannel.navbar.openChat(targetChannel); await poHomeChannel.content.sendMessage(message1); - await poHomeChannel.tabs.kebab.click({ force: true }); - await poHomeChannel.tabs.btnExportMessages.click(); + await poHomeChannel.roomToolbar.openMoreOptions(); + await poHomeChannel.roomToolbar.menuItemExportMessages.click(); await poHomeChannel.content.getMessageByText(message1).click(); await poHomeChannel.btnContextualbarClose.click(); @@ -127,8 +119,7 @@ test.describe('export-messages', () => { await expect(poHomeChannel.content.getMessageByText(message2)).toBeVisible(); }); - test('should be able to select a single message to export', async ({ page }) => { - const exportMessagesTab = new ExportMessagesTab(page); + test('should be able to select a single message to export', async () => { const message1 = uniqueMessage(); const message2 = uniqueMessage(); @@ -136,20 +127,20 @@ test.describe('export-messages', () => { await poHomeChannel.content.sendMessage(message1); await poHomeChannel.content.sendMessage(message2); - await poHomeChannel.tabs.kebab.click({ force: true }); - await poHomeChannel.tabs.btnExportMessages.click(); - await exportMessagesTab.waitForDisplay(); + await poHomeChannel.roomToolbar.openMoreOptions(); + await poHomeChannel.roomToolbar.menuItemExportMessages.click(); + await poHomeChannel.tabs.exportMessages.waitForDisplay(); await poHomeChannel.content.getMessageByText(message1).click(); - await expect(exportMessagesTab.getMessageCheckbox(message1)).toBeChecked(); - await expect(exportMessagesTab.getMessageCheckbox(message2)).not.toBeChecked(); - await expect(exportMessagesTab.clearSelectionButton).toBeEnabled(); + await expect(poHomeChannel.tabs.exportMessages.getMessageCheckbox(message1)).toBeChecked(); + await expect(poHomeChannel.tabs.exportMessages.getMessageCheckbox(message2)).not.toBeChecked(); + await expect(poHomeChannel.tabs.exportMessages.clearSelectionButton).toBeEnabled(); - await expect(exportMessagesTab.sendButton).toBeEnabled(); + await expect(poHomeChannel.tabs.exportMessages.sendButton).toBeEnabled(); }); - test('should be able to select a single message to export with hide contextual bar preference enabled', async ({ page, api }) => { + test('should be able to select a single message to export with hide contextual bar preference enabled', async ({ api }) => { await api.post('/users.setPreferences', { userId: 'rocketchat.internal.admin.test', data: { hideFlexTab: true }, @@ -157,21 +148,19 @@ test.describe('export-messages', () => { const message1 = uniqueMessage(); const message2 = uniqueMessage(); - const exportMessagesTab = new ExportMessagesTab(page); - await poHomeChannel.navbar.openChat(targetChannel); await poHomeChannel.content.sendMessage(message1); await poHomeChannel.content.sendMessage(message2); - await poHomeChannel.tabs.kebab.click({ force: true }); - await poHomeChannel.tabs.btnExportMessages.click(); + await poHomeChannel.roomToolbar.openMoreOptions(); + await poHomeChannel.roomToolbar.menuItemExportMessages.click(); - await exportMessagesTab.waitForDisplay(); + await poHomeChannel.tabs.exportMessages.waitForDisplay(); await poHomeChannel.content.getMessageByText(message1).click(); - await expect(exportMessagesTab.getMessageCheckbox(message1)).toBeChecked(); - await expect(exportMessagesTab.clearSelectionButton).toBeEnabled(); + await expect(poHomeChannel.tabs.exportMessages.getMessageCheckbox(message1)).toBeChecked(); + await expect(poHomeChannel.tabs.exportMessages.clearSelectionButton).toBeEnabled(); - await expect(exportMessagesTab.sendButton).toBeEnabled(); + await expect(poHomeChannel.tabs.exportMessages.sendButton).toBeEnabled(); }); }); diff --git a/apps/meteor/tests/e2e/feature-preview.spec.ts b/apps/meteor/tests/e2e/feature-preview.spec.ts index b0481e8cfdd18..4697b83ed4060 100644 --- a/apps/meteor/tests/e2e/feature-preview.spec.ts +++ b/apps/meteor/tests/e2e/feature-preview.spec.ts @@ -1,7 +1,7 @@ import { faker } from '@faker-js/faker'; import { Users } from './fixtures/userStates'; -import { AdminInfo, HomeChannel } from './page-objects'; +import { AdminInfo, HomeChannel, HomeDiscussion, HomeTeam } from './page-objects'; import { CreateNewChannelModal } from './page-objects/fragments/modals'; import { createTargetChannel, @@ -19,6 +19,7 @@ test.use({ storageState: Users.admin.state }); test.describe.serial('feature preview', () => { let poHomeChannel: HomeChannel; + let poHomeTeam: HomeTeam; let targetChannel: string; let targetDiscussion: Record; let sidepanelTeam: string; @@ -55,6 +56,7 @@ test.describe.serial('feature preview', () => { test.beforeEach(async ({ page }) => { poHomeChannel = new HomeChannel(page); + poHomeTeam = new HomeTeam(page); }); test('should show "Navigation" feature section', async ({ page }) => { @@ -105,17 +107,17 @@ test.describe.serial('feature preview', () => { newChannelModal = new CreateNewChannelModal(page); await page.goto(`/group/${sidepanelTeam}`); - await poHomeChannel.content.waitForChannel(); + await poHomeTeam.content.waitForChannel(); - await poHomeChannel.roomToolbar.openTeamChannels(); - await poHomeChannel.tabs.channels.btnCreateNew.click(); + await poHomeTeam.headerToolbar.openTeamChannels(); + await poHomeTeam.tabs.channels.btnCreateNew.click(); await newChannelModal.inputName.fill(targetChannelNameInTeam); await newChannelModal.checkboxPrivate.click(); await newChannelModal.btnCreate.click(); - await expect(poHomeChannel.sidepanel.sidepanelList).toBeVisible(); - await expect(poHomeChannel.sidepanel.getItemByName(targetChannelNameInTeam)).toBeVisible(); + await expect(poHomeTeam.sidepanel.sidepanelList).toBeVisible(); + await expect(poHomeTeam.sidepanel.getItemByName(targetChannelNameInTeam)).toBeVisible(); await deleteChannel(api, targetChannelNameInTeam); }); @@ -144,20 +146,10 @@ test.describe.serial('feature preview', () => { test('should show channel in sidepanel after adding existing one', async ({ page }) => { await page.goto(`/group/${sidepanelTeam}`); - await poHomeChannel.roomToolbar.openTeamChannels(); - await poHomeChannel.tabs.channels.btnAddExisting.click(); - // flaky: workarround for when AutoComplete does not close the list box before trying to click `Add` - await expect(async () => { - await poHomeChannel.tabs.channels.inputChannels.fill(targetChannel); - const option = poHomeChannel.tabs.channels.getListboxOption(targetChannel); - await option.click(); - await expect(option).not.toBeVisible(); - }).toPass(); - - await poHomeChannel.tabs.channels.btnAdd.click(); - await poHomeChannel.content.waitForChannel(); + await poHomeTeam.headerToolbar.openTeamChannels(); + await poHomeTeam.tabs.channels.addExistingChannel(targetChannel); - await expect(poHomeChannel.sidepanel.getItemByName(targetChannel)).toBeVisible(); + await expect(poHomeTeam.sidepanel.getItemByName(targetChannel)).toBeVisible(); }); test('should keep the main room on the top even if child has unread messages', async ({ page, browser }) => { @@ -166,30 +158,22 @@ test.describe.serial('feature preview', () => { await page.goto(`/group/${sidepanelTeam}`); - await poHomeChannel.roomToolbar.openTeamChannels(); - await poHomeChannel.tabs.channels.btnAddExisting.click(); - // flaky: workarround for when AutoComplete does not close the list box before trying to click `Add` - await expect(async () => { - await poHomeChannel.tabs.channels.inputChannels.fill(targetChannel); - const option = poHomeChannel.tabs.channels.getListboxOption(targetChannel); - await option.click(); - await expect(option).not.toBeVisible(); - }).toPass(); - await poHomeChannel.tabs.channels.btnAdd.click(); + await poHomeTeam.headerToolbar.openTeamChannels(); + await poHomeTeam.tabs.channels.addExistingChannel(targetChannel); - const sidepanelTeamItem = poHomeChannel.sidepanel.getTeamItemByName(sidepanelTeam); - const targetChannelItem = poHomeChannel.sidepanel.getTeamItemByName(targetChannel); + const sidepanelTeamItem = poHomeTeam.sidepanel.getTeamItemByName(sidepanelTeam); + const targetChannelItem = poHomeTeam.sidepanel.getTeamItemByName(targetChannel); await targetChannelItem.click(); expect(page.url()).toContain(`/channel/${targetChannel}`); - await poHomeChannel.content.sendMessage('hello channel'); + await poHomeTeam.content.sendMessage('hello channel'); await expect(async () => { await sidepanelTeamItem.focus(); await sidepanelTeamItem.click(); expect(page.url()).toContain(`/group/${sidepanelTeam}`); }).toPass(); - await poHomeChannel.content.sendMessage('hello team'); + await poHomeTeam.content.sendMessage('hello team'); await user1Page.goto(`/channel/${targetChannel}`); await user1Channel.content.waitForChannel(); @@ -197,7 +181,7 @@ test.describe.serial('feature preview', () => { await user1Channel.content.toggleAlsoSendThreadToChannel(false); await user1Channel.content.sendMessageInThread('hello thread'); - const item = poHomeChannel.sidepanel.getTeamItemByName(targetChannel); + const item = poHomeTeam.sidepanel.getTeamItemByName(targetChannel); await expect(item.locator('..')).toHaveAttribute('data-item-index', '1'); await user1Page.close(); @@ -254,6 +238,7 @@ test.describe.serial('feature preview', () => { }); test('should show discussion in discussions and all sidepanel filter, should remove after deleting discussion', async ({ page }) => { + const poHomeDiscussion = new HomeDiscussion(page); await page.goto(`/group/${sidepanelTeam}`); await poHomeChannel.content.waitForChannel(); @@ -265,22 +250,20 @@ test.describe.serial('feature preview', () => { await poHomeChannel.content.btnCreateDiscussionModal.click(); await expect(page.getByRole('heading', { name: discussionName })).toBeVisible(); - await poHomeChannel.sidebar.discussionsTeamCollabFilter.click(); - await expect(poHomeChannel.sidepanel.getItemByName(discussionName)).toBeVisible(); + await poHomeDiscussion.sidebar.discussionsTeamCollabFilter.click(); + await expect(poHomeDiscussion.sidepanel.getItemByName(discussionName)).toBeVisible(); - await poHomeChannel.sidebar.allTeamCollabFilter.click(); - await expect(poHomeChannel.sidepanel.getItemByName(discussionName)).toBeVisible(); + await poHomeDiscussion.sidebar.allTeamCollabFilter.click(); + await expect(poHomeDiscussion.sidepanel.getItemByName(discussionName)).toBeVisible(); - await poHomeChannel.roomToolbar.openRoomInfo(); - await poHomeChannel.tabs.room.btnMore.click(); - await poHomeChannel.tabs.room.getMoreOption('Delete').click(); - await poHomeChannel.tabs.room.confirmDeleteDiscussion(); + await poHomeDiscussion.roomToolbar.openRoomInfo(); + await poHomeDiscussion.tabs.room.deleteRoom(); - await poHomeChannel.sidebar.discussionsTeamCollabFilter.click(); - await expect(poHomeChannel.sidepanel.getItemByName(discussionName)).not.toBeVisible(); + await poHomeDiscussion.sidebar.discussionsTeamCollabFilter.click(); + await expect(poHomeDiscussion.sidepanel.getItemByName(discussionName)).not.toBeVisible(); - await poHomeChannel.sidebar.allTeamCollabFilter.click(); - await expect(poHomeChannel.sidepanel.getItemByName(discussionName)).not.toBeVisible(); + await poHomeDiscussion.sidebar.allTeamCollabFilter.click(); + await expect(poHomeDiscussion.sidepanel.getItemByName(discussionName)).not.toBeVisible(); }); test('should persist sidepanel state after page reload', async ({ page }) => { diff --git a/apps/meteor/tests/e2e/message-actions.spec.ts b/apps/meteor/tests/e2e/message-actions.spec.ts index 5e043d198d37e..f25164c4e4d66 100644 --- a/apps/meteor/tests/e2e/message-actions.spec.ts +++ b/apps/meteor/tests/e2e/message-actions.spec.ts @@ -1,7 +1,7 @@ import { ADMIN_CREDENTIALS } from './config/constants'; import { Users } from './fixtures/userStates'; -import { HomeChannel, HomeDiscussion } from './page-objects'; -import { HomeFlextab } from './page-objects/fragments'; +import { HomeChannel } from './page-objects'; +import { CreateNewDiscussionModal } from './page-objects/fragments'; import { createTargetChannel, createTargetTeam } from './utils'; import { setUserPreferences } from './utils/setUserPreferences'; import { expect, test } from './utils/test'; @@ -9,7 +9,6 @@ import { expect, test } from './utils/test'; test.use({ storageState: Users.admin.state }); test.describe.serial('message-actions', () => { let poHomeChannel: HomeChannel; - let poHomeDiscussion: HomeDiscussion; let targetChannel: string; let forwardChannel: string; let forwardTeam: string; @@ -20,7 +19,6 @@ test.describe.serial('message-actions', () => { }); test.beforeEach(async ({ page }) => { poHomeChannel = new HomeChannel(page); - poHomeDiscussion = new HomeDiscussion(page); await page.goto('/home'); await poHomeChannel.navbar.openChat(targetChannel); }); @@ -39,7 +37,7 @@ test.describe.serial('message-actions', () => { await page.locator('.rcx-vertical-bar').locator(`role=textbox[name="Message #${targetChannel}"]`).type('this is a reply message'); await page.keyboard.press('Enter'); - await expect(poHomeChannel.tabs.flexTabViewThreadMessage).toHaveText('this is a reply message'); + await expect(poHomeChannel.tabs.threads.lastThreadMessage).toHaveText('this is a reply message'); }); // with thread open we listen to the subscription and update the collection from there @@ -50,7 +48,7 @@ test.describe.serial('message-actions', () => { await page.locator('role=button[name="Reply in thread"]').click(); await page.getByRole('dialog').locator(`role=textbox[name="Message #${targetChannel}"]`).fill('this is a reply message'); await page.keyboard.press('Enter'); - await expect(poHomeChannel.tabs.flexTabViewThreadMessage).toHaveText('this is a reply message'); + await expect(poHomeChannel.tabs.threads.lastThreadMessage).toHaveText('this is a reply message'); }); await test.step('unfollow thread', async () => { @@ -86,7 +84,7 @@ test.describe.serial('message-actions', () => { await page.locator('role=button[name="Reply in thread"]').click(); await page.locator('.rcx-vertical-bar').locator(`role=textbox[name="Message #${targetChannel}"]`).fill('this is a reply message'); await page.keyboard.press('Enter'); - await expect(poHomeChannel.tabs.flexTabViewThreadMessage).toHaveText('this is a reply message'); + await expect(poHomeChannel.tabs.threads.lastThreadMessage).toHaveText('this is a reply message'); }); // close thread before testing because the behavior changes @@ -144,10 +142,11 @@ test.describe.serial('message-actions', () => { await poHomeChannel.content.sendMessage(message); await poHomeChannel.content.openLastMessageMenu(); await page.locator('role=menuitem[name="Start a Discussion"]').click(); - const createButton = poHomeDiscussion.btnCreate; + const createDiscussionModal = new CreateNewDiscussionModal(page); + const createButton = createDiscussionModal.btnCreate; // Name should be prefilled thus making the create button enabled await expect(createButton).not.toBeDisabled(); - await poHomeDiscussion.inputName.fill(discussionName); + await createDiscussionModal.inputName.fill(discussionName); await createButton.click(); await expect(page.locator('header h1')).toHaveText(discussionName); await poHomeChannel.navbar.openChat(targetChannel); @@ -156,13 +155,12 @@ test.describe.serial('message-actions', () => { }); test('expect star the message', async ({ page }) => { - const flextab = new HomeFlextab(page); await poHomeChannel.content.sendMessage('Message to star'); await poHomeChannel.content.openLastMessageMenu(); await page.locator('role=menuitem[name="Star"]').click(); await poHomeChannel.toastMessage.dismissToast(); - await flextab.kebab.click(); - await page.locator('[data-key="starred-messages"]').click(); + await poHomeChannel.roomToolbar.openMoreOptions(); + await poHomeChannel.roomToolbar.menuItemStarredMessages.click(); await expect(poHomeChannel.content.lastUserMessageBody).toHaveText('Message to star'); }); diff --git a/apps/meteor/tests/e2e/page-objects/admin-emojis.ts b/apps/meteor/tests/e2e/page-objects/admin-emojis.ts index 71717404e50d0..432cc619766db 100644 --- a/apps/meteor/tests/e2e/page-objects/admin-emojis.ts +++ b/apps/meteor/tests/e2e/page-objects/admin-emojis.ts @@ -1,7 +1,7 @@ import type { Locator, Page } from '@playwright/test'; import { Admin } from './admin'; -import { AddEmojiFlexTab, EditEmojiFlexTab } from './fragments/admin-flextab-emoji'; +import { AddEmojiFlexTab, EditEmojiFlexTab } from './fragments/flextabs'; export class AdminEmoji extends Admin { readonly addEmojiFlexTab: AddEmojiFlexTab; diff --git a/apps/meteor/tests/e2e/page-objects/admin-rooms.ts b/apps/meteor/tests/e2e/page-objects/admin-rooms.ts index eda0a45707606..40104eeeddb7b 100644 --- a/apps/meteor/tests/e2e/page-objects/admin-rooms.ts +++ b/apps/meteor/tests/e2e/page-objects/admin-rooms.ts @@ -1,14 +1,14 @@ import type { Locator, Page } from '@playwright/test'; import { Admin } from './admin'; -import { EditRoomFlexTab } from './fragments/edit-room-flextab'; +import { EditAdminRoomFlexTab } from './fragments/flextabs'; export class AdminRooms extends Admin { - readonly editRoom: EditRoomFlexTab; + readonly editRoom: EditAdminRoomFlexTab; constructor(page: Page) { super(page); - this.editRoom = new EditRoomFlexTab(page.getByRole('dialog', { name: 'Room Information' })); + this.editRoom = new EditAdminRoomFlexTab(page.getByRole('dialog', { name: 'Room Information' })); } get adminPageContent(): Locator { diff --git a/apps/meteor/tests/e2e/page-objects/encrypted-room.ts b/apps/meteor/tests/e2e/page-objects/encrypted-room.ts index 4b8a4e98c1e59..13da26be440c6 100644 --- a/apps/meteor/tests/e2e/page-objects/encrypted-room.ts +++ b/apps/meteor/tests/e2e/page-objects/encrypted-room.ts @@ -1,8 +1,17 @@ -import { HomeContent, HomeFlextab } from './fragments'; +import type { Page } from '@playwright/test'; + +import { EncryptedRoomToolbar, HomeContent } from './fragments'; import { Message } from './fragments/message'; import { DisableRoomEncryptionModal, EnableRoomEncryptionModal } from './fragments/modals'; export class EncryptedRoomPage extends HomeContent { + readonly toolbar: EncryptedRoomToolbar; + + constructor(page: Page) { + super(page); + this.toolbar = new EncryptedRoomToolbar(page); + } + get encryptedTitle() { return this.page.getByRole('button', { name: '- encrypted' }); } @@ -20,28 +29,23 @@ export class EncryptedRoomPage extends HomeContent { } async enableEncryption() { - const tabs = new HomeFlextab(this.page); - const enableRoomEncryptionModal = new EnableRoomEncryptionModal(this.page); - await tabs.kebab.click(); - await tabs.btnEnableE2E.click(); + await this.toolbar.openMoreOptions(); + await this.toolbar.btnEnableE2EEncryption.click(); await enableRoomEncryptionModal.enable(); } async disableEncryption() { - const tabs = new HomeFlextab(this.page); const disableRoomEncryptionModal = new DisableRoomEncryptionModal(this.page); - await tabs.kebab.click(); - await tabs.btnDisableE2E.click(); + await this.toolbar.openMoreOptions(); + await this.toolbar.btnDisableE2EEncryption.click(); await disableRoomEncryptionModal.disable(); } async showExportMessagesTab() { - const tabs = new HomeFlextab(this.page); - - await tabs.kebab.click(); - await tabs.btnExportMessages.click(); + await this.toolbar.openMoreOptions(); + await this.toolbar.menuItemExportMessages.click(); } } diff --git a/apps/meteor/tests/e2e/page-objects/fragments/edit-room-flextab.ts b/apps/meteor/tests/e2e/page-objects/fragments/edit-room-flextab.ts deleted file mode 100644 index bfc88661991bb..0000000000000 --- a/apps/meteor/tests/e2e/page-objects/fragments/edit-room-flextab.ts +++ /dev/null @@ -1,87 +0,0 @@ -import type { Locator, Page } from '@playwright/test'; - -import { FlexTab } from './flextab'; -import { Listbox } from './listbox'; - -export class EditRoomFlexTab extends FlexTab { - constructor(locator: Locator) { - super(locator); - } - - get roomNameInput(): Locator { - return this.root.locator('input[name="roomName"]'); - } - - get privateLabel(): Locator { - return this.root.locator(`label >> text=Private`); - } - - get privateInput(): Locator { - return this.root.locator('input[name="roomType"]'); - } - - get roomOwnerInput(): Locator { - return this.root.locator('input[name="roomOwner"]'); - } - - get archivedLabel(): Locator { - return this.root.locator('label >> text=Archived'); - } - - get archivedInput(): Locator { - return this.root.locator('input[name="archived"]'); - } - - get favoriteLabel(): Locator { - return this.root.locator('label >> text=Favorite'); - } - - get favoriteInput(): Locator { - return this.root.locator('input[name="favorite"]'); - } - - get defaultLabel(): Locator { - return this.root.locator('label >> text=Default'); - } - - get defaultInput(): Locator { - return this.root.locator('input[name="isDefault"]'); - } -} - -export class OmnichannelEditRoomFlexTab extends EditRoomFlexTab { - private readonly tagsListbox: Listbox; - - private readonly slaListbox: Listbox; - - constructor(page: Page) { - super(page.getByRole('dialog', { name: 'Edit Room' })); - this.tagsListbox = new Listbox(page); - this.slaListbox = new Listbox(page, 'SLA Policy'); - } - - get inputTopic(): Locator { - return this.root.getByRole('textbox', { name: 'Topic', exact: true }); - } - - get inputSLAPolicy(): Locator { - return this.root.getByRole('button', { name: 'SLA Policy', exact: true }); - } - - optionTag(name: string): Locator { - return this.tagsListbox.getOption(name); - } - - async selectTag(name: string) { - await this.tagsListbox.selectOption(name); - } - - async selectSLA(name: string) { - await this.inputSLAPolicy.click(); - await this.slaListbox.selectOption(name, true); - } - - get inputTags(): Locator { - return this.root.getByRole('textbox', { name: 'Select an option' }); - } -} diff --git a/apps/meteor/tests/e2e/page-objects/fragments/flextabs/admin-edit-room-flextab.ts b/apps/meteor/tests/e2e/page-objects/fragments/flextabs/admin-edit-room-flextab.ts new file mode 100644 index 0000000000000..fe0d5206af00c --- /dev/null +++ b/apps/meteor/tests/e2e/page-objects/fragments/flextabs/admin-edit-room-flextab.ts @@ -0,0 +1,49 @@ +import type { Locator } from '@playwright/test'; + +import { FlexTab } from './flextab'; + +export class EditAdminRoomFlexTab extends FlexTab { + constructor(locator: Locator) { + super(locator); + } + + get roomNameInput(): Locator { + return this.root.locator('input[name="roomName"]'); + } + + get privateLabel(): Locator { + return this.root.locator(`label >> text=Private`); + } + + get privateInput(): Locator { + return this.root.locator('input[name="roomType"]'); + } + + get roomOwnerInput(): Locator { + return this.root.locator('input[name="roomOwner"]'); + } + + get archivedLabel(): Locator { + return this.root.locator('label >> text=Archived'); + } + + get archivedInput(): Locator { + return this.root.locator('input[name="archived"]'); + } + + get favoriteLabel(): Locator { + return this.root.locator('label >> text=Favorite'); + } + + get favoriteInput(): Locator { + return this.root.locator('input[name="favorite"]'); + } + + get defaultLabel(): Locator { + return this.root.locator('label >> text=Default'); + } + + get defaultInput(): Locator { + return this.root.locator('input[name="isDefault"]'); + } +} diff --git a/apps/meteor/tests/e2e/page-objects/fragments/admin-flextab-emoji.ts b/apps/meteor/tests/e2e/page-objects/fragments/flextabs/admin-flextab-emoji.ts similarity index 100% rename from apps/meteor/tests/e2e/page-objects/fragments/admin-flextab-emoji.ts rename to apps/meteor/tests/e2e/page-objects/fragments/flextabs/admin-flextab-emoji.ts diff --git a/apps/meteor/tests/e2e/page-objects/fragments/flextabs/channels-flextab.ts b/apps/meteor/tests/e2e/page-objects/fragments/flextabs/channels-flextab.ts new file mode 100644 index 0000000000000..d40cecdd489ea --- /dev/null +++ b/apps/meteor/tests/e2e/page-objects/fragments/flextabs/channels-flextab.ts @@ -0,0 +1,83 @@ +import type { Locator, Page } from '@playwright/test'; + +import { FlexTab } from './flextab'; +import { Listbox } from '../listbox'; +import { ConfirmDeleteRoomModal, ConfirmRemoveModal } from '../modals'; +import { Modal } from '../modals/modal'; + +class AddExistingChannelModal extends Modal { + constructor(page: Page) { + super(page.getByRole('dialog', { name: 'Add Existing Channels' })); + } + + get inputChannels(): Locator { + return this.root.getByRole('textbox'); + } + + get btnAdd(): Locator { + return this.root.getByRole('button', { name: 'Add' }); + } + + async confirmAdd() { + await this.btnAdd.click(); + await this.waitForDismissal(); + } +} + +export class ChannelsFlexTab extends FlexTab { + readonly confirmRemoveModal: ConfirmRemoveModal; + + readonly confirmDeleteModal: ConfirmDeleteRoomModal; + + readonly addExistingChannelModal: AddExistingChannelModal; + + readonly listbox: Listbox; + + constructor(page: Page) { + super(page.getByRole('dialog', { name: 'Team Channels' })); + this.confirmRemoveModal = new ConfirmRemoveModal(page.getByRole('dialog', { name: 'Are you sure?' })); + this.confirmDeleteModal = new ConfirmDeleteRoomModal(page); + this.addExistingChannelModal = new AddExistingChannelModal(page); + this.listbox = new Listbox(page); + } + + get btnAddExisting(): Locator { + return this.root.getByRole('button', { name: 'Add Existing' }); + } + + get btnCreateNew(): Locator { + return this.root.getByRole('button', { name: 'Create new' }); + } + + get channelsList(): Locator { + return this.root.getByRole('list'); + } + + getListboxOption(name: string): Locator { + return this.listbox.getOption(name); + } + + channelOption(name: string) { + return this.root.locator('li', { hasText: name }); + } + + async openChannelOptionMoreActions(name: string) { + await this.channelOption(name).hover(); + await this.channelOption(name).getByRole('button', { name: 'More' }).click(); + } + + async confirmRemoveChannel() { + return this.confirmRemoveModal.confirmRemove(); + } + + async confirmDeleteRoom() { + return this.confirmDeleteModal.confirmDelete(); + } + + async addExistingChannel(name: string) { + await this.btnAddExisting.click(); + await this.addExistingChannelModal.inputChannels.fill(name); + await this.listbox.selectOption(name); + await this.addExistingChannelModal.confirmAdd(); + } +} diff --git a/apps/meteor/tests/e2e/page-objects/fragments/edit-contact-flaxtab.ts b/apps/meteor/tests/e2e/page-objects/fragments/flextabs/edit-contact-flextab.ts similarity index 100% rename from apps/meteor/tests/e2e/page-objects/fragments/edit-contact-flaxtab.ts rename to apps/meteor/tests/e2e/page-objects/fragments/flextabs/edit-contact-flextab.ts diff --git a/apps/meteor/tests/e2e/page-objects/fragments/flextabs/edit-room-flextab.ts b/apps/meteor/tests/e2e/page-objects/fragments/flextabs/edit-room-flextab.ts new file mode 100644 index 0000000000000..92c1780acf861 --- /dev/null +++ b/apps/meteor/tests/e2e/page-objects/fragments/flextabs/edit-room-flextab.ts @@ -0,0 +1,110 @@ +import type { Locator, Page } from '@playwright/test'; + +import { FlexTab } from './flextab'; +import { Listbox } from '../listbox'; + +export class EditRoomFlexTab extends FlexTab { + constructor(locator: Locator) { + super(locator); + } + + get inputTopic(): Locator { + return this.root.getByRole('textbox', { name: 'Topic' }); + } + + get inputAnnouncement(): Locator { + return this.root.getByRole('textbox', { name: 'Announcement' }); + } + + get inputDescription(): Locator { + return this.root.getByRole('textbox', { name: 'Description' }); + } + + get checkboxReadOnly(): Locator { + return this.root.locator('label', { hasText: 'Read-only' }); + } + + get calloutRetentionPolicy(): Locator { + return this.root.getByRole('alert', { name: 'Retention policy warning callout' }); + } + + get advancedSettingsAccordion(): Locator { + return this.root.getByRole('button', { name: 'Advanced settings' }); + } + + get pruneAccordion(): Locator { + return this.root.getByRole('button', { name: 'Prune', exact: true }); + } + + getMaxAgeLabel(maxAge = '30') { + return this.root.getByText(`Maximum message age in days (default: ${maxAge})`); + } + + get inputRetentionMaxAge(): Locator { + return this.root.locator('input[name="retentionMaxAge"]'); + } + + get checkboxPruneMessages(): Locator { + return this.root.locator('label', { hasText: 'Automatically prune old messages' }); + } + + get checkboxOverrideGlobalRetention(): Locator { + return this.root.locator('label', { hasText: 'Override global retention policy' }); + } + + get checkboxIgnoreThreads(): Locator { + return this.root.locator('label', { hasText: 'Do not prune Threads' }); + } + + get checkboxChannels(): Locator { + return this.root.locator('label', { hasText: 'Channels' }); + } + + get checkboxDiscussions(): Locator { + return this.root.locator('label', { hasText: 'Discussions' }); + } + + async toggleSidepanelItems() { + await this.checkboxChannels.click(); + await this.checkboxDiscussions.click(); + } +} + +export class EditTeamFlexTab extends EditRoomFlexTab { + constructor(page: Page) { + super(page.getByRole('dialog', { name: 'Edit team' })); + } +} + +export class OmnichannelEditRoomFlexTab extends EditRoomFlexTab { + private readonly tagsListbox: Listbox; + + private readonly slaListbox: Listbox; + + constructor(page: Page) { + super(page.getByRole('dialog', { name: 'Edit Room' })); + this.tagsListbox = new Listbox(page); + this.slaListbox = new Listbox(page, 'SLA Policy'); + } + + get inputSLAPolicy(): Locator { + return this.root.getByRole('button', { name: 'SLA Policy', exact: true }); + } + + optionTag(name: string): Locator { + return this.tagsListbox.getOption(name); + } + + async selectTag(name: string) { + await this.tagsListbox.selectOption(name); + } + + async selectSLA(name: string) { + await this.inputSLAPolicy.click(); + await this.slaListbox.selectOption(name, true); + } + + get inputTags(): Locator { + return this.root.getByRole('textbox', { name: 'Select an option' }); + } +} diff --git a/apps/meteor/tests/e2e/page-objects/fragments/edit-user-flextab.ts b/apps/meteor/tests/e2e/page-objects/fragments/flextabs/edit-user-flextab.ts similarity index 100% rename from apps/meteor/tests/e2e/page-objects/fragments/edit-user-flextab.ts rename to apps/meteor/tests/e2e/page-objects/fragments/flextabs/edit-user-flextab.ts diff --git a/apps/meteor/tests/e2e/page-objects/fragments/export-messages-tab.ts b/apps/meteor/tests/e2e/page-objects/fragments/flextabs/export-messages-flextab.ts similarity index 97% rename from apps/meteor/tests/e2e/page-objects/fragments/export-messages-tab.ts rename to apps/meteor/tests/e2e/page-objects/fragments/flextabs/export-messages-flextab.ts index fc47a7ade63b6..aade25ebe4e8c 100644 --- a/apps/meteor/tests/e2e/page-objects/fragments/export-messages-tab.ts +++ b/apps/meteor/tests/e2e/page-objects/fragments/flextabs/export-messages-flextab.ts @@ -2,7 +2,7 @@ import type { Locator, Page } from '@playwright/test'; import { FlexTab } from './flextab'; -export class ExportMessagesTab extends FlexTab { +export class ExportMessagesFlexTab extends FlexTab { constructor(page: Page) { super(page.getByRole('dialog', { name: 'Export Messages' })); } diff --git a/apps/meteor/tests/e2e/page-objects/fragments/flextab.ts b/apps/meteor/tests/e2e/page-objects/fragments/flextabs/flextab.ts similarity index 82% rename from apps/meteor/tests/e2e/page-objects/fragments/flextab.ts rename to apps/meteor/tests/e2e/page-objects/fragments/flextabs/flextab.ts index e406a0decb43a..3c5257aef4ceb 100644 --- a/apps/meteor/tests/e2e/page-objects/fragments/flextab.ts +++ b/apps/meteor/tests/e2e/page-objects/fragments/flextabs/flextab.ts @@ -1,8 +1,11 @@ import type { Locator } from '@playwright/test'; -import { expect } from '../../utils/test'; +import { expect } from '../../../utils/test'; export abstract class FlexTab { + /** + * @param root should be protected, but for now there are a lot of tests relying on accessing it directly, * so we need to keep it public until we can refactor those tests + */ constructor(public root: Locator) {} waitForDisplay() { diff --git a/apps/meteor/tests/e2e/page-objects/fragments/flextabs/index.ts b/apps/meteor/tests/e2e/page-objects/fragments/flextabs/index.ts new file mode 100644 index 0000000000000..fce63c0a3be7d --- /dev/null +++ b/apps/meteor/tests/e2e/page-objects/fragments/flextabs/index.ts @@ -0,0 +1,14 @@ +export * from './admin-flextab-emoji'; +export * from './admin-edit-room-flextab'; +export * from './channels-flextab'; +export * from './edit-room-flextab'; +export * from './edit-user-flextab'; +export * from './edit-contact-flextab'; +export * from './export-messages-flextab'; +export * from './members-flextab'; +export * from './notification-preferences-flextab'; +export * from './prune-messages-flextab'; +export * from './room-info-flextab'; +export * from './threads-flextab'; +export * from './search-messages-flextab'; +export * from './user-info-flextab'; diff --git a/apps/meteor/tests/e2e/page-objects/fragments/flextabs/members-flextab.ts b/apps/meteor/tests/e2e/page-objects/fragments/flextabs/members-flextab.ts new file mode 100644 index 0000000000000..720d0090059a9 --- /dev/null +++ b/apps/meteor/tests/e2e/page-objects/fragments/flextabs/members-flextab.ts @@ -0,0 +1,145 @@ +import type { Page } from '@playwright/test'; + +import { FlexTab } from './flextab'; +import { Listbox } from '../listbox'; +import { MenuMore } from '../menu'; +import { ConfirmRemoveModal } from '../modals'; +import { UserInfoFlexTab } from './user-info-flextab'; +import { Modal } from '../modals/modal'; + +export class ConfirmMuteModal extends Modal { + constructor(page: Page) { + super(page.getByRole('dialog', { name: 'Are you sure' })); + } + + private get btnMute() { + return this.root.getByRole('button', { name: 'Yes, mute user!' }); + } + + async confirmMute() { + await this.btnMute.click(); + await this.waitForDismissal(); + } +} + +class AddUsersFlexTab extends FlexTab { + readonly listbox: Listbox; + + constructor(page: Page) { + super(page.getByRole('dialog', { name: 'Add users' })); + this.listbox = new Listbox(page); + } + + private btnAddUsers() { + return this.root.getByRole('button', { name: 'Add users' }); + } + + async addUser(username: string) { + await this.root.getByRole('textbox', { name: 'Choose users' }).pressSequentially(username); + await this.listbox.selectOption(username); + await this.btnAddUsers().click(); + await this.waitForDismissal(); + } +} + +export class MembersFlexTab extends FlexTab { + readonly listbox: Listbox; + + readonly removeModal: ConfirmRemoveModal; + + readonly menu: MenuMore; + + readonly confirmMuteModal: ConfirmMuteModal; + + readonly addUsersFlexTab: AddUsersFlexTab; + + readonly userInfo: UserInfoFlexTab; + + constructor(page: Page) { + super(page.getByRole('dialog', { name: 'Members' })); + this.removeModal = new ConfirmRemoveModal(page.getByRole('dialog', { name: 'Confirmation', exact: true })); + this.listbox = new Listbox(page); + this.menu = new MenuMore(page); + this.confirmMuteModal = new ConfirmMuteModal(page); + this.addUsersFlexTab = new AddUsersFlexTab(page); + this.userInfo = new UserInfoFlexTab(page); + } + + memberOption(username: string) { + return this.root.locator('li', { hasText: username }); + } + + getMenuItemAction(action: string) { + return this.menu.getMenuItem(action); + } + + async openMemberInfo(username: string) { + await this.memberOption(username).click(); + } + + async openMoreActions() { + await this.root.getByRole('button', { name: 'More' }).click(); + } + + async openMemberOptionMoreActions(username: string) { + await this.memberOption(username).hover(); + await this.memberOption(username).getByRole('button', { name: 'More' }).click(); + } + + async addUser(username: string) { + await this.root.getByRole('button', { name: 'Add' }).click(); + await this.addUsersFlexTab.addUser(username); + } + + private get btnInviteLink() { + return this.root.getByRole('button', { name: 'Invite Link' }); + } + + async inviteUser() { + await this.btnInviteLink.click(); + } + + async muteUser(username: string) { + await this.openMemberOptionMoreActions(username); + await this.menu.selectMenuItem('Mute user'); + await this.confirmMuteModal.confirmMute(); + } + + async unmuteUser(username: string) { + await this.openMemberOptionMoreActions(username); + await this.menu.selectMenuItem('Unmute user'); + } + + async setUserAsModerator(username: string) { + await this.openMemberOptionMoreActions(username); + await this.menu.selectMenuItem('Set as moderator'); + } + + async setUserAsOwner(username: string) { + await this.openMemberOptionMoreActions(username); + await this.menu.selectMenuItem('Set as owner'); + } + + async showAllUsers() { + await this.root.getByRole('button', { name: 'Online' }).click(); + await this.listbox.selectOption('All'); + } + + private async ignoreUserAction(action: string, username: string) { + await this.openMemberInfo(username); + await this.userInfo.openMoreActions(); + await this.userInfo.menu.selectMenuItem(action); + } + + async ignoreUser(username: string) { + await this.ignoreUserAction('Ignore', username); + } + + async unignoreUser(username: string) { + await this.ignoreUserAction('Unignore', username); + } + + async confirmRemoveUser() { + return this.removeModal.confirmRemove(); + } +} diff --git a/apps/meteor/tests/e2e/page-objects/fragments/home-flextab-notificationPreferences.ts b/apps/meteor/tests/e2e/page-objects/fragments/flextabs/notification-preferences-flextab.ts similarity index 53% rename from apps/meteor/tests/e2e/page-objects/fragments/home-flextab-notificationPreferences.ts rename to apps/meteor/tests/e2e/page-objects/fragments/flextabs/notification-preferences-flextab.ts index 9a38571b32898..30d9f6516b18f 100644 --- a/apps/meteor/tests/e2e/page-objects/fragments/home-flextab-notificationPreferences.ts +++ b/apps/meteor/tests/e2e/page-objects/fragments/flextabs/notification-preferences-flextab.ts @@ -1,34 +1,30 @@ import type { Locator, Page } from '@playwright/test'; -export class HomeFlextabNotificationPreferences { - private readonly page: Page; +import { FlexTab } from './flextab'; +import { Listbox } from '../listbox'; - constructor(page: Page) { - this.page = page; - } +export class NotificationPreferencesFlexTab extends FlexTab { + readonly listbox: Listbox; - get btnSave(): Locator { - return this.page.locator('role=button[name="Save"]'); - } - - get dialogNotificationPreferences(): Locator { - return this.page.getByRole('dialog', { name: 'Notifications Preferences' }); + constructor(page: Page) { + super(page.getByRole('dialog', { name: 'Notifications Preferences' })); + this.listbox = new Listbox(page); } getPreferenceByDevice(device: string): Locator { - return this.page.locator(`//div[@id="${device}Alert"]`); + return this.root.locator(`//div[@id="${device}Alert"]`); } async selectDropdownById(text: string): Promise { - await this.dialogNotificationPreferences.locator(`//div[@id="${text}"]`).click(); + await this.root.locator(`//div[@id="${text}"]`).click(); } async selectOptionByLabel(text: string): Promise { - await this.page.getByRole('listbox').getByRole('option', { name: text }).click(); + await this.listbox.selectOption(text); } async selectDevice(text: string): Promise { - await this.dialogNotificationPreferences.getByRole('button', { name: text }).click(); + await this.root.getByRole('button', { name: text }).click(); } async updateDevicePreference(device: string): Promise { diff --git a/apps/meteor/tests/e2e/page-objects/fragments/flextabs/prune-messages-flextab.ts b/apps/meteor/tests/e2e/page-objects/fragments/flextabs/prune-messages-flextab.ts new file mode 100644 index 0000000000000..33e1d23a667ab --- /dev/null +++ b/apps/meteor/tests/e2e/page-objects/fragments/flextabs/prune-messages-flextab.ts @@ -0,0 +1,37 @@ +import type { Locator, Page } from '@playwright/test'; + +import { FlexTab } from './flextab'; +import { Modal } from '../modals/modal'; + +class ConfirmPruneMessageModal extends Modal { + constructor(page: Page) { + super(page.getByRole('dialog', { name: 'Are you sure?' })); + } + + async pruneConfirm(): Promise { + await this.root.getByRole('button', { name: 'Yes, prune them!' }).click(); + await this.waitForDismissal(); + } +} + +export class PruneMessagesFlexTab extends FlexTab { + readonly confirmPruneModal: ConfirmPruneMessageModal; + + constructor(page: Page) { + super(page.getByRole('dialog', { name: 'Prune Messages' })); + this.confirmPruneModal = new ConfirmPruneMessageModal(page); + } + + get labelDoNotPrunePinned(): Locator { + return this.root.locator('label', { hasText: 'Do not prune pinned messages' }); + } + + get labelFilesOnly(): Locator { + return this.root.locator('label', { hasText: 'Only remove the attached files, keep messages' }); + } + + async prune(): Promise { + await this.root.getByRole('button', { name: 'Prune' }).click(); + await this.confirmPruneModal.pruneConfirm(); + } +} diff --git a/apps/meteor/tests/e2e/page-objects/fragments/flextabs/room-info-flextab.ts b/apps/meteor/tests/e2e/page-objects/fragments/flextabs/room-info-flextab.ts new file mode 100644 index 0000000000000..e3b5ecea39464 --- /dev/null +++ b/apps/meteor/tests/e2e/page-objects/fragments/flextabs/room-info-flextab.ts @@ -0,0 +1,135 @@ +import type { Locator, Page } from '@playwright/test'; + +import { FlexTab } from './flextab'; +import { MenuMore } from '../menu'; +import { ConfirmDeleteTeamModal } from '../modals'; +import { Modal } from '../modals/modal'; + +class ConfirmLeaveRoomModal extends Modal { + constructor(page: Page) { + super(page.getByRole('dialog', { name: 'Confirmation', exact: true })); + } + + private get btnLeave() { + return this.root.getByRole('button', { name: 'Leave', exact: true }); + } + + async confirmLeave() { + await this.btnLeave.click(); + await this.waitForDismissal(); + } +} + +class ConfirmDeleteRoomModal extends Modal { + constructor(page: Page) { + super(page.getByRole('dialog', { name: 'Delete' })); + } + + private get btnDelete() { + return this.root.getByRole('button', { name: 'Yes, delete', exact: true }); + } + + async confirmDelete() { + await this.btnDelete.click(); + await this.waitForDismissal(); + } +} + +export class RoomInfoFlexTab extends FlexTab { + readonly menu: MenuMore; + + readonly confirmLeaveModal: ConfirmLeaveRoomModal; + + readonly confirmDeleteModal: ConfirmDeleteRoomModal; + + constructor(root: Locator, page: Page) { + super(root); + this.menu = new MenuMore(page); + this.confirmLeaveModal = new ConfirmLeaveRoomModal(page); + this.confirmDeleteModal = new ConfirmDeleteRoomModal(page); + } + + get btnEdit(): Locator { + return this.root.getByRole('button', { name: 'Edit' }); + } + + get btnLeave(): Locator { + return this.root.getByRole('button', { name: 'Leave' }); + } + + get btnMore(): Locator { + return this.root.getByRole('button', { name: 'More' }); + } + + get optionDelete(): Locator { + return this.menu.getMenuItem('Delete'); + } + + async leaveRoom() { + await this.btnLeave.click(); + await this.confirmLeaveModal.confirmLeave(); + } + + async deleteRoom() { + await this.btnMore.click(); + await this.menu.selectMenuItem('Delete'); + await this.confirmDeleteModal.confirmDelete(); + } +} + +class ConfirmConvertIntoChannelModal extends Modal { + constructor(page: Page) { + super(page.getByRole('dialog', { name: 'Confirmation', exact: true })); + } + + private get btnConvert() { + return this.root.getByRole('button', { name: 'Convert', exact: true }); + } + + async confirmConvert() { + await this.btnConvert.click(); + await this.waitForDismissal(); + } +} + +export class TeamInfoFlexTab extends RoomInfoFlexTab { + readonly confirmDeleteTeamModal: ConfirmDeleteTeamModal; + + readonly confirmConvertIntoChannelModal: ConfirmConvertIntoChannelModal; + + constructor(page: Page) { + super(page.getByRole('dialog', { name: 'Team info' }), page); + this.confirmDeleteTeamModal = new ConfirmDeleteTeamModal(page); + this.confirmConvertIntoChannelModal = new ConfirmConvertIntoChannelModal(page); + } + + async deleteTeam() { + await this.btnMore.click(); + await this.menu.selectMenuItem('Delete'); + return this.confirmDeleteTeamModal.confirmDelete(); + } + + async convertIntoChannel() { + await this.btnMore.click(); + await this.menu.selectMenuItem('Convert to Channel'); + await this.confirmConvertIntoChannelModal.confirmConvert(); + } +} + +export class OmnichannelRoomInfoFlexTab extends RoomInfoFlexTab { + getInfo(value: string): Locator { + return this.root.locator(`span >> text="${value}"`); + } + + getLabel(label: string): Locator { + return this.root.locator(`div >> text="${label}"`); + } + + getInfoByLabel(label: string): Locator { + return this.root.getByLabel(label); + } + + getTagInfoByLabel(label: string): Locator { + return this.root.getByRole('list', { name: 'Tags' }).getByText(label, { exact: true }); + } +} diff --git a/apps/meteor/tests/e2e/page-objects/fragments/searchMessages-flextab.ts b/apps/meteor/tests/e2e/page-objects/fragments/flextabs/search-messages-flextab.ts similarity index 100% rename from apps/meteor/tests/e2e/page-objects/fragments/searchMessages-flextab.ts rename to apps/meteor/tests/e2e/page-objects/fragments/flextabs/search-messages-flextab.ts diff --git a/apps/meteor/tests/e2e/page-objects/fragments/flextabs/threads-flextab.ts b/apps/meteor/tests/e2e/page-objects/fragments/flextabs/threads-flextab.ts new file mode 100644 index 0000000000000..a1f3e3d5a71cd --- /dev/null +++ b/apps/meteor/tests/e2e/page-objects/fragments/flextabs/threads-flextab.ts @@ -0,0 +1,17 @@ +import type { Locator, Page } from '@playwright/test'; + +import { FlexTab } from './flextab'; + +export class ThreadsFlexTab extends FlexTab { + constructor(page: Page) { + super(page.getByRole('dialog')); + } + + private get listThreadMessages(): Locator { + return this.root.getByRole('list', { name: 'Thread message list' }); + } + + get lastThreadMessage(): Locator { + return this.listThreadMessages.locator('[data-qa-type="message"]').last().locator('[data-qa-type="message-body"]'); + } +} diff --git a/apps/meteor/tests/e2e/page-objects/fragments/user-info-flextab.ts b/apps/meteor/tests/e2e/page-objects/fragments/flextabs/user-info-flextab.ts similarity index 76% rename from apps/meteor/tests/e2e/page-objects/fragments/user-info-flextab.ts rename to apps/meteor/tests/e2e/page-objects/fragments/flextabs/user-info-flextab.ts index 249fb15c35eae..43fc1b626ed68 100644 --- a/apps/meteor/tests/e2e/page-objects/fragments/user-info-flextab.ts +++ b/apps/meteor/tests/e2e/page-objects/fragments/flextabs/user-info-flextab.ts @@ -1,7 +1,7 @@ import type { Locator, Page } from '@playwright/test'; import { FlexTab } from './flextab'; -import { MenuMore } from './menu'; +import { MenuMore } from '../menu'; export class UserInfoFlexTab extends FlexTab { readonly menu: MenuMore; @@ -22,4 +22,12 @@ export class UserInfoFlexTab extends FlexTab { get menuItemDeleteUser(): Locator { return this.menu.root.getByRole('menuitem', { name: 'Delete' }); } + + get userName(): Locator { + return this.root.getByLabel('Username'); + } + + async openMoreActions() { + await this.btnMoreActions.click(); + } } diff --git a/apps/meteor/tests/e2e/page-objects/fragments/home-content.ts b/apps/meteor/tests/e2e/page-objects/fragments/home-content.ts index eba1a2f986a26..0a18065a8a715 100644 --- a/apps/meteor/tests/e2e/page-objects/fragments/home-content.ts +++ b/apps/meteor/tests/e2e/page-objects/fragments/home-content.ts @@ -291,14 +291,6 @@ export class HomeContent { return this.primaryRoomActionsToolbar.getByRole('button', { name: 'Voice call' }); } - get userCard(): Locator { - return this.page.getByRole('dialog', { name: 'User card', exact: true }); - } - - get linkUserCard(): Locator { - return this.userCard.locator('a'); - } - get btnContactInformation(): Locator { return this.page.getByRole('button', { name: 'User Info' }); } diff --git a/apps/meteor/tests/e2e/page-objects/fragments/home-flextab-channels.ts b/apps/meteor/tests/e2e/page-objects/fragments/home-flextab-channels.ts deleted file mode 100644 index 7b95c17d14c49..0000000000000 --- a/apps/meteor/tests/e2e/page-objects/fragments/home-flextab-channels.ts +++ /dev/null @@ -1,57 +0,0 @@ -import type { Locator, Page } from '@playwright/test'; - -export class HomeFlextabChannels { - private readonly page: Page; - - constructor(page: Page) { - this.page = page; - } - - get channelsTab(): Locator { - return this.page.getByRole('dialog', { exact: true }); - } - - get btnAddExisting(): Locator { - return this.page.locator('button >> text="Add Existing"'); - } - - get btnCreateNew(): Locator { - return this.page.locator('button >> text="Create new"'); - } - - get inputChannels(): Locator { - return this.page.locator('#modal-root').getByRole('dialog').getByRole('textbox'); - } - - get btnAdd(): Locator { - return this.page.locator('role=dialog >> role=group >> role=button[name=Add]'); - } - - get channelsList(): Locator { - return this.channelsTab.getByRole('list'); - } - - getListboxOption(name: string): Locator { - return this.page.getByRole('listbox').getByRole('option', { name }); - } - - channelOption(name: string) { - return this.channelsTab.locator('li', { hasText: name }); - } - - async openChannelOptionMoreActions(name: string) { - await this.channelOption(name).hover(); - await this.channelOption(name).locator('role=button[name="More"]').click(); - } - - async confirmRemoveChannel() { - return this.page - .getByRole('dialog', { name: 'Are you sure?', exact: true }) - .getByRole('button', { name: 'Remove', exact: true }) - .click(); - } - - async confirmDeleteRoom() { - return this.page.getByRole('button', { name: 'Yes, delete', exact: true }).click(); - } -} diff --git a/apps/meteor/tests/e2e/page-objects/fragments/home-flextab-members.ts b/apps/meteor/tests/e2e/page-objects/fragments/home-flextab-members.ts deleted file mode 100644 index d23622e7d70f5..0000000000000 --- a/apps/meteor/tests/e2e/page-objects/fragments/home-flextab-members.ts +++ /dev/null @@ -1,91 +0,0 @@ -import type { Page } from '@playwright/test'; - -export class HomeFlextabMembers { - private readonly page: Page; - - constructor(page: Page) { - this.page = page; - } - - memberOption(username: string) { - return this.page.getByRole('dialog').locator('li', { hasText: username }); - } - - async openMemberInfo(username: string) { - await this.memberOption(username).click(); - } - - getMenuItemAction(action: string) { - return this.page.locator(`role=menuitem[name="${action}"]`); - } - - async openMoreActions() { - await this.page.locator('role=button[name="More"]').click(); - } - - async openMemberOptionMoreActions(username: string) { - await this.memberOption(username).hover(); - await this.memberOption(username).locator('role=button[name="More"]').click(); - } - - async addUser(username: string) { - await this.page.locator('role=button[name="Add"]').click(); - await this.page.getByRole('textbox', { name: 'Choose users' }).pressSequentially(username); - await this.page.getByRole('option', { name: username }).click(); - await this.page.locator('role=button[name="Add users"]').click(); - } - - async inviteUser() { - await this.page.locator('role=button[name="Invite Link"]').click(); - } - - async muteUser(username: string) { - await this.openMemberOptionMoreActions(username); - await this.getMenuItemAction('Mute user').click(); - await this.page.locator('.rcx-modal .rcx-button--danger').click(); - await this.page.getByRole('dialog').getByRole('button').first().click(); - } - - async unmuteUser(username: string) { - await this.openMemberOptionMoreActions(username); - await this.getMenuItemAction('Unmute user').click(); - } - - async setUserAsModerator(username: string) { - await this.openMemberOptionMoreActions(username); - await this.getMenuItemAction('Set as moderator').click(); - } - - async setUserAsOwner(username: string) { - await this.openMemberOptionMoreActions(username); - await this.getMenuItemAction('Set as owner').click(); - } - - async showAllUsers() { - const selectInput = this.page.getByRole('button', { name: 'Online' }); - await selectInput.click(); - await this.page.getByRole('listbox').getByRole('option', { name: 'All' }).click(); - } - - private async ignoreUserAction(action: string, username: string) { - await this.openMemberInfo(username); - await this.openMoreActions(); - await this.getMenuItemAction(action).click(); - } - - async ignoreUser(username: string) { - await this.ignoreUserAction('Ignore', username); - } - - async unignoreUser(username: string) { - await this.ignoreUserAction('Unignore', username); - } - - get confirmRemoveUserModal() { - return this.page.getByRole('dialog', { name: 'Confirmation', exact: true }); - } - - async confirmRemoveUser() { - return this.confirmRemoveUserModal.getByRole('button', { name: 'Remove', exact: true }).click(); - } -} diff --git a/apps/meteor/tests/e2e/page-objects/fragments/home-flextab-pruneMessages.ts b/apps/meteor/tests/e2e/page-objects/fragments/home-flextab-pruneMessages.ts deleted file mode 100644 index d73896abbf9ba..0000000000000 --- a/apps/meteor/tests/e2e/page-objects/fragments/home-flextab-pruneMessages.ts +++ /dev/null @@ -1,29 +0,0 @@ -import type { Locator, Page } from '@playwright/test'; - -export class HomeFlextabPruneMessages { - private readonly page: Page; - - constructor(page: Page) { - this.page = page; - } - - private get form(): Locator { - return this.page.getByRole('dialog', { name: 'Prune Messages' }); - } - - get doNotPrunePinned(): Locator { - return this.form.getByRole('checkbox', { name: 'Do not prune pinned messages', exact: true }); - } - - get filesOnly(): Locator { - return this.form.getByRole('checkbox', { name: 'Only remove the attached files, keep messages', exact: true }); - } - - async prune(): Promise { - await this.form.getByRole('button', { name: 'Prune' }).click(); - return this.page - .getByRole('dialog', { name: 'Are you sure?', exact: true }) - .getByRole('button', { name: 'Yes, prune them!', exact: true }) - .click(); - } -} diff --git a/apps/meteor/tests/e2e/page-objects/fragments/home-flextab-room.ts b/apps/meteor/tests/e2e/page-objects/fragments/home-flextab-room.ts deleted file mode 100644 index 308c46681d0e2..0000000000000 --- a/apps/meteor/tests/e2e/page-objects/fragments/home-flextab-room.ts +++ /dev/null @@ -1,134 +0,0 @@ -import type { Locator, Page } from '@playwright/test'; - -export class HomeFlextabRoom { - private readonly page: Page; - - constructor(page: Page) { - this.page = page; - } - - get btnEdit(): Locator { - return this.page.locator('role=button[name="Edit"]'); - } - - get btnLeave(): Locator { - return this.page.locator('role=button[name="Leave"]'); - } - - get btnMore(): Locator { - return this.page.locator('role=button[name="More"]'); - } - - getMoreOption(option: string) { - return this.page.locator(`role=menuitem[name="${option}"]`); - } - - get confirmLeaveModal(): Locator { - return this.page.getByRole('dialog', { name: 'Confirmation', exact: true }); - } - - async confirmLeave() { - return this.confirmLeaveModal.getByRole('button', { name: 'Leave', exact: true }).click(); - } - - get confirmDeleteTeamModal(): Locator { - return this.page.getByRole('dialog', { name: 'Delete team', exact: true }); - } - - get confirmDeleteDiscussionModal(): Locator { - return this.page.getByRole('dialog', { name: 'Delete discussion', exact: true }); - } - - async confirmDeleteTeam() { - return this.confirmDeleteTeamModal.getByRole('button', { name: 'Yes, delete', exact: true }).click(); - } - - async confirmDeleteDiscussion() { - return this.confirmDeleteDiscussionModal.getByRole('button', { name: 'Yes, delete', exact: true }).click(); - } - - get confirmConvertModal(): Locator { - return this.page.getByRole('dialog', { name: 'Confirmation', exact: true }); - } - - async confirmConvert() { - return this.confirmConvertModal.getByRole('button', { name: 'Convert', exact: true }).click(); - } - - get optionDelete(): Locator { - return this.page.locator('label[data-key="delete"]'); - } - - get inputName(): Locator { - return this.page.getByRole('dialog').getByRole('textbox', { name: 'Name' }); - } - - get inputTopic(): Locator { - return this.page.getByRole('dialog').getByRole('textbox', { name: 'Topic' }); - } - - get inputAnnouncement(): Locator { - return this.page.getByRole('dialog').getByRole('textbox', { name: 'Announcement' }); - } - - get inputDescription(): Locator { - return this.page.getByRole('dialog').getByRole('textbox', { name: 'Description' }); - } - - get checkboxReadOnly(): Locator { - return this.page.locator('label', { has: this.page.getByRole('checkbox', { name: 'Read-only' }) }); - } - - get btnSave(): Locator { - return this.page.locator('role=button[name="Save"]'); - } - - get calloutRetentionPolicy(): Locator { - return this.page.getByRole('dialog').getByRole('alert', { name: 'Retention policy warning callout' }); - } - - get advancedSettingsAccordion(): Locator { - return this.page.getByRole('dialog').getByRole('button', { name: 'Advanced settings' }); - } - - get pruneAccordion(): Locator { - return this.page.getByRole('dialog').getByRole('button', { name: 'Prune', exact: true }); - } - - getMaxAgeLabel(maxAge = '30') { - return this.page.getByRole('dialog').getByText(`Maximum message age in days (default: ${maxAge})`); - } - - get inputRetentionMaxAge(): Locator { - return this.page.getByRole('dialog').locator('input[name="retentionMaxAge"]'); - } - - get checkboxPruneMessages(): Locator { - return this.page - .getByRole('dialog') - .locator('label', { has: this.page.getByRole('checkbox', { name: 'Automatically prune old messages' }) }); - } - - get checkboxOverrideGlobalRetention(): Locator { - return this.page - .getByRole('dialog') - .locator('label', { has: this.page.getByRole('checkbox', { name: 'Override global retention policy' }) }); - } - - get checkboxIgnoreThreads(): Locator { - return this.page.getByRole('dialog').locator('label', { has: this.page.getByRole('checkbox', { name: 'Do not prune Threads' }) }); - } - - get checkboxChannels(): Locator { - return this.page.getByRole('dialog').locator('label', { has: this.page.getByRole('checkbox', { name: 'Channels' }) }); - } - - get checkboxDiscussions(): Locator { - return this.page.getByRole('dialog').locator('label', { has: this.page.getByRole('checkbox', { name: 'Discussions' }) }); - } - - async toggleSidepanelItems() { - await this.checkboxChannels.click(); - await this.checkboxDiscussions.click(); - } -} diff --git a/apps/meteor/tests/e2e/page-objects/fragments/home-flextab.ts b/apps/meteor/tests/e2e/page-objects/fragments/home-flextab.ts deleted file mode 100644 index 07d50efb0fc51..0000000000000 --- a/apps/meteor/tests/e2e/page-objects/fragments/home-flextab.ts +++ /dev/null @@ -1,86 +0,0 @@ -import type { Locator, Page } from '@playwright/test'; - -import { ExportMessagesTab } from './export-messages-tab'; -import { HomeFlextabChannels } from './home-flextab-channels'; -import { HomeFlextabMembers } from './home-flextab-members'; -import { HomeFlextabNotificationPreferences } from './home-flextab-notificationPreferences'; -import { HomeFlextabPruneMessages } from './home-flextab-pruneMessages'; -import { HomeFlextabRoom } from './home-flextab-room'; -import { SearchMessagesFlexTab } from './searchMessages-flextab'; - -export class HomeFlextab { - private readonly page: Page; - - readonly members: HomeFlextabMembers; - - readonly room: HomeFlextabRoom; - - readonly channels: HomeFlextabChannels; - - readonly notificationPreferences: HomeFlextabNotificationPreferences; - - readonly exportMessages: ExportMessagesTab; - - readonly pruneMessages: HomeFlextabPruneMessages; - - readonly searchMessages: SearchMessagesFlexTab; - - constructor(page: Page) { - this.page = page; - this.members = new HomeFlextabMembers(page); - this.room = new HomeFlextabRoom(page); - this.channels = new HomeFlextabChannels(page); - this.notificationPreferences = new HomeFlextabNotificationPreferences(page); - this.exportMessages = new ExportMessagesTab(page); - this.pruneMessages = new HomeFlextabPruneMessages(page); - this.searchMessages = new SearchMessagesFlexTab(page); - } - - get toolbarPrimaryActions(): Locator { - return this.page.getByRole('toolbar', { name: 'Primary Room actions' }); - } - - get btnTeamMembers(): Locator { - return this.page.locator('role=menuitem[name="Teams Members"]'); - } - - get kebab(): Locator { - return this.toolbarPrimaryActions.locator('role=button[name="Options"]'); - } - - get btnNotificationPreferences(): Locator { - return this.page.locator('role=menuitem[name="Notifications Preferences"]'); - } - - get btnExportMessages(): Locator { - return this.page.locator('role=menuitem[name="Export messages"]'); - } - - get btnPruneMessages(): Locator { - return this.page.getByRole('menuitem', { name: 'Prune Messages' }); - } - - get btnDisableE2E(): Locator { - return this.page.locator('role=menuitem[name="Disable E2E encryption"]'); - } - - get btnEnableE2E(): Locator { - return this.page.locator('role=menuitem[name="Enable E2E encryption"]'); - } - - get flexTabViewThreadMessage(): Locator { - return this.page.locator('div.thread-list ul.thread [data-qa-type="message"]').last().locator('[data-qa-type="message-body"]'); - } - - get userInfoUsername(): Locator { - return this.page.locator('[data-qa="UserInfoUserName"]'); - } - - get btnPinnedMessagesList(): Locator { - return this.page.locator('[data-key="pinned-messages"]'); - } - - get btnStarredMessageList(): Locator { - return this.page.locator('[data-key="starred-messages"]'); - } -} diff --git a/apps/meteor/tests/e2e/page-objects/fragments/index.ts b/apps/meteor/tests/e2e/page-objects/fragments/index.ts index f6a076472ab99..60fa33fc2a8cb 100644 --- a/apps/meteor/tests/e2e/page-objects/fragments/index.ts +++ b/apps/meteor/tests/e2e/page-objects/fragments/index.ts @@ -1,14 +1,11 @@ -export * from './edit-user-flextab'; -export * from './user-info-flextab'; export * from './home-content'; export * from './home-omnichannel-content'; -export * from './home-flextab'; export * from './navbar'; export * from './sidebar'; export * from './sidepanel'; export * from './modals'; export * from './toast-messages'; -export * from './export-messages-tab'; export * from './menu'; export * from './toolbar'; export * from './composer'; +export * from './flextabs'; diff --git a/apps/meteor/tests/e2e/page-objects/fragments/modals/confirm-delete-modal.ts b/apps/meteor/tests/e2e/page-objects/fragments/modals/confirm-delete-modal.ts index 64967bbdf19ca..5fea3747648d3 100644 --- a/apps/meteor/tests/e2e/page-objects/fragments/modals/confirm-delete-modal.ts +++ b/apps/meteor/tests/e2e/page-objects/fragments/modals/confirm-delete-modal.ts @@ -17,6 +17,21 @@ export class ConfirmDeleteModal extends Modal { } } +export class ConfirmDeleteRoomModal extends Modal { + constructor(page: Page) { + super(page.getByRole('dialog', { name: 'Delete' })); + } + + get btnDelete() { + return this.root.getByRole('button', { name: 'Yes, delete', exact: true }); + } + + async confirmDelete() { + await this.btnDelete.click(); + await this.waitForDismissal(); + } +} + export class ConfirmDeleteDepartmentModal extends ConfirmDeleteModal { constructor(page: Page) { super(page.getByRole('dialog', { name: 'Delete Department?' })); @@ -31,3 +46,18 @@ export class ConfirmDeleteDepartmentModal extends ConfirmDeleteModal { await this.confirmDelete(); } } + +export class ConfirmDeleteTeamModal extends Modal { + constructor(page: Page) { + super(page.getByRole('dialog', { name: 'Delete team', exact: true })); + } + + private get btnDelete() { + return this.root.getByRole('button', { name: 'Yes, delete', exact: true }); + } + + async confirmDelete() { + await this.btnDelete.click(); + await this.waitForDismissal(); + } +} diff --git a/apps/meteor/tests/e2e/page-objects/fragments/modals/confirm-remove-modal.ts b/apps/meteor/tests/e2e/page-objects/fragments/modals/confirm-remove-modal.ts new file mode 100644 index 0000000000000..64557a24e3e18 --- /dev/null +++ b/apps/meteor/tests/e2e/page-objects/fragments/modals/confirm-remove-modal.ts @@ -0,0 +1,18 @@ +import type { Locator } from 'playwright-core'; + +import { Modal } from './modal'; + +export class ConfirmRemoveModal extends Modal { + constructor(root: Locator) { + super(root); + } + + get btnRemove() { + return this.root.getByRole('button', { name: 'Remove' }); + } + + async confirmRemove() { + await this.btnRemove.click(); + await this.waitForDismissal(); + } +} diff --git a/apps/meteor/tests/e2e/page-objects/fragments/modals/index.ts b/apps/meteor/tests/e2e/page-objects/fragments/modals/index.ts index 77c38b3dd78db..c5bc6bc2a9394 100644 --- a/apps/meteor/tests/e2e/page-objects/fragments/modals/index.ts +++ b/apps/meteor/tests/e2e/page-objects/fragments/modals/index.ts @@ -1,5 +1,6 @@ export * from './apps-modal'; export * from './confirm-delete-modal'; +export * from './confirm-remove-modal'; export * from './create-new-modal'; export * from './disable-room-encryption-modal'; export * from './edit-status-modal'; diff --git a/apps/meteor/tests/e2e/page-objects/fragments/room-info-flextab.ts b/apps/meteor/tests/e2e/page-objects/fragments/room-info-flextab.ts deleted file mode 100644 index 1983f8c6c57b7..0000000000000 --- a/apps/meteor/tests/e2e/page-objects/fragments/room-info-flextab.ts +++ /dev/null @@ -1,31 +0,0 @@ -import type { Locator, Page } from '@playwright/test'; - -import { FlexTab } from './flextab'; - -export class RoomInfoFlexTab extends FlexTab { - constructor(page: Page) { - super(page.getByRole('dialog', { name: 'Room Information' })); - } - - get btnEdit(): Locator { - return this.root.getByRole('button', { name: 'Edit' }); - } -} - -export class OmnichannelRoomInfoFlexTab extends RoomInfoFlexTab { - getInfo(value: string): Locator { - return this.root.locator(`span >> text="${value}"`); - } - - getLabel(label: string): Locator { - return this.root.locator(`div >> text="${label}"`); - } - - getInfoByLabel(label: string): Locator { - return this.root.getByLabel(label); - } - - getTagInfoByLabel(label: string): Locator { - return this.root.getByRole('list', { name: 'Tags' }).getByText(label, { exact: true }); - } -} diff --git a/apps/meteor/tests/e2e/page-objects/fragments/toolbar.ts b/apps/meteor/tests/e2e/page-objects/fragments/toolbar.ts index 104d39fc05a13..0216ebfc110b3 100644 --- a/apps/meteor/tests/e2e/page-objects/fragments/toolbar.ts +++ b/apps/meteor/tests/e2e/page-objects/fragments/toolbar.ts @@ -1,5 +1,6 @@ import type { Locator, Page } from '@playwright/test'; +import { MenuOptions } from './menu'; import { OmnichannelCloseChatModal, OmnichannelOnHoldModal } from './modals'; export abstract class Toolbar { @@ -11,18 +12,17 @@ export abstract class Toolbar { } export class RoomToolbar extends Toolbar { + readonly menu: MenuOptions; + constructor(page: Page) { super(page.getByRole('toolbar', { name: 'Primary Room actions' })); + this.menu = new MenuOptions(page); } get btnRoomInfo() { return this.root.getByRole('button', { name: 'Room Information' }); } - private get btnTeamInfo() { - return this.root.getByRole('button', { name: 'Team info' }); - } - get btnMembers() { return this.root.getByRole('button', { name: 'Members' }); } @@ -43,10 +43,6 @@ export class RoomToolbar extends Toolbar { return this.root.getByRole('button', { name: 'Discussions' }); } - private get btnTeamChannels(): Locator { - return this.root.getByRole('button', { name: 'Team Channels' }); - } - get btnThreads(): Locator { return this.root.getByRole('button', { name: 'Threads' }); } @@ -67,28 +63,40 @@ export class RoomToolbar extends Toolbar { return this.root.getByRole('button', { name: 'Disable E2E encryption' }); } + get menuItemExportMessages(): Locator { + return this.menu.getMenuItem('Export messages'); + } + get menuItemMentions(): Locator { - return this.root.getByRole('menuitem', { name: 'Mentions' }); + return this.menu.getMenuItem('Mentions'); } get menuItemStarredMessages(): Locator { - return this.root.getByRole('menuitem', { name: 'Starred Messages' }); + return this.menu.getMenuItem('Starred Messages'); } get menuItemPinnedMessages(): Locator { - return this.root.getByRole('menuitem', { name: 'Pinned Messages' }); + return this.menu.getMenuItem('Pinned Messages'); } get menuItemPruneMessages(): Locator { - return this.root.getByRole('menuitem', { name: 'Prune Messages' }); + return this.menu.getMenuItem('Prune Messages'); } - async openRoomInfo() { - await this.btnRoomInfo.click(); + get menuItemNotificationsPreferences(): Locator { + return this.menu.getMenuItem('Notifications Preferences'); } - async openTeamInfo() { - await this.btnTeamInfo.click(); + get menuItemDisabledE2EEncryption(): Locator { + return this.menu.getMenuItem('Disable E2E encryption'); + } + + get menuItemEnableE2EEncryption(): Locator { + return this.menu.getMenuItem('Enable E2E encryption'); + } + + async openRoomInfo() { + await this.btnRoomInfo.click(); } async openMembersTab() { @@ -99,12 +107,40 @@ export class RoomToolbar extends Toolbar { await this.btnUserInfo.click(); } + async openMoreOptions() { + await this.btnMoreOptions.click(); + } + + private get btnTeamChannels(): Locator { + return this.root.getByRole('button', { name: 'Team Channels' }); + } + async openTeamChannels() { await this.btnTeamChannels.click(); } +} - async openMoreOptions() { - await this.btnMoreOptions.click(); +export class TeamToolbar extends RoomToolbar { + private get menuItemTeamMembers() { + return this.menu.getMenuItem('Teams Members'); + } + + private get btnTeamInfo() { + return this.root.getByRole('button', { name: 'Team info' }); + } + + async openTeamMembers() { + await this.menuItemTeamMembers.click(); + } + + async openTeamInfo() { + await this.btnTeamInfo.click(); + } +} + +export class EncryptedRoomToolbar extends RoomToolbar { + get btnEnableE2EEncryption(): Locator { + return this.root.getByRole('button', { name: 'Enable E2E encryption' }); } } diff --git a/apps/meteor/tests/e2e/page-objects/fragments/user-card.ts b/apps/meteor/tests/e2e/page-objects/fragments/user-card.ts new file mode 100644 index 0000000000000..32c7ae4c96182 --- /dev/null +++ b/apps/meteor/tests/e2e/page-objects/fragments/user-card.ts @@ -0,0 +1,31 @@ +import type { Locator, Page } from '@playwright/test'; + +import { expect } from '../../utils/test'; + +export class UserCard { + readonly root: Locator; + + constructor(protected page: Page) { + this.root = page.getByRole('dialog', { name: 'User card', exact: true }); + } + + waitForDisplay() { + return expect(this.root).toBeVisible(); + } + + waitForDismissal() { + return expect(this.root).not.toBeVisible(); + } + + get btnSeeFullProfile(): Locator { + return this.root.getByRole('button', { name: 'See full profile', exact: true }); + } + + get imgUserCard(): Locator { + return this.root.locator('img'); + } + + async openUserInfo() { + await this.btnSeeFullProfile.click(); + } +} diff --git a/apps/meteor/tests/e2e/page-objects/home-channel.ts b/apps/meteor/tests/e2e/page-objects/home-channel.ts index 4efd3bcdc4303..da98c9b2302b8 100644 --- a/apps/meteor/tests/e2e/page-objects/home-channel.ts +++ b/apps/meteor/tests/e2e/page-objects/home-channel.ts @@ -1,7 +1,26 @@ import type { Locator, Page } from '@playwright/test'; -import { HomeContent, HomeFlextab, Navbar, Sidepanel, RoomSidebar, ToastMessages, RoomComposer, ThreadComposer } from './fragments'; +import { + HomeContent, + Navbar, + Sidepanel, + RoomSidebar, + ToastMessages, + RoomComposer, + ThreadComposer, + MembersFlexTab, + ChannelsFlexTab, + NotificationPreferencesFlexTab, + ExportMessagesFlexTab, + PruneMessagesFlexTab, + SearchMessagesFlexTab, + RoomInfoFlexTab, + ThreadsFlexTab, + EditRoomFlexTab, + UserInfoFlexTab, +} from './fragments'; import { RoomToolbar } from './fragments/toolbar'; +import { UserCard } from './fragments/user-card'; import { VoiceCalls } from './fragments/voice-calls'; export class HomeChannel { @@ -15,7 +34,20 @@ export class HomeChannel { readonly navbar: Navbar; - readonly tabs: HomeFlextab; + readonly userCard: UserCard; + + private _tabs: { + members: MembersFlexTab; + userInfo: UserInfoFlexTab; + room: RoomInfoFlexTab; + editRoom: EditRoomFlexTab; + channels: ChannelsFlexTab; + notificationPreferences: NotificationPreferencesFlexTab; + exportMessages: ExportMessagesFlexTab; + pruneMessages: PruneMessagesFlexTab; + searchMessages: SearchMessagesFlexTab; + threads: ThreadsFlexTab; + }; readonly roomToolbar: RoomToolbar; @@ -33,7 +65,19 @@ export class HomeChannel { this.sidebar = new RoomSidebar(page); this.sidepanel = new Sidepanel(page); this.navbar = new Navbar(page); - this.tabs = new HomeFlextab(page); + this.userCard = new UserCard(page); + this._tabs = { + members: new MembersFlexTab(page), + userInfo: new UserInfoFlexTab(page), + room: new RoomInfoFlexTab(page.getByRole('dialog', { name: 'Channel info' }), page), + editRoom: new EditRoomFlexTab(page.getByRole('dialog', { name: 'Edit channel' })), + channels: new ChannelsFlexTab(page), + notificationPreferences: new NotificationPreferencesFlexTab(page), + exportMessages: new ExportMessagesFlexTab(page), + pruneMessages: new PruneMessagesFlexTab(page), + searchMessages: new SearchMessagesFlexTab(page), + threads: new ThreadsFlexTab(page), + }; this.roomToolbar = new RoomToolbar(page); this.voiceCalls = new VoiceCalls(page); this.toastMessage = new ToastMessages(page); @@ -41,6 +85,10 @@ export class HomeChannel { this.threadComposer = new ThreadComposer(page); } + get tabs() { + return this._tabs; + } + goto() { return this.page.goto('/home'); } diff --git a/apps/meteor/tests/e2e/page-objects/home-discussion.ts b/apps/meteor/tests/e2e/page-objects/home-discussion.ts index 1088007bd9152..e6b407059a5a5 100644 --- a/apps/meteor/tests/e2e/page-objects/home-discussion.ts +++ b/apps/meteor/tests/e2e/page-objects/home-discussion.ts @@ -1,36 +1,11 @@ -import type { Locator, Page } from '@playwright/test'; +import type { Page } from '@playwright/test'; -import { HomeContent, HomeFlextab, Navbar } from './fragments'; - -export class HomeDiscussion { - private readonly page: Page; - - readonly content: HomeContent; - - readonly navbar: Navbar; - - readonly tabs: HomeFlextab; +import { RoomInfoFlexTab } from './fragments'; +import { HomeChannel } from './home-channel'; +export class HomeDiscussion extends HomeChannel { constructor(page: Page) { - this.page = page; - this.content = new HomeContent(page); - this.navbar = new Navbar(page); - this.tabs = new HomeFlextab(page); - } - - get inputChannelName(): Locator { - return this.page.locator('role=textbox[name="Parent channel or team"]'); - } - - get inputName(): Locator { - return this.page.locator('role=textbox[name="Name"]'); - } - - get inputMessage(): Locator { - return this.page.locator('role=textbox[name="Message"]'); - } - - get btnCreate(): Locator { - return this.page.locator('role=dialog >> role=group >> role=button[name="Create"]'); + super(page); + this.tabs.room = new RoomInfoFlexTab(page.getByRole('dialog', { name: 'Discussion Info' }), page); } } diff --git a/apps/meteor/tests/e2e/page-objects/home-omnichannel.ts b/apps/meteor/tests/e2e/page-objects/home-omnichannel.ts index ea7695d398bf5..fcd5ae0e82c5d 100644 --- a/apps/meteor/tests/e2e/page-objects/home-omnichannel.ts +++ b/apps/meteor/tests/e2e/page-objects/home-omnichannel.ts @@ -1,8 +1,8 @@ import type { Locator, Page } from '@playwright/test'; import { HomeOmnichannelContent, OmnichannelQuickActionsRoomToolbar, OmnichannelRoomToolbar, OmnichannelSidebar } from './fragments'; -import { OmnichannelEditRoomFlexTab } from './fragments/edit-room-flextab'; -import { OmnichannelRoomInfoFlexTab } from './fragments/room-info-flextab'; +import { OmnichannelEditRoomFlexTab } from './fragments/flextabs'; +import { OmnichannelRoomInfoFlexTab } from './fragments/flextabs/room-info-flextab'; import { HomeChannel } from './home-channel'; import { OmnichannelCannedResponses, @@ -39,7 +39,7 @@ export class HomeOmnichannel extends HomeChannel { this.cannedResponses = new OmnichannelCannedResponses(page); this.contacts = new OmnichannelContactCenterContacts(page); this.chats = new OmnichannelContactCenterChats(page); - this.roomInfo = new OmnichannelRoomInfoFlexTab(page); + this.roomInfo = new OmnichannelRoomInfoFlexTab(page.getByRole('dialog', { name: 'Room Information' }), page); this.quickActionsRoomToolbar = new OmnichannelQuickActionsRoomToolbar(page); this.content = new HomeOmnichannelContent(page); this.roomToolbar = new OmnichannelRoomToolbar(page); diff --git a/apps/meteor/tests/e2e/page-objects/home-team.ts b/apps/meteor/tests/e2e/page-objects/home-team.ts index 350daa7036de1..3fc7d1cea0062 100644 --- a/apps/meteor/tests/e2e/page-objects/home-team.ts +++ b/apps/meteor/tests/e2e/page-objects/home-team.ts @@ -1,28 +1,21 @@ -import type { Locator, Page } from '@playwright/test'; +import type { Page } from '@playwright/test'; +import { EditTeamFlexTab, TeamInfoFlexTab, TeamToolbar } from './fragments'; import { HomeChannel } from './home-channel'; -/** - * TODO: HomeTeam shouldn't exist since the rooms are the same - */ export class HomeTeam extends HomeChannel { + readonly headerToolbar: TeamToolbar; + constructor(page: Page) { super(page); + this.headerToolbar = new TeamToolbar(page); } - get inputTeamName(): Locator { - return this.page.locator('role=textbox[name="Name"]'); - } - - get btnTeamCreate(): Locator { - return this.page.locator('role=dialog >> role=group >> role=button[name=Create]'); - } - - get textPrivate(): Locator { - return this.page.locator('label', { has: this.page.getByRole('checkbox', { name: 'Private' }) }); - } - - get textReadOnly(): Locator { - return this.page.locator('label', { has: this.page.getByRole('checkbox', { name: 'Read-only' }) }); + override get tabs() { + return { + ...super.tabs, + room: new TeamInfoFlexTab(this.page), + editRoom: new EditTeamFlexTab(this.page), + }; } } diff --git a/apps/meteor/tests/e2e/page-objects/omnichannel/omnichannel-agents.ts b/apps/meteor/tests/e2e/page-objects/omnichannel/omnichannel-agents.ts index b40141802759c..cbbd40ba92912 100644 --- a/apps/meteor/tests/e2e/page-objects/omnichannel/omnichannel-agents.ts +++ b/apps/meteor/tests/e2e/page-objects/omnichannel/omnichannel-agents.ts @@ -1,7 +1,7 @@ import type { Locator, Page } from '@playwright/test'; import { OmnichannelAdmin } from './omnichannel-admin'; -import { FlexTab } from '../fragments/flextab'; +import { FlexTab } from '../fragments/flextabs/flextab'; import { Listbox } from '../fragments/listbox'; import { Table } from '../fragments/table'; diff --git a/apps/meteor/tests/e2e/page-objects/omnichannel/omnichannel-contact-center/omnichannel-contact-center-chats.ts b/apps/meteor/tests/e2e/page-objects/omnichannel/omnichannel-contact-center/omnichannel-contact-center-chats.ts index 3831bb49fb877..8168032b60cfb 100644 --- a/apps/meteor/tests/e2e/page-objects/omnichannel/omnichannel-contact-center/omnichannel-contact-center-chats.ts +++ b/apps/meteor/tests/e2e/page-objects/omnichannel/omnichannel-contact-center/omnichannel-contact-center-chats.ts @@ -1,7 +1,7 @@ import type { Locator, Page } from '@playwright/test'; import { OmnichannelContactCenter } from './omnichannel-contact-center'; -import { FlexTab } from '../../fragments/flextab'; +import { FlexTab } from '../../fragments/flextabs/flextab'; import { Listbox } from '../../fragments/listbox'; import { OmnichannelConfirmRemoveChat } from '../../fragments/modals'; import { Table } from '../../fragments/table'; diff --git a/apps/meteor/tests/e2e/page-objects/omnichannel/omnichannel-contact-center/omnichannel-contact-center-contacts.ts b/apps/meteor/tests/e2e/page-objects/omnichannel/omnichannel-contact-center/omnichannel-contact-center-contacts.ts index 00989c8510325..5f10e0dc0c1c0 100644 --- a/apps/meteor/tests/e2e/page-objects/omnichannel/omnichannel-contact-center/omnichannel-contact-center-contacts.ts +++ b/apps/meteor/tests/e2e/page-objects/omnichannel/omnichannel-contact-center/omnichannel-contact-center-contacts.ts @@ -3,7 +3,7 @@ import type { Locator, Page } from '@playwright/test'; import { OmnichannelContactInfo } from '../omnichannel-info'; import { OmnichannelContactCenter } from './omnichannel-contact-center'; import { MenuMoreActions } from '../../fragments'; -import { OmnichannelEditContactFlexTab } from '../../fragments/edit-contact-flaxtab'; +import { OmnichannelEditContactFlexTab } from '../../fragments/flextabs'; import { OmnichannelDeleteContactModal } from '../../fragments/modals'; import { Table } from '../../fragments/table'; diff --git a/apps/meteor/tests/e2e/page-objects/omnichannel/omnichannel-custom-fields.ts b/apps/meteor/tests/e2e/page-objects/omnichannel/omnichannel-custom-fields.ts index ca9fcf7ad26d0..25d10540d2590 100644 --- a/apps/meteor/tests/e2e/page-objects/omnichannel/omnichannel-custom-fields.ts +++ b/apps/meteor/tests/e2e/page-objects/omnichannel/omnichannel-custom-fields.ts @@ -1,7 +1,7 @@ import type { Locator, Page } from '@playwright/test'; import { OmnichannelAdmin } from './omnichannel-admin'; -import { FlexTab } from '../fragments/flextab'; +import { FlexTab } from '../fragments/flextabs/flextab'; import { Table } from '../fragments/table'; class OmnichannelManageCustomFieldsFlexTab extends FlexTab { diff --git a/apps/meteor/tests/e2e/page-objects/omnichannel/omnichannel-info.ts b/apps/meteor/tests/e2e/page-objects/omnichannel/omnichannel-info.ts index d911a81305d00..6bac8ecc4fe45 100644 --- a/apps/meteor/tests/e2e/page-objects/omnichannel/omnichannel-info.ts +++ b/apps/meteor/tests/e2e/page-objects/omnichannel/omnichannel-info.ts @@ -1,6 +1,6 @@ import type { Locator, Page } from '@playwright/test'; -import { FlexTab } from '../fragments/flextab'; +import { FlexTab } from '../fragments/flextabs/flextab'; import { OmnichannelContactReviewModal } from '../fragments/modals'; export class OmnichannelContactInfo extends FlexTab { diff --git a/apps/meteor/tests/e2e/page-objects/omnichannel/omnichannel-priorities.ts b/apps/meteor/tests/e2e/page-objects/omnichannel/omnichannel-priorities.ts index d458c9f4f3970..1b28c02c1fe44 100644 --- a/apps/meteor/tests/e2e/page-objects/omnichannel/omnichannel-priorities.ts +++ b/apps/meteor/tests/e2e/page-objects/omnichannel/omnichannel-priorities.ts @@ -2,7 +2,7 @@ import type { Page } from '@playwright/test'; import { OmnichannelAdmin } from './omnichannel-admin'; import { ToastMessages } from '../fragments'; -import { FlexTab } from '../fragments/flextab'; +import { FlexTab } from '../fragments/flextabs/flextab'; import { OmnichannelResetPrioritiesModal } from '../fragments/modals'; import { Table } from '../fragments/table'; diff --git a/apps/meteor/tests/e2e/page-objects/omnichannel/omnichannel-sla-policies.ts b/apps/meteor/tests/e2e/page-objects/omnichannel/omnichannel-sla-policies.ts index 62a06fe2d75cf..2c8d606c19fd0 100644 --- a/apps/meteor/tests/e2e/page-objects/omnichannel/omnichannel-sla-policies.ts +++ b/apps/meteor/tests/e2e/page-objects/omnichannel/omnichannel-sla-policies.ts @@ -1,7 +1,7 @@ import type { Locator, Page } from '@playwright/test'; import { OmnichannelAdmin } from './omnichannel-admin'; -import { FlexTab } from '../fragments/flextab'; +import { FlexTab } from '../fragments/flextabs/flextab'; import { Table } from '../fragments/table'; class OmnichannelManageSlaPolicyFlexTab extends FlexTab { diff --git a/apps/meteor/tests/e2e/page-objects/omnichannel/omnichannel-tags.ts b/apps/meteor/tests/e2e/page-objects/omnichannel/omnichannel-tags.ts index 4bf0212e25aad..a718a29e03e1c 100644 --- a/apps/meteor/tests/e2e/page-objects/omnichannel/omnichannel-tags.ts +++ b/apps/meteor/tests/e2e/page-objects/omnichannel/omnichannel-tags.ts @@ -1,7 +1,7 @@ import type { Locator, Page } from '@playwright/test'; import { OmnichannelAdmin } from './omnichannel-admin'; -import { FlexTab } from '../fragments/flextab'; +import { FlexTab } from '../fragments/flextabs/flextab'; import { Listbox } from '../fragments/listbox'; import { Table } from '../fragments/table'; diff --git a/apps/meteor/tests/e2e/page-objects/omnichannel/omnichannel-triggers.ts b/apps/meteor/tests/e2e/page-objects/omnichannel/omnichannel-triggers.ts index 9619671a2c140..16e3def384c8e 100644 --- a/apps/meteor/tests/e2e/page-objects/omnichannel/omnichannel-triggers.ts +++ b/apps/meteor/tests/e2e/page-objects/omnichannel/omnichannel-triggers.ts @@ -1,7 +1,7 @@ import type { Locator, Page } from '@playwright/test'; import { OmnichannelAdmin } from './omnichannel-admin'; -import { FlexTab } from '../fragments/flextab'; +import { FlexTab } from '../fragments/flextabs/flextab'; import { Listbox } from '../fragments/listbox'; import { Table } from '../fragments/table'; diff --git a/apps/meteor/tests/e2e/page-objects/omnichannel/omnichannel-units.ts b/apps/meteor/tests/e2e/page-objects/omnichannel/omnichannel-units.ts index 1ee38399ee639..32f5c03df6e10 100644 --- a/apps/meteor/tests/e2e/page-objects/omnichannel/omnichannel-units.ts +++ b/apps/meteor/tests/e2e/page-objects/omnichannel/omnichannel-units.ts @@ -1,7 +1,7 @@ import type { Locator, Page } from '@playwright/test'; import { OmnichannelAdmin } from './omnichannel-admin'; -import { FlexTab } from '../fragments/flextab'; +import { FlexTab } from '../fragments/flextabs/flextab'; import { Listbox } from '../fragments/listbox'; import { Table } from '../fragments/table'; diff --git a/apps/meteor/tests/e2e/prune-messages.spec.ts b/apps/meteor/tests/e2e/prune-messages.spec.ts index d56856bfff51c..8ca21efc5271d 100644 --- a/apps/meteor/tests/e2e/prune-messages.spec.ts +++ b/apps/meteor/tests/e2e/prune-messages.spec.ts @@ -56,35 +56,34 @@ test.describe('prune-messages', () => { }); await test.step('prune files only not pinned', async () => { - await pruneMessages.doNotPrunePinned.check({ force: true }); - await pruneMessages.filesOnly.check({ force: true }); + await pruneMessages.labelDoNotPrunePinned.click(); + await pruneMessages.labelFilesOnly.click(); await pruneMessages.prune(); await toastMessage.waitForDisplay({ type: 'success', message: '1 file pruned' }); await toastMessage.dismissToast(); - await expect(pruneMessages.filesOnly, 'Checkbox is reset after success').not.toBeChecked(); - await expect(pruneMessages.doNotPrunePinned, 'Checkbox is reset after success').not.toBeChecked(); + await expect(pruneMessages.labelFilesOnly, 'Checkbox is reset after success').not.toBeChecked(); + await expect(pruneMessages.labelDoNotPrunePinned, 'Checkbox is reset after success').not.toBeChecked(); }); await test.step('prune files only again', async () => { - await pruneMessages.doNotPrunePinned.check({ force: true }); - await pruneMessages.filesOnly.check({ force: true }); + await pruneMessages.labelDoNotPrunePinned.click(); + await pruneMessages.labelFilesOnly.click(); await pruneMessages.prune(); await toastMessage.waitForDisplay({ type: 'error', message: 'No files found to prune' }); await toastMessage.dismissToast('error'); - await expect(pruneMessages.filesOnly, 'Checkbox retains value after error').toBeChecked(); - await expect(pruneMessages.doNotPrunePinned, 'Checkbox retains value after error').toBeChecked(); + await expect(pruneMessages.labelFilesOnly, 'Checkbox retains value after error').toBeChecked(); + await expect(pruneMessages.labelDoNotPrunePinned, 'Checkbox retains value after error').toBeChecked(); }); await test.step('uncheck files only', async () => { - await pruneMessages.filesOnly.uncheck({ force: true }); + await pruneMessages.labelFilesOnly.click(); await pruneMessages.prune(); await toastMessage.waitForDisplay({ type: 'success', message: '2 messages pruned' }); await toastMessage.dismissToast(); - await expect(pruneMessages.filesOnly, 'Checkbox is reset after success').not.toBeChecked(); + await expect(pruneMessages.labelFilesOnly, 'Checkbox is reset after success').not.toBeChecked(); }); - await test.step('uncheck do not prune pinned', async () => { - await pruneMessages.doNotPrunePinned.uncheck({ force: true }); + await test.step('prune remained pinned message', async () => { await pruneMessages.prune(); await toastMessage.waitForDisplay({ type: 'success', message: '1 message pruned' }); await toastMessage.dismissToast(); @@ -115,12 +114,12 @@ test.describe('prune-messages', () => { await expect(content.lastMessageFileName).toHaveText('any_file.txt'); await test.step('prune files only', async () => { - await pruneMessages.filesOnly.check({ force: true }); + await pruneMessages.labelFilesOnly.click(); await pruneMessages.prune(); await toastMessage.waitForDisplay({ type: 'success', message: '1 file pruned' }); await toastMessage.dismissToast(); - await expect(pruneMessages.filesOnly, 'Checkbox is reset after success').not.toBeChecked(); - await expect(pruneMessages.doNotPrunePinned, 'Checkbox is reset after success').not.toBeChecked(); + await expect(pruneMessages.labelFilesOnly, 'Checkbox is reset after success').not.toBeChecked(); + await expect(pruneMessages.labelDoNotPrunePinned, 'Checkbox is reset after success').not.toBeChecked(); }); await test.step('check message list for prune message-attachment', async () => { diff --git a/apps/meteor/tests/e2e/retention-policy.spec.ts b/apps/meteor/tests/e2e/retention-policy.spec.ts index 35ab3b60b7678..f989f18b05147 100644 --- a/apps/meteor/tests/e2e/retention-policy.spec.ts +++ b/apps/meteor/tests/e2e/retention-policy.spec.ts @@ -3,7 +3,7 @@ import type { Page } from '@playwright/test'; import { createAuxContext } from './fixtures/createAuxContext'; import { Users } from './fixtures/userStates'; -import { HomeChannel } from './page-objects'; +import { HomeChannel, HomeTeam } from './page-objects'; import { createTargetTeam, createTargetPrivateChannel, getSettingValueById, setSettingValueById } from './utils'; import { test, expect } from './utils/test'; import { timeUnitToMs, TIMEUNIT } from '../../client/lib/convertTimeUnit'; @@ -53,7 +53,7 @@ test.describe.serial('retention-policy', () => { await poHomeChannel.roomToolbar.openRoomInfo(); await poHomeChannel.tabs.room.btnEdit.click(); - await expect(poHomeChannel.tabs.room.pruneAccordion).not.toBeVisible(); + await expect(poHomeChannel.tabs.editRoom.pruneAccordion).not.toBeVisible(); }); }); @@ -88,7 +88,7 @@ test.describe.serial('retention-policy', () => { await poHomeChannel.roomToolbar.openRoomInfo(); await poHomeChannel.tabs.room.btnEdit.click(); - await expect(poHomeChannel.tabs.room.pruneAccordion).toBeVisible(); + await expect(poHomeChannel.tabs.editRoom.pruneAccordion).toBeVisible(); }); test.describe('edit-room-retention-policy permission', async () => { @@ -104,13 +104,13 @@ test.describe.serial('retention-policy', () => { await auxContext.page.close(); }); test('should not show prune section in edit channel for users without permission', async () => { - await expect(poHomeChannel.tabs.room.pruneAccordion).not.toBeVisible(); + await expect(poHomeChannel.tabs.editRoom.pruneAccordion).not.toBeVisible(); }); test('users without permission should be able to edit the channel', async () => { - await auxContext.poHomeChannel.tabs.room.advancedSettingsAccordion.click(); - await auxContext.poHomeChannel.tabs.room.checkboxReadOnly.check(); - await auxContext.poHomeChannel.tabs.room.btnSave.click(); + await auxContext.poHomeChannel.tabs.editRoom.advancedSettingsAccordion.click(); + await auxContext.poHomeChannel.tabs.editRoom.checkboxReadOnly.check(); + await auxContext.poHomeChannel.tabs.editRoom.btnSave.click(); await expect(auxContext.poHomeChannel.content.getSystemMessageByText('set room to read only')).toBeVisible(); }); @@ -129,18 +129,19 @@ test.describe.serial('retention-policy', () => { await poHomeChannel.roomToolbar.openRoomInfo(); await poHomeChannel.tabs.room.btnEdit.click(); - await poHomeChannel.tabs.room.pruneAccordion.click(); - await expect(poHomeChannel.tabs.room.checkboxPruneMessages).toBeChecked(); + await poHomeChannel.tabs.editRoom.pruneAccordion.click(); + await expect(poHomeChannel.tabs.editRoom.checkboxPruneMessages).toBeChecked(); }); - test('should prune old messages checkbox enabled by default in team and show retention policy banner', async () => { - await poHomeChannel.navbar.openChat(targetTeam); - await expect(poHomeChannel.content.channelRetentionPolicyWarning).toBeVisible(); + test('should prune old messages checkbox enabled by default in team and show retention policy banner', async ({ page }) => { + const poHomeTeam = new HomeTeam(page); + await poHomeTeam.navbar.openChat(targetTeam); + await expect(poHomeTeam.content.channelRetentionPolicyWarning).toBeVisible(); - await poHomeChannel.roomToolbar.openTeamInfo(); - await poHomeChannel.tabs.room.btnEdit.click(); - await poHomeChannel.tabs.room.pruneAccordion.click(); - await expect(poHomeChannel.tabs.room.checkboxPruneMessages).toBeChecked(); + await poHomeTeam.headerToolbar.openTeamInfo(); + await poHomeTeam.tabs.room.btnEdit.click(); + await poHomeTeam.tabs.editRoom.pruneAccordion.click(); + await expect(poHomeTeam.tabs.editRoom.checkboxPruneMessages).toBeChecked(); }); test('should prune old messages checkbox enabled by default in group and show retention policy banner', async () => { @@ -149,8 +150,8 @@ test.describe.serial('retention-policy', () => { await poHomeChannel.roomToolbar.openRoomInfo(); await poHomeChannel.tabs.room.btnEdit.click(); - await poHomeChannel.tabs.room.pruneAccordion.click(); - await expect(poHomeChannel.tabs.room.checkboxPruneMessages).toBeChecked(); + await poHomeChannel.tabs.editRoom.pruneAccordion.click(); + await expect(poHomeChannel.tabs.editRoom.checkboxPruneMessages).toBeChecked(); }); test('should show retention policy banner in DMs', async () => { @@ -171,43 +172,43 @@ test.describe.serial('retention-policy', () => { await poHomeChannel.navbar.openChat(targetChannel); await poHomeChannel.roomToolbar.openRoomInfo(); await poHomeChannel.tabs.room.btnEdit.click(); - await poHomeChannel.tabs.room.pruneAccordion.click(); + await poHomeChannel.tabs.editRoom.pruneAccordion.click(); }); test('should display the default max age in edit channel', async () => { - await poHomeChannel.tabs.room.checkboxOverrideGlobalRetention.click(); + await poHomeChannel.tabs.editRoom.checkboxOverrideGlobalRetention.click(); - await expect(poHomeChannel.tabs.room.getMaxAgeLabel('15')).toBeVisible(); + await expect(poHomeChannel.tabs.editRoom.getMaxAgeLabel('15')).toBeVisible(); }); test('should display overridden retention max age value', async () => { - await poHomeChannel.tabs.room.checkboxOverrideGlobalRetention.click(); - await poHomeChannel.tabs.room.inputRetentionMaxAge.fill('365'); - await poHomeChannel.tabs.room.btnSave.click(); + await poHomeChannel.tabs.editRoom.checkboxOverrideGlobalRetention.click(); + await poHomeChannel.tabs.editRoom.inputRetentionMaxAge.fill('365'); + await poHomeChannel.tabs.editRoom.btnSave.click(); await poHomeChannel.toastMessage.dismissToast(); await poHomeChannel.roomToolbar.openRoomInfo(); await poHomeChannel.tabs.room.btnEdit.click(); - await poHomeChannel.tabs.room.pruneAccordion.click(); + await poHomeChannel.tabs.editRoom.pruneAccordion.click(); - await expect(poHomeChannel.tabs.room.getMaxAgeLabel('15')).toBeVisible(); - await expect(poHomeChannel.tabs.room.inputRetentionMaxAge).toHaveValue('365'); + await expect(poHomeChannel.tabs.editRoom.getMaxAgeLabel('15')).toBeVisible(); + await expect(poHomeChannel.tabs.editRoom.inputRetentionMaxAge).toHaveValue('365'); }); test('should ignore threads be checked accordingly with the global default value', async () => { - await expect(poHomeChannel.tabs.room.checkboxIgnoreThreads).toBeChecked({ checked: ignoreThreadsSetting }); + await expect(poHomeChannel.tabs.editRoom.checkboxIgnoreThreads).toBeChecked({ checked: ignoreThreadsSetting }); }); test('should override ignore threads default value', async () => { - await poHomeChannel.tabs.room.checkboxIgnoreThreads.click(); - await poHomeChannel.tabs.room.btnSave.click(); + await poHomeChannel.tabs.editRoom.checkboxIgnoreThreads.click(); + await poHomeChannel.tabs.editRoom.btnSave.click(); await poHomeChannel.toastMessage.dismissToast(); await poHomeChannel.roomToolbar.openRoomInfo(); await poHomeChannel.tabs.room.btnEdit.click(); - await poHomeChannel.tabs.room.pruneAccordion.click(); + await poHomeChannel.tabs.editRoom.pruneAccordion.click(); - await expect(poHomeChannel.tabs.room.checkboxIgnoreThreads).toBeChecked({ checked: !ignoreThreadsSetting }); + await expect(poHomeChannel.tabs.editRoom.checkboxIgnoreThreads).toBeChecked({ checked: !ignoreThreadsSetting }); }); }); }); diff --git a/apps/meteor/tests/e2e/team-management.spec.ts b/apps/meteor/tests/e2e/team-management.spec.ts index 81f76ef60e628..d6ceec5dab930 100644 --- a/apps/meteor/tests/e2e/team-management.spec.ts +++ b/apps/meteor/tests/e2e/team-management.spec.ts @@ -10,9 +10,11 @@ test.use({ storageState: Users.admin.state }); test.describe('teams-management-permissions', () => { let poHomeTeam: HomeTeam; + let newTeamModal: CreateNewTeamModal; test.beforeEach(async ({ page }) => { poHomeTeam = new HomeTeam(page); + newTeamModal = new CreateNewTeamModal(page); await page.goto('/home'); }); @@ -37,8 +39,8 @@ test.describe('teams-management-permissions', () => { await poHomeTeam.navbar.openCreate('Team'); - await expect(poHomeTeam.textPrivate).toBeDisabled(); - await expect(poHomeTeam.textPrivate).toBeChecked(); + await expect(newTeamModal.checkboxPrivate).toBeDisabled(); + await expect(newTeamModal.checkboxPrivate).toBeChecked(); }); test('should not allow to create private team if user does not have the create-p permission', async ({ api }) => { @@ -52,8 +54,8 @@ test.describe('teams-management-permissions', () => { await poHomeTeam.navbar.openCreate('Team'); - await expect(poHomeTeam.textPrivate).toBeDisabled(); - await expect(poHomeTeam.textPrivate).not.toBeChecked(); + await expect(newTeamModal.checkboxPrivate).toBeDisabled(); + await expect(newTeamModal.checkboxPrivate).not.toBeChecked(); }); test('should not allow to create team if user does not have both create-p and create-c permissions', async ({ api }) => { @@ -151,16 +153,16 @@ test.describe.serial('teams-management', () => { await page.locator('role=button[name="Reply in thread"]').click(); await page.locator('.rcx-vertical-bar').locator(`role=textbox[name="Message #${targetTeam}"]`).type('any-reply-message'); await page.keyboard.press('Enter'); - await expect(poHomeTeam.tabs.flexTabViewThreadMessage).toHaveText('any-reply-message'); + await expect(poHomeTeam.tabs.threads.lastThreadMessage).toHaveText('any-reply-message'); }); test('should set targetTeam as readonly', async () => { await poHomeTeam.navbar.openChat(targetTeam); - await poHomeTeam.roomToolbar.openTeamInfo(); + await poHomeTeam.headerToolbar.openTeamInfo(); await poHomeTeam.tabs.room.btnEdit.click(); - await poHomeTeam.tabs.room.advancedSettingsAccordion.click(); - await poHomeTeam.tabs.room.checkboxReadOnly.click(); - await poHomeTeam.tabs.room.btnSave.click(); + await poHomeTeam.tabs.editRoom.advancedSettingsAccordion.click(); + await poHomeTeam.tabs.editRoom.checkboxReadOnly.click(); + await poHomeTeam.tabs.editRoom.btnSave.click(); await expect(poHomeTeam.content.getSystemMessageByText('set room to read only')).toBeVisible(); }); @@ -171,7 +173,7 @@ test.describe.serial('teams-management', () => { ); await poHomeTeam.navbar.openChat(targetTeam); - await poHomeTeam.roomToolbar.openTeamChannels(); + await poHomeTeam.headerToolbar.openTeamChannels(); await expect(poHomeTeam.tabs.channels.btnAddExisting).not.toBeVisible(); }); @@ -190,7 +192,7 @@ test.describe.serial('teams-management', () => { ).toBe(200); await poHomeTeam.navbar.openChat(targetTeam); - await poHomeTeam.roomToolbar.openTeamChannels(); + await poHomeTeam.headerToolbar.openTeamChannels(); await expect(poHomeTeam.tabs.channels.btnCreateNew).not.toBeVisible(); }); @@ -209,7 +211,7 @@ test.describe.serial('teams-management', () => { ).toBe(200); await poHomeTeam.navbar.openChat(targetTeam); - await poHomeTeam.roomToolbar.openTeamChannels(); + await poHomeTeam.headerToolbar.openTeamChannels(); await expect(poHomeTeam.tabs.channels.btnCreateNew).toBeVisible(); await poHomeTeam.tabs.channels.btnCreateNew.click(); @@ -236,7 +238,7 @@ test.describe.serial('teams-management', () => { ).toBe(200); await poHomeTeam.navbar.openChat(targetTeam); - await poHomeTeam.roomToolbar.openTeamChannels(); + await poHomeTeam.headerToolbar.openTeamChannels(); await expect(poHomeTeam.tabs.channels.btnCreateNew).toBeVisible(); await poHomeTeam.tabs.channels.btnCreateNew.click(); @@ -249,15 +251,12 @@ test.describe.serial('teams-management', () => { await expect(poHomeTeam.tabs.channels.channelsList).toContainText(targetGroupNameInTeam); }); - test('should move targetChannel to targetTeam', async ({ page, api }) => { + test('should move targetChannel to targetTeam', async ({ api }) => { expect((await api.post('/permissions.update', { permissions: [{ _id: 'move-room-to-team', roles: ['owner'] }] })).status()).toBe(200); await poHomeTeam.navbar.openChat(targetTeam); - await poHomeTeam.roomToolbar.openTeamChannels(); - await poHomeTeam.tabs.channels.btnAddExisting.click(); - await poHomeTeam.tabs.channels.inputChannels.fill(targetChannel); - await page.locator(`.rcx-option__content:has-text("${targetChannel}")`).click(); - await poHomeTeam.tabs.channels.btnAdd.click(); + await poHomeTeam.headerToolbar.openTeamChannels(); + await poHomeTeam.tabs.channels.addExistingChannel(targetChannel); await expect(poHomeTeam.tabs.channels.channelsList).toContainText(targetChannel); }); @@ -280,7 +279,7 @@ test.describe.serial('teams-management', () => { ); await poHomeTeam.navbar.openChat(targetTeam); - await poHomeTeam.roomToolbar.openTeamChannels(); + await poHomeTeam.headerToolbar.openTeamChannels(); await poHomeTeam.tabs.channels.openChannelOptionMoreActions(targetGroupNameInTeam); await expect(page.getByRole('menu', { exact: true }).getByRole('menuitem', { name: 'Remove from team' })).not.toBeVisible(); }); @@ -289,7 +288,7 @@ test.describe.serial('teams-management', () => { expect((await api.post('/permissions.update', { permissions: [{ _id: 'remove-team-channel', roles: ['owner'] }] })).status()).toBe(200); await poHomeTeam.navbar.openChat(targetTeam); - await poHomeTeam.roomToolbar.openTeamChannels(); + await poHomeTeam.headerToolbar.openTeamChannels(); await poHomeTeam.tabs.channels.openChannelOptionMoreActions(targetGroupNameInTeam); await expect(page.getByRole('menu', { exact: true }).getByRole('menuitem', { name: 'Remove from team' })).toBeVisible(); await page.getByRole('menu', { exact: true }).getByRole('menuitem', { name: 'Remove from team' }).click(); @@ -315,11 +314,8 @@ test.describe.serial('teams-management', () => { // re-add channel to team await poHomeTeam.navbar.openChat(targetTeam); - await poHomeTeam.roomToolbar.openTeamChannels(); - await poHomeTeam.tabs.channels.btnAddExisting.click(); - await poHomeTeam.tabs.channels.inputChannels.fill(targetGroupNameInTeam); - await page.locator(`.rcx-option__content:has-text("${targetGroupNameInTeam}")`).click(); - await poHomeTeam.tabs.channels.btnAdd.click(); + await poHomeTeam.headerToolbar.openTeamChannels(); + await poHomeTeam.tabs.channels.addExistingChannel(targetGroupNameInTeam); await expect(poHomeTeam.tabs.channels.channelsList).toContainText(targetGroupNameInTeam); // try to delete group in team @@ -334,14 +330,14 @@ test.describe.serial('teams-management', () => { expect((await api.post('/permissions.update', { permissions: [{ _id: 'delete-team-group', roles: ['owner'] }] })).status()).toBe(200); await poHomeTeam.navbar.openChat(targetTeam); - await poHomeTeam.roomToolbar.openTeamChannels(); + await poHomeTeam.headerToolbar.openTeamChannels(); await poHomeTeam.tabs.channels.openChannelOptionMoreActions(targetGroupNameInTeam); await expect(page.getByRole('menu', { exact: true }).getByRole('menuitem', { name: 'Delete' })).toBeVisible(); await page.getByRole('menu', { exact: true }).getByRole('menuitem', { name: 'Delete' }).click(); await poHomeTeam.tabs.channels.confirmDeleteRoom(); await poHomeTeam.navbar.openChat(targetTeam); - await poHomeTeam.roomToolbar.openTeamChannels(); + await poHomeTeam.headerToolbar.openTeamChannels(); await expect(poHomeTeam.tabs.channels.channelsList).not.toContainText(targetGroupNameInTeam); }); @@ -354,7 +350,7 @@ test.describe.serial('teams-management', () => { ); await poHomeTeam.navbar.openChat(targetTeam); - await poHomeTeam.roomToolbar.openTeamChannels(); + await poHomeTeam.headerToolbar.openTeamChannels(); await poHomeTeam.tabs.channels.openChannelOptionMoreActions(targetChannelNameInTeam); await expect(page.getByRole('menu', { exact: true }).getByRole('menuitem', { name: 'Remove from team' })).not.toBeVisible(); }); @@ -363,7 +359,7 @@ test.describe.serial('teams-management', () => { expect((await api.post('/permissions.update', { permissions: [{ _id: 'remove-team-channel', roles: ['owner'] }] })).status()).toBe(200); await poHomeTeam.navbar.openChat(targetTeam); - await poHomeTeam.roomToolbar.openTeamChannels(); + await poHomeTeam.headerToolbar.openTeamChannels(); await poHomeTeam.tabs.channels.openChannelOptionMoreActions(targetChannelNameInTeam); await expect(page.getByRole('menu', { exact: true }).getByRole('menuitem', { name: 'Remove from team' })).toBeVisible(); await page.getByRole('menu', { exact: true }).getByRole('menuitem', { name: 'Remove from team' }).click(); @@ -389,11 +385,8 @@ test.describe.serial('teams-management', () => { // re-add channel to team await poHomeTeam.navbar.openChat(targetTeam); - await poHomeTeam.roomToolbar.openTeamChannels(); - await poHomeTeam.tabs.channels.btnAddExisting.click(); - await poHomeTeam.tabs.channels.inputChannels.fill(targetChannelNameInTeam); - await page.locator(`.rcx-option__content:has-text("${targetChannelNameInTeam}")`).click(); - await poHomeTeam.tabs.channels.btnAdd.click(); + await poHomeTeam.headerToolbar.openTeamChannels(); + await poHomeTeam.tabs.channels.addExistingChannel(targetChannelNameInTeam); await expect(poHomeTeam.tabs.channels.channelsList).toContainText(targetChannelNameInTeam); // try to delete channel in team @@ -408,14 +401,14 @@ test.describe.serial('teams-management', () => { expect((await api.post('/permissions.update', { permissions: [{ _id: 'delete-team-channel', roles: ['owner'] }] })).status()).toBe(200); await poHomeTeam.navbar.openChat(targetTeam); - await poHomeTeam.roomToolbar.openTeamChannels(); + await poHomeTeam.headerToolbar.openTeamChannels(); await poHomeTeam.tabs.channels.openChannelOptionMoreActions(targetChannelNameInTeam); await expect(page.getByRole('menu', { exact: true }).getByRole('menuitem', { name: 'Delete' })).toBeVisible(); await page.getByRole('menu', { exact: true }).getByRole('menuitem', { name: 'Delete' }).click(); await poHomeTeam.tabs.channels.confirmDeleteRoom(); await poHomeTeam.navbar.openChat(targetTeam); - await poHomeTeam.roomToolbar.openTeamChannels(); + await poHomeTeam.headerToolbar.openTeamChannels(); await expect(poHomeTeam.tabs.channels.channelsList).not.toContainText(targetChannelNameInTeam); }); @@ -423,7 +416,7 @@ test.describe.serial('teams-management', () => { expect((await api.post('/permissions.update', { permissions: [{ _id: 'remove-team-channel', roles: ['owner'] }] })).status()).toBe(200); await poHomeTeam.navbar.openChat(targetTeam); - await poHomeTeam.roomToolbar.openTeamChannels(); + await poHomeTeam.headerToolbar.openTeamChannels(); await poHomeTeam.tabs.channels.openChannelOptionMoreActions(targetChannel); await page.getByRole('menu', { exact: true }).getByRole('menuitem', { name: 'Remove from team' }).click(); await poHomeTeam.tabs.channels.confirmRemoveChannel(); @@ -433,25 +426,20 @@ test.describe.serial('teams-management', () => { test('should remove user1 from targetTeamNonPrivate', async () => { await poHomeTeam.navbar.openChat(targetTeamNonPrivate); - await poHomeTeam.tabs.kebab.click({ force: true }); - await poHomeTeam.tabs.btnTeamMembers.click(); + await poHomeTeam.headerToolbar.openMoreOptions(); + await poHomeTeam.headerToolbar.openTeamMembers(); await poHomeTeam.tabs.members.showAllUsers(); await poHomeTeam.tabs.members.openMemberOptionMoreActions('user1'); await poHomeTeam.tabs.members.getMenuItemAction('Remove from team').click(); - await expect(poHomeTeam.tabs.members.confirmRemoveUserModal).toBeVisible(); - await poHomeTeam.tabs.members.confirmRemoveUser(); await expect(poHomeTeam.tabs.members.memberOption('user1')).not.toBeVisible(); }); test('should delete targetTeamNonPrivate', async () => { await poHomeTeam.navbar.openChat(targetTeamNonPrivate); - await poHomeTeam.roomToolbar.openTeamInfo(); - await poHomeTeam.tabs.room.btnMore.click(); - await poHomeTeam.tabs.room.getMoreOption('Delete').click(); - await expect(poHomeTeam.tabs.room.confirmDeleteTeamModal).toBeVisible(); + await poHomeTeam.headerToolbar.openTeamInfo(); + await poHomeTeam.tabs.room.deleteTeam(); - await poHomeTeam.tabs.room.confirmDeleteTeam(); await poHomeTeam.navbar.typeSearch(targetTeamNonPrivate); await expect(poHomeTeam.navbar.getSearchRoomByName(targetTeamNonPrivate)).not.toBeVisible(); }); @@ -462,28 +450,21 @@ test.describe.serial('teams-management', () => { await user1Page.goto(`/group/${targetTeam}`); await user1Channel.content.waitForChannel(); - await user1Channel.roomToolbar.openTeamInfo(); - await user1Channel.tabs.room.btnLeave.click(); - await expect(user1Channel.tabs.room.confirmLeaveModal).toBeVisible(); - - await user1Channel.tabs.room.confirmLeave(); + await user1Channel.headerToolbar.openTeamInfo(); + await user1Channel.tabs.room.leaveRoom(); await user1Page.close(); await poHomeTeam.navbar.openChat(targetTeam); - await poHomeTeam.tabs.kebab.click({ force: true }); - await poHomeTeam.tabs.btnTeamMembers.click(); + await poHomeTeam.headerToolbar.openMoreOptions(); + await poHomeTeam.headerToolbar.openTeamMembers(); await poHomeTeam.tabs.members.showAllUsers(); await expect(poHomeTeam.tabs.members.memberOption('user1')).not.toBeVisible(); }); test('should convert team into a channel', async () => { await poHomeTeam.navbar.openChat(targetTeam); - await poHomeTeam.roomToolbar.openTeamInfo(); - await poHomeTeam.tabs.room.btnMore.click(); - await poHomeTeam.tabs.room.getMoreOption('Convert to Channel').click(); - await expect(poHomeTeam.tabs.room.confirmConvertModal).toBeVisible(); - - await poHomeTeam.tabs.room.confirmConvert(); + await poHomeTeam.headerToolbar.openTeamInfo(); + await poHomeTeam.tabs.room.convertIntoChannel(); // TODO: improve this locator and check the action reactivity await expect(poHomeTeam.content.getSystemMessageByText(`converted #${targetTeam} to channel`)).toBeVisible();