Skip to content
This repository has been archived by the owner on Sep 11, 2024. It is now read-only.

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
test ExportDialog with settings
Browse files Browse the repository at this point in the history
Signed-off-by: Kerry Archibald <[email protected]>
Kerry Archibald committed Jan 26, 2022

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
1 parent 2bd036a commit d5af324
Showing 5 changed files with 233 additions and 37 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -191,6 +191,7 @@
"stylelint": "^13.9.0",
"stylelint-config-standard": "^20.0.0",
"stylelint-scss": "^3.18.0",
"ts-jest": "^27.1.3",
"typescript": "4.5.3",
"walk": "^2.3.14"
},
8 changes: 5 additions & 3 deletions src/components/views/dialogs/ExportDialog.tsx
Original file line number Diff line number Diff line change
@@ -57,10 +57,11 @@ const validateNumberInRange = (min: number, max: number) => (value?: string | nu
};

// Sanitize setting values, exclude invalid or missing values
export const getSafeForceRoomExportSettings = (): {
export type ForceRoomExportSettings = {
format?: ExportFormat; range?: ExportType; numberOfMessages?: number; includeAttachments?: boolean; sizeMb?: number;
} => {
const config = SettingsStore.getValue(UIFeature.ForceRoomExportSettings);
};
export const getSafeForceRoomExportSettings = (): ForceRoomExportSettings => {
const config = SettingsStore.getValue<ForceRoomExportSettings>(UIFeature.ForceRoomExportSettings);
if (!config || typeof config !== "object") return {};

const { format, range, numberOfMessages, includeAttachments, sizeMb } = config;
@@ -87,6 +88,7 @@ interface ExportConfig {
setNumberOfMessages?: Dispatch<SetStateAction<number>>;
setSizeLimit?: Dispatch<SetStateAction<number>>;
}

/**
* Set up form state using UIFeature.ForceRoomExportSettings or defaults
* Form fields configured in ForceRoomExportSettings are not allowed to be edited
153 changes: 140 additions & 13 deletions test/components/views/dialogs/ExportDialog-test.tsx
Original file line number Diff line number Diff line change
@@ -16,22 +16,40 @@ limitations under the License.

import React from 'react';
import { mount } from 'enzyme';
import { mocked } from 'ts-jest/utils';
import '../../../skinned-sdk';
import { act } from "react-dom/test-utils";
import { Room } from 'matrix-js-sdk';

import ExportDialog from '../../../../src/components/views/dialogs/ExportDialog';
import ExportDialog,
{ getSafeForceRoomExportSettings, ForceRoomExportSettings }
from '../../../../src/components/views/dialogs/ExportDialog';
import { ExportType, ExportFormat } from '../../../../src/utils/exportUtils/exportUtils';
import { createTestClient, mkStubRoom } from '../../../test-utils';
import { MatrixClientPeg } from '../../../../src/MatrixClientPeg';
import HTMLExporter from "../../../../src/utils/exportUtils/HtmlExport";
import SettingsStore from '../../../../src/settings/SettingsStore';
import PlainTextExporter from '../../../../src/utils/exportUtils/PlainTextExport';

jest.useFakeTimers();

const mockHtmlExporter = ({
const htmlExporterInstance = ({
export: jest.fn().mockResolvedValue({}),
});
const plainTextExporterInstance = ({
export: jest.fn().mockResolvedValue({}),
});
jest.mock("../../../../src/utils/exportUtils/HtmlExport", () => jest.fn());
jest.mock("../../../../src/utils/exportUtils/PlainTextExport", () => jest.fn());

jest.mock('../../../../src/settings/SettingsStore', () => ({
monitorSetting: jest.fn(),
getValue: jest.fn(),
}));

const SettingsStoreMock = mocked(SettingsStore);
const HTMLExporterMock = mocked(HTMLExporter);
const PlainTextExporterMock = mocked(PlainTextExporter);

describe('<ExportDialog />', () => {
const mockClient = createTestClient();
@@ -81,8 +99,13 @@ describe('<ExportDialog />', () => {
});

beforeEach(() => {
(HTMLExporter as jest.Mock).mockImplementation(jest.fn().mockReturnValue(mockHtmlExporter));
mockHtmlExporter.export.mockClear();
HTMLExporterMock.mockClear().mockImplementation(jest.fn().mockReturnValue(htmlExporterInstance));
PlainTextExporterMock.mockClear().mockImplementation(jest.fn().mockReturnValue(plainTextExporterInstance));
htmlExporterInstance.export.mockClear();
plainTextExporterInstance.export.mockClear();

// default setting value
SettingsStoreMock.getValue.mockClear().mockReturnValue({});
});

it('renders export dialog', () => {
@@ -104,7 +127,7 @@ describe('<ExportDialog />', () => {
await submitForm(component);

// 4th arg is an component function
const exportConstructorProps = (HTMLExporter as jest.Mock).mock.calls[0].slice(0, 3);
const exportConstructorProps = HTMLExporterMock.mock.calls[0].slice(0, 3);
expect(exportConstructorProps).toEqual([
defaultProps.room,
ExportType.Timeline,
@@ -114,7 +137,32 @@ describe('<ExportDialog />', () => {
numberOfMessages: 100,
},
]);
expect(mockHtmlExporter.export).toHaveBeenCalled();
expect(htmlExporterInstance.export).toHaveBeenCalled();
});

it('exports room using values set from ForceRoomExportSettings', async () => {
SettingsStoreMock.getValue.mockReturnValue({
format: ExportFormat.PlainText,
range: ExportType.Beginning,
sizeMb: 15000,
numberOfMessages: 30,
attachmentsIncluded: true,
});
const component = getComponent();
await submitForm(component);

// 4th arg is an component function
const exportConstructorProps = PlainTextExporterMock.mock.calls[0].slice(0, 3);
expect(exportConstructorProps).toEqual([
defaultProps.room,
ExportType.Beginning,
{
attachmentsIncluded: false,
maxSize: 15000 * 1024 * 1024,
numberOfMessages: 30,
},
]);
expect(plainTextExporterInstance.export).toHaveBeenCalled();
});

it('renders success screen when export is finished', async () => {
@@ -139,6 +187,19 @@ describe('<ExportDialog />', () => {
expect(getExportFormatInput(component, ExportFormat.PlainText).props().checked).toBeTruthy();
expect(getExportFormatInput(component, ExportFormat.Html).props().checked).toBeFalsy();
});

it('hides export format input when format is valid in ForceRoomExportSettings', () => {
const component = getComponent();
expect(getExportFormatInput(component, ExportFormat.Html).props().checked).toBeTruthy();
});

it('does not render export format when set in ForceRoomExportSettings', () => {
SettingsStoreMock.getValue.mockReturnValue({
format: ExportFormat.PlainText,
});
const component = getComponent();
expect(getExportFormatInput(component, ExportFormat.Html).length).toBeFalsy();
});
});

describe('export type', () => {
@@ -153,6 +214,14 @@ describe('<ExportDialog />', () => {
expect(getExportTypeInput(component).props().value).toEqual(ExportType.Beginning);
});

it('does not render export type when set in ForceRoomExportSettings', () => {
SettingsStoreMock.getValue.mockReturnValue({
range: ExportType.Beginning,
});
const component = getComponent();
expect(getExportTypeInput(component).length).toBeFalsy();
});

it('does not render message count input', async () => {
const component = getComponent();
expect(getMessageCountInput(component).length).toBeFalsy();
@@ -177,7 +246,7 @@ describe('<ExportDialog />', () => {
await setMessageCount(component, 0);
await submitForm(component);

expect(mockHtmlExporter.export).not.toHaveBeenCalled();
expect(htmlExporterInstance.export).not.toHaveBeenCalled();
});

it('does not export when export type is lastNMessages and message count is more than max', async () => {
@@ -186,7 +255,7 @@ describe('<ExportDialog />', () => {
await setMessageCount(component, 99999999999);
await submitForm(component);

expect(mockHtmlExporter.export).not.toHaveBeenCalled();
expect(htmlExporterInstance.export).not.toHaveBeenCalled();
});

it('exports when export type is NOT lastNMessages and message count is falsy', async () => {
@@ -196,7 +265,7 @@ describe('<ExportDialog />', () => {
await selectExportType(component, ExportType.Timeline);
await submitForm(component);

expect(mockHtmlExporter.export).toHaveBeenCalled();
expect(htmlExporterInstance.export).toHaveBeenCalled();
});
});

@@ -217,27 +286,48 @@ describe('<ExportDialog />', () => {
await setSizeLimit(component, 0);
await submitForm(component);

expect(mockHtmlExporter.export).not.toHaveBeenCalled();
expect(htmlExporterInstance.export).not.toHaveBeenCalled();
});

it('does not export when size limit is larger than max', async () => {
const component = getComponent();
await setSizeLimit(component, 2001);
await submitForm(component);

expect(mockHtmlExporter.export).not.toHaveBeenCalled();
expect(htmlExporterInstance.export).not.toHaveBeenCalled();
});

it('exports when size limit is max', async () => {
const component = getComponent();
await setSizeLimit(component, 2000);
await submitForm(component);

expect(mockHtmlExporter.export).toHaveBeenCalled();
expect(htmlExporterInstance.export).toHaveBeenCalled();
});

it('does not render size limit input when set in ForceRoomExportSettings', () => {
SettingsStoreMock.getValue.mockReturnValue({
sizeMb: 10000,
});
const component = getComponent();
expect(getSizeInput(component).length).toBeFalsy();
});

/**
* 2000mb size limit does not apply when higher limit is configured in config
*/
it('exports when size limit set in ForceRoomExportSettings is larger than 2000', async () => {
SettingsStoreMock.getValue.mockReturnValue({
sizeMb: 10000,
});
const component = getComponent();
await submitForm(component);

expect(htmlExporterInstance.export).toHaveBeenCalled();
});
});

