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