Skip to content
This repository has been archived by the owner on Sep 11, 2024. It is now read-only.

Commit

Permalink
Write additional test for both issues
Browse files Browse the repository at this point in the history
- Thread dropdown should be shown if there is any thread, even if not participated
- Thread list correctly updates after every change of the dropdown immediately
  • Loading branch information
justjanne committed Jan 11, 2023
1 parent 05d6e15 commit b25b7f9
Showing 1 changed file with 191 additions and 7 deletions.
198 changes: 191 additions & 7 deletions test/components/structures/ThreadPanel-test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,23 @@ See the License for the specific language governing permissions and
limitations under the License.
*/

import React from "react";
import { render, screen, fireEvent } from "@testing-library/react";
import { mocked } from "jest-mock";
import { fireEvent, render, screen, waitFor } from "@testing-library/react";
import "focus-visible"; // to fix context menus
import { mocked } from "jest-mock";
import React from "react";
import { MatrixClient, MatrixEvent, PendingEventOrdering, Room } from "matrix-js-sdk/src/matrix";
import { FeatureSupport, Thread } from "matrix-js-sdk/src/models/thread";

import ThreadPanel, { ThreadFilterType, ThreadPanelHeader } from "../../../src/components/structures/ThreadPanel";
import MatrixClientContext from "../../../src/contexts/MatrixClientContext";
import RoomContext from "../../../src/contexts/RoomContext";
import { _t } from "../../../src/languageHandler";
import ResizeNotifier from "../../../src/utils/ResizeNotifier";
import { RoomPermalinkCreator } from "../../../src/utils/permalinks/Permalinks";
import { createTestClient, mkStubRoom } from "../../test-utils";
import { MatrixClientPeg } from "../../../src/MatrixClientPeg";
import { shouldShowFeedback } from "../../../src/utils/Feedback";
import MatrixClientContext from "../../../src/contexts/MatrixClientContext";
import { RoomPermalinkCreator } from "../../../src/utils/permalinks/Permalinks";
import ResizeNotifier from "../../../src/utils/ResizeNotifier";
import { createTestClient, getRoomContext, mkStubRoom, mockPlatformPeg, stubClient } from "../../test-utils";
import { mkThread } from "../../test-utils/threads";

jest.mock("../../../src/utils/Feedback");

Expand Down Expand Up @@ -122,4 +127,183 @@ describe("ThreadPanel", () => {
expect(foundButton).toMatchSnapshot();
});
});

