defmodule Mobilizon.GraphQL.Resolvers.PostTest do use Mobilizon.Web.ConnCase import Mobilizon.Factory alias Mobilizon.Actors.{Actor, Member} alias Mobilizon.Posts.Post alias Mobilizon.Users.User alias Mobilizon.GraphQL.AbsintheHelpers @post_fragment """ fragment PostFragment on Post { id title slug url body author { id preferredUsername name avatar { url } } attributedTo { id preferredUsername name avatar { url } } visibility insertedAt updatedAt draft } """ @get_group_posts """ query($name: String!, $page: Int, $limit: Int) { group(preferredUsername: $name) { id posts(page: $page, limit: $limit) { elements { id, title, }, total }, } } """ @post_query """ query Post($slug: String!) { post(slug: $slug) { ...PostFragment } } #{@post_fragment} """ @create_post """ mutation CreatePost($title: String!, $body: String!, $attributedToId: ID!, $draft: Boolean) { createPost(title: $title, body: $body, attributedToId: $attributedToId, draft: $draft) { ...PostFragment } } #{@post_fragment} """ @update_post """ mutation UpdatePost($id: ID!, $title: String, $body: String, $attributedToId: ID, $draft: Boolean) { updatePost(id: $id, title: $title, body: $body, attributedToId: $attributedToId, draft: $draft) { ...PostFragment } } #{@post_fragment} """ @delete_post """ mutation DeletePost($id: ID!) { deletePost(id: $id) { id } } """ @post_title "my post" @updated_post_title "my updated post" setup do %User{} = user = insert(:user) %Actor{} = actor = insert(:actor, user: user) %Actor{} = group = insert(:group) %Post{} = post = insert(:post, attributed_to: group, author: actor) %Post{} = post_unlisted = insert(:post, attributed_to: group, author: actor, visibility: :unlisted) %Post{} = post_draft = insert(:post, attributed_to: group, author: actor, draft: true) %Member{} = insert(:member, parent: group, actor: actor, role: :member) %Post{} = post_private = insert(:post, attributed_to: group, author: actor, visibility: :private) insert(:follower, target_actor: group, approved: true) {:ok, user: user, group: group, post: post, post_unlisted: post_unlisted, post_draft: post_draft, post_private: post_private} end describe "Resolver: Get group's posts" do test "find_posts_for_group/3", %{ conn: conn, user: user, group: group, post: post, post_unlisted: post_unlisted, post_draft: post_draft, post_private: post_private } do res = conn |> auth_conn(user) |> AbsintheHelpers.graphql_query( query: @get_group_posts, variables: %{ name: group.preferred_username } ) assert is_nil(res["errors"]) assert res["data"]["group"]["posts"]["total"] == 4 assert res["data"]["group"]["posts"]["elements"] |> Enum.map(& &1["id"]) |> MapSet.new() == MapSet.new([ post.id, post_unlisted.id, post_draft.id, post_private.id ]) end test "find_posts_for_group/3 when not member of group", %{ conn: conn, group: group, post: post } do %User{} = user = insert(:user) %Actor{} = insert(:actor, user: user) res = conn |> auth_conn(user) |> AbsintheHelpers.graphql_query( query: @get_group_posts, variables: %{ name: group.preferred_username } ) assert is_nil(res["errors"]) assert res["data"]["group"]["posts"]["total"] == 1 assert res["data"]["group"]["posts"]["elements"] |> Enum.map(& &1["id"]) == [post.id] end test "find_posts_for_group/3 when not connected", %{ conn: conn, group: group, post: post } do res = conn |> AbsintheHelpers.graphql_query( query: @get_group_posts, variables: %{ name: group.preferred_username } ) assert is_nil(res["errors"]) assert res["data"]["group"]["posts"]["total"] == 1 assert res["data"]["group"]["posts"]["elements"] |> Enum.map(& &1["id"]) == [post.id] end end describe "Resolver: Get a specific post" do test "get_post/3 for a public post", %{ conn: conn, user: user, post: post } do res = conn |> auth_conn(user) |> AbsintheHelpers.graphql_query( query: @post_query, variables: %{ slug: post.slug } ) assert is_nil(res["errors"]) assert res["data"]["post"]["title"] == post.title end test "get_post/3 for a non-existing post", %{ conn: conn, user: user } do res = conn |> auth_conn(user) |> AbsintheHelpers.graphql_query( query: @post_query, variables: %{ slug: "not existing" } ) assert hd(res["errors"])["message"] == "Post not found" end test "get_post/3 for an unlisted post", %{ conn: conn, user: user, post_unlisted: post_unlisted } do res = conn |> auth_conn(user) |> AbsintheHelpers.graphql_query( query: @post_query, variables: %{ slug: post_unlisted.slug } ) assert is_nil(res["errors"]) assert res["data"]["post"]["title"] == post_unlisted.title assert res["data"]["post"]["visibility"] == post_unlisted.visibility |> to_string() |> String.upcase() end test "get_post/3 for a private post", %{ conn: conn, user: user, post_private: post_private } do res = conn |> auth_conn(user) |> AbsintheHelpers.graphql_query( query: @post_query, variables: %{ slug: post_private.slug } ) assert is_nil(res["errors"]) assert res["data"]["post"]["title"] == post_private.title assert res["data"]["post"]["visibility"] == post_private.visibility |> to_string() |> String.upcase() end test "get_post/3 for a draft post", %{ conn: conn, user: user, post_draft: post_draft } do res = conn |> auth_conn(user) |> AbsintheHelpers.graphql_query( query: @post_query, variables: %{ slug: post_draft.slug } ) assert res["errors"] == nil assert res["data"]["post"]["title"] == post_draft.title assert res["data"]["post"]["draft"] == true end test "get_post/3 without being a member for a public post", %{ conn: conn, post: post } do %User{} = user = insert(:user) %Actor{} = insert(:actor, user: user) res = conn |> auth_conn(user) |> AbsintheHelpers.graphql_query( query: @post_query, variables: %{ slug: post.slug } ) assert is_nil(res["errors"]) assert res["data"]["post"]["title"] == post.title end test "get_post/3 without being connected for a public post", %{ conn: conn, post: post } do res = conn |> AbsintheHelpers.graphql_query( query: @post_query, variables: %{ slug: post.slug } ) assert is_nil(res["errors"]) assert res["data"]["post"]["title"] == post.title end test "get_post/3 without being a member for an unlisted post", %{ conn: conn, post_unlisted: post_unlisted } do %User{} = user = insert(:user) %Actor{} = insert(:actor, user: user) res = conn |> auth_conn(user) |> AbsintheHelpers.graphql_query( query: @post_query, variables: %{ slug: post_unlisted.slug } ) assert is_nil(res["errors"]) assert res["data"]["post"]["title"] == post_unlisted.title assert res["data"]["post"]["visibility"] == post_unlisted.visibility |> to_string() |> String.upcase() end test "get_post/3 without being a member for a private post", %{ conn: conn, post_private: post_private } do %User{} = user = insert(:user) %Actor{} = insert(:actor, user: user) res = conn |> auth_conn(user) |> AbsintheHelpers.graphql_query( query: @post_query, variables: %{ slug: post_private.slug } ) assert hd(res["errors"])["message"] == "Post not found" end test "get_post/3 without being connected for an unlisted post still gives the post", %{ conn: conn, post_unlisted: post_unlisted } do res = conn |> AbsintheHelpers.graphql_query( query: @post_query, variables: %{ slug: post_unlisted.slug } ) assert is_nil(res["errors"]) assert res["data"]["post"]["title"] == post_unlisted.title assert res["data"]["post"]["visibility"] == post_unlisted.visibility |> to_string() |> String.upcase() end test "get_post/3 without being connected for a private post", %{ conn: conn, post_private: post_private } do res = conn |> AbsintheHelpers.graphql_query( query: @post_query, variables: %{ slug: post_private.slug } ) assert hd(res["errors"])["message"] == "Post not found" end test "get_post/3 without being a member for a draft post", %{ conn: conn, post_draft: post_draft } do %User{} = user = insert(:user) %Actor{} = insert(:actor, user: user) res = conn |> auth_conn(user) |> AbsintheHelpers.graphql_query( query: @post_query, variables: %{ slug: post_draft.slug } ) assert hd(res["errors"])["message"] == "Post not found" end test "get_post/3 without being connected for a draft post", %{ conn: conn, post_draft: post_draft } do res = conn |> AbsintheHelpers.graphql_query( query: @post_query, variables: %{ slug: post_draft.slug } ) assert hd(res["errors"])["message"] == "Post not found" end end describe "Resolver: Create a post" do test "create_post/3 creates a post for a group", %{ conn: conn, user: user, group: group } do res = conn |> auth_conn(user) |> AbsintheHelpers.graphql_query( query: @create_post, variables: %{ title: @post_title, body: "My new post is here", attributedToId: group.id } ) assert is_nil(res["errors"]) assert res["data"]["createPost"]["title"] == @post_title id = res["data"]["createPost"]["id"] assert res["data"]["createPost"]["slug"] == "my-post-#{ShortUUID.encode!(id)}" end test "create_post/3 creates a draft post for a group", %{ conn: conn, user: user, group: group } do res = conn |> auth_conn(user) |> AbsintheHelpers.graphql_query( query: @create_post, variables: %{ title: @post_title, body: "My new post is here", attributedToId: group.id, draft: true } ) assert is_nil(res["errors"]) assert res["data"]["createPost"]["title"] == @post_title id = res["data"]["createPost"]["id"] assert res["data"]["createPost"]["slug"] == "my-post-#{ShortUUID.encode!(id)}" assert res["data"]["createPost"]["draft"] == true end test "create_post/3 doesn't create a post if no group is defined", %{ conn: conn, user: user } do res = conn |> auth_conn(user) |> AbsintheHelpers.graphql_query( query: @create_post, variables: %{ title: @post_title, body: "some body", attributedToId: nil } ) assert Enum.map(res["errors"], & &1["message"]) == [ "Argument \"attributedToId\" has invalid value $attributedToId.", "Variable \"attributedToId\": Expected non-null, found null." ] end test "create_post/3 doesn't create a post if the actor is not a member of the group", %{ conn: conn, group: group } do %User{} = user = insert(:user) %Actor{} = insert(:actor, user: user) res = conn |> auth_conn(user) |> AbsintheHelpers.graphql_query( query: @create_post, variables: %{ title: @post_title, body: "My body", attributedToId: group.id } ) assert Enum.map(res["errors"], & &1["message"]) == [ "Profile is not member of group" ] end end describe "Resolver: Update a post" do test "update_post/3 updates a post for a group", %{ conn: conn, user: user, group: group } do %Post{id: post_id} = insert(:post, attributed_to: group) res = conn |> auth_conn(user) |> AbsintheHelpers.graphql_query( query: @update_post, variables: %{ id: post_id, title: @updated_post_title } ) assert is_nil(res["errors"]) assert res["data"]["updatePost"]["title"] == @updated_post_title end end describe "Resolver: Delete a post" do test "delete_post/3 deletes a post", %{ conn: conn, user: user, group: group } do %Post{id: post_id, slug: post_slug} = insert(:post, attributed_to: group ) res = conn |> auth_conn(user) |> AbsintheHelpers.graphql_query( query: @delete_post, variables: %{ id: post_id } ) assert is_nil(res["errors"]) assert res["data"]["deletePost"]["id"] == post_id res = conn |> auth_conn(user) |> AbsintheHelpers.graphql_query( query: @post_query, variables: %{ slug: post_slug } ) assert hd(res["errors"])["message"] == "Post not found" end test "delete_post/3 deletes a post not found", %{ conn: conn, user: user } do res = conn |> auth_conn(user) |> AbsintheHelpers.graphql_query( query: @delete_post, variables: %{ id: "not found" } ) assert hd(res["errors"])["message"] == "Post ID is not a valid ID" res = conn |> auth_conn(user) |> AbsintheHelpers.graphql_query( query: @delete_post, variables: %{ id: "d276ef98-8433-48d7-890e-c24eda0dcdbe" } ) assert hd(res["errors"])["message"] == "Post doesn't exist" end end end