Poll history - make poll history independent from dialogs (#10349)

* move pollhistory from dialogs to polls directory

* rename PollHistoryDialog -> PollHistory

* rename references to PollHistoryDialog

* move title to PollHistory

* add option to collapse empty dialog header
This commit is contained in:
Kerry 2023-03-13 09:22:30 +13:00 committed by GitHub
parent 127a3b667c
commit 1e46efe89c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
25 changed files with 290 additions and 251 deletions

View file

@ -1,435 +0,0 @@
/*
Copyright 2023 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 React from "react";
import { fireEvent, render } from "@testing-library/react";
import { Filter } from "matrix-js-sdk/src/filter";
import { EventTimeline, Room } from "matrix-js-sdk/src/matrix";
import { M_POLL_START } from "matrix-js-sdk/src/@types/polls";
import { PollHistoryDialog } from "../../../../../src/components/views/dialogs/polls/PollHistoryDialog";
import {
flushPromises,
getMockClientWithEventEmitter,
makePollEndEvent,
makePollStartEvent,
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";
describe("<PollHistoryDialog />", () => {
// 14.03.2022 16:15
const now = 1647270879403;
const userId = "@alice:domain.org";
const roomId = "!room:domain.org";
const mockClient = getMockClientWithEventEmitter({
...mockClientMethodsUser(userId),
getRoom: jest.fn(),
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(<PollHistoryDialog {...defaultProps} />);
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 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 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 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]);
// 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 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 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-PollHistoryDialog_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-PollHistoryDialog_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 history")).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 history")).not.toBeInTheDocument();
expect(getByText("Active polls")).toMatchSnapshot();
fireEvent.click(getByText("Active polls"));
// main list header displayed again
expect(getByText("Polls history")).toBeInTheDocument();
// active filter still active
expect(getByTestId("filter-tab-PollHistoryDialog_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()!}`,
);
});
});
});

View file

@ -1,62 +0,0 @@
/*
Copyright 2023 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 React from "react";
import { fireEvent, render } from "@testing-library/react";
import { MatrixEvent } from "matrix-js-sdk/src/matrix";
import { PollListItem } from "../../../../../src/components/views/dialogs/polls/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();
});
});

View file

@ -1,182 +0,0 @@
/*
Copyright 2023 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 React from "react";
import { render } from "@testing-library/react";
import { MatrixEvent, Poll, Room } from "matrix-js-sdk/src/matrix";
import { M_TEXT } from "matrix-js-sdk/src/@types/extensible_events";
import { PollListItemEnded } from "../../../../../src/components/views/dialogs/polls/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 } = 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
expect(getByText("Final result based on 3 votes")).toBeInTheDocument();
expect(getByText("Nissan Silvia S15")).toBeInTheDocument();
expect(queryByText("Mitsubishi Lancer Evolution IX")).not.toBeInTheDocument();
});
});

View file

@ -1,186 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`<PollHistoryDialog /> Poll detail displays poll detail on active poll list item click 1`] = `
<h2
data-testid="pollQuestion"
>
Question?
</h2>
`;
exports[`<PollHistoryDialog /> Poll detail displays poll detail on past poll list item click 1`] = `
<h2
data-testid="pollQuestion"
>
What?
</h2>
`;
exports[`<PollHistoryDialog /> 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[`<PollHistoryDialog /> renders a list of active polls when there are polls in the room 1`] = `
<div>
<div
data-focus-guard="true"
style="width: 1px; height: 0px; padding: 0px; overflow: hidden; position: fixed; top: 1px; left: 1px;"
tabindex="0"
/>
<div
aria-labelledby="mx_BaseDialog_title"
class="mx_Dialog_fixedWidth"
data-focus-lock-disabled="false"
role="dialog"
>
<div
class="mx_Dialog_header mx_Dialog_headerWithCancel"
>
<h2
class="mx_Heading_h2 mx_Dialog_title"
id="mx_BaseDialog_title"
>
Polls history
</h2>
<div
aria-label="Close dialog"
class="mx_AccessibleButton mx_Dialog_cancelButton"
role="button"
tabindex="0"
/>
</div>
<div
class="mx_PollHistoryDialog_content"
>
<div
class="mx_PollHistoryList"
>
<fieldset
class="mx_FilterTabGroup"
>
<label
data-testid="filter-tab-PollHistoryDialog_filter-ACTIVE"
>
<input
checked=""
name="PollHistoryDialog_filter"
type="radio"
value="ACTIVE"
/>
<span>
Active polls
</span>
</label>
<label
data-testid="filter-tab-PollHistoryDialog_filter-ENDED"
>
<input
name="PollHistoryDialog_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"
>
<div
tabindex="0"
>
<div
class="mx_PollListItem_content"
>
<span>
02/02/23
</span>
<div
class="mx_PollListItem_icon"
/>
<span
class="mx_PollListItem_question"
>
Where?
</span>
</div>
</div>
</li>
<li
class="mx_PollListItem"
data-testid="pollListItem-$1"
>
<div
tabindex="0"
>
<div
class="mx_PollListItem_content"
>
<span>
02/02/23
</span>
<div
class="mx_PollListItem_icon"
/>
<span
class="mx_PollListItem_question"
>
Question?
</span>
</div>
</div>
</li>
</ol>
</div>
</div>
</div>
<div
data-focus-guard="true"
style="width: 1px; height: 0px; padding: 0px; overflow: hidden; position: fixed; top: 1px; left: 1px;"
tabindex="0"
/>
</div>
`;
exports[`<PollHistoryDialog /> 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[`<PollHistoryDialog /> 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>
`;

View file

@ -1,30 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`<PollListItem /> renders a poll 1`] = `
<div>
<li
class="mx_PollListItem"
data-testid="pollListItem-$mypoll"
>
<div
tabindex="0"
>
<div
class="mx_PollListItem_content"
>
<span>
01/01/70
</span>
<div
class="mx_PollListItem_icon"
/>
<span
class="mx_PollListItem_question"
>
Question?
</span>
</div>
</div>
</li>
</div>
`;

View file

@ -1,45 +0,0 @@
// 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"
>
<div
tabindex="0"
>
<div
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>
</div>
</li>
</div>
`;