github.com/Desuuuu/genqlient@v0.5.3/internal/integration/integration_test.go (about) 1 // Package integration contains genqlient's integration tests, which run 2 // against a real server (defined in internal/integration/server/server.go). 3 // 4 // These are especially important for cases where we generate nontrivial logic, 5 // such as JSON-unmarshaling. 6 package integration 7 8 import ( 9 "context" 10 "net/http" 11 "testing" 12 "time" 13 14 "github.com/stretchr/testify/assert" 15 "github.com/stretchr/testify/require" 16 17 "github.com/Desuuuu/genqlient/graphql" 18 "github.com/Desuuuu/genqlient/internal/integration/server" 19 ) 20 21 func TestSimpleQuery(t *testing.T) { 22 _ = `# @genqlient 23 query simpleQuery { me { id name luckyNumber } }` 24 25 ctx := context.Background() 26 server := server.RunServer() 27 defer server.Close() 28 clients := newRoundtripClients(t, server.URL) 29 30 for _, client := range clients { 31 resp, _, err := simpleQuery(ctx, client) 32 require.NoError(t, err) 33 34 assert.Equal(t, "1", resp.Me.Id) 35 assert.Equal(t, "Yours Truly", resp.Me.Name) 36 assert.Equal(t, 17, resp.Me.LuckyNumber) 37 } 38 } 39 40 func TestMutation(t *testing.T) { 41 _ = `# @genqlient 42 mutation createUser($user: NewUser!) { createUser(input: $user) { id name } }` 43 44 ctx := context.Background() 45 server := server.RunServer() 46 defer server.Close() 47 postClient := newRoundtripClient(t, server.URL) 48 getClient := newRoundtripGetClient(t, server.URL) 49 50 resp, _, err := createUser(ctx, postClient, NewUser{Name: "Jack"}) 51 require.NoError(t, err) 52 assert.Equal(t, "5", resp.CreateUser.Id) 53 assert.Equal(t, "Jack", resp.CreateUser.Name) 54 55 _, _, err = createUser(ctx, getClient, NewUser{Name: "Jill"}) 56 require.Errorf(t, err, "client does not support mutations") 57 } 58 59 func TestServerError(t *testing.T) { 60 _ = `# @genqlient 61 query failingQuery { fail me { id } }` 62 63 ctx := context.Background() 64 server := server.RunServer() 65 defer server.Close() 66 clients := newRoundtripClients(t, server.URL) 67 68 for _, client := range clients { 69 resp, _, err := failingQuery(ctx, client) 70 // As long as we get some response back, we should still return a full 71 // response -- and indeed in this case it should even have another field 72 // (which didn't err) set. 73 assert.Error(t, err) 74 assert.NotNil(t, resp) 75 assert.Equal(t, "1", resp.Me.Id) 76 } 77 } 78 79 func TestNetworkError(t *testing.T) { 80 ctx := context.Background() 81 clients := newRoundtripClients(t, "https://nothing.invalid/graphql") 82 83 for _, client := range clients { 84 resp, _, err := failingQuery(ctx, client) 85 // As we guarantee in the README, even on network error you always get a 86 // non-nil response; this is so you can write e.g. 87 // resp, err := failingQuery(ctx) 88 // return resp.Me.Id, err 89 // without a bunch of extra ceremony. 90 assert.Error(t, err) 91 assert.NotNil(t, resp) 92 assert.Equal(t, new(failingQueryResponse), resp) 93 } 94 } 95 96 func TestVariables(t *testing.T) { 97 _ = `# @genqlient 98 query queryWithVariables($id: ID!) { user(id: $id) { id name luckyNumber } }` 99 100 ctx := context.Background() 101 server := server.RunServer() 102 defer server.Close() 103 // This doesn't roundtrip successfully because the zero user gets marshaled 104 // as {"id": "", "name": "", ...}, not null. There's really no way to do 105 // this right in Go (without adding `pointer: true` just for this purpose), 106 // and unmarshal(marshal(resp)) == resp should still hold, so we don't 107 // worry about it. 108 clients := []graphql.Client{ 109 graphql.NewClient(server.URL, http.DefaultClient), 110 graphql.NewClientUsingGet(server.URL, http.DefaultClient), 111 } 112 113 for _, client := range clients { 114 resp, _, err := queryWithVariables(ctx, client, "2") 115 require.NoError(t, err) 116 117 assert.Equal(t, "2", resp.User.Id) 118 assert.Equal(t, "Raven", resp.User.Name) 119 assert.Equal(t, -1, resp.User.LuckyNumber) 120 121 resp, _, err = queryWithVariables(ctx, client, "374892379482379") 122 require.NoError(t, err) 123 124 assert.Zero(t, resp.User) 125 } 126 } 127 128 func TestExtensions(t *testing.T) { 129 _ = `# @genqlient 130 query simpleQueryExt { me { id name luckyNumber } }` 131 132 ctx := context.Background() 133 server := server.RunServer() 134 defer server.Close() 135 clients := newRoundtripClients(t, server.URL) 136 137 for _, client := range clients { 138 _, extensions, err := simpleQueryExt(ctx, client) 139 require.NoError(t, err) 140 assert.NotNil(t, extensions) 141 assert.Equal(t, extensions["foobar"], "test") 142 } 143 } 144 145 func TestOmitempty(t *testing.T) { 146 _ = `# @genqlient(omitempty: true) 147 query queryWithOmitempty($id: ID) { 148 user(id: $id) { id name luckyNumber } 149 }` 150 151 ctx := context.Background() 152 server := server.RunServer() 153 defer server.Close() 154 clients := newRoundtripClients(t, server.URL) 155 156 for _, client := range clients { 157 resp, _, err := queryWithOmitempty(ctx, client, "2") 158 require.NoError(t, err) 159 160 assert.Equal(t, "2", resp.User.Id) 161 assert.Equal(t, "Raven", resp.User.Name) 162 assert.Equal(t, -1, resp.User.LuckyNumber) 163 164 // should return default user, not the user with ID "" 165 resp, _, err = queryWithOmitempty(ctx, client, "") 166 require.NoError(t, err) 167 168 assert.Equal(t, "1", resp.User.Id) 169 assert.Equal(t, "Yours Truly", resp.User.Name) 170 assert.Equal(t, 17, resp.User.LuckyNumber) 171 } 172 } 173 174 func TestCustomMarshal(t *testing.T) { 175 _ = `# @genqlient 176 query queryWithCustomMarshal($date: Date!) { 177 usersBornOn(date: $date) { id name birthdate } 178 }` 179 180 ctx := context.Background() 181 server := server.RunServer() 182 defer server.Close() 183 clients := newRoundtripClients(t, server.URL) 184 185 for _, client := range clients { 186 resp, _, err := queryWithCustomMarshal(ctx, client, 187 time.Date(2025, time.January, 1, 12, 34, 56, 789, time.UTC)) 188 require.NoError(t, err) 189 190 assert.Len(t, resp.UsersBornOn, 1) 191 user := resp.UsersBornOn[0] 192 assert.Equal(t, "1", user.Id) 193 assert.Equal(t, "Yours Truly", user.Name) 194 assert.Equal(t, 195 time.Date(2025, time.January, 1, 0, 0, 0, 0, time.UTC), 196 user.Birthdate) 197 198 resp, _, err = queryWithCustomMarshal(ctx, client, 199 time.Date(2021, time.January, 1, 12, 34, 56, 789, time.UTC)) 200 require.NoError(t, err) 201 assert.Len(t, resp.UsersBornOn, 0) 202 } 203 } 204 205 func TestCustomMarshalSlice(t *testing.T) { 206 _ = `# @genqlient 207 query queryWithCustomMarshalSlice($dates: [Date!]!) { 208 usersBornOnDates(dates: $dates) { id name birthdate } 209 }` 210 211 ctx := context.Background() 212 server := server.RunServer() 213 defer server.Close() 214 clients := newRoundtripClients(t, server.URL) 215 216 for _, client := range clients { 217 resp, _, err := queryWithCustomMarshalSlice(ctx, client, 218 []time.Time{time.Date(2025, time.January, 1, 12, 34, 56, 789, time.UTC)}) 219 require.NoError(t, err) 220 221 assert.Len(t, resp.UsersBornOnDates, 1) 222 user := resp.UsersBornOnDates[0] 223 assert.Equal(t, "1", user.Id) 224 assert.Equal(t, "Yours Truly", user.Name) 225 assert.Equal(t, 226 time.Date(2025, time.January, 1, 0, 0, 0, 0, time.UTC), 227 user.Birthdate) 228 229 resp, _, err = queryWithCustomMarshalSlice(ctx, client, 230 []time.Time{time.Date(2021, time.January, 1, 12, 34, 56, 789, time.UTC)}) 231 require.NoError(t, err) 232 assert.Len(t, resp.UsersBornOnDates, 0) 233 } 234 } 235 236 func TestCustomMarshalOptional(t *testing.T) { 237 _ = `# @genqlient 238 query queryWithCustomMarshalOptional( 239 # @genqlient(pointer: true) 240 $date: Date, 241 # @genqlient(pointer: true) 242 $id: ID, 243 ) { 244 userSearch(birthdate: $date, id: $id) { id name birthdate } 245 }` 246 247 ctx := context.Background() 248 server := server.RunServer() 249 defer server.Close() 250 clients := newRoundtripClients(t, server.URL) 251 252 for _, client := range clients { 253 date := time.Date(2025, time.January, 1, 12, 34, 56, 789, time.UTC) 254 resp, _, err := queryWithCustomMarshalOptional(ctx, client, &date, nil) 255 require.NoError(t, err) 256 257 assert.Len(t, resp.UserSearch, 1) 258 user := resp.UserSearch[0] 259 assert.Equal(t, "1", user.Id) 260 assert.Equal(t, "Yours Truly", user.Name) 261 assert.Equal(t, 262 time.Date(2025, time.January, 1, 0, 0, 0, 0, time.UTC), 263 user.Birthdate) 264 265 id := "2" 266 resp, _, err = queryWithCustomMarshalOptional(ctx, client, nil, &id) 267 require.NoError(t, err) 268 assert.Len(t, resp.UserSearch, 1) 269 user = resp.UserSearch[0] 270 assert.Equal(t, "2", user.Id) 271 assert.Equal(t, "Raven", user.Name) 272 assert.Zero(t, user.Birthdate) 273 } 274 } 275 276 func TestInterfaceNoFragments(t *testing.T) { 277 _ = `# @genqlient 278 query queryWithInterfaceNoFragments($id: ID!) { 279 being(id: $id) { id name } 280 me { id name } 281 }` 282 283 ctx := context.Background() 284 server := server.RunServer() 285 defer server.Close() 286 clients := newRoundtripClients(t, server.URL) 287 288 for _, client := range clients { 289 resp, _, err := queryWithInterfaceNoFragments(ctx, client, "1") 290 require.NoError(t, err) 291 292 // We should get the following response: 293 // me: User{Id: 1, Name: "Yours Truly"}, 294 // being: User{Id: 1, Name: "Yours Truly"}, 295 296 assert.Equal(t, "1", resp.Me.Id) 297 assert.Equal(t, "Yours Truly", resp.Me.Name) 298 299 // Check fields both via interface and via type-assertion: 300 assert.Equal(t, "User", resp.Being.GetTypename()) 301 assert.Equal(t, "1", resp.Being.GetId()) 302 assert.Equal(t, "Yours Truly", resp.Being.GetName()) 303 304 user, ok := resp.Being.(*queryWithInterfaceNoFragmentsBeingUser) 305 require.Truef(t, ok, "got %T, not User", resp.Being) 306 assert.Equal(t, "1", user.Id) 307 assert.Equal(t, "Yours Truly", user.Name) 308 309 resp, _, err = queryWithInterfaceNoFragments(ctx, client, "3") 310 require.NoError(t, err) 311 312 // We should get the following response: 313 // me: User{Id: 1, Name: "Yours Truly"}, 314 // being: Animal{Id: 3, Name: "Fido"}, 315 316 assert.Equal(t, "1", resp.Me.Id) 317 assert.Equal(t, "Yours Truly", resp.Me.Name) 318 319 assert.Equal(t, "Animal", resp.Being.GetTypename()) 320 assert.Equal(t, "3", resp.Being.GetId()) 321 assert.Equal(t, "Fido", resp.Being.GetName()) 322 323 animal, ok := resp.Being.(*queryWithInterfaceNoFragmentsBeingAnimal) 324 require.Truef(t, ok, "got %T, not Animal", resp.Being) 325 assert.Equal(t, "3", animal.Id) 326 assert.Equal(t, "Fido", animal.Name) 327 328 resp, _, err = queryWithInterfaceNoFragments(ctx, client, "4757233945723") 329 require.NoError(t, err) 330 331 // We should get the following response: 332 // me: User{Id: 1, Name: "Yours Truly"}, 333 // being: null 334 335 assert.Equal(t, "1", resp.Me.Id) 336 assert.Equal(t, "Yours Truly", resp.Me.Name) 337 338 assert.Nil(t, resp.Being) 339 } 340 } 341 342 func TestInterfaceListField(t *testing.T) { 343 _ = `# @genqlient 344 query queryWithInterfaceListField($ids: [ID!]!) { 345 beings(ids: $ids) { id name } 346 }` 347 348 ctx := context.Background() 349 server := server.RunServer() 350 defer server.Close() 351 clients := newRoundtripClients(t, server.URL) 352 353 for _, client := range clients { 354 resp, _, err := queryWithInterfaceListField(ctx, client, 355 []string{"1", "3", "12847394823"}) 356 require.NoError(t, err) 357 358 require.Len(t, resp.Beings, 3) 359 360 // We should get the following three beings: 361 // User{Id: 1, Name: "Yours Truly"}, 362 // Animal{Id: 3, Name: "Fido"}, 363 // null 364 365 // Check fields both via interface and via type-assertion: 366 assert.Equal(t, "User", resp.Beings[0].GetTypename()) 367 assert.Equal(t, "1", resp.Beings[0].GetId()) 368 assert.Equal(t, "Yours Truly", resp.Beings[0].GetName()) 369 370 user, ok := resp.Beings[0].(*queryWithInterfaceListFieldBeingsUser) 371 require.Truef(t, ok, "got %T, not User", resp.Beings[0]) 372 assert.Equal(t, "1", user.Id) 373 assert.Equal(t, "Yours Truly", user.Name) 374 375 assert.Equal(t, "Animal", resp.Beings[1].GetTypename()) 376 assert.Equal(t, "3", resp.Beings[1].GetId()) 377 assert.Equal(t, "Fido", resp.Beings[1].GetName()) 378 379 animal, ok := resp.Beings[1].(*queryWithInterfaceListFieldBeingsAnimal) 380 require.Truef(t, ok, "got %T, not Animal", resp.Beings[1]) 381 assert.Equal(t, "3", animal.Id) 382 assert.Equal(t, "Fido", animal.Name) 383 384 assert.Nil(t, resp.Beings[2]) 385 } 386 } 387 388 func TestInterfaceListPointerField(t *testing.T) { 389 _ = `# @genqlient 390 query queryWithInterfaceListPointerField($ids: [ID!]!) { 391 # @genqlient(pointer: true) 392 beings(ids: $ids) { 393 __typename id name 394 } 395 }` 396 397 ctx := context.Background() 398 server := server.RunServer() 399 defer server.Close() 400 clients := newRoundtripClients(t, server.URL) 401 402 for _, client := range clients { 403 resp, _, err := queryWithInterfaceListPointerField(ctx, client, 404 []string{"1", "3", "12847394823"}) 405 require.NoError(t, err) 406 407 require.Len(t, resp.Beings, 3) 408 409 // Check fields both via interface and via type-assertion: 410 assert.Equal(t, "User", (*resp.Beings[0]).GetTypename()) 411 assert.Equal(t, "1", (*resp.Beings[0]).GetId()) 412 assert.Equal(t, "Yours Truly", (*resp.Beings[0]).GetName()) 413 414 user, ok := (*resp.Beings[0]).(*queryWithInterfaceListPointerFieldBeingsUser) 415 require.Truef(t, ok, "got %T, not User", *resp.Beings[0]) 416 assert.Equal(t, "1", user.Id) 417 assert.Equal(t, "Yours Truly", user.Name) 418 419 assert.Equal(t, "Animal", (*resp.Beings[1]).GetTypename()) 420 assert.Equal(t, "3", (*resp.Beings[1]).GetId()) 421 assert.Equal(t, "Fido", (*resp.Beings[1]).GetName()) 422 423 animal, ok := (*resp.Beings[1]).(*queryWithInterfaceListPointerFieldBeingsAnimal) 424 require.Truef(t, ok, "got %T, not Animal", resp.Beings[1]) 425 assert.Equal(t, "3", animal.Id) 426 assert.Equal(t, "Fido", animal.Name) 427 428 assert.Nil(t, resp.Beings[2]) 429 } 430 } 431 432 func TestFragments(t *testing.T) { 433 _ = `# @genqlient 434 query queryWithFragments($ids: [ID!]!) { 435 beings(ids: $ids) { 436 __typename id 437 ... on Being { id name } 438 ... on Animal { 439 id 440 hair { hasHair } 441 species 442 owner { 443 id 444 ... on Being { name } 445 ... on User { luckyNumber } 446 } 447 } 448 ... on Lucky { luckyNumber } 449 ... on User { hair { color } } 450 } 451 }` 452 453 ctx := context.Background() 454 server := server.RunServer() 455 defer server.Close() 456 clients := newRoundtripClients(t, server.URL) 457 458 for _, client := range clients { 459 resp, _, err := queryWithFragments(ctx, client, []string{"1", "3", "12847394823"}) 460 require.NoError(t, err) 461 462 require.Len(t, resp.Beings, 3) 463 464 // We should get the following three beings: 465 // User{Id: 1, Name: "Yours Truly"}, 466 // Animal{Id: 3, Name: "Fido"}, 467 // null 468 469 // Check fields both via interface and via type-assertion when possible 470 // User has, in total, the fields: __typename id name luckyNumber. 471 assert.Equal(t, "User", resp.Beings[0].GetTypename()) 472 assert.Equal(t, "1", resp.Beings[0].GetId()) 473 assert.Equal(t, "Yours Truly", resp.Beings[0].GetName()) 474 // (hair and luckyNumber we need to cast for) 475 476 user, ok := resp.Beings[0].(*queryWithFragmentsBeingsUser) 477 require.Truef(t, ok, "got %T, not User", resp.Beings[0]) 478 assert.Equal(t, "1", user.Id) 479 assert.Equal(t, "Yours Truly", user.Name) 480 assert.Equal(t, "Black", user.Hair.Color) 481 assert.Equal(t, 17, user.LuckyNumber) 482 483 // Animal has, in total, the fields: 484 // __typename 485 // id 486 // species 487 // owner { 488 // id 489 // name 490 // ... on User { luckyNumber } 491 // } 492 assert.Equal(t, "Animal", resp.Beings[1].GetTypename()) 493 assert.Equal(t, "3", resp.Beings[1].GetId()) 494 // (hair, species, and owner.* we have to cast for) 495 496 animal, ok := resp.Beings[1].(*queryWithFragmentsBeingsAnimal) 497 require.Truef(t, ok, "got %T, not Animal", resp.Beings[1]) 498 assert.Equal(t, "3", animal.Id) 499 assert.Equal(t, SpeciesDog, animal.Species) 500 assert.True(t, animal.Hair.HasHair) 501 502 assert.Equal(t, "1", animal.Owner.GetId()) 503 assert.Equal(t, "Yours Truly", animal.Owner.GetName()) 504 // (luckyNumber we have to cast for, again) 505 506 owner, ok := animal.Owner.(*queryWithFragmentsBeingsAnimalOwnerUser) 507 require.Truef(t, ok, "got %T, not User", animal.Owner) 508 assert.Equal(t, "1", owner.Id) 509 assert.Equal(t, "Yours Truly", owner.Name) 510 assert.Equal(t, 17, owner.LuckyNumber) 511 512 assert.Nil(t, resp.Beings[2]) 513 } 514 } 515 516 func TestNamedFragments(t *testing.T) { 517 _ = `# @genqlient 518 fragment AnimalFields on Animal { 519 id 520 hair { hasHair } 521 owner { id ...UserFields ...LuckyFields } 522 } 523 524 fragment MoreUserFields on User { 525 id 526 hair { color } 527 } 528 529 fragment LuckyFields on Lucky { 530 ...MoreUserFields 531 luckyNumber 532 } 533 534 fragment UserFields on User { 535 id 536 ...LuckyFields 537 ...MoreUserFields 538 } 539 540 query queryWithNamedFragments($ids: [ID!]!) { 541 beings(ids: $ids) { 542 __typename id 543 ...AnimalFields 544 ...UserFields 545 } 546 }` 547 548 ctx := context.Background() 549 server := server.RunServer() 550 defer server.Close() 551 clients := newRoundtripClients(t, server.URL) 552 553 for _, client := range clients { 554 resp, _, err := queryWithNamedFragments(ctx, client, []string{"1", "3", "12847394823"}) 555 require.NoError(t, err) 556 557 require.Len(t, resp.Beings, 3) 558 559 // We should get the following three beings: 560 // User{Id: 1, Name: "Yours Truly"}, 561 // Animal{Id: 3, Name: "Fido"}, 562 // null 563 564 // Check fields both via interface and via type-assertion when possible 565 // User has, in total, the fields: __typename id luckyNumber. 566 assert.Equal(t, "User", resp.Beings[0].GetTypename()) 567 assert.Equal(t, "1", resp.Beings[0].GetId()) 568 // (luckyNumber, hair we need to cast for) 569 570 user, ok := resp.Beings[0].(*queryWithNamedFragmentsBeingsUser) 571 require.Truef(t, ok, "got %T, not User", resp.Beings[0]) 572 assert.Equal(t, "1", user.Id) 573 assert.Equal(t, "1", user.UserFields.Id) 574 assert.Equal(t, "1", user.UserFields.MoreUserFields.Id) 575 assert.Equal(t, "1", user.UserFields.LuckyFieldsUser.MoreUserFields.Id) 576 // on UserFields, but we should be able to access directly via embedding: 577 assert.Equal(t, 17, user.LuckyNumber) 578 assert.Equal(t, "Black", user.Hair.Color) 579 assert.Equal(t, "Black", user.UserFields.MoreUserFields.Hair.Color) 580 assert.Equal(t, "Black", user.UserFields.LuckyFieldsUser.MoreUserFields.Hair.Color) 581 582 // Animal has, in total, the fields: 583 // __typename 584 // id 585 // hair { hasHair } 586 // owner { id luckyNumber } 587 assert.Equal(t, "Animal", resp.Beings[1].GetTypename()) 588 assert.Equal(t, "3", resp.Beings[1].GetId()) 589 // (hair.* and owner.* we have to cast for) 590 591 animal, ok := resp.Beings[1].(*queryWithNamedFragmentsBeingsAnimal) 592 require.Truef(t, ok, "got %T, not Animal", resp.Beings[1]) 593 // Check that we filled in *both* ID fields: 594 assert.Equal(t, "3", animal.Id) 595 assert.Equal(t, "3", animal.AnimalFields.Id) 596 // on AnimalFields: 597 assert.True(t, animal.Hair.HasHair) 598 assert.Equal(t, "1", animal.Owner.GetId()) 599 // (luckyNumber we have to cast for, again) 600 601 owner, ok := animal.Owner.(*AnimalFieldsOwnerUser) 602 require.Truef(t, ok, "got %T, not User", animal.Owner) 603 // Check that we filled in *both* ID fields: 604 assert.Equal(t, "1", owner.Id) 605 assert.Equal(t, "1", owner.UserFields.Id) 606 assert.Equal(t, "1", owner.UserFields.MoreUserFields.Id) 607 assert.Equal(t, "1", owner.UserFields.LuckyFieldsUser.MoreUserFields.Id) 608 // on UserFields: 609 assert.Equal(t, 17, owner.LuckyNumber) 610 assert.Equal(t, "Black", owner.UserFields.MoreUserFields.Hair.Color) 611 assert.Equal(t, "Black", owner.UserFields.LuckyFieldsUser.MoreUserFields.Hair.Color) 612 613 // Lucky-based fields we can also get by casting to the fragment-interface. 614 luckyOwner, ok := animal.Owner.(LuckyFields) 615 require.Truef(t, ok, "got %T, not Lucky", animal.Owner) 616 assert.Equal(t, 17, luckyOwner.GetLuckyNumber()) 617 618 assert.Nil(t, resp.Beings[2]) 619 } 620 } 621 622 func TestFlatten(t *testing.T) { 623 _ = `# @genqlient 624 # @genqlient(flatten: true) 625 fragment BeingFields on Being { 626 ...InnerBeingFields 627 } 628 629 fragment InnerBeingFields on Being { 630 id 631 name 632 ... on User { 633 # @genqlient(flatten: true) 634 friends { 635 ...FriendsFields 636 } 637 } 638 } 639 640 fragment FriendsFields on User { 641 id 642 name 643 } 644 645 # @genqlient(flatten: true) 646 fragment FlattenedUserFields on User { 647 ...FlattenedLuckyFields 648 } 649 650 # @genqlient(flatten: true) 651 fragment FlattenedLuckyFields on Lucky { 652 ...InnerLuckyFields 653 } 654 655 fragment InnerLuckyFields on Lucky { 656 luckyNumber 657 } 658 659 fragment QueryFragment on Query { 660 beings(ids: $ids) { 661 __typename id 662 ...FlattenedUserFields 663 ... on Animal { 664 # @genqlient(flatten: true) 665 owner { 666 ...BeingFields 667 } 668 } 669 } 670 } 671 672 # @genqlient(flatten: true) 673 query queryWithFlatten( 674 $ids: [ID!]!, 675 ) { 676 ...QueryFragment 677 }` 678 679 ctx := context.Background() 680 server := server.RunServer() 681 defer server.Close() 682 clients := newRoundtripClients(t, server.URL) 683 684 for _, client := range clients { 685 resp, _, err := queryWithFlatten(ctx, client, []string{"1", "3", "12847394823"}) 686 require.NoError(t, err) 687 688 require.Len(t, resp.Beings, 3) 689 690 // We should get the following three beings: 691 // User{Id: 1, Name: "Yours Truly"}, 692 // Animal{Id: 3, Name: "Fido"}, 693 // null 694 695 // Check fields both via interface and via type-assertion when possible 696 // User has, in total, the fields: __typename id luckyNumber. 697 assert.Equal(t, "User", resp.Beings[0].GetTypename()) 698 assert.Equal(t, "1", resp.Beings[0].GetId()) 699 // (luckyNumber we need to cast for) 700 701 user, ok := resp.Beings[0].(*QueryFragmentBeingsUser) 702 require.Truef(t, ok, "got %T, not User", resp.Beings[0]) 703 assert.Equal(t, "1", user.Id) 704 assert.Equal(t, 17, user.InnerLuckyFieldsUser.LuckyNumber) 705 706 // Animal has, in total, the fields: 707 // __typename 708 // id 709 // owner { id name ... on User { friends { id name } } } 710 assert.Equal(t, "Animal", resp.Beings[1].GetTypename()) 711 assert.Equal(t, "3", resp.Beings[1].GetId()) 712 // (owner.* we have to cast for) 713 714 animal, ok := resp.Beings[1].(*QueryFragmentBeingsAnimal) 715 require.Truef(t, ok, "got %T, not Animal", resp.Beings[1]) 716 assert.Equal(t, "3", animal.Id) 717 // on AnimalFields: 718 assert.Equal(t, "1", animal.Owner.GetId()) 719 assert.Equal(t, "Yours Truly", animal.Owner.GetName()) 720 // (friends.* we have to cast for, again) 721 722 owner, ok := animal.Owner.(*InnerBeingFieldsUser) 723 require.Truef(t, ok, "got %T, not User", animal.Owner) 724 assert.Equal(t, "1", owner.Id) 725 assert.Equal(t, "Yours Truly", owner.Name) 726 assert.Len(t, owner.Friends, 1) 727 assert.Equal(t, "2", owner.Friends[0].Id) 728 assert.Equal(t, "Raven", owner.Friends[0].Name) 729 730 assert.Nil(t, resp.Beings[2]) 731 } 732 } 733 734 func TestGeneratedCode(t *testing.T) { 735 // TODO(benkraft): Check that gqlgen is up to date too. In practice that's 736 // less likely to be a problem, since it should only change if you update 737 // the schema, likely too add something new, in which case you'll notice. 738 RunGenerateTest(t, "internal/integration/genqlient.yaml") 739 } 740 741 //go:generate go run github.com/Desuuuu/genqlient genqlient.yaml