describe("Filtering", () => {
const ROOM_ID = "!roomId:example.org";
const SENDER = "@alice:example.org";

let mockClient: MatrixClient;
let room: Room;

const TestThreadPanel = () => (
<MatrixClientContext.Provider value={mockClient}>
<RoomContext.Provider
value={getRoomContext(room, {
canSendMessages: true,
})}
>
<ThreadPanel
roomId={ROOM_ID}
onClose={jest.fn()}
resizeNotifier={new ResizeNotifier()}
permalinkCreator={new RoomPermalinkCreator(room)}
/>
</RoomContext.Provider>
</MatrixClientContext.Provider>
);

beforeEach(async () => {
jest.clearAllMocks();

stubClient();
mockPlatformPeg();
mockClient = mocked(MatrixClientPeg.get());
Thread.setServerSideSupport(FeatureSupport.Stable);
Thread.setServerSideListSupport(FeatureSupport.Stable);
Thread.setServerSideFwdPaginationSupport(FeatureSupport.Stable);
jest.spyOn(mockClient, "supportsExperimentalThreads").mockReturnValue(true);

room = new Room(ROOM_ID, mockClient, mockClient.getUserId() ?? "", {
pendingEventOrdering: PendingEventOrdering.Detached,
});
jest.spyOn(room, "fetchRoomThreads").mockReturnValue(Promise.resolve());
jest.spyOn(mockClient, "getRoom").mockReturnValue(room);
await room.createThreadsTimelineSets();
const [allThreads, myThreads] = room.threadsTimelineSets;
jest.spyOn(room, "createThreadsTimelineSets").mockReturnValue(Promise.resolve([allThreads, myThreads]));
});

function toggleThreadFilter(container: HTMLElement, newFilter: ThreadFilterType) {
fireEvent.click(container.querySelector(".mx_ThreadPanel_dropdown"));
const found = screen.queryAllByRole("menuitemradio");
expect(found).toHaveLength(2);

const allThreadsContent = `${_t("All threads")}${_t("Shows all threads from current room")}`;
const myThreadsContent = `${_t("My threads")}${_t("Shows all threads you've participated in")}`;

const allThreadsOption = found.find((it) => it.textContent === allThreadsContent);
const myThreadsOption = found.find((it) => it.textContent === myThreadsContent);
expect(allThreadsOption).toBeTruthy();
expect(myThreadsOption).toBeTruthy();

const toSelect = newFilter === ThreadFilterType.My ? myThreadsOption : allThreadsOption;
fireEvent.click(toSelect);
}

type EventData = { sender: string; content: string };

function findEvents(container: HTMLElement): EventData[] {
return Array.from(container.querySelectorAll(".mx_EventTile")).map((el) => {
const sender = el.querySelector(".mx_DisambiguatedProfile_displayName").textContent;
const content = el.querySelector(".mx_EventTile_body").textContent;
return { sender, content };
});
}

function toEventData(event: MatrixEvent): EventData {
return { sender: event.event.sender, content: event.event.content.body };
}

it("correctly filters Thread List with multiple threads", async () => {
const otherThread = mkThread({
room,
client: mockClient,
authorId: SENDER,
participantUserIds: [mockClient.getUserId()],
});

const mixedThread = mkThread({
room,
client: mockClient,
authorId: SENDER,
participantUserIds: [SENDER, mockClient.getUserId()],
});

const ownThread = mkThread({
room,
client: mockClient,
authorId: mockClient.getUserId(),
participantUserIds: [mockClient.getUserId()],
});

const threadRoots = [otherThread.rootEvent, mixedThread.rootEvent, ownThread.rootEvent];
jest.spyOn(mockClient, "fetchRoomEvent").mockImplementation((_, eventId) =>
Promise.resolve(threadRoots.find((it) => it.getId() === eventId).event),
);
const [allThreads, myThreads] = room.threadsTimelineSets;
allThreads.addLiveEvent(otherThread.rootEvent);
allThreads.addLiveEvent(mixedThread.rootEvent);
allThreads.addLiveEvent(ownThread.rootEvent);
myThreads.addLiveEvent(mixedThread.rootEvent);
myThreads.addLiveEvent(ownThread.rootEvent);

let events: EventData[] = [];
const renderResult = render(<TestThreadPanel />);
await waitFor(() => expect(renderResult.container.querySelector(".mx_AutoHideScrollbar")).toBeFalsy());
await waitFor(() => {
events = findEvents(renderResult.container);
expect(findEvents(renderResult.container)).toHaveLength(3);
});
expect(events[0]).toEqual(toEventData(otherThread.rootEvent));
expect(events[1]).toEqual(toEventData(mixedThread.rootEvent));
expect(events[2]).toEqual(toEventData(ownThread.rootEvent));
await waitFor(() => expect(renderResult.container.querySelector(".mx_ThreadPanel_dropdown")).toBeTruthy());
toggleThreadFilter(renderResult.container, ThreadFilterType.My);
await waitFor(() => expect(renderResult.container.querySelector(".mx_AutoHideScrollbar")).toBeFalsy());
await waitFor(() => {
events = findEvents(renderResult.container);
expect(findEvents(renderResult.container)).toHaveLength(2);
});
expect(events[0]).toEqual(toEventData(mixedThread.rootEvent));
expect(events[1]).toEqual(toEventData(ownThread.rootEvent));
toggleThreadFilter(renderResult.container, ThreadFilterType.All);
await waitFor(() => expect(renderResult.container.querySelector(".mx_AutoHideScrollbar")).toBeFalsy());
await waitFor(() => {
events = findEvents(renderResult.container);
expect(findEvents(renderResult.container)).toHaveLength(3);
});
expect(events[0]).toEqual(toEventData(otherThread.rootEvent));
expect(events[1]).toEqual(toEventData(mixedThread.rootEvent));
expect(events[2]).toEqual(toEventData(ownThread.rootEvent));
});

it("correctly filters Thread List with a single, unparticipated thread", async () => {
const otherThread = mkThread({
room,
client: mockClient,
authorId: SENDER,
participantUserIds: [mockClient.getUserId()],
});

const threadRoots = [otherThread.rootEvent];
jest.spyOn(mockClient, "fetchRoomEvent").mockImplementation((_, eventId) =>
Promise.resolve(threadRoots.find((it) => it.getId() === eventId).event),
);
const [allThreads] = room.threadsTimelineSets;
allThreads.addLiveEvent(otherThread.rootEvent);

let events: EventData[] = [];
const renderResult = render(<TestThreadPanel />);
await waitFor(() => expect(renderResult.container.querySelector(".mx_AutoHideScrollbar")).toBeFalsy());
await waitFor(() => {
events = findEvents(renderResult.container);
expect(findEvents(renderResult.container)).toHaveLength(1);
});
expect(events[0]).toEqual(toEventData(otherThread.rootEvent));
await waitFor(() => expect(renderResult.container.querySelector(".mx_ThreadPanel_dropdown")).toBeTruthy());
toggleThreadFilter(renderResult.container, ThreadFilterType.My);
await waitFor(() => expect(renderResult.container.querySelector(".mx_AutoHideScrollbar")).toBeFalsy());
await waitFor(() => {
events = findEvents(renderResult.container);
expect(findEvents(renderResult.container)).toHaveLength(0);
});
toggleThreadFilter(renderResult.container, ThreadFilterType.All);
await waitFor(() => expect(renderResult.container.querySelector(".mx_AutoHideScrollbar")).toBeFalsy());
await waitFor(() => {
events = findEvents(renderResult.container);
expect(findEvents(renderResult.container)).toHaveLength(1);
});
expect(events[0]).toEqual(toEventData(otherThread.rootEvent));
});
});
});

0 comments on commit b25b7f9

Please sign in to comment.