posts: allow toggling between upvotes and downvotes.
Like 9efb374ae, allow users to toggle between upvoting and downvoting a
post without raising an error or having to manually remove the vote
first. If you upvote a post, then downvote it, the upvote is
automatically removed and replaced by the downvote.
Other changes:
* Tagging a post with `upvote:self` or `downvote:self` is now silently
ignored when the user doesn't have permission to vote, instead of
raising an error.
* Undoing a vote that doesn't exist now does nothing instead of
returning an error. This can happen if you open the same post in two
tabs, undo the vote in tab 1, then try to undo the vote again in tab 2.
Changes to the /post_votes API:
* `POST /post_votes` and `DELETE /post_votes` now return a post vote
instead of a post.
* The `score` param in `POST /post_votes` is now 1 or -1, not `up` or
`down`.
This commit is contained in:
@@ -1162,19 +1162,19 @@ class PostTest < ActiveSupport::TestCase
|
||||
context "upvote:self or downvote:self" do
|
||||
context "by a member" do
|
||||
should "not upvote the post" do
|
||||
assert_raises PostVote::Error do
|
||||
@post.update(:tag_string => "upvote:self")
|
||||
assert_no_difference("PostVote.count") do
|
||||
@post.update(tag_string: "upvote:self")
|
||||
end
|
||||
|
||||
assert_equal(0, @post.score)
|
||||
assert_equal(0, @post.reload.score)
|
||||
end
|
||||
|
||||
should "not downvote the post" do
|
||||
assert_raises PostVote::Error do
|
||||
@post.update(:tag_string => "downvote:self")
|
||||
assert_no_difference("PostVote.count") do
|
||||
@post.update(tag_string: "downvote:self")
|
||||
end
|
||||
|
||||
assert_equal(0, @post.score)
|
||||
assert_equal(0, @post.reload.score)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1832,50 +1832,63 @@ class PostTest < ActiveSupport::TestCase
|
||||
|
||||
context "Voting:" do
|
||||
should "not allow members to vote" do
|
||||
@user = FactoryBot.create(:user)
|
||||
@post = FactoryBot.create(:post)
|
||||
as(@user) do
|
||||
assert_raises(PostVote::Error) { @post.vote!("up") }
|
||||
end
|
||||
user = create(:user)
|
||||
post = create(:post)
|
||||
|
||||
assert_nothing_raised { post.vote!(1, user) }
|
||||
assert_equal(0, post.votes.count)
|
||||
assert_equal(0, post.reload.score)
|
||||
end
|
||||
|
||||
should "not allow duplicate votes" do
|
||||
user = FactoryBot.create(:gold_user)
|
||||
post = FactoryBot.create(:post)
|
||||
CurrentUser.scoped(user, "127.0.0.1") do
|
||||
assert_nothing_raised {post.vote!("up")}
|
||||
assert_raises(PostVote::Error) {post.vote!("up")}
|
||||
post.reload
|
||||
assert_equal(1, PostVote.count)
|
||||
assert_equal(1, post.score)
|
||||
end
|
||||
user = create(:gold_user)
|
||||
post = create(:post)
|
||||
|
||||
post.vote!(1, user)
|
||||
post.vote!(1, user)
|
||||
|
||||
assert_equal(1, post.reload.score)
|
||||
assert_equal(1, post.votes.count)
|
||||
end
|
||||
|
||||
should "allow undoing of votes" do
|
||||
user = FactoryBot.create(:gold_user)
|
||||
post = FactoryBot.create(:post)
|
||||
user = create(:gold_user)
|
||||
post = create(:post)
|
||||
|
||||
# We deliberately don't call post.reload until the end to verify that
|
||||
# post.unvote! returns the correct score even when not forcibly reloaded.
|
||||
CurrentUser.scoped(user, "127.0.0.1") do
|
||||
post.vote!("up")
|
||||
assert_equal(1, post.score)
|
||||
post.vote!(1, user)
|
||||
assert_equal(1, post.score)
|
||||
assert_equal(1, post.up_score)
|
||||
assert_equal(0, post.down_score)
|
||||
assert_equal(1, post.votes.positive.count)
|
||||
|
||||
post.unvote!
|
||||
assert_equal(0, post.score)
|
||||
post.unvote!(user)
|
||||
assert_equal(0, post.score)
|
||||
assert_equal(0, post.up_score)
|
||||
assert_equal(0, post.down_score)
|
||||
assert_equal(0, post.votes.count)
|
||||
|
||||
assert_nothing_raised {post.vote!("down")}
|
||||
assert_equal(-1, post.score)
|
||||
post.vote!(-1, user)
|
||||
assert_equal(-1, post.score)
|
||||
assert_equal(0, post.up_score)
|
||||
assert_equal(-1, post.down_score)
|
||||
assert_equal(1, post.votes.negative.count)
|
||||
|
||||
post.unvote!
|
||||
assert_equal(0, post.score)
|
||||
post.unvote!(user)
|
||||
assert_equal(0, post.score)
|
||||
assert_equal(0, post.up_score)
|
||||
assert_equal(0, post.down_score)
|
||||
assert_equal(0, post.votes.count)
|
||||
|
||||
assert_nothing_raised {post.vote!("up")}
|
||||
assert_equal(1, post.score)
|
||||
post.vote!(1, user)
|
||||
assert_equal(1, post.score)
|
||||
assert_equal(1, post.up_score)
|
||||
assert_equal(0, post.down_score)
|
||||
assert_equal(1, post.votes.positive.count)
|
||||
|
||||
post.reload
|
||||
assert_equal(1, post.score)
|
||||
end
|
||||
post.reload
|
||||
assert_equal(1, post.score)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -1,46 +1,74 @@
|
||||
require 'test_helper'
|
||||
|
||||
class PostVoteTest < ActiveSupport::TestCase
|
||||
def setup
|
||||
super
|
||||
|
||||
@user = FactoryBot.create(:user)
|
||||
CurrentUser.user = @user
|
||||
CurrentUser.ip_addr = "127.0.0.1"
|
||||
|
||||
@post = FactoryBot.create(:post)
|
||||
end
|
||||
|
||||
context "Voting for a post" do
|
||||
should "interpret up as +1 score" do
|
||||
vote = PostVote.create(:post_id => @post.id, :vote => "up")
|
||||
assert_equal(1, vote.score)
|
||||
context "A PostVote" do
|
||||
setup do
|
||||
@post = create(:post)
|
||||
end
|
||||
|
||||
should "interpret down as -1 score" do
|
||||
vote = PostVote.create(:post_id => @post.id, :vote => "down")
|
||||
assert_equal(-1, vote.score)
|
||||
context "during validation" do
|
||||
subject { build(:post_vote, post: @post) }
|
||||
|
||||
should validate_uniqueness_of(:user_id).scoped_to(:post_id).with_message("have already voted for this post")
|
||||
should validate_inclusion_of(:score).in_array([-1, 1]).with_message("must be 1 or -1")
|
||||
end
|
||||
|
||||
should "not accept any other scores" do
|
||||
vote = PostVote.create(:post_id => @post.id, :vote => "xxx")
|
||||
assert(vote.errors.any?)
|
||||
context "creating" do
|
||||
context "an upvote" do
|
||||
should "increment the post's score" do
|
||||
vote = create(:post_vote, post: @post, score: 1)
|
||||
|
||||
assert_equal(1, @post.reload.score)
|
||||
assert_equal(1, @post.up_score)
|
||||
assert_equal(0, @post.down_score)
|
||||
assert_equal(1, @post.votes.positive.count)
|
||||
end
|
||||
end
|
||||
|
||||
context "a downvote" do
|
||||
should "decrement the post's score" do
|
||||
vote = create(:post_vote, post: @post, score: -1)
|
||||
|
||||
assert_equal(-1, @post.reload.score)
|
||||
assert_equal(0, @post.up_score)
|
||||
assert_equal(-1, @post.down_score)
|
||||
assert_equal(1, @post.votes.negative.count)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
should "increase the score of the post" do
|
||||
@post.votes.create(vote: "up")
|
||||
@post.reload
|
||||
context "destroying" do
|
||||
context "an upvote" do
|
||||
should "decrement the post's score" do
|
||||
vote = create(:post_vote, post: @post, score: 1)
|
||||
assert_equal(1, @post.reload.score)
|
||||
assert_equal(1, @post.up_score)
|
||||
assert_equal(0, @post.down_score)
|
||||
assert_equal(1, @post.votes.count)
|
||||
|
||||
assert_equal(1, @post.score)
|
||||
assert_equal(1, @post.up_score)
|
||||
end
|
||||
vote.destroy
|
||||
assert_equal(0, @post.reload.score)
|
||||
assert_equal(0, @post.up_score)
|
||||
assert_equal(0, @post.down_score)
|
||||
assert_equal(0, @post.votes.count)
|
||||
end
|
||||
end
|
||||
|
||||
should "decrease the score of the post when removed" do
|
||||
@post.votes.create(vote: "up").destroy
|
||||
@post.reload
|
||||
context "a downvote" do
|
||||
should "increment the post's score" do
|
||||
vote = create(:post_vote, post: @post, score: -1)
|
||||
assert_equal(-1, @post.reload.score)
|
||||
assert_equal(0, @post.up_score)
|
||||
assert_equal(-1, @post.down_score)
|
||||
assert_equal(1, @post.votes.count)
|
||||
|
||||
assert_equal(0, @post.score)
|
||||
assert_equal(0, @post.up_score)
|
||||
vote.destroy
|
||||
assert_equal(0, @post.reload.score)
|
||||
assert_equal(0, @post.up_score)
|
||||
assert_equal(0, @post.down_score)
|
||||
assert_equal(0, @post.votes.count)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user