graphql 0.11.0 → 0.11.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/graphql/base_type.rb +6 -2
- data/lib/graphql/definition_helpers.rb +0 -5
- data/lib/graphql/definition_helpers/defined_by_config.rb +106 -102
- data/lib/graphql/definition_helpers/non_null_with_bang.rb +13 -9
- data/lib/graphql/definition_helpers/string_named_hash.rb +19 -15
- data/lib/graphql/definition_helpers/type_definer.rb +25 -21
- data/lib/graphql/enum_type.rb +8 -2
- data/lib/graphql/float_type.rb +1 -1
- data/lib/graphql/input_object_type.rb +27 -6
- data/lib/graphql/interface_type.rb +10 -0
- data/lib/graphql/introspection/fields_field.rb +2 -2
- data/lib/graphql/list_type.rb +12 -2
- data/lib/graphql/non_null_type.rb +11 -1
- data/lib/graphql/object_type.rb +19 -0
- data/lib/graphql/query.rb +2 -14
- data/lib/graphql/query/input_validation_result.rb +23 -0
- data/lib/graphql/query/literal_input.rb +3 -1
- data/lib/graphql/query/serial_execution/field_resolution.rb +3 -1
- data/lib/graphql/query/serial_execution/selection_resolution.rb +21 -15
- data/lib/graphql/query/variable_validation_error.rb +18 -0
- data/lib/graphql/query/variables.rb +4 -8
- data/lib/graphql/scalar_type.rb +10 -4
- data/lib/graphql/schema.rb +4 -2
- data/lib/graphql/schema/printer.rb +12 -3
- data/lib/graphql/schema/type_reducer.rb +4 -3
- data/lib/graphql/static_validation.rb +1 -0
- data/lib/graphql/static_validation/all_rules.rb +1 -0
- data/lib/graphql/static_validation/rules/document_does_not_exceed_max_depth.rb +79 -0
- data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +1 -1
- data/lib/graphql/static_validation/validation_context.rb +63 -0
- data/lib/graphql/static_validation/validator.rb +1 -52
- data/lib/graphql/version.rb +1 -1
- data/readme.md +21 -22
- data/spec/graphql/enum_type_spec.rb +8 -0
- data/spec/graphql/input_object_type_spec.rb +101 -3
- data/spec/graphql/introspection/schema_type_spec.rb +6 -6
- data/spec/graphql/introspection/type_type_spec.rb +6 -6
- data/spec/graphql/language/transform_spec.rb +9 -5
- data/spec/graphql/list_type_spec.rb +23 -0
- data/spec/graphql/object_type_spec.rb +11 -4
- data/spec/graphql/query/executor_spec.rb +34 -5
- data/spec/graphql/query_spec.rb +22 -3
- data/spec/graphql/scalar_type_spec.rb +28 -0
- data/spec/graphql/schema/type_reducer_spec.rb +2 -2
- data/spec/graphql/static_validation/complexity_validator_spec.rb +15 -0
- data/spec/graphql/static_validation/rules/document_does_not_exceed_max_depth_spec.rb +93 -0
- data/spec/support/dairy_app.rb +2 -2
- data/spec/support/minimum_input_object.rb +8 -5
- metadata +10 -4
- data/spec/graphql/static_validation/complexity_validator.rb +0 -15
@@ -19,7 +19,7 @@ class GraphQL::StaticValidation::FieldsAreDefinedOnType
|
|
19
19
|
return GraphQL::Language::Visitor::SKIP
|
20
20
|
end
|
21
21
|
|
22
|
-
field = parent_type.
|
22
|
+
field = parent_type.get_field(ast_field.name)
|
23
23
|
if field.nil?
|
24
24
|
errors << message("Field '#{ast_field.name}' doesn't exist on type '#{parent_type.name}'", parent)
|
25
25
|
return GraphQL::Language::Visitor::SKIP
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module GraphQL
|
2
|
+
module StaticValidation
|
3
|
+
# The validation context gets passed to each validator.
|
4
|
+
#
|
5
|
+
# It exposes a {GraphQL::Language::Visitor} where validators may add hooks. ({Visitor#visit} is called in {Validator#validate})
|
6
|
+
#
|
7
|
+
# It provides access to the schema & fragments which validators may read from.
|
8
|
+
#
|
9
|
+
# It holds a list of errors which each validator may add to.
|
10
|
+
#
|
11
|
+
# It also provides limited access to the {TypeStack} instance,
|
12
|
+
# which tracks state as you climb in and out of different fields.
|
13
|
+
class ValidationContext
|
14
|
+
attr_reader :schema, :document, :errors, :visitor, :fragments, :operations
|
15
|
+
def initialize(schema, document)
|
16
|
+
@schema = schema
|
17
|
+
@document = document
|
18
|
+
@fragments = {}
|
19
|
+
@operations = {}
|
20
|
+
|
21
|
+
document.definitions.each do |definition|
|
22
|
+
case definition
|
23
|
+
when GraphQL::Language::Nodes::FragmentDefinition
|
24
|
+
@fragments[definition.name] = definition
|
25
|
+
when GraphQL::Language::Nodes::OperationDefinition
|
26
|
+
@operations[definition.name] = definition
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
@errors = []
|
31
|
+
@visitor = GraphQL::Language::Visitor.new
|
32
|
+
@type_stack = GraphQL::StaticValidation::TypeStack.new(schema, visitor)
|
33
|
+
end
|
34
|
+
|
35
|
+
def object_types
|
36
|
+
@type_stack.object_types
|
37
|
+
end
|
38
|
+
|
39
|
+
# @return [GraphQL::Field, nil] The most-recently-entered GraphQL::Field, if currently inside one
|
40
|
+
def field_definition
|
41
|
+
@type_stack.field_definitions.last
|
42
|
+
end
|
43
|
+
|
44
|
+
# @return [GraphQL::Directive, nil] The most-recently-entered GraphQL::Directive, if currently inside one
|
45
|
+
def directive_definition
|
46
|
+
@type_stack.directive_definitions.last
|
47
|
+
end
|
48
|
+
|
49
|
+
# @return [GraphQL::Argument, nil] The most-recently-entered GraphQL::Argument, if currently inside one
|
50
|
+
def argument_definition
|
51
|
+
# Don't get the _last_ one because that's the current one.
|
52
|
+
# Get the second-to-last one, which is the parent of the current one.
|
53
|
+
@type_stack.argument_definitions[-2]
|
54
|
+
end
|
55
|
+
|
56
|
+
# Don't try to validate dynamic fields
|
57
|
+
# since they aren't defined by the type system
|
58
|
+
def skip_field?(field_name)
|
59
|
+
GraphQL::Schema::DYNAMIC_FIELDS.include?(field_name)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -19,62 +19,11 @@ class GraphQL::StaticValidation::Validator
|
|
19
19
|
# @param document [GraphQL::Language::Nodes::Document]
|
20
20
|
# @return [Array<Hash>]
|
21
21
|
def validate(document)
|
22
|
-
context =
|
22
|
+
context = GraphQL::StaticValidation::ValidationContext.new(@schema, document)
|
23
23
|
@rules.each do |rules|
|
24
24
|
rules.new.validate(context)
|
25
25
|
end
|
26
26
|
context.visitor.visit(document)
|
27
27
|
context.errors.map(&:to_h)
|
28
28
|
end
|
29
|
-
|
30
|
-
# The validation context gets passed to each validator.
|
31
|
-
#
|
32
|
-
# It exposes a {GraphQL::Language::Visitor} where validators may add hooks. ({Visitor#visit} is called in {Validator#validate})
|
33
|
-
#
|
34
|
-
# It provides access to the schema & fragments which validators may read from.
|
35
|
-
#
|
36
|
-
# It holds a list of errors which each validator may add to.
|
37
|
-
#
|
38
|
-
# It also provides limited access to the {TypeStack} instance,
|
39
|
-
# which tracks state as you climb in and out of different fields.
|
40
|
-
class Context
|
41
|
-
attr_reader :schema, :document, :errors, :visitor, :fragments
|
42
|
-
def initialize(schema, document)
|
43
|
-
@schema = schema
|
44
|
-
@document = document
|
45
|
-
@fragments = document.definitions.each_with_object({}) do |part, memo|
|
46
|
-
part.is_a?(GraphQL::Language::Nodes::FragmentDefinition) && memo[part.name] = part
|
47
|
-
end
|
48
|
-
@errors = []
|
49
|
-
@visitor = GraphQL::Language::Visitor.new
|
50
|
-
@type_stack = GraphQL::StaticValidation::TypeStack.new(schema, visitor)
|
51
|
-
end
|
52
|
-
|
53
|
-
def object_types
|
54
|
-
@type_stack.object_types
|
55
|
-
end
|
56
|
-
|
57
|
-
# @return [GraphQL::Field, nil] The most-recently-entered GraphQL::Field, if currently inside one
|
58
|
-
def field_definition
|
59
|
-
@type_stack.field_definitions.last
|
60
|
-
end
|
61
|
-
|
62
|
-
# @return [GraphQL::Directive, nil] The most-recently-entered GraphQL::Directive, if currently inside one
|
63
|
-
def directive_definition
|
64
|
-
@type_stack.directive_definitions.last
|
65
|
-
end
|
66
|
-
|
67
|
-
# @return [GraphQL::Argument, nil] The most-recently-entered GraphQL::Argument, if currently inside one
|
68
|
-
def argument_definition
|
69
|
-
# Don't get the _last_ one because that's the current one.
|
70
|
-
# Get the second-to-last one, which is the parent of the current one.
|
71
|
-
@type_stack.argument_definitions[-2]
|
72
|
-
end
|
73
|
-
|
74
|
-
# Don't try to validate dynamic fields
|
75
|
-
# since they aren't defined by the type system
|
76
|
-
def skip_field?(field_name)
|
77
|
-
GraphQL::Schema::DYNAMIC_FIELDS.include?(field_name)
|
78
|
-
end
|
79
|
-
end
|
80
29
|
end
|
data/lib/graphql/version.rb
CHANGED
data/readme.md
CHANGED
@@ -58,7 +58,10 @@ QueryType = GraphQL::ObjectType.define do
|
|
58
58
|
end
|
59
59
|
|
60
60
|
# Then create your schema
|
61
|
-
Schema = GraphQL::Schema.new(
|
61
|
+
Schema = GraphQL::Schema.new(
|
62
|
+
query: QueryType,
|
63
|
+
max_depth: 8,
|
64
|
+
)
|
62
65
|
```
|
63
66
|
|
64
67
|
See also:
|
@@ -108,24 +111,6 @@ https://medium.com/@gauravtiwari/graphql-and-relay-on-rails-first-relay-powered-
|
|
108
111
|
3. http://mgiroux.me/2015/getting-started-with-rails-graphql-relay/
|
109
112
|
4. http://mgiroux.me/2015/uploading-files-using-relay-with-rails/
|
110
113
|
|
111
|
-
## To Do
|
112
|
-
|
113
|
-
- Code clean-up
|
114
|
-
- Raise if you try to configure an attribute which doesn't suit the type (ie, if you try to define `resolve` on an ObjectType, it should somehow raise)
|
115
|
-
- make `DefinitionHelpers` more friendly for extension
|
116
|
-
- Interface's possible types should be a property of the schema, not the interface
|
117
|
-
- Type lookup should be by type name (to support reloaded constants in Rails code)
|
118
|
-
- Add a complexity validator (reject queries if they're too big)
|
119
|
-
- Add a custom dump for Relay (it expects default value strings to be double-quoted)
|
120
|
-
- Make variable validation provide a specific, useful message
|
121
|
-
- Add docs for shared behaviors & DRY code
|
122
|
-
- After releasing the next version, use it for [graphql-libgraphqlparser](https://github.com/rmosolgo/graphql-libgraphqlparser-ruby)
|
123
|
-
- Big ideas:
|
124
|
-
- Revamp the fixture Schema to be more useful (better names, more extensible)
|
125
|
-
- __Subscriptions__
|
126
|
-
- This is a good chance to make an `Operation` abstraction of which `query`, `mutation` and `subscription` are members
|
127
|
-
- For a subscription, `graphql` would send an outbound message to the system (allow the host application to manage its own subscriptions via Pusher, ActionCable, whatever)
|
128
|
-
|
129
114
|
## Goals
|
130
115
|
|
131
116
|
- Implement the GraphQL spec & support a Relay front end
|
@@ -145,8 +130,22 @@ https://medium.com/@gauravtiwari/graphql-and-relay-on-rails-first-relay-powered-
|
|
145
130
|
- [`graphql-batch`](https://github.com/shopify/graphql-batch), a batched query execution strategy
|
146
131
|
- [`graphql-parallel`](https://github.com/rmosolgo/graphql-parallel), an asynchronous query execution strategy
|
147
132
|
- [Example Relay support](https://github.com/rmosolgo/graphql-relay-ruby) in Ruby
|
133
|
+
- [`graphql-libgraphqlparser`](https://github.com/rmosolgo/graphql-libgraphqlparser), bindings to [libgraphqlparser](https://github.com/graphql/libgraphqlparser), a C-level parser.
|
148
134
|
|
149
|
-
##
|
135
|
+
## To Do
|
150
136
|
|
151
|
-
-
|
152
|
-
-
|
137
|
+
- Code clean-up
|
138
|
+
- Raise if you try to configure an attribute which doesn't suit the type (ie, if you try to define `resolve` on an ObjectType, it should somehow raise)
|
139
|
+
- make `DefinitionHelpers` more friendly for extension
|
140
|
+
- Interface's possible types should be a property of the schema, not the interface
|
141
|
+
- Type lookup should be by type name (to support reloaded constants in Rails code)
|
142
|
+
- Depth validator should be aware of fragments
|
143
|
+
- Add a complexity validator (reject queries if they're too big)
|
144
|
+
- Add a custom dump for Relay (it expects default value strings to be double-quoted)
|
145
|
+
- Add docs for shared behaviors & DRY code
|
146
|
+
- Optimize the pure-Ruby parser (hand-write, RACC?!)
|
147
|
+
- Big ideas:
|
148
|
+
- Revamp the fixture Schema to be more useful (better names, more extensible)
|
149
|
+
- __Subscriptions__
|
150
|
+
- This is a good chance to make an `Operation` abstraction of which `query`, `mutation` and `subscription` are members
|
151
|
+
- For a subscription, `graphql` would send an outbound message to the system (allow the host application to manage its own subscriptions via Pusher, ActionCable, whatever)
|
@@ -16,4 +16,12 @@ describe GraphQL::EnumType do
|
|
16
16
|
it 'has value description' do
|
17
17
|
assert_equal("Animal with horns", enum.values['GOAT'].description)
|
18
18
|
end
|
19
|
+
|
20
|
+
describe 'validate_input with bad input' do
|
21
|
+
let(:result) { DairyAnimalEnum.validate_input('bad enum') }
|
22
|
+
|
23
|
+
it 'returns an invalid result' do
|
24
|
+
assert(!result.valid?)
|
25
|
+
end
|
26
|
+
end
|
19
27
|
end
|
@@ -12,8 +12,106 @@ describe GraphQL::InputObjectType do
|
|
12
12
|
|
13
13
|
describe "input validation" do
|
14
14
|
it "Accepts anything that yields key-value pairs to #all?" do
|
15
|
-
values_obj = MinimumInputObject.new
|
16
|
-
assert DairyProductInputType.
|
15
|
+
values_obj = MinimumInputObject.new({"source" => "COW", "fatContent" => 0.4})
|
16
|
+
assert DairyProductInputType.valid_input?(values_obj)
|
17
|
+
end
|
18
|
+
|
19
|
+
describe 'validate_input with non-enumerable input' do
|
20
|
+
it "returns a valid result for MinimumInputObject" do
|
21
|
+
result = DairyProductInputType.validate_input(MinimumInputObject.new({"source" => "COW", "fatContent" => 0.4}))
|
22
|
+
assert(result.valid?)
|
23
|
+
end
|
24
|
+
|
25
|
+
it "returns an invalid result for MinimumInvalidInputObject" do
|
26
|
+
invalid_input = MinimumInputObject.new({"source" => "KOALA", "fatContent" => 0.4})
|
27
|
+
result = DairyProductInputType.validate_input(invalid_input)
|
28
|
+
assert(!result.valid?)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe 'validate_input with enumerable input' do
|
33
|
+
describe 'with good input' do
|
34
|
+
let(:input) do
|
35
|
+
{
|
36
|
+
'source' => 'COW',
|
37
|
+
'fatContent' => 0.4
|
38
|
+
}
|
39
|
+
end
|
40
|
+
let(:result) { DairyProductInputType.validate_input(input) }
|
41
|
+
|
42
|
+
it 'returns a valid result' do
|
43
|
+
assert(result.valid?)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
describe 'with bad enum and float' do
|
48
|
+
let(:result) { DairyProductInputType.validate_input('source' => 'KOALA', 'fatContent' => 'bad_num') }
|
49
|
+
|
50
|
+
it 'returns an invalid result' do
|
51
|
+
assert(!result.valid?)
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'has problems with correct paths' do
|
55
|
+
paths = result.problems.map { |p| p['path'] }
|
56
|
+
assert(paths.include?(['source']))
|
57
|
+
assert(paths.include?(['fatContent']))
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'has correct problem explanation' do
|
61
|
+
expected = DairyAnimalEnum.validate_input('KOALA').problems[0]['explanation']
|
62
|
+
|
63
|
+
source_problem = result.problems.detect { |p| p['path'] == ['source'] }
|
64
|
+
actual = source_problem['explanation']
|
65
|
+
|
66
|
+
assert_equal(expected, actual)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
describe 'with extra argument' do
|
71
|
+
let(:result) { DairyProductInputType.validate_input('source' => 'COW', 'fatContent' => 0.4, 'isDelicious' => false) }
|
72
|
+
|
73
|
+
it 'returns an invalid result' do
|
74
|
+
assert(!result.valid?)
|
75
|
+
end
|
76
|
+
|
77
|
+
it 'has problem with correct path' do
|
78
|
+
paths = result.problems.map { |p| p['path'] }
|
79
|
+
assert_equal(paths, [['isDelicious']])
|
80
|
+
end
|
81
|
+
|
82
|
+
it 'has correct problem explanation' do
|
83
|
+
assert(result.problems[0]['explanation'].include?('Field is not defined'))
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
describe 'list with one invalid element' do
|
88
|
+
let(:list_type) { GraphQL::ListType.new(of_type: DairyProductInputType) }
|
89
|
+
let(:result) do
|
90
|
+
list_type.validate_input([
|
91
|
+
{ 'source' => 'COW', 'fatContent' => 0.4 },
|
92
|
+
{ 'source' => 'KOALA', 'fatContent' => 0.4 }
|
93
|
+
])
|
94
|
+
end
|
95
|
+
|
96
|
+
it 'returns an invalid result' do
|
97
|
+
assert(!result.valid?)
|
98
|
+
end
|
99
|
+
|
100
|
+
it 'has one problem' do
|
101
|
+
assert_equal(result.problems.length, 1)
|
102
|
+
end
|
103
|
+
|
104
|
+
it 'has problem with correct path' do
|
105
|
+
path = result.problems[0]['path']
|
106
|
+
assert_equal(path, [1, 'source'])
|
107
|
+
end
|
108
|
+
|
109
|
+
it 'has problem with correct explanation' do
|
110
|
+
expected = DairyAnimalEnum.validate_input('KOALA').problems[0]['explanation']
|
111
|
+
actual = result.problems[0]['explanation']
|
112
|
+
assert_equal(expected, actual)
|
113
|
+
end
|
114
|
+
end
|
17
115
|
end
|
18
116
|
end
|
19
117
|
|
@@ -22,7 +120,7 @@ describe GraphQL::InputObjectType do
|
|
22
120
|
let(:result) { DummySchema.execute(query_string, variables: variables) }
|
23
121
|
|
24
122
|
describe "list inputs" do
|
25
|
-
let(:variables) { {"search" => [MinimumInputObject.new]} }
|
123
|
+
let(:variables) { {"search" => [MinimumInputObject.new({"source" => "COW", "fatContent" => 0.4})]} }
|
26
124
|
let(:query_string) {%|
|
27
125
|
query getCheeses($search: [DairyProductInput]!){
|
28
126
|
sheep: searchDairy(product: [{source: SHEEP, fatContent: 0.1}]) {
|
@@ -19,15 +19,15 @@ describe GraphQL::Introspection::SchemaType do
|
|
19
19
|
"queryType"=>{
|
20
20
|
"fields"=>[
|
21
21
|
{"name"=>"cheese"},
|
22
|
-
{"name"=>"milk"},
|
23
|
-
{"name"=>"dairy"},
|
24
|
-
{"name"=>"fromSource"},
|
25
|
-
{"name"=>"favoriteEdible"},
|
26
22
|
{"name"=>"cow"},
|
27
|
-
{"name"=>"
|
23
|
+
{"name"=>"dairy"},
|
28
24
|
{"name"=>"error"},
|
29
25
|
{"name"=>"executionError"},
|
30
|
-
{"name"=>"
|
26
|
+
{"name"=>"favoriteEdible"},
|
27
|
+
{"name"=>"fromSource"},
|
28
|
+
{"name"=>"maybeNull"},
|
29
|
+
{"name"=>"milk"},
|
30
|
+
{"name"=>"searchDairy"},
|
31
31
|
]
|
32
32
|
},
|
33
33
|
"mutationType"=> {
|
@@ -12,11 +12,11 @@ describe GraphQL::Introspection::TypeType do
|
|
12
12
|
|}
|
13
13
|
let(:result) { DummySchema.execute(query_string, context: {}, variables: {"cheeseId" => 2}) }
|
14
14
|
let(:cheese_fields) {[
|
15
|
-
{"name"=>"id", "isDeprecated" => false, "type" => { "name" => "Non-Null", "ofType" => { "name" => "Int"}}},
|
16
15
|
{"name"=>"flavor", "isDeprecated" => false, "type" => { "name" => "Non-Null", "ofType" => { "name" => "String"}}},
|
16
|
+
{"name"=>"id", "isDeprecated" => false, "type" => { "name" => "Non-Null", "ofType" => { "name" => "Int"}}},
|
17
17
|
{"name"=>"origin", "isDeprecated" => false, "type" => { "name" => "Non-Null", "ofType" => { "name" => "String"}}},
|
18
|
-
{"name"=>"source", "isDeprecated" => false, "type" => { "name" => "Non-Null", "ofType" => { "name" => "DairyAnimal"}}},
|
19
18
|
{"name"=>"similarCheese", "isDeprecated"=>false, "type"=>{"name"=>"Cheese", "ofType"=>nil}},
|
19
|
+
{"name"=>"source", "isDeprecated" => false, "type" => { "name" => "Non-Null", "ofType" => { "name" => "DairyAnimal"}}},
|
20
20
|
]}
|
21
21
|
|
22
22
|
let(:dairy_animals) {[
|
@@ -37,11 +37,11 @@ describe GraphQL::Introspection::TypeType do
|
|
37
37
|
{"name"=>"AnimalProduct"}
|
38
38
|
],
|
39
39
|
"fields"=>[
|
40
|
-
{"type"=>{"name"=>"Non-Null", "ofType"=>{"name"=>"ID"}}},
|
41
|
-
{"type"=>{"name"=>"DairyAnimal", "ofType"=>nil}},
|
42
|
-
{"type"=>{"name"=>"Non-Null", "ofType"=>{"name"=>"String"}}},
|
43
40
|
{"type"=>{"name"=>"Non-Null", "ofType"=>{"name"=>"Float"}}},
|
44
41
|
{"type"=>{"name"=>"List", "ofType"=>{"name"=>"String"}}},
|
42
|
+
{"type"=>{"name"=>"Non-Null", "ofType"=>{"name"=>"ID"}}},
|
43
|
+
{"type"=>{"name"=>"Non-Null", "ofType"=>{"name"=>"String"}}},
|
44
|
+
{"type"=>{"name"=>"DairyAnimal", "ofType"=>nil}},
|
45
45
|
]
|
46
46
|
},
|
47
47
|
"dairyAnimal"=>{
|
@@ -75,7 +75,7 @@ describe GraphQL::Introspection::TypeType do
|
|
75
75
|
|}
|
76
76
|
let(:deprecated_fields) { {"name"=>"fatContent", "isDeprecated"=>true, "type"=>{"name"=>"Non-Null", "ofType"=>{"name"=>"Float"}}} }
|
77
77
|
it 'can expose deprecated fields' do
|
78
|
-
new_cheese_fields =
|
78
|
+
new_cheese_fields = [deprecated_fields] + cheese_fields
|
79
79
|
expected = { "data" => {
|
80
80
|
"cheeseType" => {
|
81
81
|
"name"=> "Cheese",
|
@@ -113,17 +113,21 @@ describe GraphQL::Language::Transform do
|
|
113
113
|
|
114
114
|
it 'transforms input objects' do
|
115
115
|
res_one_pair = get_result(%q|{one: 1}|, parse: :value_input_object)
|
116
|
-
|
116
|
+
res_many_pair = get_result(%q|{first: "Apple", second: "Banana", third: ORANGE}|, parse: :value_input_object)
|
117
117
|
res_empty = get_result(%q|{}|, parse: :value_input_object)
|
118
118
|
res_empty_space = get_result(%q|{ }|, parse: :value_input_object)
|
119
119
|
|
120
120
|
assert_equal('one', res_one_pair.arguments[0].name)
|
121
121
|
assert_equal(1 , res_one_pair.arguments[0].value)
|
122
122
|
|
123
|
-
assert_equal(
|
124
|
-
assert_equal(
|
125
|
-
assert_equal(
|
126
|
-
assert_equal(
|
123
|
+
assert_equal("first" , res_many_pair.arguments[0].name)
|
124
|
+
assert_equal("Apple" , res_many_pair.arguments[0].value)
|
125
|
+
assert_equal("second", res_many_pair.arguments[1].name)
|
126
|
+
assert_equal("Banana", res_many_pair.arguments[1].value)
|
127
|
+
|
128
|
+
assert(res_many_pair.arguments[2].value.is_a?(GraphQL::Language::Nodes::Enum))
|
129
|
+
assert_equal("third", res_many_pair.arguments[2].name)
|
130
|
+
assert_equal("ORANGE", res_many_pair.arguments[2].value.name)
|
127
131
|
|
128
132
|
assert_equal([], res_empty.arguments)
|
129
133
|
assert_equal([], res_empty_space.arguments)
|
@@ -6,4 +6,27 @@ describe GraphQL::ListType do
|
|
6
6
|
it 'coerces elements in the list' do
|
7
7
|
assert_equal([1.0, 2.0, 3.0].inspect, float_list.coerce_input([1, 2, 3]).inspect)
|
8
8
|
end
|
9
|
+
|
10
|
+
describe 'validate_input with bad input' do
|
11
|
+
let(:bad_num) { 'bad_num' }
|
12
|
+
let(:result) { float_list.validate_input([bad_num, 2.0, 3.0]) }
|
13
|
+
|
14
|
+
it 'returns an invalid result' do
|
15
|
+
assert(!result.valid?)
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'has one problem' do
|
19
|
+
assert_equal(result.problems.length, 1)
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'has path [0]' do
|
23
|
+
assert_equal(result.problems[0]['path'], [0])
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'has the correct explanation' do
|
27
|
+
expected = GraphQL::FLOAT_TYPE.validate_input(bad_num).problems[0]['explanation']
|
28
|
+
actual = result.problems[0]['explanation']
|
29
|
+
assert_equal(actual, expected)
|
30
|
+
end
|
31
|
+
end
|
9
32
|
end
|