Question

I'm using active model serializers to render JSON responses from a rails controller.

I have a controller action like this:

def show
  @foo = Foo.find(params[:id])
  if @foo.user == current_user
    render json: @foo, serializer: FooSerializer
  else
    render json: @foo, serializer: TrimmedFooSerializer
  end
end

I want to be able to test which serializer has been used in my Rspec controller tests. Is it possible to get a reference to the serializer from the tests?

UPDATE:

I don't think this a correct use of the serializer. I now have logic in the serializer itself to conditionally include attributes. The controller shouldn't really care about which serializer to use.

Was it helpful?

Solution 2

You can try this. I am assuming that you are using factory_girl. You can write the other test by returning a different user for current_user

describe "show" do
  it "should use FooSerializer to serialize if the logged in user is the same as params user" do
    user = FactoryGirl.create(:user)
    controller.stub(:current_user).and_return(user)
    FooSerializer.any_instance.should_receive(:to_json).and_return("{\"key\": \"value\"")
    get :show, :id => user.id
    response.should be_success
  end
end

OTHER TIPS

It has been a while since anyone replied but in case future googlers find this, I like the following approach:

RSpec::Matchers.define :serialize_object do |object|
  match do |response|
    @serializer_klass.new(object).to_json == response.body
  end

  chain :with do |serializer_klass|
    @serializer_klass = serializer_klass
  end
end

Then in your tests you can do:

expect(response).to serialize_object(claim).with(ClaimSerializer)

Note that I didn't call the matcher 'serialize' because shoulda already defines a matcher of that name.

To elaborate further on Dan Draper's answer, I found that when using the JsonApi adapter, this is the way to go:

RSpec::Matchers.define :serialize_resource do |object|
  match do |response|
    serialized_json(object) == response.body
  end

  chain :with do |serializer_klass|
    @serializer_klass = serializer_klass
  end

  failure_message do |response|
    "expected response body #{serialized_json(object)}, got #{response.body}"
  end

  def serialized_json(object)
    serializer = @serializer_klass.new(object)
    adapted = ActiveModelSerializers::Adapter::JsonApi.new(serializer)
    adapted.serializable_hash.to_json
  end
end

I took what Knightstick did above and improved it a little bit, like for instance, the error message and by adding ability to handle both single resource or a resources collection (I'm using the active_model_serializers gem, version 0.10.0).

RSpec::Matchers.define :serialize_resource do |resource|
  match do |response|
    serialized_json(resource) == response.body
  end

  chain :with do |serializer_klass|
    @serializer_klass = serializer_klass
  end

  failure_message do |response|
    "expected response body #{serialized_json(resource).inspect}, got #{response.body.inspect}"
  end

  def serialized_json(resource)
    options = if resource.is_a?(Array)
                { each_serializer: @serializer_klass }
              else
                { serializer: @serializer_klass }
              end

    serializable = ActiveModelSerializers::SerializableResource.new(resource, options)
    serializable.serializable_hash.to_json
  end
end
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top