diff --git a/apps/webapp/test/e2e_tests/README.md b/apps/webapp/test/e2e_tests/README.md index 14656267fc7..56fdac7ce86 100644 --- a/apps/webapp/test/e2e_tests/README.md +++ b/apps/webapp/test/e2e_tests/README.md @@ -9,7 +9,7 @@ Have 1Password's cli installed (op) Before running tests create the env file by ``` -op inject -i test/e2e_tests/.env.staging.tpl -o test/e2e_tests/.env +op inject -i apps/webapp/test/e2e_tests/.env.staging.tpl -o apps/webapp/test/e2e_tests/.env ``` It will generate .env file with variables from 1Password diff --git a/apps/webapp/test/e2e_tests/pageManager/webapp/cells/cellsConversation.page.ts b/apps/webapp/test/e2e_tests/pageManager/webapp/cells/cellsConversation.page.ts index cdb0b976e6f..eab6b3afd87 100644 --- a/apps/webapp/test/e2e_tests/pageManager/webapp/cells/cellsConversation.page.ts +++ b/apps/webapp/test/e2e_tests/pageManager/webapp/cells/cellsConversation.page.ts @@ -20,8 +20,6 @@ import {Locator, Page} from '@playwright/test'; import {User} from 'test/e2e_tests/data/user'; -import {selectByDataAttribute} from 'test/e2e_tests/utils/selector.util'; - import {ConversationPage} from '../pages/conversation.page'; export class CellsConversationPage extends ConversationPage { @@ -40,6 +38,17 @@ export class CellsConversationPage extends ConversationPage { } override getImageLocator(user: User): Locator { - return this.page.locator(`${selectByDataAttribute('item-message')} [aria-label^="Image from ${user.fullName}"]`); + return this.page.getByLabel(new RegExp(`^Image from ${user.fullName}`)).getByRole('img'); + } + + protected getVideoLocator(user: User): Locator { + return this.page.getByLabel(new RegExp(`^Image from ${user.fullName}`)).locator('video'); + } + + async isVideoFromUserVisible(user: User) { + // Wait for the video element to become visible + const locator = this.getVideoLocator(user); + + return await locator.isVisible(); } } diff --git a/apps/webapp/test/e2e_tests/pageManager/webapp/cells/cellsConversationFiles.page.ts b/apps/webapp/test/e2e_tests/pageManager/webapp/cells/cellsConversationFiles.page.ts index cd9a36a1987..b70e0e6efbf 100644 --- a/apps/webapp/test/e2e_tests/pageManager/webapp/cells/cellsConversationFiles.page.ts +++ b/apps/webapp/test/e2e_tests/pageManager/webapp/cells/cellsConversationFiles.page.ts @@ -21,15 +21,20 @@ import {Locator, Page} from '@playwright/test'; export class CellsConversationFilesPage { readonly page: Page; - readonly filesList: Locator; + filesList: Locator; + readonly searchInput: Locator; constructor(page: Page) { this.page = page; this.filesList = page.locator('table td[data-cell="Name"]'); + this.searchInput = page.getByRole('textbox', {name: 'Search files and folders'}); } - async clickFile(fileName: string) { - const file = this.filesList.getByRole('button', {name: fileName}); - await file.click(); + async searchFile(fileName: string) { + await this.searchInput.fill(fileName); + } + + getFile(fileName: string) { + return this.filesList.getByRole('button', {name: fileName}); } } diff --git a/apps/webapp/test/e2e_tests/specs/CriticalFlow/Cells/searchFilesInGroupConversation-TC-8788.spec.ts b/apps/webapp/test/e2e_tests/specs/CriticalFlow/Cells/searchFilesInGroupConversation-TC-8788.spec.ts new file mode 100644 index 00000000000..82c29d5ff92 --- /dev/null +++ b/apps/webapp/test/e2e_tests/specs/CriticalFlow/Cells/searchFilesInGroupConversation-TC-8788.spec.ts @@ -0,0 +1,99 @@ +/* + * Wire + * Copyright (C) 2025 Wire Swiss GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/. + * + */ + +import {User} from 'test/e2e_tests/data/user'; +import {PageManager} from 'test/e2e_tests/pageManager'; +import {getImageFilePath} from 'test/e2e_tests/utils/sendImage.util'; +import {getVideoFilePath, VideoFileName} from 'test/e2e_tests/utils/asset.util'; + +import {test, expect, withLogin} from '../../../test.fixtures'; + +// User A is a team owner, User B is a team member +let userA: User; +let userB: User; + +const teamName = 'Cells Critical Team'; +const conversationName = 'Cells Critical Conversation'; + +const imageFilePath = getImageFilePath(); +const videoFilePath = getVideoFilePath(); + +test.beforeEach(async ({createTeam}) => { + const team = await createTeam(teamName, {withMembers: 1}); + userA = team.owner; + userB = team.members[0]; +}); + +test( + 'Searching files in a group conversation', + {tag: ['@crit-flow-cells', '@regression', '@TC-8788']}, + async ({createPage, api}) => { + const [userAPage, userBPage] = await Promise.all([createPage(withLogin(userA)), createPage(withLogin(userB))]); + + const {pages: userAPages, components: userAComponents} = PageManager.from(userAPage).webapp; + const userBPages = PageManager.from(userBPage).webapp.pages; + + await test.step('Preconditions: Creating preconditions for the test via API', async () => { + await api.brig.unlockCellsFeature(userA.teamId); + await api.brig.enableCells(userA.teamId); + }); + + await test.step('Preconditions: Both users log in and open the group', async () => { + await userAPages.conversationList().clickCreateGroup(); + // Files should be disabled by default + expect(await userAPages.groupCreation().isFilesCheckboxChecked()).toBeFalsy(); + + await userAPages.groupCreation().enableFilesCheckbox(); + await userAPages.groupCreation().setGroupName(conversationName); + await userAPages.groupCreation().selectGroupMembers(userB.username); + await userAPages.groupCreation().clickCreateGroupButton(); + }); + + await test.step('User A sends a message with assets in a group conversation', async () => { + await userAPages.conversationList().openConversation(conversationName); + await userAComponents.inputBarControls().clickShareFile(imageFilePath); + await userAComponents.inputBarControls().clickShareFile(videoFilePath); + await userAComponents.inputBarControls().clickSendMessage(); + await userBPages.conversationList().openConversation(conversationName); + + expect(await userBPages.cellsConversation().isImageFromUserVisible(userA)).toBeTruthy(); + expect(await userBPages.cellsConversation().isVideoFromUserVisible(userA)).toBeTruthy(); + }); + + await test.step('User B opens Files tab and searches for a file', async () => { + await userBPages.conversation().clickFilesTab(); + + // Initially both files should be visible + await expect(userBPages.cellsConversationFiles().filesList).toHaveCount(2); + + // Search for a non-existing file + await userBPages.cellsConversationFiles().searchFile('non-existing-file.txt'); + await expect(userBPages.cellsConversationFiles().filesList).toHaveCount(0); + + // Search for the video file + await userBPages.cellsConversationFiles().searchFile(VideoFileName); + await expect(userBPages.cellsConversationFiles().filesList).toHaveCount(1); + await expect(userBPages.cellsConversationFiles().getFile(VideoFileName)).toBeVisible(); + + // Clearing the search input and making sure both files are visible again + await userBPages.cellsConversationFiles().searchFile(''); + await expect(userBPages.cellsConversationFiles().filesList).toHaveCount(2); + }); + }, +); diff --git a/apps/webapp/test/e2e_tests/specs/CriticalFlow/Cells/uploadingFileInGroupConversation.spec.ts b/apps/webapp/test/e2e_tests/specs/CriticalFlow/Cells/uploadingFileInGroupConversation.spec.ts index 2e23571ecbf..faee404a403 100644 --- a/apps/webapp/test/e2e_tests/specs/CriticalFlow/Cells/uploadingFileInGroupConversation.spec.ts +++ b/apps/webapp/test/e2e_tests/specs/CriticalFlow/Cells/uploadingFileInGroupConversation.spec.ts @@ -116,7 +116,7 @@ test( await test.step('User A opens group conversation files and sees the image file there', async () => { await userAPages.conversation().clickFilesTab(); - await userAPages.cellsConversationFiles().clickFile(ImageQRCodeFileName); + await userAPages.cellsConversationFiles().getFile(ImageQRCodeFileName).click(); expect(await userAModals.cellsFileDetailView().isImageVisible()).toBeTruthy(); }); diff --git a/apps/webapp/test/e2e_tests/utils/asset.util.ts b/apps/webapp/test/e2e_tests/utils/asset.util.ts index 0d5a129b369..88d1e2913d6 100644 --- a/apps/webapp/test/e2e_tests/utils/asset.util.ts +++ b/apps/webapp/test/e2e_tests/utils/asset.util.ts @@ -26,7 +26,7 @@ export const DownloadFilePath = './test-results/downloads/'; const e2eRootDir = path.join(__dirname, '../'); const fileTransferAssetsDir = path.join(e2eRootDir, 'assets/filetransfer'); -const VideoFileName = 'example.mp4'; +export const VideoFileName = 'example.mp4'; const AudioFileName = 'example.mp3'; const TextFileName = 'example.txt';