diff --git a/src/routes/_components/status/StatusPoll.html b/src/routes/_components/status/StatusPoll.html index 1bfa0d83..4ab0943d 100644 --- a/src/routes/_components/status/StatusPoll.html +++ b/src/routes/_components/status/StatusPoll.html @@ -4,7 +4,7 @@ {#each options as option}
  • - {option.share}% {option.title} + {option.share}% {@html option.title}
    {option.title} + {@html option.title}
  • {/each} @@ -245,6 +245,8 @@ import { registerClickDelegate } from '../../_utils/delegate' import { classname } from '../../_utils/classname' import { getPoll, voteOnPoll } from '../../_actions/polls' + import escapeHtml from 'escape-html' + import { emojifyText } from '../../_utils/emojifyText' const REFRESH_MIN_DELAY = 1000 @@ -284,10 +286,12 @@ computed: { pollId: ({ originalStatus }) => originalStatus.poll.id, poll: ({ originalStatus, $polls, pollId }) => $polls[pollId] || originalStatus.poll, - options: ({ poll }) => poll.options.map(({ title, votes_count: votesCount }) => ({ - title, - share: poll.votes_count ? Math.round(votesCount / poll.votes_count * 100) : 0 - })), + options: ({ poll, originalStatusEmojis, $autoplayGifs }) => ( + poll.options.map(({ title, votes_count: votesCount }) => ({ + title: emojifyText(escapeHtml(title), originalStatusEmojis, $autoplayGifs), + share: poll.votes_count ? Math.round(votesCount / poll.votes_count * 100) : 0 + })) + ), votesCount: ({ poll }) => poll.votes_count, voted: ({ poll }) => poll.voted, multiple: ({ poll }) => poll.multiple, diff --git a/tests/spec/127-compose-polls.js b/tests/spec/127-compose-polls.js index 92d80b69..57b9d45b 100644 --- a/tests/spec/127-compose-polls.js +++ b/tests/spec/127-compose-polls.js @@ -7,7 +7,13 @@ import { getComposePollNthInput, composePoll, composePollMultipleChoice, - composePollExpiry, composePollAddButton, getComposePollRemoveNthButton, postStatusButton, composeInput, sleep + composePollExpiry, + composePollAddButton, + getComposePollRemoveNthButton, + postStatusButton, + composeInput, + sleep, + getNthStatus } from '../utils' import { loginAsFoobar } from '../roles' import { POLL_EXPIRY_DEFAULT } from '../../src/routes/_static/polls' @@ -18,6 +24,7 @@ fixture`127-compose-polls.js` test('Can add and remove poll', async t => { await loginAsFoobar(t) await t + .expect(getNthStatus(1).exists).ok() .expect(composePoll.exists).notOk() .expect(pollButton.getAttribute('aria-label')).eql('Add poll') .click(pollButton) @@ -36,6 +43,7 @@ test('Can add and remove poll', async t => { test('Can add and remove poll options', async t => { await loginAsFoobar(t) await t + .expect(getNthStatus(1).exists).ok() .expect(composePoll.exists).notOk() .expect(pollButton.getAttribute('aria-label')).eql('Add poll') .click(pollButton) @@ -73,3 +81,22 @@ test('Can add and remove poll options', async t => { .expect(getNthStatusPollResult(1, 4).exists).notOk() .expect(getNthStatusPollVoteCount(1).innerText).eql('0 votes') }) + +test('Properly escapes HTML and emojos in polls', async t => { + await loginAsFoobar(t) + await t + .expect(getNthStatus(1).exists).ok() + .click(pollButton) + .expect(composePoll.exists).ok() + await sleep(1000) + await t + .typeText(composeInput, 'vote vote vote', { paste: true }) + .typeText(getComposePollNthInput(1), '–', { paste: true }) + .typeText(getComposePollNthInput(2), ':blobpeek:', { paste: true }) + await sleep(1000) + await t + .click(postStatusButton) + .expect(getNthStatusPollResult(1, 1).innerText).contains('–') + .expect(getNthStatusPollResult(1, 2).find('img').exists).ok() + .expect(getNthStatusPollResult(1, 2).find('img').getAttribute('alt')).eql(':blobpeek:') +})