# frozen_string_literal: true require "rails_helper" RSpec.describe ::DiscoursePoll::PollsController do routes { ::DiscoursePoll::Engine.routes } let!(:user) { log_in } let(:topic) { Fabricate(:topic) } let(:poll) { Fabricate(:post, topic: topic, user: user, raw: "[poll]\n- A\n- B\n[/poll]") } let(:multi_poll) do Fabricate( :post, topic: topic, user: user, raw: "[poll min=1 max=2 type=multiple public=true]\n- A\n- B\n[/poll]", ) end let(:public_poll_on_vote) do Fabricate( :post, topic: topic, user: user, raw: "[poll public=true results=on_vote]\n- A\n- B\n[/poll]", ) end let(:public_poll_on_close) do Fabricate( :post, topic: topic, user: user, raw: "[poll public=true results=on_close]\n- A\n- B\n[/poll]", ) end describe "#vote" do it "works" do channel = "/polls/#{poll.topic_id}" message = MessageBus .track_publish(channel) do put :vote, params: { post_id: poll.id, poll_name: "poll", options: ["5c24fc1df56d764b550ceae1b9319125"], }, format: :json end .first expect(response.status).to eq(200) json = response.parsed_body expect(json["poll"]["name"]).to eq("poll") expect(json["poll"]["voters"]).to eq(1) expect(json["vote"]).to eq(["5c24fc1df56d764b550ceae1b9319125"]) expect(message.channel).to eq(channel) expect(message.user_ids).to eq(nil) expect(message.group_ids).to eq(nil) end it "works in PM" do user2 = Fabricate(:user) topic = Fabricate( :private_message_topic, topic_allowed_users: [ Fabricate.build(:topic_allowed_user, user: user), Fabricate.build(:topic_allowed_user, user: user2), ], ) poll = Fabricate(:post, topic: topic, user: user, raw: "[poll]\n- A\n- B\n[/poll]") channel = "/polls/#{poll.topic_id}" message = MessageBus .track_publish(channel) do put :vote, params: { post_id: poll.id, poll_name: "poll", options: ["5c24fc1df56d764b550ceae1b9319125"], }, format: :json end .first expect(response.status).to eq(200) json = response.parsed_body expect(json["poll"]["name"]).to eq("poll") expect(json["poll"]["voters"]).to eq(1) expect(json["vote"]).to eq(["5c24fc1df56d764b550ceae1b9319125"]) expect(message.channel).to eq(channel) expect(message.user_ids).to contain_exactly(user.id, user2.id) expect(message.group_ids).to eq(nil) end it "works in secure categories" do group = Fabricate(:group) group.add_owner(user) category = Fabricate(:private_category, group: group) topic = Fabricate(:topic, category: category) poll = Fabricate(:post, topic: topic, user: user, raw: "[poll]\n- A\n- B\n[/poll]") channel = "/polls/#{poll.topic_id}" message = MessageBus .track_publish(channel) do put :vote, params: { post_id: poll.id, poll_name: "poll", options: ["5c24fc1df56d764b550ceae1b9319125"], }, format: :json end .first expect(response.status).to eq(200) json = response.parsed_body expect(json["poll"]["name"]).to eq("poll") expect(json["poll"]["voters"]).to eq(1) expect(json["vote"]).to eq(["5c24fc1df56d764b550ceae1b9319125"]) expect(message.channel).to eq(channel) expect(message.user_ids).to eq(nil) expect(message.group_ids).to contain_exactly(group.id) end it "requires at least 1 valid option" do put :vote, params: { post_id: poll.id, poll_name: "poll", options: %w[A B] }, format: :json expect(response.status).not_to eq(200) json = response.parsed_body expect(json["errors"][0]).to eq(I18n.t("poll.requires_at_least_1_valid_option")) end it "supports vote changes" do put :vote, params: { post_id: poll.id, poll_name: "poll", options: ["5c24fc1df56d764b550ceae1b9319125"], }, format: :json expect(response.status).to eq(200) put :vote, params: { post_id: poll.id, poll_name: "poll", options: ["e89dec30bbd9bf50fabf6a05b4324edf"], }, format: :json expect(response.status).to eq(200) json = response.parsed_body expect(json["poll"]["voters"]).to eq(1) expect(json["poll"]["options"][0]["votes"]).to eq(0) expect(json["poll"]["options"][1]["votes"]).to eq(1) end it "supports removing votes" do put :vote, params: { post_id: poll.id, poll_name: "poll", options: ["5c24fc1df56d764b550ceae1b9319125"], }, format: :json expect(response.status).to eq(200) delete :remove_vote, params: { post_id: poll.id, poll_name: "poll" }, format: :json expect(response.status).to eq(200) json = response.parsed_body expect(json["poll"]["voters"]).to eq(0) expect(json["poll"]["options"][0]["votes"]).to eq(0) expect(json["poll"]["options"][1]["votes"]).to eq(0) end it "works on closed topics" do topic.update_attribute(:closed, true) put :vote, params: { post_id: poll.id, poll_name: "poll", options: ["5c24fc1df56d764b550ceae1b9319125"], }, format: :json expect(response.status).to eq(200) end it "ensures topic is not archived" do topic.update_attribute(:archived, true) put :vote, params: { post_id: poll.id, poll_name: "poll", options: ["A"] }, format: :json expect(response.status).not_to eq(200) json = response.parsed_body expect(json["errors"][0]).to eq(I18n.t("poll.topic_must_be_open_to_vote")) end it "ensures post is not trashed" do poll.trash! put :vote, params: { post_id: poll.id, poll_name: "poll", options: ["A"] }, format: :json expect(response.status).not_to eq(200) json = response.parsed_body expect(json["errors"][0]).to eq(I18n.t("poll.post_is_deleted")) end it "ensures user can post in topic" do Guardian.any_instance.expects(:can_create_post?).returns(false) put :vote, params: { post_id: poll.id, poll_name: "poll", options: ["A"] }, format: :json expect(response.status).not_to eq(200) json = response.parsed_body expect(json["errors"][0]).to eq(I18n.t("poll.user_cant_post_in_topic")) end it "checks the name of the poll" do put :vote, params: { post_id: poll.id, poll_name: "foobar", options: ["A"] }, format: :json expect(response.status).not_to eq(200) json = response.parsed_body expect(json["errors"][0]).to eq(I18n.t("poll.no_poll_with_this_name", name: "foobar")) end it "ensures poll is open" do closed_poll = create_post(raw: "[poll status=closed]\n- A\n- B\n[/poll]") put :vote, params: { post_id: closed_poll.id, poll_name: "poll", options: ["5c24fc1df56d764b550ceae1b9319125"], }, format: :json expect(response.status).not_to eq(200) json = response.parsed_body expect(json["errors"][0]).to eq(I18n.t("poll.poll_must_be_open_to_vote")) end it "ensures user has required trust level" do poll = create_post(raw: "[poll groups=#{Fabricate(:group).name}]\n- A\n- B\n[/poll]") put :vote, params: { post_id: poll.id, poll_name: "poll", options: ["5c24fc1df56d764b550ceae1b9319125"], }, format: :json expect(response.status).not_to eq(200) json = response.parsed_body expect(json["errors"][0]).to eq( I18n.t("js.poll.results.groups.title", groups: poll.polls.first.groups), ) end it "doesn't discard anonymous votes when someone votes" do the_poll = poll.polls.first the_poll.update_attribute(:anonymous_voters, 17) the_poll.poll_options[0].update_attribute(:anonymous_votes, 11) the_poll.poll_options[1].update_attribute(:anonymous_votes, 6) put :vote, params: { post_id: poll.id, poll_name: "poll", options: ["5c24fc1df56d764b550ceae1b9319125"], }, format: :json expect(response.status).to eq(200) json = response.parsed_body expect(json["poll"]["voters"]).to eq(18) expect(json["poll"]["options"][0]["votes"]).to eq(12) expect(json["poll"]["options"][1]["votes"]).to eq(6) end end describe "#toggle_status" do it "works for OP" do channel = "/polls/#{poll.topic_id}" message = MessageBus .track_publish(channel) do put :toggle_status, params: { post_id: poll.id, poll_name: "poll", status: "closed", }, format: :json expect(response.status).to eq(200) end .first json = response.parsed_body expect(json["poll"]["status"]).to eq("closed") expect(message.channel).to eq(channel) end it "works for staff" do log_in(:moderator) channel = "/polls/#{poll.topic_id}" message = MessageBus .track_publish(channel) do put :toggle_status, params: { post_id: poll.id, poll_name: "poll", status: "closed", }, format: :json expect(response.status).to eq(200) end .first json = response.parsed_body expect(json["poll"]["status"]).to eq("closed") expect(message.channel).to eq(channel) end it "ensures post is not trashed" do poll.trash! put :toggle_status, params: { post_id: poll.id, poll_name: "poll", status: "closed", }, format: :json expect(response.status).not_to eq(200) json = response.parsed_body expect(json["errors"][0]).to eq(I18n.t("poll.post_is_deleted")) end end describe "#voters" do let(:first) { "5c24fc1df56d764b550ceae1b9319125" } let(:second) { "e89dec30bbd9bf50fabf6a05b4324edf" } it "correctly handles offset" do user1 = log_in put :vote, params: { post_id: multi_poll.id, poll_name: "poll", options: [first], }, format: :json expect(response.status).to eq(200) user2 = log_in put :vote, params: { post_id: multi_poll.id, poll_name: "poll", options: [first], }, format: :json expect(response.status).to eq(200) user3 = log_in put :vote, params: { post_id: multi_poll.id, poll_name: "poll", options: [first, second], }, format: :json expect(response.status).to eq(200) get :voters, params: { poll_name: "poll", post_id: multi_poll.id, limit: 2 }, format: :json expect(response.status).to eq(200) json = response.parsed_body # no user3 cause voter_limit is 2 expect(json["voters"][first].map { |h| h["id"] }).to contain_exactly(user1.id, user2.id) expect(json["voters"][second].map { |h| h["id"] }).to contain_exactly(user3.id) end it "ensures voters can only be seen after casting a vote" do put :vote, params: { post_id: public_poll_on_vote.id, poll_name: "poll", options: [first], }, format: :json expect(response.status).to eq(200) get :voters, params: { poll_name: "poll", post_id: public_poll_on_vote.id }, format: :json expect(response.status).to eq(200) json = response.parsed_body expect(json["voters"][first].size).to eq(1) _user2 = log_in get :voters, params: { poll_name: "poll", post_id: public_poll_on_vote.id }, format: :json expect(response.status).to eq(400) put :vote, params: { post_id: public_poll_on_vote.id, poll_name: "poll", options: [second], }, format: :json expect(response.status).to eq(200) get :voters, params: { poll_name: "poll", post_id: public_poll_on_vote.id }, format: :json expect(response.status).to eq(200) json = response.parsed_body expect(json["voters"][first].size).to eq(1) expect(json["voters"][second].size).to eq(1) end it "ensures voters can only be seen when poll is closed" do put :vote, params: { post_id: public_poll_on_close.id, poll_name: "poll", options: [first], }, format: :json expect(response.status).to eq(200) get :voters, params: { poll_name: "poll", post_id: public_poll_on_close.id }, format: :json expect(response.status).to eq(400) put :toggle_status, params: { post_id: public_poll_on_close.id, poll_name: "poll", status: "closed", }, format: :json expect(response.status).to eq(200) get :voters, params: { poll_name: "poll", post_id: public_poll_on_close.id }, format: :json expect(response.status).to eq(200) json = response.parsed_body expect(json["voters"][first].size).to eq(1) end end end