# frozen_string_literal: true require 'rspec/roda/version' require 'rspec' require 'rspec/its' require 'rack/test' require 'dry/inflector' require 'rspec/mocks/standalone' require 'rspec/matchers' module RSpec # Module containing different contexts for Roda. module Roda Inflector = Dry::Inflector.new # Module containing helpers for specifying Roda apps. module App include Rack::Test::Methods # @return [Class(Roda)] def roda_class respond_to?(:_roda_class) ? _roda_class : described_class end # Rack-, and Rack::Test-compliant Roda app # @return [#call] def app roda_class.app.freeze end end # Module containing helpers for specifying Roda plugins. module Plugin # Class interface for plugin specs. module ClassInterface # @param [Module] child def extended(child) super(child) roda end # @param [Symbol] plugin # @param [Proc] block def roda(plugin = metadata[:name], &block) let(:_roda_class) do route_block = self.route_block self.class.const_set(:TestApp, Class.new(::Roda) do include ::RSpec::Matchers include ::RSpec::Mocks::ExampleMethods plugin plugin instance_exec(&block) if block route { |r| instance_exec(r, &route_block) } if route_block end) end end # @param [Proc] block def route(&block) let(:route_block) { block } roda # re-initiate app end private # @return [Symbol] def plugin_name @plugin_name ||= metadata[:name] || Inflector.underscore( Inflector.demodulize(described_class.name) ) end end end end end RSpec.shared_context 'Roda app', roda: :app do include RSpec::Roda::App let(:roda_instance) { roda_class.new(env) } let(:env) { {} } end RSpec.shared_context 'Roda plugin', roda: :plugin do extend RSpec::Roda::Plugin::ClassInterface include_context 'Roda app' let(:route_block) { proc { |r| } } let(:plugin) { described_class } it { expect(plugin).to be_a Module } end RSpec::Mocks::Syntax.enable_should