371 строка
10 KiB
Ruby
371 строка
10 KiB
Ruby
# frozen_string_literal: true
|
|
require "graphql"
|
|
require "graphql/client"
|
|
require "minitest/autorun"
|
|
|
|
class TestClientErrors < MiniTest::Test
|
|
class FooType < GraphQL::Schema::Object
|
|
field :nullable_error, String, null: true
|
|
def nullable_error
|
|
raise GraphQL::ExecutionError, "b00m"
|
|
end
|
|
|
|
field :nonnullable_error, String, null: false
|
|
def nonnullable_error
|
|
raise GraphQL::ExecutionError, "b00m"
|
|
end
|
|
end
|
|
|
|
class QueryType < GraphQL::Schema::Object
|
|
field :version, Int, null: false
|
|
def version
|
|
1
|
|
end
|
|
|
|
field :node, FooType, null: true
|
|
def node
|
|
GraphQL::ExecutionError.new("missing node")
|
|
end
|
|
|
|
field :nodes, [FooType, null: true], null: false
|
|
def nodes
|
|
[GraphQL::ExecutionError.new("missing node"), {}]
|
|
end
|
|
|
|
field :nullable_error, String, null: true
|
|
def nullable_error
|
|
raise GraphQL::ExecutionError, "b00m"
|
|
end
|
|
|
|
field :nonnullable_error, String, null: false
|
|
def nonnullable_error
|
|
raise GraphQL::ExecutionError, "b00m"
|
|
end
|
|
|
|
field :foo, FooType, null: false
|
|
def foo
|
|
{}
|
|
end
|
|
|
|
field :foos, [FooType], null: true
|
|
def foos
|
|
[{}, {}]
|
|
end
|
|
end
|
|
|
|
class Schema < GraphQL::Schema
|
|
query(QueryType)
|
|
|
|
if defined?(GraphQL::Execution::Interpreter)
|
|
use GraphQL::Execution::Interpreter
|
|
use GraphQL::Analysis::AST
|
|
end
|
|
end
|
|
|
|
module Temp
|
|
end
|
|
|
|
def setup
|
|
@client = GraphQL::Client.new(schema: Schema, execute: Schema)
|
|
end
|
|
|
|
def teardown
|
|
Temp.constants.each do |sym|
|
|
Temp.send(:remove_const, sym)
|
|
end
|
|
end
|
|
|
|
def test_normalize_error_path
|
|
actual = {
|
|
"data" => nil,
|
|
"errors" => [
|
|
{
|
|
"message" => "error"
|
|
}
|
|
]
|
|
}
|
|
GraphQL::Client::Errors.normalize_error_paths(actual["data"], actual["errors"])
|
|
expected = {
|
|
"data" => nil,
|
|
"errors" => [
|
|
{
|
|
"message" => "error",
|
|
"normalizedPath" => %w(data)
|
|
}
|
|
]
|
|
}
|
|
assert_equal expected, actual
|
|
|
|
actual = {
|
|
"data" => {
|
|
"node" => nil
|
|
},
|
|
"errors" => [
|
|
{
|
|
"message" => "error",
|
|
"path" => %w(node)
|
|
}
|
|
]
|
|
}
|
|
GraphQL::Client::Errors.normalize_error_paths(actual["data"], actual["errors"])
|
|
expected = {
|
|
"data" => {
|
|
"node" => nil
|
|
},
|
|
"errors" => [
|
|
{
|
|
"message" => "error",
|
|
"path" => %w(node),
|
|
"normalizedPath" => %w(data node)
|
|
}
|
|
]
|
|
}
|
|
assert_equal expected, actual
|
|
|
|
actual = {
|
|
"data" => nil,
|
|
"errors" => [
|
|
{
|
|
"message" => "error",
|
|
"path" => %w(node projects owner)
|
|
}
|
|
]
|
|
}
|
|
GraphQL::Client::Errors.normalize_error_paths(actual["data"], actual["errors"])
|
|
expected = {
|
|
"data" => nil,
|
|
"errors" => [
|
|
{
|
|
"message" => "error",
|
|
"path" => %w(node projects owner),
|
|
"normalizedPath" => %w(data)
|
|
}
|
|
]
|
|
}
|
|
assert_equal expected, actual
|
|
|
|
actual = {
|
|
"data" => {
|
|
"node" => nil
|
|
},
|
|
"errors" => [
|
|
{
|
|
"message" => "error",
|
|
"path" => %w(node projects owner)
|
|
}
|
|
]
|
|
}
|
|
GraphQL::Client::Errors.normalize_error_paths(actual["data"], actual["errors"])
|
|
expected = {
|
|
"data" => {
|
|
"node" => nil
|
|
},
|
|
"errors" => [
|
|
{
|
|
"message" => "error",
|
|
"path" => %w(node projects owner),
|
|
"normalizedPath" => %w(data node)
|
|
}
|
|
]
|
|
}
|
|
assert_equal expected, actual
|
|
end
|
|
|
|
def test_filter_nested_errors_by_path
|
|
raw_errors = [
|
|
{
|
|
"message" => "1",
|
|
"normalizedPath" => %w(node id)
|
|
},
|
|
{
|
|
"message" => "2",
|
|
"normalizedPath" => %w(node owner name)
|
|
},
|
|
{
|
|
"message" => "3",
|
|
"normalizedPath" => ["node", "repositories", 0, "name"]
|
|
},
|
|
{
|
|
"message" => "4",
|
|
"normalizedPath" => ["version"]
|
|
}
|
|
]
|
|
|
|
errors = GraphQL::Client::Errors.new(raw_errors, [], true)
|
|
assert_equal 4, errors.count
|
|
assert_equal({ "node" => %w(1 2 3), "version" => ["4"] }, errors.messages.to_h)
|
|
|
|
errors = GraphQL::Client::Errors.new(raw_errors, ["node"], true)
|
|
assert_equal 3, errors.count
|
|
assert_equal({ "id" => ["1"], "owner" => ["2"], "repositories" => ["3"] }, errors.messages.to_h)
|
|
|
|
errors = GraphQL::Client::Errors.new(raw_errors, ["version"], true)
|
|
assert_empty errors
|
|
end
|
|
|
|
def test_filter_direct_errors_by_path
|
|
raw_errors = [
|
|
{
|
|
"message" => "1",
|
|
"normalizedPath" => %w(node id)
|
|
},
|
|
{
|
|
"message" => "2",
|
|
"normalizedPath" => %w(node owner name)
|
|
},
|
|
{
|
|
"message" => "3",
|
|
"normalizedPath" => ["node", "repositories", 0, "name"]
|
|
},
|
|
{
|
|
"message" => "4",
|
|
"normalizedPath" => ["version"]
|
|
}
|
|
]
|
|
|
|
errors = GraphQL::Client::Errors.new(raw_errors, [], false)
|
|
assert_equal 1, errors.count
|
|
assert_equal({ "version" => ["4"] }, errors.messages.to_h)
|
|
|
|
errors = GraphQL::Client::Errors.new(raw_errors, ["node"], false)
|
|
assert_equal 1, errors.count
|
|
assert_equal({ "id" => ["1"] }, errors.messages.to_h)
|
|
|
|
errors = GraphQL::Client::Errors.new(raw_errors, %w(node owner), false)
|
|
assert_equal 1, errors.count
|
|
assert_equal({ "name" => ["2"] }, errors.messages.to_h)
|
|
|
|
errors = GraphQL::Client::Errors.new(raw_errors, ["node", "repositories", 0], false)
|
|
assert_equal 1, errors.count
|
|
assert_equal({ "name" => ["3"] }, errors.messages.to_h)
|
|
|
|
errors = GraphQL::Client::Errors.new(raw_errors, ["version"], false)
|
|
assert_empty errors
|
|
end
|
|
|
|
def test_errors_collection
|
|
Temp.const_set :Query, @client.parse("{ nullableError }")
|
|
assert response = @client.query(Temp::Query)
|
|
|
|
assert_nil response.data.nullable_error
|
|
|
|
assert_equal false, response.data.errors.empty?
|
|
assert_equal false, response.data.errors.blank?
|
|
|
|
assert_equal 1, response.data.errors.size
|
|
assert_equal 1, response.data.errors.count
|
|
|
|
assert_equal true, response.data.errors.include?(:nullableError)
|
|
assert_equal true, response.data.errors.include?("nullableError")
|
|
assert_equal true, response.data.errors.include?(:nullable_error)
|
|
assert_equal true, response.data.errors[:nullableError].any?
|
|
assert_equal true, response.data.errors["nullableError"].any?
|
|
assert_equal true, response.data.errors[:nullable_error].any?
|
|
|
|
assert_equal false, response.data.errors.include?(:missingError)
|
|
assert_equal false, response.data.errors.include?("missingError")
|
|
assert_equal false, response.data.errors.include?(:missing_error)
|
|
assert_equal false, response.data.errors[:missingError].any?
|
|
assert_equal false, response.data.errors["missingError"].any?
|
|
assert_equal false, response.data.errors[:missing_error].any?
|
|
|
|
assert_equal "b00m", response.data.errors[:nullableError][0]
|
|
assert_equal "b00m", response.data.errors[:nullable_error][0]
|
|
|
|
assert_equal "b00m", response.data.errors.messages["nullableError"][0]
|
|
|
|
detail = {
|
|
"message" => "b00m",
|
|
"locations" => [{ "line" => 1, "column" => 3 }],
|
|
"path" => %w(nullableError),
|
|
"normalizedPath" => %w(data nullableError)
|
|
}
|
|
assert_equal(detail, response.data.errors.details["nullableError"][0])
|
|
|
|
assert_equal [%w(nullableError b00m)], response.data.errors.each.to_a
|
|
assert_equal ["nullableError"], response.data.errors.keys
|
|
assert_equal [["b00m"]], response.data.errors.values
|
|
|
|
assert_equal({
|
|
"data" => {
|
|
"nullableError" => nil
|
|
},
|
|
"errors" => [
|
|
{
|
|
"message" => "b00m",
|
|
"locations" => [{"line" => 1, "column" => 3}],
|
|
"path" => ["nullableError"]
|
|
}
|
|
]
|
|
}, response.to_h)
|
|
end
|
|
|
|
def test_nested_errors
|
|
Temp.const_set :Query, @client.parse("{ foo { nullableError } }")
|
|
assert response = @client.query(Temp::Query)
|
|
|
|
assert response.data.foo
|
|
assert_empty response.data.errors
|
|
assert_equal "b00m", response.data.errors.all["foo"][0]
|
|
|
|
assert_nil response.data.foo.nullable_error
|
|
assert_equal "b00m", response.data.foo.errors["nullableError"][0]
|
|
assert_equal "b00m", response.data.foo.errors.all["nullableError"][0]
|
|
end
|
|
|
|
def test_nonnullable_root_error
|
|
Temp.const_set :Query, @client.parse("{ version, nonnullableError }")
|
|
assert response = @client.query(Temp::Query)
|
|
|
|
assert_nil response.data
|
|
refute_empty response.errors
|
|
assert_equal "b00m", response.errors[:data][0]
|
|
assert_equal "b00m", response.errors.all[:data][0]
|
|
end
|
|
|
|
def test_nonnullable_nested_error
|
|
Temp.const_set :Query, @client.parse("{ version, foo { nonnullableError } }")
|
|
assert response = @client.query(Temp::Query)
|
|
|
|
assert_nil response.data
|
|
refute_empty response.errors
|
|
assert_equal "b00m", response.errors[:data][0]
|
|
assert_equal "b00m", response.errors.all[:data][0]
|
|
end
|
|
|
|
def test_collection_errors
|
|
Temp.const_set :Query, @client.parse("{ foos { nullableError } }")
|
|
assert response = @client.query(Temp::Query)
|
|
|
|
assert response.data.foos
|
|
assert_empty response.data.errors
|
|
assert_equal "b00m", response.data.errors.all["foos"][0]
|
|
assert_equal "b00m", response.data.errors.all["foos"][1]
|
|
|
|
assert_nil response.data.foos[0].nullable_error
|
|
assert_equal "b00m", response.data.foos[0].errors["nullableError"][0]
|
|
assert_equal "b00m", response.data.foos[0].errors.all["nullableError"][0]
|
|
end
|
|
|
|
def test_node_errors
|
|
Temp.const_set :Query, @client.parse("{ node { __typename } nodes { __typename } }")
|
|
assert response = @client.query(Temp::Query)
|
|
|
|
assert_nil response.data.node
|
|
# This list-error handling behavior is broken for class-based schemas that don't use the interpreter.
|
|
# The fix is an `.is_a?` check in `proxy_to_depth` in member_instrumentation.rb
|
|
if defined?(GraphQL::Execution::Interpreter)
|
|
assert_nil response.data.nodes[0]
|
|
end
|
|
assert response.data.nodes[1]
|
|
assert_equal "Foo", response.data.nodes[1].__typename
|
|
|
|
refute_empty response.data.errors
|
|
assert_equal "missing node", response.data.errors["node"][0]
|
|
# This error isn't added in class-based schemas + `Execution::Execute`, same bug as above
|
|
if defined?(GraphQL::Execution::Interpreter)
|
|
assert_equal "missing node", response.data.nodes.errors[0][0]
|
|
end
|
|
end
|
|
end
|