require_relative 'tester' require_relative 'hash_methods' require_relative 'xpath_not_found' require 'json' require 'nori' module Soaspec # Wraps around Savon client defining default values dependent on the soap request class RestHandler < Tester # Savon client used to make SOAP calls attr_accessor :client # SOAP Operation to use by default attr_accessor :operation # Options to log xml request and response def logging_options { # See request and response. (Put this in traffic file) } end # Default Savon options. See https://github.com/rest-client/rest-client for details # @return [Hash] Default Savon options for all BasicSoapHandler def default_options { # method: :get # headers: { content_type: 'text/plain' } } end # Override in class def base_url '' end # Add values to here when extending this class to have default REST options. # See rest client resource for details # @return [Hash] Options adding to & overriding defaults def rest_resource_options { } end # Setup object to handle communicating with a particular SOAP WSDL # @param [Hash] specific_options Options defining SOAP request. WSDL, authentication def initialize(name, specific_options = {}) options = default_options.merge logging_options options.merge! rest_resource_options options.merge!(specific_options) @resource = RestClient::Resource.new(base_url, options) # @resource[url_extension].get super end def name(name) @test_values = {} @test_name = name self end def override(request_parameters) @test_values = request_parameters self end # Used in together with Exchange request that passes such override parameters def make_request(override_parameters) test_values = override_parameters test_values[:params] ||= {} test_values[:suburl] = test_values[:suburl].to_s if test_values[:suburl] response = case test_values[:method] when :post if test_values[:suburl] @resource[test_values[:suburl]].send(test_values[:method].to_s, test_values[:payload], test_values[:params]) else @resource.send(test_values[:method].to_s, test_values[:payload], test_values[:params]) end else if test_values[:suburl] @resource[test_values[:suburl]].send(test_values[:method].to_s, test_values[:params]) else @resource.send(test_values[:method].to_s, test_values[:params]) end end Soaspec::SpecLogger.add_to(response) response end def include_in_body?(response, expected) response.body.include? expected end # Convert XML or JSON response into a Hash def extract_hash(response) raise "Empty Body. Can't assert on it" if response.body.empty? type = case response.body[0] when '<' :xml when '{' :json else :unknown end case type when :json JSON.parse(response.body).transform_keys_to_symbols when :xml parser = Nori.new(:convert_tags_to => lambda { |tag| tag.snakecase.to_sym }) parser.parse(response.body) else raise "Neither XML nor JSON detected. It is #{type}. Don't know how to parse It is #{response.body}" end end def include_value?(response, expected) extract_hash(response).include_value? expected end def status_code_for(response) response.code end # Override this to specify elements that must be present in the response # Will be used in 'success_scenarios' shared examples # @return [Array] Array of symbols specifying element names def mandatory_elements [] end # Override this to specify xpath results that must be present in the response # Will be used in 'success_scenarios' shared examples # @return [Hash] Hash of 'xpath' => 'expected value' pairs def mandatory_xpath_values {} end # Attributes set at the root XML element of SOAP request def root_attributes nil end # Returns the value at the provided xpath def xpath_value_for(param) result = if Soaspec::Environment.strip_namespaces? && !param[:xpath].include?(':') temp_doc = param[:exchange].response.doc temp_doc.remove_namespaces! temp_doc.xpath(param[:xpath]).first else puts 'no strip' + param[:xpath] param[:exchange].response.xpath(param[:xpath]).first end raise NoElementAtXpath, "No value at Xpath '#{param[:xpath]}'" unless result result.inner_text end def value_from_path(exchange, path) path = '//' + path if path[0] != '/' xpath_value_for(exchange: exchange, xpath: path) end end end