require_relative 'tester' require_relative 'hash_methods' module Soaspec # Wraps around Savon client defining default values dependent on the soap request class BasicSoapHandler < 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 { log: true, # See request and response. (Put this in traffic file) log_level: :debug, logger: Soaspec::SpecLogger.create, pretty_print_xml: true # Prints XML pretty } end # Default Savon options. See http://savonrb.com/version2/globals.html for details # @return [Hash] Default Savon options for all BasicSoapHandler def default_options { ssl_verify_mode: :none, # Easier for testing. Not so secure follow_redirects: true, # Necessary for many API calls soap_version: 2, # use SOAP 1.2. You will get 415 error if this is incorrect raise_errors: false # HTTP errors not cause failure as often negative test scenarios expect not 200 response # Things could go wrong if not set properly # env_namespace: :soap, # Change environment namespace # namespace_identifier: :tst, # Change namespace element # element_form_default: :qualified # Populate each element with namespace # namespace: 'http://Extended_namespace.xsd' change root namespace # basic_auth: 'user', 'password' } end # Add values to here when extending this class to have default Savon options. # See http://savonrb.com/version2/globals.html for details # @return [Hash] Savon options adding to & overriding defaults def savon_options { } end # Setup object to handle communicating with a particular SOAP WSDL # @param [Hash] specific_options Options defining SOAP request. WSDL, authentication, see http://savonrb.com/version2/globals.html for list of options def initialize(name, specific_options = {}) options = default_options.merge logging_options options.merge! savon_options options.merge!(specific_options) @client = Savon.client(options) 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 # Used in Erb # Erb parses template file, executing Ruby code in `<% %>` blocks to work out final request test_values = test_values.transform_keys_to_symbols unless Soaspec::Environment.always_use_keys? if @request_option == :template request_body = File.read('template/' + template_name + '.xml') render_body = ERB.new(request_body).result(binding) @client.call(operation, xml: render_body) # Call the SOAP operation with the request XML provided elsif @request_option == :hash @client.call(operation, message: @default_hash.merge(test_values), attributes: root_attributes) end end def default_hash=(hash) @request_option = :hash @default_hash = Soaspec::Environment.always_use_keys? ? hash.transform_keys_to_symbols : hash end def status_code_for(response) response.http.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 def xpath_value_for(param) result = param[:exchange].response.xpath(param[:xpath]).first raise 'No value at 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