();
- const getCompletionsSpy = jest.spyOn(Autocompleter.prototype, "getCompletions").mockResolvedValue([
- {
- completions: mockCompletion,
- provider: constructMockProvider(mockCompletion),
- command: { command: ["truthy"] as RegExpExecArray }, // needed for us to unhide the autocomplete when testing
- },
- ]);
- const mockHandleMention = jest.fn();
-
- const renderComponent = (props = {}) => {
- const mockClient = stubClient();
- const mockRoom = mkStubRoom("test_room", "test_room", mockClient);
- const mockRoomContext = getRoomContext(mockRoom, {});
-
- return render(
-
-
-
-
- ,
- );
- };
-
- it("does not show the autocomplete when room is undefined", () => {
- render();
- expect(screen.queryByTestId("autocomplete-wrapper")).not.toBeInTheDocument();
- });
-
- it("does not call for suggestions with a null suggestion prop", async () => {
- // render the component, the default props have suggestion = null
- renderComponent();
-
- // check that getCompletions is not called, and we have no suggestions
- expect(getCompletionsSpy).not.toHaveBeenCalled();
- expect(screen.queryByRole("presentation")).not.toBeInTheDocument();
- });
-
- it("calls getCompletions when given a valid suggestion prop", async () => {
- renderComponent({ suggestion: { keyChar: "@", text: "abc", type: "mention" } });
-
- // wait for getCompletions to have been called
- await waitFor(() => {
- expect(getCompletionsSpy).toHaveBeenCalled();
- });
-
- // check that some suggestions are shown
- expect(screen.getByRole("presentation")).toBeInTheDocument();
-
- // and that they are the mock completions
- mockCompletion.forEach(({ completion }) => expect(screen.getByText(completion)).toBeInTheDocument());
- });
-});
diff --git a/test/components/views/rooms/wysiwyg_composer/components/WysiwygComposer-test.tsx b/test/components/views/rooms/wysiwyg_composer/components/WysiwygComposer-test.tsx
index 3f9694e2a3..3ab7d768d6 100644
--- a/test/components/views/rooms/wysiwyg_composer/components/WysiwygComposer-test.tsx
+++ b/test/components/views/rooms/wysiwyg_composer/components/WysiwygComposer-test.tsx
@@ -21,7 +21,7 @@ import userEvent from "@testing-library/user-event";
import { WysiwygComposer } from "../../../../../../src/components/views/rooms/wysiwyg_composer/components/WysiwygComposer";
import SettingsStore from "../../../../../../src/settings/SettingsStore";
-import { flushPromises, mockPlatformPeg, stubClient, mkStubRoom } from "../../../../../test-utils";
+import { createTestClient, flushPromises, mockPlatformPeg } from "../../../../../test-utils";
import defaultDispatcher from "../../../../../../src/dispatcher/dispatcher";
import * as EventUtils from "../../../../../../src/utils/EventUtils";
import { Action } from "../../../../../../src/dispatcher/actions";
@@ -36,25 +36,11 @@ import EditorStateTransfer from "../../../../../../src/utils/EditorStateTransfer
import { SubSelection } from "../../../../../../src/components/views/rooms/wysiwyg_composer/types";
import { setSelection } from "../../../../../../src/components/views/rooms/wysiwyg_composer/utils/selection";
import { parseEditorStateTransfer } from "../../../../../../src/components/views/rooms/wysiwyg_composer/hooks/useInitialContent";
-import Autocompleter, { ICompletion } from "../../../../../../src/autocomplete/Autocompleter";
-import AutocompleteProvider from "../../../../../../src/autocomplete/AutocompleteProvider";
-import * as Permalinks from "../../../../../../src/utils/permalinks/Permalinks";
-import { PermalinkParts } from "../../../../../../src/utils/permalinks/PermalinkConstructor";
describe("WysiwygComposer", () => {
const customRender = (onChange = jest.fn(), onSend = jest.fn(), disabled = false, initialContent?: string) => {
- const { mockClient, defaultRoomContext } = createMocks();
return render(
-
-
-
-
- ,
+ ,
);
};
@@ -62,12 +48,12 @@ describe("WysiwygComposer", () => {
jest.resetAllMocks();
});
- it("Should have contentEditable at false when disabled", async () => {
+ it("Should have contentEditable at false when disabled", () => {
// When
customRender(jest.fn(), jest.fn(), true);
// Then
- await waitFor(() => expect(screen.getByRole("textbox")).toHaveAttribute("contentEditable", "false"));
+ expect(screen.getByRole("textbox")).toHaveAttribute("contentEditable", "false");
});
describe("Standard behavior", () => {
@@ -158,199 +144,6 @@ describe("WysiwygComposer", () => {
});
});
- describe("Mentions", () => {
- const dispatchSpy = jest.spyOn(defaultDispatcher, "dispatch");
-
- const mockCompletions: ICompletion[] = [
- {
- type: "user",
- href: "www.user1.com",
- completion: "user_1",
- completionId: "@user_1:host.local",
- range: { start: 1, end: 1 },
- component: user_1
,
- },
- {
- type: "user",
- href: "www.user2.com",
- completion: "user_2",
- completionId: "@user_2:host.local",
- range: { start: 1, end: 1 },
- component: user_2
,
- },
- {
- // no href user
- type: "user",
- completion: "user_without_href",
- completionId: "@user_3:host.local",
- range: { start: 1, end: 1 },
- component: user_without_href
,
- },
- {
- type: "room",
- href: "www.room1.com",
- completion: "#room_with_completion_id",
- completionId: "@room_1:host.local",
- range: { start: 1, end: 1 },
- component: room_with_completion_id
,
- },
- {
- type: "room",
- href: "www.room2.com",
- completion: "#room_without_completion_id",
- range: { start: 1, end: 1 },
- component: room_without_completion_id
,
- },
- ];
-
- const constructMockProvider = (data: ICompletion[]) =>
- ({
- getCompletions: jest.fn().mockImplementation(async () => data),
- getName: jest.fn().mockReturnValue("test provider"),
- renderCompletions: jest.fn().mockImplementation((components) => components),
- } as unknown as AutocompleteProvider);
-
- // for each test we will insert input simulating a user mention
- const insertMentionInput = async () => {
- fireEvent.input(screen.getByRole("textbox"), {
- data: "@abc",
- inputType: "insertText",
- });
-
- // the autocomplete suggestions container has the presentation role, wait for it to be present
- expect(await screen.findByRole("presentation")).toBeInTheDocument();
- };
-
- beforeEach(async () => {
- // setup the required spies
- jest.spyOn(Autocompleter.prototype, "getCompletions").mockResolvedValue([
- {
- completions: mockCompletions,
- provider: constructMockProvider(mockCompletions),
- command: { command: ["truthy"] as RegExpExecArray }, // needed for us to unhide the autocomplete when testing
- },
- ]);
- jest.spyOn(Permalinks, "parsePermalink").mockReturnValue({
- userId: "mockParsedUserId",
- } as unknown as PermalinkParts);
-
- // then render the component and wait for the composer to be ready
- customRender();
- await waitFor(() => expect(screen.getByRole("textbox")).toHaveAttribute("contentEditable", "true"));
- });
-
- afterEach(() => {
- jest.clearAllMocks();
- });
-
- it("shows the autocomplete when text has @ prefix and autoselects the first item", async () => {
- await insertMentionInput();
- expect(screen.getByText(mockCompletions[0].completion)).toHaveAttribute("aria-selected", "true");
- });
-
- it("pressing up and down arrows allows us to change the autocomplete selection", async () => {
- await insertMentionInput();
-
- // press the down arrow - nb using .keyboard allows us to not have to specify a node, which
- // means that we know the autocomplete is correctly catching the event
- await userEvent.keyboard("{ArrowDown}");
- expect(screen.getByText(mockCompletions[0].completion)).toHaveAttribute("aria-selected", "false");
- expect(screen.getByText(mockCompletions[1].completion)).toHaveAttribute("aria-selected", "true");
-
- // reverse the process and check again
- await userEvent.keyboard("{ArrowUp}");
- expect(screen.getByText(mockCompletions[0].completion)).toHaveAttribute("aria-selected", "true");
- expect(screen.getByText(mockCompletions[1].completion)).toHaveAttribute("aria-selected", "false");
- });
-
- it("pressing enter selects the mention and inserts it into the composer as a link", async () => {
- await insertMentionInput();
-
- // press enter
- await userEvent.keyboard("{Enter}");
-
- // check that it closes the autocomplete
- await waitFor(() => {
- expect(screen.queryByRole("presentation")).not.toBeInTheDocument();
- });
-
- // check that it inserts the completion text as a link
- expect(screen.getByRole("link", { name: mockCompletions[0].completion })).toBeInTheDocument();
- });
-
- it("clicking on a mention in the composer dispatches the correct action", async () => {
- await insertMentionInput();
-
- // press enter
- await userEvent.keyboard("{Enter}");
-
- // check that it closes the autocomplete
- await waitFor(() => {
- expect(screen.queryByRole("presentation")).not.toBeInTheDocument();
- });
-
- // click on the user mention link that has been inserted
- await userEvent.click(screen.getByRole("link", { name: mockCompletions[0].completion }));
- expect(dispatchSpy).toHaveBeenCalledTimes(1);
-
- // this relies on the output from the mock function in mkStubRoom
- expect(dispatchSpy).toHaveBeenCalledWith(
- expect.objectContaining({
- action: Action.ViewUser,
- member: expect.objectContaining({
- userId: mkStubRoom(undefined, undefined, undefined).getMember("any")?.userId,
- }),
- }),
- );
- });
-
- it("selecting a mention without a href closes the autocomplete but does not insert a mention", async () => {
- await insertMentionInput();
-
- // select the relevant user by clicking
- await userEvent.click(screen.getByText("user_without_href"));
-
- // check that it closes the autocomplete
- await waitFor(() => {
- expect(screen.queryByRole("presentation")).not.toBeInTheDocument();
- });
-
- // check that it has not inserted a link
- expect(screen.queryByRole("link", { name: "user_without_href" })).not.toBeInTheDocument();
- });
-
- it("selecting a room mention with a completionId uses client.getRoom", async () => {
- await insertMentionInput();
-
- // select the room suggestion by clicking
- await userEvent.click(screen.getByText("room_with_completion_id"));
-
- // check that it closes the autocomplete
- await waitFor(() => {
- expect(screen.queryByRole("presentation")).not.toBeInTheDocument();
- });
-
- // check that it has inserted a link and looked up the name from the mock client
- // which will always return 'My room'
- expect(screen.getByRole("link", { name: "My room" })).toBeInTheDocument();
- });
-
- it("selecting a room mention without a completionId uses client.getRooms", async () => {
- await insertMentionInput();
-
- // select the room suggestion
- await userEvent.click(screen.getByText("room_without_completion_id"));
-
- // check that it closes the autocomplete
- await waitFor(() => {
- expect(screen.queryByRole("presentation")).not.toBeInTheDocument();
- });
-
- // check that it has inserted a link and falls back to the completion text
- expect(screen.getByRole("link", { name: "#room_without_completion_id" })).toBeInTheDocument();
- });
- });
-
describe("When settings require Ctrl+Enter to send", () => {
const onChange = jest.fn();
const onSend = jest.fn();
@@ -448,11 +241,10 @@ describe("WysiwygComposer", () => {
const setup = async (
editorState?: EditorStateTransfer,
- client = stubClient(),
+ client = createTestClient(),
roomContext = defaultRoomContext,
) => {
const spyDispatcher = jest.spyOn(defaultDispatcher, "dispatch");
-
customRender(client, roomContext, editorState);
await waitFor(() => expect(screen.getByRole("textbox")).toHaveAttribute("contentEditable", "true"));
return { textbox: screen.getByRole("textbox"), spyDispatcher };
diff --git a/test/components/views/rooms/wysiwyg_composer/utils.ts b/test/components/views/rooms/wysiwyg_composer/utils.ts
index 82b2fd537d..0eb99b251d 100644
--- a/test/components/views/rooms/wysiwyg_composer/utils.ts
+++ b/test/components/views/rooms/wysiwyg_composer/utils.ts
@@ -16,12 +16,12 @@ limitations under the License.
import { EventTimeline, MatrixEvent } from "matrix-js-sdk/src/matrix";
-import { getRoomContext, mkEvent, mkStubRoom, stubClient } from "../../../../test-utils";
+import { createTestClient, getRoomContext, mkEvent, mkStubRoom } from "../../../../test-utils";
import { IRoomState } from "../../../../../src/components/structures/RoomView";
import EditorStateTransfer from "../../../../../src/utils/EditorStateTransfer";
export function createMocks(eventContent = "Replying to this new content") {
- const mockClient = stubClient();
+ const mockClient = createTestClient();
const mockEvent = mkEvent({
type: "m.room.message",
room: "myfakeroom",
diff --git a/yarn.lock b/yarn.lock
index dd1991a173..ca1ba5485b 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1664,10 +1664,10 @@
resolved "https://registry.yarnpkg.com/@matrix-org/matrix-sdk-crypto-js/-/matrix-sdk-crypto-js-0.1.0-alpha.4.tgz#1b20294e0354c3dcc9c7dc810d883198a4042f04"
integrity sha512-mdaDKrw3P5ZVCpq0ioW0pV6ihviDEbS8ZH36kpt9stLKHwwDSopPogE6CkQhi0B1jn1yBUtOYi32mBV/zcOR7g==
-"@matrix-org/matrix-wysiwyg@^1.4.0":
- version "1.4.0"
- resolved "https://registry.yarnpkg.com/@matrix-org/matrix-wysiwyg/-/matrix-wysiwyg-1.4.0.tgz#b04f4c05c8117c0917f9a1401bb1d9c5f976052c"
- integrity sha512-NIxX1oia61zut/DA7fUCCQfOhWKLbVDmPrDeUeX40NgXZRROhLPF1/jcOKgAnXK8yqflmNrVlX/dlUVcfj/kqw==
+"@matrix-org/matrix-wysiwyg@^1.1.1":
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/@matrix-org/matrix-wysiwyg/-/matrix-wysiwyg-1.3.0.tgz#647837be552c1a96ca8157e0dc0d7d8f897fcbe2"
+ integrity sha512-uHcPYP+mriJZcI54lDBpO+wPGDli/+VEL/NjuW+BBgt7PLViSa4xaGdD7K+yUBgntRdbJ/J4fo+lYB06kqF+sA==
"@matrix-org/olm@https://gitlab.matrix.org/api/v4/projects/27/packages/npm/@matrix-org/olm/-/@matrix-org/olm-3.2.14.tgz":
version "3.2.14"