How to check for a JSON response using RSpec?

后端 未结 14 1277
谎友^
谎友^ 2020-11-29 16:03

I have the following code in my controller:

format.json { render :json => { 
        :flashcard  => @flashcard,
        :lesson     => @lesson,
             


        
相关标签:
14条回答
  • 2020-11-29 16:28

    Building off of Kevin Trowbridge's answer

    response.header['Content-Type'].should include 'application/json'
    
    0 讨论(0)
  • 2020-11-29 16:29

    You can examine the response object and verify that it contains the expected value:

    @expected = { 
            :flashcard  => @flashcard,
            :lesson     => @lesson,
            :success    => true
    }.to_json
    get :action # replace with action name / params as necessary
    response.body.should == @expected
    

    EDIT

    Changing this to a post makes it a bit trickier. Here's a way to handle it:

     it "responds with JSON" do
        my_model = stub_model(MyModel,:save=>true)
        MyModel.stub(:new).with({'these' => 'params'}) { my_model }
        post :create, :my_model => {'these' => 'params'}, :format => :json
        response.body.should == my_model.to_json
      end
    

    Note that mock_model will not respond to to_json, so either stub_model or a real model instance is needed.

    0 讨论(0)
  • 2020-11-29 16:29

    You could look into the 'Content-Type' header to see that it is correct?

    response.header['Content-Type'].should include 'text/javascript'
    
    0 讨论(0)
  • 2020-11-29 16:32

    You can also define a helper function inside spec/support/

    module ApiHelpers
      def json_body
        JSON.parse(response.body)
      end
    end
    
    RSpec.configure do |config| 
      config.include ApiHelpers, type: :request
    end
    

    and use json_body whenever you need to access the JSON response.

    For example, inside your request spec you can use it directly

    context 'when the request contains an authentication header' do
      it 'should return the user info' do
        user  = create(:user)
        get URL, headers: authenticated_header(user)
    
        expect(response).to have_http_status(:ok)
        expect(response.content_type).to eq('application/vnd.api+json')
        expect(json_body["data"]["attributes"]["email"]).to eq(user.email)
        expect(json_body["data"]["attributes"]["name"]).to eq(user.name)
      end
    end
    
    0 讨论(0)
  • 2020-11-29 16:32

    A lot of the above answers are a bit out of date, so this is a quick summary for a more recent version of RSpec (3.8+). This solution raises no warnings from rubocop-rspec and is inline with rspec best practices:

    A successful JSON response is identified by two things:

    1. The content type of the response is application/json
    2. The body of the response can be parsed without errors

    Assuming that the response object is the anonymous subject of the test, both of the above conditions can be validate using Rspec's built in matchers:

    context 'when response is received' do
      subject { response }
    
      # check for a successful JSON response
      it { is_expected.to have_attributes(content_type: include('application/json')) }
      it { is_expected.to have_attributes(body: satisfy { |v| JSON.parse(v) }) }
    
      # validates OP's condition
      it { is_expected.to satisfy { |v| JSON.parse(v.body).key?('success') }
      it { is_expected.to satisfy { |v| JSON.parse(v.body)['success'] == true }
    end
    

    If you're prepared to name your subject then the above tests can be simplified further:

    context 'when response is received' do
      subject(:response) { response }
    
      it 'responds with a valid content type' do
        expect(response.content_type).to include('application/json')
      end
    
      it 'responds with a valid json object' do
        expect { JSON.parse(response.body) }.not_to raise_error
      end
    
      it 'validates OPs condition' do
        expect(JSON.parse(response.body, symoblize_names: true))
          .to include(success: true)
      end
    end
    
    0 讨论(0)
  • 2020-11-29 16:35

    Simple and easy to way to do this.

    # set some variable on success like :success => true in your controller
    controller.rb
    render :json => {:success => true, :data => data} # on success
    
    spec_controller.rb
    parse_json = JSON(response.body)
    parse_json["success"].should == true
    
    0 讨论(0)
提交回复
热议问题