Mike
Mike

Reputation: 296

Rails rspec controller test is returning an unknown hash

I have a very simple controller that looks like this.

module Veterinarians
  module Dictionaries
    class SpecialitiesController < ApplicationController
      respond_to :json

      skip_before_action :check_current_vet, only: %i( index )

      def index
        @specialities = Veterinarians::Speciality.all
        respond_with(@specialities)
      end
    end
  end
end

I have an rspec controller test that looks like this.

require 'rails_helper'

Rails.describe Veterinarians::Dictionaries::SpecialitiesController, type: :controller do
  # Not returning a response body in JSON when testing RSPEC (https://github.com/rails/jbuilder/issues/32)
  render_views true

  routes { Veterinarians::Engine.routes }

  let(:user) { double :user, id: 123 }
  before { sign_in(user) }

  context '#index' do
    let(:speciality) { double :speciality, id: :some_id, value: :some_val }

    before { allow(Veterinarians::Speciality).to receive(:all).and_return [speciality] }

    subject { get :index, format: :json }

    it { is_expected.to have_http_status(:ok) }
    it { expect(JSON.parse(subject.body)).to include('id' => 'some_id', 'value' => 'some_val') }
  end
end

The second example fails with this error.

expected [{"__expired" => false, "name" => "speciality"}] to include {"id" => "some_id", "value" => "some_val"}

Any hints as to why this would fail and where the hash with "__expired" is coming from?

I have other tests that are using this same method of testing that are successful.

Upvotes: 0

Views: 449

Answers (3)

Nesha Zoric
Nesha Zoric

Reputation: 6620

You should use factories for creating your test data. Two most popular ones are FactoryGirl or FactoryBot.

Example:

FactoryGirl.define do
  factory :user do
    sequence(:email) { |n| "name#{n}@example.com" }
    password 'password'
  end
end

The sequence(:email) will create you a different email for each user. More details can be found here.

Upvotes: 0

Frederick Cheung
Frederick Cheung

Reputation: 84114

Rails winds up calling to_json on the double. You haven't stubbed that method on the double, so the to_json method rails adds to Object is called.

This implementation just dumps the instance variables of the object, which in this case is the internal state of the test double.

You could stub to_json on the double, although your spec wouldn't be testing a whole lot at that point.

Upvotes: 0

Andy Waite
Andy Waite

Reputation: 11076

I suspect this is coming from RSpec's internal representation of a double:

https://github.com/rspec/rspec-mocks/blob/master/lib/rspec/mocks/test_double.rb#L10

RSpec's doubles sometimes don't work well alongside Rails. Try instantiating a real Speciality instance, or using something like FactoryGirl to do so.

Upvotes: 1

Related Questions