diff --git a/src/components/views/rooms/wysiwyg_composer/components/LinkModal.tsx b/src/components/views/rooms/wysiwyg_composer/components/LinkModal.tsx index 88230cd00df..d38a240d5c9 100644 --- a/src/components/views/rooms/wysiwyg_composer/components/LinkModal.tsx +++ b/src/components/views/rooms/wysiwyg_composer/components/LinkModal.tsx @@ -44,7 +44,7 @@ interface LinkModalProps { onClose: () => void; } -function LinkModal({ composer, isTextEnabled, onClose }: LinkModalProps) { +export function LinkModal({ composer, isTextEnabled, onClose }: LinkModalProps) { const composerContext = useComposerContext(); const [fields, setFields] = useState({ text: "", link: "" }); diff --git a/test/components/views/rooms/wysiwyg_composer/components/FormattingButtons-test.tsx b/test/components/views/rooms/wysiwyg_composer/components/FormattingButtons-test.tsx index d143e43a628..a467aa404e7 100644 --- a/test/components/views/rooms/wysiwyg_composer/components/FormattingButtons-test.tsx +++ b/test/components/views/rooms/wysiwyg_composer/components/FormattingButtons-test.tsx @@ -20,6 +20,7 @@ import userEvent from "@testing-library/user-event"; import { AllActionStates, FormattingFunctions } from "@matrix-org/matrix-wysiwyg"; import { FormattingButtons } from "../../../../../../src/components/views/rooms/wysiwyg_composer/components/FormattingButtons"; +import * as LinkModal from "../../../../../../src/components/views/rooms/wysiwyg_composer/components/LinkModal"; describe("FormattingButtons", () => { const wysiwyg = { @@ -28,6 +29,7 @@ describe("FormattingButtons", () => { underline: jest.fn(), strikeThrough: jest.fn(), inlineCode: jest.fn(), + link: jest.fn(), } as unknown as FormattingFunctions; const actionStates = { @@ -36,6 +38,7 @@ describe("FormattingButtons", () => { underline: "enabled", strikeThrough: "enabled", inlineCode: "enabled", + link: "enabled", } as AllActionStates; afterEach(() => { @@ -52,16 +55,19 @@ describe("FormattingButtons", () => { expect(screen.getByLabelText("Underline")).not.toHaveClass("mx_FormattingButtons_active"); expect(screen.getByLabelText("Strikethrough")).not.toHaveClass("mx_FormattingButtons_active"); expect(screen.getByLabelText("Code")).not.toHaveClass("mx_FormattingButtons_active"); + expect(screen.getByLabelText("Link")).not.toHaveClass("mx_FormattingButtons_active"); }); it("Should call wysiwyg function on button click", () => { // When + const spy = jest.spyOn(LinkModal, "openLinkModal"); render(); screen.getByLabelText("Bold").click(); screen.getByLabelText("Italic").click(); screen.getByLabelText("Underline").click(); screen.getByLabelText("Strikethrough").click(); screen.getByLabelText("Code").click(); + screen.getByLabelText("Link").click(); // Then expect(wysiwyg.bold).toHaveBeenCalledTimes(1); @@ -69,6 +75,7 @@ describe("FormattingButtons", () => { expect(wysiwyg.underline).toHaveBeenCalledTimes(1); expect(wysiwyg.strikeThrough).toHaveBeenCalledTimes(1); expect(wysiwyg.inlineCode).toHaveBeenCalledTimes(1); + expect(spy).toHaveBeenCalledTimes(1); }); it("Should display the tooltip on mouse over", async () => { diff --git a/test/components/views/rooms/wysiwyg_composer/components/LinkModal-test.tsx b/test/components/views/rooms/wysiwyg_composer/components/LinkModal-test.tsx new file mode 100644 index 00000000000..c51961b24f9 --- /dev/null +++ b/test/components/views/rooms/wysiwyg_composer/components/LinkModal-test.tsx @@ -0,0 +1,124 @@ +/* +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 { FormattingFunctions } from "@matrix-org/matrix-wysiwyg"; +import { render, screen, waitFor } from "@testing-library/react"; +import React from "react"; +import userEvent from "@testing-library/user-event"; + +import { ComposerContext } from "../../../../../../src/components/views/rooms/wysiwyg_composer/ComposerContext"; +import { LinkModal } from "../../../../../../src/components/views/rooms/wysiwyg_composer/components/LinkModal"; +import { mockPlatformPeg } from "../../../../../test-utils"; +import * as selection from "../../../../../../src/components/views/rooms/wysiwyg_composer/utils/selection"; + +describe("LinkModal", () => { + const composer = { + link: jest.fn(), + } as unknown as FormattingFunctions; + const defaultValue = { focusNode: null, anchorNode: null, focusOffset: 3, anchorOffset: 4 }; + + const customRender = (isTextEnabled: boolean, onClose: () => void) => { + return render( + + + , + ); + }; + + mockPlatformPeg({ overrideBrowserShortcuts: jest.fn().mockReturnValue(false) }); + const selectionSpy = jest.spyOn(selection, "setSelection"); + + afterEach(() => { + jest.clearAllMocks(); + jest.useRealTimers(); + }); + + it("Should create a link", async () => { + // When + const onClose = jest.fn(); + customRender(false, onClose); + + // Then + expect(screen.getByLabelText("Link")).toBeTruthy(); + expect(screen.getByText("Save")).toBeDisabled(); + + // When + await userEvent.type(screen.getByLabelText("Link"), "l"); + + // Then + await waitFor(() => { + expect(screen.getByText("Save")).toBeEnabled(); + expect(screen.getByLabelText("Link")).toHaveAttribute("value", "l"); + }); + + // When + jest.useFakeTimers(); + screen.getByText("Save").click(); + + // Then + expect(selectionSpy).toHaveBeenCalledWith(defaultValue); + expect(onClose).toBeCalledTimes(1); + + // When + jest.runAllTimers(); + + // Then + expect(composer.link).toHaveBeenCalledWith("l", undefined); + }); + + it("Should create a link with text", async () => { + // When + const onClose = jest.fn(); + customRender(true, onClose); + + // Then + expect(screen.getByLabelText("Text")).toBeTruthy(); + expect(screen.getByLabelText("Link")).toBeTruthy(); + expect(screen.getByText("Save")).toBeDisabled(); + + // When + await userEvent.type(screen.getByLabelText("Text"), "t"); + + // Then + await waitFor(() => { + expect(screen.getByText("Save")).toBeDisabled(); + expect(screen.getByLabelText("Text")).toHaveAttribute("value", "t"); + }); + + // When + await userEvent.type(screen.getByLabelText("Link"), "l"); + + // Then + await waitFor(() => { + expect(screen.getByText("Save")).toBeEnabled(); + expect(screen.getByLabelText("Link")).toHaveAttribute("value", "l"); + }); + + // When + jest.useFakeTimers(); + screen.getByText("Save").click(); + + // Then + expect(selectionSpy).toHaveBeenCalledWith(defaultValue); + expect(onClose).toBeCalledTimes(1); + + // When + jest.runAllTimers(); + + // Then + expect(composer.link).toHaveBeenCalledWith("l", "t"); + }); +});