discourse/plugins/poll/spec/lib/polls_updater_spec.rb
Bianca Nenciu 6a143030f8
FEATURE: Allow users to remove their vote (#14459)
They can use the remove vote button or select the same option again for
single choice polls.

This commit refactor the plugin to properly organize code and make it
easier to follow.
2021-10-05 11:38:49 +03:00

223 lines
5.3 KiB
Ruby

# frozen_string_literal: true
require 'rails_helper'
describe DiscoursePoll::PollsUpdater do
def update(post, polls)
DiscoursePoll::PollsUpdater.update(post, polls)
end
let(:user) { Fabricate(:user) }
let(:post) {
Fabricate(:post, raw: <<~RAW)
[poll]
* 1
* 2
[/poll]
RAW
}
let(:post_with_3_options) {
Fabricate(:post, raw: <<~RAW)
[poll]
- a
- b
- c
[/poll]
RAW
}
let(:post_with_some_attributes) {
Fabricate(:post, raw: <<~RAW)
[poll close=#{1.week.from_now.to_formatted_s(:iso8601)} results=on_close]
- A
- B
- C
[/poll]
RAW
}
let(:polls) {
DiscoursePoll::PollsValidator.new(post).validate_polls
}
let(:polls_with_3_options) {
DiscoursePoll::PollsValidator.new(post_with_3_options).validate_polls
}
let(:polls_with_some_attributes) {
DiscoursePoll::PollsValidator.new(post_with_some_attributes).validate_polls
}
describe "update" do
it "does nothing when there are no changes" do
message = MessageBus.track_publish("/polls/#{post.topic_id}") do
update(post, polls)
end.first
expect(message).to be(nil)
end
describe "when editing" do
let(:raw) do
<<~RAW
This is a new poll with three options.
[poll type=multiple results=always min=1 max=2]
* first
* second
* third
[/poll]
RAW
end
let(:post) { Fabricate(:post, raw: raw) }
it "works if poll is closed and unmodified" do
DiscoursePoll::Poll.vote(post.user, post.id, "poll", ["e55de753c08b93d04d677ce05e942d3c"])
DiscoursePoll::Poll.toggle_status(post.user, post.id, "poll", "closed")
freeze_time (SiteSetting.poll_edit_window_mins + 1).minutes.from_now
update(post, DiscoursePoll::PollsValidator.new(post).validate_polls)
expect(post.errors[:base].size).to equal(0)
end
end
describe "deletes polls" do
it "that were removed" do
update(post, {})
post.reload
expect(Poll.where(post: post).exists?).to eq(false)
expect(post.custom_fields[DiscoursePoll::HAS_POLLS]).to eq(nil)
end
end
describe "creates polls" do
it "that were added" do
post = Fabricate(:post)
expect(Poll.find_by(post: post)).to_not be
message = MessageBus.track_publish("/polls/#{post.topic_id}") do
update(post, polls)
end.first
poll = Poll.find_by(post: post)
expect(poll).to be
expect(poll.poll_options.size).to eq(2)
expect(poll.post.custom_fields[DiscoursePoll::HAS_POLLS]).to eq(true)
expect(message.data[:post_id]).to eq(post.id)
expect(message.data[:polls][0][:name]).to eq(poll.name)
end
end
describe "updates polls" do
describe "when there are no votes" do
it "at any time" do
post # create the post
freeze_time 1.month.from_now
message = MessageBus.track_publish("/polls/#{post.topic_id}") do
update(post, polls_with_some_attributes)
end.first
poll = Poll.find_by(post: post)
expect(poll).to be
expect(poll.poll_options.size).to eq(3)
expect(poll.poll_votes.size).to eq(0)
expect(poll.on_close?).to eq(true)
expect(poll.close_at).to be
expect(poll.post.custom_fields[DiscoursePoll::HAS_POLLS]).to eq(true)
expect(message.data[:post_id]).to eq(post.id)
expect(message.data[:polls][0][:name]).to eq(poll.name)
end
end
describe "when there are votes" do
before do
expect {
DiscoursePoll::Poll.vote(user, post.id, "poll", [polls["poll"]["options"][0]["id"]])
}.to change { PollVote.count }.by(1)
end
describe "inside the edit window" do
it "and deletes the votes" do
message = MessageBus.track_publish("/polls/#{post.topic_id}") do
update(post, polls_with_some_attributes)
end.first
poll = Poll.find_by(post: post)
expect(poll).to be
expect(poll.poll_options.size).to eq(3)
expect(poll.poll_votes.size).to eq(0)
expect(poll.on_close?).to eq(true)
expect(poll.close_at).to be
expect(poll.post.custom_fields[DiscoursePoll::HAS_POLLS]).to eq(true)
expect(message.data[:post_id]).to eq(post.id)
expect(message.data[:polls][0][:name]).to eq(poll.name)
end
end
describe "outside the edit window" do
it "throws an error" do
edit_window = SiteSetting.poll_edit_window_mins
freeze_time (edit_window + 1).minutes.from_now
update(post, polls_with_some_attributes)
poll = Poll.find_by(post: post)
expect(poll).to be
expect(poll.poll_options.size).to eq(2)
expect(poll.poll_votes.size).to eq(1)
expect(poll.on_close?).to eq(false)
expect(poll.close_at).to_not be
expect(post.errors[:base]).to include(
I18n.t(
"poll.edit_window_expired.cannot_edit_default_poll_with_votes",
minutes: edit_window
)
)
end
end
end
end
end
end