From dee0cc6fb4d5ff8b5b9ee5c5f96824c3e0fdd38f Mon Sep 17 00:00:00 2001 From: Sam Christen Oliphant Date: Wed, 23 Oct 2024 15:03:31 -0400 Subject: [PATCH 1/6] add devModeCheck and output errors without values --- .../variablesvalidation.go | 137 ++++++++++++++---- 1 file changed, 111 insertions(+), 26 deletions(-) diff --git a/v2/pkg/variablesvalidation/variablesvalidation.go b/v2/pkg/variablesvalidation/variablesvalidation.go index 2e179bc8d..d5393e2ac 100644 --- a/v2/pkg/variablesvalidation/variablesvalidation.go +++ b/v2/pkg/variablesvalidation/variablesvalidation.go @@ -3,6 +3,8 @@ package variablesvalidation import ( "bytes" "fmt" + "os" + "strings" "github.com/wundergraph/graphql-go-tools/v2/pkg/ast" "github.com/wundergraph/graphql-go-tools/v2/pkg/astjson" @@ -87,6 +89,11 @@ const ( pathItemKindArray ) +func devModeCheck() bool { + d := strings.ToLower(os.Getenv("DEV_MODE")) + return (d == "true") +} + type pathItem struct { kind pathItemKind name []byte @@ -182,8 +189,14 @@ func (v *variablesVisitor) renderVariableInvalidObjectTypeError(typeName []byte, return } variableContent := out.String() - v.err = &InvalidVariableError{ - Message: fmt.Sprintf(`Variable "$%s" got invalid value %s; Expected type "%s" to be an object.`, string(v.currentVariableName), variableContent, string(typeName)), + if devModeCheck() { + v.err = &InvalidVariableError{ + Message: fmt.Sprintf(`Variable "$%s" got invalid value %s; Expected type "%s" to be an object.`, string(v.currentVariableName), variableContent, string(typeName)), + } + } else { + v.err = &InvalidVariableError{ + Message: fmt.Sprintf(`Variable "$%s" got invalid value; Expected type "%s" to be an object.`, string(v.currentVariableName), string(typeName)), + } } } @@ -201,8 +214,14 @@ func (v *variablesVisitor) renderVariableRequiredNotProvidedError(fieldName []by v.err = err return } - v.err = &InvalidVariableError{ - Message: fmt.Sprintf(`Variable "$%s" got invalid value %s; Field "%s" of required type "%s" was not provided.`, string(v.currentVariableName), variableContent, string(fieldName), out.String()), + if devModeCheck() { + v.err = &InvalidVariableError{ + Message: fmt.Sprintf(`Variable "$%s" got invalid value %s; Field "%s" of required type "%s" was not provided.`, string(v.currentVariableName), variableContent, string(fieldName), out.String()), + } + } else { + v.err = &InvalidVariableError{ + Message: fmt.Sprintf(`Variable "$%s" got invalid value; Field "%s" of required type "%s" was not provided.`, string(v.currentVariableName), string(fieldName), out.String()), + } } } @@ -224,43 +243,97 @@ func (v *variablesVisitor) renderVariableInvalidNestedTypeError(actualJsonNodeRe case ast.NodeKindScalarTypeDefinition: switch typeName { case "String": - v.err = &InvalidVariableError{ - Message: fmt.Sprintf(`Variable "$%s" got invalid value %s%s; String cannot represent a non string value: %s`, variableName, invalidValue, path, invalidValue), + if devModeCheck() { + v.err = &InvalidVariableError{ + Message: fmt.Sprintf(`Variable "$%s" got invalid value %s%s; String cannot represent a non string value: %s`, variableName, invalidValue, path, invalidValue), + } + } else { + v.err = &InvalidVariableError{ + Message: fmt.Sprintf(`Variable "$%s" got invalid value at %s; String cannot represent a non string value`, variableName, path), + } } case "Int": - v.err = &InvalidVariableError{ - Message: fmt.Sprintf(`Variable "$%s" got invalid value %s%s; Int cannot represent non-integer value: %s`, variableName, invalidValue, path, invalidValue), + if devModeCheck() { + v.err = &InvalidVariableError{ + Message: fmt.Sprintf(`Variable "$%s" got invalid value %s%s; Int cannot represent non-integer value: %s`, variableName, invalidValue, path, invalidValue), + } + } else { + v.err = &InvalidVariableError{ + Message: fmt.Sprintf(`Variable "$%s" got invalid value %s; Int cannot represent non-integer value`, variableName, path), + } } case "Float": - v.err = &InvalidVariableError{ - Message: fmt.Sprintf(`Variable "$%s" got invalid value %s%s; Float cannot represent non numeric value: %s`, variableName, invalidValue, path, invalidValue), + if devModeCheck() { + v.err = &InvalidVariableError{ + Message: fmt.Sprintf(`Variable "$%s" got invalid value %s%s; Float cannot represent non numeric value: %s`, variableName, invalidValue, path, invalidValue), + } + } else { + v.err = &InvalidVariableError{ + Message: fmt.Sprintf(`Variable "$%s" got invalid value %s; Float cannot represent non numeric value`, variableName, path), + } } case "Boolean": - v.err = &InvalidVariableError{ - Message: fmt.Sprintf(`Variable "$%s" got invalid value %s%s; Boolean cannot represent a non boolean value: %s`, variableName, invalidValue, path, invalidValue), + if devModeCheck() { + v.err = &InvalidVariableError{ + Message: fmt.Sprintf(`Variable "$%s" got invalid value %s%s; Boolean cannot represent a non boolean value: %s`, variableName, invalidValue, path, invalidValue), + } + } else { + v.err = &InvalidVariableError{ + Message: fmt.Sprintf(`Variable "$%s" got invalid value %s; Boolean cannot represent a non boolean value`, variableName, path), + } } case "ID": - v.err = &InvalidVariableError{ - Message: fmt.Sprintf(`Variable "$%s" got invalid value %s%s; ID cannot represent value: %s`, variableName, invalidValue, path, invalidValue), + if devModeCheck() { + v.err = &InvalidVariableError{ + Message: fmt.Sprintf(`Variable "$%s" got invalid value %s%s; ID cannot represent value: %s`, variableName, invalidValue, path, invalidValue), + } + } else { + v.err = &InvalidVariableError{ + Message: fmt.Sprintf(`Variable "$%s" got invalid value %s; ID cannot represent value`, variableName, path), + } } default: - v.err = &InvalidVariableError{ - Message: fmt.Sprintf(`Variable "$%s" got invalid value %s%s; Expected type "%s" to be a scalar.`, variableName, invalidValue, path, typeName), + if devModeCheck() { + v.err = &InvalidVariableError{ + Message: fmt.Sprintf(`Variable "$%s" got invalid value %s%s; Expected type "%s" to be a scalar.`, variableName, invalidValue, path, typeName), + } + } else { + v.err = &InvalidVariableError{ + Message: fmt.Sprintf(`Variable "$%s" got invalid value %s; Expected type "%s" to be a scalar.`, variableName, path, typeName), + } } } case ast.NodeKindInputObjectTypeDefinition: if expectedList { - v.err = &InvalidVariableError{ - Message: fmt.Sprintf(`Variable "$%s" got invalid value %s%s; Got input type "%s", want: "[%s]"`, variableName, invalidValue, path, typeName, typeName), + if devModeCheck() { + v.err = &InvalidVariableError{ + Message: fmt.Sprintf(`Variable "$%s" got invalid value %s%s; Got input type "%s", want: "[%s]"`, variableName, invalidValue, path, typeName, typeName), + } + } else { + v.err = &InvalidVariableError{ + Message: fmt.Sprintf(`Variable "$%s" got invalid value %s; Got input type "%s", want: "[%s]"`, variableName, path, typeName, typeName), + } } } else { - v.err = &InvalidVariableError{ - Message: fmt.Sprintf(`Variable "$%s" got invalid value %s%s; Expected type "%s" to be an input object.`, variableName, invalidValue, path, typeName), + if devModeCheck() { + v.err = &InvalidVariableError{ + Message: fmt.Sprintf(`Variable "$%s" got invalid value %s%s; Expected type "%s" to be an input object.`, variableName, invalidValue, path, typeName), + } + } else { + v.err = &InvalidVariableError{ + Message: fmt.Sprintf(`Variable "$%s" got invalid value %s; Expected type "%s" to be an input object.`, variableName, path, typeName), + } } } case ast.NodeKindEnumTypeDefinition: - v.err = &InvalidVariableError{ - Message: fmt.Sprintf(`Variable "$%s" got invalid value %s%s; Enum "%s" cannot represent non-string value: %s.`, variableName, invalidValue, path, typeName, invalidValue), + if devModeCheck() { + v.err = &InvalidVariableError{ + Message: fmt.Sprintf(`Variable "$%s" got invalid value %s%s; Enum "%s" cannot represent non-string value: %s.`, variableName, invalidValue, path, typeName, invalidValue), + } + } else { + v.err = &InvalidVariableError{ + Message: fmt.Sprintf(`Variable "$%s" got invalid value %s; Enum "%s" cannot represent non-string value.`, variableName, path, typeName), + } } } } @@ -275,8 +348,14 @@ func (v *variablesVisitor) renderVariableFieldNotDefinedError(fieldName []byte, } invalidValue := buf.String() path := v.renderPath() - v.err = &InvalidVariableError{ - Message: fmt.Sprintf(`Variable "$%s" got invalid value %s at "%s"; Field "%s" is not defined by type "%s".`, variableName, invalidValue, path, string(fieldName), string(typeName)), + if devModeCheck() { + v.err = &InvalidVariableError{ + Message: fmt.Sprintf(`Variable "$%s" got invalid value %s at "%s"; Field "%s" is not defined by type "%s".`, variableName, invalidValue, path, string(fieldName), string(typeName)), + } + } else { + v.err = &InvalidVariableError{ + Message: fmt.Sprintf(`Variable "$%s" got invalid value at "%s"; Field "%s" is not defined by type "%s".`, variableName, path, string(fieldName), string(typeName)), + } } } @@ -293,8 +372,14 @@ func (v *variablesVisitor) renderVariableEnumValueDoesNotExistError(typeName []b if len(v.path) > 1 { path = fmt.Sprintf(` at "%s"`, v.renderPath()) } - v.err = &InvalidVariableError{ - Message: fmt.Sprintf(`Variable "$%s" got invalid value %s%s; Value "%s" does not exist in "%s" enum.`, variableName, invalidValue, path, string(enumValue), string(typeName)), + if devModeCheck() { + v.err = &InvalidVariableError{ + Message: fmt.Sprintf(`Variable "$%s" got invalid value %s%s; Value "%s" does not exist in "%s" enum.`, variableName, invalidValue, path, string(enumValue), string(typeName)), + } + } else { + v.err = &InvalidVariableError{ + Message: fmt.Sprintf(`Variable "$%s" got invalid value %s; Value "%s" does not exist in "%s" enum.`, variableName, path, string(enumValue), string(typeName)), + } } } From 5fc212cb3098377dfb8a638f6b506ac5cf7dc554 Mon Sep 17 00:00:00 2001 From: Sam Christen Oliphant Date: Thu, 24 Oct 2024 14:23:34 -0400 Subject: [PATCH 2/6] add dev_mode unit tests --- .../variablesvalidation.go | 20 +- .../variablesvalidation_test.go | 496 ++++++++++++++++-- 2 files changed, 470 insertions(+), 46 deletions(-) diff --git a/v2/pkg/variablesvalidation/variablesvalidation.go b/v2/pkg/variablesvalidation/variablesvalidation.go index d5393e2ac..20c302ec2 100644 --- a/v2/pkg/variablesvalidation/variablesvalidation.go +++ b/v2/pkg/variablesvalidation/variablesvalidation.go @@ -249,7 +249,7 @@ func (v *variablesVisitor) renderVariableInvalidNestedTypeError(actualJsonNodeRe } } else { v.err = &InvalidVariableError{ - Message: fmt.Sprintf(`Variable "$%s" got invalid value at %s; String cannot represent a non string value`, variableName, path), + Message: fmt.Sprintf(`Variable "$%s" got invalid value%s; String cannot represent a non string value`, variableName, path), } } case "Int": @@ -259,7 +259,7 @@ func (v *variablesVisitor) renderVariableInvalidNestedTypeError(actualJsonNodeRe } } else { v.err = &InvalidVariableError{ - Message: fmt.Sprintf(`Variable "$%s" got invalid value %s; Int cannot represent non-integer value`, variableName, path), + Message: fmt.Sprintf(`Variable "$%s" got invalid value%s; Int cannot represent non-integer value`, variableName, path), } } case "Float": @@ -269,7 +269,7 @@ func (v *variablesVisitor) renderVariableInvalidNestedTypeError(actualJsonNodeRe } } else { v.err = &InvalidVariableError{ - Message: fmt.Sprintf(`Variable "$%s" got invalid value %s; Float cannot represent non numeric value`, variableName, path), + Message: fmt.Sprintf(`Variable "$%s" got invalid value%s; Float cannot represent non numeric value`, variableName, path), } } case "Boolean": @@ -279,7 +279,7 @@ func (v *variablesVisitor) renderVariableInvalidNestedTypeError(actualJsonNodeRe } } else { v.err = &InvalidVariableError{ - Message: fmt.Sprintf(`Variable "$%s" got invalid value %s; Boolean cannot represent a non boolean value`, variableName, path), + Message: fmt.Sprintf(`Variable "$%s" got invalid value%s; Boolean cannot represent a non boolean value`, variableName, path), } } case "ID": @@ -289,7 +289,7 @@ func (v *variablesVisitor) renderVariableInvalidNestedTypeError(actualJsonNodeRe } } else { v.err = &InvalidVariableError{ - Message: fmt.Sprintf(`Variable "$%s" got invalid value %s; ID cannot represent value`, variableName, path), + Message: fmt.Sprintf(`Variable "$%s" got invalid value%s; ID cannot represent value`, variableName, path), } } default: @@ -299,7 +299,7 @@ func (v *variablesVisitor) renderVariableInvalidNestedTypeError(actualJsonNodeRe } } else { v.err = &InvalidVariableError{ - Message: fmt.Sprintf(`Variable "$%s" got invalid value %s; Expected type "%s" to be a scalar.`, variableName, path, typeName), + Message: fmt.Sprintf(`Variable "$%s" got invalid value%s; Expected type "%s" to be a scalar.`, variableName, path, typeName), } } } @@ -311,7 +311,7 @@ func (v *variablesVisitor) renderVariableInvalidNestedTypeError(actualJsonNodeRe } } else { v.err = &InvalidVariableError{ - Message: fmt.Sprintf(`Variable "$%s" got invalid value %s; Got input type "%s", want: "[%s]"`, variableName, path, typeName, typeName), + Message: fmt.Sprintf(`Variable "$%s" got invalid value%s; Got input type "%s", want: "[%s]"`, variableName, path, typeName, typeName), } } } else { @@ -321,7 +321,7 @@ func (v *variablesVisitor) renderVariableInvalidNestedTypeError(actualJsonNodeRe } } else { v.err = &InvalidVariableError{ - Message: fmt.Sprintf(`Variable "$%s" got invalid value %s; Expected type "%s" to be an input object.`, variableName, path, typeName), + Message: fmt.Sprintf(`Variable "$%s" got invalid value%s; Expected type "%s" to be an input object.`, variableName, path, typeName), } } } @@ -332,7 +332,7 @@ func (v *variablesVisitor) renderVariableInvalidNestedTypeError(actualJsonNodeRe } } else { v.err = &InvalidVariableError{ - Message: fmt.Sprintf(`Variable "$%s" got invalid value %s; Enum "%s" cannot represent non-string value.`, variableName, path, typeName), + Message: fmt.Sprintf(`Variable "$%s" got invalid value%s; Enum "%s" cannot represent non-string value.`, variableName, path, typeName), } } } @@ -378,7 +378,7 @@ func (v *variablesVisitor) renderVariableEnumValueDoesNotExistError(typeName []b } } else { v.err = &InvalidVariableError{ - Message: fmt.Sprintf(`Variable "$%s" got invalid value %s; Value "%s" does not exist in "%s" enum.`, variableName, path, string(enumValue), string(typeName)), + Message: fmt.Sprintf(`Variable "$%s" got invalid value%s; Value does not exist in "%s" enum.`, variableName, path, string(typeName)), } } } diff --git a/v2/pkg/variablesvalidation/variablesvalidation_test.go b/v2/pkg/variablesvalidation/variablesvalidation_test.go index 4dec7423f..0ff16a022 100644 --- a/v2/pkg/variablesvalidation/variablesvalidation_test.go +++ b/v2/pkg/variablesvalidation/variablesvalidation_test.go @@ -13,7 +13,7 @@ import ( ) func TestVariablesValidation(t *testing.T) { - + t.Run("required field argument not provided", func(t *testing.T) { tc := testCase{ schema: `type Query { hello(arg: String!): String }`, @@ -57,7 +57,8 @@ func TestVariablesValidation(t *testing.T) { assert.Equal(t, `Variable "$input" got invalid value {}; Field "nested" of required type "NestedSelfSatisfiedInput!" was not provided.`, err.Error()) }) - t.Run("unprovided required input fields without default values produce validation errors #2", func(t *testing.T) { + t.Run("dev_mode unprovided required input fields without default values produce validation errors #2", func(t *testing.T) { + t.Setenv("DEV_MODE", "true") tc := testCase{ schema: inputSchema, operation: `query Foo($input: SelfUnsatisfiedInput!) { unsatisfied(input: $input) }`, @@ -68,6 +69,17 @@ func TestVariablesValidation(t *testing.T) { assert.Equal(t, `Variable "$input" got invalid value {"nested":{},"value":"string"}; Field "secondNested" of required type "NestedSelfSatisfiedInput!" was not provided.`, err.Error()) }) + t.Run("unprovided required input fields without default values produce validation errors #2", func(t *testing.T) { + tc := testCase{ + schema: inputSchema, + operation: `query Foo($input: SelfUnsatisfiedInput!) { unsatisfied(input: $input) }`, + variables: `{ "input": { "nested": { }, "value": "string" } }`, + } + err := runTest(t, tc) + require.Error(t, err) + assert.Equal(t, `Variable "$input" got invalid value; Field "secondNested" of required type "NestedSelfSatisfiedInput!" was not provided.`, err.Error()) + }) + t.Run("provided but empty nested required inputs with default values do not produce validation errors", func(t *testing.T) { tc := testCase{ schema: inputSchema, @@ -98,7 +110,8 @@ func TestVariablesValidation(t *testing.T) { require.NoError(t, err) }) - t.Run("nested argument is value instead of list", func(t *testing.T) { + t.Run("dev_mode nested argument is value instead of list", func(t *testing.T) { + t.Setenv("DEV_MODE", "true") tc := testCase{ schema: `type Query { hello(input: Input): String } input Input { bar: [String]! }`, operation: `query Foo($input: Input) { hello(input: $input) }`, @@ -109,7 +122,19 @@ func TestVariablesValidation(t *testing.T) { assert.Equal(t, `Variable "$input" got invalid value "world" at "input.bar"; Got input type "String", want: "[String]"`, err.Error()) }) - t.Run("nested enum argument is value instead of list", func(t *testing.T) { + t.Run("nested argument is value instead of list", func(t *testing.T) { + tc := testCase{ + schema: `type Query { hello(input: Input): String } input Input { bar: [String]! }`, + operation: `query Foo($input: Input) { hello(input: $input) }`, + variables: `{"input":{"bar":"world"}}`, + } + err := runTest(t, tc) + require.NotNil(t, err) + assert.Equal(t, `Variable "$input" got invalid value at "input.bar"; Got input type "String", want: "[String]"`, err.Error()) + }) + + t.Run("dev_mode nested enum argument is value instead of list", func(t *testing.T) { + t.Setenv("DEV_MODE", "true") tc := testCase{ schema: `type Query { hello(input: Input): String } input Input { bar: [MyNum]! } enum MyNum { ONE TWO }`, operation: `query Foo($input: Input) { hello(input: $input) }`, @@ -120,6 +145,18 @@ func TestVariablesValidation(t *testing.T) { assert.Equal(t, `Variable "$input" got invalid value "ONE" at "input.bar"; Got input type "MyNum", want: "[MyNum]"`, err.Error()) }) + t.Run("nested enum argument is value instead of list", func(t *testing.T) { + t.Setenv("DEV_MODE", "true") + tc := testCase{ + schema: `type Query { hello(input: Input): String } input Input { bar: [MyNum]! } enum MyNum { ONE TWO }`, + operation: `query Foo($input: Input) { hello(input: $input) }`, + variables: `{"input":{"bar":"ONE"}}`, + } + err := runTest(t, tc) + require.NotNil(t, err) + assert.Equal(t, `Variable "$input" got invalid value at "input.bar"; Got input type "MyNum", want: "[MyNum]"`, err.Error()) + }) + t.Run("required field argument of custom scalar type not provided", func(t *testing.T) { tc := testCase{ schema: `type Query { hello(arg: Baz!): String } scalar Baz`, @@ -142,7 +179,8 @@ func TestVariablesValidation(t *testing.T) { assert.Equal(t, `Variable "$bar" got invalid value null; Expected non-nullable type "Baz!" not to be null.`, err.Error()) }) - t.Run("required nested field field argument of custom scalar not provided", func(t *testing.T) { + t.Run("dev_mode required nested field field argument of custom scalar not provided", func(t *testing.T) { + t.Setenv("DEV_MODE", "true") tc := testCase{ schema: `type Query { hello(arg: Foo!): String } input Foo { bar: Baz! } scalar Baz`, operation: `query Foo($bar: Foo!) { hello(arg: $bar) }`, @@ -153,7 +191,19 @@ func TestVariablesValidation(t *testing.T) { assert.Equal(t, `Variable "$bar" got invalid value {}; Field "bar" of required type "Baz!" was not provided.`, err.Error()) }) - t.Run("required nested field field argument of custom scalar was null", func(t *testing.T) { + t.Run("required nested field field argument of custom scalar not provided", func(t *testing.T) { + tc := testCase{ + schema: `type Query { hello(arg: Foo!): String } input Foo { bar: Baz! } scalar Baz`, + operation: `query Foo($bar: Foo!) { hello(arg: $bar) }`, + variables: `{"bar":{}}`, + } + err := runTest(t, tc) + assert.NotNil(t, err) + assert.Equal(t, `Variable "$bar" got invalid value; Field "bar" of required type "Baz!" was not provided.`, err.Error()) + }) + + t.Run("dev_mode required nested field field argument of custom scalar was null", func(t *testing.T) { + t.Setenv("DEV_MODE", "true") tc := testCase{ schema: `type Query { hello(arg: Foo!): String } input Foo { bar: Baz! } scalar Baz`, operation: `query Foo($bar: Foo!) { hello(arg: $bar) }`, @@ -164,6 +214,17 @@ func TestVariablesValidation(t *testing.T) { assert.Equal(t, `Variable "$bar" got invalid value {"bar":null}; Field "bar" of required type "Baz!" was not provided.`, err.Error()) }) + t.Run("required nested field field argument of custom scalar was null", func(t *testing.T) { + tc := testCase{ + schema: `type Query { hello(arg: Foo!): String } input Foo { bar: Baz! } scalar Baz`, + operation: `query Foo($bar: Foo!) { hello(arg: $bar) }`, + variables: `{"bar":{"bar":null}}`, + } + err := runTest(t, tc) + assert.NotNil(t, err) + assert.Equal(t, `Variable "$bar" got invalid value; Field "bar" of required type "Baz!" was not provided.`, err.Error()) + }) + t.Run("required field argument provided with default value", func(t *testing.T) { tc := testCase{ schema: `type Query { hello(arg: String!): String }`, @@ -272,7 +333,8 @@ func TestVariablesValidation(t *testing.T) { assert.Equal(t, `Variable "$bar" of required type "[String]!" was not provided.`, err.Error()) }) - t.Run("wrong Boolean value for input object field", func(t *testing.T) { + t.Run("dev_mode wrong Boolean value for input object field", func(t *testing.T) { + t.Setenv("DEV_MODE", "true") tc := testCase{ schema: `input Foo { bar: String! } type Query { hello(arg: Foo!): String }`, operation: `query Foo($bar: Foo!) { hello(arg: $bar) }`, @@ -283,7 +345,19 @@ func TestVariablesValidation(t *testing.T) { assert.Equal(t, `Variable "$bar" got invalid value true; Expected type "Foo" to be an object.`, err.Error()) }) - t.Run("wrong Integer value for input object field", func(t *testing.T) { + t.Run("wrong Boolean value for input object field", func(t *testing.T) { + tc := testCase{ + schema: `input Foo { bar: String! } type Query { hello(arg: Foo!): String }`, + operation: `query Foo($bar: Foo!) { hello(arg: $bar) }`, + variables: `{"bar":true}`, + } + err := runTest(t, tc) + require.Error(t, err) + assert.Equal(t, `Variable "$bar" got invalid value; Expected type "Foo" to be an object.`, err.Error()) + }) + + t.Run("dev_mode wrong Integer value for input object field", func(t *testing.T) { + t.Setenv("DEV_MODE", "true") tc := testCase{ schema: `input Foo { bar: String! } type Query { hello(arg: Foo!): String }`, operation: `query Foo($bar: Foo!) { hello(arg: $bar) }`, @@ -294,7 +368,19 @@ func TestVariablesValidation(t *testing.T) { assert.Equal(t, `Variable "$bar" got invalid value 123; Expected type "Foo" to be an object.`, err.Error()) }) - t.Run("required field on present input object not provided", func(t *testing.T) { + t.Run("wrong Integer value for input object field", func(t *testing.T) { + tc := testCase{ + schema: `input Foo { bar: String! } type Query { hello(arg: Foo!): String }`, + operation: `query Foo($bar: Foo!) { hello(arg: $bar) }`, + variables: `{"bar":123}`, + } + err := runTest(t, tc) + require.Error(t, err) + assert.Equal(t, `Variable "$bar" got invalid value; Expected type "Foo" to be an object.`, err.Error()) + }) + + t.Run("dev_mode required field on present input object not provided", func(t *testing.T) { + t.Setenv("DEV_MODE", "true") tc := testCase{ schema: `input Foo { bar: String! } type Query { hello(arg: Foo!): String }`, operation: `query Foo($bar: Foo!) { hello(arg: $bar) }`, @@ -305,6 +391,17 @@ func TestVariablesValidation(t *testing.T) { assert.Equal(t, `Variable "$bar" got invalid value {}; Field "bar" of required type "String!" was not provided.`, err.Error()) }) + t.Run("required field on present input object not provided", func(t *testing.T) { + tc := testCase{ + schema: `input Foo { bar: String! } type Query { hello(arg: Foo!): String }`, + operation: `query Foo($bar: Foo!) { hello(arg: $bar) }`, + variables: `{"bar":{}}`, + } + err := runTest(t, tc) + require.Error(t, err) + assert.Equal(t, `Variable "$bar" got invalid value; Field "bar" of required type "String!" was not provided.`, err.Error()) + }) + t.Run("required field on present input object provided with correct type", func(t *testing.T) { tc := testCase{ schema: `input Foo { bar: String! } type Query { hello(arg: Foo!): String }`, @@ -315,7 +412,8 @@ func TestVariablesValidation(t *testing.T) { require.NoError(t, err) }) - t.Run("required field on present input object provided with wrong type", func(t *testing.T) { + t.Run("dev_mode required field on present input object provided with wrong type", func(t *testing.T) { + t.Setenv("DEV_MODE", "true") tc := testCase{ schema: `input Foo { bar: String! } type Query { hello(arg: Foo!): String }`, operation: `query Foo($input: Foo!) { hello(arg: $input) }`, @@ -326,7 +424,19 @@ func TestVariablesValidation(t *testing.T) { assert.Equal(t, `Variable "$input" got invalid value 123 at "input.bar"; String cannot represent a non string value: 123`, err.Error()) }) - t.Run("required field on present input object not provided", func(t *testing.T) { + t.Run("required field on present input object provided with wrong type", func(t *testing.T) { + tc := testCase{ + schema: `input Foo { bar: String! } type Query { hello(arg: Foo!): String }`, + operation: `query Foo($input: Foo!) { hello(arg: $input) }`, + variables: `{"input":{"bar":123}}`, + } + err := runTest(t, tc) + require.Error(t, err) + assert.Equal(t, `Variable "$input" got invalid value at "input.bar"; String cannot represent a non string value`, err.Error()) + }) + + t.Run("dev_mode required field on present input object not provided", func(t *testing.T) { + t.Setenv("DEV_MODE", "true") tc := testCase{ schema: `input Foo { bar: String! } type Query { hello(arg: Foo!): String }`, operation: `query Foo($input: Foo!) { hello(arg: $input) }`, @@ -337,7 +447,19 @@ func TestVariablesValidation(t *testing.T) { assert.Equal(t, `Variable "$input" got invalid value {}; Field "bar" of required type "String!" was not provided.`, err.Error()) }) - t.Run("required string field on input object provided with null", func(t *testing.T) { + t.Run("required field on present input object not provided", func(t *testing.T) { + tc := testCase{ + schema: `input Foo { bar: String! } type Query { hello(arg: Foo!): String }`, + operation: `query Foo($input: Foo!) { hello(arg: $input) }`, + variables: `{"input":{}}`, + } + err := runTest(t, tc) + require.Error(t, err) + assert.Equal(t, `Variable "$input" got invalid value; Field "bar" of required type "String!" was not provided.`, err.Error()) + }) + + t.Run("dev_mode required string field on input object provided with null", func(t *testing.T) { + t.Setenv("DEV_MODE", "true") tc := testCase{ schema: `input Foo { bar: String! } type Query { hello(arg: Foo!): String }`, operation: `query Foo($input: Foo!) { hello(arg: $input) }`, @@ -347,8 +469,20 @@ func TestVariablesValidation(t *testing.T) { require.Error(t, err) assert.Equal(t, `Variable "$input" got invalid value {"bar":null}; Field "bar" of required type "String!" was not provided.`, err.Error()) }) + + t.Run("required string field on input object provided with null", func(t *testing.T) { + tc := testCase{ + schema: `input Foo { bar: String! } type Query { hello(arg: Foo!): String }`, + operation: `query Foo($input: Foo!) { hello(arg: $input) }`, + variables: `{"input":{"bar":null}}`, + } + err := runTest(t, tc) + require.Error(t, err) + assert.Equal(t, `Variable "$input" got invalid value; Field "bar" of required type "String!" was not provided.`, err.Error()) + }) - t.Run("required string field on input object provided with Int", func(t *testing.T) { + t.Run("dev_mode required string field on input object provided with Int", func(t *testing.T) { + t.Setenv("DEV_MODE", "true") tc := testCase{ schema: `input Foo { bar: String! } type Query { hello(arg: Foo!): String }`, operation: `query Foo($input: Foo!) { hello(arg: $input) }`, @@ -359,7 +493,19 @@ func TestVariablesValidation(t *testing.T) { assert.Equal(t, `Variable "$input" got invalid value 123 at "input.bar"; String cannot represent a non string value: 123`, err.Error()) }) - t.Run("required string field on input object provided with Float", func(t *testing.T) { + t.Run("required string field on input object provided with Int", func(t *testing.T) { + tc := testCase{ + schema: `input Foo { bar: String! } type Query { hello(arg: Foo!): String }`, + operation: `query Foo($input: Foo!) { hello(arg: $input) }`, + variables: `{"input":{"bar":123}}`, + } + err := runTest(t, tc) + require.Error(t, err) + assert.Equal(t, `Variable "$input" got invalid value at "input.bar"; String cannot represent a non string value`, err.Error()) + }) + + t.Run("dev_mode required string field on input object provided with Float", func(t *testing.T) { + t.Setenv("DEV_MODE", "true") tc := testCase{ schema: `input Foo { bar: String! } type Query { hello(arg: Foo!): String }`, operation: `query Foo($input: Foo!) { hello(arg: $input) }`, @@ -370,7 +516,19 @@ func TestVariablesValidation(t *testing.T) { assert.Equal(t, `Variable "$input" got invalid value 123.456 at "input.bar"; String cannot represent a non string value: 123.456`, err.Error()) }) - t.Run("required string field on input object provided with Boolean", func(t *testing.T) { + t.Run("required string field on input object provided with Float", func(t *testing.T) { + tc := testCase{ + schema: `input Foo { bar: String! } type Query { hello(arg: Foo!): String }`, + operation: `query Foo($input: Foo!) { hello(arg: $input) }`, + variables: `{"input":{"bar":123.456}}`, + } + err := runTest(t, tc) + require.Error(t, err) + assert.Equal(t, `Variable "$input" got invalid value at "input.bar"; String cannot represent a non string value`, err.Error()) + }) + + t.Run("dev_mode required string field on input object provided with Boolean", func(t *testing.T) { + t.Setenv("DEV_MODE", "true") tc := testCase{ schema: `input Foo { bar: String! } type Query { hello(arg: Foo!): String }`, operation: `query Foo($input: Foo!) { hello(arg: $input) }`, @@ -381,7 +539,19 @@ func TestVariablesValidation(t *testing.T) { assert.Equal(t, `Variable "$input" got invalid value true at "input.bar"; String cannot represent a non string value: true`, err.Error()) }) - t.Run("required string field on nested input object not provided", func(t *testing.T) { + t.Run("required string field on input object provided with Boolean", func(t *testing.T) { + tc := testCase{ + schema: `input Foo { bar: String! } type Query { hello(arg: Foo!): String }`, + operation: `query Foo($input: Foo!) { hello(arg: $input) }`, + variables: `{"input":{"bar":true}}`, + } + err := runTest(t, tc) + require.Error(t, err) + assert.Equal(t, `Variable "$input" got invalid value at "input.bar"; String cannot represent a non string value`, err.Error()) + }) + + t.Run("dev_mode required string field on nested input object not provided", func(t *testing.T) { + t.Setenv("DEV_MODE", "true") tc := testCase{ schema: `input Foo { bar: String! } input Bar { foo: Foo! } type Query { hello(arg: Bar!): String }`, operation: `query Foo($input: Bar!) { hello(arg: $input) }`, @@ -392,7 +562,19 @@ func TestVariablesValidation(t *testing.T) { assert.Equal(t, `Variable "$input" got invalid value {"foo":{}}; Field "bar" of required type "String!" was not provided.`, err.Error()) }) - t.Run("required string field on nested input object provided with null", func(t *testing.T) { + t.Run("required string field on nested input object not provided", func(t *testing.T) { + tc := testCase{ + schema: `input Foo { bar: String! } input Bar { foo: Foo! } type Query { hello(arg: Bar!): String }`, + operation: `query Foo($input: Bar!) { hello(arg: $input) }`, + variables: `{"input":{"foo":{}}}`, + } + err := runTest(t, tc) + require.Error(t, err) + assert.Equal(t, `Variable "$input" got invalid value; Field "bar" of required type "String!" was not provided.`, err.Error()) + }) + + t.Run("dev_mode required string field on nested input object provided with null", func(t *testing.T) { + t.Setenv("DEV_MODE", "true") tc := testCase{ schema: `input Foo { bar: String! } input Bar { foo: Foo! } type Query { hello(arg: Bar!): String }`, operation: `query Foo($input: Bar!) { hello(arg: $input) }`, @@ -403,7 +585,19 @@ func TestVariablesValidation(t *testing.T) { assert.Equal(t, `Variable "$input" got invalid value {"foo":{"bar":null}}; Field "bar" of required type "String!" was not provided.`, err.Error()) }) - t.Run("required string field on nested input object provided with Int", func(t *testing.T) { + t.Run("required string field on nested input object provided with null", func(t *testing.T) { + tc := testCase{ + schema: `input Foo { bar: String! } input Bar { foo: Foo! } type Query { hello(arg: Bar!): String }`, + operation: `query Foo($input: Bar!) { hello(arg: $input) }`, + variables: `{"input":{"foo":{"bar":null}}}`, + } + err := runTest(t, tc) + require.Error(t, err) + assert.Equal(t, `Variable "$input" got invalid value; Field "bar" of required type "String!" was not provided.`, err.Error()) + }) + + t.Run("dev_mode required string field on nested input object provided with Int", func(t *testing.T) { + t.Setenv("DEV_MODE", "true") tc := testCase{ schema: `input Foo { bar: String! } input Bar { foo: Foo! } type Query { hello(arg: Bar!): String }`, operation: `query Foo($input: Bar!) { hello(arg: $input) }`, @@ -414,7 +608,19 @@ func TestVariablesValidation(t *testing.T) { assert.Equal(t, `Variable "$input" got invalid value 123 at "input.foo.bar"; String cannot represent a non string value: 123`, err.Error()) }) - t.Run("required string field on nested input object array provided with Int", func(t *testing.T) { + t.Run("required string field on nested input object provided with Int", func(t *testing.T) { + tc := testCase{ + schema: `input Foo { bar: String! } input Bar { foo: Foo! } type Query { hello(arg: Bar!): String }`, + operation: `query Foo($input: Bar!) { hello(arg: $input) }`, + variables: `{"input":{"foo":{"bar":123}}}`, + } + err := runTest(t, tc) + require.Error(t, err) + assert.Equal(t, `Variable "$input" got invalid value at "input.foo.bar"; String cannot represent a non string value`, err.Error()) + }) + + t.Run("dev_mode required string field on nested input object array provided with Int", func(t *testing.T) { + t.Setenv("DEV_MODE", "true") tc := testCase{ schema: `input Foo { bar: String! } input Bar { foo: [Foo!]! } type Query { hello(arg: Bar!): String }`, operation: `query Foo($input: Bar!) { hello(arg: $input) }`, @@ -425,7 +631,19 @@ func TestVariablesValidation(t *testing.T) { assert.Equal(t, `Variable "$input" got invalid value 123 at "input.foo.[0].bar"; String cannot represent a non string value: 123`, err.Error()) }) - t.Run("required string field on nested input object array index 1 provided with Int", func(t *testing.T) { + t.Run("required string field on nested input object array provided with Int", func(t *testing.T) { + tc := testCase{ + schema: `input Foo { bar: String! } input Bar { foo: [Foo!]! } type Query { hello(arg: Bar!): String }`, + operation: `query Foo($input: Bar!) { hello(arg: $input) }`, + variables: `{"input":{"foo":[{"bar":123}]}}`, + } + err := runTest(t, tc) + require.Error(t, err) + assert.Equal(t, `Variable "$input" got invalid value at "input.foo.[0].bar"; String cannot represent a non string value`, err.Error()) + }) + + t.Run("dev_mode required string field on nested input object array index 1 provided with Int", func(t *testing.T) { + t.Setenv("DEV_MODE", "true") tc := testCase{ schema: `input Foo { bar: String! } input Bar { foo: [Foo!]! } type Query { hello(arg: Bar!): String }`, operation: `query Foo($input: Bar!) { hello(arg: $input) }`, @@ -436,7 +654,19 @@ func TestVariablesValidation(t *testing.T) { assert.Equal(t, `Variable "$input" got invalid value 123 at "input.foo.[1].bar"; String cannot represent a non string value: 123`, err.Error()) }) - t.Run("non existing field on nested input object", func(t *testing.T) { + t.Run("required string field on nested input object array index 1 provided with Int", func(t *testing.T) { + tc := testCase{ + schema: `input Foo { bar: String! } input Bar { foo: [Foo!]! } type Query { hello(arg: Bar!): String }`, + operation: `query Foo($input: Bar!) { hello(arg: $input) }`, + variables: `{"input":{"foo":[{"bar":"hello"},{"bar":123}]}}`, + } + err := runTest(t, tc) + require.Error(t, err) + assert.Equal(t, `Variable "$input" got invalid value at "input.foo.[1].bar"; String cannot represent a non string value`, err.Error()) + }) + + t.Run("dev_mode non existing field on nested input object", func(t *testing.T) { + t.Setenv("DEV_MODE", "true") tc := testCase{ schema: `input Foo { bar: String! } input Bar { foo: Foo! } type Query { hello(arg: Bar!): String }`, operation: `query Foo($input: Bar!) { hello(arg: $input) }`, @@ -447,6 +677,17 @@ func TestVariablesValidation(t *testing.T) { assert.Equal(t, `Variable "$input" got invalid value {"foo":{"bar":"hello","baz":"world"}} at "input.foo"; Field "baz" is not defined by type "Foo".`, err.Error()) }) + t.Run("non existing field on nested input object", func(t *testing.T) { + tc := testCase{ + schema: `input Foo { bar: String! } input Bar { foo: Foo! } type Query { hello(arg: Bar!): String }`, + operation: `query Foo($input: Bar!) { hello(arg: $input) }`, + variables: `{"input":{"foo":{"bar":"hello","baz":"world"}}}`, + } + err := runTest(t, tc) + require.Error(t, err) + assert.Equal(t, `Variable "$input" got invalid value at "input.foo"; Field "baz" is not defined by type "Foo".`, err.Error()) + }) + t.Run("required enum argument provided with correct value", func(t *testing.T) { tc := testCase{ schema: `enum Foo { BAR } type Query { hello(arg: Foo!): String }`, @@ -457,7 +698,8 @@ func TestVariablesValidation(t *testing.T) { require.NoError(t, err) }) - t.Run("required enum argument provided with wrong value", func(t *testing.T) { + t.Run("dev_mode required enum argument provided with wrong value", func(t *testing.T) { + t.Setenv("DEV_MODE", "true") tc := testCase{ schema: `enum Foo { BAR } type Query { hello(arg: Foo!): String }`, operation: `query Foo($bar: Foo!) { hello(arg: $bar) }`, @@ -468,7 +710,19 @@ func TestVariablesValidation(t *testing.T) { assert.Equal(t, `Variable "$bar" got invalid value "BAZ"; Value "BAZ" does not exist in "Foo" enum.`, err.Error()) }) - t.Run("required enum argument provided with Int value", func(t *testing.T) { + t.Run("required enum argument provided with wrong value", func(t *testing.T) { + tc := testCase{ + schema: `enum Foo { BAR } type Query { hello(arg: Foo!): String }`, + operation: `query Foo($bar: Foo!) { hello(arg: $bar) }`, + variables: `{"bar":"BAZ"}`, + } + err := runTest(t, tc) + require.Error(t, err) + assert.Equal(t, `Variable "$bar" got invalid value; Value does not exist in "Foo" enum.`, err.Error()) + }) + + t.Run("dev_mode required enum argument provided with Int value", func(t *testing.T) { + t.Setenv("DEV_MODE", "true") tc := testCase{ schema: `enum Foo { BAR } type Query { hello(arg: Foo!): String }`, operation: `query Foo($bar: Foo!) { hello(arg: $bar) }`, @@ -479,6 +733,17 @@ func TestVariablesValidation(t *testing.T) { assert.Equal(t, `Variable "$bar" got invalid value 123; Enum "Foo" cannot represent non-string value: 123.`, err.Error()) }) + t.Run("required enum argument provided with Int value", func(t *testing.T) { + tc := testCase{ + schema: `enum Foo { BAR } type Query { hello(arg: Foo!): String }`, + operation: `query Foo($bar: Foo!) { hello(arg: $bar) }`, + variables: `{"bar":123}`, + } + err := runTest(t, tc) + require.Error(t, err) + assert.Equal(t, `Variable "$bar" got invalid value; Enum "Foo" cannot represent non-string value.`, err.Error()) + }) + t.Run("required enum argument provided with null", func(t *testing.T) { tc := testCase{ schema: `enum Foo { BAR } type Query { hello(arg: Foo!): String }`, @@ -490,7 +755,8 @@ func TestVariablesValidation(t *testing.T) { assert.Equal(t, `Variable "$bar" got invalid value null; Expected non-nullable type "Foo!" not to be null.`, err.Error()) }) - t.Run("required nested enum argument provided with null", func(t *testing.T) { + t.Run("dev_mode required nested enum argument provided with null", func(t *testing.T) { + t.Setenv("DEV_MODE", "true") tc := testCase{ schema: `enum Foo { BAR } input Bar { foo: Foo! } type Query { hello(arg: Bar!): String }`, operation: `query Foo($input: Bar!) { hello(arg: $input) }`, @@ -501,6 +767,17 @@ func TestVariablesValidation(t *testing.T) { assert.Equal(t, `Variable "$input" got invalid value {"foo":null}; Field "foo" of required type "Foo!" was not provided.`, err.Error()) }) + t.Run("required nested enum argument provided with null", func(t *testing.T) { + tc := testCase{ + schema: `enum Foo { BAR } input Bar { foo: Foo! } type Query { hello(arg: Bar!): String }`, + operation: `query Foo($input: Bar!) { hello(arg: $input) }`, + variables: `{"input":{"foo":null}}`, + } + err := runTest(t, tc) + require.Error(t, err) + assert.Equal(t, `Variable "$input" got invalid value; Field "foo" of required type "Foo!" was not provided.`, err.Error()) + }) + t.Run("required nested enum argument provided with correct value", func(t *testing.T) { tc := testCase{ schema: `enum Foo { BAR } input Bar { foo: Foo! } type Query { hello(arg: Bar!): String }`, @@ -511,7 +788,8 @@ func TestVariablesValidation(t *testing.T) { require.NoError(t, err) }) - t.Run("required nested enum argument provided with wrong value", func(t *testing.T) { + t.Run("dev_mode required nested enum argument provided with wrong value", func(t *testing.T) { + t.Setenv("DEV_MODE", "true") tc := testCase{ schema: `enum Foo { BAR } input Bar { foo: Foo! } type Query { hello(arg: Bar!): String }`, operation: `query Foo($input: Bar!) { hello(arg: $input) }`, @@ -522,6 +800,17 @@ func TestVariablesValidation(t *testing.T) { assert.Equal(t, `Variable "$input" got invalid value {"foo":"BAZ"} at "input.foo"; Value "BAZ" does not exist in "Foo" enum.`, err.Error()) }) + t.Run("required nested enum argument provided with wrong value", func(t *testing.T) { + tc := testCase{ + schema: `enum Foo { BAR } input Bar { foo: Foo! } type Query { hello(arg: Bar!): String }`, + operation: `query Foo($input: Bar!) { hello(arg: $input) }`, + variables: `{"input":{"foo":"BAZ"}}`, + } + err := runTest(t, tc) + require.Error(t, err) + assert.Equal(t, `Variable "$input" got invalid value at "input.foo"; Value does not exist in "Foo" enum.`, err.Error()) + }) + t.Run("optional enum argument provided with null", func(t *testing.T) { tc := testCase{ schema: `enum Foo { BAR } type Query { hello(arg: Foo): String }`, @@ -542,7 +831,8 @@ func TestVariablesValidation(t *testing.T) { require.NoError(t, err) }) - t.Run("optional nested enum argument provided with incorrect value", func(t *testing.T) { + t.Run("dev_mode optional nested enum argument provided with incorrect value", func(t *testing.T) { + t.Setenv("DEV_MODE", "true") tc := testCase{ schema: `enum Foo { BAR } input Bar { foo: Foo } type Query { hello(arg: Bar): String }`, operation: `query Foo($input: Bar) { hello(arg: $input) }`, @@ -553,6 +843,17 @@ func TestVariablesValidation(t *testing.T) { assert.Equal(t, `Variable "$input" got invalid value {"foo":"BAZ"} at "input.foo"; Value "BAZ" does not exist in "Foo" enum.`, err.Error()) }) + t.Run("optional nested enum argument provided with incorrect value", func(t *testing.T) { + tc := testCase{ + schema: `enum Foo { BAR } input Bar { foo: Foo } type Query { hello(arg: Bar): String }`, + operation: `query Foo($input: Bar) { hello(arg: $input) }`, + variables: `{"input":{"foo":"BAZ"}}`, + } + err := runTest(t, tc) + require.Error(t, err) + assert.Equal(t, `Variable "$input" got invalid value at "input.foo"; Value does not exist in "Foo" enum.`, err.Error()) + }) + t.Run("optional enum argument provided with correct value", func(t *testing.T) { tc := testCase{ schema: `enum Foo { BAR } type Query { hello(arg: Foo): String }`, @@ -563,7 +864,8 @@ func TestVariablesValidation(t *testing.T) { require.NoError(t, err) }) - t.Run("optional enum argument provided with wrong value", func(t *testing.T) { + t.Run("dev_mode optional enum argument provided with wrong value", func(t *testing.T) { + t.Setenv("DEV_MODE", "true") tc := testCase{ schema: `enum Foo { BAR } type Query { hello(arg: Foo): String }`, operation: `query Foo($bar: Foo) { hello(arg: $bar) }`, @@ -574,6 +876,17 @@ func TestVariablesValidation(t *testing.T) { assert.Equal(t, `Variable "$bar" got invalid value "BAZ"; Value "BAZ" does not exist in "Foo" enum.`, err.Error()) }) + t.Run("optional enum argument provided with wrong value", func(t *testing.T) { + tc := testCase{ + schema: `enum Foo { BAR } type Query { hello(arg: Foo): String }`, + operation: `query Foo($bar: Foo) { hello(arg: $bar) }`, + variables: `{"bar":"BAZ"}`, + } + err := runTest(t, tc) + require.Error(t, err) + assert.Equal(t, `Variable "$bar" got invalid value; Value does not exist in "Foo" enum.`, err.Error()) + }) + t.Run("required string list field argument provided with null", func(t *testing.T) { tc := testCase{ schema: `type Query { hello(arg: [String]!): String }`, @@ -585,7 +898,8 @@ func TestVariablesValidation(t *testing.T) { assert.Equal(t, `Variable "$bar" got invalid value null; Expected non-nullable type "[String]!" not to be null.`, err.Error()) }) - t.Run("required string list field argument provided with non list Int value", func(t *testing.T) { + t.Run("dev_mode required string list field argument provided with non list Int value", func(t *testing.T) { + t.Setenv("DEV_MODE", "true") tc := testCase{ schema: `type Query { hello(arg: [String]!): String }`, operation: `query Foo($bar: [String]!) { hello(arg: $bar) }`, @@ -597,6 +911,18 @@ func TestVariablesValidation(t *testing.T) { assert.Equal(t, `Variable "$bar" got invalid value 123 at "bar.[0]"; String cannot represent a non string value: 123`, err.Error()) }) + t.Run("required string list field argument provided with non list Int value", func(t *testing.T) { + tc := testCase{ + schema: `type Query { hello(arg: [String]!): String }`, + operation: `query Foo($bar: [String]!) { hello(arg: $bar) }`, + variables: `{"bar":123}`, + withNormalization: true, + } + err := runTest(t, tc) + require.Error(t, err) + assert.Equal(t, `Variable "$bar" got invalid value at "bar.[0]"; String cannot represent a non string value`, err.Error()) + }) + t.Run("required string argument on input object list provided with correct value", func(t *testing.T) { tc := testCase{ schema: `input Foo { bar: String! } type Query { hello(arg: [Foo!]!): String }`, @@ -618,6 +944,18 @@ func TestVariablesValidation(t *testing.T) { assert.Equal(t, `Variable "$bar" got invalid value 123 at "bar.[0].bar"; String cannot represent a non string value: 123`, err.Error()) }) + t.Run("dev_mode required string argument on input object list provided with wrong value", func(t *testing.T) { + t.Setenv("DEV_MODE", "true") + tc := testCase{ + schema: `input Foo { bar: String! } type Query { hello(arg: [Foo!]!): String }`, + operation: `query Foo($bar: [Foo!]!) { hello(arg: $bar) }`, + variables: `{"bar":[{"bar":123}]}`, + } + err := runTest(t, tc) + require.Error(t, err) + assert.Equal(t, `Variable "$bar" got invalid value 123 at "bar.[0].bar"; String cannot represent a non string value: 123`, err.Error()) + }) + t.Run("required string argument provided with string list", func(t *testing.T) { tc := testCase{ schema: `type Query { hello(arg: String!): String }`, @@ -626,10 +964,11 @@ func TestVariablesValidation(t *testing.T) { } err := runTest(t, tc) require.Error(t, err) - assert.Equal(t, `Variable "$bar" got invalid value ["hello"]; String cannot represent a non string value: ["hello"]`, err.Error()) + assert.Equal(t, `Variable "$bar" got invalid value; String cannot represent a non string value`, err.Error()) }) - t.Run("required input object list field argument provided with non list Int value", func(t *testing.T) { + t.Run("dev_mode required input object list field argument provided with non list Int value", func(t *testing.T) { + t.Setenv("DEV_MODE", "true") tc := testCase{ schema: `input Foo { bar: String! } type Query { hello(arg: [Foo!]!): String }`, operation: `query Foo($bar: [Foo!]!) { hello(arg: $bar) }`, @@ -640,7 +979,19 @@ func TestVariablesValidation(t *testing.T) { assert.Equal(t, `Variable "$bar" got invalid value 123; Expected type "Foo" to be an object.`, err.Error()) }) - t.Run("required input object field argument provided with list input object value", func(t *testing.T) { + t.Run("required input object list field argument provided with non list Int value", func(t *testing.T) { + tc := testCase{ + schema: `input Foo { bar: String! } type Query { hello(arg: [Foo!]!): String }`, + operation: `query Foo($bar: [Foo!]!) { hello(arg: $bar) }`, + variables: `{"bar":123}`, + } + err := runTest(t, tc) + require.Error(t, err) + assert.Equal(t, `Variable "$bar" got invalid value; Expected type "Foo" to be an object.`, err.Error()) + }) + + t.Run("dev_mode required input object field argument provided with list input object value", func(t *testing.T) { + t.Setenv("DEV_MODE", "true") tc := testCase{ schema: `input Foo { bar: String! } type Query { hello(arg: Foo!): String }`, operation: `query Foo($bar: Foo!) { hello(arg: $bar) }`, @@ -651,7 +1002,19 @@ func TestVariablesValidation(t *testing.T) { assert.Equal(t, `Variable "$bar" got invalid value [{"bar":"hello"}]; Expected type "Foo" to be an object.`, err.Error()) }) - t.Run("required enum list argument provided with non list Int value", func(t *testing.T) { + t.Run("required input object field argument provided with list input object value", func(t *testing.T) { + tc := testCase{ + schema: `input Foo { bar: String! } type Query { hello(arg: Foo!): String }`, + operation: `query Foo($bar: Foo!) { hello(arg: $bar) }`, + variables: `{"bar":[{"bar":"hello"}]}`, + } + err := runTest(t, tc) + require.Error(t, err) + assert.Equal(t, `Variable "$bar" got invalid value; Expected type "Foo" to be an object.`, err.Error()) + }) + + t.Run("dev_mode required enum list argument provided with non list Int value", func(t *testing.T) { + t.Setenv("DEV_MODE", "true") tc := testCase{ schema: `enum Foo { BAR } type Query { hello(arg: [Foo]!): String }`, operation: `query Foo($bar: [Foo]!) { hello(arg: $bar) }`, @@ -663,7 +1026,20 @@ func TestVariablesValidation(t *testing.T) { assert.Equal(t, `Variable "$bar" got invalid value 123 at "bar.[0]"; Enum "Foo" cannot represent non-string value: 123.`, err.Error()) }) - t.Run("required string list field argument provided with Int", func(t *testing.T) { + t.Run("required enum list argument provided with non list Int value", func(t *testing.T) { + tc := testCase{ + schema: `enum Foo { BAR } type Query { hello(arg: [Foo]!): String }`, + operation: `query Foo($bar: [Foo]!) { hello(arg: $bar) }`, + variables: `{"bar":123}`, + withNormalization: true, + } + err := runTest(t, tc) + require.Error(t, err) + assert.Equal(t, `Variable "$bar" got invalid value at "bar.[0]"; Enum "Foo" cannot represent non-string value.`, err.Error()) + }) + + t.Run("dev_mode required string list field argument provided with Int", func(t *testing.T) { + t.Setenv("DEV_MODE", "true") tc := testCase{ schema: `type Query { hello(arg: [String]!): String }`, operation: `query Foo($bar: [String]!) { hello(arg: $bar) }`, @@ -675,6 +1051,18 @@ func TestVariablesValidation(t *testing.T) { assert.Equal(t, `Variable "$bar" got invalid value 123 at "bar.[0]"; String cannot represent a non string value: 123`, err.Error()) }) + t.Run("required string list field argument provided with Int", func(t *testing.T) { + tc := testCase{ + schema: `type Query { hello(arg: [String]!): String }`, + operation: `query Foo($bar: [String]!) { hello(arg: $bar) }`, + variables: `{"bar":123}`, + withNormalization: true, + } + err := runTest(t, tc) + require.Error(t, err) + assert.Equal(t, `Variable "$bar" got invalid value at "bar.[0]"; String cannot represent a non string value`, err.Error()) + }) + t.Run("optional nested list argument provided with null", func(t *testing.T) { tc := testCase{ schema: `input Foo { bars : [String] bat: Int! } type Query { hello(arg: Foo): String }`, @@ -695,7 +1083,8 @@ func TestVariablesValidation(t *testing.T) { require.NoError(t, err) }) - t.Run("optional nested list argument provided with empty list and missing Int", func(t *testing.T) { + t.Run("dev_mode optional nested list argument provided with empty list and missing Int", func(t *testing.T) { + t.Setenv("DEV_MODE", "true") tc := testCase{ schema: `input Foo { bars : [String] bat: Int! } type Query { hello(arg: Foo): String }`, operation: `query Foo($input: Foo) { hello(arg: $input) }`, @@ -706,7 +1095,19 @@ func TestVariablesValidation(t *testing.T) { assert.Equal(t, `Variable "$input" got invalid value {"bars":[]}; Field "bat" of required type "Int!" was not provided.`, err.Error()) }) - t.Run("optional nested field is null followed by required nested field of wrong type", func(t *testing.T) { + t.Run("optional nested list argument provided with empty list and missing Int", func(t *testing.T) { + tc := testCase{ + schema: `input Foo { bars : [String] bat: Int! } type Query { hello(arg: Foo): String }`, + operation: `query Foo($input: Foo) { hello(arg: $input) }`, + variables: `{"input":{"bars":[]}}`, + } + err := runTest(t, tc) + require.Error(t, err) + assert.Equal(t, `Variable "$input" got invalid value; Field "bat" of required type "Int!" was not provided.`, err.Error()) + }) + + t.Run("dev_mode optional nested field is null followed by required nested field of wrong type", func(t *testing.T) { + t.Setenv("DEV_MODE", "true") tc := testCase{ schema: `input Foo { bar: String! } input Bar { foo: Foo bat: Int! } type Query { hello(arg: Bar): String }`, operation: `query Foo($input: Bar) { hello(arg: $input) }`, @@ -717,6 +1118,17 @@ func TestVariablesValidation(t *testing.T) { assert.Equal(t, `Variable "$input" got invalid value "hello" at "input.bat"; Int cannot represent non-integer value: "hello"`, err.Error()) }) + t.Run("optional nested field is null followed by required nested field of wrong type", func(t *testing.T) { + tc := testCase{ + schema: `input Foo { bar: String! } input Bar { foo: Foo bat: Int! } type Query { hello(arg: Bar): String }`, + operation: `query Foo($input: Bar) { hello(arg: $input) }`, + variables: `{"input":{"foo":null,"bat":"hello"}}`, + } + err := runTest(t, tc) + require.Error(t, err) + assert.Equal(t, `Variable "$input" got invalid value at "input.bat"; Int cannot represent non-integer value`, err.Error()) + }) + t.Run("input field is a double nested list", func(t *testing.T) { tc := testCase{ schema: `input Filter { option: String! } input FilterWrapper { filters: [[Filter!]!] } type Query { hello(filter: FilterWrapper): String }`, @@ -737,7 +1149,8 @@ func TestVariablesValidation(t *testing.T) { require.NoError(t, err) }) - t.Run("triple nested value into variable of double nested list type", func(t *testing.T) { + t.Run("dev_mode triple nested value into variable of double nested list type", func(t *testing.T) { + t.Setenv("DEV_MODE", "true") tc := testCase{ schema: `type Query { hello(filter: [[String]]): String }`, operation: `query Foo($input: [[String]]) { hello(filter: $input) }`, @@ -748,6 +1161,17 @@ func TestVariablesValidation(t *testing.T) { assert.Equal(t, `Variable "$input" got invalid value ["value"] at "input.[0].[0]"; String cannot represent a non string value: ["value"]`, err.Error()) }) + t.Run("triple nested value into variable of double nested list type", func(t *testing.T) { + tc := testCase{ + schema: `type Query { hello(filter: [[String]]): String }`, + operation: `query Foo($input: [[String]]) { hello(filter: $input) }`, + variables: `{"input":[[["value"]]]}`, + } + err := runTest(t, tc) + require.Error(t, err) + assert.Equal(t, `Variable "$input" got invalid value at "input.[0].[0]"; String cannot represent a non string value`, err.Error()) + }) + t.Run("null into non required list value", func(t *testing.T) { tc := testCase{ schema: `type Query { hello(filter: [String]): String }`, From acaf08f3981907c20466845ce995403b4caae0d2 Mon Sep 17 00:00:00 2001 From: Sam Christen Oliphant Date: Thu, 24 Oct 2024 14:27:18 -0400 Subject: [PATCH 3/6] fix remaining bugs --- .../variablesvalidation_test.go | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/v2/pkg/variablesvalidation/variablesvalidation_test.go b/v2/pkg/variablesvalidation/variablesvalidation_test.go index 0ff16a022..6743096b3 100644 --- a/v2/pkg/variablesvalidation/variablesvalidation_test.go +++ b/v2/pkg/variablesvalidation/variablesvalidation_test.go @@ -13,7 +13,7 @@ import ( ) func TestVariablesValidation(t *testing.T) { - + t.Run("required field argument not provided", func(t *testing.T) { tc := testCase{ schema: `type Query { hello(arg: String!): String }`, @@ -46,7 +46,8 @@ func TestVariablesValidation(t *testing.T) { require.NoError(t, err) }) - t.Run("unprovided required input fields without default values produce validation errors #1", func(t *testing.T) { + t.Run("dev_mode unprovided required input fields without default values produce validation errors #1", func(t *testing.T) { + t.Setenv("DEV_MODE", "true") tc := testCase{ schema: inputSchema, operation: `query Foo($input: SelfUnsatisfiedInput!) { unsatisfied(input: $input) }`, @@ -57,6 +58,18 @@ func TestVariablesValidation(t *testing.T) { assert.Equal(t, `Variable "$input" got invalid value {}; Field "nested" of required type "NestedSelfSatisfiedInput!" was not provided.`, err.Error()) }) + t.Run("unprovided required input fields without default values produce validation errors #1", func(t *testing.T) { + tc := testCase{ + schema: inputSchema, + operation: `query Foo($input: SelfUnsatisfiedInput!) { unsatisfied(input: $input) }`, + variables: `{ "input": { } }`, + } + err := runTest(t, tc) + require.Error(t, err) + assert.Equal(t, `Variable "$input" got invalid value; Field "nested" of required type "NestedSelfSatisfiedInput!" was not provided.`, err.Error()) + }) + + t.Run("dev_mode unprovided required input fields without default values produce validation errors #2", func(t *testing.T) { t.Setenv("DEV_MODE", "true") tc := testCase{ @@ -146,7 +159,6 @@ func TestVariablesValidation(t *testing.T) { }) t.Run("nested enum argument is value instead of list", func(t *testing.T) { - t.Setenv("DEV_MODE", "true") tc := testCase{ schema: `type Query { hello(input: Input): String } input Input { bar: [MyNum]! } enum MyNum { ONE TWO }`, operation: `query Foo($input: Input) { hello(input: $input) }`, @@ -941,7 +953,7 @@ func TestVariablesValidation(t *testing.T) { } err := runTest(t, tc) require.Error(t, err) - assert.Equal(t, `Variable "$bar" got invalid value 123 at "bar.[0].bar"; String cannot represent a non string value: 123`, err.Error()) + assert.Equal(t, `Variable "$bar" got invalid value at "bar.[0].bar"; String cannot represent a non string value`, err.Error()) }) t.Run("dev_mode required string argument on input object list provided with wrong value", func(t *testing.T) { From 0201aae467fa381e238ad467b0c5db3e95dfd705 Mon Sep 17 00:00:00 2001 From: Sam Christen Oliphant Date: Thu, 24 Oct 2024 15:25:29 -0400 Subject: [PATCH 4/6] this? --- .../variablesvalidation.go | 33 +++++++++---------- 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/v2/pkg/variablesvalidation/variablesvalidation.go b/v2/pkg/variablesvalidation/variablesvalidation.go index 20c302ec2..7f4d5f981 100644 --- a/v2/pkg/variablesvalidation/variablesvalidation.go +++ b/v2/pkg/variablesvalidation/variablesvalidation.go @@ -31,6 +31,7 @@ func NewVariablesValidator() *VariablesValidator { visitor := &variablesVisitor{ variables: &astjson.JSON{}, walker: &walker, + dev_mode: (strings.ToLower(os.Getenv("DEV_MODE")) == "true"), } walker.RegisterEnterVariableDefinitionVisitor(visitor) return &VariablesValidator{ @@ -64,6 +65,7 @@ type variablesVisitor struct { currentVariableName []byte currentVariableJsonNodeRef int path []pathItem + dev_mode bool } func (v *variablesVisitor) renderPath() string { @@ -89,11 +91,6 @@ const ( pathItemKindArray ) -func devModeCheck() bool { - d := strings.ToLower(os.Getenv("DEV_MODE")) - return (d == "true") -} - type pathItem struct { kind pathItemKind name []byte @@ -189,7 +186,7 @@ func (v *variablesVisitor) renderVariableInvalidObjectTypeError(typeName []byte, return } variableContent := out.String() - if devModeCheck() { + if v.dev_mode { v.err = &InvalidVariableError{ Message: fmt.Sprintf(`Variable "$%s" got invalid value %s; Expected type "%s" to be an object.`, string(v.currentVariableName), variableContent, string(typeName)), } @@ -214,7 +211,7 @@ func (v *variablesVisitor) renderVariableRequiredNotProvidedError(fieldName []by v.err = err return } - if devModeCheck() { + if v.dev_mode { v.err = &InvalidVariableError{ Message: fmt.Sprintf(`Variable "$%s" got invalid value %s; Field "%s" of required type "%s" was not provided.`, string(v.currentVariableName), variableContent, string(fieldName), out.String()), } @@ -243,7 +240,7 @@ func (v *variablesVisitor) renderVariableInvalidNestedTypeError(actualJsonNodeRe case ast.NodeKindScalarTypeDefinition: switch typeName { case "String": - if devModeCheck() { + if v.dev_mode { v.err = &InvalidVariableError{ Message: fmt.Sprintf(`Variable "$%s" got invalid value %s%s; String cannot represent a non string value: %s`, variableName, invalidValue, path, invalidValue), } @@ -253,7 +250,7 @@ func (v *variablesVisitor) renderVariableInvalidNestedTypeError(actualJsonNodeRe } } case "Int": - if devModeCheck() { + if v.dev_mode { v.err = &InvalidVariableError{ Message: fmt.Sprintf(`Variable "$%s" got invalid value %s%s; Int cannot represent non-integer value: %s`, variableName, invalidValue, path, invalidValue), } @@ -263,7 +260,7 @@ func (v *variablesVisitor) renderVariableInvalidNestedTypeError(actualJsonNodeRe } } case "Float": - if devModeCheck() { + if v.dev_mode { v.err = &InvalidVariableError{ Message: fmt.Sprintf(`Variable "$%s" got invalid value %s%s; Float cannot represent non numeric value: %s`, variableName, invalidValue, path, invalidValue), } @@ -273,7 +270,7 @@ func (v *variablesVisitor) renderVariableInvalidNestedTypeError(actualJsonNodeRe } } case "Boolean": - if devModeCheck() { + if v.dev_mode { v.err = &InvalidVariableError{ Message: fmt.Sprintf(`Variable "$%s" got invalid value %s%s; Boolean cannot represent a non boolean value: %s`, variableName, invalidValue, path, invalidValue), } @@ -283,7 +280,7 @@ func (v *variablesVisitor) renderVariableInvalidNestedTypeError(actualJsonNodeRe } } case "ID": - if devModeCheck() { + if v.dev_mode { v.err = &InvalidVariableError{ Message: fmt.Sprintf(`Variable "$%s" got invalid value %s%s; ID cannot represent value: %s`, variableName, invalidValue, path, invalidValue), } @@ -293,7 +290,7 @@ func (v *variablesVisitor) renderVariableInvalidNestedTypeError(actualJsonNodeRe } } default: - if devModeCheck() { + if v.dev_mode { v.err = &InvalidVariableError{ Message: fmt.Sprintf(`Variable "$%s" got invalid value %s%s; Expected type "%s" to be a scalar.`, variableName, invalidValue, path, typeName), } @@ -305,7 +302,7 @@ func (v *variablesVisitor) renderVariableInvalidNestedTypeError(actualJsonNodeRe } case ast.NodeKindInputObjectTypeDefinition: if expectedList { - if devModeCheck() { + if v.dev_mode { v.err = &InvalidVariableError{ Message: fmt.Sprintf(`Variable "$%s" got invalid value %s%s; Got input type "%s", want: "[%s]"`, variableName, invalidValue, path, typeName, typeName), } @@ -315,7 +312,7 @@ func (v *variablesVisitor) renderVariableInvalidNestedTypeError(actualJsonNodeRe } } } else { - if devModeCheck() { + if v.dev_mode { v.err = &InvalidVariableError{ Message: fmt.Sprintf(`Variable "$%s" got invalid value %s%s; Expected type "%s" to be an input object.`, variableName, invalidValue, path, typeName), } @@ -326,7 +323,7 @@ func (v *variablesVisitor) renderVariableInvalidNestedTypeError(actualJsonNodeRe } } case ast.NodeKindEnumTypeDefinition: - if devModeCheck() { + if v.dev_mode { v.err = &InvalidVariableError{ Message: fmt.Sprintf(`Variable "$%s" got invalid value %s%s; Enum "%s" cannot represent non-string value: %s.`, variableName, invalidValue, path, typeName, invalidValue), } @@ -348,7 +345,7 @@ func (v *variablesVisitor) renderVariableFieldNotDefinedError(fieldName []byte, } invalidValue := buf.String() path := v.renderPath() - if devModeCheck() { + if v.dev_mode { v.err = &InvalidVariableError{ Message: fmt.Sprintf(`Variable "$%s" got invalid value %s at "%s"; Field "%s" is not defined by type "%s".`, variableName, invalidValue, path, string(fieldName), string(typeName)), } @@ -372,7 +369,7 @@ func (v *variablesVisitor) renderVariableEnumValueDoesNotExistError(typeName []b if len(v.path) > 1 { path = fmt.Sprintf(` at "%s"`, v.renderPath()) } - if devModeCheck() { + if v.dev_mode { v.err = &InvalidVariableError{ Message: fmt.Sprintf(`Variable "$%s" got invalid value %s%s; Value "%s" does not exist in "%s" enum.`, variableName, invalidValue, path, string(enumValue), string(typeName)), } From 86df2c6a465175b1fd8ad9ca06747bc533131e9c Mon Sep 17 00:00:00 2001 From: Sam Christen Oliphant Date: Thu, 24 Oct 2024 15:27:51 -0400 Subject: [PATCH 5/6] spacing matters --- v2/pkg/variablesvalidation/variablesvalidation.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/v2/pkg/variablesvalidation/variablesvalidation.go b/v2/pkg/variablesvalidation/variablesvalidation.go index 7f4d5f981..f7f4ac193 100644 --- a/v2/pkg/variablesvalidation/variablesvalidation.go +++ b/v2/pkg/variablesvalidation/variablesvalidation.go @@ -65,7 +65,7 @@ type variablesVisitor struct { currentVariableName []byte currentVariableJsonNodeRef int path []pathItem - dev_mode bool + dev_mode bool } func (v *variablesVisitor) renderPath() string { From 8ce789a112e22e06efc2a0d5bf518eba60fe64b7 Mon Sep 17 00:00:00 2001 From: Sam Christen Oliphant Date: Fri, 25 Oct 2024 09:10:46 -0400 Subject: [PATCH 6/6] this works at least --- .../variablesvalidation.go | 9 +- .../variablesvalidation_test.go | 361 +++++++++++------- 2 files changed, 221 insertions(+), 149 deletions(-) diff --git a/v2/pkg/variablesvalidation/variablesvalidation.go b/v2/pkg/variablesvalidation/variablesvalidation.go index f7f4ac193..95e12d39a 100644 --- a/v2/pkg/variablesvalidation/variablesvalidation.go +++ b/v2/pkg/variablesvalidation/variablesvalidation.go @@ -3,8 +3,6 @@ package variablesvalidation import ( "bytes" "fmt" - "os" - "strings" "github.com/wundergraph/graphql-go-tools/v2/pkg/ast" "github.com/wundergraph/graphql-go-tools/v2/pkg/astjson" @@ -31,7 +29,7 @@ func NewVariablesValidator() *VariablesValidator { visitor := &variablesVisitor{ variables: &astjson.JSON{}, walker: &walker, - dev_mode: (strings.ToLower(os.Getenv("DEV_MODE")) == "true"), + dev_mode: false, } walker.RegisterEnterVariableDefinitionVisitor(visitor) return &VariablesValidator{ @@ -40,8 +38,11 @@ func NewVariablesValidator() *VariablesValidator { } } -func (v *VariablesValidator) Validate(operation, definition *ast.Document, variables []byte) error { +func (v *VariablesValidator) Validate(operation, definition *ast.Document, variables []byte, devMode bool) error { v.visitor.err = nil + if devMode { + v.visitor.dev_mode = devMode + } v.visitor.definition = definition v.visitor.operation = operation err := v.visitor.variables.ParseObject(variables) diff --git a/v2/pkg/variablesvalidation/variablesvalidation_test.go b/v2/pkg/variablesvalidation/variablesvalidation_test.go index 6743096b3..71ff43eb1 100644 --- a/v2/pkg/variablesvalidation/variablesvalidation_test.go +++ b/v2/pkg/variablesvalidation/variablesvalidation_test.go @@ -15,1202 +15,1273 @@ import ( func TestVariablesValidation(t *testing.T) { t.Run("required field argument not provided", func(t *testing.T) { + devMode := false tc := testCase{ schema: `type Query { hello(arg: String!): String }`, operation: `query Foo($bar: String!) { hello }`, variables: `{}`, } - err := runTest(t, tc) + err := runTest(t, tc, devMode) require.Error(t, err) assert.Equal(t, `Variable "$bar" of required type "String!" was not provided.`, err.Error()) }) t.Run("a missing required input produces an error", func(t *testing.T) { + devMode := false tc := testCase{ schema: inputSchema, operation: `query Foo($input: SelfSatisfiedInput!) { satisfied }`, variables: `{}`, } - err := runTest(t, tc) + err := runTest(t, tc, devMode) require.Error(t, err) assert.Equal(t, `Variable "$input" of required type "SelfSatisfiedInput!" was not provided.`, err.Error()) }) t.Run("provided required input fields with default values do not produce validation errors", func(t *testing.T) { + devMode := false tc := testCase{ schema: inputSchema, operation: `query Foo($input: SelfSatisfiedInput!) { satisfied(input: $input) }`, variables: `{ "input": { } }`, } - err := runTest(t, tc) + err := runTest(t, tc, devMode) require.NoError(t, err) }) t.Run("dev_mode unprovided required input fields without default values produce validation errors #1", func(t *testing.T) { - t.Setenv("DEV_MODE", "true") + devMode := true tc := testCase{ schema: inputSchema, operation: `query Foo($input: SelfUnsatisfiedInput!) { unsatisfied(input: $input) }`, variables: `{ "input": { } }`, } - err := runTest(t, tc) + err := runTest(t, tc, devMode) require.Error(t, err) assert.Equal(t, `Variable "$input" got invalid value {}; Field "nested" of required type "NestedSelfSatisfiedInput!" was not provided.`, err.Error()) }) t.Run("unprovided required input fields without default values produce validation errors #1", func(t *testing.T) { + devMode := false tc := testCase{ schema: inputSchema, operation: `query Foo($input: SelfUnsatisfiedInput!) { unsatisfied(input: $input) }`, variables: `{ "input": { } }`, } - err := runTest(t, tc) + err := runTest(t, tc, devMode) require.Error(t, err) assert.Equal(t, `Variable "$input" got invalid value; Field "nested" of required type "NestedSelfSatisfiedInput!" was not provided.`, err.Error()) }) t.Run("dev_mode unprovided required input fields without default values produce validation errors #2", func(t *testing.T) { - t.Setenv("DEV_MODE", "true") + devMode := true tc := testCase{ schema: inputSchema, operation: `query Foo($input: SelfUnsatisfiedInput!) { unsatisfied(input: $input) }`, variables: `{ "input": { "nested": { }, "value": "string" } }`, } - err := runTest(t, tc) + err := runTest(t, tc, devMode) require.Error(t, err) assert.Equal(t, `Variable "$input" got invalid value {"nested":{},"value":"string"}; Field "secondNested" of required type "NestedSelfSatisfiedInput!" was not provided.`, err.Error()) }) t.Run("unprovided required input fields without default values produce validation errors #2", func(t *testing.T) { + devMode := false tc := testCase{ schema: inputSchema, operation: `query Foo($input: SelfUnsatisfiedInput!) { unsatisfied(input: $input) }`, variables: `{ "input": { "nested": { }, "value": "string" } }`, } - err := runTest(t, tc) + err := runTest(t, tc, devMode) require.Error(t, err) assert.Equal(t, `Variable "$input" got invalid value; Field "secondNested" of required type "NestedSelfSatisfiedInput!" was not provided.`, err.Error()) }) t.Run("provided but empty nested required inputs with default values do not produce validation errors", func(t *testing.T) { + devMode := false tc := testCase{ schema: inputSchema, operation: `query Foo($input: SelfUnsatisfiedInput!) { unsatisfied(input: $input) }`, variables: `{ "input": { "nested": { }, "secondNested": { } } }`, } - err := runTest(t, tc) + err := runTest(t, tc, devMode) require.NoError(t, err) }) t.Run("not required field argument not provided", func(t *testing.T) { + devMode := false tc := testCase{ schema: `type Query { hello(arg: String): String }`, operation: `query Foo($bar: String) { hello }`, variables: `{}`, } - err := runTest(t, tc) + err := runTest(t, tc, devMode) require.NoError(t, err) }) t.Run("required field argument provided", func(t *testing.T) { + devMode := false tc := testCase{ schema: `type Query { hello(arg: String!): String }`, operation: `query Foo($bar: String!) { hello(arg: $bar) }`, variables: `{"bar": "world"}`, } - err := runTest(t, tc) + err := runTest(t, tc, devMode) require.NoError(t, err) }) t.Run("dev_mode nested argument is value instead of list", func(t *testing.T) { - t.Setenv("DEV_MODE", "true") + devMode := true tc := testCase{ schema: `type Query { hello(input: Input): String } input Input { bar: [String]! }`, operation: `query Foo($input: Input) { hello(input: $input) }`, variables: `{"input":{"bar":"world"}}`, } - err := runTest(t, tc) + err := runTest(t, tc, devMode) require.NotNil(t, err) assert.Equal(t, `Variable "$input" got invalid value "world" at "input.bar"; Got input type "String", want: "[String]"`, err.Error()) }) t.Run("nested argument is value instead of list", func(t *testing.T) { + devMode := false tc := testCase{ schema: `type Query { hello(input: Input): String } input Input { bar: [String]! }`, operation: `query Foo($input: Input) { hello(input: $input) }`, variables: `{"input":{"bar":"world"}}`, } - err := runTest(t, tc) + err := runTest(t, tc, devMode) require.NotNil(t, err) assert.Equal(t, `Variable "$input" got invalid value at "input.bar"; Got input type "String", want: "[String]"`, err.Error()) }) t.Run("dev_mode nested enum argument is value instead of list", func(t *testing.T) { - t.Setenv("DEV_MODE", "true") + devMode := true tc := testCase{ schema: `type Query { hello(input: Input): String } input Input { bar: [MyNum]! } enum MyNum { ONE TWO }`, operation: `query Foo($input: Input) { hello(input: $input) }`, variables: `{"input":{"bar":"ONE"}}`, } - err := runTest(t, tc) + err := runTest(t, tc, devMode) require.NotNil(t, err) assert.Equal(t, `Variable "$input" got invalid value "ONE" at "input.bar"; Got input type "MyNum", want: "[MyNum]"`, err.Error()) }) t.Run("nested enum argument is value instead of list", func(t *testing.T) { + devMode := false tc := testCase{ schema: `type Query { hello(input: Input): String } input Input { bar: [MyNum]! } enum MyNum { ONE TWO }`, operation: `query Foo($input: Input) { hello(input: $input) }`, variables: `{"input":{"bar":"ONE"}}`, } - err := runTest(t, tc) + err := runTest(t, tc, devMode) require.NotNil(t, err) assert.Equal(t, `Variable "$input" got invalid value at "input.bar"; Got input type "MyNum", want: "[MyNum]"`, err.Error()) }) t.Run("required field argument of custom scalar type not provided", func(t *testing.T) { + devMode := false tc := testCase{ schema: `type Query { hello(arg: Baz!): String } scalar Baz`, operation: `query Foo($bar: Baz!) { hello(arg: $bar) }`, variables: `{}`, } - err := runTest(t, tc) + err := runTest(t, tc, devMode) assert.NotNil(t, err) assert.Equal(t, `Variable "$bar" of required type "Baz!" was not provided.`, err.Error()) }) t.Run("required field argument of custom scalar type was null", func(t *testing.T) { + devMode := false tc := testCase{ schema: `type Query { hello(arg: Baz!): String } scalar Baz`, operation: `query Foo($bar: Baz!) { hello(arg: $bar) }`, variables: `{"bar":null}`, } - err := runTest(t, tc) + err := runTest(t, tc, devMode) assert.NotNil(t, err) assert.Equal(t, `Variable "$bar" got invalid value null; Expected non-nullable type "Baz!" not to be null.`, err.Error()) }) t.Run("dev_mode required nested field field argument of custom scalar not provided", func(t *testing.T) { - t.Setenv("DEV_MODE", "true") + devMode := true tc := testCase{ schema: `type Query { hello(arg: Foo!): String } input Foo { bar: Baz! } scalar Baz`, operation: `query Foo($bar: Foo!) { hello(arg: $bar) }`, variables: `{"bar":{}}`, } - err := runTest(t, tc) + err := runTest(t, tc, devMode) assert.NotNil(t, err) assert.Equal(t, `Variable "$bar" got invalid value {}; Field "bar" of required type "Baz!" was not provided.`, err.Error()) }) t.Run("required nested field field argument of custom scalar not provided", func(t *testing.T) { + devMode := false tc := testCase{ schema: `type Query { hello(arg: Foo!): String } input Foo { bar: Baz! } scalar Baz`, operation: `query Foo($bar: Foo!) { hello(arg: $bar) }`, variables: `{"bar":{}}`, } - err := runTest(t, tc) + err := runTest(t, tc, devMode) assert.NotNil(t, err) assert.Equal(t, `Variable "$bar" got invalid value; Field "bar" of required type "Baz!" was not provided.`, err.Error()) }) t.Run("dev_mode required nested field field argument of custom scalar was null", func(t *testing.T) { - t.Setenv("DEV_MODE", "true") + devMode := true tc := testCase{ schema: `type Query { hello(arg: Foo!): String } input Foo { bar: Baz! } scalar Baz`, operation: `query Foo($bar: Foo!) { hello(arg: $bar) }`, variables: `{"bar":{"bar":null}}`, } - err := runTest(t, tc) + err := runTest(t, tc, devMode) assert.NotNil(t, err) assert.Equal(t, `Variable "$bar" got invalid value {"bar":null}; Field "bar" of required type "Baz!" was not provided.`, err.Error()) }) t.Run("required nested field field argument of custom scalar was null", func(t *testing.T) { + devMode := false tc := testCase{ schema: `type Query { hello(arg: Foo!): String } input Foo { bar: Baz! } scalar Baz`, operation: `query Foo($bar: Foo!) { hello(arg: $bar) }`, variables: `{"bar":{"bar":null}}`, } - err := runTest(t, tc) + err := runTest(t, tc, devMode) assert.NotNil(t, err) assert.Equal(t, `Variable "$bar" got invalid value; Field "bar" of required type "Baz!" was not provided.`, err.Error()) }) t.Run("required field argument provided with default value", func(t *testing.T) { + devMode := false tc := testCase{ schema: `type Query { hello(arg: String!): String }`, operation: `query Foo($bar: String! = "world") { hello(arg: $bar) }`, variables: `{}`, withNormalization: true, } - err := runTest(t, tc) + err := runTest(t, tc, devMode) require.NoError(t, err) }) t.Run("required Int field argument not provided", func(t *testing.T) { + devMode := false tc := testCase{ schema: `type Query { hello(arg: Int!): String }`, operation: `query Foo($bar: Int!) { hello }`, variables: `{}`, } - err := runTest(t, tc) + err := runTest(t, tc, devMode) require.Error(t, err) assert.Equal(t, `Variable "$bar" of required type "Int!" was not provided.`, err.Error()) }) t.Run("required Float field argument not provided", func(t *testing.T) { + devMode := false tc := testCase{ schema: `type Query { hello(arg: Float!): String }`, operation: `query Foo($bar: Float!) { hello }`, variables: `{}`, } - err := runTest(t, tc) + err := runTest(t, tc, devMode) require.Error(t, err) assert.Equal(t, `Variable "$bar" of required type "Float!" was not provided.`, err.Error()) }) t.Run("required Boolean field argument not provided", func(t *testing.T) { + devMode := false tc := testCase{ schema: `type Query { hello(arg: Boolean!): String }`, operation: `query Foo($bar: Boolean!) { hello }`, variables: `{}`, } - err := runTest(t, tc) + err := runTest(t, tc, devMode) require.Error(t, err) assert.Equal(t, `Variable "$bar" of required type "Boolean!" was not provided.`, err.Error()) }) t.Run("required ID field argument not provided", func(t *testing.T) { + devMode := false tc := testCase{ schema: `type Query { hello(arg: ID!): String }`, operation: `query Foo($bar: ID!) { hello }`, variables: `{}`, } - err := runTest(t, tc) + err := runTest(t, tc, devMode) require.Error(t, err) assert.Equal(t, `Variable "$bar" of required type "ID!" was not provided.`, err.Error()) }) t.Run("required ID field argument provided with Int", func(t *testing.T) { + devMode := false tc := testCase{ schema: `type Query { hello(arg: ID!): String }`, operation: `query Foo($bar: ID!) { hello(arg: $bar) }`, variables: `{"bar":123}`, } - err := runTest(t, tc) + err := runTest(t, tc, devMode) require.NoError(t, err) }) t.Run("required ID field argument provided with String", func(t *testing.T) { + devMode := false tc := testCase{ schema: `type Query { hello(arg: ID!): String }`, operation: `query Foo($bar: ID!) { hello(arg: $bar) }`, variables: `{"bar":"hello"}`, } - err := runTest(t, tc) + err := runTest(t, tc, devMode) require.NoError(t, err) }) t.Run("required Enum field argument not provided", func(t *testing.T) { + devMode := false tc := testCase{ schema: `enum Foo { BAR } type Query { hello(arg: Foo!): String }`, operation: `query Foo($bar: Foo!) { hello }`, variables: `{}`, } - err := runTest(t, tc) + err := runTest(t, tc, devMode) require.Error(t, err) assert.Equal(t, `Variable "$bar" of required type "Foo!" was not provided.`, err.Error()) }) t.Run("required input object field argument not provided", func(t *testing.T) { + devMode := false tc := testCase{ schema: `input Foo { bar: String! } type Query { hello(arg: Foo!): String }`, operation: `query Foo($bar: Foo!) { hello }`, variables: `{}`, } - err := runTest(t, tc) + err := runTest(t, tc, devMode) require.Error(t, err) assert.Equal(t, `Variable "$bar" of required type "Foo!" was not provided.`, err.Error()) }) t.Run("required string list field argument not provided", func(t *testing.T) { + devMode := false tc := testCase{ schema: `type Query { hello(arg: [String]!): String }`, operation: `query Foo($bar: [String]!) { hello }`, variables: `{}`, } - err := runTest(t, tc) + err := runTest(t, tc, devMode) require.Error(t, err) assert.Equal(t, `Variable "$bar" of required type "[String]!" was not provided.`, err.Error()) }) t.Run("dev_mode wrong Boolean value for input object field", func(t *testing.T) { - t.Setenv("DEV_MODE", "true") + devMode := true tc := testCase{ schema: `input Foo { bar: String! } type Query { hello(arg: Foo!): String }`, operation: `query Foo($bar: Foo!) { hello(arg: $bar) }`, variables: `{"bar":true}`, } - err := runTest(t, tc) + err := runTest(t, tc, devMode) require.Error(t, err) assert.Equal(t, `Variable "$bar" got invalid value true; Expected type "Foo" to be an object.`, err.Error()) }) t.Run("wrong Boolean value for input object field", func(t *testing.T) { + devMode := false tc := testCase{ schema: `input Foo { bar: String! } type Query { hello(arg: Foo!): String }`, operation: `query Foo($bar: Foo!) { hello(arg: $bar) }`, variables: `{"bar":true}`, } - err := runTest(t, tc) + err := runTest(t, tc, devMode) require.Error(t, err) assert.Equal(t, `Variable "$bar" got invalid value; Expected type "Foo" to be an object.`, err.Error()) }) t.Run("dev_mode wrong Integer value for input object field", func(t *testing.T) { - t.Setenv("DEV_MODE", "true") + devMode := true tc := testCase{ schema: `input Foo { bar: String! } type Query { hello(arg: Foo!): String }`, operation: `query Foo($bar: Foo!) { hello(arg: $bar) }`, variables: `{"bar":123}`, } - err := runTest(t, tc) + err := runTest(t, tc, devMode) require.Error(t, err) assert.Equal(t, `Variable "$bar" got invalid value 123; Expected type "Foo" to be an object.`, err.Error()) }) t.Run("wrong Integer value for input object field", func(t *testing.T) { + devMode := false tc := testCase{ schema: `input Foo { bar: String! } type Query { hello(arg: Foo!): String }`, operation: `query Foo($bar: Foo!) { hello(arg: $bar) }`, variables: `{"bar":123}`, } - err := runTest(t, tc) + err := runTest(t, tc, devMode) require.Error(t, err) assert.Equal(t, `Variable "$bar" got invalid value; Expected type "Foo" to be an object.`, err.Error()) }) t.Run("dev_mode required field on present input object not provided", func(t *testing.T) { - t.Setenv("DEV_MODE", "true") + devMode := true tc := testCase{ schema: `input Foo { bar: String! } type Query { hello(arg: Foo!): String }`, operation: `query Foo($bar: Foo!) { hello(arg: $bar) }`, variables: `{"bar":{}}`, } - err := runTest(t, tc) + err := runTest(t, tc, devMode) require.Error(t, err) assert.Equal(t, `Variable "$bar" got invalid value {}; Field "bar" of required type "String!" was not provided.`, err.Error()) }) t.Run("required field on present input object not provided", func(t *testing.T) { + devMode := false tc := testCase{ schema: `input Foo { bar: String! } type Query { hello(arg: Foo!): String }`, operation: `query Foo($bar: Foo!) { hello(arg: $bar) }`, variables: `{"bar":{}}`, } - err := runTest(t, tc) + err := runTest(t, tc, devMode) require.Error(t, err) assert.Equal(t, `Variable "$bar" got invalid value; Field "bar" of required type "String!" was not provided.`, err.Error()) }) t.Run("required field on present input object provided with correct type", func(t *testing.T) { + devMode := false tc := testCase{ schema: `input Foo { bar: String! } type Query { hello(arg: Foo!): String }`, operation: `query Foo($bar: Foo!) { hello(arg: $bar) }`, variables: `{"bar":{"bar":"hello"}}`, } - err := runTest(t, tc) + err := runTest(t, tc, devMode) require.NoError(t, err) }) t.Run("dev_mode required field on present input object provided with wrong type", func(t *testing.T) { - t.Setenv("DEV_MODE", "true") + devMode := true tc := testCase{ schema: `input Foo { bar: String! } type Query { hello(arg: Foo!): String }`, operation: `query Foo($input: Foo!) { hello(arg: $input) }`, variables: `{"input":{"bar":123}}`, } - err := runTest(t, tc) + err := runTest(t, tc, devMode) require.Error(t, err) assert.Equal(t, `Variable "$input" got invalid value 123 at "input.bar"; String cannot represent a non string value: 123`, err.Error()) }) t.Run("required field on present input object provided with wrong type", func(t *testing.T) { + devMode := false tc := testCase{ schema: `input Foo { bar: String! } type Query { hello(arg: Foo!): String }`, operation: `query Foo($input: Foo!) { hello(arg: $input) }`, variables: `{"input":{"bar":123}}`, } - err := runTest(t, tc) + err := runTest(t, tc, devMode) require.Error(t, err) assert.Equal(t, `Variable "$input" got invalid value at "input.bar"; String cannot represent a non string value`, err.Error()) }) t.Run("dev_mode required field on present input object not provided", func(t *testing.T) { - t.Setenv("DEV_MODE", "true") + devMode := true tc := testCase{ schema: `input Foo { bar: String! } type Query { hello(arg: Foo!): String }`, operation: `query Foo($input: Foo!) { hello(arg: $input) }`, variables: `{"input":{}}`, } - err := runTest(t, tc) + err := runTest(t, tc, devMode) require.Error(t, err) assert.Equal(t, `Variable "$input" got invalid value {}; Field "bar" of required type "String!" was not provided.`, err.Error()) }) t.Run("required field on present input object not provided", func(t *testing.T) { + devMode := false tc := testCase{ schema: `input Foo { bar: String! } type Query { hello(arg: Foo!): String }`, operation: `query Foo($input: Foo!) { hello(arg: $input) }`, variables: `{"input":{}}`, } - err := runTest(t, tc) + err := runTest(t, tc, devMode) require.Error(t, err) assert.Equal(t, `Variable "$input" got invalid value; Field "bar" of required type "String!" was not provided.`, err.Error()) }) t.Run("dev_mode required string field on input object provided with null", func(t *testing.T) { - t.Setenv("DEV_MODE", "true") + devMode := true tc := testCase{ schema: `input Foo { bar: String! } type Query { hello(arg: Foo!): String }`, operation: `query Foo($input: Foo!) { hello(arg: $input) }`, variables: `{"input":{"bar":null}}`, } - err := runTest(t, tc) + err := runTest(t, tc, devMode) require.Error(t, err) assert.Equal(t, `Variable "$input" got invalid value {"bar":null}; Field "bar" of required type "String!" was not provided.`, err.Error()) }) t.Run("required string field on input object provided with null", func(t *testing.T) { + devMode := false tc := testCase{ schema: `input Foo { bar: String! } type Query { hello(arg: Foo!): String }`, operation: `query Foo($input: Foo!) { hello(arg: $input) }`, variables: `{"input":{"bar":null}}`, } - err := runTest(t, tc) + err := runTest(t, tc, devMode) require.Error(t, err) assert.Equal(t, `Variable "$input" got invalid value; Field "bar" of required type "String!" was not provided.`, err.Error()) }) t.Run("dev_mode required string field on input object provided with Int", func(t *testing.T) { - t.Setenv("DEV_MODE", "true") + devMode := true tc := testCase{ schema: `input Foo { bar: String! } type Query { hello(arg: Foo!): String }`, operation: `query Foo($input: Foo!) { hello(arg: $input) }`, variables: `{"input":{"bar":123}}`, } - err := runTest(t, tc) + err := runTest(t, tc, devMode) require.Error(t, err) assert.Equal(t, `Variable "$input" got invalid value 123 at "input.bar"; String cannot represent a non string value: 123`, err.Error()) }) t.Run("required string field on input object provided with Int", func(t *testing.T) { + devMode := false tc := testCase{ schema: `input Foo { bar: String! } type Query { hello(arg: Foo!): String }`, operation: `query Foo($input: Foo!) { hello(arg: $input) }`, variables: `{"input":{"bar":123}}`, } - err := runTest(t, tc) + err := runTest(t, tc, devMode) require.Error(t, err) assert.Equal(t, `Variable "$input" got invalid value at "input.bar"; String cannot represent a non string value`, err.Error()) }) t.Run("dev_mode required string field on input object provided with Float", func(t *testing.T) { - t.Setenv("DEV_MODE", "true") + devMode := true tc := testCase{ schema: `input Foo { bar: String! } type Query { hello(arg: Foo!): String }`, operation: `query Foo($input: Foo!) { hello(arg: $input) }`, variables: `{"input":{"bar":123.456}}`, } - err := runTest(t, tc) + err := runTest(t, tc, devMode) require.Error(t, err) assert.Equal(t, `Variable "$input" got invalid value 123.456 at "input.bar"; String cannot represent a non string value: 123.456`, err.Error()) }) t.Run("required string field on input object provided with Float", func(t *testing.T) { + devMode := false tc := testCase{ schema: `input Foo { bar: String! } type Query { hello(arg: Foo!): String }`, operation: `query Foo($input: Foo!) { hello(arg: $input) }`, variables: `{"input":{"bar":123.456}}`, } - err := runTest(t, tc) + err := runTest(t, tc, devMode) require.Error(t, err) assert.Equal(t, `Variable "$input" got invalid value at "input.bar"; String cannot represent a non string value`, err.Error()) }) t.Run("dev_mode required string field on input object provided with Boolean", func(t *testing.T) { - t.Setenv("DEV_MODE", "true") + devMode := true tc := testCase{ schema: `input Foo { bar: String! } type Query { hello(arg: Foo!): String }`, operation: `query Foo($input: Foo!) { hello(arg: $input) }`, variables: `{"input":{"bar":true}}`, } - err := runTest(t, tc) + err := runTest(t, tc, devMode) require.Error(t, err) assert.Equal(t, `Variable "$input" got invalid value true at "input.bar"; String cannot represent a non string value: true`, err.Error()) }) t.Run("required string field on input object provided with Boolean", func(t *testing.T) { + devMode := false tc := testCase{ schema: `input Foo { bar: String! } type Query { hello(arg: Foo!): String }`, operation: `query Foo($input: Foo!) { hello(arg: $input) }`, variables: `{"input":{"bar":true}}`, } - err := runTest(t, tc) + err := runTest(t, tc, devMode) require.Error(t, err) assert.Equal(t, `Variable "$input" got invalid value at "input.bar"; String cannot represent a non string value`, err.Error()) }) t.Run("dev_mode required string field on nested input object not provided", func(t *testing.T) { - t.Setenv("DEV_MODE", "true") + devMode := true tc := testCase{ schema: `input Foo { bar: String! } input Bar { foo: Foo! } type Query { hello(arg: Bar!): String }`, operation: `query Foo($input: Bar!) { hello(arg: $input) }`, variables: `{"input":{"foo":{}}}`, } - err := runTest(t, tc) + err := runTest(t, tc, devMode) require.Error(t, err) assert.Equal(t, `Variable "$input" got invalid value {"foo":{}}; Field "bar" of required type "String!" was not provided.`, err.Error()) }) t.Run("required string field on nested input object not provided", func(t *testing.T) { + devMode := false tc := testCase{ schema: `input Foo { bar: String! } input Bar { foo: Foo! } type Query { hello(arg: Bar!): String }`, operation: `query Foo($input: Bar!) { hello(arg: $input) }`, variables: `{"input":{"foo":{}}}`, } - err := runTest(t, tc) + err := runTest(t, tc, devMode) require.Error(t, err) assert.Equal(t, `Variable "$input" got invalid value; Field "bar" of required type "String!" was not provided.`, err.Error()) }) t.Run("dev_mode required string field on nested input object provided with null", func(t *testing.T) { - t.Setenv("DEV_MODE", "true") + devMode := true tc := testCase{ schema: `input Foo { bar: String! } input Bar { foo: Foo! } type Query { hello(arg: Bar!): String }`, operation: `query Foo($input: Bar!) { hello(arg: $input) }`, variables: `{"input":{"foo":{"bar":null}}}`, } - err := runTest(t, tc) + err := runTest(t, tc, devMode) require.Error(t, err) assert.Equal(t, `Variable "$input" got invalid value {"foo":{"bar":null}}; Field "bar" of required type "String!" was not provided.`, err.Error()) }) t.Run("required string field on nested input object provided with null", func(t *testing.T) { + devMode := false tc := testCase{ schema: `input Foo { bar: String! } input Bar { foo: Foo! } type Query { hello(arg: Bar!): String }`, operation: `query Foo($input: Bar!) { hello(arg: $input) }`, variables: `{"input":{"foo":{"bar":null}}}`, } - err := runTest(t, tc) + err := runTest(t, tc, devMode) require.Error(t, err) assert.Equal(t, `Variable "$input" got invalid value; Field "bar" of required type "String!" was not provided.`, err.Error()) }) t.Run("dev_mode required string field on nested input object provided with Int", func(t *testing.T) { - t.Setenv("DEV_MODE", "true") + devMode := true tc := testCase{ schema: `input Foo { bar: String! } input Bar { foo: Foo! } type Query { hello(arg: Bar!): String }`, operation: `query Foo($input: Bar!) { hello(arg: $input) }`, variables: `{"input":{"foo":{"bar":123}}}`, } - err := runTest(t, tc) + err := runTest(t, tc, devMode) require.Error(t, err) assert.Equal(t, `Variable "$input" got invalid value 123 at "input.foo.bar"; String cannot represent a non string value: 123`, err.Error()) }) t.Run("required string field on nested input object provided with Int", func(t *testing.T) { + devMode := false tc := testCase{ schema: `input Foo { bar: String! } input Bar { foo: Foo! } type Query { hello(arg: Bar!): String }`, operation: `query Foo($input: Bar!) { hello(arg: $input) }`, variables: `{"input":{"foo":{"bar":123}}}`, } - err := runTest(t, tc) + err := runTest(t, tc, devMode) require.Error(t, err) assert.Equal(t, `Variable "$input" got invalid value at "input.foo.bar"; String cannot represent a non string value`, err.Error()) }) t.Run("dev_mode required string field on nested input object array provided with Int", func(t *testing.T) { - t.Setenv("DEV_MODE", "true") + devMode := true tc := testCase{ schema: `input Foo { bar: String! } input Bar { foo: [Foo!]! } type Query { hello(arg: Bar!): String }`, operation: `query Foo($input: Bar!) { hello(arg: $input) }`, variables: `{"input":{"foo":[{"bar":123}]}}`, } - err := runTest(t, tc) + err := runTest(t, tc, devMode) require.Error(t, err) assert.Equal(t, `Variable "$input" got invalid value 123 at "input.foo.[0].bar"; String cannot represent a non string value: 123`, err.Error()) }) t.Run("required string field on nested input object array provided with Int", func(t *testing.T) { + devMode := false tc := testCase{ schema: `input Foo { bar: String! } input Bar { foo: [Foo!]! } type Query { hello(arg: Bar!): String }`, operation: `query Foo($input: Bar!) { hello(arg: $input) }`, variables: `{"input":{"foo":[{"bar":123}]}}`, } - err := runTest(t, tc) + err := runTest(t, tc, devMode) require.Error(t, err) assert.Equal(t, `Variable "$input" got invalid value at "input.foo.[0].bar"; String cannot represent a non string value`, err.Error()) }) t.Run("dev_mode required string field on nested input object array index 1 provided with Int", func(t *testing.T) { - t.Setenv("DEV_MODE", "true") + devMode := true tc := testCase{ schema: `input Foo { bar: String! } input Bar { foo: [Foo!]! } type Query { hello(arg: Bar!): String }`, operation: `query Foo($input: Bar!) { hello(arg: $input) }`, variables: `{"input":{"foo":[{"bar":"hello"},{"bar":123}]}}`, } - err := runTest(t, tc) + err := runTest(t, tc, devMode) require.Error(t, err) assert.Equal(t, `Variable "$input" got invalid value 123 at "input.foo.[1].bar"; String cannot represent a non string value: 123`, err.Error()) }) t.Run("required string field on nested input object array index 1 provided with Int", func(t *testing.T) { + devMode := false tc := testCase{ schema: `input Foo { bar: String! } input Bar { foo: [Foo!]! } type Query { hello(arg: Bar!): String }`, operation: `query Foo($input: Bar!) { hello(arg: $input) }`, variables: `{"input":{"foo":[{"bar":"hello"},{"bar":123}]}}`, } - err := runTest(t, tc) + err := runTest(t, tc, devMode) require.Error(t, err) assert.Equal(t, `Variable "$input" got invalid value at "input.foo.[1].bar"; String cannot represent a non string value`, err.Error()) }) t.Run("dev_mode non existing field on nested input object", func(t *testing.T) { - t.Setenv("DEV_MODE", "true") + devMode := true tc := testCase{ schema: `input Foo { bar: String! } input Bar { foo: Foo! } type Query { hello(arg: Bar!): String }`, operation: `query Foo($input: Bar!) { hello(arg: $input) }`, variables: `{"input":{"foo":{"bar":"hello","baz":"world"}}}`, } - err := runTest(t, tc) + err := runTest(t, tc, devMode) require.Error(t, err) assert.Equal(t, `Variable "$input" got invalid value {"foo":{"bar":"hello","baz":"world"}} at "input.foo"; Field "baz" is not defined by type "Foo".`, err.Error()) }) t.Run("non existing field on nested input object", func(t *testing.T) { + devMode := false tc := testCase{ schema: `input Foo { bar: String! } input Bar { foo: Foo! } type Query { hello(arg: Bar!): String }`, operation: `query Foo($input: Bar!) { hello(arg: $input) }`, variables: `{"input":{"foo":{"bar":"hello","baz":"world"}}}`, } - err := runTest(t, tc) + err := runTest(t, tc, devMode) require.Error(t, err) assert.Equal(t, `Variable "$input" got invalid value at "input.foo"; Field "baz" is not defined by type "Foo".`, err.Error()) }) t.Run("required enum argument provided with correct value", func(t *testing.T) { + devMode := false tc := testCase{ schema: `enum Foo { BAR } type Query { hello(arg: Foo!): String }`, operation: `query Foo($bar: Foo!) { hello(arg: $bar) }`, variables: `{"bar":"BAR"}`, } - err := runTest(t, tc) + err := runTest(t, tc, devMode) require.NoError(t, err) }) t.Run("dev_mode required enum argument provided with wrong value", func(t *testing.T) { - t.Setenv("DEV_MODE", "true") + devMode := true tc := testCase{ schema: `enum Foo { BAR } type Query { hello(arg: Foo!): String }`, operation: `query Foo($bar: Foo!) { hello(arg: $bar) }`, variables: `{"bar":"BAZ"}`, } - err := runTest(t, tc) + err := runTest(t, tc, devMode) require.Error(t, err) assert.Equal(t, `Variable "$bar" got invalid value "BAZ"; Value "BAZ" does not exist in "Foo" enum.`, err.Error()) }) t.Run("required enum argument provided with wrong value", func(t *testing.T) { + devMode := false tc := testCase{ schema: `enum Foo { BAR } type Query { hello(arg: Foo!): String }`, operation: `query Foo($bar: Foo!) { hello(arg: $bar) }`, variables: `{"bar":"BAZ"}`, } - err := runTest(t, tc) + err := runTest(t, tc, devMode) require.Error(t, err) assert.Equal(t, `Variable "$bar" got invalid value; Value does not exist in "Foo" enum.`, err.Error()) }) t.Run("dev_mode required enum argument provided with Int value", func(t *testing.T) { - t.Setenv("DEV_MODE", "true") + devMode := true tc := testCase{ schema: `enum Foo { BAR } type Query { hello(arg: Foo!): String }`, operation: `query Foo($bar: Foo!) { hello(arg: $bar) }`, variables: `{"bar":123}`, } - err := runTest(t, tc) + err := runTest(t, tc, devMode) require.Error(t, err) assert.Equal(t, `Variable "$bar" got invalid value 123; Enum "Foo" cannot represent non-string value: 123.`, err.Error()) }) t.Run("required enum argument provided with Int value", func(t *testing.T) { + devMode := false tc := testCase{ schema: `enum Foo { BAR } type Query { hello(arg: Foo!): String }`, operation: `query Foo($bar: Foo!) { hello(arg: $bar) }`, variables: `{"bar":123}`, } - err := runTest(t, tc) + err := runTest(t, tc, devMode) require.Error(t, err) assert.Equal(t, `Variable "$bar" got invalid value; Enum "Foo" cannot represent non-string value.`, err.Error()) }) t.Run("required enum argument provided with null", func(t *testing.T) { + devMode := false tc := testCase{ schema: `enum Foo { BAR } type Query { hello(arg: Foo!): String }`, operation: `query Foo($bar: Foo!) { hello(arg: $bar) }`, variables: `{"bar":null}`, } - err := runTest(t, tc) + err := runTest(t, tc, devMode) require.Error(t, err) assert.Equal(t, `Variable "$bar" got invalid value null; Expected non-nullable type "Foo!" not to be null.`, err.Error()) }) t.Run("dev_mode required nested enum argument provided with null", func(t *testing.T) { - t.Setenv("DEV_MODE", "true") + devMode := true tc := testCase{ schema: `enum Foo { BAR } input Bar { foo: Foo! } type Query { hello(arg: Bar!): String }`, operation: `query Foo($input: Bar!) { hello(arg: $input) }`, variables: `{"input":{"foo":null}}`, } - err := runTest(t, tc) + err := runTest(t, tc, devMode) require.Error(t, err) assert.Equal(t, `Variable "$input" got invalid value {"foo":null}; Field "foo" of required type "Foo!" was not provided.`, err.Error()) }) t.Run("required nested enum argument provided with null", func(t *testing.T) { + devMode := false tc := testCase{ schema: `enum Foo { BAR } input Bar { foo: Foo! } type Query { hello(arg: Bar!): String }`, operation: `query Foo($input: Bar!) { hello(arg: $input) }`, variables: `{"input":{"foo":null}}`, } - err := runTest(t, tc) + err := runTest(t, tc, devMode) require.Error(t, err) assert.Equal(t, `Variable "$input" got invalid value; Field "foo" of required type "Foo!" was not provided.`, err.Error()) }) t.Run("required nested enum argument provided with correct value", func(t *testing.T) { + devMode := false tc := testCase{ schema: `enum Foo { BAR } input Bar { foo: Foo! } type Query { hello(arg: Bar!): String }`, operation: `query Foo($input: Bar!) { hello(arg: $input) }`, variables: `{"input":{"foo":"BAR"}}`, } - err := runTest(t, tc) + err := runTest(t, tc, devMode) require.NoError(t, err) }) t.Run("dev_mode required nested enum argument provided with wrong value", func(t *testing.T) { - t.Setenv("DEV_MODE", "true") + devMode := true tc := testCase{ schema: `enum Foo { BAR } input Bar { foo: Foo! } type Query { hello(arg: Bar!): String }`, operation: `query Foo($input: Bar!) { hello(arg: $input) }`, variables: `{"input":{"foo":"BAZ"}}`, } - err := runTest(t, tc) + err := runTest(t, tc, devMode) require.Error(t, err) assert.Equal(t, `Variable "$input" got invalid value {"foo":"BAZ"} at "input.foo"; Value "BAZ" does not exist in "Foo" enum.`, err.Error()) }) t.Run("required nested enum argument provided with wrong value", func(t *testing.T) { + devMode := false tc := testCase{ schema: `enum Foo { BAR } input Bar { foo: Foo! } type Query { hello(arg: Bar!): String }`, operation: `query Foo($input: Bar!) { hello(arg: $input) }`, variables: `{"input":{"foo":"BAZ"}}`, } - err := runTest(t, tc) + err := runTest(t, tc, devMode) require.Error(t, err) assert.Equal(t, `Variable "$input" got invalid value at "input.foo"; Value does not exist in "Foo" enum.`, err.Error()) }) t.Run("optional enum argument provided with null", func(t *testing.T) { + devMode := false tc := testCase{ schema: `enum Foo { BAR } type Query { hello(arg: Foo): String }`, operation: `query Foo($bar: Foo) { hello(arg: $bar) }`, variables: `{"bar":null}`, } - err := runTest(t, tc) + err := runTest(t, tc, devMode) require.NoError(t, err) }) t.Run("optional nested enum argument provided with null", func(t *testing.T) { + devMode := false tc := testCase{ schema: `enum Foo { BAR } input Bar { foo: Foo } type Query { hello(arg: Bar): String }`, operation: `query Foo($input: Bar) { hello(arg: $input) }`, variables: `{"input":{"foo":null}}`, } - err := runTest(t, tc) + err := runTest(t, tc, devMode) require.NoError(t, err) }) t.Run("dev_mode optional nested enum argument provided with incorrect value", func(t *testing.T) { - t.Setenv("DEV_MODE", "true") + devMode := true tc := testCase{ schema: `enum Foo { BAR } input Bar { foo: Foo } type Query { hello(arg: Bar): String }`, operation: `query Foo($input: Bar) { hello(arg: $input) }`, variables: `{"input":{"foo":"BAZ"}}`, } - err := runTest(t, tc) + err := runTest(t, tc, devMode) require.Error(t, err) assert.Equal(t, `Variable "$input" got invalid value {"foo":"BAZ"} at "input.foo"; Value "BAZ" does not exist in "Foo" enum.`, err.Error()) }) t.Run("optional nested enum argument provided with incorrect value", func(t *testing.T) { + devMode := false tc := testCase{ schema: `enum Foo { BAR } input Bar { foo: Foo } type Query { hello(arg: Bar): String }`, operation: `query Foo($input: Bar) { hello(arg: $input) }`, variables: `{"input":{"foo":"BAZ"}}`, } - err := runTest(t, tc) + err := runTest(t, tc, devMode) require.Error(t, err) assert.Equal(t, `Variable "$input" got invalid value at "input.foo"; Value does not exist in "Foo" enum.`, err.Error()) }) t.Run("optional enum argument provided with correct value", func(t *testing.T) { + devMode := false tc := testCase{ schema: `enum Foo { BAR } type Query { hello(arg: Foo): String }`, operation: `query Foo($bar: Foo) { hello(arg: $bar) }`, variables: `{"bar":"BAR"}`, } - err := runTest(t, tc) + err := runTest(t, tc, devMode) require.NoError(t, err) }) t.Run("dev_mode optional enum argument provided with wrong value", func(t *testing.T) { - t.Setenv("DEV_MODE", "true") + devMode := true tc := testCase{ schema: `enum Foo { BAR } type Query { hello(arg: Foo): String }`, operation: `query Foo($bar: Foo) { hello(arg: $bar) }`, variables: `{"bar":"BAZ"}`, } - err := runTest(t, tc) + err := runTest(t, tc, devMode) require.Error(t, err) assert.Equal(t, `Variable "$bar" got invalid value "BAZ"; Value "BAZ" does not exist in "Foo" enum.`, err.Error()) }) t.Run("optional enum argument provided with wrong value", func(t *testing.T) { + devMode := false tc := testCase{ schema: `enum Foo { BAR } type Query { hello(arg: Foo): String }`, operation: `query Foo($bar: Foo) { hello(arg: $bar) }`, variables: `{"bar":"BAZ"}`, } - err := runTest(t, tc) + err := runTest(t, tc, devMode) require.Error(t, err) assert.Equal(t, `Variable "$bar" got invalid value; Value does not exist in "Foo" enum.`, err.Error()) }) t.Run("required string list field argument provided with null", func(t *testing.T) { + devMode := false tc := testCase{ schema: `type Query { hello(arg: [String]!): String }`, operation: `query Foo($bar: [String]!) { hello(arg: $bar) }`, variables: `{"bar":null}`, } - err := runTest(t, tc) + err := runTest(t, tc, devMode) require.Error(t, err) assert.Equal(t, `Variable "$bar" got invalid value null; Expected non-nullable type "[String]!" not to be null.`, err.Error()) }) t.Run("dev_mode required string list field argument provided with non list Int value", func(t *testing.T) { - t.Setenv("DEV_MODE", "true") + devMode := true tc := testCase{ schema: `type Query { hello(arg: [String]!): String }`, operation: `query Foo($bar: [String]!) { hello(arg: $bar) }`, variables: `{"bar":123}`, withNormalization: true, } - err := runTest(t, tc) + err := runTest(t, tc, devMode) require.Error(t, err) assert.Equal(t, `Variable "$bar" got invalid value 123 at "bar.[0]"; String cannot represent a non string value: 123`, err.Error()) }) t.Run("required string list field argument provided with non list Int value", func(t *testing.T) { + devMode := false tc := testCase{ schema: `type Query { hello(arg: [String]!): String }`, operation: `query Foo($bar: [String]!) { hello(arg: $bar) }`, variables: `{"bar":123}`, withNormalization: true, } - err := runTest(t, tc) + err := runTest(t, tc, devMode) require.Error(t, err) assert.Equal(t, `Variable "$bar" got invalid value at "bar.[0]"; String cannot represent a non string value`, err.Error()) }) t.Run("required string argument on input object list provided with correct value", func(t *testing.T) { + devMode := false tc := testCase{ schema: `input Foo { bar: String! } type Query { hello(arg: [Foo!]!): String }`, operation: `query Foo($bar: [Foo!]!) { hello(arg: $bar) }`, variables: `{"bar":[{"bar":"hello"}]}`, } - err := runTest(t, tc) + err := runTest(t, tc, devMode) require.NoError(t, err) }) t.Run("required string argument on input object list provided with wrong value", func(t *testing.T) { + devMode := false tc := testCase{ schema: `input Foo { bar: String! } type Query { hello(arg: [Foo!]!): String }`, operation: `query Foo($bar: [Foo!]!) { hello(arg: $bar) }`, variables: `{"bar":[{"bar":123}]}`, } - err := runTest(t, tc) + err := runTest(t, tc, devMode) require.Error(t, err) assert.Equal(t, `Variable "$bar" got invalid value at "bar.[0].bar"; String cannot represent a non string value`, err.Error()) }) t.Run("dev_mode required string argument on input object list provided with wrong value", func(t *testing.T) { - t.Setenv("DEV_MODE", "true") + devMode := true tc := testCase{ schema: `input Foo { bar: String! } type Query { hello(arg: [Foo!]!): String }`, operation: `query Foo($bar: [Foo!]!) { hello(arg: $bar) }`, variables: `{"bar":[{"bar":123}]}`, } - err := runTest(t, tc) + err := runTest(t, tc, devMode) require.Error(t, err) assert.Equal(t, `Variable "$bar" got invalid value 123 at "bar.[0].bar"; String cannot represent a non string value: 123`, err.Error()) }) t.Run("required string argument provided with string list", func(t *testing.T) { + devMode := false tc := testCase{ schema: `type Query { hello(arg: String!): String }`, operation: `query Foo($bar: String!) { hello(arg: $bar) }`, variables: `{"bar":["hello"]}`, } - err := runTest(t, tc) + err := runTest(t, tc, devMode) require.Error(t, err) assert.Equal(t, `Variable "$bar" got invalid value; String cannot represent a non string value`, err.Error()) }) t.Run("dev_mode required input object list field argument provided with non list Int value", func(t *testing.T) { - t.Setenv("DEV_MODE", "true") + devMode := true tc := testCase{ schema: `input Foo { bar: String! } type Query { hello(arg: [Foo!]!): String }`, operation: `query Foo($bar: [Foo!]!) { hello(arg: $bar) }`, variables: `{"bar":123}`, } - err := runTest(t, tc) + err := runTest(t, tc, devMode) require.Error(t, err) assert.Equal(t, `Variable "$bar" got invalid value 123; Expected type "Foo" to be an object.`, err.Error()) }) t.Run("required input object list field argument provided with non list Int value", func(t *testing.T) { + devMode := false tc := testCase{ schema: `input Foo { bar: String! } type Query { hello(arg: [Foo!]!): String }`, operation: `query Foo($bar: [Foo!]!) { hello(arg: $bar) }`, variables: `{"bar":123}`, } - err := runTest(t, tc) + err := runTest(t, tc, devMode) require.Error(t, err) assert.Equal(t, `Variable "$bar" got invalid value; Expected type "Foo" to be an object.`, err.Error()) }) t.Run("dev_mode required input object field argument provided with list input object value", func(t *testing.T) { - t.Setenv("DEV_MODE", "true") + devMode := true tc := testCase{ schema: `input Foo { bar: String! } type Query { hello(arg: Foo!): String }`, operation: `query Foo($bar: Foo!) { hello(arg: $bar) }`, variables: `{"bar":[{"bar":"hello"}]}`, } - err := runTest(t, tc) + err := runTest(t, tc, devMode) require.Error(t, err) assert.Equal(t, `Variable "$bar" got invalid value [{"bar":"hello"}]; Expected type "Foo" to be an object.`, err.Error()) }) t.Run("required input object field argument provided with list input object value", func(t *testing.T) { + devMode := false tc := testCase{ schema: `input Foo { bar: String! } type Query { hello(arg: Foo!): String }`, operation: `query Foo($bar: Foo!) { hello(arg: $bar) }`, variables: `{"bar":[{"bar":"hello"}]}`, } - err := runTest(t, tc) + err := runTest(t, tc, devMode) require.Error(t, err) assert.Equal(t, `Variable "$bar" got invalid value; Expected type "Foo" to be an object.`, err.Error()) }) t.Run("dev_mode required enum list argument provided with non list Int value", func(t *testing.T) { - t.Setenv("DEV_MODE", "true") + devMode := true tc := testCase{ schema: `enum Foo { BAR } type Query { hello(arg: [Foo]!): String }`, operation: `query Foo($bar: [Foo]!) { hello(arg: $bar) }`, variables: `{"bar":123}`, withNormalization: true, } - err := runTest(t, tc) + err := runTest(t, tc, devMode) require.Error(t, err) assert.Equal(t, `Variable "$bar" got invalid value 123 at "bar.[0]"; Enum "Foo" cannot represent non-string value: 123.`, err.Error()) }) t.Run("required enum list argument provided with non list Int value", func(t *testing.T) { + devMode := false tc := testCase{ schema: `enum Foo { BAR } type Query { hello(arg: [Foo]!): String }`, operation: `query Foo($bar: [Foo]!) { hello(arg: $bar) }`, variables: `{"bar":123}`, withNormalization: true, } - err := runTest(t, tc) + err := runTest(t, tc, devMode) require.Error(t, err) assert.Equal(t, `Variable "$bar" got invalid value at "bar.[0]"; Enum "Foo" cannot represent non-string value.`, err.Error()) }) t.Run("dev_mode required string list field argument provided with Int", func(t *testing.T) { - t.Setenv("DEV_MODE", "true") + devMode := true tc := testCase{ schema: `type Query { hello(arg: [String]!): String }`, operation: `query Foo($bar: [String]!) { hello(arg: $bar) }`, variables: `{"bar":123}`, withNormalization: true, } - err := runTest(t, tc) + err := runTest(t, tc, devMode) require.Error(t, err) assert.Equal(t, `Variable "$bar" got invalid value 123 at "bar.[0]"; String cannot represent a non string value: 123`, err.Error()) }) t.Run("required string list field argument provided with Int", func(t *testing.T) { + devMode := false tc := testCase{ schema: `type Query { hello(arg: [String]!): String }`, operation: `query Foo($bar: [String]!) { hello(arg: $bar) }`, variables: `{"bar":123}`, withNormalization: true, } - err := runTest(t, tc) + err := runTest(t, tc, devMode) require.Error(t, err) assert.Equal(t, `Variable "$bar" got invalid value at "bar.[0]"; String cannot represent a non string value`, err.Error()) }) t.Run("optional nested list argument provided with null", func(t *testing.T) { + devMode := false tc := testCase{ schema: `input Foo { bars : [String] bat: Int! } type Query { hello(arg: Foo): String }`, operation: `query Foo($input: Foo) { hello(arg: $input) }`, variables: `{"input":{"bars":null,"bat":1}}`, } - err := runTest(t, tc) + err := runTest(t, tc, devMode) require.NoError(t, err) }) t.Run("optional nested list argument provided with empty list", func(t *testing.T) { + devMode := false tc := testCase{ schema: `input Foo { bars : [String] bat: Int! } type Query { hello(arg: Foo): String }`, operation: `query Foo($input: Foo) { hello(arg: $input) }`, variables: `{"input":{"bars":[],"bat":1}}`, } - err := runTest(t, tc) + err := runTest(t, tc, devMode) require.NoError(t, err) }) t.Run("dev_mode optional nested list argument provided with empty list and missing Int", func(t *testing.T) { - t.Setenv("DEV_MODE", "true") + devMode := true tc := testCase{ schema: `input Foo { bars : [String] bat: Int! } type Query { hello(arg: Foo): String }`, operation: `query Foo($input: Foo) { hello(arg: $input) }`, variables: `{"input":{"bars":[]}}`, } - err := runTest(t, tc) + err := runTest(t, tc, devMode) require.Error(t, err) assert.Equal(t, `Variable "$input" got invalid value {"bars":[]}; Field "bat" of required type "Int!" was not provided.`, err.Error()) }) t.Run("optional nested list argument provided with empty list and missing Int", func(t *testing.T) { + devMode := false tc := testCase{ schema: `input Foo { bars : [String] bat: Int! } type Query { hello(arg: Foo): String }`, operation: `query Foo($input: Foo) { hello(arg: $input) }`, variables: `{"input":{"bars":[]}}`, } - err := runTest(t, tc) + err := runTest(t, tc, devMode) require.Error(t, err) assert.Equal(t, `Variable "$input" got invalid value; Field "bat" of required type "Int!" was not provided.`, err.Error()) }) t.Run("dev_mode optional nested field is null followed by required nested field of wrong type", func(t *testing.T) { - t.Setenv("DEV_MODE", "true") + devMode := true tc := testCase{ schema: `input Foo { bar: String! } input Bar { foo: Foo bat: Int! } type Query { hello(arg: Bar): String }`, operation: `query Foo($input: Bar) { hello(arg: $input) }`, variables: `{"input":{"foo":null,"bat":"hello"}}`, } - err := runTest(t, tc) + err := runTest(t, tc, devMode) require.Error(t, err) assert.Equal(t, `Variable "$input" got invalid value "hello" at "input.bat"; Int cannot represent non-integer value: "hello"`, err.Error()) }) t.Run("optional nested field is null followed by required nested field of wrong type", func(t *testing.T) { + devMode := false tc := testCase{ schema: `input Foo { bar: String! } input Bar { foo: Foo bat: Int! } type Query { hello(arg: Bar): String }`, operation: `query Foo($input: Bar) { hello(arg: $input) }`, variables: `{"input":{"foo":null,"bat":"hello"}}`, } - err := runTest(t, tc) + err := runTest(t, tc, devMode) require.Error(t, err) assert.Equal(t, `Variable "$input" got invalid value at "input.bat"; Int cannot represent non-integer value`, err.Error()) }) t.Run("input field is a double nested list", func(t *testing.T) { + devMode := false tc := testCase{ schema: `input Filter { option: String! } input FilterWrapper { filters: [[Filter!]!] } type Query { hello(filter: FilterWrapper): String }`, operation: `query Foo($input: FilterWrapper) { hello(filter: $input) }`, variables: `{"input":{"filters":[[{"option": "a"}]]}}`, } - err := runTest(t, tc) + err := runTest(t, tc, devMode) require.NoError(t, err) }) t.Run("variable of double nested list type", func(t *testing.T) { + devMode := false tc := testCase{ schema: `type Query { hello(filter: [[String]]): String }`, operation: `query Foo($input: [[String]]) { hello(filter: $input) }`, variables: `{"input":[["value"]]}`, } - err := runTest(t, tc) + err := runTest(t, tc, devMode) require.NoError(t, err) }) t.Run("dev_mode triple nested value into variable of double nested list type", func(t *testing.T) { - t.Setenv("DEV_MODE", "true") + devMode := true tc := testCase{ schema: `type Query { hello(filter: [[String]]): String }`, operation: `query Foo($input: [[String]]) { hello(filter: $input) }`, variables: `{"input":[[["value"]]]}`, } - err := runTest(t, tc) + err := runTest(t, tc, devMode) require.Error(t, err) assert.Equal(t, `Variable "$input" got invalid value ["value"] at "input.[0].[0]"; String cannot represent a non string value: ["value"]`, err.Error()) }) t.Run("triple nested value into variable of double nested list type", func(t *testing.T) { + devMode := false tc := testCase{ schema: `type Query { hello(filter: [[String]]): String }`, operation: `query Foo($input: [[String]]) { hello(filter: $input) }`, variables: `{"input":[[["value"]]]}`, } - err := runTest(t, tc) + err := runTest(t, tc, devMode) require.Error(t, err) assert.Equal(t, `Variable "$input" got invalid value at "input.[0].[0]"; String cannot represent a non string value`, err.Error()) }) t.Run("null into non required list value", func(t *testing.T) { + devMode := false tc := testCase{ schema: `type Query { hello(filter: [String]): String }`, operation: `query Foo($input: [String]) { hello(filter: $input) }`, variables: `{"input":[null]}`, } - err := runTest(t, tc) + err := runTest(t, tc, devMode) require.NoError(t, err) }) t.Run("value and null into non required list value", func(t *testing.T) { + devMode := false tc := testCase{ schema: `type Query { hello(filter: [String]): String }`, operation: `query Foo($input: [String]) { hello(filter: $input) }`, variables: `{"input":["ok", null]}`, } - err := runTest(t, tc) + err := runTest(t, tc, devMode) require.NoError(t, err) }) t.Run("null into non required value", func(t *testing.T) { + devMode := false tc := testCase{ schema: `type Query { hello(filter: String): String }`, operation: `query Foo($input: String) { hello(filter: $input) }`, variables: `{"input":null}`, } - err := runTest(t, tc) + err := runTest(t, tc, devMode) require.NoError(t, err) }) } @@ -1220,7 +1291,7 @@ type testCase struct { withNormalization bool } -func runTest(t *testing.T, tc testCase) error { +func runTest(t *testing.T, tc testCase, devMode bool) error { t.Helper() def := unsafeparser.ParseGraphqlDocumentString(tc.schema) op := unsafeparser.ParseGraphqlDocumentString(tc.operation) @@ -1238,7 +1309,7 @@ func runTest(t *testing.T, tc testCase) error { } } validator := NewVariablesValidator() - return validator.Validate(&op, &def, op.Input.Variables) + return validator.Validate(&op, &def, op.Input.Variables, devMode) } var inputSchema = `