module GraphQL::Compatibility::QueryParserSpecification

This asserts that a given parse function turns a string into the proper tree of {{GraphQL::Language::Nodes}}.

Constants

QUERY_STRING

Public Class Methods

build_suite(&block) click to toggle source

@yieldparam query_string [String] A query string to parse @yieldreturn [GraphQL::Language::Nodes::Document] @return [Class<Minitest::Test>] A test suite for this parse function

# File lib/graphql/compatibility/query_parser_specification.rb, line 13
def self.build_suite(&block)
  GraphQL::Deprecation.warn "#{self} will be removed from GraphQL-Ruby 2.0. There is no replacement, please open an issue on GitHub if you need support."

  Class.new(Minitest::Test) do
    include QueryAssertions
    include ParseErrorSpecification

    @@parse_fn = block

    def parse(query_string)
      @@parse_fn.call(query_string)
    end

    def test_it_parses_queries
      document = parse(QUERY_STRING)
      query = document.definitions.first
      assert_valid_query(query)
      assert_valid_fragment(document.definitions.last)
      assert_valid_variable(query.variables.first)
      field = query.selections.first
      assert_valid_field(field)
      assert_valid_variable_argument(field.arguments.first)
      assert_valid_literal_argument(field.arguments.last)
      assert_valid_directive(field.directives.first)
      fragment_spread = query.selections[1].selections.last
      assert_valid_fragment_spread(fragment_spread)
      assert_valid_typed_inline_fragment(query.selections[2])
      assert_valid_typeless_inline_fragment(query.selections[3])
    end

    def test_it_parses_unnamed_queries
      document = parse("{ name, age, height }")
      operation =  document.definitions.first
      assert_equal 1, document.definitions.length
      assert_equal "query", operation.operation_type
      assert_equal nil, operation.name
      assert_equal 3, operation.selections.length
    end

    def test_it_parses_the_introspection_query
      parse(GraphQL::Introspection::INTROSPECTION_QUERY)
    end

    def test_it_parses_inputs
      query_string = %|
        {
          field(
            int: 3,
            float: 4.7e-24,
            bool: false,
            string: "☀︎🏆 \\b \\f \\n \\r \\t \\" \u00b6 \\u00b6 / \\/",
            enum: ENUM_NAME,
            array: [7, 8, 9]
            object: {a: [1,2,3], b: {c: "4"}}
            unicode_bom: "\xef\xbb\xbfquery"
            keywordEnum: on
            nullValue: null
            nullValueInObject: {a: null, b: "b"}
            nullValueInArray: ["a", null, "b"]
            blockString: """
            Hello,
              World
            """
          )
        }
      |
      document = parse(query_string)
      inputs = document.definitions.first.selections.first.arguments
      assert_equal 3, inputs[0].value, "Integers"
      assert_equal 0.47e-23, inputs[1].value, "Floats"
      assert_equal false, inputs[2].value, "Booleans"
      assert_equal %|☀︎🏆 \b \f \n \r \t " ¶ ¶ / /|, inputs[3].value, "Strings"
      assert_instance_of GraphQL::Language::Nodes::Enum, inputs[4].value
      assert_equal "ENUM_NAME", inputs[4].value.name, "Enums"
      assert_equal [7,8,9], inputs[5].value, "Lists"

      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

      assert_equal %|\xef\xbb\xbfquery|, inputs[7].value, "Unicode BOM"
      assert_equal "on", inputs[8].value.name, "Enum value 'on'"

      assert_instance_of GraphQL::Language::Nodes::NullValue, inputs[9].value

      args = inputs[10].value.arguments
      assert_instance_of GraphQL::Language::Nodes::NullValue, args.find{ |arg| arg.name == 'a' }.value
      assert_equal 'b', args.find{ |arg| arg.name == 'b' }.value

      values = inputs[11].value
      assert_equal 'a', values[0]
      assert_instance_of GraphQL::Language::Nodes::NullValue, values[1]
      assert_equal 'b', values[2]

      block_str_value = inputs[12].value
      assert_equal "Hello,\n  World", block_str_value
    end

    def test_it_doesnt_parse_nonsense_variables
      query_string_1 = "query Vars($var1) { cheese(id: $var1) { flavor } }"
      query_string_2 = "query Vars2($var1: Int = $var1) { cheese(id: $var1) { flavor } }"

      err_1 = assert_raises(GraphQL::ParseError) do
        parse(query_string_1)
      end
      assert_equal [1,17], [err_1.line, err_1.col]

      err_2 = assert_raises(GraphQL::ParseError) do
        parse(query_string_2)
      end
      assert_equal [1,26], [err_2.line, err_2.col]
    end

    def test_enum_value_definitions_have_a_position
      document = parse("""
        enum Enum {
          VALUE
        }
      """)

      assert_equal [3, 17], document.definitions[0].values[0].position
    end

    def test_field_definitions_have_a_position
      document = parse("""
        type A {
          field: String
        }
      """)

      assert_equal [3, 17], document.definitions[0].fields[0].position
    end

    def test_input_value_definitions_have_a_position
      document = parse("""
        input A {
          field: String
        }
      """)

      assert_equal [3, 17], document.definitions[0].fields[0].position
    end

    def test_parses_when_there_are_no_interfaces
      schema = "
        type A {
          a: String
        }
      "

      document = parse(schema)

      assert_equal [], document.definitions[0].interfaces.map(&:name)
    end

    def test_parses_implements_with_leading_ampersand
      schema = "
        type A implements & B {
          a: String
        }
      "

      document = parse(schema)

      assert_equal ["B"], document.definitions[0].interfaces.map(&:name)
      assert_equal [2, 35], document.definitions[0].interfaces[0].position
    end

    def test_parses_implements_with_leading_ampersand_and_multiple_interfaces
      schema = "
        type A implements & B & C {
          a: String
        }
      "

      document = parse(schema)

      assert_equal ["B", "C"], document.definitions[0].interfaces.map(&:name)
      assert_equal [2, 35], document.definitions[0].interfaces[0].position
      assert_equal [2, 39], document.definitions[0].interfaces[1].position
    end

    def test_parses_implements_without_leading_ampersand
      schema = "
        type A implements B {
          a: String
        }
      "

      document = parse(schema)

      assert_equal ["B"], document.definitions[0].interfaces.map(&:name)
      assert_equal [2, 33], document.definitions[0].interfaces[0].position
    end

    def test_parses_implements_without_leading_ampersand_and_multiple_interfaces
      schema = "
        type A implements B & C {
          a: String
        }
      "

      document = parse(schema)

      assert_equal ["B", "C"], document.definitions[0].interfaces.map(&:name)
      assert_equal [2, 33], document.definitions[0].interfaces[0].position
      assert_equal [2, 37], document.definitions[0].interfaces[1].position
    end

    def test_supports_old_syntax_for_parsing_multiple_interfaces
      schema = "
        type A implements B, C {
          a: String
        }
      "

      document = parse(schema)

      assert_equal ["B", "C"], document.definitions[0].interfaces.map(&:name)
      assert_equal [2, 33], document.definitions[0].interfaces[0].position
      assert_equal [2, 36], document.definitions[0].interfaces[1].position
    end
  end
