Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,14 @@ const ExportMessages = () => {
}, [t, pfdExportPermission]);

// Remove HTML from download options
const downloadOutputOptions = outputOptions.slice(1);
const downloadOutputOptions = useMemo<SelectOption[]>(() => {
return outputOptions.filter((option) => option[0] !== 'html');
}, [outputOptions]);

// Remove PDF from file options
const fileOutputOptions = useMemo<SelectOption[]>(() => {
return outputOptions.filter((option) => option[0] !== 'pdf');
}, [outputOptions]);

const { mutateAsync: exportRoom } = useRoomExportMutation();
const { mutateAsync: exportAndDownload } = useDownloadExportMutation();
Expand Down Expand Up @@ -201,7 +208,7 @@ const ExportMessages = () => {
const subjectField = useId();

return (
<ContextualbarDialog>
<ContextualbarDialog aria-labelledby={`${formId}-title`}>
<ContextualbarHeader>
<ContextualbarIcon name='mail' />
<ContextualbarTitle id={`${formId}-title`}>{t('Export_Messages')}</ContextualbarTitle>
Expand All @@ -224,7 +231,14 @@ const ExportMessages = () => {
name='type'
control={control}
render={({ field }) => (
<Select id={methodField} {...field} placeholder={t('Type')} disabled={isE2ERoom} options={exportOptions} />
<Select
id={methodField}
data-testid='export-messages-method'
{...field}
placeholder={t('Type')}
disabled={isE2ERoom}
options={exportOptions}
/>
)}
/>
</FieldRow>
Expand All @@ -235,15 +249,28 @@ const ExportMessages = () => {
<Controller
name='format'
control={control}
render={({ field }) => (
<Select
{...field}
id={formatField}
disabled={type === 'email'}
placeholder={t('Format')}
options={type === 'download' ? downloadOutputOptions : outputOptions}
/>
)}
render={({ field }) => {
let options: SelectOption[];

if (type === 'download') {
options = downloadOutputOptions;
} else if (type === 'file') {
options = fileOutputOptions;
} else {
options = outputOptions;
}

return (
<Select
{...field}
id={formatField}
data-testid='export-messages-output-format'
disabled={type === 'email'}
placeholder={t('Format')}
options={options}
/>
);
}}
/>
</FieldRow>
</Field>
Expand Down
22 changes: 10 additions & 12 deletions apps/meteor/tests/e2e/e2e-encryption.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand Down Expand Up @@ -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();

Expand All @@ -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();

Expand All @@ -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$/);
});
});

Expand Down
57 changes: 46 additions & 11 deletions apps/meteor/tests/e2e/export-messages.spec.ts
Original file line number Diff line number Diff line change
@@ -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';

Expand All @@ -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 });
Expand All @@ -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('[email protected]');
await poHomeChannel.tabs.exportMessages.btnSend.click();
await exportMessagesTab.setAdditionalEmail('[email protected]');
await exportMessagesTab.send();

await expect(poUtils.getAlertByText(`You haven't selected any messages`)).toBeVisible();
});
Expand Down
Original file line number Diff line number Diff line change
@@ -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 });
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -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';
Expand All @@ -21,7 +21,7 @@ export class HomeFlextab {

readonly otr: HomeFlextabOtr;

readonly exportMessages: HomeFlextabExportMessages;
readonly exportMessages: ExportMessagesTab;

readonly pruneMessages: HomeFlextabPruneMessages;

Expand All @@ -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);
}

Expand Down
2 changes: 1 addition & 1 deletion apps/meteor/tests/e2e/page-objects/login.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down
Loading