...

Source file src/github.com/vektah/gqlparser/v2/validator/vars_test.go

Documentation: github.com/vektah/gqlparser/v2/validator

     1  package validator_test
     2  
     3  import (
     4  	"os"
     5  	"testing"
     6  
     7  	"github.com/stretchr/testify/require"
     8  
     9  	"github.com/vektah/gqlparser/v2"
    10  	"github.com/vektah/gqlparser/v2/ast"
    11  	"github.com/vektah/gqlparser/v2/validator"
    12  )
    13  
    14  func TestValidateVars(t *testing.T) {
    15  	schema := gqlparser.MustLoadSchema(&ast.Source{
    16  		Name:  "vars.graphql",
    17  		Input: mustReadFile("./testdata/vars.graphql"),
    18  	})
    19  
    20  	t.Run("undefined variable", func(t *testing.T) {
    21  		t.Run("without default", func(t *testing.T) {
    22  			q := gqlparser.MustLoadQuery(schema, `query($id: Int!) { intArg(i: $id) }`)
    23  			_, gerr := validator.VariableValues(schema, q.Operations.ForName(""), nil)
    24  			require.EqualError(t, gerr, "input: variable.id must be defined")
    25  		})
    26  
    27  		t.Run("nil in required value", func(t *testing.T) {
    28  			q := gqlparser.MustLoadQuery(schema, `query($id: Int!) { intArg(i: $id) }`)
    29  			_, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{
    30  				"id": nil,
    31  			})
    32  			require.EqualError(t, gerr, "input: variable.id cannot be null")
    33  		})
    34  
    35  		t.Run("with default", func(t *testing.T) {
    36  			q := gqlparser.MustLoadQuery(schema, `query($id: Int! = 1) { intArg(i: $id) }`)
    37  			vars, gerr := validator.VariableValues(schema, q.Operations.ForName(""), nil)
    38  			require.Nil(t, gerr)
    39  			require.EqualValues(t, 1, vars["id"])
    40  		})
    41  
    42  		t.Run("with union", func(t *testing.T) {
    43  			q := gqlparser.MustLoadQuery(schema, `query($id: Int! = 1) { intArg(i: $id) }`)
    44  			vars, gerr := validator.VariableValues(schema, q.Operations.ForName(""), nil)
    45  			require.Nil(t, gerr)
    46  			require.EqualValues(t, 1, vars["id"])
    47  		})
    48  	})
    49  
    50  	t.Run("input object", func(t *testing.T) {
    51  		t.Run("non object", func(t *testing.T) {
    52  			q := gqlparser.MustLoadQuery(schema, `query foo($var: InputType!) { structArg(i: $var) }`)
    53  			_, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{
    54  				"var": "hello",
    55  			})
    56  			require.EqualError(t, gerr, "input: variable.var must be a InputType")
    57  		})
    58  
    59  		t.Run("defaults", func(t *testing.T) {
    60  			q := gqlparser.MustLoadQuery(schema, `query foo($var: InputType! = {name: "foo"}) { structArg(i: $var) }`)
    61  			vars, gerr := validator.VariableValues(schema, q.Operations.ForName(""), nil)
    62  			require.Nil(t, gerr)
    63  			require.EqualValues(t, map[string]interface{}{"name": "foo"}, vars["var"])
    64  		})
    65  
    66  		t.Run("valid value", func(t *testing.T) {
    67  			q := gqlparser.MustLoadQuery(schema, `query foo($var: InputType!) { structArg(i: $var) }`)
    68  			vars, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{
    69  				"var": map[string]interface{}{
    70  					"name": "foobar",
    71  				},
    72  			})
    73  			require.Nil(t, gerr)
    74  			require.EqualValues(t, map[string]interface{}{"name": "foobar"}, vars["var"])
    75  		})
    76  
    77  		t.Run("null object field", func(t *testing.T) {
    78  			q := gqlparser.MustLoadQuery(schema, `query foo($var: InputType!) { structArg(i: $var) }`)
    79  			vars, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{
    80  				"var": map[string]interface{}{
    81  					"name":     "foobar",
    82  					"nullName": nil,
    83  				},
    84  			})
    85  			require.Nil(t, gerr)
    86  			require.EqualValues(t, map[string]interface{}{"name": "foobar", "nullName": nil}, vars["var"])
    87  		})
    88  
    89  		t.Run("missing required values", func(t *testing.T) {
    90  			q := gqlparser.MustLoadQuery(schema, `query foo($var: InputType!) { structArg(i: $var) }`)
    91  			_, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{
    92  				"var": map[string]interface{}{},
    93  			})
    94  			require.EqualError(t, gerr, "input: variable.var.name must be defined")
    95  		})
    96  
    97  		t.Run("null required field", func(t *testing.T) {
    98  			q := gqlparser.MustLoadQuery(schema, `query foo($var: InputType!) { structArg(i: $var) }`)
    99  			_, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{
   100  				"var": map[string]interface{}{
   101  					"name": nil,
   102  				},
   103  			})
   104  			require.EqualError(t, gerr, "input: variable.var.name cannot be null")
   105  		})
   106  
   107  		t.Run("null embedded input object", func(t *testing.T) {
   108  			q := gqlparser.MustLoadQuery(schema, `query foo($var: InputType!) { structArg(i: $var) }`)
   109  			_, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{
   110  				"var": map[string]interface{}{
   111  					"name":         "foo",
   112  					"nullEmbedded": nil,
   113  				},
   114  			})
   115  			require.Nil(t, gerr)
   116  		})
   117  
   118  		t.Run("unknown field", func(t *testing.T) {
   119  			q := gqlparser.MustLoadQuery(schema, `query foo($var: InputType!) { structArg(i: $var) }`)
   120  			_, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{
   121  				"var": map[string]interface{}{
   122  					"name":    "foobar",
   123  					"foobard": true,
   124  				},
   125  			})
   126  			require.EqualError(t, gerr, "input: variable.var.foobard unknown field")
   127  		})
   128  
   129  		t.Run("unknown __typefield", func(t *testing.T) {
   130  			q := gqlparser.MustLoadQuery(schema, `query foo($var: InputType!) { structArg(i: $var) }`)
   131  			vars, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{
   132  				"var": map[string]interface{}{
   133  					"name":       "foobar",
   134  					"__typename": "InputType",
   135  				},
   136  			})
   137  			require.Nil(t, gerr)
   138  			require.EqualValues(t, map[string]interface{}{"__typename": "InputType", "name": "foobar"}, vars["var"])
   139  
   140  		})
   141  
   142  		t.Run("enum input object", func(t *testing.T) {
   143  			q := gqlparser.MustLoadQuery(schema, `query foo($var: InputType!) { structArg(i: $var) }`)
   144  			_, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{
   145  				"var": map[string]interface{}{
   146  					"name": "foobar",
   147  					"enum": "A",
   148  				},
   149  			})
   150  			require.Nil(t, gerr)
   151  		})
   152  
   153  		t.Run("unknown enum value input object", func(t *testing.T) {
   154  			q := gqlparser.MustLoadQuery(schema, `query foo($var: InputType!) { structArg(i: $var) }`)
   155  			_, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{
   156  				"var": map[string]interface{}{
   157  					"name": "foobar",
   158  					"enum": "B",
   159  				},
   160  			})
   161  			require.EqualError(t, gerr, "input: variable.var.enum B is not a valid Enum")
   162  		})
   163  	})
   164  
   165  	t.Run("array", func(t *testing.T) {
   166  		t.Run("non-null object value should be coerced to an array", func(t *testing.T) {
   167  			q := gqlparser.MustLoadQuery(schema, `query foo($var: [InputType!]) { arrayArg(i: $var) }`)
   168  			vars, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{
   169  				"var": map[string]interface{}{"name": "hello"},
   170  			})
   171  			require.Nil(t, gerr)
   172  			require.EqualValues(t, []map[string]interface{}{{"name": "hello"}}, vars["var"])
   173  		})
   174  
   175  		t.Run("non-null int value should be coerced to an array", func(t *testing.T) {
   176  			q := gqlparser.MustLoadQuery(schema, `query foo($var: [Int!]) { intArrayArg(i: $var) }`)
   177  			vars, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{
   178  				"var": 5,
   179  			})
   180  			require.Nil(t, gerr)
   181  			expected := []int{5}
   182  			require.EqualValues(t, expected, vars["var"])
   183  		})
   184  
   185  		t.Run("non-null int deep value should be coerced to an array", func(t *testing.T) {
   186  			q := gqlparser.MustLoadQuery(schema, `query foo($var: [CustomType]) { typeArrayArg(i: $var) }`)
   187  			vars, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{
   188  				"var": []map[string]interface{}{{"and": 5}},
   189  			})
   190  			require.Nil(t, gerr)
   191  			expected := []map[string]interface{}{{"and": []int{5}}}
   192  			require.EqualValues(t, expected, vars["var"])
   193  		})
   194  
   195  		t.Run("defaults", func(t *testing.T) {
   196  			q := gqlparser.MustLoadQuery(schema, `query foo($var: [InputType!] = [{name: "foo"}]) { arrayArg(i: $var) }`)
   197  			vars, gerr := validator.VariableValues(schema, q.Operations.ForName(""), nil)
   198  			require.Nil(t, gerr)
   199  			require.EqualValues(t, []interface{}{map[string]interface{}{
   200  				"name": "foo",
   201  			}}, vars["var"])
   202  		})
   203  
   204  		t.Run("valid value", func(t *testing.T) {
   205  			q := gqlparser.MustLoadQuery(schema, `query foo($var: [InputType!]) { arrayArg(i: $var) }`)
   206  			vars, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{
   207  				"var": []interface{}{map[string]interface{}{
   208  					"name": "foo",
   209  				}},
   210  			})
   211  			require.Nil(t, gerr)
   212  			require.EqualValues(t, []interface{}{map[string]interface{}{
   213  				"name": "foo",
   214  			}}, vars["var"])
   215  		})
   216  
   217  		t.Run("null element value", func(t *testing.T) {
   218  			q := gqlparser.MustLoadQuery(schema, `query foo($var: [InputType!]) { arrayArg(i: $var) }`)
   219  			_, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{
   220  				"var": []interface{}{nil},
   221  			})
   222  			require.EqualError(t, gerr, "input: variable.var[0] cannot be null")
   223  		})
   224  
   225  		t.Run("missing required values", func(t *testing.T) {
   226  			q := gqlparser.MustLoadQuery(schema, `query foo($var: [InputType!]) { arrayArg(i: $var) }`)
   227  			_, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{
   228  				"var": []interface{}{map[string]interface{}{}},
   229  			})
   230  			require.EqualError(t, gerr, "input: variable.var[0].name must be defined")
   231  		})
   232  		t.Run("invalid variable paths", func(t *testing.T) {
   233  			q := gqlparser.MustLoadQuery(schema, `query foo($var1: InputType!, $var2: InputType!) { a:structArg(i: $var1) b:structArg(i: $var2) }`)
   234  			_, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{
   235  				"var1": map[string]interface{}{
   236  					"name": "foobar",
   237  				},
   238  				"var2": map[string]interface{}{
   239  					"nullName": "foobar",
   240  				},
   241  			})
   242  			require.EqualError(t, gerr, "input: variable.var2.name must be defined")
   243  		})
   244  	})
   245  
   246  	t.Run("Scalars", func(t *testing.T) {
   247  		t.Run("String -> String", func(t *testing.T) {
   248  			q := gqlparser.MustLoadQuery(schema, `query foo($var: String!) { stringArg(i: $var) }`)
   249  			vars, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{
   250  				"var": "asdf",
   251  			})
   252  			require.Nil(t, gerr)
   253  			require.EqualValues(t, "asdf", vars["var"])
   254  		})
   255  
   256  		t.Run("Int -> String", func(t *testing.T) {
   257  			q := gqlparser.MustLoadQuery(schema, `query foo($var: String!) { stringArg(i: $var) }`)
   258  			_, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{
   259  				"var": 1,
   260  			})
   261  			require.EqualError(t, gerr, "input: variable.var cannot use int as String")
   262  		})
   263  
   264  		t.Run("Nil -> String", func(t *testing.T) {
   265  			q := gqlparser.MustLoadQuery(schema, `query foo($var: String!) { stringArg(i: $var) }`)
   266  			_, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{
   267  				"var": nil,
   268  			})
   269  			require.EqualError(t, gerr, "input: variable.var cannot be null")
   270  		})
   271  
   272  		t.Run("Undefined -> String!", func(t *testing.T) {
   273  			q := gqlparser.MustLoadQuery(schema, `query foo($var: String!) { stringArg(i: $var) }`)
   274  			_, gerr := validator.VariableValues(schema, q.Operations.ForName(""), nil)
   275  			require.EqualError(t, gerr, "input: variable.var must be defined")
   276  		})
   277  
   278  		t.Run("Undefined -> Int", func(t *testing.T) {
   279  			q := gqlparser.MustLoadQuery(schema, `query foo($var: Int) { optionalIntArg(i: $var) }`)
   280  			_, gerr := validator.VariableValues(schema, q.Operations.ForName(""), nil)
   281  			require.Nil(t, gerr)
   282  		})
   283  
   284  		t.Run("Json Number -> Int", func(t *testing.T) {
   285  			q := gqlparser.MustLoadQuery(schema, `query foo($var: Int) { optionalIntArg(i: $var) }`)
   286  			vars, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{
   287  				"var": 10,
   288  			})
   289  			require.Nil(t, gerr)
   290  			require.Equal(t, 10, vars["var"])
   291  		})
   292  
   293  		t.Run("Json Number -> Float", func(t *testing.T) {
   294  			q := gqlparser.MustLoadQuery(schema, `query foo($var: Float!) { floatArg(i: $var) }`)
   295  			vars, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{
   296  				"var": 10.2,
   297  			})
   298  			require.Nil(t, gerr)
   299  			require.Equal(t, 10.2, vars["var"])
   300  		})
   301  
   302  		t.Run("Nil -> Int", func(t *testing.T) {
   303  			q := gqlparser.MustLoadQuery(schema, `query foo($var: Int) { optionalIntArg(i: $var) }`)
   304  			vars, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{
   305  				"var": nil,
   306  			})
   307  			require.Nil(t, gerr)
   308  			require.Equal(t, nil, vars["var"])
   309  		})
   310  
   311  		t.Run("Bool -> Int", func(t *testing.T) {
   312  			q := gqlparser.MustLoadQuery(schema, `query foo($var: Int!) { intArg(i: $var) }`)
   313  			_, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{
   314  				"var": true,
   315  			})
   316  			require.EqualError(t, gerr, "input: variable.var cannot use bool as Int")
   317  		})
   318  	})
   319  
   320  	t.Run("Int Array", func(t *testing.T) {
   321  		t.Run("Array with null", func(t *testing.T) {
   322  			q := gqlparser.MustLoadQuery(schema, `query foo($var: [Int]) { intArrayArg(i: $var) }`)
   323  			a := 1
   324  			b := 2
   325  
   326  			_, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{
   327  				"var": []*int{&a, &b, nil},
   328  			})
   329  			require.Nil(t, gerr)
   330  		})
   331  	})
   332  
   333  	t.Run("String Array", func(t *testing.T) {
   334  		t.Run("Array with null", func(t *testing.T) {
   335  			q := gqlparser.MustLoadQuery(schema, `query foo($var: [String]) { stringArrayArg(i: $var) }`)
   336  			a := "1"
   337  			b := "2"
   338  
   339  			_, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{
   340  				"var": []*string{&a, &b, nil},
   341  			})
   342  			require.Nil(t, gerr)
   343  		})
   344  	})
   345  
   346  	t.Run("Boolean Array", func(t *testing.T) {
   347  		t.Run("Array with null", func(t *testing.T) {
   348  			q := gqlparser.MustLoadQuery(schema, `query foo($var: [Boolean]) { boolArrayArg(i: $var) }`)
   349  			a := true
   350  			b := false
   351  
   352  			_, gerr := validator.VariableValues(schema, q.Operations.ForName(""), map[string]interface{}{
   353  				"var": []*bool{&a, &b, nil},
   354  			})
   355  			require.Nil(t, gerr)
   356  		})
   357  	})
   358  }
   359  
   360  func mustReadFile(name string) string {
   361  	src, err := os.ReadFile(name)
   362  	if err != nil {
   363  		panic(err)
   364  	}
   365  
   366  	return string(src)
   367  }
   368  

View as plain text