spec/graphql/language/parser_spec.rb in graphql-0.18.5 vs spec/graphql/language/parser_spec.rb in graphql-0.18.6
- old
+ new
@@ -1,562 +1,7 @@
require "spec_helper"
+require 'graphql/language/parser_tests'
describe GraphQL::Language::Parser do
- let(:document) { GraphQL::Language::Parser.parse(query_string) }
- let(:query_string) {%|
- query getStuff($someVar: Int = 1, $anotherVar: [String!] ) @skip(if: false) {
- myField: someField(someArg: $someVar, ok: 1.4) @skip(if: $anotherVar) @thing(or: "Whatever")
-
- anotherField(someArg: [1,2,3]) {
- nestedField
- ... moreNestedFields @skip(if: true)
- }
-
- ... on OtherType @include(unless: false){
- field(arg: [{key: "value", anotherKey: 0.9, anotherAnotherKey: WHATEVER}])
- anotherField
- }
-
- ... {
- id
- }
- }
-
- fragment moreNestedFields on NestedType @or(something: "ok") {
- anotherNestedField
- }
- |}
-
- describe ".parse" do
- it "parses queries" do
- assert document
- end
-
- describe "visited nodes" do
- let(:query) { document.definitions.first }
- let(:fragment_def) { document.definitions.last }
-
- it "creates a valid document" do
- assert document.is_a?(GraphQL::Language::Nodes::Document)
- assert_equal 2, document.definitions.length
- end
-
- it "creates a valid operation" do
- assert query.is_a?(GraphQL::Language::Nodes::OperationDefinition)
- assert_equal "getStuff", query.name
- assert_equal "query", query.operation_type
- assert_equal 2, query.variables.length
- assert_equal 4, query.selections.length
- assert_equal 1, query.directives.length
- assert_equal [2, 5], [query.line, query.col]
- end
-
- it "creates a valid fragment definition" do
- assert fragment_def.is_a?(GraphQL::Language::Nodes::FragmentDefinition)
- assert_equal "moreNestedFields", fragment_def.name
- assert_equal 1, fragment_def.selections.length
- assert_equal "NestedType", fragment_def.type
- assert_equal 1, fragment_def.directives.length
- assert_equal [20, 5], fragment_def.position
- end
-
- describe "variable definitions" do
- let(:optional_var) { query.variables.first }
- it "gets name and type" do
- assert_equal "someVar", optional_var.name
- assert_equal "Int", optional_var.type.name
- end
-
- it "gets default value" do
- assert_equal 1, optional_var.default_value
- end
-
- it "gets position info" do
- assert_equal [2, 20], optional_var.position
- end
- end
-
- describe "fields" do
- let(:leaf_field) { query.selections.first }
- let(:parent_field) { query.selections[1] }
-
- it "gets name, alias, arguments and directives" do
- assert_equal "someField", leaf_field.name
- assert_equal "myField", leaf_field.alias
- assert_equal 2, leaf_field.directives.length
- assert_equal 2, leaf_field.arguments.length
- end
-
- it "gets nested fields" do
- assert_equal 2, parent_field.selections.length
- end
-
- it "gets location info" do
- assert_equal [3 ,7], leaf_field.position
- end
-
- describe "when the arguments list is empty" do
- let(:query_string) { "{ field() }"}
- let(:field) { query.selections.first }
- it "has zero arguments" do
- assert_equal 0, field.arguments.length
- end
- end
-
- describe "when selections are empty" do
- let(:query_string) { "{ field { } }"}
- let(:field) { query.selections.first }
- it "has zero selections" do
- assert_equal 0, field.selections.length
- end
- end
- end
-
- describe "arguments" do
- let(:literal_argument) { query.selections.first.arguments.last }
- let(:variable_argument) { query.selections.first.arguments.first }
-
- it "gets name and literal value" do
- assert_equal "ok", literal_argument.name
- assert_equal 1.4, literal_argument.value
- end
-
- it "gets name and variable value" do
- assert_equal "someArg", variable_argument.name
- assert_equal "someVar", variable_argument.value.name
- end
-
-
- it "gets position info" do
- assert_equal [3, 26], variable_argument.position
- end
- end
-
- describe "fragment spreads" do
- let(:fragment_spread) { query.selections[1].selections.last }
- it "gets the name and directives" do
- assert_equal "moreNestedFields", fragment_spread.name
- assert_equal 1, fragment_spread.directives.length
- end
-
- it "gets position info" do
- assert_equal [7, 9], fragment_spread.position
- end
- end
-
- describe "directives" do
- let(:variable_directive) { query.selections.first.directives.first }
-
- it "gets the name and arguments" do
- assert_equal "skip", variable_directive.name
- assert_equal "if", variable_directive.arguments.first.name
- assert_equal 1, variable_directive.arguments.length
- end
-
- it "gets position info" do
- assert_equal [3, 54], variable_directive.position
- end
- end
-
- describe "inline fragments" do
- let(:inline_fragment) { query.selections[2] }
- let(:typeless_inline_fragment) { query.selections[3] }
-
- it "gets the type and directives" do
- assert_equal "OtherType", inline_fragment.type
- assert_equal 2, inline_fragment.selections.length
- assert_equal 1, inline_fragment.directives.length
- end
-
- it "gets inline fragments without type conditions" do
- assert_equal nil, typeless_inline_fragment.type
- assert_equal 1, typeless_inline_fragment.selections.length
- assert_equal 0, typeless_inline_fragment.directives.length
- end
-
- it "gets position info" do
- assert_equal [10, 7], inline_fragment.position
- end
- end
-
- describe "inputs" do
- let(:query_string) {%|
- {
- field(
- int: 3,
- float: 4.7e-24,
- bool: false,
- string: "βοΈπ\\n escaped \\" unicode \\u00b6 /",
- enum: ENUM_NAME,
- array: [7, 8, 9]
- object: {a: [1,2,3], b: {c: "4"}}
- unicode_bom: "\xef\xbb\xbfquery"
- keywordEnum: on
- )
- }
- |}
-
- let(:inputs) { document.definitions.first.selections.first.arguments }
-
- it "parses ints" do
- assert_equal 3, inputs[0].value
- end
-
- it "parses floats" do
- assert_equal 0.47e-23, inputs[1].value
- end
-
- it "parses booleans" do
- assert_equal false, inputs[2].value
- end
-
- it "parses UTF-8 strings" do
- assert_equal %|βοΈπ\n escaped " unicode ΒΆ /|, inputs[3].value
- end
-
- it "parses enums" do
- assert_instance_of GraphQL::Language::Nodes::Enum, inputs[4].value
- assert_equal "ENUM_NAME", inputs[4].value.name
- end
-
- it "parses arrays" do
- assert_equal [7,8,9], inputs[5].value
- end
-
- it "parses objects" do
- obj = inputs[6].value
- assert_equal "a", obj.arguments[0].name
- assert_equal [1,2,3], obj.arguments[0].value
- assert_equal "b", obj.arguments[1].name
- assert_equal "c", obj.arguments[1].value.arguments[0].name
- assert_equal "4", obj.arguments[1].value.arguments[0].value
- end
-
- it "parses unicode bom" do
- obj = inputs[7].value
- assert_equal %|\xef\xbb\xbfquery|, inputs[7].value
- end
-
- it "parses enum 'on''" do
- assert_equal "on", inputs[8].value.name
- end
- end
- end
-
- describe "unnamed queries" do
- let(:query_string) {%|
- { name, age, height }
- |}
- let(:operation) { document.definitions.first }
-
- it "parses unnamed queries" do
- assert_equal 1, document.definitions.length
- assert_equal "query", operation.operation_type
- assert_equal nil, operation.name
- assert_equal 3, operation.selections.length
- end
- end
-
- describe "introspection query" do
- let(:query_string) { GraphQL::Introspection::INTROSPECTION_QUERY }
-
- it "parses a big ol' query" do
- assert(document)
- end
- end
-
- describe "schema" do
- it "parses the test schema" do
- schema = DummySchema
- schema_string = GraphQL::Schema::Printer.print_schema(schema)
- document = GraphQL::Language::Parser.parse(schema_string)
-
- assert_equal schema_string, document.to_query_string
- end
-
- it "parses mimal schema definition" do
- document = GraphQL::Language::Parser.parse('schema { query: QueryRoot }')
-
- schema = document.definitions.first
- assert_equal 'QueryRoot', schema.query
- assert_equal nil, schema.mutation
- assert_equal nil, schema.subscription
- end
-
- it "parses full schema definitions" do
- document = GraphQL::Language::Parser.parse('
- schema {
- query: QueryRoot
- mutation: MutationRoot
- subscription: SubscriptionRoot
- }
- ')
-
- schema = document.definitions.first
- assert_equal 'QueryRoot', schema.query
- assert_equal 'MutationRoot', schema.mutation
- assert_equal 'SubscriptionRoot', schema.subscription
- end
-
- it "parses object types" do
- document = GraphQL::Language::Parser.parse('
- type Comment implements Node {
- id: ID!
- }
- ')
-
- type = document.definitions.first
- assert_equal GraphQL::Language::Nodes::ObjectTypeDefinition, type.class
- assert_equal 'Comment', type.name
- assert_equal ['Node'], type.interfaces
- assert_equal ['id'], type.fields.map(&:name)
- assert_equal [], type.fields[0].arguments
- assert_equal 'ID', type.fields[0].type.of_type.name
- end
-
- it "parses field arguments" do
- document = GraphQL::Language::Parser.parse('
- type Mutation {
- post(id: ID!, data: PostData = { message: "First!1!", type: BLOG, tags: ["Test", "Annoying"] }): Post
- }
- ')
-
- field = document.definitions.first.fields.first
- assert_equal ['id', 'data'], field.arguments.map(&:name)
- data_arg = field.arguments[1]
- assert_equal 'PostData', data_arg.type.name
- assert_equal ['message', 'type', 'tags'], data_arg.default_value.arguments.map(&:name)
- tags_arg = data_arg.default_value.arguments[2]
- assert_equal ['Test', 'Annoying'], tags_arg.value
- end
-
- it "parses scalar types" do
- document = GraphQL::Language::Parser.parse('scalar DateTime')
-
- type = document.definitions.first
- assert_equal GraphQL::Language::Nodes::ScalarTypeDefinition, type.class
- assert_equal 'DateTime', type.name
- end
-
- it "parses interface types" do
- document = GraphQL::Language::Parser.parse('
- interface Node {
- id: ID!
- }
- ')
-
- type = document.definitions.first
- assert_equal GraphQL::Language::Nodes::InterfaceTypeDefinition, type.class
- assert_equal 'Node', type.name
- assert_equal ['id'], type.fields.map(&:name)
- assert_equal [], type.fields[0].arguments
- assert_equal 'ID', type.fields[0].type.of_type.name
- end
-
- it "parses enum types" do
- document = GraphQL::Language::Parser.parse('
- enum DogCommand { SIT, DOWN, HEEL }
- ')
-
- type = document.definitions.first
- assert_equal GraphQL::Language::Nodes::EnumTypeDefinition, type.class
- assert_equal 'DogCommand', type.name
- assert_equal ['SIT', 'DOWN', 'HEEL'], type.values
- end
-
- it "parses input object types" do
- document = GraphQL::Language::Parser.parse('
- input EmptyMutationInput {
- clientMutationId: String
- }
- ')
-
- type = document.definitions.first
- assert_equal GraphQL::Language::Nodes::InputObjectTypeDefinition, type.class
- assert_equal 'EmptyMutationInput', type.name
- assert_equal ['clientMutationId'], type.fields.map(&:name)
- assert_equal 'String', type.fields[0].type.name
- assert_equal nil, type.fields[0].default_value
- end
- end
- end
-
- describe "errors" do
- let(:query_string) {%| query doSomething { bogus { } |}
- it "raises a parse error" do
- err = assert_raises(GraphQL::ParseError) { document }
- end
-
- it "correctly identifies parse error location and content" do
- e = assert_raises(GraphQL::ParseError) do
- GraphQL.parse("
- query getCoupons {
- allCoupons: {data{id}}
- }
- ")
- end
- assert_includes(e.message, '"{"')
- assert_includes(e.message, "RCURLY")
- assert_equal(3, e.line)
- assert_equal(25, e.col)
- end
-
- it "handles unexpected ends" do
- err = assert_raises(GraphQL::ParseError) { GraphQL.parse("{ ") }
- assert_equal "Unexpected end of document", err.message
- end
-
- it "rejects unsupported characters" do
- e = assert_raises(GraphQL::ParseError) do
- GraphQL.parse("{ field; }")
- end
-
- assert_includes(e.message, "Parse error on \";\"")
- end
-
- it "rejects control characters" do
- e = assert_raises(GraphQL::ParseError) do
- GraphQL.parse("{ \afield }")
- end
-
- assert_includes(e.message, "Parse error on \"\\a\"")
- end
-
- it "rejects partial BOM" do
- e = assert_raises(GraphQL::ParseError) do
- GraphQL.parse("{ \xeffield }")
- end
-
- assert_includes(e.message, "Parse error on \"\\xEF\"")
- end
-
- it "rejects vertical tabs" do
- e = assert_raises(GraphQL::ParseError) do
- GraphQL.parse("{ \vfield }")
- end
-
- assert_includes(e.message, "Parse error on \"\\v\"")
- end
-
- it "rejects form feed" do
- e = assert_raises(GraphQL::ParseError) do
- GraphQL.parse("{ \ffield }")
- end
-
- assert_includes(e.message, "Parse error on \"\\f\"")
- end
-
- it "rejects no break space" do
- e = assert_raises(GraphQL::ParseError) do
- GraphQL.parse("{ \xa0field }")
- end
-
- assert_includes(e.message, "Parse error on \"\\xA0\"")
- end
-
- it "rejects unterminated strings" do
- e = assert_raises(GraphQL::ParseError) do
- GraphQL.parse("\"")
- end
-
- assert_includes(e.message, "Parse error on \"\\\"\"")
-
- e = assert_raises(GraphQL::ParseError) do
- GraphQL.parse("\"\n\"")
- end
-
- assert_includes(e.message, "Parse error on \"\\n\"")
- end
-
- it "rejects bad escape sequence in strings" do
- e = assert_raises(GraphQL::ParseError) do
- GraphQL.parse("{ field(arg:\"\\x\") }")
- end
-
- assert_includes(e.message, "Parse error on bad Unicode escape sequence")
- end
-
- it "rejects incomplete escape sequence in strings" do
- e = assert_raises(GraphQL::ParseError) do
- GraphQL.parse("{ field(arg:\"\\u1\") }")
- end
-
- assert_includes(e.message, "bad Unicode escape sequence")
- end
-
- it "rejects unicode escape with bad chars" do
- e = assert_raises(GraphQL::ParseError) do
- GraphQL.parse("{ field(arg:\"\\u0XX1\") }")
- end
-
- assert_includes(e.message, "bad Unicode escape sequence")
-
- e = assert_raises(GraphQL::ParseError) do
- GraphQL.parse("{ field(arg:\"\\uXXXX\") }")
- end
-
- assert_includes(e.message, "bad Unicode escape sequence")
-
-
- e = assert_raises(GraphQL::ParseError) do
- GraphQL.parse("{ field(arg:\"\\uFXXX\") }")
- end
-
- assert_includes(e.message, "bad Unicode escape sequence")
-
-
- e = assert_raises(GraphQL::ParseError) do
- GraphQL.parse("{ field(arg:\"\\uXXXF\") }")
- end
-
- assert_includes(e.message, "bad Unicode escape sequence")
- end
-
- it "rejects fragments named 'on'" do
- e = assert_raises(GraphQL::ParseError) do
- GraphQL.parse("fragment on on on { on }")
- end
-
- assert_includes(e.message, "Parse error on \"on\"")
- end
-
- it "rejects fragment spread of 'on'" do
- e = assert_raises(GraphQL::ParseError) do
- GraphQL.parse("{ ...on }")
- end
-
- assert_includes(e.message, "Parse error on \"}\"")
- end
-
- it "rejects null value" do
- e = assert_raises(GraphQL::ParseError) do
- GraphQL.parse("{ fieldWithNullableStringInput(input: null) }")
- end
-
- assert_includes(e.message, "Parse error on \"null\"")
- end
- end
-
-
- describe "whitespace" do
- describe "whitespace-only queries" do
- let(:query_string) { " " }
- it "doesn't blow up" do
- assert_equal [], document.definitions
- end
- end
-
- describe "empty string queries" do
- let(:query_string) { "" }
- it "doesn't blow up" do
- assert_equal [], document.definitions
- end
- end
-
- describe "using tabs as whitespace" do
- let(:query_string) { "\t{\t\tid, \tname}"}
- it "parses the query" do
- assert_equal 1, document.definitions.length
- end
- end
- end
+ include GraphQL::Language::ParserTests
+ subject { GraphQL::Language::Parser }
end