Luis Masuelli Luis Masuelli - 5 months ago 35
Ruby Question

Why is my controller acting different in the rspec execution than in the browser execution?

I have my controller:

class Api::BunknotesController < Api::ApiController
# ... omitted code
def show
@bunknote =
current_user.bunknotes.includes(:person).find(params[:id])

respond_to do |format|
format.html {
render layout: false
}
format.pdf {
render pdf: @bunknote.filename,
template: '/bunknotes/show.pdf',
margin: { top: 5, bottom: 5 }
byebug
}
format.json {
render json: @bunknote.api_json(true)
}
end
end
# ... omitted code
end


In the second format, Wicked PDF is used to render. The rendered template looks like this:

<%= wicked_pdf_stylesheet_link_tag "bunknotes" %>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<div class="page <% if @bunknote.reply %>pagebreak<% end %> bunknote_pdf">
<div class="bn-id">bn<%= @bunknote.id %></div>
<h1>Bunk Note to <%= @bunknote.person ? @bunknote.person.name : @bunknote.writein %> <%= "(#{@bunknote.address})" if @bunknote.address && @bunknote.address.length > 1 %></h1>
<%= render partial: 'details', locals: { :bunknote => @bunknote } %>
</div>
<% if @bunknote.reply %>
<div class="page bunkreply-stationery">
<%=
render partial: '/common/stationery',
locals: {
user_fullname: @bunknote.user.fullname,
org_name: @bunknote.organization.name,
org_id: @bunknote.organization.id,
user_id: @bunknote.user.id,
bunknote_id: "bn#{@bunknote.id}",
barcode_value: "#{has_bunknote = 1}#{@bunknote.id}",
height: "720px",
camper_name: @bunknote.person ? @bunknote.person.name : @bunknote.writein
}
%>
</div>
<% end %>


When I try to hit my controller, I have a template error. The error's nature is like this: Inside my show.pdf.erb template, which is /bunknotes/show.pdf.erb, I am referencing the file 'details'. Since my controller is
Api::BunknotesController
(there is another controller named
BunknotesController
, without prefix, which had a copy of this template in first place), the relative inclusion would try to find the file in /app/views/api/bunknotes/ instead of /app/views/bunknotes.

By trying to hit it in my browser, I get a 500 when trying to render the pdf, and the
byebug
instruction is not reached (as anyone could expect when having any exception out of the special purpose ones in rails like
RecordInvalid
and so). Due to other internals, the generated pdf is corrupt on this scenario (something we will fix later but for now it serves as a good sign that something did not go well).

However a pretty different behavior is triggered when running a test

My test file looks like:

# ... omitted code
describe Api::BunknotesController do
# ... omitted code
it "gets a bunknote (PDF)" do
get :show, {id: bunknote1.id, format: :pdf}
expect(response.status).to be 200
end
# ... omitted code
end
# ... omitted code


When the rspec utility runs this example, A blank pdf (non-corrupt, but totally blank) is generated by the controller, and a 200 response code is returned.

I made this test to succeed for a 200 code if things got well. The test should have failed when the show view misreferenced (for my needs) the inner view. But instead it succeeded, seeming to absorb the error like a diaper, and generating the blank PDF file. I expect that this behave exactly as the browser call, generate the corrupt pdf, returns a 500 code, and fails.

Summary:


  1. Yes, I will fix the path to the included view so it is absolute.

  2. Yes, I will fix the corrupt pdf generation so that no pdf attachment files are ever sent.

  3. The test should not have succeeded as it did. The test is expected to succeed only if the response code is 200. This is right, but the controller produced a 200 in the rspec execution, while returning a 500 in the browser execution.



Why is my controller acting different in the rspec execution than in the browser execution?

I am using:


  • Ruby 2.3.0p0

  • Rails 3.2.22.2

  • RSpec 3.4.1


Answer

By default Rails / RSpec does not render views for controllers in tests. To get the view to render, add a render_views call at the top of the spec like so

describe Api::BunknotesController do
  render_views
  #
  #
  it "does..." do
  end
end