Search code examples
ruby-on-railsrubyrspecrspec-rails

RSpec check if method has been called


I have an AccountsController and a destroy action. I want to test if the account is being deleted and if the subscription is being canceled.

AccountsController

def destroy
  Current.account.subscription&.cancel_now!
  Current.account.destroy
end

RSpec

describe "#destroy" do
  let(:account) { create(:account) }
  
  it "deletes the account and cancels the subscription" do
    allow(account).to receive(:subscription)
    expect do
      delete accounts_path
    end.to change(Account, :count).by(-1)

    expect(account.subscription).to have_received(:cancel_now!)
  end
end

But the above test does not pass. It says,

(nil).cancel_now!
expected: 1 time with any arguments
received: 0 times with any arguments

Because the account.subscription returns nil it is showing this. How do I fix this test?


Solution

  • You need to replace the account entity in the context of the controller to the account from the test

    It could be

    describe "#destroy" do
      let(:account) { create(:account) }
      
      it "deletes the account and cancels the subscription" do
        allow(Current).to receive(:account).and_return(account)
        # if the subscription does not exist in the context of the account  
        # then you should stub or create it...
        expect do
          delete accounts_path
        end.to change(Account, :count).by(-1)
    
        expect(account.subscription).to have_received(:cancel_now!)
      end
    end
    

    Regarding subscription

    expect(account).to receive(:subscription).and_return(instance_double(Subscription))
    # or
    receive(:subscription).and_return(double('some subscription'))
    # or
    create(:subscription, account: account)
    # or
    account.subscription = create(:subscription)
    # or other options ...