Improve switching between rich and plain editing modes (#9776)
* allows switching between modes that retains formatting * updates rich text composer dependency to 0.13.0 (@matrix-org/matrix-wysiwyg) * improves handling of enter keypresses when ctrlEnterTosend setting is true in plain text editor * changes the message event content when using the new editor * adds tests for the changes to the plain text editor
This commit is contained in:
parent
3bcea5fb0b
commit
432ce3ca31
13 changed files with 336 additions and 94 deletions
|
@ -19,6 +19,8 @@ import { act, render, screen } from "@testing-library/react";
|
|||
import userEvent from "@testing-library/user-event";
|
||||
|
||||
import { PlainTextComposer } from "../../../../../../src/components/views/rooms/wysiwyg_composer/components/PlainTextComposer";
|
||||
import * as mockUseSettingsHook from "../../../../../../src/hooks/useSettings";
|
||||
import * as mockKeyboard from "../../../../../../src/Keyboard";
|
||||
|
||||
describe("PlainTextComposer", () => {
|
||||
const customRender = (
|
||||
|
@ -37,6 +39,17 @@ describe("PlainTextComposer", () => {
|
|||
);
|
||||
};
|
||||
|
||||
let mockUseSettingValue: jest.SpyInstance;
|
||||
beforeEach(() => {
|
||||
// defaults for these tests are:
|
||||
// ctrlEnterToSend is false
|
||||
mockUseSettingValue = jest.spyOn(mockUseSettingsHook, "useSettingValue").mockReturnValue(false);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.restoreAllMocks();
|
||||
});
|
||||
|
||||
it("Should have contentEditable at false when disabled", () => {
|
||||
// When
|
||||
customRender(jest.fn(), jest.fn(), true);
|
||||
|
@ -64,7 +77,7 @@ describe("PlainTextComposer", () => {
|
|||
expect(onChange).toBeCalledWith(content);
|
||||
});
|
||||
|
||||
it("Should call onSend when Enter is pressed", async () => {
|
||||
it("Should call onSend when Enter is pressed when ctrlEnterToSend is false", async () => {
|
||||
//When
|
||||
const onSend = jest.fn();
|
||||
customRender(jest.fn(), onSend);
|
||||
|
@ -74,9 +87,134 @@ describe("PlainTextComposer", () => {
|
|||
expect(onSend).toBeCalledTimes(1);
|
||||
});
|
||||
|
||||
it("Should not call onSend when Enter is pressed when ctrlEnterToSend is true", async () => {
|
||||
//When
|
||||
mockUseSettingValue.mockReturnValue(true);
|
||||
const onSend = jest.fn();
|
||||
customRender(jest.fn(), onSend);
|
||||
await userEvent.type(screen.getByRole("textbox"), "{enter}");
|
||||
|
||||
// Then it does not send a message
|
||||
expect(onSend).toBeCalledTimes(0);
|
||||
});
|
||||
|
||||
it("Should only call onSend when ctrl+enter is pressed when ctrlEnterToSend is true on windows", async () => {
|
||||
//When
|
||||
mockUseSettingValue.mockReturnValue(true);
|
||||
|
||||
const onSend = jest.fn();
|
||||
customRender(jest.fn(), onSend);
|
||||
const textBox = screen.getByRole("textbox");
|
||||
await userEvent.type(textBox, "hello");
|
||||
|
||||
// Then it does NOT send a message on enter
|
||||
await userEvent.type(textBox, "{enter}");
|
||||
expect(onSend).toBeCalledTimes(0);
|
||||
|
||||
// Then it does NOT send a message on windows+enter
|
||||
await userEvent.type(textBox, "{meta>}{enter}{meta/}");
|
||||
expect(onSend).toBeCalledTimes(0);
|
||||
|
||||
// Then it does send a message on ctrl+enter
|
||||
await userEvent.type(textBox, "{control>}{enter}{control/}");
|
||||
expect(onSend).toBeCalledTimes(1);
|
||||
});
|
||||
|
||||
it("Should only call onSend when cmd+enter is pressed when ctrlEnterToSend is true on mac", async () => {
|
||||
//When
|
||||
mockUseSettingValue.mockReturnValue(true);
|
||||
Object.defineProperty(mockKeyboard, "IS_MAC", { value: true });
|
||||
|
||||
const onSend = jest.fn();
|
||||
customRender(jest.fn(), onSend);
|
||||
const textBox = screen.getByRole("textbox");
|
||||
await userEvent.type(textBox, "hello");
|
||||
|
||||
// Then it does NOT send a message on enter
|
||||
await userEvent.type(textBox, "{enter}");
|
||||
expect(onSend).toBeCalledTimes(0);
|
||||
|
||||
// Then it does NOT send a message on ctrl+enter
|
||||
await userEvent.type(textBox, "{control>}{enter}{control/}");
|
||||
expect(onSend).toBeCalledTimes(0);
|
||||
|
||||
// Then it does send a message on cmd+enter
|
||||
await userEvent.type(textBox, "{meta>}{enter}{meta/}");
|
||||
expect(onSend).toBeCalledTimes(1);
|
||||
});
|
||||
|
||||
it("Should insert a newline character when shift enter is pressed when ctrlEnterToSend is false", async () => {
|
||||
//When
|
||||
const onSend = jest.fn();
|
||||
customRender(jest.fn(), onSend);
|
||||
const textBox = screen.getByRole("textbox");
|
||||
const inputWithShiftEnter = "new{Shift>}{enter}{/Shift}line";
|
||||
const expectedInnerHtml = "new\nline";
|
||||
|
||||
await userEvent.click(textBox);
|
||||
await userEvent.type(textBox, inputWithShiftEnter);
|
||||
|
||||
// Then it does not send a message, but inserts a newline character
|
||||
expect(onSend).toBeCalledTimes(0);
|
||||
expect(textBox.innerHTML).toBe(expectedInnerHtml);
|
||||
});
|
||||
|
||||
it("Should insert a newline character when shift enter is pressed when ctrlEnterToSend is true", async () => {
|
||||
//When
|
||||
mockUseSettingValue.mockReturnValue(true);
|
||||
const onSend = jest.fn();
|
||||
customRender(jest.fn(), onSend);
|
||||
const textBox = screen.getByRole("textbox");
|
||||
const keyboardInput = "new{Shift>}{enter}{/Shift}line";
|
||||
const expectedInnerHtml = "new\nline";
|
||||
|
||||
await userEvent.click(textBox);
|
||||
await userEvent.type(textBox, keyboardInput);
|
||||
|
||||
// Then it does not send a message, but inserts a newline character
|
||||
expect(onSend).toBeCalledTimes(0);
|
||||
expect(textBox.innerHTML).toBe(expectedInnerHtml);
|
||||
});
|
||||
|
||||
it("Should not insert div and br tags when enter is pressed when ctrlEnterToSend is true", async () => {
|
||||
//When
|
||||
mockUseSettingValue.mockReturnValue(true);
|
||||
const onSend = jest.fn();
|
||||
customRender(jest.fn(), onSend);
|
||||
const textBox = screen.getByRole("textbox");
|
||||
const enterThenTypeHtml = "<div>hello</div";
|
||||
|
||||
await userEvent.click(textBox);
|
||||
await userEvent.type(textBox, "{enter}hello");
|
||||
|
||||
// Then it does not send a message, but inserts a newline character
|
||||
expect(onSend).toBeCalledTimes(0);
|
||||
expect(textBox).not.toContainHTML(enterThenTypeHtml);
|
||||
});
|
||||
|
||||
it("Should not insert div tags when enter is pressed then user types more when ctrlEnterToSend is true", async () => {
|
||||
//When
|
||||
mockUseSettingValue.mockReturnValue(true);
|
||||
const onSend = jest.fn();
|
||||
customRender(jest.fn(), onSend);
|
||||
const textBox = screen.getByRole("textbox");
|
||||
const defaultEnterHtml = "<div><br></div";
|
||||
|
||||
await userEvent.click(textBox);
|
||||
await userEvent.type(textBox, "{enter}");
|
||||
|
||||
// Then it does not send a message, but inserts a newline character
|
||||
expect(onSend).toBeCalledTimes(0);
|
||||
expect(textBox).not.toContainHTML(defaultEnterHtml);
|
||||
});
|
||||
|
||||
it("Should clear textbox content when clear is called", async () => {
|
||||
//When
|
||||
let composer;
|
||||
let composer: {
|
||||
clear: () => void;
|
||||
insertText: (text: string) => void;
|
||||
};
|
||||
|
||||
render(
|
||||
<PlainTextComposer onChange={jest.fn()} onSend={jest.fn()}>
|
||||
{(ref, composerFunctions) => {
|
||||
|
@ -85,9 +223,11 @@ describe("PlainTextComposer", () => {
|
|||
}}
|
||||
</PlainTextComposer>,
|
||||
);
|
||||
|
||||
await userEvent.type(screen.getByRole("textbox"), "content");
|
||||
expect(screen.getByRole("textbox").innerHTML).toBe("content");
|
||||
composer.clear();
|
||||
|
||||
composer!.clear();
|
||||
|
||||
// Then
|
||||
expect(screen.getByRole("textbox").innerHTML).toBeFalsy();
|
||||
|
@ -112,7 +252,7 @@ describe("PlainTextComposer", () => {
|
|||
render(<PlainTextComposer onChange={jest.fn()} onSend={jest.fn()} />);
|
||||
|
||||
// Then
|
||||
expect(screen.getByTestId("WysiwygComposerEditor").attributes["data-is-expanded"].value).toBe("false");
|
||||
expect(screen.getByTestId("WysiwygComposerEditor").dataset["isExpanded"]).toBe("false");
|
||||
expect(editor).toBe(screen.getByRole("textbox"));
|
||||
|
||||
// When
|
||||
|
@ -126,7 +266,7 @@ describe("PlainTextComposer", () => {
|
|||
});
|
||||
|
||||
// Then
|
||||
expect(screen.getByTestId("WysiwygComposerEditor").attributes["data-is-expanded"].value).toBe("true");
|
||||
expect(screen.getByTestId("WysiwygComposerEditor").dataset["isExpanded"]).toBe("true");
|
||||
|
||||
jest.useRealTimers();
|
||||
(global.ResizeObserver as jest.Mock).mockRestore();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue