diff --git a/apps/meteor/client/views/room/contextualBar/ExportMessages/ExportMessages.tsx b/apps/meteor/client/views/room/contextualBar/ExportMessages/ExportMessages.tsx index 58b6e58567ae7..f03e0956b20df 100644 --- a/apps/meteor/client/views/room/contextualBar/ExportMessages/ExportMessages.tsx +++ b/apps/meteor/client/views/room/contextualBar/ExportMessages/ExportMessages.tsx @@ -109,7 +109,14 @@ const ExportMessages = () => { }, [t, pfdExportPermission]); // Remove HTML from download options - const downloadOutputOptions = outputOptions.slice(1); + const downloadOutputOptions = useMemo(() => { + return outputOptions.filter((option) => option[0] !== 'html'); + }, [outputOptions]); + + // Remove PDF from file options + const fileOutputOptions = useMemo(() => { + return outputOptions.filter((option) => option[0] !== 'pdf'); + }, [outputOptions]); const { mutateAsync: exportRoom } = useRoomExportMutation(); const { mutateAsync: exportAndDownload } = useDownloadExportMutation(); @@ -201,7 +208,7 @@ const ExportMessages = () => { const subjectField = useId(); return ( - + {t('Export_Messages')} @@ -224,7 +231,14 @@ const ExportMessages = () => { name='type' control={control} render={({ field }) => ( - )} /> @@ -235,15 +249,28 @@ const ExportMessages = () => { ( - + ); + }} /> diff --git a/apps/meteor/tests/e2e/e2e-encryption.spec.ts b/apps/meteor/tests/e2e/e2e-encryption.spec.ts index 038e736adc57f..6e8b1cce98952 100644 --- a/apps/meteor/tests/e2e/e2e-encryption.spec.ts +++ b/apps/meteor/tests/e2e/e2e-encryption.spec.ts @@ -16,8 +16,8 @@ import { SaveE2EEPasswordBanner, SaveE2EEPasswordModal, } from './page-objects/fragments/e2ee'; +import { ExportMessagesTab } from './page-objects/fragments/export-messages-tab'; import { FileUploadModal } from './page-objects/fragments/file-upload-modal'; -import { HomeFlextabExportMessages } from './page-objects/fragments/home-flextab-exportMessages'; import { LoginPage } from './page-objects/login'; import { test, expect } from './utils/test'; @@ -272,7 +272,7 @@ test.describe('basic features', () => { test('should display only the download file method when exporting messages in an e2ee room', async ({ page }) => { const sidenav = new HomeSidenav(page); const encryptedRoomPage = new EncryptedRoomPage(page); - const exportMessagesTab = new HomeFlextabExportMessages(page); + const exportMessagesTab = new ExportMessagesTab(page); const channelName = faker.string.uuid(); @@ -281,14 +281,14 @@ test.describe('basic features', () => { await expect(encryptedRoomPage.encryptedRoomHeaderIcon).toBeVisible(); await encryptedRoomPage.showExportMessagesTab(); - await expect(exportMessagesTab.downloadFileMethod).toBeVisible(); - await expect(exportMessagesTab.sendEmailMethod).not.toBeVisible(); + await expect(exportMessagesTab.method).toContainClass('disabled'); // FIXME: looks like the component have an a11y issue + await expect(exportMessagesTab.method).toHaveAccessibleName('Download file'); }); test('should allow exporting messages as PDF in an encrypted room', async ({ page }) => { const sidenav = new HomeSidenav(page); const encryptedRoomPage = new EncryptedRoomPage(page); - const exportMessagesTab = new HomeFlextabExportMessages(page); + const exportMessagesTab = new ExportMessagesTab(page); const channelName = faker.string.uuid(); @@ -298,19 +298,17 @@ test.describe('basic features', () => { await encryptedRoomPage.sendMessage('This is a message to export as PDF.'); await encryptedRoomPage.showExportMessagesTab(); - await expect(exportMessagesTab.downloadFileMethod).toBeVisible(); + await expect(exportMessagesTab.method).toHaveAccessibleName('Download file'); // Select Output format as PDF - await exportMessagesTab.outputFormat.click(); - await exportMessagesTab.getMethodByName('PDF').click(); + await exportMessagesTab.setOutputFormat('PDF'); // select messages to be exported - await exportMessagesTab.btnSelectMessages.click(); + await exportMessagesTab.selectAllMessages(); // Wait for download event and match format - const [download] = await Promise.all([page.waitForEvent('download'), exportMessagesTab.btnDownloadExportMessages.click()]); - const suggestedFilename = download.suggestedFilename(); - expect(suggestedFilename).toMatch(/\.pdf$/); + const download = await exportMessagesTab.downloadMessages(); + expect(download.suggestedFilename()).toMatch(/\.pdf$/); }); }); diff --git a/apps/meteor/tests/e2e/export-messages.spec.ts b/apps/meteor/tests/e2e/export-messages.spec.ts index a91b071f0c8be..3c1804f6c2062 100644 --- a/apps/meteor/tests/e2e/export-messages.spec.ts +++ b/apps/meteor/tests/e2e/export-messages.spec.ts @@ -1,5 +1,6 @@ import { Users } from './fixtures/userStates'; import { HomeChannel, Utils } from './page-objects'; +import { ExportMessagesTab } from './page-objects/fragments/export-messages-tab'; import { createTargetChannel } from './utils'; import { test, expect } from './utils/test'; @@ -21,19 +22,51 @@ test.describe.serial('export-messages', () => { await page.goto('/home'); }); - test('should all export methods be available in targetChannel', async () => { + test('should all export methods be available in targetChannel', async ({ page }) => { + const exportMessagesTab = new ExportMessagesTab(page); + await poHomeChannel.sidenav.openChat(targetChannel); await poHomeChannel.tabs.kebab.click({ force: true }); await poHomeChannel.tabs.btnExportMessages.click(); - await expect(poHomeChannel.tabs.exportMessages.sendEmailMethod).not.toBeDisabled(); - await poHomeChannel.tabs.exportMessages.sendEmailMethod.click(); - await expect(poHomeChannel.tabs.exportMessages.getMethodByName('Send email')).toBeVisible(); - await expect(poHomeChannel.tabs.exportMessages.getMethodByName('Send file via email')).toBeVisible(); - await expect(poHomeChannel.tabs.exportMessages.getMethodByName('Download file')).toBeVisible(); + 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(); }); - test('should display an error when trying to send email without filling to users or to additional emails', async () => { + test('should display export output format correctly depending on the selected method', async ({ page }) => { + const exportMessagesTab = new ExportMessagesTab(page); + + await poHomeChannel.sidenav.openChat(targetChannel); + await poHomeChannel.tabs.kebab.click({ force: true }); + await poHomeChannel.tabs.btnExportMessages.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 exportMessagesTab.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 exportMessagesTab.setOutputFormat('html'); + + await exportMessagesTab.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(); + }); + + 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); + await poHomeChannel.sidenav.openChat(targetChannel); await poHomeChannel.content.sendMessage('hello world'); await poHomeChannel.tabs.kebab.click({ force: true }); @@ -42,20 +75,22 @@ test.describe.serial('export-messages', () => { await expect(poHomeChannel.btnContextualbarClose).toBeVisible(); await poHomeChannel.content.getMessageByText('hello world').click(); - await poHomeChannel.tabs.exportMessages.btnSend.click(); + await exportMessagesTab.send(); await expect( poUtils.getAlertByText('You must select one or more users or provide one or more email addresses, separated by commas'), ).toBeVisible(); }); - test('should display an error when trying to send email without selecting any message', async () => { + test('should display an error when trying to send email without selecting any message', async ({ page }) => { + const exportMessagesTab = new ExportMessagesTab(page); + await poHomeChannel.sidenav.openChat(targetChannel); await poHomeChannel.tabs.kebab.click({ force: true }); await poHomeChannel.tabs.btnExportMessages.click(); - await poHomeChannel.tabs.exportMessages.textboxAdditionalEmails.fill('mail@mail.com'); - await poHomeChannel.tabs.exportMessages.btnSend.click(); + await exportMessagesTab.setAdditionalEmail('mail@mail.com'); + await exportMessagesTab.send(); await expect(poUtils.getAlertByText(`You haven't selected any messages`)).toBeVisible(); }); diff --git a/apps/meteor/tests/e2e/page-objects/fragments/export-messages-tab.ts b/apps/meteor/tests/e2e/page-objects/fragments/export-messages-tab.ts new file mode 100644 index 0000000000000..b2604b6b6f409 --- /dev/null +++ b/apps/meteor/tests/e2e/page-objects/fragments/export-messages-tab.ts @@ -0,0 +1,75 @@ +import type { Locator, Page } from '@playwright/test'; + +export class ExportMessagesTab { + private readonly root: Locator; + + constructor(page: Page) { + this.root = page.getByRole('dialog', { name: 'Export Messages' }); + } + + async exposeMethods() { + await this.method.click(); + } + + async setMethod(optionName: string) { + await this.exposeMethods(); + await this.root.page().getByRole('option', { name: optionName }).click(); + } + + async exposeOutputFormats() { + await this.outputFormat.click(); + } + + async setOutputFormat(optionName: string) { + await this.exposeOutputFormats(); + await this.root.page().getByRole('option', { name: optionName }).click(); + } + + getMethodOptionByName(name: string) { + return this.root.page().getByRole('option', { name }); + } + + getOutputFormatOptionByName(name: string) { + return this.root.page().getByRole('option', { name }); + } + + async selectAllMessages() { + await this.root + .page() + .getByRole('button', { name: /Select \d+ messages/ }) + .click(); + } + + async downloadMessages() { + const [download] = await Promise.all([this.root.page().waitForEvent('download'), this.downloadButton.click()]); + return download; + } + + async send() { + await this.sendButton.click(); + } + + async setAdditionalEmail(email: string) { + await this.toAdditionalEmailsInput.fill(email); + } + + get method() { + return this.root.getByTestId('export-messages-method'); + } + + get outputFormat() { + return this.root.page().getByTestId('export-messages-output-format'); + } + + get toAdditionalEmailsInput() { + return this.root.getByRole('textbox', { name: 'To additional emails' }); + } + + get downloadButton() { + return this.root.getByRole('button', { name: 'Download', exact: true }); + } + + get sendButton() { + return this.root.getByRole('button', { name: 'Send', exact: true }); + } +} diff --git a/apps/meteor/tests/e2e/page-objects/fragments/home-flextab-exportMessages.ts b/apps/meteor/tests/e2e/page-objects/fragments/home-flextab-exportMessages.ts deleted file mode 100644 index 1359caa4712cb..0000000000000 --- a/apps/meteor/tests/e2e/page-objects/fragments/home-flextab-exportMessages.ts +++ /dev/null @@ -1,45 +0,0 @@ -import type { Page } from '@playwright/test'; - -export class HomeFlextabExportMessages { - private readonly page: Page; - - constructor(page: Page) { - this.page = page; - } - - get sendEmailMethod() { - return this.page.getByLabel('Send email'); - } - - get downloadFileMethod() { - return this.page.getByLabel('Download file'); - } - - getMethodByName(name: string) { - return this.page.getByRole('option', { name }); - } - - get outputFormat() { - return this.page.getByRole('button', { name: 'JSON' }); - } - - get btnSelectMessages() { - return this.page.getByRole('button', { name: 'Select 1 messages' }); - } - - get btnDownloadExportMessages() { - return this.page.getByRole('button', { name: 'Download', exact: true }); - } - - get textboxAdditionalEmails() { - return this.page.getByRole('textbox', { name: 'To additional emails' }); - } - - get btnSend() { - return this.page.locator('role=button[name="Send"]'); - } - - get btnCancel() { - return this.page.locator('role=button[name="Cancel"]'); - } -} diff --git a/apps/meteor/tests/e2e/page-objects/fragments/home-flextab.ts b/apps/meteor/tests/e2e/page-objects/fragments/home-flextab.ts index 0f67340aec592..c48448ebaed02 100644 --- a/apps/meteor/tests/e2e/page-objects/fragments/home-flextab.ts +++ b/apps/meteor/tests/e2e/page-objects/fragments/home-flextab.ts @@ -1,7 +1,7 @@ import type { Locator, Page } from '@playwright/test'; +import { ExportMessagesTab } from './export-messages-tab'; import { HomeFlextabChannels } from './home-flextab-channels'; -import { HomeFlextabExportMessages } from './home-flextab-exportMessages'; import { HomeFlextabMembers } from './home-flextab-members'; import { HomeFlextabNotificationPreferences } from './home-flextab-notificationPreferences'; import { HomeFlextabOtr } from './home-flextab-otr'; @@ -21,7 +21,7 @@ export class HomeFlextab { readonly otr: HomeFlextabOtr; - readonly exportMessages: HomeFlextabExportMessages; + readonly exportMessages: ExportMessagesTab; readonly pruneMessages: HomeFlextabPruneMessages; @@ -32,7 +32,7 @@ export class HomeFlextab { this.channels = new HomeFlextabChannels(page); this.notificationPreferences = new HomeFlextabNotificationPreferences(page); this.otr = new HomeFlextabOtr(page); - this.exportMessages = new HomeFlextabExportMessages(page); + this.exportMessages = new ExportMessagesTab(page); this.pruneMessages = new HomeFlextabPruneMessages(page); } diff --git a/apps/meteor/tests/e2e/page-objects/login.ts b/apps/meteor/tests/e2e/page-objects/login.ts index e1a3bc4edc257..87caa9312bf58 100644 --- a/apps/meteor/tests/e2e/page-objects/login.ts +++ b/apps/meteor/tests/e2e/page-objects/login.ts @@ -10,7 +10,7 @@ export class LoginPage { constructor(protected readonly page: Page) {} get loginButton() { - return this.page.getByRole('button', { name: 'Login' }); + return this.page.getByRole('button', { name: 'Login', exact: true }); } /** @deprecated ideally the previous action should ensure the user is logged out and we should just assume to be at the login page */