rspec / rspec-rails

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

Unable to set cookies to be passed in request specs #1993

Closed raldred closed 5 years ago

raldred commented 6 years ago

What Ruby, Rails and RSpec versions are you using?

Ruby version: 2.5.0 Rails version: 5.2.0 Rspec version: 3.7

Observed behaviour

Cookies are not available in the controller

Expected behaviour

Cookies should be available in the controller

spec

RSpec.describe "logout", type: :request do
  it "removes the cookie" do
    cookies['_cookiename'] = 'abc123'
    get "/logout"
    expect(response.cookies['_cookiename']).to_not be_present
  end
end

controller

def logout
  p cookies # <-- will output {} no cookies are available
  reset_session
  cookies.delete('_cookiename')
end

Works fine in controller specs

ebihara99999 commented 6 years ago

Request spec doesn't support testing cookies, but controller spec does. What's the problem with you using controller spec?

raldred commented 6 years ago

No problem, like I said controller specs are fine, merely raising the gap in functionality.

mikegee commented 6 years ago

Since controller specs are discouraged these days, I wouldn't expect to see their features moved to request specs. Instead, perhaps we should directly set the cookie header when calling get.

raldred commented 6 years ago

agree @mikegee, in a similar fashion to passing params and headers. I suspect this is really down to a limitation of Rails' integration tests.

I wonder if you can do...

headers: {"HTTP_COOKIE" => "key=value; key2=value2;"}
JonRowe commented 6 years ago

Most of the behaviour for these sets of specs is direct from Rails, can you see if it works in the minitest equivalent for me?

fables-tales commented 6 years ago

I actually just tried to reproduce this and failed.

@raldred Thanks for the issue. We need a little more detail to be able to reproduce this.

Could you please provide us with a rails app that we can clone that demonstrates the issue. Specifically it'd be great if

1) you could rails new an application and commit 2) make all the changes necessary to reproduce the issue and commit

then, provide us with a description of how to clone your application and reproduce the issue.

Thanks :)

ghost commented 5 years ago

@samphippen cc: @raldred I reproduce this issue. Please check if you have the time.

Steps to reproduce

This is reproduced Rails application.

  1. git clone git@github.com:taki/rpsec-rails-does-not-set-cookie.git
  2. cd rpsec-rails-does-not-set-cookie
  3. bundle install
  4. bin/rails db:setup
  5. bundle exec rspec spec/requests/sign_outs_controller_spec.rb

Environment

tomaszganski commented 5 years ago

Just pass cookies in the header as was mentioned before

 get "/logout", nil, {'cookie' => '_cookiename=123'}
 expect(response.cookies['_cookiename']).to_not be_present
benoittgt commented 5 years ago

Hello

TL;DR


I finaly took some times to look at this issue. I jumped to Rails source code on cookies test an especially one that look similar to the last reproduction case published by @taki?

https://github.com/rails/rails/blob/b9ca94caea2ca6a6cc09abaffaad67b447134079/actionpack/test/controller/integration_test.rb#L272-L280 or https://github.com/rails/rails/blob/43866b2ca338375b964b0b905ee20f74f9b21b22/actionpack/test/dispatch/cookies_test.rb#L1136-L1142

When setting cookies with cookies[] you need to use cookies for expectation.

For example:

# app/controllers/sign_outs_controller.rb
class SignOutsController < ApplicationController
  def show
    cookies["inside_controller"] = "FROM_CONTROLLER"
    puts "cookies inside controller #{cookies.to_hash}"
    head 200
  end
end
# spec/requests/sign_outs_controller_spec.rb

require 'rails_helper'

RSpec.describe SignOutsController, type: :request do
  describe 'GET /signout' do
    specify do
      cookies["inside_test"] = "FROM_TEST"

      get "/sign_out"

      puts ">> With response.cookies: #{response.cookies.inspect}"
      puts ">> With cookies.to_hash: #{cookies.to_hash.inspect}"
      puts ">> With headers[\"Set-Cookie\"]: #{headers["Set-Cookie"]}"
    end
  end
end
SignOutsController
  GET /signout
cookies inside controller {"inside_test"=>"FROM_TEST", "inside_controller"=>"FROM_CONTROLLER"}
>> With response.cookies: {"inside_controller"=>"FROM_CONTROLLER"}
>> With cookies.to_hash: {"inside_controller"=>"FROM_CONTROLLER", "inside_test"=>"FROM_TEST"}
>> With headers["Set-Cookie"]: "inside_controller=FROM_CONTROLLER; path=/"
    example at ./spec/requests/sign_outs_controller_spec.rb:5

When using response.cookies it is only on cookies not modified inside the test.

This issue is for me not related to rspec-rails because we can see the same behavior tested into actionpack codebase. I am in favor of closing this issue but maybe we could add some documentation?

fables-tales commented 5 years ago

@benoittgt do you want to send a PR to update the cucumber features with whatever you think will work best?

benoittgt commented 5 years ago

Good idea @samphippen. I will try now.

benoittgt commented 5 years ago

There is also an old documentation on this https://relishapp.com/rspec/rspec-rails/docs/controller-specs/cookies I will send a PR to update this one too.

Sorry I had my daughter that wake-up after her nap was not able to make it this afternoon. 😃

benoittgt commented 5 years ago

Documentation will be simplified on next rspec-rails 4 documentation. See #2127

I am closing this issue because I don't think we can do more.