render_template is not working
raoehtesham03 opened this issue · 12 comments
Ruby version: 2.7.8
Rails version: 6.0.6.1
RSpec version: 4.0
Observed behaviour
While executing the below test cases
expect(response).to render_template(file: "#{Rails.root}/public/errors/link_expired.html")
I am facing this issue.
Failure/Error: expect(response).to render_template(file: "#{Rails.root}/public/errors/link_expired.html")
Expected [] to include "/opt/app/public/errors/link_expired.html".
👋 What version of rspec-rails are you using? There is no publically released rspec 4.0.0 (the highest release of rspec itself is 3.12.x) but rspec-railss current release is 6.1.0 , I would recommend trying to upgrade rspec-rails if you are using version 4.0.x of that.
Closing because we don't support older versions of Rails (current support is the same as Rails itself, 6.1, 7.0 and 7.1) or older versions of rspec-rails.
I tried to upgrade the rspec-rails version to 5.0 but I am still getting the same error. I am stuck in the middle of a project because of this since a very long time. Please help me resolve this. @JonRowe
Please provide a reproducible snippet like https://github.com/rspec/rspec-rails/blob/main/snippets/use_active_record_false.rb
Please provide a reproducible snippet like https://github.com/rspec/rspec-rails/blob/main/snippets/use_active_record_false.rb
@pirj Can you please tell me how to use this ?
I could not understand.
Those are self-contained scripts to reproduce issues like Rails bug templates https://guides.rubyonrails.org/contributing_to_ruby_on_rails.html#create-an-executable-test-case
I wish we had a barebones one with some instructions, but we don’t
@JonRowe I know you closed this but I think this is actually an issue with the latest.
I started a new project recently. I'm running:
rails = 7.1.2ruby = 3.2.2rspec-rails = 6.1.0rspec ~> 3.12
I have this controller test to simulate what @raoehtesham03 was talking about:
(Note: the show_404 doesn't do any logic. My actual code in my project is a before_action that checks for the presence of a particular subdomain, and otherwise renders the 404 file, but I didn't think that mattered for the purpose of highlighting this behavior.)
require "rails_helper"
RSpec.describe ApplicationController, type: :controller do
controller do
before_action :show_404
def index
render plain: "some content"
end
private
def show_404
render file: "public/404.html", status: 404, layout: false
end
end
it "renders the 404 page" do
get :index
expect(response).to have_rendered(file: "public/404.html", layout: false)
expect(response.status).to eq(404)
end
end
Here's the run:
♯ bundle exec rspec spec/controllers/application_controller_spec.rb
ApplicationController
renders the 404 page (FAILED - 1)
Failures:
1) ApplicationController renders the 404 page
Failure/Error: expect(response).to have_rendered(file: "public/404.html", layout: false)
Expected [] to include "public/404.html".
# ./spec/controllers/application_controller_spec.rb:20:in `block (2 levels) in <top (required)>'
Finished in 0.17184 seconds (files took 2 seconds to load)
1 example, 1 failure
Failed examples:
rspec ./spec/controllers/application_controller_spec.rb:18 # ApplicationController renders the 404 page
I'm using have_rendered instead of render_template but it looks like it's an alias anyway.
Also, the render file: "public/404.html", status: 404, layout: false in my project code works just fine when tested in the browser. It just seems the RSpect test doesn't quite work.
Cheers!
What if you set a breakpoint inside show_404, will it stop there?
if you remove the rendered template expectation, will the response status expectation pass?
is it just for templates rendered in action filters?
Is it just for action filters defined inside controller do?
What if you used the assert_template directly, would it work? Do we use it under the hood in our have_rendered matcher?
Hi Phil! Thanks for your questions...
I tried this:
class PagesController < ApplicationController
def index
render file: "public/404.html", status: 404, layout: false
end
end
With this test:
require 'rails_helper'
RSpec.describe PagesController, type: :controller do
it "renders the 404 file" do
get :index
expect(response.not_found?).to be_truthy
end
end
as my baseline for your questions. Note that just testing the status code passes. Result:
# bundle exec rspec spec/controllers/pages_controller_spec.rb
PagesController
renders the 404 file
Finished in 0.14765 seconds (files took 2.08 seconds to load)
1 example, 0 failures
but when I also test the rendered template it fails.
In the test:
expect(response.not_found?).to be_truthy
expect(response).to have_rendered(file: "public/404.html", layout: false)
Result:
♯ bundle exec rspec spec/controllers/pages_controller_spec.rb
PagesController
renders the 404 file (FAILED - 1)
Failures:
1) PagesController renders the 404 file
Failure/Error: expect(response).to have_rendered(file: "public/404.html", layout: false)
Expected [] to include "public/404.html".
# ./spec/controllers/pages_controller_spec.rb:7:in `block (2 levels) in <top (required)>'
What if you set a breakpoint inside show_404, will it stop there?
Yup. I tried that it and works fine. So it's running the before_action. Also in my example above where it's just within a normal controller action (not a before_action) it still hits. So it's not a flow issue.
if you remove the rendered template expectation, will the response status expectation pass?
Yes, as in the example above.
is it just for templates rendered in action filters?
Nope. It seems to be related to render file: "...". Something about it rendering a file not a template is where the bug is.
Is it just for action filters defined inside
controller do?
Nope. See above.
What if you used the assert_template directly, would it work? Do we use it under the hood in our have_rendered matcher?
Fails similarly. In the test:
expect(response.not_found?).to be_truthy
assert_template file: "public/404.html"
With the result:
♯ bundle exec rspec spec/controllers/pages_controller_spec.rb
PagesController
renders the 404 file (FAILED - 1)
Failures:
1) PagesController renders the 404 file
Failure/Error: assert_template file: "public/404.html"
Minitest::Assertion:
Expected [] to include "public/404.html".
So I think it's something specifically about using render file: "some/file" that isn't assertable with render_template or assert_template (or have_rendered, which is just an alias). 🤷
@drsharp Instead of using this
expect(response).to have_rendered(file: "public/404.html", layout: false)
Try Below code snippet.
expect(response).to render_template { "public/404.html" }
@drsharp Instead of using this expect(response).to have_rendered(file: "public/404.html", layout: false)
Try Below code snippet. expect(response).to render_template { "public/404.html" }
@raoehtesham03 thanks for the suggestion. It didn't work, though:
1) PagesController renders the 'index' action as the root path
Failure/Error: expect(response).to render_template { "public/404.html" }
ArgumentError:
wrong number of arguments (given 0, expected 1..2)
It's interesting because assert_template file: "some/file" is very much supported:
https://github.com/rails/rails-controller-testing/blob/c203673f8011a7cdc2a8edf995ae6b3eec3417ca/lib/rails/controller/testing/template_assertions.rb#L97-L98
so I don't know why it's not working via rspec-rails. 🤷
If assert_template doesn’t work, there’s not much we can do, as we usually just wrap Rails’ assertions.
You’re left to debug Rails testing code I believe.
If assert_template doesn’t work, there’s not much we can do, as we usually just wrap Rails’ assertions. You’re left to debug Rails testing code I believe.
Thanks Phil. Yeah, I'm guessing at this point it's a problem with assert_template itself, and not an rspec-rails problem. 🤷 Thanks for your thoughts and help here. I'll see about diving in with the Rails testing code.