rspec / rspec-rails

RSpec for Rails 6+
https://rspec.info
MIT License
5.16k stars 1.03k forks source link

render_template is not working #2724

Closed raoehtesham03 closed 9 months ago

raoehtesham03 commented 9 months ago

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".
JonRowe commented 9 months ago

:wave: 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.

raoehtesham03 commented 9 months ago

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

pirj commented 9 months ago

Please provide a reproducible snippet like https://github.com/rspec/rspec-rails/blob/main/snippets/use_active_record_false.rb

raoehtesham03 commented 9 months ago

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.

pirj commented 9 months ago

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

drsharp commented 8 months ago

@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:

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!

pirj commented 8 months ago

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?

drsharp commented 8 months ago

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). 🤷

raoehtesham03 commented 8 months ago

@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 commented 8 months ago

@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. 🤷

pirj commented 8 months ago

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.

drsharp commented 8 months ago

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.