Home > database >  Rspec - Stub/allow_any_instance_of included module methods is not working
Rspec - Stub/allow_any_instance_of included module methods is not working

Time:04-09

I've been trying to stub a private module method for the whole day now but with not progress.

Here is a snippet of my application controller class

class ApplicationController < ActionController::Base
   include Cesid::Application
end

Cesid > Application.rb

module Cesid
  module Application
    extend ActiveSupport::Concern

    included do
      before_action :track_marketing_suite_cesid, only: [:new]
    end

    private

    def track_marketing_suite_cesid
      return unless id_token_available?
      ## @cesid_auth = Auth.new(@id_token)
      @cesid_auth = Auth.new(id_token)
      return unless @cesid_auth.present? && @cesid_auth.valid?
      @cesid_admin = Admin.where(email: @cesid_auth.email).first_or_initialize
    end

    def id_token_available?
      ## @id_token.present?
      id_token.present?
    end

    def id_token
      @id_token ||= id_token_param
    end

    def id_token_param
      cookies[:id_token]
    end
  end
end

Now, I'm trying to create a simple unit test for the method

id_token_available?

And I am just trying to set the id_token_param to a random value.

I've tried using this code as stated Is there a way to stub a method of an included module with Rspec?

allow_any_instance_of(Cesid).to receive(:id_token_param).and_return('hello')

but I just get this error

NoMethodError:
   undefined method `allow_any_instance_of' for #<RSpec::ExampleGroups::CesidApplication::CesidAuthorizations::GetCesidApplication:0x00007fa3d200c1c0> Did you mean?  allow_mass_assignment_of

Rspec file

require 'rails_helper'

describe Cesid::Application,  :type => :controller  do
  describe 'cesid application' do
    before do
      allow_any_instance_of(ApplicationController).to receive(:id_token_param).and_return('hello')
    end

    it 'returns true if the id_token is present' do
      expect(Cesid::Application.send('id_token_available?')).to eql(true)
    end
  end
end

Rspec version

3.5.4

This is honestly starting to drive me crazy

CodePudding user response:

I see three issues:

  1. You call allow_any_instance_of in a context in which it is not defined. allow_any_instance_of can be used in before blocks. I need to see your RSpec code to be more specific.

  2. Actually your code is called on the ApplicationController, not on the module, therefore you need to change your stub to

    allow_any_instance_of(ApplicationController).to receive(:id_token_param).and_return('hello')
    
  3. Currently id_token_param will not be called at all, because id_token_available? checks the instance variable and not the return value of the id_token method that calls the id_token_param. Just change the id_token_available? to:

    def id_token_available? id_token.present? end

CodePudding user response:

There's a much better way of going about this test. The type: :controller metadata on your spec gives you an anonymous controller instance to work with. Here's an example of how you could write this to actually test that the before_action from your module is used:

describe Cesid::Application, type: :controller do
  controller(ApplicationController) do
    def new
      render plain: 'Hello'
    end
  end

  describe 'cesid before_action' do
    before(:each) do
      routes.draw { get 'new' => 'anonymous#new' }
      cookies[:id_token] = id_token
      allow(Auth).to receive(:new).with(id_token)
        .and_return(instance_double(Auth, valid?: false))
      get :new
    end

    context 'when id token is available' do
      let(:id_token) { 'hello' }

      it 'sets @cesid_auth' do
        expect(assigns(:cesid_auth)).to be_present
      end
    end

    context 'when id token is unavailable' do
      let(:id_token) { '' }

      it 'does not set @cesid_auth' do
        expect(assigns(:cesid_auth)).to be_nil
      end
    end
  end
end

  • Related