Rspec Testing: Coverage for controllers which accept api requests from another server not working

439 views Asked by At

Attempting to write Rspec tests for a controller which accepts api requests from another server/service.

The code below accepts a request launched from another service for an authenticated user in the form /servers/users/some/create (post request)

    module Servers
      module Users
        class SomeController < ::Servers::Users::BaseController
    
          def create
            some_service.create!
            render json: {status: 'ok'}
          end
         end

         def some_service
          if current_user.randommodel.nil?
           @some_service ||= ::SomeService.new(current_user)
         end

randommodel is embedded within the user class and by default does not exist. Some_Service is responsible for creating this randommodel

class SetupMfaService
  attr_accessor :current_user

  def initialize(current_user)
   @current_user = current_user
  end

 def create! 
  current_user.randommodel = randommodel.new
  current_user.randommodel.save!
 end

This service class has been fully covered with tests and works as expected

SomeService has been fully covered with tests and works completely fine. (It works). However when I attempt to test this method through doing:

require 'rails_helper'
require 'requests/servers/servers_api_context'

RSpec.describe '::Servers::Users::SomeController' do
  include_context "Servers API"

  let!(:user) { Fabricate(:user, { clear_password: password }) }
  let(:request_auth_data) do
    {
      user_id: user.id,
      account_id: user.account_id,
      role: ''
    }
  end

  let(:source_server) { 'web_application' }
  let(:endpoint) { 'localhost' }


  context 'create' do
    subject do
      servers_api_post '/servers/users/some/create'
    end

    it 'returns a 200' do
      response = subject
      expect(response.status).to be(200)
    end

    it 'returns the expected JSON data' do
      response = subject
      expect(response.data).to eql({})
    end

  end
end

Tests are failing with no method error 'somemodel' for nil:NilClass which means to me it is not able to detect the presence of current_user (Which is available in the base controller which my controller inherits from as attr_reader :current_user. There also exists a decoded_payload object which allows us to read the parameters present in the requests handled which contains the user id which I've tried to do a look up for in the controller below despite the fact this process is done in the BaseController that this controller inherits from too. Which leads me to the conclusion the way in which I am writing the test is wrong. How can I explicit the current user parameter in the rspec test for this controller file? ~

Logging in for requests is handled in BaseController where it is inherited down into my SomeController

  def authenticate
    @jwt = case request_source
           when 'web_application'
             ::Servers::WebApplication::JwtAuthService.new(endpoint).decrypt_and_verify(jwe)

           else
             raise 'Unknown request source'
           end

    @current_user = User.find(decoded_payload[:user_id])
    @current_account = current_user&.account
    raise ::Api::Error::AccountNotFound.new if current_account.blank?
  end
1

There are 1 answers

0
Schwern On

Assuming that by somemodel you mean current_user.randommodel.nil?, then your tests are not logged in. The tests declare request_auth_data but don't appear to do anything with it.

I can't tell you how to login, just that your tests must do it.

Also your tests reveal a bug in your controller. If a login is required the API should have responded with 401 Unauthorized, not an exception. Often this is handled by inheriting from a controller base class which requires and handles authorization.