# 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.id, "poll", ["e55de753c08b93d04d677ce05e942d3c"], post.user) DiscoursePoll::Poll.toggle_status(post.id, "poll", "closed", post.user) 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(post.id, "poll", [polls["poll"]["options"][0]["id"]], user) }.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