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 9d7b7ad819540..b1da4a158b481 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 @@ -2,6 +2,10 @@ import { faker } from '@faker-js/faker'; import { Users } from '../fixtures/userStates'; import { HomeChannel } from '../page-objects'; +import { EncryptedRoomPage } from '../page-objects/encrypted-room'; +import { DisableRoomEncryptionModal, E2EEMessageActions, EnableRoomEncryptionModal } from '../page-objects/fragments/e2ee'; +import { PinnedMessagesTab } from '../page-objects/fragments/pinned-messages-tab'; +import { StarredMessagesTab } from '../page-objects/fragments/starred-messages-tab'; import { preserveSettings } from '../utils/preserveSettings'; import { test, expect } from '../utils/test'; @@ -16,6 +20,12 @@ preserveSettings(settingsList); test.describe('E2EE Encrypted Channels', () => { let poHomeChannel: HomeChannel; + let encryptedRoomPage: EncryptedRoomPage; + let e2eeMessageActions: E2EEMessageActions; + let enableEncryptionModal: EnableRoomEncryptionModal; + let disableEncryptionModal: DisableRoomEncryptionModal; + let pinnedMessagesTab: PinnedMessagesTab; + let starredMessagesTab: StarredMessagesTab; test.use({ storageState: Users.userE2EE.state }); @@ -29,6 +39,12 @@ test.describe('E2EE Encrypted Channels', () => { test.beforeEach(async ({ page }) => { poHomeChannel = new HomeChannel(page); + encryptedRoomPage = new EncryptedRoomPage(page); + e2eeMessageActions = new E2EEMessageActions(page); + enableEncryptionModal = new EnableRoomEncryptionModal(page); + disableEncryptionModal = new DisableRoomEncryptionModal(page); + pinnedMessagesTab = new PinnedMessagesTab(page); + starredMessagesTab = new StarredMessagesTab(page); await page.goto('/home'); }); @@ -44,34 +60,30 @@ test.describe('E2EE Encrypted Channels', () => { await poHomeChannel.content.sendMessage('hello world'); await expect(poHomeChannel.content.lastUserMessageBody).toHaveText('hello world'); - await expect(poHomeChannel.content.lastUserMessage.locator('.rcx-icon--name-key')).toBeVisible(); + await expect(encryptedRoomPage.lastMessage.encryptedIcon).toBeVisible(); await poHomeChannel.tabs.kebab.click({ force: true }); await expect(poHomeChannel.tabs.btnDisableE2E).toBeVisible(); await poHomeChannel.tabs.btnDisableE2E.click({ force: true }); - await expect(page.getByRole('dialog', { name: 'Disable encryption' })).toBeVisible(); - await page.getByRole('button', { name: 'Disable encryption' }).click(); - await poHomeChannel.toastMessage.dismissToast(); + await disableEncryptionModal.disable(); await page.waitForTimeout(1000); await poHomeChannel.content.sendMessage('hello world not encrypted'); await expect(poHomeChannel.content.lastUserMessageBody).toHaveText('hello world not encrypted'); - await expect(poHomeChannel.content.lastUserMessage.locator('.rcx-icon--name-key')).not.toBeVisible(); + await expect(encryptedRoomPage.lastMessage.encryptedIcon).not.toBeVisible(); await poHomeChannel.tabs.kebab.click({ force: true }); await expect(poHomeChannel.tabs.btnEnableE2E).toBeVisible(); await poHomeChannel.tabs.btnEnableE2E.click({ force: true }); - await expect(page.getByRole('dialog', { name: 'Enable encryption' })).toBeVisible(); - await page.getByRole('button', { name: 'Enable encryption' }).click(); - await poHomeChannel.toastMessage.dismissToast(); + await enableEncryptionModal.enable(); await page.waitForTimeout(1000); await poHomeChannel.content.sendMessage('hello world encrypted again'); await expect(poHomeChannel.content.lastUserMessageBody).toHaveText('hello world encrypted again'); - await expect(poHomeChannel.content.lastUserMessage.locator('.rcx-icon--name-key')).toBeVisible(); + await expect(encryptedRoomPage.lastMessage.encryptedIcon).toBeVisible(); }); test('expect create a private encrypted channel and send a encrypted thread message', async ({ page }) => { @@ -86,10 +98,9 @@ test.describe('E2EE Encrypted Channels', () => { await poHomeChannel.content.sendMessage('This is the thread main message.'); await expect(poHomeChannel.content.lastUserMessageBody).toHaveText('This is the thread main message.'); - await expect(poHomeChannel.content.lastUserMessage.locator('.rcx-icon--name-key')).toBeVisible(); + await expect(encryptedRoomPage.lastMessage.encryptedIcon).toBeVisible(); - await page.locator('[data-qa-type="message"]').last().hover(); - await page.locator('role=button[name="Reply in thread"]').click(); + await poHomeChannel.content.openReplyInThread(); await expect(page).toHaveURL(/.*thread/); @@ -97,8 +108,7 @@ test.describe('E2EE Encrypted Channels', () => { await expect(poHomeChannel.content.mainThreadMessageText.locator('.rcx-icon--name-key')).toBeVisible(); await poHomeChannel.content.toggleAlsoSendThreadToChannel(true); - await page.getByRole('dialog').locator('[name="msg"]').last().fill('This is an encrypted thread message also sent in channel'); - await page.keyboard.press('Enter'); + await poHomeChannel.content.sendMessageInThread('This is an encrypted thread message also sent in channel'); await expect(poHomeChannel.content.lastThreadMessageText).toContainText('This is an encrypted thread message also sent in channel'); await expect(poHomeChannel.content.lastThreadMessageText.locator('.rcx-icon--name-key')).toBeVisible(); await expect(poHomeChannel.content.lastUserMessage).toContainText('This is an encrypted thread message also sent in channel'); @@ -118,15 +128,15 @@ test.describe('E2EE Encrypted Channels', () => { await poHomeChannel.content.sendMessage('This is an encrypted message.'); await expect(poHomeChannel.content.lastUserMessageBody).toHaveText('This is an encrypted message.'); - await expect(poHomeChannel.content.lastUserMessage.locator('.rcx-icon--name-key')).toBeVisible(); + await expect(encryptedRoomPage.lastMessage.encryptedIcon).toBeVisible(); - await page.locator('[data-qa-type="message"]').last().hover(); - await expect(page.locator('role=button[name="Forward message not available on encrypted content"]')).toBeDisabled(); + await poHomeChannel.content.lastUserMessage.hover(); + await expect(e2eeMessageActions.forwardMessageButton).toBeDisabled(); await poHomeChannel.content.openLastMessageMenu(); - await expect(page.locator('role=menuitem[name="Reply in direct message"]')).toHaveClass(/disabled/); - await expect(page.locator('role=menuitem[name="Copy link"]')).toHaveClass(/disabled/); + await expect(e2eeMessageActions.replyInDirectMessageOption).toHaveClass(/disabled/); + await expect(e2eeMessageActions.copyLinkOption).toHaveClass(/disabled/); }); test('expect create a private channel, encrypt it and send an encrypted message', async ({ page }) => { @@ -142,21 +152,15 @@ test.describe('E2EE Encrypted Channels', () => { await poHomeChannel.toastMessage.dismissToast(); await poHomeChannel.tabs.kebab.click(); - // TODO(@jessicaschelly/@dougfabris): fix this flaky behavior - if (!(await poHomeChannel.tabs.btnEnableE2E.isVisible())) { - await poHomeChannel.tabs.kebab.click(); - } + await expect(poHomeChannel.tabs.btnEnableE2E).toBeVisible(); await poHomeChannel.tabs.btnEnableE2E.click(); - await expect(page.getByRole('dialog', { name: 'Enable encryption' })).toBeVisible(); - await page.getByRole('button', { name: 'Enable encryption' }).click(); - await page.waitForTimeout(1000); - + await enableEncryptionModal.enable(); await expect(poHomeChannel.content.encryptedRoomHeaderIcon).toBeVisible(); await poHomeChannel.content.sendMessage('hello world'); await expect(poHomeChannel.content.lastUserMessageBody).toHaveText('hello world'); - await expect(poHomeChannel.content.lastUserMessage.locator('.rcx-icon--name-key')).toBeVisible(); + await expect(encryptedRoomPage.lastMessage.encryptedIcon).toBeVisible(); }); test('expect create a encrypted private channel and mention user', async ({ page }) => { @@ -170,11 +174,7 @@ test.describe('E2EE Encrypted Channels', () => { await poHomeChannel.content.sendMessage('hello @user1'); - const userMention = page.getByRole('button', { - name: 'user1', - }); - - await expect(userMention).toBeVisible(); + await expect(poHomeChannel.content.getUserMention('user1')).toBeVisible(); }); test('expect create a encrypted private channel, mention a channel and navigate to it', async ({ page }) => { @@ -188,13 +188,9 @@ test.describe('E2EE Encrypted Channels', () => { await poHomeChannel.content.sendMessage('Are you in the #general channel?'); - const channelMention = page.getByRole('button', { - name: 'general', - }); + await expect(poHomeChannel.content.getChannelMention('general')).toBeVisible(); - await expect(channelMention).toBeVisible(); - - await channelMention.click(); + await poHomeChannel.content.getChannelMention('general').click(); await expect(page).toHaveURL(`/channel/general`); }); @@ -210,16 +206,8 @@ test.describe('E2EE Encrypted Channels', () => { await poHomeChannel.content.sendMessage('Are you in the #general channel, @user1 ?'); - const channelMention = page.getByRole('button', { - name: 'general', - }); - - const userMention = page.getByRole('button', { - name: 'user1', - }); - - await expect(userMention).toBeVisible(); - await expect(channelMention).toBeVisible(); + await expect(poHomeChannel.content.getUserMention('user1')).toBeVisible(); + await expect(poHomeChannel.content.getChannelMention('general')).toBeVisible(); }); test('expect create a private channel, send unecrypted messages, encrypt the channel and delete the last message and check the last message in the sidebar', async ({ @@ -246,8 +234,7 @@ test.describe('E2EE Encrypted Channels', () => { await poHomeChannel.tabs.kebab.click({ force: true }); await expect(poHomeChannel.tabs.btnEnableE2E).toBeVisible(); await poHomeChannel.tabs.btnEnableE2E.click({ force: true }); - await expect(page.getByRole('dialog', { name: 'Enable encryption' })).toBeVisible(); - await page.getByRole('button', { name: 'Enable encryption' }).click(); + await enableEncryptionModal.enable(); await page.waitForTimeout(1000); await expect(poHomeChannel.content.encryptedRoomHeaderIcon).toBeVisible(); @@ -259,13 +246,7 @@ test.describe('E2EE Encrypted Channels', () => { // Delete last message await expect(poHomeChannel.content.lastUserMessageBody).toHaveText(encriptedMessage2); - await poHomeChannel.content.openLastMessageMenu(); - // TODO(@jessicaschelly/@dougfabris): fix this flaky behavior - if (!(await page.locator('role=menuitem[name="Delete"]').isVisible())) { - await poHomeChannel.content.openLastMessageMenu(); - } - await page.locator('role=menuitem[name="Delete"]').click(); - await page.locator('#modal-root .rcx-button-group--align-end .rcx-button--danger').click(); + await poHomeChannel.content.deleteLastMessage(); // Check last message in the sidebar const sidebarChannel = poHomeChannel.sidenav.getSidebarItemByName(channelName); @@ -282,48 +263,35 @@ test.describe('E2EE Encrypted Channels', () => { await expect(poHomeChannel.content.encryptedRoomHeaderIcon).toBeVisible(); - await poHomeChannel.content.sendMessage('This message should be pinned and stared.'); + await poHomeChannel.content.sendMessage('This message should be pinned and starred.'); - await expect(poHomeChannel.content.lastUserMessageBody).toHaveText('This message should be pinned and stared.'); - await expect(poHomeChannel.content.lastUserMessage.locator('.rcx-icon--name-key')).toBeVisible(); + await expect(poHomeChannel.content.lastUserMessageBody).toHaveText('This message should be pinned and starred.'); + await expect(encryptedRoomPage.lastMessage.encryptedIcon).toBeVisible(); await poHomeChannel.content.openLastMessageMenu(); - await page.locator('role=menuitem[name="Star"]').click(); + await poHomeChannel.content.btnOptionStarMessage.click(); await poHomeChannel.toastMessage.waitForDisplay(); await poHomeChannel.toastMessage.dismissToast(); await poHomeChannel.content.openLastMessageMenu(); - await page.locator('role=menuitem[name="Pin"]').click(); - await page.locator('#modal-root >> button:has-text("Yes, pin message")').click(); + await poHomeChannel.content.btnOptionPinMessage.click(); + await poHomeChannel.content.btnModalConfirm.click(); await poHomeChannel.toastMessage.waitForDisplay(); await poHomeChannel.toastMessage.dismissToast(); - await poHomeChannel.tabs.kebab.click(); - await poHomeChannel.tabs.btnPinnedMessagesList.click(); - - await expect(page.getByRole('dialog', { name: 'Pinned Messages' })).toBeVisible(); - - const lastPinnedMessage = page.getByRole('dialog', { name: 'Pinned Messages' }).locator('[data-qa-type="message"]').last(); - await expect(lastPinnedMessage).toContainText('This message should be pinned and stared.'); - await lastPinnedMessage.hover(); - await lastPinnedMessage.locator('role=button[name="More"]').waitFor(); - await lastPinnedMessage.locator('role=button[name="More"]').click(); - await expect(page.locator('role=menuitem[name="Copy link"]')).toHaveClass(/disabled/); + await pinnedMessagesTab.openTab(); + await expect(pinnedMessagesTab.lastMessage.body).toContainText('This message should be pinned and starred.'); + await pinnedMessagesTab.openLastMessageMenu(); + await expect(e2eeMessageActions.copyLinkOption).toHaveClass(/disabled/); await poHomeChannel.btnContextualbarClose.click(); - await poHomeChannel.tabs.kebab.click(); - await poHomeChannel.tabs.btnStarredMessageList.click(); - - const lastStarredMessage = page.getByRole('dialog', { name: 'Starred Messages' }).locator('[data-qa-type="message"]').last(); - await expect(page.getByRole('dialog', { name: 'Starred Messages' })).toBeVisible(); - await expect(lastStarredMessage).toContainText('This message should be pinned and stared.'); - await lastStarredMessage.hover(); - await lastStarredMessage.locator('role=button[name="More"]').waitFor(); - await lastStarredMessage.locator('role=button[name="More"]').click(); - await expect(page.locator('role=menuitem[name="Copy link"]')).toHaveClass(/disabled/); + await starredMessagesTab.openTab(); + await expect(starredMessagesTab.lastMessage.body).toContainText('This message should be pinned and starred.'); + await starredMessagesTab.openLastMessageMenu(); + await expect(e2eeMessageActions.copyLinkOption).toHaveClass(/disabled/); }); test('expect to edit encrypted message', async ({ page }) => { @@ -338,7 +306,7 @@ test.describe('E2EE Encrypted Channels', () => { await poHomeChannel.content.sendMessage(originalMessage); await expect(poHomeChannel.content.lastUserMessageBody).toHaveText(originalMessage); - await expect(poHomeChannel.content.lastUserMessage.locator('.rcx-icon--name-key')).toBeVisible(); + await expect(encryptedRoomPage.lastMessage.encryptedIcon).toBeVisible(); await poHomeChannel.content.openLastMessageMenu(); await poHomeChannel.content.btnOptionEditMessage.click(); @@ -347,7 +315,7 @@ test.describe('E2EE Encrypted Channels', () => { await page.keyboard.press('Enter'); await expect(poHomeChannel.content.lastUserMessageBody).toHaveText(editedMessage); - await expect(poHomeChannel.content.lastUserMessage.locator('.rcx-icon--name-key')).toBeVisible(); + await expect(encryptedRoomPage.lastMessage.encryptedIcon).toBeVisible(); }); test('expect to edit encrypted message to include mention', async ({ page }) => { @@ -362,7 +330,7 @@ test.describe('E2EE Encrypted Channels', () => { await poHomeChannel.content.sendMessage(originalMessage); await expect(poHomeChannel.content.lastUserMessageBody).toHaveText(originalMessage); - await expect(poHomeChannel.content.lastUserMessage.locator('.rcx-icon--name-key')).toBeVisible(); + await expect(encryptedRoomPage.lastMessage.encryptedIcon).toBeVisible(); await poHomeChannel.content.openLastMessageMenu(); await poHomeChannel.content.btnOptionEditMessage.click(); @@ -371,18 +339,9 @@ test.describe('E2EE Encrypted Channels', () => { await page.keyboard.press('Enter'); await expect(poHomeChannel.content.lastUserMessageBody).toHaveText(displayedMessage); - await expect(poHomeChannel.content.lastUserMessage.locator('.rcx-icon--name-key')).toBeVisible(); - - const userMention = page.getByRole('button', { - name: 'user1', - }); - - await expect(userMention).toBeVisible(); - - const channelMention = page.getByRole('button', { - name: 'general', - }); + await expect(encryptedRoomPage.lastMessage.encryptedIcon).toBeVisible(); - await expect(channelMention).toBeVisible(); + await expect(poHomeChannel.content.getUserMention('user1')).toBeVisible(); + await expect(poHomeChannel.content.getChannelMention('general')).toBeVisible(); }); }); diff --git a/apps/meteor/tests/e2e/e2e-encryption/e2ee-file-encryption.spec.ts b/apps/meteor/tests/e2e/e2e-encryption/e2ee-file-encryption.spec.ts index bfb18e84f4b3f..8abb0eccdbc3b 100644 --- a/apps/meteor/tests/e2e/e2e-encryption/e2ee-file-encryption.spec.ts +++ b/apps/meteor/tests/e2e/e2e-encryption/e2ee-file-encryption.spec.ts @@ -2,6 +2,7 @@ import { faker } from '@faker-js/faker'; import { Users } from '../fixtures/userStates'; import { HomeChannel } from '../page-objects'; +import { EncryptedRoomPage } from '../page-objects/encrypted-room'; import { preserveSettings } from '../utils/preserveSettings'; import { test, expect } from '../utils/test'; @@ -17,6 +18,7 @@ const originalSettings = preserveSettings(settingsList); test.describe('E2EE File Encryption', () => { let poHomeChannel: HomeChannel; + let encryptedRoomPage: EncryptedRoomPage; test.use({ storageState: Users.userE2EE.state }); @@ -25,7 +27,6 @@ test.describe('E2EE File Encryption', () => { await api.post('/settings/E2E_Allow_Unencrypted_Messages', { value: true }); await api.post('/settings/E2E_Enabled_Default_DirectRooms', { value: false }); await api.post('/settings/E2E_Enabled_Default_PrivateRooms', { value: false }); - await api.post('/im.delete', { username: 'user2' }); }); test.afterAll(async ({ api }) => { @@ -35,6 +36,7 @@ test.describe('E2EE File Encryption', () => { test.beforeEach(async ({ page }) => { poHomeChannel = new HomeChannel(page); + encryptedRoomPage = new EncryptedRoomPage(page); await page.goto('/home'); }); @@ -55,7 +57,7 @@ test.describe('E2EE File Encryption', () => { await poHomeChannel.content.fileNameInput.fill('any_file1.txt'); await poHomeChannel.content.btnModalConfirm.click(); - await expect(poHomeChannel.content.lastUserMessage.locator('.rcx-icon--name-key')).toBeVisible(); + await expect(encryptedRoomPage.lastMessage.encryptedIcon).toBeVisible(); await expect(poHomeChannel.content.getFileDescription).toHaveText('any_description'); await expect(poHomeChannel.content.lastMessageFileName).toContainText('any_file1.txt'); }); @@ -90,7 +92,7 @@ test.describe('E2EE File Encryption', () => { await poHomeChannel.content.fileNameInput.fill('any_file1.txt'); await poHomeChannel.content.btnModalConfirm.click(); - await expect(poHomeChannel.content.lastUserMessage.locator('.rcx-icon--name-key')).toBeVisible(); + await expect(encryptedRoomPage.lastMessage.encryptedIcon).toBeVisible(); await expect(poHomeChannel.content.getFileDescription).toHaveText('message 1'); await expect(poHomeChannel.content.lastMessageFileName).toContainText('any_file1.txt'); }); @@ -105,7 +107,7 @@ test.describe('E2EE File Encryption', () => { await poHomeChannel.content.fileNameInput.fill('any_file2.txt'); await poHomeChannel.content.btnModalConfirm.click(); - await expect(poHomeChannel.content.lastUserMessage.locator('.rcx-icon--name-key')).toBeVisible(); + await expect(encryptedRoomPage.lastMessage.encryptedIcon).toBeVisible(); await expect(poHomeChannel.content.getFileDescription).toHaveText('message 2'); await expect(poHomeChannel.content.lastMessageFileName).toContainText('any_file2.txt'); }); @@ -120,7 +122,7 @@ test.describe('E2EE File Encryption', () => { await poHomeChannel.content.fileNameInput.fill('any_file3.txt'); await poHomeChannel.content.btnModalConfirm.click(); - await expect(poHomeChannel.content.lastUserMessage.locator('.rcx-icon--name-key')).toBeVisible(); + await expect(encryptedRoomPage.lastMessage.encryptedIcon).toBeVisible(); await expect(poHomeChannel.content.getFileDescription).toHaveText('message 2'); await expect(poHomeChannel.content.lastMessageFileName).toContainText('any_file2.txt'); }); @@ -152,7 +154,7 @@ test.describe('E2EE File Encryption', () => { await poHomeChannel.content.sendMessage('This is an encrypted message.'); await expect(poHomeChannel.content.lastUserMessageBody).toHaveText('This is an encrypted message.'); - await expect(poHomeChannel.content.lastUserMessage.locator('.rcx-icon--name-key')).toBeVisible(); + await expect(encryptedRoomPage.lastMessage.encryptedIcon).toBeVisible(); }); await test.step('send a text file in channel, file should not be encrypted', async () => { @@ -161,7 +163,7 @@ test.describe('E2EE File Encryption', () => { await poHomeChannel.content.fileNameInput.fill('any_file1.txt'); await poHomeChannel.content.btnModalConfirm.click(); - await expect(poHomeChannel.content.lastUserMessage.locator('.rcx-icon--name-key')).not.toBeVisible(); + await expect(encryptedRoomPage.lastMessage.encryptedIcon).not.toBeVisible(); await expect(poHomeChannel.content.getFileDescription).toHaveText('any_description'); await expect(poHomeChannel.content.lastMessageFileName).toContainText('any_file1.txt'); }); diff --git a/apps/meteor/tests/e2e/e2e-encryption/e2ee-key-reset.spec.ts b/apps/meteor/tests/e2e/e2e-encryption/e2ee-key-reset.spec.ts index fab641ba6021c..d95cc55e9d8ba 100644 --- a/apps/meteor/tests/e2e/e2e-encryption/e2ee-key-reset.spec.ts +++ b/apps/meteor/tests/e2e/e2e-encryption/e2ee-key-reset.spec.ts @@ -25,7 +25,6 @@ test.describe('E2EE Key Reset', () => { await api.post('/settings/E2E_Allow_Unencrypted_Messages', { value: true }); await api.post('/settings/E2E_Enabled_Default_DirectRooms', { value: false }); await api.post('/settings/E2E_Enabled_Default_PrivateRooms', { value: false }); - await api.post('/im.delete', { username: 'user2' }); }); test.beforeEach(async ({ browser, page }) => { diff --git a/apps/meteor/tests/e2e/e2e-encryption/e2ee-legacy-format.spec.ts b/apps/meteor/tests/e2e/e2e-encryption/e2ee-legacy-format.spec.ts index fcd3c11010fc1..00e78da23acc4 100644 --- a/apps/meteor/tests/e2e/e2e-encryption/e2ee-legacy-format.spec.ts +++ b/apps/meteor/tests/e2e/e2e-encryption/e2ee-legacy-format.spec.ts @@ -5,6 +5,7 @@ import { BASE_API_URL } from '../config/constants'; import injectInitialData from '../fixtures/inject-initial-data'; import { Users, restoreState } from '../fixtures/userStates'; import { HomeChannel } from '../page-objects'; +import { EncryptedRoomPage } from '../page-objects/encrypted-room'; import { preserveSettings } from '../utils/preserveSettings'; import { test, expect } from '../utils/test'; @@ -35,6 +36,7 @@ const sendEncryptedMessage = async (request: APIRequestContext, rid: string, enc test.describe('E2EE Legacy Format', () => { let poHomeChannel: HomeChannel; + let encryptedRoomPage: EncryptedRoomPage; test.use({ storageState: Users.userE2EE.state }); @@ -43,11 +45,11 @@ test.describe('E2EE Legacy Format', () => { await api.post('/settings/E2E_Allow_Unencrypted_Messages', { value: true }); await api.post('/settings/E2E_Enabled_Default_DirectRooms', { value: false }); await api.post('/settings/E2E_Enabled_Default_PrivateRooms', { value: false }); - await api.post('/im.delete', { username: 'user2' }); }); test.beforeEach(async ({ page }) => { poHomeChannel = new HomeChannel(page); + encryptedRoomPage = new EncryptedRoomPage(page); await page.goto('/home'); }); @@ -87,6 +89,6 @@ test.describe('E2EE Legacy Format', () => { await sendEncryptedMessage(request, rid, kid + encryptedMessage); await expect(poHomeChannel.content.lastUserMessageBody).toHaveText('world'); - await expect(poHomeChannel.content.lastUserMessage.locator('.rcx-icon--name-key')).toBeVisible(); + await expect(encryptedRoomPage.lastMessage.encryptedIcon).toBeVisible(); }); }); diff --git a/apps/meteor/tests/e2e/e2e-encryption/e2ee-otr.spec.ts b/apps/meteor/tests/e2e/e2e-encryption/e2ee-otr.spec.ts index 0101f190ca27c..955fd57726f71 100644 --- a/apps/meteor/tests/e2e/e2e-encryption/e2ee-otr.spec.ts +++ b/apps/meteor/tests/e2e/e2e-encryption/e2ee-otr.spec.ts @@ -1,5 +1,6 @@ import { Users } from '../fixtures/userStates'; import { HomeChannel } from '../page-objects'; +import { DisableRoomEncryptionModal, EnableRoomEncryptionModal } from '../page-objects/fragments/e2ee'; import { preserveSettings } from '../utils/preserveSettings'; import { test, expect } from '../utils/test'; @@ -14,6 +15,8 @@ preserveSettings(settingsList); test.describe('E2EE OTR (Off-The-Record)', () => { let poHomeChannel: HomeChannel; + let enableEncryptionModal: EnableRoomEncryptionModal; + let disableEncryptionModal: DisableRoomEncryptionModal; test.use({ storageState: Users.userE2EE.state }); @@ -27,6 +30,8 @@ test.describe('E2EE OTR (Off-The-Record)', () => { test.beforeEach(async ({ page }) => { poHomeChannel = new HomeChannel(page); + enableEncryptionModal = new EnableRoomEncryptionModal(page); + disableEncryptionModal = new DisableRoomEncryptionModal(page); await page.goto('/home'); }); @@ -43,21 +48,16 @@ test.describe('E2EE OTR (Off-The-Record)', () => { await poHomeChannel.tabs.kebab.click({ force: true }); if (await poHomeChannel.tabs.btnDisableE2E.isVisible()) { await poHomeChannel.tabs.btnDisableE2E.click({ force: true }); - await expect(page.getByRole('dialog', { name: 'Disable encryption' })).toBeVisible(); - await page.getByRole('button', { name: 'Disable encryption' }).click(); - await poHomeChannel.toastMessage.dismissToast(); + await disableEncryptionModal.disable(); await poHomeChannel.tabs.kebab.click({ force: true }); } await expect(poHomeChannel.tabs.btnEnableE2E).toBeVisible(); await poHomeChannel.tabs.btnEnableE2E.click({ force: true }); - await expect(page.getByRole('dialog', { name: 'Enable encryption' })).toBeVisible(); - await page.getByRole('button', { name: 'Enable encryption' }).click(); + await enableEncryptionModal.enable(); await page.waitForTimeout(1000); await expect(poHomeChannel.content.encryptedRoomHeaderIcon).toBeVisible(); - await poHomeChannel.toastMessage.dismissToast(); - await poHomeChannel.tabs.kebab.click({ force: true }); await expect(poHomeChannel.tabs.btnEnableOTR).toBeVisible(); await poHomeChannel.tabs.btnEnableOTR.click({ force: true }); diff --git a/apps/meteor/tests/e2e/e2e-encryption/e2ee-passphrase-management.spec.ts b/apps/meteor/tests/e2e/e2e-encryption/e2ee-passphrase-management.spec.ts index ae2d2870086e7..95165c7beeaa2 100644 --- a/apps/meteor/tests/e2e/e2e-encryption/e2ee-passphrase-management.spec.ts +++ b/apps/meteor/tests/e2e/e2e-encryption/e2ee-passphrase-management.spec.ts @@ -5,6 +5,7 @@ import { Users, storeState, restoreState } from '../fixtures/userStates'; import { AccountProfile, HomeChannel } from '../page-objects'; import { setupE2EEPassword } from './setupE2EEPassword'; import { AccountSecurityPage } from '../page-objects/account-security'; +import { EncryptedRoomPage } from '../page-objects/encrypted-room'; import { HomeSidenav } from '../page-objects/fragments'; import { E2EEKeyDecodeFailureBanner, @@ -27,6 +28,13 @@ const originalSettings = preserveSettings(settingsList); test.describe('E2EE Passphrase Management - Initial Setup', () => { test.use({ storageState: Users.admin.state }); + let loginPage: LoginPage; + let enterE2EEPasswordBanner: EnterE2EEPasswordBanner; + let enterE2EEPasswordModal: EnterE2EEPasswordModal; + let e2EEKeyDecodeFailureBanner: E2EEKeyDecodeFailureBanner; + let sidenav: HomeSidenav; + let accountSecurityPage: AccountSecurityPage; + let resetE2EEPasswordModal: ResetE2EEPasswordModal; test.beforeAll(async ({ api }) => { await api.post('/settings/E2E_Enable', { value: true }); @@ -35,6 +43,16 @@ test.describe('E2EE Passphrase Management - Initial Setup', () => { await api.post('/settings/E2E_Enabled_Default_PrivateRooms', { value: false }); }); + test.beforeEach(async ({ page }) => { + loginPage = new LoginPage(page); + enterE2EEPasswordBanner = new EnterE2EEPasswordBanner(page); + enterE2EEPasswordModal = new EnterE2EEPasswordModal(page); + e2EEKeyDecodeFailureBanner = new E2EEKeyDecodeFailureBanner(page); + sidenav = new HomeSidenav(page); + accountSecurityPage = new AccountSecurityPage(page); + resetE2EEPasswordModal = new ResetE2EEPasswordModal(page); + }); + test.afterAll(async ({ api }) => { await api.post('/settings/E2E_Enable', { value: originalSettings.E2E_Enable }); await api.post('/settings/E2E_Allow_Unencrypted_Messages', { value: originalSettings.E2E_Allow_Unencrypted_Messages }); @@ -44,8 +62,6 @@ test.describe('E2EE Passphrase Management - Initial Setup', () => { test.describe('Generate', () => { test.beforeEach(async ({ page, api }) => { - const loginPage = new LoginPage(page); - await api.post('/method.call/e2e.resetOwnE2EKey', { message: JSON.stringify({ msg: 'method', id: '1', method: 'e2e.resetOwnE2EKey', params: [] }), }); @@ -56,12 +72,6 @@ test.describe('E2EE Passphrase Management - Initial Setup', () => { }); test('expect the randomly generated password to work', async ({ page }) => { - const loginPage = new LoginPage(page); - const enterE2EEPasswordBanner = new EnterE2EEPasswordBanner(page); - const enterE2EEPasswordModal = new EnterE2EEPasswordModal(page); - const e2EEKeyDecodeFailureBanner = new E2EEKeyDecodeFailureBanner(page); - const sidenav = new HomeSidenav(page); - const password = await setupE2EEPassword(page); // Log out @@ -78,10 +88,7 @@ test.describe('E2EE Passphrase Management - Initial Setup', () => { await e2EEKeyDecodeFailureBanner.expectToNotBeVisible(); }); - test('expect to manually reset the password', async ({ page }) => { - const accountSecurityPage = new AccountSecurityPage(page); - const loginPage = new LoginPage(page); - + test('expect to manually reset the password', async () => { // Reset the E2EE key to start the flow from the beginning await accountSecurityPage.goto(); await accountSecurityPage.resetE2EEPassword(); @@ -90,12 +97,6 @@ test.describe('E2EE Passphrase Management - Initial Setup', () => { }); test('should reset e2e password from the modal', async ({ page }) => { - const sidenav = new HomeSidenav(page); - const loginPage = new LoginPage(page); - const enterE2EEPasswordBanner = new EnterE2EEPasswordBanner(page); - const enterE2EEPasswordModal = new EnterE2EEPasswordModal(page); - const resetE2EEPasswordModal = new ResetE2EEPasswordModal(page); - await setupE2EEPassword(page); // Logout @@ -114,13 +115,6 @@ test.describe('E2EE Passphrase Management - Initial Setup', () => { }); test('expect to manually set a new password', async ({ page }) => { - const accountSecurityPage = new AccountSecurityPage(page); - const loginPage = new LoginPage(page); - const enterE2EEPasswordBanner = new EnterE2EEPasswordBanner(page); - const enterE2EEPasswordModal = new EnterE2EEPasswordModal(page); - const e2EEKeyDecodeFailureBanner = new E2EEKeyDecodeFailureBanner(page); - const sidenav = new HomeSidenav(page); - const newPassword = faker.internet.password({ length: 30, prefix: @@ -160,16 +154,10 @@ test.describe('E2EE Passphrase Management - Initial Setup', () => { await page.goto('/home'); await injectInitialData(); await restoreState(page, Users.userE2EE); - const sidenav = new HomeSidenav(page); await sidenav.logout(); - const loginPage = new LoginPage(page); await loginPage.loginByUserState(Users.userE2EE, { except: ['private_key', 'public_key'] }); - const enterE2EEPasswordBanner = new EnterE2EEPasswordBanner(page); - const enterE2EEPasswordModal = new EnterE2EEPasswordModal(page); - const e2EEKeyDecodeFailureBanner = new E2EEKeyDecodeFailureBanner(page); - await enterE2EEPasswordBanner.click(); await enterE2EEPasswordModal.enterPassword('minus mobile dexter forest elvis'); await e2EEKeyDecodeFailureBanner.expectToNotBeVisible(); @@ -185,6 +173,10 @@ const roomSetupSettingsList = ['E2E_Enable', 'E2E_Allow_Unencrypted_Messages']; test.describe.serial('E2EE Passphrase Management - Room Setup States', () => { let poAccountProfile: AccountProfile; let poHomeChannel: HomeChannel; + let encryptedRoomPage: EncryptedRoomPage; + let loginPage: LoginPage; + let accountSecurityPage: AccountSecurityPage; + let enterE2EEPasswordModal: EnterE2EEPasswordModal; let e2eePassword: string; preserveSettings(roomSetupSettingsList); @@ -192,6 +184,10 @@ test.describe.serial('E2EE Passphrase Management - Room Setup States', () => { test.beforeEach(async ({ page }) => { poAccountProfile = new AccountProfile(page); poHomeChannel = new HomeChannel(page); + encryptedRoomPage = new EncryptedRoomPage(page); + loginPage = new LoginPage(page); + accountSecurityPage = new AccountSecurityPage(page); + enterE2EEPasswordModal = new EnterE2EEPasswordModal(page); }); test.beforeAll(async ({ api }) => { @@ -248,7 +244,7 @@ test.describe.serial('E2EE Passphrase Management - Room Setup States', () => { await poHomeChannel.content.sendMessage('hello world'); await expect(poHomeChannel.content.lastUserMessageBody).toHaveText('hello world'); - await expect(poHomeChannel.content.lastUserMessage.locator('.rcx-icon--name-key')).toBeVisible(); + await expect(encryptedRoomPage.lastMessage.encryptedIcon).toBeVisible(); }); test('expect enter password state on encrypted room', async ({ page }) => { @@ -281,9 +277,7 @@ test.describe.serial('E2EE Passphrase Management - Room Setup States', () => { await poHomeChannel.btnRoomEnterE2EEPassword.click(); - await page.locator('#modal-root input').fill(e2eePassword); - - await page.locator('#modal-root .rcx-button--primary').click(); + await enterE2EEPasswordModal.enterPassword(e2eePassword); await expect(poHomeChannel.bannerEnterE2EEPassword).not.toBeVisible(); @@ -294,7 +288,7 @@ test.describe.serial('E2EE Passphrase Management - Room Setup States', () => { await poHomeChannel.content.sendMessage('hello world'); await expect(poHomeChannel.content.lastUserMessageBody).toHaveText('hello world'); - await expect(poHomeChannel.content.lastUserMessage.locator('.rcx-icon--name-key')).toBeVisible(); + await expect(encryptedRoomPage.lastMessage.encryptedIcon).toBeVisible(); await storeState(page, Users.admin); }); @@ -313,28 +307,25 @@ test.describe.serial('E2EE Passphrase Management - Room Setup States', () => { await poHomeChannel.content.sendMessage('hello world'); await expect(poHomeChannel.content.lastUserMessageBody).toHaveText('hello world'); - await expect(poHomeChannel.content.lastUserMessage.locator('.rcx-icon--name-key')).toBeVisible(); + await expect(encryptedRoomPage.lastMessage.encryptedIcon).toBeVisible(); - await poHomeChannel.sidenav.btnUserProfileMenu.click(); - await poHomeChannel.sidenav.accountProfileOption.click(); - - await page.locator('role=navigation >> a:has-text("Security")').click(); + await accountSecurityPage.goto(); await poAccountProfile.securityE2EEncryptionSection.click(); await poAccountProfile.securityE2EEncryptionResetKeyButton.click(); - await page.locator('role=button[name="Login"]').waitFor(); + await loginPage.waitForIt(); await page.reload(); - await page.locator('role=button[name="Login"]').waitFor(); + await loginPage.waitForIt(); await injectInitialData(); await restoreState(page, Users.admin); - await page.locator('role=navigation >> role=button[name=Search]').click(); - await page.locator('role=search >> role=searchbox').fill(channelName); - await page.locator(`role=search >> role=listbox >> role=link >> text="${channelName}"`).click(); + await poHomeChannel.sidenav.openSearch(); + await poHomeChannel.sidenav.inputSearch.fill(channelName); + await poHomeChannel.sidenav.getSearchItemByName(channelName).click(); await poHomeChannel.btnRoomSaveE2EEPassword.click(); await poHomeChannel.btnSavedMyPassword.click(); diff --git a/apps/meteor/tests/e2e/e2e-encryption/e2ee-server-settings.spec.ts b/apps/meteor/tests/e2e/e2e-encryption/e2ee-server-settings.spec.ts index 9a6fd5de8576d..031e113b4e4cf 100644 --- a/apps/meteor/tests/e2e/e2e-encryption/e2ee-server-settings.spec.ts +++ b/apps/meteor/tests/e2e/e2e-encryption/e2ee-server-settings.spec.ts @@ -3,6 +3,7 @@ import { faker } from '@faker-js/faker'; import { IS_EE } from '../config/constants'; import { Users } from '../fixtures/userStates'; import { HomeChannel } from '../page-objects'; +import { EncryptedRoomPage } from '../page-objects/encrypted-room'; import { preserveSettings } from '../utils/preserveSettings'; import { test, expect } from '../utils/test'; @@ -17,6 +18,7 @@ preserveSettings(settingsList); test.describe('E2EE Server Settings', () => { let poHomeChannel: HomeChannel; + let encryptedRoomPage: EncryptedRoomPage; test.use({ storageState: Users.userE2EE.state }); @@ -30,6 +32,7 @@ test.describe('E2EE Server Settings', () => { test.beforeEach(async ({ page }) => { poHomeChannel = new HomeChannel(page); + encryptedRoomPage = new EncryptedRoomPage(page); await page.goto('/home'); }); @@ -46,11 +49,11 @@ test.describe('E2EE Server Settings', () => { await poHomeChannel.content.sendMessage('This is an encrypted message.'); await expect(poHomeChannel.content.lastUserMessageBody).toHaveText('This is an encrypted message.'); - await expect(poHomeChannel.content.lastUserMessage.locator('.rcx-icon--name-key')).toBeVisible(); + await expect(encryptedRoomPage.lastMessage.encryptedIcon).toBeVisible(); - await page.locator('[name="msg"]').type('/'); + await poHomeChannel.content.inputMessage.pressSequentially('/'); await expect(page.locator('#popup-item-contextualbar')).not.toHaveClass(/disabled/); - await page.locator('[name="msg"]').clear(); + await poHomeChannel.content.inputMessage.clear(); await poHomeChannel.content.dispatchSlashCommand('/contextualbar'); await expect(poHomeChannel.btnContextualbarClose).toBeVisible(); @@ -62,9 +65,11 @@ test.describe('E2EE Server Settings', () => { test.describe('un-encrypted messages not allowed in e2ee rooms', () => { test.skip(!IS_EE, 'Premium Only'); let poHomeChannel: HomeChannel; + let encryptedRoomPage: EncryptedRoomPage; test.beforeEach(async ({ page }) => { poHomeChannel = new HomeChannel(page); + encryptedRoomPage = new EncryptedRoomPage(page); await page.goto('/home'); }); @@ -88,9 +93,9 @@ test.describe('E2EE Server Settings', () => { await poHomeChannel.content.sendMessage('This is an encrypted message.'); await expect(poHomeChannel.content.lastUserMessageBody).toHaveText('This is an encrypted message.'); - await expect(poHomeChannel.content.lastUserMessage.locator('.rcx-icon--name-key')).toBeVisible(); + await expect(encryptedRoomPage.lastMessage.encryptedIcon).toBeVisible(); - await page.locator('[name="msg"]').pressSequentially('/'); + await poHomeChannel.content.inputMessage.pressSequentially('/'); await expect(page.locator('#popup-item-contextualbar')).toHaveClass(/disabled/); }); }); diff --git a/apps/meteor/tests/e2e/page-objects/fragments/e2ee.ts b/apps/meteor/tests/e2e/page-objects/fragments/e2ee.ts index 151915016bbc2..2e22455a4b3ad 100644 --- a/apps/meteor/tests/e2e/page-objects/fragments/e2ee.ts +++ b/apps/meteor/tests/e2e/page-objects/fragments/e2ee.ts @@ -152,3 +152,23 @@ export class DisableRoomEncryptionModal extends Modal { await this.toastMessages.dismissToast('success'); } } + +export class E2EEMessageActions { + private readonly page: Page; + + constructor(page: Page) { + this.page = page; + } + + get forwardMessageButton(): Locator { + return this.page.getByRole('button', { name: 'Forward message not available on encrypted content' }); + } + + get replyInDirectMessageOption(): Locator { + return this.page.getByRole('menuitem', { name: 'Reply in direct message' }); + } + + get copyLinkOption(): Locator { + return this.page.getByRole('menuitem', { name: 'Copy link' }); + } +} 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 b0a474a00930c..1af46811ea84d 100644 --- a/apps/meteor/tests/e2e/page-objects/fragments/home-content.ts +++ b/apps/meteor/tests/e2e/page-objects/fragments/home-content.ts @@ -66,6 +66,14 @@ export class HomeContent { return this.page.locator('[data-qa-type="message"][data-sequential="false"]').last(); } + getUserMention(username: string): Locator { + return this.page.locator('[title="Mentions user"]', { hasText: username }); + } + + getChannelMention(channelName: string): Locator { + return this.page.locator('[title="Mentions channel"]', { hasText: channelName }); + } + get encryptedRoomHeaderIcon(): Locator { return this.page.locator('.rcx-room-header i.rcx-icon--name-key'); } diff --git a/apps/meteor/tests/e2e/page-objects/fragments/index.ts b/apps/meteor/tests/e2e/page-objects/fragments/index.ts index a46cbe188f3bb..8c579733884ad 100644 --- a/apps/meteor/tests/e2e/page-objects/fragments/index.ts +++ b/apps/meteor/tests/e2e/page-objects/fragments/index.ts @@ -13,4 +13,6 @@ export * from './report-message-modal'; export * from './toast-messages'; export * from './export-messages-tab'; export * from './menu'; +export * from './pinned-messages-tab'; +export * from './starred-messages-tab'; export * from './toolbar'; diff --git a/apps/meteor/tests/e2e/page-objects/fragments/message.ts b/apps/meteor/tests/e2e/page-objects/fragments/message.ts index 77dee24c85ca0..02e1f29ca836e 100644 --- a/apps/meteor/tests/e2e/page-objects/fragments/message.ts +++ b/apps/meteor/tests/e2e/page-objects/fragments/message.ts @@ -14,4 +14,14 @@ export class Message { get encryptedIcon() { return this.root.locator('.rcx-icon--name-key'); } + + get moreButton() { + return this.root.getByRole('button', { name: 'More' }); + } + + async openMenu(): Promise { + await this.root.hover(); + await this.moreButton.waitFor(); + await this.moreButton.click(); + } } diff --git a/apps/meteor/tests/e2e/page-objects/fragments/pinned-messages-tab.ts b/apps/meteor/tests/e2e/page-objects/fragments/pinned-messages-tab.ts new file mode 100644 index 0000000000000..6b5bd03b915c3 --- /dev/null +++ b/apps/meteor/tests/e2e/page-objects/fragments/pinned-messages-tab.ts @@ -0,0 +1,30 @@ +import type { Locator, Page } from '@playwright/test'; + +import { Message } from './message'; +import { RoomToolbar } from './toolbar'; +import { expect } from '../../utils/test'; + +export class PinnedMessagesTab { + readonly root: Locator; + + private readonly roomToolbar: RoomToolbar; + + constructor(page: Page) { + this.root = page.getByRole('dialog', { name: 'Pinned Messages' }); + this.roomToolbar = new RoomToolbar(page); + } + + get lastMessage(): Message { + return new Message(this.root.locator('[data-qa-type="message"]').last()); + } + + async openTab(): Promise { + await this.roomToolbar.openMoreOptions(); + await this.roomToolbar.menuItemPinnedMessages.click(); + await expect(this.root).toBeVisible(); + } + + async openLastMessageMenu(): Promise { + await this.lastMessage.openMenu(); + } +} diff --git a/apps/meteor/tests/e2e/page-objects/fragments/starred-messages-tab.ts b/apps/meteor/tests/e2e/page-objects/fragments/starred-messages-tab.ts new file mode 100644 index 0000000000000..d766661d42ed6 --- /dev/null +++ b/apps/meteor/tests/e2e/page-objects/fragments/starred-messages-tab.ts @@ -0,0 +1,30 @@ +import type { Locator, Page } from '@playwright/test'; + +import { Message } from './message'; +import { RoomToolbar } from './toolbar'; +import { expect } from '../../utils/test'; + +export class StarredMessagesTab { + readonly root: Locator; + + private readonly roomToolbar: RoomToolbar; + + constructor(page: Page) { + this.root = page.getByRole('dialog', { name: 'Starred Messages' }); + this.roomToolbar = new RoomToolbar(page); + } + + get lastMessage(): Message { + return new Message(this.root.locator('[data-qa-type="message"]').last()); + } + + async openTab(): Promise { + await this.roomToolbar.openMoreOptions(); + await this.roomToolbar.menuItemStarredMessages.click(); + await expect(this.root).toBeVisible(); + } + + async openLastMessageMenu(): Promise { + await this.lastMessage.openMenu(); + } +} diff --git a/apps/meteor/tests/e2e/page-objects/fragments/toolbar.ts b/apps/meteor/tests/e2e/page-objects/fragments/toolbar.ts index f55910a6d2b02..46a6245d2627b 100644 --- a/apps/meteor/tests/e2e/page-objects/fragments/toolbar.ts +++ b/apps/meteor/tests/e2e/page-objects/fragments/toolbar.ts @@ -12,7 +12,7 @@ export abstract class Toolbar { } export class RoomToolbar extends Toolbar { - constructor(page: Page) { + constructor(private page: Page) { super(page.getByRole('toolbar', { name: 'Primary Room actions' })); } @@ -65,19 +65,19 @@ export class RoomToolbar extends Toolbar { } get menuItemMentions(): Locator { - return this.root.getByRole('menuitem', { name: 'Mentions' }); + return this.page.getByRole('menuitem', { name: 'Mentions' }); } get menuItemStarredMessages(): Locator { - return this.root.getByRole('menuitem', { name: 'Starred Messages' }); + return this.page.getByRole('menuitem', { name: 'Starred Messages' }); } get menuItemPinnedMessages(): Locator { - return this.root.getByRole('menuitem', { name: 'Pinned Messages' }); + return this.page.getByRole('menuitem', { name: 'Pinned Messages' }); } get menuItemPruneMessages(): Locator { - return this.root.getByRole('menuitem', { name: 'Prune Messages' }); + return this.page.getByRole('menuitem', { name: 'Prune Messages' }); } async openRoomInfo() {