package graphql_test import ( "bytes" "context" "encoding/json" "fmt" "net/http" "net/http/httptest" "testing" graph "tercul/internal/adapters/graphql" "tercul/internal/testutil" "github.com/99designs/gqlgen/graphql/handler" "github.com/stretchr/testify/suite" ) // GraphQLRequest represents a GraphQL request type GraphQLRequest struct { Query string `json:"query"` OperationName string `json:"operationName,omitempty"` Variables map[string]interface{} `json:"variables,omitempty"` } // GraphQLResponse represents a GraphQL response type GraphQLResponse struct { Data map[string]interface{} `json:"data,omitempty"` Errors []map[string]interface{} `json:"errors,omitempty"` } // GraphQLIntegrationSuite is a test suite for GraphQL integration tests type GraphQLIntegrationSuite struct { testutil.SimpleTestSuite server *httptest.Server client *http.Client } // SetupSuite sets up the test suite func (s *GraphQLIntegrationSuite) SetupSuite() { // Use the simple test utilities s.SimpleTestSuite.SetupSuite() // Create GraphQL server with the test resolver resolver := s.GetResolver() srv := handler.NewDefaultServer(graph.NewExecutableSchema(graph.Config{Resolvers: resolver})) s.server = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { srv.ServeHTTP(w, r) })) s.client = s.server.Client() } // TearDownSuite tears down the test suite func (s *GraphQLIntegrationSuite) TearDownSuite() { s.server.Close() } // SetupTest sets up each test func (s *GraphQLIntegrationSuite) SetupTest() { s.SimpleTestSuite.SetupTest() } // executeGraphQL executes a GraphQL query func (s *GraphQLIntegrationSuite) executeGraphQL(query string, variables map[string]interface{}) (*GraphQLResponse, error) { // Create the request request := GraphQLRequest{ Query: query, Variables: variables, } // Marshal the request to JSON requestBody, err := json.Marshal(request) if err != nil { return nil, err } // Create an HTTP request req, err := http.NewRequest("POST", s.server.URL, bytes.NewBuffer(requestBody)) if err != nil { return nil, err } req.Header.Set("Content-Type", "application/json") // Execute the request resp, err := s.client.Do(req) if err != nil { return nil, err } defer resp.Body.Close() // Parse the response var response GraphQLResponse err = json.NewDecoder(resp.Body).Decode(&response) if err != nil { return nil, err } return &response, nil } // TestQueryWork tests the work query func (s *GraphQLIntegrationSuite) TestQueryWork() { // Create a test work with content work := s.CreateTestWork("Test Work", "en", "Test content for work") // Define the query query := ` query GetWork($id: ID!) { work(id: $id) { id name language content } } ` // Define the variables variables := map[string]interface{}{ "id": fmt.Sprintf("%d", work.ID), } // Execute the query response, err := s.executeGraphQL(query, variables) s.Require().NoError(err) s.Require().NotNil(response) s.Require().Nil(response.Errors, "GraphQL query should not return errors") s.Require().NotNil(response.Data, "GraphQL query should return data") // Verify the response workData, ok := response.Data["work"].(map[string]interface{}) s.Require().True(ok, "GraphQL response should contain work data") s.Equal("Test Work", workData["name"], "Work name should match") s.Equal("Test content for work", workData["content"], "Work content should match") s.Equal("en", workData["language"], "Work language should match") } // TestQueryWorks tests the works query func (s *GraphQLIntegrationSuite) TestQueryWorks() { // Create test works s.CreateTestWork("Test Work 1", "en", "Test content for work 1") s.CreateTestWork("Test Work 2", "en", "Test content for work 2") s.CreateTestWork("Test Work 3", "fr", "Test content for work 3") // Define the query query := ` query GetWorks { works { id name language content } } ` // Execute the query response, err := s.executeGraphQL(query, nil) s.Require().NoError(err) s.Require().NotNil(response) s.Require().Nil(response.Errors, "GraphQL query should not return errors") s.Require().NotNil(response.Data, "GraphQL query should return data") // Verify the response worksData, ok := response.Data["works"].([]interface{}) s.Require().True(ok, "GraphQL response should contain works data") s.True(len(worksData) >= 3, "GraphQL response should contain at least 3 works") // Verify each work foundWork1 := false foundWork2 := false foundWork3 := false for _, workData := range worksData { work, ok := workData.(map[string]interface{}) s.Require().True(ok, "Work data should be a map") name := work["name"].(string) if name == "Test Work 1" { foundWork1 = true s.Equal("en", work["language"], "Work 1 language should match") } else if name == "Test Work 2" { foundWork2 = true s.Equal("en", work["language"], "Work 2 language should match") } else if name == "Test Work 3" { foundWork3 = true s.Equal("fr", work["language"], "Work 3 language should match") } } s.True(foundWork1, "GraphQL response should contain work 1") s.True(foundWork2, "GraphQL response should contain work 2") s.True(foundWork3, "GraphQL response should contain work 3") } // TestCreateWork tests the createWork mutation func (s *GraphQLIntegrationSuite) TestCreateWork() { // Define the mutation mutation := ` mutation CreateWork($input: WorkInput!) { createWork(input: $input) { id name language content } } ` // Define the variables variables := map[string]interface{}{ "input": map[string]interface{}{ "name": "New Test Work", "language": "en", "content": "New test content", }, } // Execute the mutation response, err := s.executeGraphQL(mutation, variables) s.Require().NoError(err) s.Require().NotNil(response) s.Require().Nil(response.Errors, "GraphQL mutation should not return errors") s.Require().NotNil(response.Data, "GraphQL mutation should return data") // Verify the response workData, ok := response.Data["createWork"].(map[string]interface{}) s.Require().True(ok, "GraphQL response should contain work data") s.NotNil(workData["id"], "Work ID should not be nil") s.Equal("New Test Work", workData["name"], "Work name should match") s.Equal("en", workData["language"], "Work language should match") s.Equal("New test content", workData["content"], "Work content should match") // Verify that the work was created in the repository // Since we're using the real repository interface, we can query it works, err := s.WorkRepo.ListAll(context.Background()) s.Require().NoError(err) var found bool for _, w := range works { if w.Title == "New Test Work" { found = true s.Equal("en", w.Language, "Work language should be set correctly") break } } s.True(found, "Work should be created in repository") } // TestGraphQLIntegrationSuite runs the test suite func TestGraphQLIntegrationSuite(t *testing.T) { testutil.SkipIfShort(t) suite.Run(t, new(GraphQLIntegrationSuite)) }