Poll history - extract poll option display components (#10107)

* wip

* remove dupe

* use poll model relations in all cases

* update mpollbody tests to use poll instance

* update poll fetching login in pinned messages card

* add pinned polls to room polls state

* add spinner while relations are still loading

* handle no poll in end poll dialog

* strict errors

* render a poll body that errors for poll end events

* add fetching logic to pollend tile

* extract poll testing utilities

* test mpollend

* strict fix

* more strict fix

* strict fix for forwardref

* add filter component

* update poll test utils

* add unstyled filter tab group

* filtertabgroup snapshot

* lint

* update test util setupRoomWithPollEvents to allow testing multiple polls in one room

* style filter tabs

* test error message for past polls

* sort polls list by latest

* extract poll option display components

* strict fixes
This commit is contained in:
Kerry 2023-02-13 15:55:39 +13:00 committed by GitHub
parent 18ab325eaf
commit 1c6b06bb58
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 597 additions and 494 deletions

View file

@ -42,7 +42,7 @@ import MPollBody from "../../../../src/components/views/messages/MPollBody";
import { RoomPermalinkCreator } from "../../../../src/utils/permalinks/Permalinks";
import { MediaEventHelper } from "../../../../src/utils/MediaEventHelper";
const CHECKED = "mx_MPollBody_option_checked";
const CHECKED = "mx_PollOption_checked";
const userId = "@me:example.com";
const mockClient = getMockClientWithEventEmitter({
@ -383,7 +383,7 @@ describe("MPollBody", () => {
const votes: MatrixEvent[] = [];
const ends: MatrixEvent[] = [];
const { container } = await newMPollBody(votes, ends, answers);
expect(container.querySelectorAll(".mx_MPollBody_option").length).toBe(20);
expect(container.querySelectorAll(".mx_PollOption").length).toBe(20);
});
it("hides scores if I voted but the poll is undisclosed", async () => {
@ -429,7 +429,7 @@ describe("MPollBody", () => {
];
const ends = [newPollEndEvent("@me:example.com", 12)];
const renderResult = await newMPollBody(votes, ends, undefined, false);
expect(endedVotesCount(renderResult, "pizza")).toBe("3 votes");
expect(endedVotesCount(renderResult, "pizza")).toBe('<div class="mx_PollOption_winnerIcon"></div>3 votes');
expect(endedVotesCount(renderResult, "poutine")).toBe("1 vote");
expect(endedVotesCount(renderResult, "italian")).toBe("0 votes");
expect(endedVotesCount(renderResult, "wings")).toBe("1 vote");
@ -531,9 +531,9 @@ describe("MPollBody", () => {
const ends = [newPollEndEvent("@me:example.com", 25)];
const renderResult = await newMPollBody(votes, ends);
expect(endedVotesCount(renderResult, "pizza")).toBe("0 votes");
expect(endedVotesCount(renderResult, "poutine")).toBe("1 vote");
expect(endedVotesCount(renderResult, "poutine")).toBe('<div class="mx_PollOption_winnerIcon"></div>1 vote');
expect(endedVotesCount(renderResult, "italian")).toBe("0 votes");
expect(endedVotesCount(renderResult, "wings")).toBe("1 vote");
expect(endedVotesCount(renderResult, "wings")).toBe('<div class="mx_PollOption_winnerIcon"></div>1 vote');
expect(renderResult.getByTestId("totalVotes").innerHTML).toBe("Final result based on 2 votes");
});
@ -542,7 +542,7 @@ describe("MPollBody", () => {
const ends = [newPollEndEvent("@me:example.com", 25)];
const renderResult = await newMPollBody(votes, ends);
expect(endedVotesCount(renderResult, "pizza")).toBe("0 votes");
expect(endedVotesCount(renderResult, "poutine")).toBe("1 vote");
expect(endedVotesCount(renderResult, "poutine")).toBe('<div class="mx_PollOption_winnerIcon"></div>1 vote');
expect(endedVotesCount(renderResult, "italian")).toBe("0 votes");
expect(endedVotesCount(renderResult, "wings")).toBe("0 votes");
expect(renderResult.getByTestId("totalVotes").innerHTML).toBe("Final result based on 1 vote");
@ -564,7 +564,7 @@ describe("MPollBody", () => {
expect(endedVotesCount(renderResult, "pizza")).toBe("2 votes");
expect(endedVotesCount(renderResult, "poutine")).toBe("0 votes");
expect(endedVotesCount(renderResult, "italian")).toBe("0 votes");
expect(endedVotesCount(renderResult, "wings")).toBe("3 votes");
expect(endedVotesCount(renderResult, "wings")).toBe('<div class="mx_PollOption_winnerIcon"></div>3 votes');
expect(renderResult.getByTestId("totalVotes").innerHTML).toBe("Final result based on 5 votes");
});
@ -584,7 +584,7 @@ describe("MPollBody", () => {
expect(endedVotesCount(renderResult, "pizza")).toBe("2 votes");
expect(endedVotesCount(renderResult, "poutine")).toBe("0 votes");
expect(endedVotesCount(renderResult, "italian")).toBe("0 votes");
expect(endedVotesCount(renderResult, "wings")).toBe("3 votes");
expect(endedVotesCount(renderResult, "wings")).toBe('<div class="mx_PollOption_winnerIcon"></div>3 votes');
expect(renderResult.getByTestId("totalVotes").innerHTML).toBe("Final result based on 5 votes");
});
@ -607,7 +607,7 @@ describe("MPollBody", () => {
expect(endedVotesCount(renderResult, "pizza")).toBe("2 votes");
expect(endedVotesCount(renderResult, "poutine")).toBe("0 votes");
expect(endedVotesCount(renderResult, "italian")).toBe("0 votes");
expect(endedVotesCount(renderResult, "wings")).toBe("3 votes");
expect(endedVotesCount(renderResult, "wings")).toBe('<div class="mx_PollOption_winnerIcon"></div>3 votes');
expect(renderResult.getByTestId("totalVotes").innerHTML).toBe("Final result based on 5 votes");
});
@ -634,7 +634,7 @@ describe("MPollBody", () => {
expect(endedVotesCount(renderResult, "pizza")).toBe("2 votes");
expect(endedVotesCount(renderResult, "poutine")).toBe("0 votes");
expect(endedVotesCount(renderResult, "italian")).toBe("0 votes");
expect(endedVotesCount(renderResult, "wings")).toBe("3 votes");
expect(endedVotesCount(renderResult, "wings")).toBe('<div class="mx_PollOption_winnerIcon"></div>3 votes');
expect(renderResult.getByTestId("totalVotes").innerHTML).toBe("Final result based on 5 votes");
});
@ -653,8 +653,8 @@ describe("MPollBody", () => {
expect(endedVoteChecked(renderResult, "pizza")).toBe(false);
// Double-check by looking for the endedOptionWinner class
expect(endedVoteDiv(renderResult, "wings").className.includes("mx_MPollBody_endedOptionWinner")).toBe(true);
expect(endedVoteDiv(renderResult, "pizza").className.includes("mx_MPollBody_endedOptionWinner")).toBe(false);
expect(endedVoteDiv(renderResult, "wings").className.includes("mx_PollOption_endedOptionWinner")).toBe(true);
expect(endedVoteDiv(renderResult, "pizza").className.includes("mx_PollOption_endedOptionWinner")).toBe(false);
});
it("highlights multiple winning votes", async () => {
@ -670,13 +670,13 @@ describe("MPollBody", () => {
expect(endedVoteChecked(renderResult, "wings")).toBe(true);
expect(endedVoteChecked(renderResult, "poutine")).toBe(true);
expect(endedVoteChecked(renderResult, "italian")).toBe(false);
expect(renderResult.container.getElementsByClassName("mx_MPollBody_option_checked")).toHaveLength(3);
expect(renderResult.container.getElementsByClassName(CHECKED)).toHaveLength(3);
});
it("highlights nothing if poll has no votes", async () => {
const ends = [newPollEndEvent("@me:example.com", 25)];
const renderResult = await newMPollBody([], ends);
expect(renderResult.container.getElementsByClassName("mx_MPollBody_option_checked")).toHaveLength(0);
expect(renderResult.container.getElementsByClassName(CHECKED)).toHaveLength(0);
});
it("says poll is not ended if there is no end event", async () => {
@ -745,7 +745,7 @@ describe("MPollBody", () => {
expect(inputs[0].getAttribute("value")).toEqual("n1");
expect(inputs[1].getAttribute("value")).toEqual("n2");
expect(inputs[2].getAttribute("value")).toEqual("n3");
const options = container.querySelectorAll(".mx_MPollBody_optionText");
const options = container.querySelectorAll(".mx_PollOption_optionText");
expect(options).toHaveLength(3);
expect(options[0].innerHTML).toEqual("new answer 1");
expect(options[1].innerHTML).toEqual("new answer 2");
@ -934,11 +934,11 @@ function voteButton({ getByTestId }: RenderResult, value: string): Element {
}
function votesCount({ getByTestId }: RenderResult, value: string): string {
return getByTestId(`pollOption-${value}`).querySelector(".mx_MPollBody_optionVoteCount")!.innerHTML;
return getByTestId(`pollOption-${value}`).querySelector(".mx_PollOption_optionVoteCount")!.innerHTML;
}
function endedVoteChecked({ getByTestId }: RenderResult, value: string): boolean {
return getByTestId(`pollOption-${value}`).className.includes("mx_MPollBody_option_checked");
return getByTestId(`pollOption-${value}`).className.includes(CHECKED);
}
function endedVoteDiv({ getByTestId }: RenderResult, value: string): Element {

View file

@ -22,65 +22,65 @@ exports[`<MPollEndBody /> when poll start event exists in current timeline rende
class="mx_MPollBody_allOptions"
>
<div
class="mx_MPollBody_option mx_MPollBody_option_ended"
class="mx_PollOption mx_PollOption_ended"
data-testid="pollOption-socks"
>
<div
class="mx_MPollBody_endedOption"
class="mx_PollOption_endedOption"
data-value="socks"
>
<div
class="mx_MPollBody_optionDescription"
class="mx_PollOption_content"
>
<div
class="mx_MPollBody_optionText"
class="mx_PollOption_optionText"
>
Socks
</div>
<div
class="mx_MPollBody_optionVoteCount"
class="mx_PollOption_optionVoteCount"
>
0 votes
</div>
</div>
</div>
<div
class="mx_MPollBody_popularityBackground"
class="mx_PollOption_popularityBackground"
>
<div
class="mx_MPollBody_popularityAmount"
class="mx_PollOption_popularityAmount"
style="width: 0%;"
/>
</div>
</div>
<div
class="mx_MPollBody_option mx_MPollBody_option_ended"
class="mx_PollOption mx_PollOption_ended"
data-testid="pollOption-shoes"
>
<div
class="mx_MPollBody_endedOption"
class="mx_PollOption_endedOption"
data-value="shoes"
>
<div
class="mx_MPollBody_optionDescription"
class="mx_PollOption_content"
>
<div
class="mx_MPollBody_optionText"
class="mx_PollOption_optionText"
>
Shoes
</div>
<div
class="mx_MPollBody_optionVoteCount"
class="mx_PollOption_optionVoteCount"
>
0 votes
</div>
</div>
</div>
<div
class="mx_MPollBody_popularityBackground"
class="mx_PollOption_popularityBackground"
>
<div
class="mx_MPollBody_popularityAmount"
class="mx_PollOption_popularityAmount"
style="width: 0%;"
/>
</div>

View file

@ -287,8 +287,8 @@ describe("<PinnedMessagesCard />", () => {
const pinTile = pins.find(MPollBody);
expect(pinTile.length).toEqual(1);
expect(pinTile.find(".mx_MPollBody_option_ended").length).toEqual(2);
expect(pinTile.find(".mx_MPollBody_optionVoteCount").first().text()).toEqual("2 votes");
expect(pinTile.find(".mx_MPollBody_optionVoteCount").last().text()).toEqual("1 vote");
expect(pinTile.find(".mx_PollOption_ended").length).toEqual(2);
expect(pinTile.find(".mx_PollOption_optionVoteCount").first().text()).toEqual("2 votes");
expect(pinTile.find(".mx_PollOption_optionVoteCount").last().text()).toEqual("1 vote");
});
});

View file

@ -26,6 +26,9 @@ mockPlatformPeg();
const MS_DAY = 86400000;
describe("<FilteredDeviceList />", () => {
// 14.03.2022 16:15
const now = 1647270879403;
jest.spyOn(global.Date, "now").mockReturnValue(now);
const newDevice = {
device_id: "new",
last_seen_ts: Date.now() - 500,
@ -81,6 +84,10 @@ describe("<FilteredDeviceList />", () => {
const getComponent = (props = {}) => <FilteredDeviceList {...defaultProps} {...props} />;
afterAll(() => {
jest.spyOn(global.Date, "now").mockRestore();
});
it("renders devices in correct order", () => {
const { container } = render(getComponent());
const tiles = container.querySelectorAll(".mx_DeviceTile");