Search code examples
ruby-on-railsjsonrubyrspecactive-model-serializers

Active Model Serializers deserialization invalid document with RSpec


I'm trying to setup RSpec tests for my Rails 5 API server. The server uses active_model_serializers (0.10.5) with the JSON API adapter.

From what I can tell, the server is serving valid JSON:

{
  "data": [{
    "id": "1",
    "type": "categories",
    "attributes": {
      "name": "Language"
    }
  }, {
    "id": "2",
    "type": "categories",
    "attributes": {
      "name": "Ruby"
    }
  }, {
    "id": "3",
    "type": "categories",
    "attributes": {
      "name": "HTML"
    }
  }]
}

Here is my setup:

app/controllers/categories_controller.rb

  def index
    @categories = Category.all

    render json: @categories
  end

app/serializers/category_serializer.rb

class CategorySerializer < ActiveModel::Serializer
  attributes :id, :name
end

spec/requests/categories_spec.rb

  describe 'GET /categories' do
    before do
      @category1 = FactoryGirl.create(:category)
      @category2 = FactoryGirl.create(:category)
      get '/categories'
      json = ActiveModelSerializers::Deserialization.jsonapi_parse!(response.body)
      @category_ids = json.collect { |category| category['id'] }
    end

    it 'returns all resources in the response body' do
      expect(@category_ids).to eq([@category1.id, @category2.id])
    end

    it 'returns HTTP status ok' do
      expect(response).to have_http_status(:ok)
    end
  end

Following is the error I get when running bundle exec spec:

ActiveModelSerializers::Adapter::JsonApi::Deserialization::InvalidDocument:
       Invalid payload (Expected hash): {"data":
[{"id":"55","type":"categories","attributes":{"name":"feed"}},
{"id":"56","type":"categories","attributes":{"name":"bus"}}]}

What am I missing to get the deserializer working?


Solution

  • You don't need to use the ActiveModel deserializer in this context. For your tests, just do something like this:

      parsed_response = JSON.parse(response.body)
      expect(parsed_response['data'].size).to eq(2)
      expect(parsed_response['data'].map { |category| category['id'].to_i })
        .to eq(Category.all.map(&:id))
      expect(response.status).to eq(200)