| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612 |
- package graph
- import (
- "encoding/json"
- "fmt"
- "strings"
- "testing"
- "github.com/99designs/gqlgen/client"
- "github.com/99designs/gqlgen/graphql/handler"
- "github.com/bradleyjkemp/cupaloy/v2"
- "gogs.dmsc.dev/arp/graph/testutil"
- "gorm.io/gorm"
- )
- var snapshotter = cupaloy.New(cupaloy.SnapshotSubdirectory("testdata/snapshots"))
- type TestClient struct {
- client *client.Client
- db *gorm.DB
- }
- type IDTracker struct {
- Permissions map[string]string
- Roles map[string]string
- Users map[string]string
- TaskStatuses map[string]string
- Services map[string]string
- Tasks map[string]string
- Notes map[string]string
- Channels []string
- Messages []string
- }
- func NewIDTracker() *IDTracker {
- return &IDTracker{
- Permissions: make(map[string]string),
- Roles: make(map[string]string),
- Users: make(map[string]string),
- TaskStatuses: make(map[string]string),
- Services: make(map[string]string),
- Tasks: make(map[string]string),
- Notes: make(map[string]string),
- Channels: make([]string, 0),
- Messages: make([]string, 0),
- }
- }
- func setupTestClient(t *testing.T) (*TestClient, *IDTracker) {
- db, err := testutil.SetupTestDB()
- if err != nil {
- t.Fatalf("Failed to setup test database: %v", err)
- }
- resolver := &Resolver{DB: db}
- schema := NewExecutableSchema(Config{Resolvers: resolver})
- srv := handler.NewDefaultServer(schema)
- return &TestClient{client: client.New(srv), db: db}, NewIDTracker()
- }
- func normalizeJSON(jsonStr string) string {
- var data interface{}
- if err := json.Unmarshal([]byte(jsonStr), &data); err != nil {
- return jsonStr
- }
- normalizeData(data)
- bytes, _ := json.MarshalIndent(data, "", " ")
- return string(bytes)
- }
- func normalizeData(data interface{}) {
- switch v := data.(type) {
- case map[string]interface{}:
- delete(v, "id")
- delete(v, "ID")
- delete(v, "createdAt")
- delete(v, "updatedAt")
- delete(v, "sentAt")
- delete(v, "createdByID")
- delete(v, "userId")
- delete(v, "serviceId")
- delete(v, "statusId")
- delete(v, "assigneeId")
- delete(v, "conversationId")
- delete(v, "senderId")
- for _, val := range v {
- normalizeData(val)
- }
- case []interface{}:
- for _, item := range v {
- normalizeData(item)
- }
- }
- }
- func snapshotResult(t *testing.T, name string, jsonStr string) {
- normalized := normalizeJSON(jsonStr)
- snapshotter.SnapshotT(t, name, normalized)
- }
- func TestIntegration_Bootstrap(t *testing.T) {
- tc, tracker := setupTestClient(t)
- seed := testutil.GetSeedData()
- // Phase 1: Create Permissions
- t.Run("CreatePermissions", func(t *testing.T) {
- for _, perm := range seed.Permissions {
- var response struct {
- CreatePermission struct {
- ID string `json:"id"`
- Code string `json:"code"`
- Description string `json:"description"`
- } `json:"createPermission"`
- }
- query := fmt.Sprintf(`mutation { createPermission(input: {code: "%s", description: "%s"}) { id code description } }`, perm.Code, perm.Description)
- err := tc.client.Post(query, &response)
- if err != nil {
- t.Fatalf("Failed to create permission %s: %v", perm.Code, err)
- }
- tracker.Permissions[perm.Code] = response.CreatePermission.ID
- }
- var permsResponse struct {
- Permissions []interface{} `json:"permissions"`
- }
- tc.client.Post(`query { permissions { id code description } }`, &permsResponse)
- jsonBytes, _ := json.MarshalIndent(permsResponse, "", " ")
- snapshotResult(t, "permissions", string(jsonBytes))
- })
- // Phase 2: Create Roles
- t.Run("CreateRoles", func(t *testing.T) {
- for _, role := range seed.Roles {
- permIDs := make([]string, len(role.PermissionCodes))
- for i, code := range role.PermissionCodes {
- permIDs[i] = tracker.Permissions[code]
- }
- var response struct {
- CreateRole struct {
- ID string `json:"id"`
- Name string `json:"name"`
- Description string `json:"description"`
- } `json:"createRole"`
- }
- query := fmt.Sprintf(`mutation { createRole(input: {name: "%s", description: "%s", permissions: ["%s"]}) { id name description } }`, role.Name, role.Description, strings.Join(permIDs, `", "`))
- err := tc.client.Post(query, &response)
- if err != nil {
- t.Fatalf("Failed to create role %s: %v", role.Name, err)
- }
- tracker.Roles[role.Name] = response.CreateRole.ID
- }
- var rolesResponse struct {
- Roles []interface{} `json:"roles"`
- }
- tc.client.Post(`query { roles { id name description permissions { id code } } }`, &rolesResponse)
- jsonBytes, _ := json.MarshalIndent(rolesResponse, "", " ")
- snapshotResult(t, "roles", string(jsonBytes))
- })
- // Phase 3: Create Users
- t.Run("CreateUsers", func(t *testing.T) {
- for _, user := range seed.Users {
- roleIDs := make([]string, len(user.RoleNames))
- for i, name := range user.RoleNames {
- roleIDs[i] = tracker.Roles[name]
- }
- var response struct {
- CreateUser struct {
- ID string `json:"id"`
- Email string `json:"email"`
- } `json:"createUser"`
- }
- query := fmt.Sprintf(`mutation { createUser(input: {email: "%s", password: "%s", roles: ["%s"]}) { id email } }`, user.Email, user.Password, strings.Join(roleIDs, `", "`))
- err := tc.client.Post(query, &response)
- if err != nil {
- t.Fatalf("Failed to create user %s: %v", user.Email, err)
- }
- tracker.Users[user.Email] = response.CreateUser.ID
- }
- var usersResponse struct {
- Users []interface{} `json:"users"`
- }
- tc.client.Post(`query { users { id email roles { id name } } }`, &usersResponse)
- jsonBytes, _ := json.MarshalIndent(usersResponse, "", " ")
- snapshotResult(t, "users", string(jsonBytes))
- })
- // Phase 4: Create Task Statuses
- t.Run("CreateTaskStatuses", func(t *testing.T) {
- for _, status := range seed.TaskStatuses {
- var response struct {
- CreateTaskStatus struct {
- ID string `json:"id"`
- Code string `json:"code"`
- Label string `json:"label"`
- } `json:"createTaskStatus"`
- }
- query := fmt.Sprintf(`mutation { createTaskStatus(input: {code: "%s", label: "%s"}) { id code label } }`, status.Code, status.Label)
- err := tc.client.Post(query, &response)
- if err != nil {
- t.Fatalf("Failed to create task status %s: %v", status.Code, err)
- }
- tracker.TaskStatuses[status.Code] = response.CreateTaskStatus.ID
- }
- var statusesResponse struct {
- TaskStatuses []interface{} `json:"taskStatuses"`
- }
- tc.client.Post(`query { taskStatuses { id code label } }`, &statusesResponse)
- jsonBytes, _ := json.MarshalIndent(statusesResponse, "", " ")
- snapshotResult(t, "taskStatuses", string(jsonBytes))
- })
- // Phase 5: Create Services
- t.Run("CreateServices", func(t *testing.T) {
- for _, service := range seed.Services {
- participantIDs := make([]string, len(service.ParticipantEmails))
- for i, email := range service.ParticipantEmails {
- participantIDs[i] = tracker.Users[email]
- }
- var response struct {
- CreateService struct {
- ID string `json:"id"`
- Name string `json:"name"`
- } `json:"createService"`
- }
- query := fmt.Sprintf(`mutation { createService(input: {name: "%s", description: "%s", createdById: "%s", participants: ["%s"]}) { id name } }`, service.Name, service.Description, tracker.Users[service.CreatorEmail], strings.Join(participantIDs, `", "`))
- err := tc.client.Post(query, &response)
- if err != nil {
- t.Fatalf("Failed to create service %s: %v", service.Name, err)
- }
- tracker.Services[service.Name] = response.CreateService.ID
- }
- var servicesResponse struct {
- Services []interface{} `json:"services"`
- }
- tc.client.Post(`query { services { id name description } }`, &servicesResponse)
- jsonBytes, _ := json.MarshalIndent(servicesResponse, "", " ")
- snapshotResult(t, "services", string(jsonBytes))
- })
- // Phase 6: Create Tasks
- t.Run("CreateTasks", func(t *testing.T) {
- for _, task := range seed.Tasks {
- var response struct {
- CreateTask struct {
- ID string `json:"id"`
- Title string `json:"title"`
- } `json:"createTask"`
- }
- var assigneeID string
- if task.AssigneeEmail != "" {
- assigneeID = tracker.Users[task.AssigneeEmail]
- }
- statusID := tracker.TaskStatuses[task.StatusCode]
- if assigneeID != "" {
- query := fmt.Sprintf(`mutation { createTask(input: {title: "%s", content: "%s", createdById: "%s", assigneeId: "%s", statusId: "%s", priority: "%s"}) { id title } }`, task.Title, task.Content, tracker.Users[task.CreatorEmail], assigneeID, statusID, task.Priority)
- err := tc.client.Post(query, &response)
- if err != nil {
- t.Fatalf("Failed to create task %s: %v", task.Title, err)
- }
- } else {
- query := fmt.Sprintf(`mutation { createTask(input: {title: "%s", content: "%s", createdById: "%s", statusId: "%s", priority: "%s"}) { id title } }`, task.Title, task.Content, tracker.Users[task.CreatorEmail], statusID, task.Priority)
- err := tc.client.Post(query, &response)
- if err != nil {
- t.Fatalf("Failed to create task %s: %v", task.Title, err)
- }
- }
- tracker.Tasks[task.Title] = response.CreateTask.ID
- }
- var tasksResponse struct {
- Tasks []interface{} `json:"tasks"`
- }
- tc.client.Post(`query { tasks { id title content priority } }`, &tasksResponse)
- jsonBytes, _ := json.MarshalIndent(tasksResponse, "", " ")
- snapshotResult(t, "tasks", string(jsonBytes))
- })
- // Phase 7: Create Notes
- t.Run("CreateNotes", func(t *testing.T) {
- for _, note := range seed.Notes {
- var response struct {
- CreateNote struct {
- ID string `json:"id"`
- Title string `json:"title"`
- } `json:"createNote"`
- }
- query := fmt.Sprintf(`mutation { createNote(input: {title: "%s", content: "%s", userId: "%s", serviceId: "%s"}) { id title } }`, note.Title, note.Content, tracker.Users[note.UserEmail], tracker.Services[note.ServiceName])
- err := tc.client.Post(query, &response)
- if err != nil {
- t.Fatalf("Failed to create note %s: %v", note.Title, err)
- }
- tracker.Notes[note.Title] = response.CreateNote.ID
- }
- var notesResponse struct {
- Notes []interface{} `json:"notes"`
- }
- tc.client.Post(`query { notes { id title content } }`, ¬esResponse)
- jsonBytes, _ := json.MarshalIndent(notesResponse, "", " ")
- snapshotResult(t, "notes", string(jsonBytes))
- })
- // Phase 8: Create Channels
- t.Run("CreateChannels", func(t *testing.T) {
- for _, channel := range seed.Channels {
- participantIDs := make([]string, len(channel.ParticipantEmails))
- for i, email := range channel.ParticipantEmails {
- participantIDs[i] = tracker.Users[email]
- }
- var response struct {
- CreateChannel struct {
- ID string `json:"id"`
- } `json:"createChannel"`
- }
- query := fmt.Sprintf(`mutation { createChannel(input: {participants: ["%s"]}) { id } }`, strings.Join(participantIDs, `", "`))
- err := tc.client.Post(query, &response)
- if err != nil {
- t.Fatalf("Failed to create channel: %v", err)
- }
- tracker.Channels = append(tracker.Channels, response.CreateChannel.ID)
- }
- var channelsResponse struct {
- Channels []interface{} `json:"channels"`
- }
- tc.client.Post(`query { channels { id } }`, &channelsResponse)
- jsonBytes, _ := json.MarshalIndent(channelsResponse, "", " ")
- snapshotResult(t, "channels", string(jsonBytes))
- })
- // Phase 9: Create Messages
- t.Run("CreateMessages", func(t *testing.T) {
- for _, msg := range seed.Messages {
- var response struct {
- CreateMessage struct {
- ID string `json:"id"`
- } `json:"createMessage"`
- }
- query := fmt.Sprintf(`mutation { createMessage(input: {conversationId: "%s", senderId: "%s", content: "%s"}) { id } }`, tracker.Channels[msg.ChannelIndex], tracker.Users[msg.SenderEmail], msg.Content)
- err := tc.client.Post(query, &response)
- if err != nil {
- t.Fatalf("Failed to create message: %v", err)
- }
- tracker.Messages = append(tracker.Messages, response.CreateMessage.ID)
- }
- var messagesResponse struct {
- Messages []interface{} `json:"messages"`
- }
- tc.client.Post(`query { messages { id content } }`, &messagesResponse)
- jsonBytes, _ := json.MarshalIndent(messagesResponse, "", " ")
- snapshotResult(t, "messages", string(jsonBytes))
- })
- }
- // TestIntegration_Update tests update operations
- func TestIntegration_Update(t *testing.T) {
- tc, tracker := setupTestClient(t)
- seed := testutil.GetSeedData()
- // Bootstrap first
- bootstrapData(t, tc, tracker, seed)
- // Update a user
- t.Run("UpdateUser", func(t *testing.T) {
- userID := tracker.Users["admin@example.com"]
- var response struct {
- UpdateUser struct {
- ID string `json:"id"`
- Email string `json:"email"`
- } `json:"updateUser"`
- }
- query := fmt.Sprintf(`mutation { updateUser(id: "%s", input: {email: "admin-updated@example.com", password: "new-password", roles: ["%s"]}) { id email } }`, userID, tracker.Roles["admin"])
- err := tc.client.Post(query, &response)
- if err != nil {
- t.Fatalf("Failed to update user: %v", err)
- }
- var usersResponse struct {
- Users []interface{} `json:"users"`
- }
- tc.client.Post(`query { users { id email roles { id name } } }`, &usersResponse)
- jsonBytes, _ := json.MarshalIndent(usersResponse, "", " ")
- snapshotResult(t, "users_after_update", string(jsonBytes))
- })
- // Update a task
- t.Run("UpdateTask", func(t *testing.T) {
- taskID := tracker.Tasks["Setup development environment"]
- var response struct {
- UpdateTask struct {
- ID string `json:"id"`
- Title string `json:"title"`
- } `json:"updateTask"`
- }
- query := fmt.Sprintf(`mutation { updateTask(id: "%s", input: {title: "Setup development environment - COMPLETE", priority: "low"}) { id title } }`, taskID)
- err := tc.client.Post(query, &response)
- if err != nil {
- t.Fatalf("Failed to update task: %v", err)
- }
- var tasksResponse struct {
- Tasks []interface{} `json:"tasks"`
- }
- tc.client.Post(`query { tasks { id title content priority } }`, &tasksResponse)
- jsonBytes, _ := json.MarshalIndent(tasksResponse, "", " ")
- snapshotResult(t, "tasks_after_update", string(jsonBytes))
- })
- }
- // TestIntegration_Delete tests delete operations
- func TestIntegration_Delete(t *testing.T) {
- tc, tracker := setupTestClient(t)
- seed := testutil.GetSeedData()
- // Bootstrap first
- bootstrapData(t, tc, tracker, seed)
- // Delete a note
- t.Run("DeleteNote", func(t *testing.T) {
- noteID := tracker.Notes["Meeting notes - Sprint 1"]
- var response struct {
- DeleteNote bool `json:"deleteNote"`
- }
- query := fmt.Sprintf(`mutation { deleteNote(id: "%s") }`, noteID)
- err := tc.client.Post(query, &response)
- if err != nil {
- t.Fatalf("Failed to delete note: %v", err)
- }
- var notesResponse struct {
- Notes []interface{} `json:"notes"`
- }
- tc.client.Post(`query { notes { id title content } }`, ¬esResponse)
- jsonBytes, _ := json.MarshalIndent(notesResponse, "", " ")
- snapshotResult(t, "notes_after_delete", string(jsonBytes))
- })
- // Delete a task
- t.Run("DeleteTask", func(t *testing.T) {
- taskID := tracker.Tasks["Performance optimization"]
- var response struct {
- DeleteTask bool `json:"deleteTask"`
- }
- query := fmt.Sprintf(`mutation { deleteTask(id: "%s") }`, taskID)
- err := tc.client.Post(query, &response)
- if err != nil {
- t.Fatalf("Failed to delete task: %v", err)
- }
- var tasksResponse struct {
- Tasks []interface{} `json:"tasks"`
- }
- tc.client.Post(`query { tasks { id title content priority } }`, &tasksResponse)
- jsonBytes, _ := json.MarshalIndent(tasksResponse, "", " ")
- snapshotResult(t, "tasks_after_delete", string(jsonBytes))
- })
- }
- // bootstrapData creates all entities for testing
- func bootstrapData(t *testing.T, tc *TestClient, tracker *IDTracker, seed testutil.SeedData) {
- // Create Permissions
- for _, perm := range seed.Permissions {
- var response struct {
- CreatePermission struct {
- ID string `json:"id"`
- } `json:"createPermission"`
- }
- query := fmt.Sprintf(`mutation { createPermission(input: {code: "%s", description: "%s"}) { id } }`, perm.Code, perm.Description)
- err := tc.client.Post(query, &response)
- if err != nil {
- t.Fatalf("Failed to create permission %s: %v", perm.Code, err)
- }
- tracker.Permissions[perm.Code] = response.CreatePermission.ID
- }
- // Create Roles
- for _, role := range seed.Roles {
- permIDs := make([]string, len(role.PermissionCodes))
- for i, code := range role.PermissionCodes {
- permIDs[i] = tracker.Permissions[code]
- }
- var response struct {
- CreateRole struct {
- ID string `json:"id"`
- } `json:"createRole"`
- }
- query := fmt.Sprintf(`mutation { createRole(input: {name: "%s", description: "%s", permissions: ["%s"]}) { id } }`, role.Name, role.Description, strings.Join(permIDs, `", "`))
- err := tc.client.Post(query, &response)
- if err != nil {
- t.Fatalf("Failed to create role %s: %v", role.Name, err)
- }
- tracker.Roles[role.Name] = response.CreateRole.ID
- }
- // Create Users
- for _, user := range seed.Users {
- roleIDs := make([]string, len(user.RoleNames))
- for i, name := range user.RoleNames {
- roleIDs[i] = tracker.Roles[name]
- }
- var response struct {
- CreateUser struct {
- ID string `json:"id"`
- } `json:"createUser"`
- }
- query := fmt.Sprintf(`mutation { createUser(input: {email: "%s", password: "%s", roles: ["%s"]}) { id } }`, user.Email, user.Password, strings.Join(roleIDs, `", "`))
- err := tc.client.Post(query, &response)
- if err != nil {
- t.Fatalf("Failed to create user %s: %v", user.Email, err)
- }
- tracker.Users[user.Email] = response.CreateUser.ID
- }
- // Create Task Statuses
- for _, status := range seed.TaskStatuses {
- var response struct {
- CreateTaskStatus struct {
- ID string `json:"id"`
- } `json:"createTaskStatus"`
- }
- query := fmt.Sprintf(`mutation { createTaskStatus(input: {code: "%s", label: "%s"}) { id } }`, status.Code, status.Label)
- err := tc.client.Post(query, &response)
- if err != nil {
- t.Fatalf("Failed to create task status %s: %v", status.Code, err)
- }
- tracker.TaskStatuses[status.Code] = response.CreateTaskStatus.ID
- }
- // Create Services
- for _, service := range seed.Services {
- participantIDs := make([]string, len(service.ParticipantEmails))
- for i, email := range service.ParticipantEmails {
- participantIDs[i] = tracker.Users[email]
- }
- var response struct {
- CreateService struct {
- ID string `json:"id"`
- } `json:"createService"`
- }
- query := fmt.Sprintf(`mutation { createService(input: {name: "%s", description: "%s", createdById: "%s", participants: ["%s"]}) { id } }`, service.Name, service.Description, tracker.Users[service.CreatorEmail], strings.Join(participantIDs, `", "`))
- err := tc.client.Post(query, &response)
- if err != nil {
- t.Fatalf("Failed to create service %s: %v", service.Name, err)
- }
- tracker.Services[service.Name] = response.CreateService.ID
- }
- // Create Tasks
- for _, task := range seed.Tasks {
- var response struct {
- CreateTask struct {
- ID string `json:"id"`
- } `json:"createTask"`
- }
- statusID := tracker.TaskStatuses[task.StatusCode]
- if task.AssigneeEmail != "" {
- query := fmt.Sprintf(`mutation { createTask(input: {title: "%s", content: "%s", createdById: "%s", assigneeId: "%s", statusId: "%s", priority: "%s"}) { id } }`, task.Title, task.Content, tracker.Users[task.CreatorEmail], tracker.Users[task.AssigneeEmail], statusID, task.Priority)
- err := tc.client.Post(query, &response)
- if err != nil {
- t.Fatalf("Failed to create task %s: %v", task.Title, err)
- }
- } else {
- query := fmt.Sprintf(`mutation { createTask(input: {title: "%s", content: "%s", createdById: "%s", statusId: "%s", priority: "%s"}) { id } }`, task.Title, task.Content, tracker.Users[task.CreatorEmail], statusID, task.Priority)
- err := tc.client.Post(query, &response)
- if err != nil {
- t.Fatalf("Failed to create task %s: %v", task.Title, err)
- }
- }
- tracker.Tasks[task.Title] = response.CreateTask.ID
- }
- // Create Notes
- for _, note := range seed.Notes {
- var response struct {
- CreateNote struct {
- ID string `json:"id"`
- } `json:"createNote"`
- }
- query := fmt.Sprintf(`mutation { createNote(input: {title: "%s", content: "%s", userId: "%s", serviceId: "%s"}) { id } }`, note.Title, note.Content, tracker.Users[note.UserEmail], tracker.Services[note.ServiceName])
- err := tc.client.Post(query, &response)
- if err != nil {
- t.Fatalf("Failed to create note %s: %v", note.Title, err)
- }
- tracker.Notes[note.Title] = response.CreateNote.ID
- }
- // Create Channels
- for _, channel := range seed.Channels {
- participantIDs := make([]string, len(channel.ParticipantEmails))
- for i, email := range channel.ParticipantEmails {
- participantIDs[i] = tracker.Users[email]
- }
- var response struct {
- CreateChannel struct {
- ID string `json:"id"`
- } `json:"createChannel"`
- }
- query := fmt.Sprintf(`mutation { createChannel(input: {participants: ["%s"]}) { id } }`, strings.Join(participantIDs, `", "`))
- err := tc.client.Post(query, &response)
- if err != nil {
- t.Fatalf("Failed to create channel: %v", err)
- }
- tracker.Channels = append(tracker.Channels, response.CreateChannel.ID)
- }
- // Create Messages
- for _, msg := range seed.Messages {
- var response struct {
- CreateMessage struct {
- ID string `json:"id"`
- } `json:"createMessage"`
- }
- query := fmt.Sprintf(`mutation { createMessage(input: {conversationId: "%s", senderId: "%s", content: "%s"}) { id } }`, tracker.Channels[msg.ChannelIndex], tracker.Users[msg.SenderEmail], msg.Content)
- err := tc.client.Post(query, &response)
- if err != nil {
- t.Fatalf("Failed to create message: %v", err)
- }
- tracker.Messages = append(tracker.Messages, response.CreateMessage.ID)
- }
- }
|