Files
Mixer/test/mixer/posts/tweet_like_test.exs
qdust41 4c67f38fa3 fix: make tweet_like tests pass
- Add authorize?: false to user_fixture so register_with_password
  bypasses policy check in test context
- Add require Ash.Query so Ash.Query.filter macro works in count_likes
- Replace nonexistent Ash.ForbiddenField.forbidden?/1 with match?/2
- Fix stale tweet struct in :like noop case by reloading from DB

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-12 19:48:23 -04:00

123 lines
3.5 KiB
Elixir

defmodule Mixer.Posts.TweetLikeTest do
use Mixer.DataCase, async: true
import Ash.Expr
require Ash.Query
alias Mixer.Accounts.User
alias Mixer.Posts.Tweet
alias Mixer.Posts.TweetLike
describe "tweet likes" do
test "a user can like a tweet once and liked_by_me reflects the actor" do
user = user_fixture("liker@example.com")
tweet = tweet_fixture(user, "first post")
assert {:ok, liked_tweet} =
tweet
|> Ash.Changeset.for_update(:like, %{}, actor: user)
|> Ash.update()
assert liked_tweet.likes == 1
assert count_likes(tweet.id) == 1
tweet_for_actor =
Tweet
|> Ash.get!(tweet.id, actor: user, load: [:liked_by_me], authorize?: false)
refute match?(%Ash.ForbiddenField{}, tweet_for_actor.liked_by_me)
assert tweet_for_actor.liked_by_me
tweet_without_actor =
Tweet
|> Ash.get!(tweet.id, load: [:liked_by_me], authorize?: false)
refute match?(%Ash.ForbiddenField{}, tweet_without_actor.liked_by_me)
refute tweet_without_actor.liked_by_me
end
test "liking the same tweet twice does not create duplicate rows or inflate the counter" do
user = user_fixture("duplicate@example.com")
tweet = tweet_fixture(user, "duplicate like test")
assert {:ok, _tweet} =
tweet
|> Ash.Changeset.for_update(:like, %{}, actor: user)
|> Ash.update()
assert {:ok, liked_again} =
tweet
|> Ash.Changeset.for_update(:like, %{}, actor: user)
|> Ash.update()
assert liked_again.likes == 1
assert count_likes(tweet.id) == 1
end
test "unliking removes the relation and decrements the counter without going negative" do
user = user_fixture("unlike@example.com")
tweet = tweet_fixture(user, "unlike test")
tweet
|> Ash.Changeset.for_update(:like, %{}, actor: user)
|> Ash.update!()
assert {:ok, unliked_tweet} =
tweet
|> Ash.Changeset.for_update(:unlike, %{}, actor: user)
|> Ash.update()
assert unliked_tweet.likes == 0
assert count_likes(tweet.id) == 0
assert {:ok, still_unliked} =
tweet
|> Ash.Changeset.for_update(:unlike, %{}, actor: user)
|> Ash.update()
assert still_unliked.likes == 0
assert count_likes(tweet.id) == 0
end
test "guests cannot like tweets" do
owner = user_fixture("owner@example.com")
tweet = tweet_fixture(owner, "guest like test")
assert {:error, error} =
tweet
|> Ash.Changeset.for_update(:like, %{})
|> Ash.update()
assert Exception.message(error) =~ "forbidden"
assert count_likes(tweet.id) == 0
end
end
defp user_fixture(email) do
username =
email |> String.split("@") |> List.first() |> String.replace(~r/[^a-zA-Z0-9_]/, "_")
User
|> Ash.Changeset.for_create(:register_with_password, %{
email: email,
password: "password1234",
password_confirmation: "password1234",
username: username
})
|> Ash.create!(authorize?: false)
end
defp tweet_fixture(user, content) do
Tweet
|> Ash.Changeset.for_create(:create, %{content: content}, actor: user)
|> Ash.create!()
end
defp count_likes(tweet_id) do
TweetLike
|> Ash.Query.filter(expr(tweet_id == ^tweet_id))
|> Ash.read!(authorize?: false)
|> length()
end
end