diff --git a/spec/graphql/execution/lookahead_spec.rb b/spec/graphql/execution/lookahead_spec.rb index 995f09b11d2..159aba4fd00 100644 --- a/spec/graphql/execution/lookahead_spec.rb +++ b/spec/graphql/execution/lookahead_spec.rb @@ -142,7 +142,7 @@ class Schema < GraphQL::Schema GRAPHQL } - it "finds fields on object types and interface types" do + it "enumerates fields on object types and interface types" do node_lookahead = query.lookahead.selection("node") assert_equal [:id, :name, :latin_name], node_lookahead.selections.map(&:name) end @@ -243,9 +243,9 @@ class Schema < GraphQL::Schema it "finds selections using merging" do merged_lookahead = query.lookahead.selection(:find_bird_species).selection(:similar_species) - assert merged_lookahead.selects?(:__typename) - assert merged_lookahead.selects?(:is_waterfowl) - assert merged_lookahead.selects?(:name) + assert_equal true, merged_lookahead.selects?(:__typename) + assert_equal true, merged_lookahead.selects?(:is_waterfowl) + assert_equal true, merged_lookahead.selects?(:name) end end end @@ -279,7 +279,7 @@ class Schema < GraphQL::Schema it "works for invalid queries" do context = {lookahead_latin_name: 0} res = LookaheadTest::Schema.execute("{ doesNotExist }", context: context) - assert res.key?("errors") + assert_equal true, res.key?("errors") assert_equal 0, context[:lookahead_latin_name] end end @@ -413,4 +413,185 @@ def query(doc = document) assert_equal false, lookahead.selects?(:name) end end + + describe '#selects?' do + let(:document) { + GraphQL.parse <<-GRAPHQL + query { + findBirdSpecies(byName: "Laughing Gull") { + name + similarSpecies { + likesWater: isWaterfowl + } + } + } + GRAPHQL + } + + def query(doc = document) + GraphQL::Query.new(LookaheadTest::Schema, document: doc) + end + + it "returns true for each field that is selected" do + ast_node = document.definitions.first.selections.first + field = LookaheadTest::Query.fields["findBirdSpecies"] + lookahead = GraphQL::Execution::Lookahead.new(query: query, ast_nodes: [ast_node], field: field) + assert_equal true, lookahead.selects?(:name) + assert_equal true, lookahead.selects?(:similar_species) + end + + it "returns false for a selection which does not match arguments" do + ast_node = document.definitions.first + lookahead = GraphQL::Execution::Lookahead.new(query: query, ast_nodes: [ast_node], root_type: LookaheadTest::Query) + arguments = { by_name: "Cardinal" } + + assert_equal false, lookahead.selects?(:name, arguments: arguments) + end + + it "returns true for a selection which matches arguments" do + ast_node = document.definitions.first + lookahead = GraphQL::Execution::Lookahead.new(query: query, ast_nodes: [ast_node], root_type: LookaheadTest::Query) + arguments = { by_name: "Laughing Gull" } + + assert_equal true, lookahead.selects?(:find_bird_species, arguments: arguments) + end + + it 'returns true for selection that is duplicated across fragments' do + doc = GraphQL.parse <<-GRAPHQL + query { + ... on Query { + ...MoreFields + } + } + + fragment MoreFields on Query { + findBirdSpecies(byName: "Laughing Gull") { + name + } + findBirdSpecies(byName: "Laughing Gull") { + ...EvenMoreFields + } + } + + fragment EvenMoreFields on BirdSpecies { + similarSpecies { + likesWater: isWaterfowl + } + } + GRAPHQL + + lookahead = query(doc).lookahead + assert_equal true, lookahead.selects?(:find_bird_species) + + assert_equal true, lookahead.selection(:find_bird_species).selects?(:name) + assert_equal true, lookahead.selection(:find_bird_species).selects?(:similar_species) + + # root_selections = lookahead.selections + # assert_equal [:find_bird_species], root_selections.map(&:name), "Selections are merged" + # assert_equal 2, root_selections.first.ast_nodes.size, "It represents both nodes" + # + # assert_equal [:name, :similar_species], root_selections.first.selections.map(&:name), "Subselections are merged" + end + + # it "avoids merging selections for same field name on distinct types" do + # query = GraphQL::Query.new(LookaheadTest::Schema, <<-GRAPHQL) + # query { + # node(id: "Cardinal") { + # ... on BirdSpecies { + # name + # } + # ... on BirdGenus { + # name + # } + # id + # } + # } + # GRAPHQL + # + # node_lookahead = query.lookahead.selection("node") + # assert_equal( + # [[LookaheadTest::Node, :id], [LookaheadTest::BirdSpecies, :name], [LookaheadTest::BirdGenus, :name]], + # node_lookahead.selections.map { |s| [s.owner_type, s.name] } + # ) + # end + + it "works for missing selections" do + ast_node = document.definitions.first.selections.first + field = LookaheadTest::Query.fields["findBirdSpecies"] + lookahead = GraphQL::Execution::Lookahead.new(query: query, ast_nodes: [ast_node], field: field) + null_lookahead = lookahead.selection(:genus) + # This is an implementation detail, but I want to make sure the test is set up right + assert_instance_of GraphQL::Execution::Lookahead::NullLookahead, null_lookahead + assert_equal [], null_lookahead.selections + end + + it "returns true for fields enabled by directives" do + document = GraphQL.parse <<-GRAPHQL + query($skipName: Boolean!, $includeGenus: Boolean!){ + findBirdSpecies(byName: "Cardinal") { + id + name @skip(if: $skipName) + genus @include(if: $includeGenus) + } + } + GRAPHQL + query = GraphQL::Query.new(LookaheadTest::Schema, document: document, + variables: { skipName: false, includeGenus: true }) + lookahead = query.lookahead.selection("findBirdSpecies") + assert_equal true, lookahead.selects?(:name) + assert_equal true, lookahead.selects?(:genus) + end + + it "returns false for fields disabled by directive" do + document = GraphQL.parse <<-GRAPHQL + query($skipName: Boolean!, $includeGenus: Boolean!){ + findBirdSpecies(byName: "Cardinal") { + id + name @skip(if: $skipName) + genus @include(if: $includeGenus) + } + } + GRAPHQL + query = GraphQL::Query.new(LookaheadTest::Schema, document: document, + variables: { skipName: true, includeGenus: false }) + lookahead = query.lookahead.selection("findBirdSpecies") + assert_equal true, lookahead.selects?(:id) + assert_equal false, lookahead.selects?(:name) + assert_equal false, lookahead.selects?(:genus) + end + + describe "fields on interfaces" do + let(:document) { + GraphQL.parse <<-GRAPHQL + query { + node(id: "Cardinal") { + id + ... on BirdSpecies { + name + } + ...Other + } + } + fragment Other on BirdGenus { + latinName + } + GRAPHQL + } + + it "returns true for fields on direct object types" do + node_lookahead = query.lookahead.selection("node") + assert_equal true, node_lookahead.selects?(:id) + end + + it "returns true for fields on interface types" do + node_lookahead = query.lookahead.selection("node") + assert_equal true, node_lookahead.selects?(:name) + end + + it "returns true for fields on interface types through fragments" do + node_lookahead = query.lookahead.selection("node") + assert_equal true, node_lookahead.selects?(:latin_name) + end + end + end end