require_relative 'base_matcher' require_relative './have_a_field_matchers/of_type' require_relative './have_a_field_matchers/with_property' require_relative './have_a_field_matchers/with_metadata' require_relative './have_a_field_matchers/with_hash_key' module RSpec module GraphqlMatchers class HaveAField < BaseMatcher DESCRIPTIONS = { type: 'of type `%s`', property: 'reading from the `%s` property', hash_key: 'reading from the `%s` hash_key', metadata: 'with metadata `%s`' }.freeze def initialize(expected_field_name, fields = :fields) @expected_field_name = expected_field_name.to_s @fields = fields.to_sym @expectations = [] @descriptions = [] end def matches?(graph_object) @graph_object = graph_object @actual_field = field_collection[@expected_field_name] return false if @actual_field.nil? @results = @expectations.select do |matcher| !matcher.matches?(@actual_field) end @results.empty? end def that_returns(expected_field_type) @expectations << HaveAFieldMatchers::OfType.new(expected_field_type) self end alias returning that_returns alias of_type that_returns def with_property(expected_property_name) @expectations << HaveAFieldMatchers::WithProperty.new(expected_property_name) self end def with_hash_key(expected_hash_key) @expectations << HaveAFieldMatchers::WithHashKey.new(expected_hash_key) self end def with_metadata(expected_metadata) @expectations << HaveAFieldMatchers::WithMetadata.new(expected_metadata) self end def failure_message base_msg = "expected #{member_name(@graph_object)} " \ "to define field `#{@expected_field_name}`" \ return "#{base_msg} #{descriptions.join(', ')}" if @actual_field "#{base_msg} but no field was found with that name" end def description ["define field `#{@expected_field_name}`"].concat(descriptions).join(', ') end private def descriptions @results.map(&:description) end def field_collection if @graph_object.respond_to?(@fields) @graph_object.public_send(@fields) else raise "Invalid object #{@graph_object} provided to #{matcher_name} " \ 'matcher. It does not seem to be a valid GraphQL object type.' end end def matcher_name case @fields when :fields then 'have_a_field' when :input_fields then 'have_an_input_field' when :return_fields then 'have_a_return_field' end end end end end