mirror of
				https://github.com/vector-im/element-web.git
				synced 2025-11-04 10:11:03 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			349 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			349 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
/*
 | 
						|
Copyright 2022 The Matrix.org Foundation C.I.C.
 | 
						|
 | 
						|
Licensed under the Apache License, Version 2.0 (the "License");
 | 
						|
you may not use this file except in compliance with the License.
 | 
						|
You may obtain a copy of the License at
 | 
						|
 | 
						|
    http://www.apache.org/licenses/LICENSE-2.0
 | 
						|
 | 
						|
Unless required by applicable law or agreed to in writing, software
 | 
						|
distributed under the License is distributed on an "AS IS" BASIS,
 | 
						|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
						|
See the License for the specific language governing permissions and
 | 
						|
limitations under the License.
 | 
						|
*/
 | 
						|
 | 
						|
import React from 'react';
 | 
						|
// eslint-disable-next-line deprecate/import
 | 
						|
import { mount } from 'enzyme';
 | 
						|
import { mocked } from 'jest-mock';
 | 
						|
import { act } from "react-dom/test-utils";
 | 
						|
import { Room } from 'matrix-js-sdk/src/matrix';
 | 
						|
 | 
						|
import ExportDialog 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 ChatExport from '../../../../src/customisations/ChatExport';
 | 
						|
import PlainTextExporter from '../../../../src/utils/exportUtils/PlainTextExport';
 | 
						|
 | 
						|
jest.useFakeTimers();
 | 
						|
 | 
						|
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/customisations/ChatExport', () => ({
 | 
						|
    getForceChatExportParameters: jest.fn().mockReturnValue({}),
 | 
						|
}));
 | 
						|
 | 
						|
const ChatExportMock = mocked(ChatExport);
 | 
						|
const HTMLExporterMock = mocked(HTMLExporter);
 | 
						|
const PlainTextExporterMock = mocked(PlainTextExporter);
 | 
						|
 | 
						|
