From 36f6953a7edc325fe8d5e1f714aa75d6c8370599 Mon Sep 17 00:00:00 2001 From: lehnerja Date: Thu, 30 Apr 2026 12:17:11 +0200 Subject: [PATCH 1/4] test(folders): add regression test for favorites folder (TC-742) This commit introduces a new test case to the Folders suite to verify the functionality and behavior of the Favorites folder. Implemented scenarios include: - Adding both 1:1 and group conversations to the Favorites folder. - Verifying that unread message notifications badge appear correctly on the Favorites sidebar button for both direct and group messages. - Ensuring a group conversation remains visible in the Favorites folder even after the user is removed from the group. - Removing conversations from Favorites and verifying the folder becomes empty while conversations remain in the "All" view. To support these assertions, the following Page Object Models were updated: - `conversationList.page.ts`: Added `addToFavoritesButton` to the context menu. - `conversationSidebar.component.ts`: Added `favoritesButton` locator. Refs: WPB-25073 # Conflicts: # apps/webapp/test/e2e_tests/specs/Folders/folders.spec.ts --- .../conversationSidebar.component.ts | 2 + .../webapp/pages/conversationList.page.ts | 1 + .../e2e_tests/specs/Folders/folders.spec.ts | 70 ++++++++++++------- 3 files changed, 48 insertions(+), 25 deletions(-) diff --git a/apps/webapp/test/e2e_tests/pageManager/webapp/components/conversationSidebar.component.ts b/apps/webapp/test/e2e_tests/pageManager/webapp/components/conversationSidebar.component.ts index e3b52bb0b5a..cc96d54a3db 100644 --- a/apps/webapp/test/e2e_tests/pageManager/webapp/components/conversationSidebar.component.ts +++ b/apps/webapp/test/e2e_tests/pageManager/webapp/components/conversationSidebar.component.ts @@ -34,6 +34,7 @@ export class ConversationSidebar { readonly manageTeamButton: Locator; readonly sidebar: Locator; readonly supportButton: Locator; + readonly favoritesButton: Locator; constructor(page: Page) { this.page = page; @@ -50,6 +51,7 @@ export class ConversationSidebar { this.manageTeamButton = page.getByTestId('go-team-management'); this.sidebar = page.locator(`.conversations-sidebar-items`); this.supportButton = page.getByRole('link', {name: 'Support'}); + this.favoritesButton = page.getByTitle('Favorites'); } async clickPreferencesButton() { diff --git a/apps/webapp/test/e2e_tests/pageManager/webapp/pages/conversationList.page.ts b/apps/webapp/test/e2e_tests/pageManager/webapp/pages/conversationList.page.ts index e0bf4a1ca77..3f9a144ee78 100644 --- a/apps/webapp/test/e2e_tests/pageManager/webapp/pages/conversationList.page.ts +++ b/apps/webapp/test/e2e_tests/pageManager/webapp/pages/conversationList.page.ts @@ -103,6 +103,7 @@ export class ConversationListPage { unarchiveButton: contextMenu.getByRole('button', {name: 'Unarchive'}), blockButton: contextMenu.getByRole('button', {name: 'Block'}), unblockButton: contextMenu.getByRole('button', {name: 'Unblock'}), + addToFavoritesButton: contextMenu.getByRole('button', {name: 'Add to favorites'}), moveToButton: contextMenu.getByRole('button', {name: 'Move to'}), notificationsButton: contextMenu.getByRole('menuitem', {name: 'Notifications'}), clearContentButton: contextMenu.getByRole('button', {name: 'Clear content'}), diff --git a/apps/webapp/test/e2e_tests/specs/Folders/folders.spec.ts b/apps/webapp/test/e2e_tests/specs/Folders/folders.spec.ts index 99fc0d17163..42730d3377b 100644 --- a/apps/webapp/test/e2e_tests/specs/Folders/folders.spec.ts +++ b/apps/webapp/test/e2e_tests/specs/Folders/folders.spec.ts @@ -57,19 +57,21 @@ async function moveConversationToFolder(pageManager: PageManager, conversationNa test.describe('Folders', () => { let userA: User; let userB: User; - let userAPageManager: PageManager; test.beforeEach(async ({createTeam, createPage, createUser}) => { userB = await createUser(); const team = await createTeam('Team', {users: [userB]}); userA = team.owner; - userAPageManager = await PageManager.from(createPage(withLogin(userA), withConnectedUser(userB))); }); - test('I want to move a 1:1 conversation to a new custom folder', {tag: ['@TC-545', '@regression']}, async () => { - const userAPages = userAPageManager.webapp.pages; + test( + 'I want to move a 1:1 conversation to a new custom folder', + {tag: ['@TC-545', '@regression']}, + async ({createPage}) => { + const userAPageManager = await PageManager.from(createPage(withLogin(userA), withConnectedUser(userB))); + const userAPages = userAPageManager.webapp.pages; - const customFolderName = 'Custom-Folder'; + const customFolderName = 'Custom-Folder'; // Step 1: User A opens 1:1 conversation with User B await userAPages.conversationList().getConversation(userB.fullName).open(); @@ -78,16 +80,21 @@ test.describe('Folders', () => { // Step 3: 1:1 conversation with User B is in the custom folder const actualTitle = userAPages.conversationList().conversationListHeaderTitle; - await expect(actualTitle).toHaveText(customFolderName); - }); + await expect(actualTitle).toHaveText(customFolderName); + }, + ); - test('I want to move a group conversation to a new custom folder', {tag: ['@TC-546', '@regression']}, async () => { - const userAPages = userAPageManager.webapp.pages; + test( + 'I want to move a group conversation to a new custom folder', + {tag: ['@TC-546', '@regression']}, + async ({createPage}) => { + const userAPageManager = await PageManager.from(createPage(withLogin(userA), withConnectedUser(userB))); + const userAPages = userAPageManager.webapp.pages; - const customFolderName = 'Custom-Folder'; - const conversationName = 'Group Conversation with User A and User B'; + const customFolderName = 'Custom-Folder'; + const conversationName = 'Group Conversation with User A and User B'; - await createGroup(userAPages, conversationName, [userB]); + await createGroup(userAPages, conversationName, [userB]); // Step 1: User A opens group conversation with User B await userAPages.conversationList().getConversation(conversationName).open(); @@ -96,13 +103,15 @@ test.describe('Folders', () => { // Step 3: Group conversation with User B is in the custom folder const actualTitle = userAPages.conversationList().conversationListHeaderTitle; - await expect(actualTitle).toHaveText(customFolderName); - }); + await expect(actualTitle).toHaveText(customFolderName); + }, + ); test( 'I want to move a 1:1 conversation to an existing custom folder', {tag: ['@TC-547', '@regression']}, - async () => { + async ({createPage}) => { + const userAPageManager = await PageManager.from(createPage(withLogin(userA), withConnectedUser(userB))); const {pages: userAPages, components: userAComponents} = userAPageManager.webapp; const customFolderName = 'Custom-Folder'; @@ -126,7 +135,8 @@ test.describe('Folders', () => { test( 'I want to move a group conversation to an existing custom folder', {tag: ['@TC-548', '@regression']}, - async () => { + async ({createPage}) => { + const userAPageManager = await PageManager.from(createPage(withLogin(userA), withConnectedUser(userB))); const {pages: userAPages, components: userAComponents} = userAPageManager.webapp; const customFolderName = 'Custom-Folder'; @@ -151,7 +161,8 @@ test.describe('Folders', () => { test.skip( 'I want to see custom folder removed when last conversation is removed', {tag: ['@TC-553', '@regression']}, - async () => { + async ({createPage}) => { + const userAPageManager = await PageManager.from(createPage(withLogin(userA), withConnectedUser(userB))); const userAPages = userAPageManager.webapp.pages; const customFolderName = 'Custom-Folder'; @@ -178,8 +189,12 @@ test.describe('Folders', () => { }, ); - test('I should not be able to create a custom folder without a name', {tag: ['@TC-560', '@regression']}, async () => { - const {pages: userAPages, modals: userAModals} = userAPageManager.webapp; + test( + 'I should not be able to create a custom folder without a name', + {tag: ['@TC-560', '@regression']}, + async ({createPage}) => { + const userAPageManager = await PageManager.from(createPage(withLogin(userA), withConnectedUser(userB))); + const {pages: userAPages, modals: userAModals} = userAPageManager.webapp; // Step 1: User A opens 1:1 conversation with User B const conversation = await userAPages.conversationList().getConversation(userB.fullName).open(); @@ -188,14 +203,19 @@ test.describe('Folders', () => { await contextMenu.moveToButton.click(); await contextMenu.getByRole('button', {name: 'Create new folder'}).click(); - // Step 3: 'Create Folder Modal' should still be visible after click on create - await expect(userAModals.optionModal().actionButton).toBeDisabled(); - }); + // Step 3: 'Create Folder Modal' should still be visible after click on create + await expect(userAModals.optionModal().actionButton).toBeDisabled(); + }, + ); - test('I should not see any traces of a deleted custom folder', {tag: ['@TC-568', '@regression']}, async () => { - const userAPages = userAPageManager.webapp.pages; + test( + 'I should not see any traces of a deleted custom folder', + {tag: ['@TC-568', '@regression']}, + async ({createPage}) => { + const userAPageManager = await PageManager.from(createPage(withLogin(userA), withConnectedUser(userB))); + const userAPages = userAPageManager.webapp.pages; - const customFolderName = 'Custom-Folder'; + const customFolderName = 'Custom-Folder'; // Preconditions: Conversation is in custom folder const conversation = await userAPages.conversationList().getConversation(userB.fullName).open(); From cab3322d8a13eeb4bb122e9d8dee2ca07b2579a2 Mon Sep 17 00:00:00 2001 From: lehnerja Date: Thu, 30 Apr 2026 14:13:12 +0200 Subject: [PATCH 2/4] test(folders): fix rebasing errors Refs: WPB-25073 --- .../e2e_tests/specs/Folders/folders.spec.ts | 171 ++++++++++++++---- 1 file changed, 139 insertions(+), 32 deletions(-) diff --git a/apps/webapp/test/e2e_tests/specs/Folders/folders.spec.ts b/apps/webapp/test/e2e_tests/specs/Folders/folders.spec.ts index 42730d3377b..9c367f49402 100644 --- a/apps/webapp/test/e2e_tests/specs/Folders/folders.spec.ts +++ b/apps/webapp/test/e2e_tests/specs/Folders/folders.spec.ts @@ -73,12 +73,12 @@ test.describe('Folders', () => { const customFolderName = 'Custom-Folder'; - // Step 1: User A opens 1:1 conversation with User B - await userAPages.conversationList().getConversation(userB.fullName).open(); - // Step 2: User A moves 1:1 conversation with User B into new custom folder - await createCustomFolder(userAPageManager, userB.fullName, customFolderName); - // Step 3: 1:1 conversation with User B is in the custom folder - const actualTitle = userAPages.conversationList().conversationListHeaderTitle; + // Step 1: User A opens 1:1 conversation with User B + await userAPages.conversationList().getConversation(userB.fullName).open(); + // Step 2: User A moves 1:1 conversation with User B into new custom folder + await createCustomFolder(userAPageManager, userB.fullName, customFolderName); + // Step 3: 1:1 conversation with User B is in the custom folder + const actualTitle = userAPages.conversationList().conversationListHeaderTitle; await expect(actualTitle).toHaveText(customFolderName); }, @@ -96,12 +96,12 @@ test.describe('Folders', () => { await createGroup(userAPages, conversationName, [userB]); - // Step 1: User A opens group conversation with User B - await userAPages.conversationList().getConversation(conversationName).open(); - // Step 2: User A moves group conversation with User B in new custom folder - await createCustomFolder(userAPageManager, conversationName, customFolderName); - // Step 3: Group conversation with User B is in the custom folder - const actualTitle = userAPages.conversationList().conversationListHeaderTitle; + // Step 1: User A opens group conversation with User B + await userAPages.conversationList().getConversation(conversationName).open(); + // Step 2: User A moves group conversation with User B in new custom folder + await createCustomFolder(userAPageManager, conversationName, customFolderName); + // Step 3: Group conversation with User B is in the custom folder + const actualTitle = userAPages.conversationList().conversationListHeaderTitle; await expect(actualTitle).toHaveText(customFolderName); }, @@ -196,12 +196,12 @@ test.describe('Folders', () => { const userAPageManager = await PageManager.from(createPage(withLogin(userA), withConnectedUser(userB))); const {pages: userAPages, modals: userAModals} = userAPageManager.webapp; - // Step 1: User A opens 1:1 conversation with User B - const conversation = await userAPages.conversationList().getConversation(userB.fullName).open(); - // Step 2: User A wants to move 1:1 conversation with User B into custom folder - const contextMenu = await conversation.openContextMenu(); - await contextMenu.moveToButton.click(); - await contextMenu.getByRole('button', {name: 'Create new folder'}).click(); + // Step 1: User A opens 1:1 conversation with User B + const conversation = await userAPages.conversationList().getConversation(userB.fullName).open(); + // Step 2: User A wants to move 1:1 conversation with User B into custom folder + const contextMenu = await conversation.openContextMenu(); + await contextMenu.moveToButton.click(); + await contextMenu.getByRole('button', {name: 'Create new folder'}).click(); // Step 3: 'Create Folder Modal' should still be visible after click on create await expect(userAModals.optionModal().actionButton).toBeDisabled(); @@ -217,20 +217,127 @@ test.describe('Folders', () => { const customFolderName = 'Custom-Folder'; - // Preconditions: Conversation is in custom folder - const conversation = await userAPages.conversationList().getConversation(userB.fullName).open(); - await createCustomFolder(userAPageManager, userB.fullName, customFolderName); + // Preconditions: Conversation is in custom folder + const conversation = await userAPages.conversationList().getConversation(userB.fullName).open(); + await createCustomFolder(userAPageManager, userB.fullName, customFolderName); - await test.step('User A removes conversation with User B from custom folder', async () => { - const contextMenu = await conversation.openContextMenu(); - await contextMenu.getByRole('button', {name: `Remove from "${customFolderName}"`}).click(); - }); + await test.step('User A removes conversation with User B from custom folder', async () => { + const contextMenu = await conversation.openContextMenu(); + await contextMenu.getByRole('button', {name: `Remove from "${customFolderName}"`}).click(); + }); - await test.step('User A tries to move conversation with User B back into the folder, custom folder name should no longer be visible in the folder menu', async () => { - await conversation.open(); - const contextMenu = await conversation.openContextMenu(); - await contextMenu.moveToButton.click(); - await expect(contextMenu.getByRole('button', {name: customFolderName})).not.toBeVisible(); - }); - }); + await test.step('User A tries to move conversation with User B back into the folder, custom folder name should no longer be visible in the folder menu', async () => { + await conversation.open(); + const contextMenu = await conversation.openContextMenu(); + await contextMenu.moveToButton.click(); + await expect(contextMenu.getByRole('button', {name: customFolderName})).not.toBeVisible(); + }); + }, + ); + + test( + 'I want to see 1:1 and group conversations in Favorites folder', + {tag: ['@TC-742', '@regression']}, + async ({createPage}) => { + const [userAPageManager, userBPageManager] = await Promise.all([ + createPage(withLogin(userA), withConnectedUser(userB)), + createPage(withLogin(userB)), + ]); + + const {pages: userAPages, components: userAComponents} = PageManager.from(userAPageManager).webapp; + const userBPages = PageManager.from(userBPageManager).webapp.pages; + + const groupName = 'Group Name'; + + // Preconditions: User A and User B are in a group conversation created by User B + await createGroup(userBPages, groupName, [userA]); + + await test.step('User A adds group conversation with User B to Favorites', async () => { + const contextMenu = await userAPages.conversationList().getConversation(groupName).openContextMenu(); + await contextMenu.addToFavoritesButton.click(); + + const actualTitle = userAPages.conversationList().conversationListHeaderTitle; + await expect(actualTitle).toHaveText('Favorites'); + + await userAComponents.conversationSidebar().clickAllConversationsButton(); + }); + + await test.step('User A adds 1:1 with User B to Favorites', async () => { + const contextMenu = await userAPages.conversationList().getConversation(userB.fullName).openContextMenu(); + await contextMenu.addToFavoritesButton.click(); + + const actualTitle = userAPages.conversationList().conversationListHeaderTitle; + await expect(actualTitle).toHaveText('Favorites'); + + await userAComponents.conversationSidebar().clickAllConversationsButton(); + await userAPages.conversationList().getConversation(groupName).open(); + }); + + await test.step('User B sends message in 1:1 conversation with User A', async () => { + await userBPages.conversationList().getConversation(userA.fullName, {protocol: 'mls'}).open(); + await userBPages.conversation().sendMessage('Direct'); + }); + + await test.step('User A sees notification in Favorites and opens it', async () => { + await expect(userAComponents.conversationSidebar().favoritesButton.getByTestId('unread-badge')).toBeVisible(); + await userAComponents.conversationSidebar().favoritesButton.click(); + await expect(userAPages.conversationList().getConversation(userB.fullName).unreadIndicator).toBeVisible(); + await userAPages.conversationList().getConversation(userB.fullName, {protocol: 'mls'}).open(); + await expect(userAPages.conversation().getMessage({content: 'Direct', sender: userB})).toBeVisible(); + }); + + await test.step('User B sends message in group conversation with User A', async () => { + await userBPages.conversationList().getConversation(groupName).open(); + await userBPages.conversation().sendMessage('Group'); + }); + + await test.step('User A sees notification in Favorites and opens it', async () => { + await expect(userAComponents.conversationSidebar().favoritesButton.getByTestId('unread-badge')).toBeVisible(); + await expect(userAPages.conversationList().getConversation(groupName).unreadIndicator).toBeVisible(); + await userAPages.conversationList().getConversation(groupName).open(); + await expect(userAPages.conversation().getMessage({content: 'Group', sender: userB})).toBeVisible(); + }); + + await test.step('User B removes User A from group conversation', async () => { + await userBPages.conversationList().getConversation(groupName).open(); + await userBPages.conversation().toggleGroupInformation(); + + await expect(userBPages.conversationDetails().groupMembers.filter({hasText: userA.fullName})).toBeVisible(); + + await userBPages.conversationDetails().openParticipantDetails(userA.fullName); + await userBPages.participantDetails().removeFromGroup(); + }); + + await test.step('User A still sees group conversation in Favorites', async () => { + const actualTitle = userAPages.conversationList().conversationListHeaderTitle; + await expect(actualTitle).toHaveText('Favorites'); + await expect(userAPages.conversationList().getConversation(groupName)).toBeVisible(); + }); + + await test.step('User A removes 1:1 and group conversation with User B from Favorites', async () => { + const contextMenuDirectConversation = await userAPages + .conversationList() + .getConversation(userB.fullName) + .openContextMenu(); + await contextMenuDirectConversation.getByRole('button', {name: 'Remove from favorites'}).click(); + + const contextMenuGroupConversation = await userAPages + .conversationList() + .getConversation(groupName) + .openContextMenu(); + await contextMenuGroupConversation.getByRole('button', {name: 'Remove from favorites'}).click(); + }); + + await test.step('User A sees empty Favorites folder', async () => { + await expect(userAPages.conversationList().getConversation(userB.fullName)).not.toBeVisible(); + await expect(userAPages.conversationList().getConversation(groupName)).not.toBeVisible(); + }); + + await test.step('User A sees 1:1 and group conversation with User B in All Conversation View', async () => { + await userAComponents.conversationSidebar().clickAllConversationsButton(); + await expect(userAPages.conversationList().getConversation(userB.fullName)).toBeVisible(); + await expect(userAPages.conversationList().getConversation(groupName)).toBeVisible(); + }); + }, + ); }); From d1ceda2714d33323013440d5dd2705c4597ad580 Mon Sep 17 00:00:00 2001 From: lehnerja Date: Thu, 30 Apr 2026 15:32:03 +0200 Subject: [PATCH 3/4] test(folders): refactor locator for `favoritesButton` in conversationSidebar.component.ts Refs: WPB-25073 --- .../webapp/components/conversationSidebar.component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/webapp/test/e2e_tests/pageManager/webapp/components/conversationSidebar.component.ts b/apps/webapp/test/e2e_tests/pageManager/webapp/components/conversationSidebar.component.ts index cc96d54a3db..2b638aa4e46 100644 --- a/apps/webapp/test/e2e_tests/pageManager/webapp/components/conversationSidebar.component.ts +++ b/apps/webapp/test/e2e_tests/pageManager/webapp/components/conversationSidebar.component.ts @@ -51,7 +51,7 @@ export class ConversationSidebar { this.manageTeamButton = page.getByTestId('go-team-management'); this.sidebar = page.locator(`.conversations-sidebar-items`); this.supportButton = page.getByRole('link', {name: 'Support'}); - this.favoritesButton = page.getByTitle('Favorites'); + this.favoritesButton = page.getByTestId('go-favorites-view'); } async clickPreferencesButton() { From 041e4253eddedd42312f1ccaeb8d0a665bcc113d Mon Sep 17 00:00:00 2001 From: lehnerja Date: Mon, 4 May 2026 09:34:18 +0200 Subject: [PATCH 4/4] test(folders): refactor locator for `favoritesButton` in conversationSidebar.component.ts from getByTestId to getByRole Refs: WPB-25073 --- .../webapp/components/conversationSidebar.component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/webapp/test/e2e_tests/pageManager/webapp/components/conversationSidebar.component.ts b/apps/webapp/test/e2e_tests/pageManager/webapp/components/conversationSidebar.component.ts index 2b638aa4e46..0815ea141da 100644 --- a/apps/webapp/test/e2e_tests/pageManager/webapp/components/conversationSidebar.component.ts +++ b/apps/webapp/test/e2e_tests/pageManager/webapp/components/conversationSidebar.component.ts @@ -51,7 +51,7 @@ export class ConversationSidebar { this.manageTeamButton = page.getByTestId('go-team-management'); this.sidebar = page.locator(`.conversations-sidebar-items`); this.supportButton = page.getByRole('link', {name: 'Support'}); - this.favoritesButton = page.getByTestId('go-favorites-view'); + this.favoritesButton = page.getByRole('tab', {name: 'Favorites'}); } async clickPreferencesButton() {