Support "closed" polls whose votes are not visible until they are ended (#7842)

This commit is contained in:
Andy Balaam 2022-02-21 10:21:35 +00:00 committed by GitHub
parent eca64d776a
commit f1e1b7be86
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 248 additions and 11 deletions

View file

@ -23,6 +23,7 @@ import { RelatedRelations } from "matrix-js-sdk/src/models/related-relations";
import {
M_POLL_END,
M_POLL_KIND_DISCLOSED,
M_POLL_KIND_UNDISCLOSED,
M_POLL_RESPONSE,
M_POLL_START,
M_POLL_START_EVENT_CONTENT,
@ -474,6 +475,60 @@ describe("MPollBody", () => {
).toBe(20);
});
it("hides scores if I voted but the poll is undisclosed", () => {
const votes = [
responseEvent("@me:example.com", "pizza"),
responseEvent("@alice:example.com", "pizza"),
responseEvent("@bellc:example.com", "pizza"),
responseEvent("@catrd:example.com", "poutine"),
responseEvent("@dune2:example.com", "wings"),
];
const body = newMPollBody(votes, [], null, false);
expect(votesCount(body, "pizza")).toBe("");
expect(votesCount(body, "poutine")).toBe("");
expect(votesCount(body, "italian")).toBe("");
expect(votesCount(body, "wings")).toBe("");
expect(body.find(".mx_MPollBody_totalVotes").text()).toBe(
"Results will be visible when the poll is ended");
});
it("highlights my vote if the poll is undisclosed", () => {
const votes = [
responseEvent("@me:example.com", "pizza"),
responseEvent("@alice:example.com", "poutine"),
responseEvent("@bellc:example.com", "poutine"),
responseEvent("@catrd:example.com", "poutine"),
responseEvent("@dune2:example.com", "wings"),
];
const body = newMPollBody(votes, [], null, false);
// My vote is marked
expect(body.find('input[value="pizza"]').prop("checked")).toBeTruthy();
// Sanity: other items are not checked
expect(body.find('input[value="poutine"]').prop("checked")).toBeFalsy();
});
it("shows scores if the poll is undisclosed but ended", () => {
const votes = [
responseEvent("@me:example.com", "pizza"),
responseEvent("@alice:example.com", "pizza"),
responseEvent("@bellc:example.com", "pizza"),
responseEvent("@catrd:example.com", "poutine"),
responseEvent("@dune2:example.com", "wings"),
];
const ends = [
endEvent("@me:example.com", 12),
];
const body = newMPollBody(votes, ends, null, false);
expect(endedVotesCount(body, "pizza")).toBe("3 votes");
expect(endedVotesCount(body, "poutine")).toBe("1 vote");
expect(endedVotesCount(body, "italian")).toBe("0 votes");
expect(endedVotesCount(body, "wings")).toBe("1 vote");
expect(body.find(".mx_MPollBody_totalVotes").text()).toBe(
"Final result based on 5 votes");
});
it("sends a vote event when I choose an option", () => {
const receivedEvents = [];
MatrixClientPeg.matrixClient.sendEvent = (
@ -993,6 +1048,34 @@ describe("MPollBody", () => {
const body = newMPollBody(votes, ends);
expect(body).toMatchSnapshot();
});
it("renders an undisclosed, unfinished poll", () => {
const votes = [
responseEvent("@ed:example.com", "pizza", 12),
responseEvent("@rf:example.com", "pizza", 12),
responseEvent("@th:example.com", "wings", 13),
responseEvent("@yh:example.com", "wings", 14),
responseEvent("@th:example.com", "poutine", 13),
responseEvent("@yh:example.com", "poutine", 14),
];
const ends = [];
const body = newMPollBody(votes, ends, null, false);
expect(body.html()).toMatchSnapshot();
});
it("renders an undisclosed, finished poll", () => {
const votes = [
responseEvent("@ed:example.com", "pizza", 12),
responseEvent("@rf:example.com", "pizza", 12),
responseEvent("@th:example.com", "wings", 13),
responseEvent("@yh:example.com", "wings", 14),
responseEvent("@th:example.com", "poutine", 13),
responseEvent("@yh:example.com", "poutine", 14),
];
const ends = [endEvent("@me:example.com", 25)];
const body = newMPollBody(votes, ends, null, false);
expect(body.html()).toMatchSnapshot();
});
});
function newVoteRelations(relationEvents: Array<MatrixEvent>): Relations {
@ -1018,12 +1101,13 @@ function newMPollBody(
relationEvents: Array<MatrixEvent>,
endEvents: Array<MatrixEvent> = [],
answers?: POLL_ANSWER[],
disclosed = true,
): ReactWrapper {
const mxEvent = new MatrixEvent({
"type": M_POLL_START.name,
"event_id": "$mypoll",
"room_id": "#myroom:example.com",
"content": newPollStart(answers),
"content": newPollStart(answers, null, disclosed),
});
return newMPollBodyFromEvent(mxEvent, relationEvents, endEvents);
}
@ -1096,6 +1180,7 @@ function endedVotesCount(wrapper: ReactWrapper, value: string): string {
function newPollStart(
answers?: POLL_ANSWER[],
question?: string,
disclosed = true,
): M_POLL_START_EVENT_CONTENT {
if (!answers) {
answers = [
@ -1121,7 +1206,11 @@ function newPollStart(
"question": {
[M_TEXT.name]: question,
},
"kind": M_POLL_KIND_DISCLOSED.name,
"kind": (
disclosed
? M_POLL_KIND_DISCLOSED.name
: M_POLL_KIND_UNDISCLOSED.name
),
"answers": answers,
},
[M_TEXT.name]: fallback,

View file

@ -2872,3 +2872,7 @@ exports[`MPollBody renders a poll with only non-local votes 1`] = `
</MPollBody>
</Wrapper>
`;
exports[`MPollBody renders an undisclosed, finished poll 1`] = `"<div class=\\"mx_MPollBody\\"><h2>What should we order for the party?</h2><div class=\\"mx_MPollBody_allOptions\\"><div class=\\"mx_MPollBody_option mx_MPollBody_option_checked mx_MPollBody_option_ended\\"><div class=\\"mx_MPollBody_endedOption mx_MPollBody_endedOptionWinner\\" data-value=\\"pizza\\"><div class=\\"mx_MPollBody_optionDescription\\"><div class=\\"mx_MPollBody_optionText\\">Pizza</div><div class=\\"mx_MPollBody_optionVoteCount\\">2 votes</div></div></div><div class=\\"mx_MPollBody_popularityBackground\\"><div class=\\"mx_MPollBody_popularityAmount\\" style=\\"width: 50%;\\"></div></div></div><div class=\\"mx_MPollBody_option mx_MPollBody_option_ended\\"><div class=\\"mx_MPollBody_endedOption\\" data-value=\\"poutine\\"><div class=\\"mx_MPollBody_optionDescription\\"><div class=\\"mx_MPollBody_optionText\\">Poutine</div><div class=\\"mx_MPollBody_optionVoteCount\\">0 votes</div></div></div><div class=\\"mx_MPollBody_popularityBackground\\"><div class=\\"mx_MPollBody_popularityAmount\\" style=\\"width: 0%;\\"></div></div></div><div class=\\"mx_MPollBody_option mx_MPollBody_option_ended\\"><div class=\\"mx_MPollBody_endedOption\\" data-value=\\"italian\\"><div class=\\"mx_MPollBody_optionDescription\\"><div class=\\"mx_MPollBody_optionText\\">Italian</div><div class=\\"mx_MPollBody_optionVoteCount\\">0 votes</div></div></div><div class=\\"mx_MPollBody_popularityBackground\\"><div class=\\"mx_MPollBody_popularityAmount\\" style=\\"width: 0%;\\"></div></div></div><div class=\\"mx_MPollBody_option mx_MPollBody_option_checked mx_MPollBody_option_ended\\"><div class=\\"mx_MPollBody_endedOption mx_MPollBody_endedOptionWinner\\" data-value=\\"wings\\"><div class=\\"mx_MPollBody_optionDescription\\"><div class=\\"mx_MPollBody_optionText\\">Wings</div><div class=\\"mx_MPollBody_optionVoteCount\\">2 votes</div></div></div><div class=\\"mx_MPollBody_popularityBackground\\"><div class=\\"mx_MPollBody_popularityAmount\\" style=\\"width: 50%;\\"></div></div></div></div><div class=\\"mx_MPollBody_totalVotes\\">Final result based on 4 votes</div></div>"`;
exports[`MPollBody renders an undisclosed, unfinished poll 1`] = `"<div class=\\"mx_MPollBody\\"><h2>What should we order for the party?</h2><div class=\\"mx_MPollBody_allOptions\\"><div class=\\"mx_MPollBody_option\\"><label class=\\"mx_StyledRadioButton mx_MPollBody_live-option mx_StyledRadioButton_enabled\\"><input type=\\"radio\\" name=\\"poll_answer_select-$mypoll\\" value=\\"pizza\\"><div><div></div></div><div class=\\"mx_StyledRadioButton_content\\"><div class=\\"mx_MPollBody_optionDescription\\"><div class=\\"mx_MPollBody_optionText\\">Pizza</div><div class=\\"mx_MPollBody_optionVoteCount\\"></div></div></div><div class=\\"mx_StyledRadioButton_spacer\\"></div></label><div class=\\"mx_MPollBody_popularityBackground\\"><div class=\\"mx_MPollBody_popularityAmount\\" style=\\"width: 0%;\\"></div></div></div><div class=\\"mx_MPollBody_option\\"><label class=\\"mx_StyledRadioButton mx_MPollBody_live-option mx_StyledRadioButton_enabled\\"><input type=\\"radio\\" name=\\"poll_answer_select-$mypoll\\" value=\\"poutine\\"><div><div></div></div><div class=\\"mx_StyledRadioButton_content\\"><div class=\\"mx_MPollBody_optionDescription\\"><div class=\\"mx_MPollBody_optionText\\">Poutine</div><div class=\\"mx_MPollBody_optionVoteCount\\"></div></div></div><div class=\\"mx_StyledRadioButton_spacer\\"></div></label><div class=\\"mx_MPollBody_popularityBackground\\"><div class=\\"mx_MPollBody_popularityAmount\\" style=\\"width: 0%;\\"></div></div></div><div class=\\"mx_MPollBody_option\\"><label class=\\"mx_StyledRadioButton mx_MPollBody_live-option mx_StyledRadioButton_enabled\\"><input type=\\"radio\\" name=\\"poll_answer_select-$mypoll\\" value=\\"italian\\"><div><div></div></div><div class=\\"mx_StyledRadioButton_content\\"><div class=\\"mx_MPollBody_optionDescription\\"><div class=\\"mx_MPollBody_optionText\\">Italian</div><div class=\\"mx_MPollBody_optionVoteCount\\"></div></div></div><div class=\\"mx_StyledRadioButton_spacer\\"></div></label><div class=\\"mx_MPollBody_popularityBackground\\"><div class=\\"mx_MPollBody_popularityAmount\\" style=\\"width: 0%;\\"></div></div></div><div class=\\"mx_MPollBody_option\\"><label class=\\"mx_StyledRadioButton mx_MPollBody_live-option mx_StyledRadioButton_enabled\\"><input type=\\"radio\\" name=\\"poll_answer_select-$mypoll\\" value=\\"wings\\"><div><div></div></div><div class=\\"mx_StyledRadioButton_content\\"><div class=\\"mx_MPollBody_optionDescription\\"><div class=\\"mx_MPollBody_optionText\\">Wings</div><div class=\\"mx_MPollBody_optionVoteCount\\"></div></div></div><div class=\\"mx_StyledRadioButton_spacer\\"></div></label><div class=\\"mx_MPollBody_popularityBackground\\"><div class=\\"mx_MPollBody_popularityAmount\\" style=\\"width: 0%;\\"></div></div></div></div><div class=\\"mx_MPollBody_totalVotes\\">Results will be visible when the poll is ended</div></div>"`;