end

Public Instance Methods

parse(query_string) click to toggle source
# File lib/graphql/compatibility/query_parser_specification.rb, line 22
def parse(query_string)
  @@parse_fn.call(query_string)
end
test_enum_value_definitions_have_a_position() click to toggle source
# File lib/graphql/compatibility/query_parser_specification.rb, line 129
def test_enum_value_definitions_have_a_position
  document = parse("""
    enum Enum {
      VALUE
    }
  """)

  assert_equal [3, 17], document.definitions[0].values[0].position
end
test_field_definitions_have_a_position() click to toggle source
# File lib/graphql/compatibility/query_parser_specification.rb, line 139
def test_field_definitions_have_a_position
  document = parse("""
    type A {
      field: String
    }
  """)

  assert_equal [3, 17], document.definitions[0].fields[0].position
end
test_input_value_definitions_have_a_position() click to toggle source
# File lib/graphql/compatibility/query_parser_specification.rb, line 149
def test_input_value_definitions_have_a_position
  document = parse("""
    input A {
      field: String
    }
  """)

  assert_equal [3, 17], document.definitions[0].fields[0].position
end
test_it_doesnt_parse_nonsense_variables() click to toggle source
# File lib/graphql/compatibility/query_parser_specification.rb, line 114
def test_it_doesnt_parse_nonsense_variables
  query_string_1 = "query Vars($var1) { cheese(id: $var1) { flavor } }"
  query_string_2 = "query Vars2($var1: Int = $var1) { cheese(id: $var1) { flavor } }"

  err_1 = assert_raises(GraphQL::ParseError) do
    parse(query_string_1)
  end
  assert_equal [1,17], [err_1.line, err_1.col]

  err_2 = assert_raises(GraphQL::ParseError) do
    parse(query_string_2)
  end
  assert_equal [1,26], [err_2.line, err_2.col]