describe('<ExportDialog />', () => {
 | 
						|
    const mockClient = createTestClient();
 | 
						|
    jest.spyOn(MatrixClientPeg, 'get').mockReturnValue(mockClient);
 | 
						|
 | 
						|
    const roomId = 'test:test.org';
 | 
						|
    const defaultProps = {
 | 
						|
        room: mkStubRoom(roomId, 'test', mockClient) as unknown as Room,
 | 
						|
        onFinished: jest.fn(),
 | 
						|
    };
 | 
						|
 | 
						|
    const getComponent = (props = {}) => mount(<ExportDialog {...defaultProps} {...props} />);
 | 
						|
 | 
						|
    const getSizeInput = (component) => component.find('input[id="size-limit"]');
 | 
						|
    const getExportTypeInput = (component) => component.find('select[id="export-type"]');
 | 
						|
    const getAttachmentsCheckbox = (component) => component.find('input[id="include-attachments"]');
 | 
						|
    const getMessageCountInput = (component) => component.find('input[id="message-count"]');
 | 
						|
    const getExportFormatInput = (component, format) => component.find(`input[id="exportFormat-${format}"]`);
 | 
						|
    const getPrimaryButton = (component) => component.find('[data-test-id="dialog-primary-button"]');
 | 
						|
    const getSecondaryButton = (component) => component.find('[data-test-id="dialog-cancel-button"]');
 | 
						|
 | 
						|
    const submitForm = async (component) => act(async () => {
 | 
						|
        getPrimaryButton(component).simulate('click');
 | 
						|
        component.setProps({});
 | 
						|
    });
 | 
						|
    const selectExportFormat = async (component, format: ExportFormat) => act(async () => {
 | 
						|
        getExportFormatInput(component, format).simulate('change');
 | 
						|
        component.setProps({});
 | 
						|
    });
 | 
						|
    const selectExportType = async (component, type: ExportType) => act(async () => {
 | 
						|
        getExportTypeInput(component).simulate('change', { target: { value: type } });
 | 
						|
        component.setProps({});
 | 
						|
    });
 | 
						|
    const setMessageCount = async (component, count: number) => act(async () => {
 | 
						|
        getMessageCountInput(component).simulate('change', { target: { value: count } });
 | 
						|
        component.setProps({});
 | 
						|
    });
 | 
						|
 | 
						|
    const setSizeLimit = async (component, limit: number) => act(async () => {
 | 
						|
        getSizeInput(component).simulate('change', { target: { value: limit } });
 | 
						|
        component.setProps({});
 | 
						|
    });
 | 
						|
 | 
						|
    const setIncludeAttachments = async (component, checked) => act(async () => {
 | 
						|
        getAttachmentsCheckbox(component).simulate('change', { target: { checked } });
 | 
						|
        component.setProps({});
 | 
						|
    });
 | 
						|
 | 
						|
    beforeEach(() => {
 | 
						|
        HTMLExporterMock.mockClear().mockImplementation(jest.fn().mockReturnValue(htmlExporterInstance));
 | 
						|
        PlainTextExporterMock.mockClear().mockImplementation(jest.fn().mockReturnValue(plainTextExporterInstance));
 | 
						|
        htmlExporterInstance.export.mockClear();
 | 
						|
        plainTextExporterInstance.export.mockClear();
 | 
						|
 | 
						|
        // default setting value
 | 
						|
        ChatExportMock.getForceChatExportParameters.mockClear().mockReturnValue({});
 | 
						|
    });
 | 
						|
 | 
						|
    it('renders export dialog', () => {
 | 
						|
        const component = getComponent();
 | 
						|
        expect(component.find('.mx_ExportDialog')).toMatchSnapshot();
 | 
						|
    });
 | 
						|
 | 
						|
    it('calls onFinished when cancel button is clicked', () => {
 | 
						|
        const onFinished = jest.fn();
 | 
						|
        const component = getComponent({ onFinished });
 | 
						|
        act(() => {
 | 
						|
            getSecondaryButton(component).simulate('click');
 | 
						|
        });
 | 
						|
        expect(onFinished).toHaveBeenCalledWith(false);
 | 
						|
    });
 | 
						|
 | 
						|
    it('exports room on submit', async () => {
 | 
						|
        const component = getComponent();
 | 
						|
        await submitForm(component);
 | 
						|
 | 
						|
        // 4th arg is an component function
 | 
						|
        const exportConstructorProps = HTMLExporterMock.mock.calls[0].slice(0, 3);
 | 
						|
        expect(exportConstructorProps).toEqual([
 | 
						|
            defaultProps.room,
 | 
						|
            ExportType.Timeline,
 | 
						|
            {
 | 
						|
                attachmentsIncluded: false,
 | 
						|
                maxSize: 8388608, // 8MB to bytes
 | 
						|
                numberOfMessages: 100,
 | 
						|
            },
 | 
						|
        ]);
 | 
						|
        expect(htmlExporterInstance.export).toHaveBeenCalled();
 | 
						|
    });
 | 
						|
 | 
						|
    it('exports room using values set from ForceRoomExportParameters', async () => {
 | 
						|
        ChatExportMock.getForceChatExportParameters.mockReturnValue({
 | 
						|
            format: ExportFormat.PlainText,
 | 
						|
            range: ExportType.Beginning,
 | 
						|
            sizeMb: 7000,
 | 
						|
            numberOfMessages: 30,
 | 
						|
            includeAttachments: 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: true,
 | 
						|
                maxSize: 7000 * 1024 * 1024,
 | 
						|
                numberOfMessages: 30,
 | 
						|
            },
 | 
						|
        ]);
 | 
						|
        expect(plainTextExporterInstance.export).toHaveBeenCalled();
 | 
						|
    });
 | 
						|
 | 
						|
    it('renders success screen when export is finished', async () => {
 | 
						|
        const component = getComponent();
 | 
						|
        await submitForm(component);
 | 
						|
        component.setProps({});
 | 
						|
 | 
						|
        jest.runAllTimers();
 | 
						|
 | 
						|
        expect(component.find('.mx_InfoDialog .mx_Dialog_content')).toMatchSnapshot();
 | 
						|
    });
 | 
						|
 | 
						|
    describe('export format', () => {
 | 
						|
        it('renders export format with html selected by default', () => {
 | 
						|
            const component = getComponent();
 | 
						|
            expect(getExportFormatInput(component, ExportFormat.Html).props().checked).toBeTruthy();
 | 
						|
        });
 | 
						|
 | 
						|
        it('sets export format on radio button click', async () => {
 | 
						|
            const component = getComponent();
 | 
						|
            await selectExportFormat(component, ExportFormat.PlainText);
 | 
						|
            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 ForceRoomExportParameters', () => {
 | 
						|
            const component = getComponent();
 | 
						|
            expect(getExportFormatInput(component, ExportFormat.Html).props().checked).toBeTruthy();
 | 
						|
        });
 | 
						|
 | 
						|
        it('does not render export format when set in ForceRoomExportParameters', () => {
 | 
						|
            ChatExportMock.getForceChatExportParameters.mockReturnValue({
 | 
						|
                format: ExportFormat.PlainText,
 | 
						|
            });
 | 
						|
            const component = getComponent();
 | 
						|
            expect(getExportFormatInput(component, ExportFormat.Html).length).toBeFalsy();
 | 
						|
        });
 | 
						|
    });
 | 
						|
 | 
						|
    describe('export type', () => {
 | 
						|
        it('renders export type with timeline selected by default', () => {
 | 
						|
            const component = getComponent();
 | 
						|
            expect(getExportTypeInput(component).props().value).toEqual(ExportType.Timeline);
 | 
						|
        });
 | 
						|
 | 
						|
        it('sets export type on change', async () => {
 | 
						|
            const component = getComponent();
 | 
						|
            await selectExportType(component, ExportType.Beginning);
 | 
						|
            expect(getExportTypeInput(component).props().value).toEqual(ExportType.Beginning);
 | 
						|
        });
 | 
						|
 | 
						|
        it('does not render export type when set in ForceRoomExportParameters', () => {
 | 
						|
            ChatExportMock.getForceChatExportParameters.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();
 | 
						|
        });
 | 
						|
 | 
						|
        it('renders message count input with default value 100 when export type is lastNMessages', async () => {
 | 
						|
            const component = getComponent();
 | 
						|
            await selectExportType(component, ExportType.LastNMessages);
 | 
						|
            expect(getMessageCountInput(component).props().value).toEqual("100");
 | 
						|
        });
 | 
						|
 | 
						|
        it('sets message count on change', async () => {
 | 
						|
            const component = getComponent();
 | 
						|
            await selectExportType(component, ExportType.LastNMessages);
 | 
						|
            await setMessageCount(component, 10);
 | 
						|
            expect(getMessageCountInput(component).props().value).toEqual("10");
 | 
						|
        });
 | 
						|
 | 
						|
        it('does not export when export type is lastNMessages and message count is falsy', async () => {
 | 
						|
            const component = getComponent();
 | 
						|
            await selectExportType(component, ExportType.LastNMessages);
 | 
						|
            await setMessageCount(component, 0);
 | 
						|
            await submitForm(component);
 | 
						|
 | 
						|
            expect(htmlExporterInstance.export).not.toHaveBeenCalled();
 | 
						|
        });
 | 
						|
 | 
						|
        it('does not export when export type is lastNMessages and message count is more than max', async () => {
 | 
						|
            const component = getComponent();
 | 
						|
            await selectExportType(component, ExportType.LastNMessages);
 | 
						|
            await setMessageCount(component, 99999999999);
 | 
						|
            await submitForm(component);
 | 
						|
 | 
						|
            expect(htmlExporterInstance.export).not.toHaveBeenCalled();
 | 
						|
        });
 | 
						|
 | 
						|
        it('exports when export type is NOT lastNMessages and message count is falsy', async () => {
 | 
						|
            const component = getComponent();
 | 
						|
            await selectExportType(component, ExportType.LastNMessages);
 | 
						|
            await setMessageCount(component, 0);
 | 
						|
            await selectExportType(component, ExportType.Timeline);
 | 
						|
            await submitForm(component);
 | 
						|
 | 
						|
            expect(htmlExporterInstance.export).toHaveBeenCalled();
 | 
						|
        });
 | 
						|
    });
 | 
						|
 | 
						|
    describe('size limit', () => {
 | 
						|
        it('renders size limit input with default value', () => {
 | 
						|
            const component = getComponent();
 | 
						|
            expect(getSizeInput(component).props().value).toEqual("8");
 | 
						|
        });
 | 
						|
 | 
						|
        it('updates size limit on change', async () => {
 | 
						|
            const component = getComponent();
 | 
						|
            await setSizeLimit(component, 20);
 | 
						|
            expect(getSizeInput(component).props().value).toEqual("20");
 | 
						|
        });
 | 
						|
 | 
						|
        it('does not export when size limit is falsy', async () => {
 | 
						|
            const component = getComponent();
 | 
						|
            await setSizeLimit(component, 0);
 | 
						|
            await submitForm(component);
 | 
						|
 | 
						|
            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(htmlExporterInstance.export).not.toHaveBeenCalled();
 | 
						|
        });
 | 
						|
 | 
						|
        it('exports when size limit is max', async () => {
 | 
						|
            const component = getComponent();
 | 
						|
            await setSizeLimit(component, 2000);
 | 
						|
            await submitForm(component);
 | 
						|
 | 
						|
            expect(htmlExporterInstance.export).toHaveBeenCalled();
 | 
						|
        });
 | 
						|
 | 
						|
        it('does not render size limit input when set in ForceRoomExportParameters', () => {
 | 
						|
            ChatExportMock.getForceChatExportParameters.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 ForceRoomExportParameters is larger than 2000', async () => {
 | 
						|
            ChatExportMock.getForceChatExportParameters.mockReturnValue({
 | 
						|
                sizeMb: 10000,
 | 
						|
            });
 | 
						|
            const component = getComponent();
 | 
						|
            await submitForm(component);
 | 
						|
 | 
						|
            expect(htmlExporterInstance.export).toHaveBeenCalled();
 | 
						|
        });
 | 
						|
    });
 | 
						|
 | 
						|
    describe('include attachments', () => {
 | 
						|
        it('renders input with default value of false', () => {
 | 
						|
            const component = getComponent();
 | 
						|
            expect(getAttachmentsCheckbox(component).props().checked).toEqual(false);
 | 
						|
        });
 | 
						|
 | 
						|
        it('updates include attachments on change', async () => {
 | 
						|
            const component = getComponent();
 | 
						|
            await setIncludeAttachments(component, true);
 | 
						|
            expect(getAttachmentsCheckbox(component).props().checked).toEqual(true);
 | 
						|
        });
 | 
						|
 | 
						|
        it('does not render input when set in ForceRoomExportParameters', () => {
 | 
						|
            ChatExportMock.getForceChatExportParameters.mockReturnValue({
 | 
						|
                includeAttachments: false,
 | 
						|
            });
 | 
						|
            const component = getComponent();
 | 
						|
            expect(getAttachmentsCheckbox(component).length).toBeFalsy();
 | 
						|
        });
 | 
						|
    });
 | 
						|
});
 | 
						|
 |