# frozen_string_literal: true require_relative 'core_ext/hash' require_relative 'errors' # Whether response has any element with the provided value RSpec::Matchers.define :contain_value do |expected| match do |actual| expect(actual.exchange_handler.include_value?(actual.response, expected)).to be true end failure_message do |actual| "expected that #{actual.exchange_handler.response_body(actual.response, format: :hash)} would contain value #{expected}" end end # Whether substring exists in body of response (more general than above) RSpec::Matchers.define :include_in_body do |expected| match do |actual| expect(actual.exchange_handler.include_in_body?(actual.response, expected)).to be true end failure_message do |actual| "expected that #{actual.exchange_handler.response_body(actual.response, format: :raw)} would contain value #{expected}" end end # Whether an element exists at expected xpath RSpec::Matchers.define :have_element_at_path do |xpath| match do |object| # Object like `response` returns the Exchange object from which a path can be obtained exchange = object.respond_to?(:exchange) ? object.exchange : object expect { exchange[xpath] }.to_not raise_error # Error will be raised if Path returns no value end # TODO: Would be better to print failure message failure_message do |object| # Object like `response` returns the Exchange object from which a path can be obtained exchange = object.respond_to?(:exchange) ? object.exchange : object "expected that #{exchange.exchange_handler.response_body(exchange.response, format: :raw)} would have element at path '#{xpath}'" end end RSpec::Matchers.alias_matcher :have_element_at_xpath, :have_element_at_path RSpec::Matchers.alias_matcher :contain_key, :have_element_at_path # Whether an element at xpath (defined by key) has value (defined by value). # @param [Hash] expected_hash Xpath => Value pair (e.g. '//xmlns:GetWeatherResult' => 'Data Not Found') RSpec::Matchers.define :have_xpath_value do |expected_hash| match do |object| # Object like `response` returns the Exchange object from which a path can be obtained exchange = object.respond_to?(:exchange) ? object.exchange : object expected_hash = Hash[*expected_hash.flatten] if expected_hash.is_a?(Array) # For some reason Array was occuring expect(exchange[expected_hash.keys.first]).to eq expected_hash.values.first end failure_message do |actual| "expected that xpath '#{expected_hash.keys.first}' has value '#{expected_hash.values.first}' but was '#{actual[expected_hash.keys.first]}'" end end RSpec::Matchers.alias_matcher :have_jsonpath_value, :have_xpath_value RSpec::Matchers.define :be_found do match do |exchange| expect(exchange.exchange_handler.found?(exchange.response)).to be true end failure_message do |exchange| "expected result #{exchange.response} to be found. Status code is #{exchange.response.code}" end end # Whether response has successful status code and correct mandatory elements and values RSpec::Matchers.define :be_successful do # @param [Exchange, RestClient::Response] actual Object that returns Exchange or is Exchange # @return [Exchange] Exchange to use def exchange_from(actual) actual.respond_to?(:exchange) ? actual.exchange : actual end # @param [Exchange, RestClient::Response] exchange Object that returns Exchange or is Exchange # @return [Array] List of errors when checking Exchange response is successful def collect_errors(exchange) failure_list = [] failure_list << "#{exchange.status_code} not valid status code" unless exchange.successful_status_code? exchange.exchange_handler.expected_mandatory_elements.each do |mandatory_element_path| begin exchange[mandatory_element_path] rescue NoElementAtPath => e failure_list << e.message end end exchange.exchange_handler.expected_mandatory_xpath_values.each do |path, value| failure_list << "Expected value at xpath '#{path}' to be '#{value}' but was '#{exchange[path]}'" unless exchange[path] == value end exchange.exchange_handler.expected_mandatory_json_values.each do |path, value| failure_list << "Expected value at json '#{path}' to be '#{value}' but was '#{exchange[path]}'" unless exchange[path] == value end failure_list end match do |actual| exchange = exchange_from actual failure_list = collect_errors exchange raise failure_list.to_s unless failure_list.empty? true end match_when_negated do |actual| exchange = exchange_from actual failure_list = collect_errors exchange raise "Expected failure. Status code is #{exchange.status_code}" if failure_list.empty? true end end