describe('include attachements', () => {
describe('include attachments', () => {
it('renders input with default value of false', () => {
const component = getComponent();
expect(getAttachmentsCheckbox(component).props().checked).toEqual(false);
@@ -248,6 +338,43 @@ describe('<ExportDialog />', () => {
await setIncludeAttachments(component, true);
expect(getAttachmentsCheckbox(component).props().checked).toEqual(true);
});

it('does not render input when set in ForceRoomExportSettings', () => {
SettingsStoreMock.getValue.mockReturnValue({
includeAttachments: false,
});
const component = getComponent();
expect(getAttachmentsCheckbox(component).length).toBeFalsy();
});
});

describe('getSafeForceRoomExportSettings()', () => {
const testCases: [string, ForceRoomExportSettings, ForceRoomExportSettings][] = [
['setting is falsy', undefined, {}],
['setting is configured to string', 'test' as unknown, {}],
['setting is empty', {}, {}],
['format is not a valid ExportFormat', { format: 'mp3' }, {}],
['format is a valid ExportFormat', { format: ExportFormat.Html }, { format: ExportFormat.Html }],
['range is not a valid ExportType', { range: 'yesterday' }, {}],
['range is a valid ExportType', { range: ExportType.LastNMessages }, { range: ExportType.LastNMessages }],
['numberOfMessages is not a number', { numberOfMessages: 'test' }, {}],
['numberOfMessages is less than 1', { numberOfMessages: -1 }, {}],
['numberOfMessages is more than 100000000', { numberOfMessages: 9999999999 }, {}],
['numberOfMessages is valid', { numberOfMessages: 2000 }, { numberOfMessages: 2000 }],
['sizeMb is not a number', { sizeMb: 'test' }, {}],
['sizeMb is less than 1', { sizeMb: -1 }, {}],
['sizeMb is more than 1024000', { sizeMb: Number.MAX_SAFE_INTEGER }, {}],
['sizeMb is valid', { sizeMb: 50000 }, { sizeMb: 50000 }],
['includeAttachments is not a boolean', { includeAttachments: 'yes' }, {}],
['includeAttachments is true', { includeAttachments: true }, { includeAttachments: true }],
['includeAttachments is false', { includeAttachments: false }, { includeAttachments: false }],
];

it.each(testCases)('sanitizes correctly when %s', (_d, setting, expected) => {
SettingsStoreMock.getValue.mockReturnValue(setting);

expect(getSafeForceRoomExportSettings()).toEqual(expected);
});
});
});

4 changes: 2 additions & 2 deletions test/utils/export-test.tsx
Original file line number Diff line number Diff line change
@@ -194,7 +194,7 @@ describe('export', function() {
).toBeTruthy();
});

const testCases: [string, IExportOptions][] = [
const invalidExportOptions: [string, IExportOptions][] = [
['numberOfMessages exceeds max', {
numberOfMessages: 10 ** 9,
maxSize: 1024 * 1024 * 1024,
@@ -211,7 +211,7 @@ describe('export', function() {
attachmentsIncluded: false,
}],
];
it.each(testCases)('%s', (_d, options) => {
it.each(invalidExportOptions)('%s', (_d, options) => {
expect(
() =>
new PlainTextExporter(mockRoom, ExportType.Beginning, options, null),
Loading

0 comments on commit d5af324

Please sign in to comment.