I have code that does cookies.delete. If I debug it in my actual controller code, they are gone (and it works in the app itself). However, in the spec, the cookies are still there. I'm pretty sure this worked before I upgraded to Rails 5 (and pointed rspec to the master branch). I've tried everything I can think of, but I'm stumped.
@gregblass for issues like this, it's easiest if we have a small minimal rails app we can clone to debug against. Could you do the following:
1) initialise a new rails app with the 5.0.0.beta3 version of rails and commit
2) make as few changes required to show the incorrect behaviour and commit
3) leave a comment in your spec explaining what the behaviour was on rails 4.2 and what you expect it to be on 5.0
Thanks :+1:
@gregblass I'm going to close this. If you can create a clean reproduction case following the steps listed above, we can re-open and debug.
@samphippen, I faced the same problem on Rails 5.0.0.1 and rspec (3.5.2 and 3.6.0.beta1). I'm just implementing a sign out feature, and it fails. Here is my controller code and controller spec.
RSpec.describe SessionsController, type: :controller do
describe "POST #destroy" do
it "delete :remember_token in cookies" do
cookies.signed[:remember_token] = { value: 'remember_token', expires: 2.weeks.from_now }
post :destroy
expect(cookies.signed[:remember_token]).to be_nil
expect(response).to redirect_to(root_path)
end
end
end
class SessionsController < ApplicationController
def destroy
cookies.delete(:remember_token)
redirect_to root_path
end
end
Failures:
1) SessionsController POST #destroy delete :remember_token in cookies
Failure/Error: expect(cookies.signed[:remember_token]).to be_nilexpected: nil got: "remember_token" # ./spec/controllers/sessions_controller_spec.rb:10:in `block (3 levels) in <top (required)>'Finished in 0.05609 seconds (files took 5.34 seconds to load)
1 example, 1 failureFailed examples:
rspec ./spec/controllers/sessions_controller_spec.rb:5 # SessionsController POST #destroy delete :remember_token in cookies
Here is the repo, https://github.com/chamnap/rails_5_cookie_problem. Let's me know if I do anything wrong.
Same error here since I upgraded to rails 5.0.0 and rspec 3.5.2. Did someone succeed to overcome this issue ?
This is related with #1658
@sgrif can we close this now https://github.com/rails/rails/issues/27145 is merged?
FYI: Rails 5.0.1 still faced this issue, as I tested.
Closing for the same reason as #1658
For some reasons, this issue still exists on rails 5.1.5 and rspec-rails 3.7.2, https://github.com/chamnap/rails_5_cookie_problem.
I've just run into this on Rails 5.0.6. During its rewrite, it seems as though ActionController::TestCase forgot how to delete a cookie from the #cookies object (which is a CookieJar instance), unless the request method is set to GET.
In the context of a controller test, there are two instances of CookieJar involved; #request.cookie_jar and #cookies.
After the controller action under test has run, it calls #write on the request's CookieJar, and then #update on the jar in #cookies.
https://github.com/rails/rails/blob/v5.0.6/actionpack/lib/action_controller/test_case.rb#L554
The call to #update only merges new cookies into the jar; it doesn't delete any that ought to be removed.
However, the call to #write updates the "Set-Cookie" HTTP header, which does give us a workaround. When a cookie is being deleted the HTTP response will send a Set-Cookie header with the string "name_of_cookie=; ".
So you could assert that response.headers['Set-Cookie'] =~ /name_of_deleted_cookie=\; / is not nil.
It looks to me like fixing this in the #cookies jar will need some additional logic in the block I linked to above, deleting cookies from the #cookies jar.
This commit (https://github.com/rails/rails/pull/27586/files) did exactly that, but was reverted as it caused other regressions.
I've been calling cookies.update(response.cookies) after any non-GET requests where I need to test the contents of #cookies, which then allows me to test the contents of #cookies successfully.
Encountered this today and @gma comment helped me with this.
The cookies.update(response.cookies) did the work.
Thanks a lot.
I faced this issue today with Rails 5.2(with Spree 3.7).
Before checking cookies content in spec after request, I did cookies.update(response.cookies) and it worked. Thanks @gma and @ganbootyard
Seen again today with Rails 6.0, RSpec 3.8, and rspec-rails 4.0.0.beta2.
@percysnoodle Can you please try with rspec-rails gem 4.0.0.beta3?
@pirj Done - same problem. (I was using beta2 before; I've updated my previous comment).
This is the failing spec, in case I'm doing something wrong:
controller(ActionController::Base) do
def index
if params[:forget]
cookies.delete("parameter")
end
parameter = params[:parameter] || cookies["parameter"]
if parameter.present?
cookies["parameter"] = parameter
else
cookies.delete("parameter")
end
render plain: parameter || "nil"
end
end
it "forgets a remembered parameter" do
get :index
expect(response.body).to eq("nil")
get :index, params: { parameter: "value" }
expect(response.body).to eq("value")
get :index
expect(response.body).to eq("value")
get :index, params: { forget: true }
expect(response.body).to eq("nil")
get :index
expect(response.body).to eq("nil") # this is where it fails
end
This is a Rails issue, the code for updating cookies resides in https://github.com/rails/rails/blob/v6.0.0/actionpack/lib/action_controller/test_case.rb I suggest you construct a similar proof of concept in minitest and open it with them
Most helpful comment
I've just run into this on Rails 5.0.6. During its rewrite, it seems as though
ActionController::TestCaseforgot how to delete a cookie from the#cookiesobject (which is aCookieJarinstance), unless the request method is set toGET.In the context of a controller test, there are two instances of
CookieJarinvolved;#request.cookie_jarand#cookies.After the controller action under test has run, it calls
#writeon the request'sCookieJar, and then#updateon the jar in#cookies.https://github.com/rails/rails/blob/v5.0.6/actionpack/lib/action_controller/test_case.rb#L554
The call to
#updateonly merges new cookies into the jar; it doesn't delete any that ought to be removed.However, the call to
#writeupdates the "Set-Cookie" HTTP header, which does give us a workaround. When a cookie is being deleted the HTTP response will send aSet-Cookieheader with the string "name_of_cookie=; ".So you could assert that
response.headers['Set-Cookie'] =~ /name_of_deleted_cookie=\; /is notnil.It looks to me like fixing this in the
#cookiesjar will need some additional logic in the block I linked to above, deleting cookies from the#cookiesjar.This commit (https://github.com/rails/rails/pull/27586/files) did exactly that, but was reverted as it caused other regressions.
I've been calling
cookies.update(response.cookies)after any non-GET requests where I need to test the contents of#cookies, which then allows me to test the contents of#cookiessuccessfully.