Search code examples
ruby-on-railsrspecdevise

Why does RSPEC behaves differently between Edit view and New view tests with Rails 5.2?


I am developing an application with Rails 5.2, and testing the features using Capybara.

I want to make sure that not connected users cannot view the Playgrounds pages, and that connected ones can. Authentication is based on Devise, so that when you request an unauthorised page, you are routed to the login page.

I wrote this test: spec/features/playgrounds_spec.rb

require 'rails_helper'

RSpec.describe Playground, type: :request do
  include Warden::Test::Helpers

  describe "Playground pages: " do
    let(:pg) {FactoryBot.create(:playground)}

    context "when not signed in " do
      it "should propose to log in when requesting index" do
        get playgrounds_path
        follow_redirect!
        expect(response.body).to include('Sign in')
      end
      it "should propose to log in when requesting new" do
        get new_playground_path(pg)
        follow_redirect!
        expect(response.body).to include('Sign in')
      end
      it "should propose to log in when requesting edit" do
        get edit_playground_path(pg)
        follow_redirect!
        expect(response.body).to include('Sign in')
      end
      it "should propose to log in when requesting show" do
        get playground_path(pg)
        follow_redirect!
        expect(response.body).to include('Sign in')
      end
    end
    context "when signed in" do
      before do
        get "/users/sign_in"
        test_user = FactoryBot.create(:user)
        login_as test_user, scope: :user
      end
      it "should display index" do
        get playgrounds_path
        expect(response).to render_template(:index)
      end
      it "should display new view" do
        get new_playground_path(pg)
        expect(response).to render_template(:_form)
      end
      it "should display edit view" do
        get edit_playground_path(pg)
        expect(response).to render_template(:_form)
      end
      it "should display show view" do
        get playground_path(pg)
        expect(response).to render_template(:show)
      end
    end
  end
end

The test should be successful, but fails with the following error:

.F....#<Playground:0x000000000d119470>
.#<Playground:0x000000000e059700>
.

Failures:

  1) Playground Playground pages:  when not signed in  should propose to log in when requesting new
     Failure/Error: follow_redirect!

     RuntimeError:
       not a redirect! 401 Unauthorized
     # ./spec/features/playgrounds_spec.rb:17:in `block (4 levels) in <top (required)>'

Finished in 4.81 seconds (files took 12.28 seconds to load)
8 examples, 1 failure

Failed examples:

rspec ./spec/features/playgrounds_spec.rb:15 # Playground Playground pages:  when not signed in  should propose to log in when requesting new

To solve this, I can simply test the status returned by the request to the New view:

  it "should propose to log in when requesting new" do
    get new_playground_path(pg)
    #follow_redirect!
    expect(response.status).to eq 401
  end

But it doesn't tell me if the user really lands on the login page...

One more detail: when a not connected user tries to reach this New view, he actually lands on the login page!

Can you explain why the behaviour is different for the New view, and how to solve this issue?

Thanks a lot!


Solution

  • I finally found out that the method new_playground_path does not expect any parameter.

    I removed the (pg) expression, which finally solved the issue.

    Solved!