Prepare for repo merge
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
This commit is contained in:
parent
0f670b8dc0
commit
b084ff2313
807 changed files with 0 additions and 0 deletions
|
@ -0,0 +1,436 @@
|
|||
/*
|
||||
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 React from "react";
|
||||
import { act, fireEvent, render } from "jest-matrix-react";
|
||||
import { Filter, EventTimeline, Room, MatrixEvent, M_POLL_START } from "matrix-js-sdk/src/matrix";
|
||||
|
||||
import { PollHistory } from "../../../../../src/components/views/polls/pollHistory/PollHistory";
|
||||
import {
|
||||
flushPromises,
|
||||
getMockClientWithEventEmitter,
|
||||
makePollEndEvent,
|
||||
makePollStartEvent,
|
||||
mockClientMethodsRooms,
|
||||
mockClientMethodsUser,
|
||||
mockIntlDateTimeFormat,
|
||||
setupRoomWithPollEvents,
|
||||
unmockIntlDateTimeFormat,
|
||||
} from "../../../../test-utils";
|
||||
import { RoomPermalinkCreator } from "../../../../../src/utils/permalinks/Permalinks";
|
||||
import defaultDispatcher from "../../../../../src/dispatcher/dispatcher";
|
||||
import { Action } from "../../../../../src/dispatcher/actions";
|
||||
import MatrixClientContext from "../../../../../src/contexts/MatrixClientContext";
|
||||
|
||||
describe("<PollHistory />", () => {
|
||||
// 14.03.2022 16:15
|
||||
const now = 1647270879403;
|
||||
const userId = "@alice:domain.org";
|
||||
const roomId = "!room:domain.org";
|
||||
const mockClient = getMockClientWithEventEmitter({
|
||||
...mockClientMethodsUser(userId),
|
||||
...mockClientMethodsRooms([]),
|
||||
relations: jest.fn(),
|
||||
decryptEventIfNeeded: jest.fn(),
|
||||
getOrCreateFilter: jest.fn(),
|
||||
paginateEventTimeline: jest.fn(),
|
||||
});
|
||||
let room = new Room(roomId, mockClient, userId);
|
||||
|
||||
const expectedFilter = new Filter(userId);
|
||||
expectedFilter.setDefinition({
|
||||
room: {
|
||||
timeline: {
|
||||
types: [M_POLL_START.name, M_POLL_START.altName],
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const defaultProps = {
|
||||
room,
|
||||
matrixClient: mockClient,
|
||||
permalinkCreator: new RoomPermalinkCreator(room),
|
||||
onFinished: jest.fn(),
|
||||
};
|
||||
const getComponent = () =>
|
||||
render(<PollHistory {...defaultProps} />, {
|
||||
wrapper: ({ children }) => (
|
||||
<MatrixClientContext.Provider value={mockClient}>{children}</MatrixClientContext.Provider>
|
||||
),
|
||||
});
|
||||
|
||||
beforeAll(() => {
|
||||
mockIntlDateTimeFormat();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
room = new Room(roomId, mockClient, userId);
|
||||
mockClient.getRoom.mockReturnValue(room);
|
||||
defaultProps.room = room;
|
||||
mockClient.relations.mockResolvedValue({ events: [] });
|
||||
const timeline = room.getLiveTimeline();
|
||||
jest.spyOn(timeline, "getEvents").mockReturnValue([]);
|
||||
jest.spyOn(defaultDispatcher, "dispatch").mockClear();
|
||||
defaultProps.onFinished.mockClear();
|
||||
jest.spyOn(room, "getOrCreateFilteredTimelineSet");
|
||||
mockClient.getOrCreateFilter.mockResolvedValue(expectedFilter.filterId!);
|
||||
mockClient.paginateEventTimeline.mockReset().mockResolvedValue(false);
|
||||
|
||||
jest.spyOn(Date, "now").mockReturnValue(now);
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
unmockIntlDateTimeFormat();
|
||||
});
|
||||
|
||||
it("throws when room is not found", () => {
|
||||
mockClient.getRoom.mockReturnValue(null);
|
||||
|
||||
expect(() => getComponent()).toThrow("Cannot find room");
|
||||
});
|
||||
|
||||
it("renders a loading message while poll history is fetched", async () => {
|
||||
const timelineSet = room.getOrCreateFilteredTimelineSet(expectedFilter);
|
||||
const liveTimeline = timelineSet.getLiveTimeline();
|
||||
jest.spyOn(liveTimeline, "getPaginationToken").mockReturnValueOnce("test-pagination-token");
|
||||
|
||||
const { queryByText, getByText } = getComponent();
|
||||
|
||||
expect(mockClient.getOrCreateFilter).toHaveBeenCalledWith(
|
||||
`POLL_HISTORY_FILTER_${room.roomId}}`,
|
||||
expectedFilter,
|
||||
);
|
||||
// no results not shown until loading finished
|
||||
expect(queryByText("There are no active polls in this room")).not.toBeInTheDocument();
|
||||
expect(getByText("Loading polls")).toBeInTheDocument();
|
||||
|
||||
// flush filter creation request
|
||||
await act(flushPromises);
|
||||
|
||||
expect(liveTimeline.getPaginationToken).toHaveBeenCalledWith(EventTimeline.BACKWARDS);
|
||||
expect(mockClient.paginateEventTimeline).toHaveBeenCalledWith(liveTimeline, { backwards: true });
|
||||
// only one page
|
||||
expect(mockClient.paginateEventTimeline).toHaveBeenCalledTimes(1);
|
||||
|
||||
// finished loading
|
||||
expect(queryByText("Loading polls")).not.toBeInTheDocument();
|
||||
expect(getByText("There are no active polls in this room")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("fetches poll history until end of timeline is reached while within time limit", async () => {
|
||||
const timelineSet = room.getOrCreateFilteredTimelineSet(expectedFilter);
|
||||
const liveTimeline = timelineSet.getLiveTimeline();
|
||||
|
||||
// mock three pages of timeline history
|
||||
jest.spyOn(liveTimeline, "getPaginationToken")
|
||||
.mockReturnValueOnce("test-pagination-token-1")
|
||||
.mockReturnValueOnce("test-pagination-token-2")
|
||||
.mockReturnValueOnce("test-pagination-token-3");
|
||||
|
||||
const { queryByText, getByText } = getComponent();
|
||||
|
||||
expect(mockClient.getOrCreateFilter).toHaveBeenCalledWith(
|
||||
`POLL_HISTORY_FILTER_${room.roomId}}`,
|
||||
expectedFilter,
|
||||
);
|
||||
|
||||
// flush filter creation request
|
||||
await act(flushPromises);
|
||||
// once per page
|
||||
expect(mockClient.paginateEventTimeline).toHaveBeenCalledTimes(3);
|
||||
|
||||
// finished loading
|
||||
expect(queryByText("Loading polls")).not.toBeInTheDocument();
|
||||
expect(getByText("There are no active polls in this room")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("fetches poll history until event older than history period is reached", async () => {
|
||||
const timelineSet = room.getOrCreateFilteredTimelineSet(expectedFilter);
|
||||
const liveTimeline = timelineSet.getLiveTimeline();
|
||||
const thirtyOneDaysAgoTs = now - 60000 * 60 * 24 * 31;
|
||||
|
||||
jest.spyOn(liveTimeline, "getEvents")
|
||||
.mockReturnValueOnce([])
|
||||
.mockReturnValueOnce([makePollStartEvent("Question?", userId, undefined, { ts: thirtyOneDaysAgoTs })]);
|
||||
|
||||
// mock three pages of timeline history
|
||||
jest.spyOn(liveTimeline, "getPaginationToken")
|
||||
.mockReturnValueOnce("test-pagination-token-1")
|
||||
.mockReturnValueOnce("test-pagination-token-2")
|
||||
.mockReturnValueOnce("test-pagination-token-3");
|
||||
|
||||
getComponent();
|
||||
|
||||
// flush filter creation request
|
||||
await flushPromises();
|
||||
// after first fetch the time limit is reached
|
||||
// stop paging
|
||||
expect(mockClient.paginateEventTimeline).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("renders a no polls message when there are no active polls in the room", async () => {
|
||||
const { getByText } = getComponent();
|
||||
await act(flushPromises);
|
||||
|
||||
expect(getByText("There are no active polls in this room")).toBeTruthy();
|
||||
});
|
||||
|
||||
it("renders a no polls message and a load more button when not at end of timeline", async () => {
|
||||
const timelineSet = room.getOrCreateFilteredTimelineSet(expectedFilter);
|
||||
const liveTimeline = timelineSet.getLiveTimeline();
|
||||
const fourtyDaysAgoTs = now - 60000 * 60 * 24 * 40;
|
||||
const pollStart = makePollStartEvent("Question?", userId, undefined, { ts: fourtyDaysAgoTs, id: "1" });
|
||||
|
||||
jest.spyOn(liveTimeline, "getEvents")
|
||||
.mockReset()
|
||||
.mockReturnValueOnce([])
|
||||
.mockReturnValueOnce([pollStart])
|
||||
.mockReturnValue(undefined as unknown as MatrixEvent[]);
|
||||
|
||||
// mock three pages of timeline history
|
||||
jest.spyOn(liveTimeline, "getPaginationToken")
|
||||
.mockReturnValueOnce("test-pagination-token-1")
|
||||
.mockReturnValueOnce("test-pagination-token-2")
|
||||
.mockReturnValueOnce("test-pagination-token-3");
|
||||
|
||||
const { getByText } = getComponent();
|
||||
await act(flushPromises);
|
||||
|
||||
expect(mockClient.paginateEventTimeline).toHaveBeenCalledTimes(1);
|
||||
|
||||
expect(getByText("There are no active polls. Load more polls to view polls for previous months")).toBeTruthy();
|
||||
|
||||
fireEvent.click(getByText("Load more polls"));
|
||||
|
||||
// paged again
|
||||
expect(mockClient.paginateEventTimeline).toHaveBeenCalledTimes(2);
|
||||
// load more polls button still in UI, with loader
|
||||
expect(getByText("Load more polls")).toMatchSnapshot();
|
||||
|
||||
await act(flushPromises);
|
||||
|
||||
// no more spinner
|
||||
expect(getByText("Load more polls")).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("renders a no past polls message when there are no past polls in the room", async () => {
|
||||
const { getByText } = getComponent();
|
||||
await flushPromises();
|
||||
|
||||
fireEvent.click(getByText("Past polls"));
|
||||
|
||||
expect(getByText("There are no past polls in this room")).toBeTruthy();
|
||||
});
|
||||
|
||||
it("renders a list of active polls when there are polls in the room", async () => {
|
||||
const timestamp = 1675300825090;
|
||||
const pollStart1 = makePollStartEvent("Question?", userId, undefined, { ts: timestamp, id: "$1" });
|
||||
const pollStart2 = makePollStartEvent("Where?", userId, undefined, { ts: timestamp + 10000, id: "$2" });
|
||||
const pollStart3 = makePollStartEvent("What?", userId, undefined, { ts: timestamp + 70000, id: "$3" });
|
||||
const pollEnd3 = makePollEndEvent(pollStart3.getId()!, roomId, userId, timestamp + 1);
|
||||
await setupRoomWithPollEvents([pollStart2, pollStart3, pollStart1], [], [pollEnd3], mockClient, room);
|
||||
|
||||
const { container, queryByText, getByTestId } = getComponent();
|
||||
|
||||
// flush relations calls for polls
|
||||
await flushPromises();
|
||||
|
||||
expect(getByTestId("filter-tab-PollHistory_filter-ACTIVE").firstElementChild).toBeChecked();
|
||||
|
||||
expect(container).toMatchSnapshot();
|
||||
// this poll is ended, and default filter is ACTIVE
|
||||
expect(queryByText("What?")).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("updates when new polls are added to the room", async () => {
|
||||
const timestamp = 1675300825090;
|
||||
const pollStart1 = makePollStartEvent("Question?", userId, undefined, { ts: timestamp, id: "$1" });
|
||||
const pollStart2 = makePollStartEvent("Where?", userId, undefined, { ts: timestamp + 10000, id: "$2" });
|
||||
// initially room has only one poll
|
||||
await setupRoomWithPollEvents([pollStart1], [], [], mockClient, room);
|
||||
|
||||
const { getByText } = getComponent();
|
||||
|
||||
// wait for relations
|
||||
await flushPromises();
|
||||
|
||||
expect(getByText("Question?")).toBeInTheDocument();
|
||||
|
||||
// add another poll
|
||||
// paged history requests using cli.paginateEventTimeline
|
||||
// call this with new events
|
||||
await room.processPollEvents([pollStart2]);
|
||||
// await relations for new poll
|
||||
await flushPromises();
|
||||
|
||||
expect(getByText("Question?")).toBeInTheDocument();
|
||||
// list updated to include new poll
|
||||
expect(getByText("Where?")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("filters ended polls", async () => {
|
||||
const pollStart1 = makePollStartEvent("Question?", userId, undefined, { ts: 1675300825090, id: "$1" });
|
||||
const pollStart2 = makePollStartEvent("Where?", userId, undefined, { ts: 1675300725090, id: "$2" });
|
||||
const pollStart3 = makePollStartEvent("What?", userId, undefined, { ts: 1675200725090, id: "$3" });
|
||||
const pollEnd3 = makePollEndEvent(pollStart3.getId()!, roomId, userId, 1675200725090 + 1);
|
||||
await setupRoomWithPollEvents([pollStart1, pollStart2, pollStart3], [], [pollEnd3], mockClient, room);
|
||||
|
||||
const { getByText, queryByText, getByTestId } = getComponent();
|
||||
await flushPromises();
|
||||
|
||||
expect(getByText("Question?")).toBeInTheDocument();
|
||||
expect(getByText("Where?")).toBeInTheDocument();
|
||||
// this poll is ended, and default filter is ACTIVE
|
||||
expect(queryByText("What?")).not.toBeInTheDocument();
|
||||
|
||||
fireEvent.click(getByText("Past polls"));
|
||||
expect(getByTestId("filter-tab-PollHistory_filter-ENDED").firstElementChild).toBeChecked();
|
||||
|
||||
// active polls no longer shown
|
||||
expect(queryByText("Question?")).not.toBeInTheDocument();
|
||||
expect(queryByText("Where?")).not.toBeInTheDocument();
|
||||
// this poll is ended
|
||||
expect(getByText("What?")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
describe("Poll detail", () => {
|
||||
const timestamp = 1675300825090;
|
||||
const pollStart1 = makePollStartEvent("Question?", userId, undefined, { ts: timestamp, id: "$1" });
|
||||
const pollStart2 = makePollStartEvent("Where?", userId, undefined, { ts: timestamp + 10000, id: "$2" });
|
||||
const pollStart3 = makePollStartEvent("What?", userId, undefined, { ts: timestamp + 70000, id: "$3" });
|
||||
const pollEnd3 = makePollEndEvent(pollStart3.getId()!, roomId, userId, timestamp + 1, "$4");
|
||||
|
||||
it("displays poll detail on active poll list item click", async () => {
|
||||
await setupRoomWithPollEvents([pollStart1, pollStart2, pollStart3], [], [pollEnd3], mockClient, room);
|
||||
|
||||
const { getByText, queryByText } = getComponent();
|
||||
await flushPromises();
|
||||
|
||||
fireEvent.click(getByText("Question?"));
|
||||
|
||||
expect(queryByText("Polls")).not.toBeInTheDocument();
|
||||
// elements from MPollBody
|
||||
expect(getByText("Question?")).toMatchSnapshot();
|
||||
expect(getByText("Socks")).toBeInTheDocument();
|
||||
expect(getByText("Shoes")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("links to the poll start event from an active poll detail", async () => {
|
||||
await setupRoomWithPollEvents([pollStart1, pollStart2, pollStart3], [], [pollEnd3], mockClient, room);
|
||||
|
||||
const { getByText } = getComponent();
|
||||
await flushPromises();
|
||||
|
||||
fireEvent.click(getByText("Question?"));
|
||||
|
||||
// links to poll start event
|
||||
expect(getByText("View poll in timeline").getAttribute("href")).toBe(
|
||||
`https://matrix.to/#/!room:domain.org/${pollStart1.getId()!}`,
|
||||
);
|
||||
});
|
||||
|
||||
it("navigates in app when clicking view in timeline button", async () => {
|
||||
await setupRoomWithPollEvents([pollStart1, pollStart2, pollStart3], [], [pollEnd3], mockClient, room);
|
||||
|
||||
const { getByText } = getComponent();
|
||||
await flushPromises();
|
||||
|
||||
fireEvent.click(getByText("Question?"));
|
||||
|
||||
const event = new MouseEvent("click", { bubbles: true, cancelable: true });
|
||||
jest.spyOn(event, "preventDefault");
|
||||
fireEvent(getByText("View poll in timeline"), event);
|
||||
|
||||
expect(event.preventDefault).toHaveBeenCalled();
|
||||
|
||||
expect(defaultDispatcher.dispatch).toHaveBeenCalledWith({
|
||||
action: Action.ViewRoom,
|
||||
event_id: pollStart1.getId()!,
|
||||
highlighted: true,
|
||||
metricsTrigger: undefined,
|
||||
room_id: pollStart1.getRoomId()!,
|
||||
});
|
||||
|
||||
// dialog closed
|
||||
expect(defaultProps.onFinished).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("doesnt navigate in app when view in timeline link is ctrl + clicked", async () => {
|
||||
await setupRoomWithPollEvents([pollStart1, pollStart2, pollStart3], [], [pollEnd3], mockClient, room);
|
||||
|
||||
const { getByText } = getComponent();
|
||||
await flushPromises();
|
||||
|
||||
fireEvent.click(getByText("Question?"));
|
||||
|
||||
const event = new MouseEvent("click", { bubbles: true, cancelable: true, ctrlKey: true });
|
||||
jest.spyOn(event, "preventDefault");
|
||||
fireEvent(getByText("View poll in timeline"), event);
|
||||
|
||||
expect(event.preventDefault).not.toHaveBeenCalled();
|
||||
expect(defaultDispatcher.dispatch).not.toHaveBeenCalled();
|
||||
expect(defaultProps.onFinished).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("navigates back to poll list from detail view on header click", async () => {
|
||||
await setupRoomWithPollEvents([pollStart1, pollStart2, pollStart3], [], [pollEnd3], mockClient, room);
|
||||
|
||||
const { getByText, queryByText, getByTestId, container } = getComponent();
|
||||
await flushPromises();
|
||||
|
||||
fireEvent.click(getByText("Question?"));
|
||||
|
||||
// detail view
|
||||
expect(getByText("Question?")).toBeInTheDocument();
|
||||
|
||||
// header not shown
|
||||
expect(queryByText("Polls")).not.toBeInTheDocument();
|
||||
|
||||
expect(getByText("Active polls")).toMatchSnapshot();
|
||||
fireEvent.click(getByText("Active polls"));
|
||||
|
||||
// main list header displayed again
|
||||
expect(getByText("Polls")).toBeInTheDocument();
|
||||
// active filter still active
|
||||
expect(getByTestId("filter-tab-PollHistory_filter-ACTIVE").firstElementChild).toBeChecked();
|
||||
// list displayed
|
||||
expect(container.getElementsByClassName("mx_PollHistoryList_list").length).toBeTruthy();
|
||||
});
|
||||
|
||||
it("displays poll detail on past poll list item click", async () => {
|
||||
await setupRoomWithPollEvents([pollStart1, pollStart2, pollStart3], [], [pollEnd3], mockClient, room);
|
||||
|
||||
const { getByText } = getComponent();
|
||||
await flushPromises();
|
||||
|
||||
fireEvent.click(getByText("Past polls"));
|
||||
|
||||
// pollStart3 is ended
|
||||
fireEvent.click(getByText("What?"));
|
||||
|
||||
expect(getByText("What?")).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("links to the poll end events from a ended poll detail", async () => {
|
||||
await setupRoomWithPollEvents([pollStart1, pollStart2, pollStart3], [], [pollEnd3], mockClient, room);
|
||||
|
||||
const { getByText } = getComponent();
|
||||
await flushPromises();
|
||||
|
||||
fireEvent.click(getByText("Past polls"));
|
||||
|
||||
// pollStart3 is ended
|
||||
fireEvent.click(getByText("What?"));
|
||||
|
||||
// links to poll end event
|
||||
expect(getByText("View poll in timeline").getAttribute("href")).toBe(
|
||||
`https://matrix.to/#/!room:domain.org/${pollEnd3.getId()!}`,
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
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 React from "react";
|
||||
import { fireEvent, render } from "jest-matrix-react";
|
||||
import { MatrixEvent } from "matrix-js-sdk/src/matrix";
|
||||
|
||||
import { PollListItem } from "../../../../../src/components/views/polls/pollHistory/PollListItem";
|
||||
import { makePollStartEvent, mockIntlDateTimeFormat, unmockIntlDateTimeFormat } from "../../../../test-utils";
|
||||
|
||||
describe("<PollListItem />", () => {
|
||||
const event = makePollStartEvent("Question?", "@me:domain.org");
|
||||
event.getContent().origin;
|
||||
const defaultProps = { event, onClick: jest.fn() };
|
||||
const getComponent = (props = {}) => render(<PollListItem {...defaultProps} {...props} />);
|
||||
|
||||
beforeAll(() => {
|
||||
// mock default locale to en-GB and set timezone
|
||||
// so these tests run the same everywhere
|
||||
mockIntlDateTimeFormat();
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
unmockIntlDateTimeFormat();
|
||||
});
|
||||
|
||||
it("renders a poll", () => {
|
||||
const { container } = getComponent();
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("renders null when event does not have an extensible poll start event", () => {
|
||||
const event = new MatrixEvent({
|
||||
type: "m.room.message",
|
||||
content: {},
|
||||
});
|
||||
const { container } = getComponent({ event });
|
||||
expect(container.firstElementChild).toBeFalsy();
|
||||
});
|
||||
|
||||
it("calls onClick handler on click", () => {
|
||||
const onClick = jest.fn();
|
||||
const { getByText } = getComponent({ onClick });
|
||||
|
||||
fireEvent.click(getByText("Question?"));
|
||||
|
||||
expect(onClick).toHaveBeenCalled();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,173 @@
|
|||
/*
|
||||
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 React from "react";
|
||||
import { render } from "jest-matrix-react";
|
||||
import { MatrixEvent, Poll, Room, M_TEXT } from "matrix-js-sdk/src/matrix";
|
||||
|
||||
import { PollListItemEnded } from "../../../../../src/components/views/polls/pollHistory/PollListItemEnded";
|
||||
import {
|
||||
flushPromises,
|
||||
getMockClientWithEventEmitter,
|
||||
makePollEndEvent,
|
||||
makePollResponseEvent,
|
||||
makePollStartEvent,
|
||||
mockClientMethodsUser,
|
||||
mockIntlDateTimeFormat,
|
||||
setupRoomWithPollEvents,
|
||||
unmockIntlDateTimeFormat,
|
||||
} from "../../../../test-utils";
|
||||
|
||||
describe("<PollListItemEnded />", () => {
|
||||
const userId = "@alice:domain.org";
|
||||
const roomId = "!room:domain.org";
|
||||
const mockClient = getMockClientWithEventEmitter({
|
||||
...mockClientMethodsUser(userId),
|
||||
getRoom: jest.fn(),
|
||||
relations: jest.fn(),
|
||||
decryptEventIfNeeded: jest.fn(),
|
||||
});
|
||||
const room = new Room(roomId, mockClient, userId);
|
||||
const timestamp = 1675300825090;
|
||||
|
||||
const pollId = "1";
|
||||
const answerOne = {
|
||||
id: "answerOneId",
|
||||
[M_TEXT.name]: "Nissan Silvia S15",
|
||||
};
|
||||
const answerTwo = {
|
||||
id: "answerTwoId",
|
||||
[M_TEXT.name]: "Mitsubishi Lancer Evolution IX",
|
||||
};
|
||||
const pollStartEvent = makePollStartEvent("Question?", userId, [answerOne, answerTwo], {
|
||||
roomId,
|
||||
id: pollId,
|
||||
ts: timestamp,
|
||||
});
|
||||
const pollEndEvent = makePollEndEvent(pollId, roomId, userId, timestamp + 60000);
|
||||
|
||||
const getComponent = (props: { event: MatrixEvent; poll: Poll }) =>
|
||||
render(<PollListItemEnded {...props} onClick={jest.fn()} />);
|
||||
|
||||
beforeAll(() => {
|
||||
// mock default locale to en-GB and set timezone
|
||||
// so these tests run the same everywhere
|
||||
mockIntlDateTimeFormat();
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
unmockIntlDateTimeFormat();
|
||||
});
|
||||
|
||||
it("renders a poll with no responses", async () => {
|
||||
await setupRoomWithPollEvents([pollStartEvent], [], [pollEndEvent], mockClient, room);
|
||||
const poll = room.polls.get(pollId)!;
|
||||
|
||||
const { container } = getComponent({ event: pollStartEvent, poll });
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("renders a poll with one winning answer", async () => {
|
||||
const responses = [
|
||||
makePollResponseEvent(pollId, [answerOne.id], userId, roomId, timestamp + 1),
|
||||
makePollResponseEvent(pollId, [answerOne.id], "@bob:domain.org", roomId, timestamp + 1),
|
||||
makePollResponseEvent(pollId, [answerTwo.id], "@charlie:domain.org", roomId, timestamp + 1),
|
||||
];
|
||||
await setupRoomWithPollEvents([pollStartEvent], responses, [pollEndEvent], mockClient, room);
|
||||
const poll = room.polls.get(pollId)!;
|
||||
|
||||
const { getByText } = getComponent({ event: pollStartEvent, poll });
|
||||
// fetch relations
|
||||
await flushPromises();
|
||||
expect(getByText("Final result based on 3 votes")).toBeInTheDocument();
|
||||
// winning answer
|
||||
expect(getByText("Nissan Silvia S15")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("renders a poll with two winning answers", async () => {
|
||||
const responses = [
|
||||
makePollResponseEvent(pollId, [answerOne.id], userId, roomId, timestamp + 1),
|
||||
makePollResponseEvent(pollId, [answerOne.id], "@han:domain.org", roomId, timestamp + 1),
|
||||
makePollResponseEvent(pollId, [answerTwo.id], "@sean:domain.org", roomId, timestamp + 1),
|
||||
makePollResponseEvent(pollId, [answerTwo.id], "@dk:domain.org", roomId, timestamp + 1),
|
||||
];
|
||||
await setupRoomWithPollEvents([pollStartEvent], responses, [pollEndEvent], mockClient, room);
|
||||
const poll = room.polls.get(pollId)!;
|
||||
|
||||
const { getByText } = getComponent({ event: pollStartEvent, poll });
|
||||
// fetch relations
|
||||
await flushPromises();
|
||||
expect(getByText("Final result based on 4 votes")).toBeInTheDocument();
|
||||
// both answers answer
|
||||
expect(getByText("Nissan Silvia S15")).toBeInTheDocument();
|
||||
expect(getByText("Mitsubishi Lancer Evolution IX")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("counts one unique vote per user", async () => {
|
||||
const responses = [
|
||||
makePollResponseEvent(pollId, [answerTwo.id], userId, roomId, timestamp + 1),
|
||||
makePollResponseEvent(pollId, [answerTwo.id], userId, roomId, timestamp + 1),
|
||||
makePollResponseEvent(pollId, [answerTwo.id], userId, roomId, timestamp + 1),
|
||||
makePollResponseEvent(pollId, [answerOne.id], userId, roomId, timestamp + 2),
|
||||
makePollResponseEvent(pollId, [answerOne.id], "@bob:domain.org", roomId, timestamp + 1),
|
||||
makePollResponseEvent(pollId, [answerTwo.id], "@charlie:domain.org", roomId, timestamp + 1),
|
||||
];
|
||||
await setupRoomWithPollEvents([pollStartEvent], responses, [pollEndEvent], mockClient, room);
|
||||
const poll = room.polls.get(pollId)!;
|
||||
|
||||
const { getByText } = getComponent({ event: pollStartEvent, poll });
|
||||
// fetch relations
|
||||
await flushPromises();
|
||||
|
||||
// still only 3 unique votes
|
||||
expect(getByText("Final result based on 3 votes")).toBeInTheDocument();
|
||||
// only latest vote counted
|
||||
expect(getByText("Nissan Silvia S15")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("excludes malformed responses", async () => {
|
||||
const responses = [
|
||||
makePollResponseEvent(pollId, ["bad-answer-id"], userId, roomId, timestamp + 1),
|
||||
makePollResponseEvent(pollId, [answerOne.id], "@bob:domain.org", roomId, timestamp + 1),
|
||||
makePollResponseEvent(pollId, [answerTwo.id], "@charlie:domain.org", roomId, timestamp + 1),
|
||||
];
|
||||
await setupRoomWithPollEvents([pollStartEvent], responses, [pollEndEvent], mockClient, room);
|
||||
const poll = room.polls.get(pollId)!;
|
||||
|
||||
const { getByText } = getComponent({ event: pollStartEvent, poll });
|
||||
// fetch relations
|
||||
await flushPromises();
|
||||
|
||||
// invalid vote excluded
|
||||
expect(getByText("Final result based on 2 votes")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("updates on new responses", async () => {
|
||||
const responses = [
|
||||
makePollResponseEvent(pollId, [answerOne.id], "@bob:domain.org", roomId, timestamp + 1),
|
||||
makePollResponseEvent(pollId, [answerTwo.id], "@charlie:domain.org", roomId, timestamp + 1),
|
||||
];
|
||||
await setupRoomWithPollEvents([pollStartEvent], responses, [pollEndEvent], mockClient, room);
|
||||
const poll = room.polls.get(pollId)!;
|
||||
|
||||
const { getByText, queryByText, findByText } = getComponent({ event: pollStartEvent, poll });
|
||||
// fetch relations
|
||||
await flushPromises();
|
||||
|
||||
expect(getByText("Final result based on 2 votes")).toBeInTheDocument();
|
||||
|
||||
await room.processPollEvents([
|
||||
makePollResponseEvent(pollId, [answerOne.id], "@han:domain.org", roomId, timestamp + 1),
|
||||
]);
|
||||
|
||||
// updated with more responses
|
||||
await expect(findByText("Final result based on 3 votes")).resolves.toBeInTheDocument();
|
||||
expect(getByText("Nissan Silvia S15")).toBeInTheDocument();
|
||||
expect(queryByText("Mitsubishi Lancer Evolution IX")).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,160 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`<PollHistory /> Poll detail displays poll detail on active poll list item click 1`] = `
|
||||
<h2
|
||||
data-testid="pollQuestion"
|
||||
>
|
||||
Question?
|
||||
</h2>
|
||||
`;
|
||||
|
||||
exports[`<PollHistory /> Poll detail displays poll detail on past poll list item click 1`] = `
|
||||
<h2
|
||||
data-testid="pollQuestion"
|
||||
>
|
||||
What?
|
||||
</h2>
|
||||
`;
|
||||
|
||||
exports[`<PollHistory /> Poll detail navigates back to poll list from detail view on header click 1`] = `
|
||||
<div
|
||||
class="mx_AccessibleButton mx_PollDetailHeader mx_AccessibleButton_hasKind mx_AccessibleButton_kind_content_inline"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
<div
|
||||
class="mx_PollDetailHeader_icon"
|
||||
/>
|
||||
Active polls
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`<PollHistory /> renders a list of active polls when there are polls in the room 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="mx_PollHistory_content"
|
||||
>
|
||||
<h2
|
||||
class="mx_Heading_h2 mx_PollHistory_header"
|
||||
>
|
||||
Polls
|
||||
</h2>
|
||||
<div
|
||||
class="mx_PollHistoryList"
|
||||
>
|
||||
<fieldset
|
||||
class="mx_FilterTabGroup"
|
||||
>
|
||||
<label
|
||||
data-testid="filter-tab-PollHistory_filter-ACTIVE"
|
||||
>
|
||||
<input
|
||||
checked=""
|
||||
name="PollHistory_filter"
|
||||
type="radio"
|
||||
value="ACTIVE"
|
||||
/>
|
||||
<span>
|
||||
Active polls
|
||||
</span>
|
||||
</label>
|
||||
<label
|
||||
data-testid="filter-tab-PollHistory_filter-ENDED"
|
||||
>
|
||||
<input
|
||||
name="PollHistory_filter"
|
||||
type="radio"
|
||||
value="ENDED"
|
||||
/>
|
||||
<span>
|
||||
Past polls
|
||||
</span>
|
||||
</label>
|
||||
</fieldset>
|
||||
<ol
|
||||
class="mx_PollHistoryList_list mx_PollHistoryList_list_ACTIVE"
|
||||
>
|
||||
<li
|
||||
class="mx_PollListItem"
|
||||
data-testid="pollListItem-$2"
|
||||
>
|
||||
<span
|
||||
tabindex="0"
|
||||
>
|
||||
<div
|
||||
aria-labelledby="floating-ui-10"
|
||||
class="mx_PollListItem_content"
|
||||
>
|
||||
<span>
|
||||
02/02/23
|
||||
</span>
|
||||
<div
|
||||
class="mx_PollListItem_icon"
|
||||
/>
|
||||
<span
|
||||
class="mx_PollListItem_question"
|
||||
>
|
||||
Where?
|
||||
</span>
|
||||
</div>
|
||||
</span>
|
||||
</li>
|
||||
<li
|
||||
class="mx_PollListItem"
|
||||
data-testid="pollListItem-$1"
|
||||
>
|
||||
<span
|
||||
tabindex="0"
|
||||
>
|
||||
<div
|
||||
aria-labelledby="floating-ui-16"
|
||||
class="mx_PollListItem_content"
|
||||
>
|
||||
<span>
|
||||
02/02/23
|
||||
</span>
|
||||
<div
|
||||
class="mx_PollListItem_icon"
|
||||
/>
|
||||
<span
|
||||
class="mx_PollListItem_question"
|
||||
>
|
||||
Question?
|
||||
</span>
|
||||
</div>
|
||||
</span>
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`<PollHistory /> renders a no polls message and a load more button when not at end of timeline 1`] = `
|
||||
<div
|
||||
class="mx_AccessibleButton mx_PollHistoryList_loadMorePolls mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link_inline"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
Load more polls
|
||||
<div
|
||||
class="mx_InlineSpinner"
|
||||
>
|
||||
<div
|
||||
aria-label="Loading…"
|
||||
class="mx_InlineSpinner_icon mx_Spinner_icon"
|
||||
style="width: 16px; height: 16px;"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`<PollHistory /> renders a no polls message and a load more button when not at end of timeline 2`] = `
|
||||
<div
|
||||
class="mx_AccessibleButton mx_PollHistoryList_loadMorePolls mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link_inline"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
Load more polls
|
||||
</div>
|
||||
`;
|
|
@ -0,0 +1,31 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`<PollListItem /> renders a poll 1`] = `
|
||||
<div>
|
||||
<li
|
||||
class="mx_PollListItem"
|
||||
data-testid="pollListItem-$mypoll"
|
||||
>
|
||||
<span
|
||||
tabindex="0"
|
||||
>
|
||||
<div
|
||||
aria-labelledby="floating-ui-1"
|
||||
class="mx_PollListItem_content"
|
||||
>
|
||||
<span>
|
||||
01/01/70
|
||||
</span>
|
||||
<div
|
||||
class="mx_PollListItem_icon"
|
||||
/>
|
||||
<span
|
||||
class="mx_PollListItem_question"
|
||||
>
|
||||
Question?
|
||||
</span>
|
||||
</div>
|
||||
</span>
|
||||
</li>
|
||||
</div>
|
||||
`;
|
|
@ -0,0 +1,46 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`<PollListItemEnded /> renders a poll with no responses 1`] = `
|
||||
<div>
|
||||
<li
|
||||
class="mx_PollListItemEnded"
|
||||
data-testid="pollListItem-1"
|
||||
>
|
||||
<span
|
||||
tabindex="0"
|
||||
>
|
||||
<div
|
||||
aria-labelledby="floating-ui-1"
|
||||
class="mx_PollListItemEnded_content"
|
||||
>
|
||||
<div
|
||||
class="mx_PollListItemEnded_title"
|
||||
>
|
||||
<div
|
||||
class="mx_PollListItemEnded_icon"
|
||||
/>
|
||||
<span
|
||||
class="mx_PollListItemEnded_question"
|
||||
>
|
||||
Question?
|
||||
</span>
|
||||
<span
|
||||
class="mx_Caption"
|
||||
>
|
||||
02/02/23
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="mx_PollListItemEnded_voteCount"
|
||||
>
|
||||
<span
|
||||
class="mx_Caption"
|
||||
>
|
||||
Final result based on 0 votes
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</span>
|
||||
</li>
|
||||
</div>
|
||||
`;
|
Loading…
Add table
Add a link
Reference in a new issue