require 'bearcat' # Bearcat RSpec Helpers # Can be included in your spec_helper.rb file by using: # - `require 'bearcat/spec_helpers'` # And # - `config.include Bearcat::SpecHelpers` # This helper requires `gem 'method_source'` in your test group module Bearcat::SpecHelpers extend ActiveSupport::Concern SOURCE_REGEX = /(?get|post|delete|put)\((?\\?('|"))(?.*)\k/ # Helper method to Stub Bearcat requests. # Automagically parses the Bearcat method source to determine the correct URL to stub. # Accepts optional keyword parameters to interpolate specific values into the URL. # Returns a mostly-normal Webmock stub (:to_return has been overridden to allow :body to be set to a Hash) def stub_bearcat(endpoint, prefix: nil, method: :auto, **kwargs) cfg = _bearcat_resolve_config(endpoint, kwargs, method: method) url = Regexp.escape(_bearcat_resolve_prefix(prefix)) + cfg[:url] url += "?" if url.end_with?('/') stub = stub_request(cfg[:method], Regexp.new(url)) # Override the to_return method to accept a Hash as body: stub.define_singleton_method(:to_return, ->(*resps, &blk) { if blk super do |*args| resp = blk.call(*args) resp[:headers] ||= {} resp[:headers]["Content-Type"] ||= "application/json" resp[:body] = resp[:body].to_json resp end else resps.map do |resp| resp[:headers] ||= {} resp[:headers]["Content-Type"] ||= "application/json" resp[:body] = resp[:body].to_json end super(*resps) end }) stub end private def _bearcat_resolve_config(endpoint, url_context, method: :auto) case endpoint when Symbol if (cfg = Bearcat::Client.registered_endpoints[endpoint]).present? bits = [] url = cfg[:url] lend = 0 url.scan(/:(?\w+)/) do |key| m = Regexp.last_match between = url[lend..m.begin(0)-1] bits << between if between.present? && (m.begin(0) > lend) lend = m.end(0) bits << (url_context[m[:key].to_sym] || /[\w:]+/) end between = url[lend..-1] bits << between if between.present? url = bits.map do |bit| next bit.source if bit.is_a?(Regexp) bit = bit.canvas_id if bit.respond_to?(:canvas_id) Regexp.escape(bit.to_s) end.join { method: method == :auto ? cfg[:method] : method, url: url } else ruby_method = Bearcat::Client.instance_method(endpoint) match = SOURCE_REGEX.match(ruby_method.source) bits = [] url = match[:url].gsub(/\/$/, '') lend = 0 url.scan(/#\{(?.*?)\}/) do |key| m = Regexp.last_match between = url[lend..m.begin(0)-1] bits << between if between.present? && (m.begin(0) > lend) lend = m.end(0) bits << (url_context[m[:key].to_sym] || /[\w:]+/) end between = url[lend..-1] bits << between if between.present? url = bits.map do |bit| next bit.source if bit.is_a?(Regexp) bit = bit.canvas_id if bit.respond_to?(:canvas_id) Regexp.escape(bit.to_s) end.join { method: method == :auto ? (match ? match[:method].to_sym : :get) : method, url: url } end when String raise "Cannot use method :auto when passing string endpoint" if method == :auto { method: method, url: Regexp.escape(endpoint) } when Regexp raise "Cannot use method :auto when passing regex endpoint" if method == :auto { method: method, url: Regexp.escape(endpoint) } end end def _bearcat_resolve_prefix(prefix) if prefix == true prefix = canvas_api_client if defined? canvas_api_client prefix = canvas_sync_client if defined? canvas_sync_client end prefix = case prefix when nil '' when false '' when true raise "stub_bearcat() prefix: set to true, but neither canvas_(sync|api)_client are defined" when Bearcat::Client prefix.prefix when String prefix end end end