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