File: validator_spec.rb

package info (click to toggle)
ruby-graphql 2.2.17-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 9,584 kB
  • sloc: ruby: 67,505; ansic: 1,753; yacc: 831; javascript: 331; makefile: 6
file content (210 lines) | stat: -rw-r--r-- 7,000 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
# frozen_string_literal: true
require "spec_helper"
require_relative "./validator/validator_helpers"

describe GraphQL::Schema::Validator do
  include ValidatorHelpers

  class CustomValidator < GraphQL::Schema::Validator
    def initialize(equal_to:, **rest)
      @equal_to = equal_to
      super(**rest)
    end

    def validate(object, context, value)
      if value == @equal_to
        nil
      else
        "%{validated} doesn't have the right the right value"
      end
    end
  end

  class CustomErrorValidator < GraphQL::Schema::Validator
    def validate(obj, ctx, value)
      if value != 7
        raise GraphQL::ExecutionError.new("#{@validated.path} must be `7`, not `#{value}`", extensions: { requiredValue: 7, actualValue: value })
      end
    end
  end

  before do
    GraphQL::Schema::Validator.install(:custom, CustomValidator)
    GraphQL::Schema::Validator.install(:custom_error, CustomErrorValidator)
  end

  after do
    GraphQL::Schema::Validator.uninstall(:custom)
    GraphQL::Schema::Validator.uninstall(:custom_error)
  end

  build_tests(CustomValidator, Integer, [
    {
      name: "with a validator class as name",
      config: { equal_to: 2 },
      cases: [
        { query: "{ validated(value: 2) }", error_messages: [], result: 2 },
        { query: "{ validated(value: 3) }", error_messages: ["value doesn't have the right the right value"], result: nil },
      ]
    }
  ])

  build_tests(:custom, Integer, [
    {
      name: "with an installed symbol name",
      config: { equal_to: 4 },
      cases: [
        { query: "{ validated(value: 4) }", error_messages: [], result: 4 },
        { query: "{ validated(value: 3) }", error_messages: ["value doesn't have the right the right value"], result: nil },
      ]
    }
  ])

  it "works with custom raised errors" do
    schema = build_schema(Integer, { custom_error: {} })
    res = schema.execute("{ validated(value: 7) }")
    assert_equal 7, res["data"]["validated"]

    res = schema.execute("{ validated(value: 77) }")
    expected_error = {
      "message"=>"Query.validated.value must be `7`, not `77`",
      "locations"=>[{"line"=>1, "column"=>3}],
      "path"=>["validated"],
      "extensions"=>{"requiredValue"=>7, "actualValue"=>77}
    }
    assert_equal [expected_error], res["errors"]
  end

  it "does something with multiple validators" do
    schema = build_schema(String, { length: { minimum: 5 }, inclusion: { in: ["0", "123456", "678910"] }})
    # Both validators pass:
    res = schema.execute("{ validated(value: \"123456\") }")
    assert_nil res["errors"]
    assert_equal "123456", res["data"]["validated"]

    # The length validator fails:
    res2 = schema.execute("{ validated(value: \"0\") }")
    assert_nil res2["data"]["validated"]
    assert_equal ["value is too short (minimum is 5)"], res2["errors"].map { |e| e["message"] }

    # The inclusion validator fails:
    res3 = schema.execute("{ validated(value: \"00000000\") }")
    assert_nil res3["data"]["validated"]
    assert_equal ["value is not included in the list"], res3["errors"].map { |e| e["message"] }

    # Both validators fail:
    res4 = schema.execute("{ validated(value: \"1\") }")
    assert_nil res4["data"]["validated"]
    errs = [
      "value is too short (minimum is 5), value is not included in the list",
    ]
    assert_equal errs, res4["errors"].map { |e| e["message"] }

    # Two fields with different errors
    res5 = schema.execute("{ v1: validated(value: \"0\") v2: validated(value: \"123456\") v3: validated(value: \"abcdefg\") }")
    expected_data = {"v1"=>nil, "v2"=>"123456", "v3"=>nil}
    assert_equal expected_data, res5["data"]
    errs = [
      {
        "message" => "value is too short (minimum is 5)",
        "locations" => [{"line"=>1, "column"=>3}],
        "path" => ["v1"]
      }, {
        "message" => "value is not included in the list",
        "locations" => [{"line"=>1, "column"=>60}],
        "path" => ["v3"]
      }
    ]
    assert_equal errs, res5["errors"]
  end

  it "validates each item in the list" do
    schema = build_schema(Integer, { numericality: { greater_than: 5 } })
    res = schema.execute("{ list { validated(value: 6) } }")
    expected_data = {
      "list" => [
        { "validated" => 6 },
        { "validated" => 6 },
        { "validated" => 6 },
      ]
    }
    assert_equal expected_data, res["data"]

    res = schema.execute("{ list { validated(value: 3) } }")
    expected_response = {
      "data" => {
        "list" => [
          { "validated" => nil },
          { "validated" => nil },
          { "validated" => nil },
        ]
      },
      "errors" => [
        {"message"=>"value must be greater than 5", "locations"=>[{"line"=>1, "column"=>10}], "path"=>["list", 0, "validated"]},
        {"message"=>"value must be greater than 5", "locations"=>[{"line"=>1, "column"=>10}], "path"=>["list", 1, "validated"]},
        {"message"=>"value must be greater than 5", "locations"=>[{"line"=>1, "column"=>10}], "path"=>["list", 2, "validated"]},
      ]
    }
    assert_equal expected_response, res
  end

  describe "Validator inheritance" do
    class ValidationInheritanceSchema < GraphQL::Schema
      class BaseValidatedInput < GraphQL::Schema::InputObject
        argument :int, Integer, required: false
        argument :other_int, Integer, required: false
        validates required: { one_of: [:int, :other_int] }
      end

      class IntInput < BaseValidatedInput
        graphql_name "IntInput"
      end

      class BaseValidatedResolver < GraphQL::Schema::Resolver
        argument :int, Integer, required: false
        argument :other_int, Integer, required: false
        validates required: { one_of: [:int, :other_int] }
        type Integer, null: true

        def resolve(int: nil, other_int: nil)
          int || other_int
        end
      end

      class IntResolver < BaseValidatedResolver
      end

      class Query < GraphQL::Schema::Object
        field :int_input, Int do
          argument :input, IntInput
        end

        def int_input(input:)
          input[:int] || input[:other_int]
        end

        field :int, resolver: IntResolver
      end

      query(Query)
    end

    it "works with input objects" do
      res = ValidationInheritanceSchema.execute("{ intInput(input: { int: 1 }) }")
      assert_equal 1, res["data"]["intInput"]

      res = ValidationInheritanceSchema.execute("{ intInput(input: { int: 1, otherInt: 2 }) }")
      assert_nil res["data"]["intInput"]
      assert_equal ["IntInput has the wrong arguments"], res["errors"].map { |e| e["message"] }
    end

    it "works with resolvers" do
      res = ValidationInheritanceSchema.execute("{ int(int: 1) }")
      assert_equal 1, res["data"]["int"]

      res = ValidationInheritanceSchema.execute("{ int(int: 1, otherInt: 2) }")
      assert_nil res["data"]["int"]
      assert_equal ["int has the wrong arguments"], res["errors"].map { |e| e["message"] }
    end
  end
end