end
test_it_parses_inputs() click to toggle source
# File lib/graphql/compatibility/query_parser_specification.rb, line 56
def test_it_parses_inputs
  query_string = %|
    {
      field(
        int: 3,
        float: 4.7e-24,
        bool: false,
        string: "☀︎🏆 \\b \\f \\n \\r \\t \\" \u00b6 \\u00b6 / \\/",
        enum: ENUM_NAME,
        array: [7, 8, 9]
        object: {a: [1,2,3], b: {c: "4"}}
        unicode_bom: "\xef\xbb\xbfquery"
        keywordEnum: on
        nullValue: null
        nullValueInObject: {a: null, b: "b"}
        nullValueInArray: ["a", null, "b"]
        blockString: """
        Hello,
          World
        """
      )
    }
  |
  document = parse(query_string)
  inputs = document.definitions.first.selections.first.arguments
  assert_equal 3, inputs[0].value, "Integers"
  assert_equal 0.47e-23, inputs[1].value, "Floats"
  assert_equal false, inputs[2].value, "Booleans"
  assert_equal %|☀︎🏆 \b \f \n \r \t " ¶ ¶ / /|, inputs[3].value, "Strings"
  assert_instance_of GraphQL::Language::Nodes::Enum, inputs[4].value
  assert_equal "ENUM_NAME", inputs[4].value.name, "Enums"
  assert_equal [7,8,9], inputs[5].value, "Lists"

  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

  assert_equal %|\xef\xbb\xbfquery|, inputs[7].value, "Unicode BOM"
  assert_equal "on", inputs[8].value.name, "Enum value 'on'"

  assert_instance_of GraphQL::Language::Nodes::NullValue, inputs[9].value

  args = inputs[10].value.arguments
  assert_instance_of GraphQL::Language::Nodes::NullValue, args.find{ |arg| arg.name == 'a' }.value
  assert_equal 'b', args.find{ |arg| arg.name == 'b' }.value

  values = inputs[11].value
  assert_equal 'a', values[0]
  assert_instance_of GraphQL::Language::Nodes::NullValue, values[1]
  assert_equal 'b', values[2]

  block_str_value = inputs[12].value
  assert_equal "Hello,\n  World", block_str_value
end
test_it_parses_queries() click to toggle source
# File lib/graphql/compatibility/query_parser_specification.rb, line 26
def test_it_parses_queries
  document = parse(QUERY_STRING)
  query = document.definitions.first
  assert_valid_query(query)
  assert_valid_fragment(document.definitions.last)
  assert_valid_variable(query.variables.first)
  field = query.selections.first
  assert_valid_field(field)
  assert_valid_variable_argument(field.arguments.first)
  assert_valid_literal_argument(field.arguments.last)
  assert_valid_directive(field.directives.first)
  fragment_spread = query.selections[1].selections.last
  assert_valid_fragment_spread(fragment_spread)
  assert_valid_typed_inline_fragment(query.selections[2])
  assert_valid_typeless_inline_fragment(query.selections[3])
