/*
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 "@testing-library/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("", () => {
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();
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();
});
});