# frozen_string_literal: true require "spec_helper" describe GraphQL::Directive do let(:variables) { {"t" => true, "f" => false} } let(:result) { Dummy::Schema.execute(query_string, variables: variables) } describe "on fields" do let(:query_string) { %|query directives($t: Boolean!, $f: Boolean!) { cheese(id: 1) { # plain fields: skipFlavor: flavor @skip(if: true) dontSkipFlavor: flavor @skip(if: false) dontSkipDontIncludeFlavor: flavor @skip(if: false), @include(if: false) skipAndInclude: flavor @skip(if: true), @include(if: true) includeFlavor: flavor @include(if: $t) dontIncludeFlavor: flavor @include(if: $f) # fields in fragments ... includeIdField ... dontIncludeIdField ... skipIdField ... dontSkipIdField } } fragment includeIdField on Cheese { includeId: id @include(if: true) } fragment dontIncludeIdField on Cheese { dontIncludeId: id @include(if: false) } fragment skipIdField on Cheese { skipId: id @skip(if: true) } fragment dontSkipIdField on Cheese { dontSkipId: id @skip(if: false) } | } describe "child fields" do let(:query_string) { <<-GRAPHQL { __type(name: "Cheese") { fields { name } fields @skip(if: true) { isDeprecated } } } GRAPHQL } it "skips child fields too" do first_field = result["data"]["__type"]["fields"].first assert first_field.key?("name") assert !first_field.key?("isDeprecated") end end it "intercepts fields" do expected = { "data" =>{ "cheese" => { "dontSkipFlavor" => "Brie", "includeFlavor" => "Brie", "includeId" => 1, "dontSkipId" => 1, }, }} assert_equal(expected, result) end end describe "on fragments spreads and inline fragments" do let(:query_string) { %|query directives { cheese(id: 1) { ... skipFlavorField @skip(if: true) ... dontSkipFlavorField @skip(if: false) ... includeFlavorField @include(if: true) ... dontIncludeFlavorField @include(if: false) ... on Cheese @skip(if: true) { skipInlineId: id } ... on Cheese @skip(if: false) { dontSkipInlineId: id } ... on Cheese @include(if: true) { includeInlineId: id } ... on Cheese @include(if: false) { dontIncludeInlineId: id } ... @skip(if: true) { skipNoType: id } ... @skip(if: false) { dontSkipNoType: id } } } fragment includeFlavorField on Cheese { includeFlavor: flavor } fragment dontIncludeFlavorField on Cheese { dontIncludeFlavor: flavor } fragment skipFlavorField on Cheese { skipFlavor: flavor } fragment dontSkipFlavorField on Cheese { dontSkipFlavor: flavor } |} it "intercepts fragment spreads" do expected = { "data" => { "cheese" => { "dontSkipFlavor" => "Brie", "includeFlavor" => "Brie", "dontSkipInlineId" => 1, "includeInlineId" => 1, "dontSkipNoType" => 1, }, }} assert_equal(expected, result) end end describe "merging @skip and @include" do let(:field_included?) { r = result["data"]["cheese"]; r.has_key?('flavor') && r.has_key?('withVariables') } let(:skip?) { false } let(:include?) { true } let(:variables) { {"skip" => skip?, "include" => include?} } let(:query_string) {" query getCheese ($include: Boolean!, $skip: Boolean!) { cheese(id: 1) { flavor @include(if: #{include?}) @skip(if: #{skip?}), withVariables: flavor @include(if: $include) @skip(if: $skip) } } "} # behavior as defined in # https://github.com/facebook/graphql/blob/master/spec/Section%203%20--%20Type%20System.md#include describe "when @skip=false and @include=true" do let(:skip?) { false } let(:include?) { true } it "is included" do assert field_included? end end describe "when @skip=false and @include=false" do let(:skip?) { false } let(:include?) { false } it "is not included" do assert !field_included? end end describe "when @skip=true and @include=true" do let(:skip?) { true } let(:include?) { true } it "is not included" do assert !field_included? end end describe "when @skip=true and @include=false" do let(:skip?) { true } let(:include?) { false } it "is not included" do assert !field_included? end end describe "when evaluating skip on query selection and fragment" do describe "with @skip" do let(:query_string) {" query getCheese ($skip: Boolean!) { cheese(id: 1) { flavor, withVariables: flavor, ...F0 } } fragment F0 on Cheese { flavor @skip(if: #{skip?}) withVariables: flavor @skip(if: $skip) } "} describe "and @skip=false" do let(:skip?) { false } it "is included" do assert field_included? end end describe "and @skip=true" do let(:skip?) { true } it "is included" do assert field_included? end end end end describe "when evaluating conflicting @skip and @include on query selection and fragment" do let(:query_string) {" query getCheese ($include: Boolean!, $skip: Boolean!) { cheese(id: 1) { ... on Cheese @include(if: #{include?}) { flavor } withVariables: flavor @include(if: $include), ...F0 } } fragment F0 on Cheese { flavor @skip(if: #{skip?}), withVariables: flavor @skip(if: $skip) } "} describe "when @skip=false and @include=true" do let(:skip?) { false } let(:include?) { true } it "is included" do assert field_included? end end describe "when @skip=false and @include=false" do let(:skip?) { false } let(:include?) { false } it "is included" do assert field_included? end end describe "when @skip=true and @include=true" do let(:skip?) { true } let(:include?) { true } it "is included" do assert field_included? end end describe "when @skip=true and @include=false" do let(:skip?) { true } let(:include?) { false } it "is not included" do assert !field_included? end end end describe "when handling multiple fields at the same level" do describe "when at least one occurrence would be included" do let(:query_string) {" query getCheese ($include: Boolean!, $skip: Boolean!) { cheese(id: 1) { ... on Cheese { flavor } flavor @include(if: #{include?}), flavor @skip(if: #{skip?}), withVariables: flavor, withVariables: flavor @include(if: $include), withVariables: flavor @skip(if: $skip) } } "} let(:skip?) { true } let(:include?) { false } it "is included" do assert field_included? end end describe "when no occurrence would be included" do let(:query_string) {" query getCheese ($include: Boolean!, $skip: Boolean!) { cheese(id: 1) { flavor @include(if: #{include?}), flavor @skip(if: #{skip?}), withVariables: flavor @include(if: $include), withVariables: flavor @skip(if: $skip) } } "} let(:skip?) { true } let(:include?) { false } it "is not included" do assert !field_included? end end end end describe "defining a directive" do let(:directive) { GraphQL::Directive.define do arguments [GraphQL::Argument.define(name: 'skip')] end } it "can accept an array of arguments" do assert_equal 1, directive.arguments.length assert_equal 'skip', directive.arguments.first.name end it "is not default" do assert_equal false, directive.default_directive? end end end