end
test_it_parses_the_introspection_query() click to toggle source
# File lib/graphql/compatibility/query_parser_specification.rb, line 52
def test_it_parses_the_introspection_query
  parse(GraphQL::Introspection::INTROSPECTION_QUERY)
end
test_it_parses_unnamed_queries() click to toggle source
# File lib/graphql/compatibility/query_parser_specification.rb, line 43
def test_it_parses_unnamed_queries
  document = parse("{ name, age, height }")
  operation =  document.definitions.first
  assert_equal 1, document.definitions.length
  assert_equal "query", operation.operation_type
  assert_equal nil, operation.name
  assert_equal 3, operation.selections.length
end
test_parses_implements_with_leading_ampersand() click to toggle source
# File lib/graphql/compatibility/query_parser_specification.rb, line 171
def test_parses_implements_with_leading_ampersand
  schema = "
    type A implements & B {
      a: String
    }
  "

  document = parse(schema)

  assert_equal ["B"], document.definitions[0].interfaces.map(&:name)
  assert_equal [2, 35], document.definitions[0].interfaces[0].position
end
test_parses_implements_with_leading_ampersand_and_multiple_interfaces() click to toggle source
# File lib/graphql/compatibility/query_parser_specification.rb, line 184
def test_parses_implements_with_leading_ampersand_and_multiple_interfaces
  schema = "
    type A implements & B & C {
      a: String
    }
  "

  document = parse(schema)

  assert_equal ["B", "C"], document.definitions[0].interfaces.map(&:name)
  assert_equal [2, 35], document.definitions[0].interfaces[0].position
  assert_equal [2, 39], document.definitions[0].interfaces[1].position
end
test_parses_implements_without_leading_ampersand() click to toggle source
# File lib/graphql/compatibility/query_parser_specification.rb, line 198
def test_parses_implements_without_leading_ampersand
  schema = "
    type A implements B {
      a: String
    }
  "

  document = parse(schema)

  assert_equal ["B"], document.definitions[0].interfaces.map(&:name)
  assert_equal [2, 33], document.definitions[0].interfaces[0].position
end
test_parses_implements_without_leading_ampersand_and_multiple_interfaces() click to toggle source
# File lib/graphql/compatibility/query_parser_specification.rb, line 211
def test_parses_implements_without_leading_ampersand_and_multiple_interfaces
  schema = "
    type A implements B & C {
      a: String
    }
  "

  document = parse(schema)

  assert_equal ["B", "C"], document.definitions[0].interfaces.map(&:name)
  assert_equal [2, 33], document.definitions[0].interfaces[0].position
  assert_equal [2, 37], document.definitions[0].interfaces[1].position
end
test_parses_when_there_are_no_interfaces() click to toggle source
# File lib/graphql/compatibility/query_parser_specification.rb, line 159
def test_parses_when_there_are_no_interfaces
  schema = "
    type A {
      a: String
    }
  "

  document = parse(schema)

  assert_equal [], document.definitions[0].interfaces.map(&:name)
end
test_supports_old_syntax_for_parsing_multiple_interfaces() click to toggle source
# File lib/graphql/compatibility/query_parser_specification.rb, line 225
def test_supports_old_syntax_for_parsing_multiple_interfaces
  schema = "
    type A implements B, C {
      a: String
    }
  "

  document = parse(schema)

  assert_equal ["B", "C"], document.definitions[0].interfaces.map(&:name)
  assert_equal [2, 33], document.definitions[0].interfaces[0].position
  assert_equal [2, 36], document.definitions[0].interfaces[1].position
end