428 lines
11 KiB
Go
428 lines
11 KiB
Go
package graphql
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"encoding/json"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"omega-server/local/graphql/handler"
|
|
"omega-server/local/service"
|
|
"testing"
|
|
|
|
"github.com/gofiber/fiber/v2"
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
// GraphQLTestUtils provides utilities for testing GraphQL endpoints
|
|
type GraphQLTestUtils struct {
|
|
App *fiber.App
|
|
Handler *handler.GraphQLHandler
|
|
DB *gorm.DB
|
|
}
|
|
|
|
// GraphQLTestRequest represents a GraphQL test request
|
|
type GraphQLTestRequest struct {
|
|
Query string `json:"query"`
|
|
Variables map[string]interface{} `json:"variables,omitempty"`
|
|
}
|
|
|
|
// GraphQLTestResponse represents a GraphQL test response
|
|
type GraphQLTestResponse struct {
|
|
Data interface{} `json:"data,omitempty"`
|
|
Errors []GraphQLError `json:"errors,omitempty"`
|
|
}
|
|
|
|
// GraphQLError represents a GraphQL error in test responses
|
|
type GraphQLError struct {
|
|
Message string `json:"message"`
|
|
Path []string `json:"path,omitempty"`
|
|
}
|
|
|
|
// NewGraphQLTestUtils creates a new GraphQL test utilities instance
|
|
func NewGraphQLTestUtils(db *gorm.DB, membershipService *service.MembershipService) *GraphQLTestUtils {
|
|
app := fiber.New(fiber.Config{
|
|
DisableStartupMessage: true,
|
|
})
|
|
|
|
graphqlHandler := handler.NewGraphQLHandler(membershipService)
|
|
app.Post("/graphql", graphqlHandler.Handle)
|
|
app.Get("/graphql", func(c *fiber.Ctx) error {
|
|
return c.SendString(graphqlHandler.GetSchema())
|
|
})
|
|
|
|
return &GraphQLTestUtils{
|
|
App: app,
|
|
Handler: graphqlHandler,
|
|
DB: db,
|
|
}
|
|
}
|
|
|
|
// ExecuteQuery executes a GraphQL query and returns the response
|
|
func (gtu *GraphQLTestUtils) ExecuteQuery(t *testing.T, query string, variables map[string]interface{}) *GraphQLTestResponse {
|
|
request := GraphQLTestRequest{
|
|
Query: query,
|
|
Variables: variables,
|
|
}
|
|
|
|
body, err := json.Marshal(request)
|
|
if err != nil {
|
|
t.Fatalf("Failed to marshal GraphQL request: %v", err)
|
|
}
|
|
|
|
req := httptest.NewRequest(http.MethodPost, "/graphql", bytes.NewBuffer(body))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
|
|
resp, err := gtu.App.Test(req)
|
|
if err != nil {
|
|
t.Fatalf("Failed to execute GraphQL request: %v", err)
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
var response GraphQLTestResponse
|
|
if err := json.NewDecoder(resp.Body).Decode(&response); err != nil {
|
|
t.Fatalf("Failed to decode GraphQL response: %v", err)
|
|
}
|
|
|
|
return &response
|
|
}
|
|
|
|
// ExecuteQueryWithContext executes a GraphQL query with context
|
|
func (gtu *GraphQLTestUtils) ExecuteQueryWithContext(t *testing.T, ctx context.Context, query string, variables map[string]interface{}) *GraphQLTestResponse {
|
|
request := GraphQLTestRequest{
|
|
Query: query,
|
|
Variables: variables,
|
|
}
|
|
|
|
body, err := json.Marshal(request)
|
|
if err != nil {
|
|
t.Fatalf("Failed to marshal GraphQL request: %v", err)
|
|
}
|
|
|
|
req := httptest.NewRequest(http.MethodPost, "/graphql", bytes.NewBuffer(body))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
req = req.WithContext(ctx)
|
|
|
|
resp, err := gtu.App.Test(req)
|
|
if err != nil {
|
|
t.Fatalf("Failed to execute GraphQL request: %v", err)
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
var response GraphQLTestResponse
|
|
if err := json.NewDecoder(resp.Body).Decode(&response); err != nil {
|
|
t.Fatalf("Failed to decode GraphQL response: %v", err)
|
|
}
|
|
|
|
return &response
|
|
}
|
|
|
|
// ExecuteLoginMutation executes a login mutation
|
|
func (gtu *GraphQLTestUtils) ExecuteLoginMutation(t *testing.T, email, password string) *GraphQLTestResponse {
|
|
query := `
|
|
mutation Login($email: String!, $password: String!) {
|
|
login(input: {email: $email, password: $password}) {
|
|
token
|
|
user {
|
|
id
|
|
email
|
|
fullName
|
|
}
|
|
}
|
|
}
|
|
`
|
|
|
|
variables := map[string]interface{}{
|
|
"email": email,
|
|
"password": password,
|
|
}
|
|
|
|
return gtu.ExecuteQuery(t, query, variables)
|
|
}
|
|
|
|
// ExecuteCreateUserMutation executes a create user mutation
|
|
func (gtu *GraphQLTestUtils) ExecuteCreateUserMutation(t *testing.T, email, password, fullName string) *GraphQLTestResponse {
|
|
query := `
|
|
mutation CreateUser($email: String!, $password: String!, $fullName: String!) {
|
|
createUser(input: {email: $email, password: $password, fullName: $fullName}) {
|
|
id
|
|
email
|
|
fullName
|
|
createdAt
|
|
updatedAt
|
|
}
|
|
}
|
|
`
|
|
|
|
variables := map[string]interface{}{
|
|
"email": email,
|
|
"password": password,
|
|
"fullName": fullName,
|
|
}
|
|
|
|
return gtu.ExecuteQuery(t, query, variables)
|
|
}
|
|
|
|
// ExecuteMeQuery executes a me query
|
|
func (gtu *GraphQLTestUtils) ExecuteMeQuery(t *testing.T) *GraphQLTestResponse {
|
|
query := `
|
|
query Me {
|
|
me {
|
|
id
|
|
email
|
|
fullName
|
|
createdAt
|
|
updatedAt
|
|
}
|
|
}
|
|
`
|
|
|
|
return gtu.ExecuteQuery(t, query, nil)
|
|
}
|
|
|
|
// ExecuteUsersQuery executes a users query
|
|
func (gtu *GraphQLTestUtils) ExecuteUsersQuery(t *testing.T) *GraphQLTestResponse {
|
|
query := `
|
|
query Users {
|
|
users {
|
|
id
|
|
email
|
|
fullName
|
|
createdAt
|
|
updatedAt
|
|
}
|
|
}
|
|
`
|
|
|
|
return gtu.ExecuteQuery(t, query, nil)
|
|
}
|
|
|
|
// ExecuteUserQuery executes a user query by ID
|
|
func (gtu *GraphQLTestUtils) ExecuteUserQuery(t *testing.T, userID string) *GraphQLTestResponse {
|
|
query := `
|
|
query User($id: String!) {
|
|
user(id: $id) {
|
|
id
|
|
email
|
|
fullName
|
|
createdAt
|
|
updatedAt
|
|
}
|
|
}
|
|
`
|
|
|
|
variables := map[string]interface{}{
|
|
"id": userID,
|
|
}
|
|
|
|
return gtu.ExecuteQuery(t, query, variables)
|
|
}
|
|
|
|
// ExecuteCreateProjectMutation executes a create project mutation
|
|
func (gtu *GraphQLTestUtils) ExecuteCreateProjectMutation(t *testing.T, name, description, ownerID string) *GraphQLTestResponse {
|
|
query := `
|
|
mutation CreateProject($name: String!, $description: String, $ownerId: String!) {
|
|
createProject(input: {name: $name, description: $description, ownerId: $ownerId}) {
|
|
id
|
|
name
|
|
description
|
|
ownerId
|
|
createdAt
|
|
updatedAt
|
|
}
|
|
}
|
|
`
|
|
|
|
variables := map[string]interface{}{
|
|
"name": name,
|
|
"description": description,
|
|
"ownerId": ownerID,
|
|
}
|
|
|
|
return gtu.ExecuteQuery(t, query, variables)
|
|
}
|
|
|
|
// ExecuteProjectsQuery executes a projects query
|
|
func (gtu *GraphQLTestUtils) ExecuteProjectsQuery(t *testing.T) *GraphQLTestResponse {
|
|
query := `
|
|
query Projects {
|
|
projects {
|
|
id
|
|
name
|
|
description
|
|
ownerId
|
|
createdAt
|
|
updatedAt
|
|
}
|
|
}
|
|
`
|
|
|
|
return gtu.ExecuteQuery(t, query, nil)
|
|
}
|
|
|
|
// ExecuteCreateTaskMutation executes a create task mutation
|
|
func (gtu *GraphQLTestUtils) ExecuteCreateTaskMutation(t *testing.T, title, description, status, priority, projectID string) *GraphQLTestResponse {
|
|
query := `
|
|
mutation CreateTask($title: String!, $description: String, $status: String, $priority: String, $projectId: String!) {
|
|
createTask(input: {title: $title, description: $description, status: $status, priority: $priority, projectId: $projectId}) {
|
|
id
|
|
title
|
|
description
|
|
status
|
|
priority
|
|
projectId
|
|
createdAt
|
|
updatedAt
|
|
}
|
|
}
|
|
`
|
|
|
|
variables := map[string]interface{}{
|
|
"title": title,
|
|
"description": description,
|
|
"status": status,
|
|
"priority": priority,
|
|
"projectId": projectID,
|
|
}
|
|
|
|
return gtu.ExecuteQuery(t, query, variables)
|
|
}
|
|
|
|
// ExecuteTasksQuery executes a tasks query
|
|
func (gtu *GraphQLTestUtils) ExecuteTasksQuery(t *testing.T, projectID *string) *GraphQLTestResponse {
|
|
query := `
|
|
query Tasks($projectId: String) {
|
|
tasks(projectId: $projectId) {
|
|
id
|
|
title
|
|
description
|
|
status
|
|
priority
|
|
projectId
|
|
createdAt
|
|
updatedAt
|
|
}
|
|
}
|
|
`
|
|
|
|
variables := make(map[string]interface{})
|
|
if projectID != nil {
|
|
variables["projectId"] = *projectID
|
|
}
|
|
|
|
return gtu.ExecuteQuery(t, query, variables)
|
|
}
|
|
|
|
// GetSchema returns the GraphQL schema
|
|
func (gtu *GraphQLTestUtils) GetSchema(t *testing.T) string {
|
|
return gtu.Handler.GetSchema()
|
|
}
|
|
|
|
// AssertNoErrors asserts that the GraphQL response has no errors
|
|
func (gtu *GraphQLTestUtils) AssertNoErrors(t *testing.T, response *GraphQLTestResponse) {
|
|
if len(response.Errors) > 0 {
|
|
t.Fatalf("Expected no GraphQL errors, but got: %+v", response.Errors)
|
|
}
|
|
}
|
|
|
|
// AssertHasErrors asserts that the GraphQL response has errors
|
|
func (gtu *GraphQLTestUtils) AssertHasErrors(t *testing.T, response *GraphQLTestResponse) {
|
|
if len(response.Errors) == 0 {
|
|
t.Fatalf("Expected GraphQL errors, but got none")
|
|
}
|
|
}
|
|
|
|
// AssertErrorMessage asserts that the GraphQL response contains a specific error message
|
|
func (gtu *GraphQLTestUtils) AssertErrorMessage(t *testing.T, response *GraphQLTestResponse, expectedMessage string) {
|
|
if len(response.Errors) == 0 {
|
|
t.Fatalf("Expected GraphQL errors, but got none")
|
|
}
|
|
|
|
for _, err := range response.Errors {
|
|
if err.Message == expectedMessage {
|
|
return
|
|
}
|
|
}
|
|
|
|
t.Fatalf("Expected error message '%s', but not found in errors: %+v", expectedMessage, response.Errors)
|
|
}
|
|
|
|
// AssertDataNotNil asserts that the GraphQL response data is not nil
|
|
func (gtu *GraphQLTestUtils) AssertDataNotNil(t *testing.T, response *GraphQLTestResponse) {
|
|
if response.Data == nil {
|
|
t.Fatalf("Expected GraphQL data to not be nil, but it was")
|
|
}
|
|
}
|
|
|
|
// AssertDataNil asserts that the GraphQL response data is nil
|
|
func (gtu *GraphQLTestUtils) AssertDataNil(t *testing.T, response *GraphQLTestResponse) {
|
|
if response.Data != nil {
|
|
t.Fatalf("Expected GraphQL data to be nil, but got: %+v", response.Data)
|
|
}
|
|
}
|
|
|
|
// ExtractField extracts a field from the GraphQL response data
|
|
func (gtu *GraphQLTestUtils) ExtractField(t *testing.T, response *GraphQLTestResponse, fieldPath ...string) interface{} {
|
|
if response.Data == nil {
|
|
t.Fatalf("Cannot extract field from nil data")
|
|
}
|
|
|
|
data := response.Data
|
|
for _, field := range fieldPath {
|
|
if dataMap, ok := data.(map[string]interface{}); ok {
|
|
if value, exists := dataMap[field]; exists {
|
|
data = value
|
|
} else {
|
|
t.Fatalf("Field '%s' not found in data: %+v", field, dataMap)
|
|
}
|
|
} else {
|
|
t.Fatalf("Cannot extract field '%s' from non-map data: %+v", field, data)
|
|
}
|
|
}
|
|
|
|
return data
|
|
}
|
|
|
|
// ExtractString extracts a string field from the GraphQL response data
|
|
func (gtu *GraphQLTestUtils) ExtractString(t *testing.T, response *GraphQLTestResponse, fieldPath ...string) string {
|
|
value := gtu.ExtractField(t, response, fieldPath...)
|
|
if str, ok := value.(string); ok {
|
|
return str
|
|
}
|
|
t.Fatalf("Expected string value for field %v, but got: %+v", fieldPath, value)
|
|
return ""
|
|
}
|
|
|
|
// ExtractInt extracts an integer field from the GraphQL response data
|
|
func (gtu *GraphQLTestUtils) ExtractInt(t *testing.T, response *GraphQLTestResponse, fieldPath ...string) int {
|
|
value := gtu.ExtractField(t, response, fieldPath...)
|
|
if floatVal, ok := value.(float64); ok {
|
|
return int(floatVal)
|
|
}
|
|
if intVal, ok := value.(int); ok {
|
|
return intVal
|
|
}
|
|
t.Fatalf("Expected int value for field %v, but got: %+v", fieldPath, value)
|
|
return 0
|
|
}
|
|
|
|
// ExtractBool extracts a boolean field from the GraphQL response data
|
|
func (gtu *GraphQLTestUtils) ExtractBool(t *testing.T, response *GraphQLTestResponse, fieldPath ...string) bool {
|
|
value := gtu.ExtractField(t, response, fieldPath...)
|
|
if boolVal, ok := value.(bool); ok {
|
|
return boolVal
|
|
}
|
|
t.Fatalf("Expected bool value for field %v, but got: %+v", fieldPath, value)
|
|
return false
|
|
}
|
|
|
|
// ExtractArray extracts an array field from the GraphQL response data
|
|
func (gtu *GraphQLTestUtils) ExtractArray(t *testing.T, response *GraphQLTestResponse, fieldPath ...string) []interface{} {
|
|
value := gtu.ExtractField(t, response, fieldPath...)
|
|
if arrVal, ok := value.([]interface{}); ok {
|
|
return arrVal
|
|
}
|
|
t.Fatalf("Expected array value for field %v, but got: %+v", fieldPath, value)
|
|
return nil
|
|
}
|