package graphql_test import ( "tercul/internal/adapters/graphql/model" "tercul/internal/domain" ) type CreateBookResponse struct { CreateBook model.Book `json:"createBook"` } type GetBookResponse struct { Book model.Book `json:"book"` } type GetBooksResponse struct { Books []model.Book `json:"books"` } type UpdateBookResponse struct { UpdateBook model.Book `json:"updateBook"` } func (s *GraphQLIntegrationSuite) TestBookMutations() { // Create users for testing authorization _, readerToken := s.CreateAuthenticatedUser("bookreader", "bookreader@test.com", domain.UserRoleReader) _, adminToken := s.CreateAuthenticatedUser("bookadmin", "bookadmin@test.com", domain.UserRoleAdmin) var bookID string s.Run("a reader can create a book", func() { // Define the mutation mutation := ` mutation CreateBook($input: BookInput!) { createBook(input: $input) { id name description language isbn } } ` // Define the variables variables := map[string]interface{}{ "input": map[string]interface{}{ "name": "My New Book", "description": "A book about something.", "language": "en", "isbn": "978-3-16-148410-0", }, } // Execute the mutation response, err := executeGraphQL[CreateBookResponse](s, mutation, variables, &readerToken) s.Require().NoError(err) s.Require().NotNil(response) s.Require().Nil(response.Errors, "GraphQL mutation should not return errors") // Verify the response s.NotNil(response.Data.CreateBook.ID, "Book ID should not be nil") bookID = response.Data.CreateBook.ID s.Equal("My New Book", response.Data.CreateBook.Name) s.Equal("A book about something.", *response.Data.CreateBook.Description) s.Equal("en", response.Data.CreateBook.Language) s.Equal("978-3-16-148410-0", *response.Data.CreateBook.Isbn) }) s.Run("a reader is forbidden from updating a book", func() { // Define the mutation mutation := ` mutation UpdateBook($id: ID!, $input: BookInput!) { updateBook(id: $id, input: $input) { id } } ` // Define the variables variables := map[string]interface{}{ "id": bookID, "input": map[string]interface{}{ "name": "Updated Book Name", "language": "en", }, } // Execute the mutation with the reader's token response, err := executeGraphQL[any](s, mutation, variables, &readerToken) s.Require().NoError(err) s.Require().NotNil(response.Errors) }) s.Run("an admin can update a book", func() { // Define the mutation mutation := ` mutation UpdateBook($id: ID!, $input: BookInput!) { updateBook(id: $id, input: $input) { id name } } ` // Define the variables variables := map[string]interface{}{ "id": bookID, "input": map[string]interface{}{ "name": "Updated Book Name by Admin", "language": "en", }, } // Execute the mutation with the admin's token response, err := executeGraphQL[UpdateBookResponse](s, mutation, variables, &adminToken) s.Require().NoError(err) s.Require().NotNil(response) s.Require().Nil(response.Errors, "GraphQL mutation should not return errors") }) s.Run("a reader is forbidden from deleting a book", func() { // Define the mutation mutation := ` mutation DeleteBook($id: ID!) { deleteBook(id: $id) } ` // Define the variables variables := map[string]interface{}{ "id": bookID, } // Execute the mutation with the reader's token response, err := executeGraphQL[any](s, mutation, variables, &readerToken) s.Require().NoError(err) s.Require().NotNil(response.Errors) }) s.Run("an admin can delete a book", func() { // Define the mutation mutation := ` mutation DeleteBook($id: ID!) { deleteBook(id: $id) } ` // Define the variables variables := map[string]interface{}{ "id": bookID, } // Execute the mutation with the admin's token response, err := executeGraphQL[any](s, mutation, variables, &adminToken) s.Require().NoError(err) s.Require().Nil(response.Errors) s.True(response.Data.(map[string]interface{})["deleteBook"].(bool)) }) } func (s *GraphQLIntegrationSuite) TestBookQueries() { // Create a book to query _, adminToken := s.CreateAuthenticatedUser("bookadmin2", "bookadmin2@test.com", domain.UserRoleAdmin) createMutation := ` mutation CreateBook($input: BookInput!) { createBook(input: $input) { id } } ` createVariables := map[string]interface{}{ "input": map[string]interface{}{ "name": "Queryable Book", "description": "A book to be queried.", "language": "en", "isbn": "978-0-306-40615-7", }, } createResponse, err := executeGraphQL[CreateBookResponse](s, createMutation, createVariables, &adminToken) s.Require().NoError(err) bookID := createResponse.Data.CreateBook.ID s.Run("should get a book by ID", func() { // Define the query query := ` query GetBook($id: ID!) { book(id: $id) { id name description } } ` // Define the variables variables := map[string]interface{}{ "id": bookID, } // Execute the query response, err := executeGraphQL[GetBookResponse](s, query, variables, nil) s.Require().NoError(err) s.Require().NotNil(response) s.Require().Nil(response.Errors, "GraphQL query should not return errors") // Verify the response s.Equal(bookID, response.Data.Book.ID) s.Equal("Queryable Book", response.Data.Book.Name) s.Equal("A book to be queried.", *response.Data.Book.Description) }) s.Run("should get a list of books", func() { // Define the query query := ` query GetBooks { books { id name } } ` // Execute the query response, err := executeGraphQL[GetBooksResponse](s, query, nil, nil) s.Require().NoError(err) s.Require().NotNil(response) s.Require().Nil(response.Errors, "GraphQL query should not return errors") // Verify the response s.True(len(response.Data.Books) >= 1) foundBook := false for _, book := range response.Data.Books { if book.ID == bookID { foundBook = true break } } s.True(foundBook, "The created book should be in the list") }) }