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
Assuming that by
somemodelyou meancurrent_user.randommodel.nil?, then your tests are not logged in. The tests declarerequest_auth_databut 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.