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
|
# frozen_string_literal: true
require "spec_helper"
describe GraphQL::Schema::Directive::Feature do
class FeatureSchema < GraphQL::Schema
class Feature < GraphQL::Schema::Directive::Feature
def self.enabled?(flag_name, obj, ctx)
!!ctx[flag_name.to_sym]
end
end
# Based on feature but uses a runtime check instead of ahead-of-time
class RuntimeFeature < GraphQL::Schema::Directive
locations(GraphQL::Schema::Directive::FRAGMENT_SPREAD)
argument :flag, String,
description: "The name of the feature to check before continuing"
def self.resolve(object, arguments, context, &block)
flag_name = arguments[:flag]
if context[flag_name]
yield
else
# pass
end
end
end
class Query < GraphQL::Schema::Object
field :int, Integer, null: false
def int
context[:int] ||= 0
context[:int] += 1
end
end
directive(Feature)
directive(RuntimeFeature)
query(Query)
end
it "skips or runs fields" do
str = '{
int1: int
int2: int @feature(flag: "flag1")
int3: int @feature(flag: "flag2")
}'
res = FeatureSchema.execute(str, context: { flag2: true })
# Int2 was not called, so `int3` is actually 2
assert_equal({"int1" => 1, "int3" => 2}, res["data"])
end
it "skips or runs fragment spreads" do
str = '{
...F1
...F2 @feature(flag: "flag1")
...F3 @feature(flag: "flag2")
int4: int
}
fragment F1 on Query { int1: int }
fragment F2 on Query { int2: int }
fragment F3 on Query { int3: int }
'
res = FeatureSchema.execute(str, context: { flag1: true })
# `int3` was skipped
assert_equal({"int1" => 1, "int2" => 2, "int4" => 3}, res["data"])
end
it "skips or runs inline fragments" do
str = '{
... { int1: int }
... @feature(flag: "flag1") { int2: int }
... @feature(flag: "flag2") { int3: int }
int4: int
}
'
res = FeatureSchema.execute(str, context: { flag2: true })
# `int2` was skipped
assert_equal({"int1" => 1, "int3" => 2, "int4" => 3}, res["data"])
end
it "returns an error if it's in the wrong place" do
str = '
query @feature(flag: "x") {
int
}
'
res = FeatureSchema.execute(str)
assert_equal ["'@feature' can't be applied to queries (allowed: fields, fragment spreads, inline fragments)"], res["errors"].map { |e| e["message"] }
end
it "runs or skips on deeply nested fragment spreads fragments" do
str = "{
int
... Q1
}
fragment Q1 on Query {
... Q2
}
fragment Q2 on Query {
... Q3 @runtimeFeature(flag: \"x\")
}
fragment Q3 on Query {
i2: int
}
"
res = FeatureSchema.execute(str, context: { "x" => true })
assert_equal 1, res["data"]["int"]
assert_equal 2, res["data"]["i2"]
end
end
|