/* Copyright 2024 New Vector Ltd. Copyright 2023 The Matrix.org Foundation C.I.C. SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only Please see LICENSE files in the repository root for full details. */ import { IEventRelation, MatrixEvent } from "matrix-js-sdk/src/matrix"; import { waitFor } from "@testing-library/react"; import { TimelineRenderingType } from "../../../../../../src/contexts/RoomContext"; import { mkStubRoom, stubClient } from "../../../../../test-utils"; import ContentMessages from "../../../../../../src/ContentMessages"; import { IRoomState } from "../../../../../../src/components/structures/RoomView"; import { handleClipboardEvent, isEventToHandleAsClipboardEvent, } from "../../../../../../src/components/views/rooms/wysiwyg_composer/hooks/utils"; const mockClient = stubClient(); const mockRoom = mkStubRoom("mock room", "mock room", mockClient); const mockRoomState = { room: mockRoom, timelineRenderingType: TimelineRenderingType.Room, replyToEvent: {} as unknown as MatrixEvent, } as unknown as IRoomState; const sendContentListToRoomSpy = jest.spyOn(ContentMessages.sharedInstance(), "sendContentListToRoom"); const sendContentToRoomSpy = jest.spyOn(ContentMessages.sharedInstance(), "sendContentToRoom"); const fetchSpy = jest.spyOn(window, "fetch"); const logSpy = jest.spyOn(console, "log").mockImplementation(() => {}); describe("handleClipboardEvent", () => { beforeEach(() => { jest.clearAllMocks(); }); afterAll(() => { jest.restoreAllMocks(); }); function createMockClipboardEvent(props: any): ClipboardEvent { return { clipboardData: { files: [], types: [] }, ...props } as ClipboardEvent; } it("returns false if it is not a paste event", () => { const originalEvent = createMockClipboardEvent({ type: "copy" }); const output = handleClipboardEvent(originalEvent, originalEvent.clipboardData, mockRoomState, mockClient); expect(output).toBe(false); }); it("returns false if clipboard data is null", () => { const originalEvent = createMockClipboardEvent({ type: "paste", clipboardData: null }); const output = handleClipboardEvent(originalEvent, originalEvent.clipboardData, mockRoomState, mockClient); expect(output).toBe(false); }); it("returns false if room is undefined", () => { const originalEvent = createMockClipboardEvent({ type: "paste" }); const { room, ...roomStateWithoutRoom } = mockRoomState; const output = handleClipboardEvent( originalEvent, originalEvent.clipboardData, roomStateWithoutRoom, mockClient, ); expect(output).toBe(false); }); it("returns false if room clipboardData files and types are empty", () => { const originalEvent = createMockClipboardEvent({ type: "paste", clipboardData: { files: [], types: [] }, }); const output = handleClipboardEvent(originalEvent, originalEvent.clipboardData, mockRoomState, mockClient); expect(output).toBe(false); }); it("handles event and calls sendContentListToRoom when data files are present", () => { const originalEvent = createMockClipboardEvent({ type: "paste", clipboardData: { files: ["something here"], types: [] }, }); const output = handleClipboardEvent(originalEvent, originalEvent.clipboardData, mockRoomState, mockClient); expect(sendContentListToRoomSpy).toHaveBeenCalledTimes(1); expect(sendContentListToRoomSpy).toHaveBeenCalledWith( originalEvent.clipboardData?.files, mockRoom.roomId, undefined, // this is the event relation, an optional arg mockClient, mockRoomState.timelineRenderingType, ); expect(output).toBe(true); }); it("calls sendContentListToRoom with eventRelation when present", () => { const originalEvent = createMockClipboardEvent({ type: "paste", clipboardData: { files: ["something here"], types: [] }, }); const mockEventRelation = {} as unknown as IEventRelation; const output = handleClipboardEvent( originalEvent, originalEvent.clipboardData, mockRoomState, mockClient, mockEventRelation, ); expect(sendContentListToRoomSpy).toHaveBeenCalledTimes(1); expect(sendContentListToRoomSpy).toHaveBeenCalledWith( originalEvent.clipboardData?.files, mockRoom.roomId, mockEventRelation, // this is the event relation, an optional arg mockClient, mockRoomState.timelineRenderingType, ); expect(output).toBe(true); }); it("calls the error handler when sentContentListToRoom errors", async () => { const mockErrorMessage = "something went wrong"; sendContentListToRoomSpy.mockRejectedValueOnce(new Error(mockErrorMessage)); const originalEvent = createMockClipboardEvent({ type: "paste", clipboardData: { files: ["something here"], types: [] }, }); const mockEventRelation = {} as unknown as IEventRelation; const output = handleClipboardEvent( originalEvent, originalEvent.clipboardData, mockRoomState, mockClient, mockEventRelation, ); expect(sendContentListToRoomSpy).toHaveBeenCalledTimes(1); await waitFor(() => { expect(logSpy).toHaveBeenCalledWith(mockErrorMessage); }); expect(output).toBe(true); }); it("calls the error handler when data types has text/html but data can not be parsed", () => { const originalEvent = createMockClipboardEvent({ type: "paste", clipboardData: { files: [], types: ["text/html"], getData: jest.fn().mockReturnValue("