rspecdeviserspec-railsactioncable

How to stub env['warden'].user for ApplicationCable::Connection tests with rspec


Rails 5.2 I have the following ApplicationCable::Connection ruby file:

module ApplicationCable
  class Connection < ActionCable::Connection::Base

    identified_by :current_user

    def connect
      self.current_user = find_verified_user
    end

    private

    def find_verified_user
      if verified_user = env['warden'].user
        verified_user
      else
        message = "The user is not found. Connection rejected."
        logger.add_tags 'ActionCable', message  
        self.transmit error: message 
        reject_unauthorized_connection
      end
    end
  end
end

I want to test this setup and and using the following RSpec test:

require 'rails_helper.rb'

RSpec.describe ApplicationCable::Connection, type: :channel do

  it "successfully connects" do
    connect "/cable", headers: { "X-USER-ID" => 325 }
    expect(connection.user_id).to eq 325
  end
end

Which fails with:

Failure/Error: if verified_user = env['warden'].user

NoMethodError: undefined method `[]' for nil:NilClass

So I want to stub out the env['warden'].user code and return an id of 325. I tried the following:

allow(env['warden']).to receive(:user).and_return(325)

But that produced the following error:

undefined local variable or methodenv'

How can I test this class?


Solution

  • Try this:

    require 'rails_helper.rb'
    
    RSpec.describe ApplicationCable::Connection, type: :channel do
    
      let(:user)    { instance_double(User, id: 325) }
      let(:env)     { instance_double('env') }
    
      context 'with a verified user' do
    
        let(:warden)  { instance_double('warden', user: user) } 
    
        before do
          allow_any_instance_of(ApplicationCable::Connection).to receive(:env).and_return(env)
          allow(env).to receive(:[]).with('warden').and_return(warden)
        end
    
        it "successfully connects" do
          connect "/cable", headers: { "X-USER-ID" => 325 }
          expect(connect.current_user.id).to eq 325
        end
    
      end
    
      context 'without a verified user' do
    
        let(:warden)  { instance_double('warden', user: nil) }
    
        before do
          allow_any_instance_of(ApplicationCable::Connection).to receive(:env).and_return(env)
          allow(env).to receive(:[]).with('warden').and_return(warden)
        end
    
        it "rejects connection" do
          expect { connect "/cable" }.to have_rejected_connection
        end
    
      end
    end