I want to test a create action where the user is authenticated via a remote API. Therefore, I do not have a user model. I have this in rspec:
describe "POST create" do
before { post :create, :user => {username: "john", password: "password"} }
it { expect(response).to be_success }
end
This does not work. I looked at this rspec docs but could not find anything. How do I resolve this?
I assume this is a controller-spec, if you do like this it should work:
RSpec.describe UserControler, type: :controller do
describe 'POST #create' do
it 'creates a new user' do
expect {
post :create, user: { username: 'john', password: 'password' }
}.to change(User, :count).by(1)
end
end
end
To just check if the request is a success you can do:
it 'creates a new user' do
post :create, user: { username: 'john', password: 'password' }
expect(response).to be_success
end
Hope this helps :)
The post line needs to be in the it block
describe "POST create" do
before { }
it "returns 200 OK" do
post :create, :user => {username: "john", password: "password"}
expect(response).to be_success
end
end
Related
I am trying to get devise and devise-jwt gems to work so I can implement Authorization into my API only Rails app.
I have installed both devise and devise-jwt gems.
I followed the instructions on this blog post:
https://medium.com/#mazik.wyry/rails-5-api-jwt-setup-in-minutes-using-devise-71670fd4ed03
I have implemented the request specs that the author has included in his post and I can't get it approved on "Deleted",
I have to pass the authorizate token on delete, but I'm not getting it.
Any suggestion?
require 'rails_helper'
require "json"
RSpec.describe "POST /users", type: :request do
let(:user) { create(:user) }
let(:url) { '/users/sign_in' }
let(:params) do
{
user: {
email: user.email,
password: user.password
}
}
end
context 'when params are correct' do
before do
post url, params: params.to_json, headers: { 'CONTENT_TYPE' => 'application/json', 'ACCEPT' => 'application/json' }
end
it 'returns 200' do
expect(response).to have_http_status(200)
end
it 'returns JTW token in authorization header' do
expect(response.headers['authorization']).to be_present
end
end
context 'when login params are incorrect' do
before { post url }
it 'returns unathorized status' do
expect(response.status).to eq 401
end
end
end
RSpec.describe 'DELETE /logout', type: :request do
let(:url) { '/users/sign_out' }
it 'returns 204, no content' do
delete url
expect(response).to have_http_status(201)
end
end
I need to pass the user's token on delete, any suggestions on how I can be doing this?
Here is my rspec test code
require 'rails_helper'
RSpec.describe Users::PaymentController, type: :controller do
let(:user) { create(:user) }
let(:secure_user) { create(:secure_user, user_id: user.id, email: 'abc123#mail.com', birth_date: '1990-01-01', gender: 'female', nation: 'jp', prefecture: 'Tokyo-to', municipality: 'Shibuya-ku') }
describe 'POST #create' do
params = {
birth_date: '2000-01-01',
gender: 'male',
prefecture: 'Osaka-fu',
municipality: 'Osaka-shi'
}
it "changes secure_user's attributes" do
expect do
post :create, params: params
end.to change{ secure_user.birth_date }.from('1990-01-01').to('2000-01-01')
end
end
end
and here is the related part from Users::PaymentController
module Users
class PaymentController < Users::BaseController
def create
current_user.secure_user.update(user_personal_info_params)
......
......
end
private
def user_personal_info_params
params.permit(:birth_date, :gender, :nation, :prefecture, :municipality)
end
end
end
The logic is: add new info to current_user.secure_user while payment is created.
But the test fails and I don't know the reason.
1) Users::PaymentController POST #create changes secure_user's attributes
Failure/Error:
expect do
post :create, params: user_info
binding.pry
end.to change{ secure_user.birth_date }.from('1990-01-01').to('2000-01-01')
expected `secure_user.birth_date` to have changed from "1990-01-01" to "2000-01-01", but did not change
I am not very familiar with RSpec (and so does English), much appreciated if anybody could help me solve this problem.
Try to use .reload
...
end.to change{ secure_user.reload.birth_date }.from('1990-01-01').to('2000-01-01')
The object doesn't get updated inside the test, you have to reload it, to have the up to date attributes.
I am trying to test some PUT/PATCH endpoint from my API, but my 'record_to_update' is not chaging as expect.
I organize the spec as follow using Rails 5.2 and RSpec 3.8:
require 'rails_helper'
RSpec.describe UsersController, type: :controller do
context 'when request with no valid headers' do
...
...
...
end
context 'when resquest with valid headers' do
before do
request.accept = 'application/vnd.api+json'
request.content_type = 'application/vnd.api+json'
2.times do
create(:user)
end
end
describe 'PATCH/PUT /users/:id' do
let(:record_to_update) { create(:user) }
let(:user_params) do
{ id: first_user.id, name: 'goku', email: 'goku#bol.com' }
end
before do
put :update, params: { id: record_to_update, user: user_params }
record_to_update.reload
end
it 'should update user' do
expect(record_to_update.name).to eq('goku')
expect(response.status).to eq 200
end
end
end
end
As I said the problem here that I am facing is that 'record_to_update' is not chaging. I already test the same PUT/PATCH endpoint in the same API with Postman and successfully updated from there. What am I doing wrong here?
Thanks in advance.
you should move the before block to it 'should update user'
before do
put :update, params: { id: record_to_update.id, user: user_params }
end
So it becoming
it 'update user' do
put :update, params: { id: record_to_update, user: user_params }
expect ...
record.reload!
....
end
so I'm writing a Test for my UserController, and the associated Devise dependency.
I'm trying to write a test that verify's userA can't access the show page of userB, but is redirected to the root_path instead. I'm guessing syntax errors are my issue, but I'd love another pair of eyes on it!
require 'rails_helper'
describe UsersController, :type => :controller do
# create test user
before do
#userA = User.create!(email: "test#example.com", password: "1234567890")
#userB = User.create!(email: "test2#example.com", password: "1234567890")
end
describe "GET #show" do
before do
sign_in(#userA)
end
context "Loads correct user details" do
get :show
expect(response).to have_http_status(200)
expect(assigns(:user)).to eq #userA
end
context "No user is logged in" do
it "redirects to login" do
get :show, id: #userA.id
expect(response).to redirect_to(root_path)
end
end
end
describe "GET Unauthorized page" do
before do
sign_in(#userA)
end
context "Attempt to access show page of UserB" do
it "redirects to login" do
get :show, id: #userB.id
expect(response).to have_http_status(401)
expect(response).to redirect_to(root_path)
end
end
end
end
You're missing an "it" block in
context "Loads correct user details" do
get :show
expect(response).to have_http_status(200)
expect(assigns(:user)).to eq #userA
end
I have devise authentication and registration set up on my Rails app. I'm using after_sign_in_path_for() to customise the redirect when the user signs in based on various scenarios.
What I'm asking is how to test this method? It seems hard to isolate since it is called automatically by Devise when the user signes in. I want to do something like this:
describe ApplicationController do
describe "after_sign_in_path_for" do
before :each do
#user = Factory :user
#listing = Factory :listing
sign_in #user
end
describe "with listing_id on the session" do
before :each do
session[:listing_id] = #listing.id
end
describe "and a user in one team" do
it "should save the listing from the session" do
expect {
ApplicationController.new.after_sign_in_path_for(#user)
}.to change(ListingStore, :count).by(1)
end
it "should return the path to the users team page" do
ApplicationController.new.after_sign_in_path_for(#user).should eq team_path(#user.team)
end
end
end
end
end
but that's obviously not the way to do it because I just get an error:
Failure/Error: ApplicationController.new.after_sign_in_path_for(#user)
RuntimeError:
ActionController::Metal#session delegated to #_request.session, but #_request is nil: #<ApplicationController:0x00000104581c68 #_routes=nil, #_action_has_layout=true, #_view_context_class=nil, #_headers={"Content-Type"=>"text/html"}, #_status=200, #_request=nil, #_response=nil>
So, how can I test this method?
Oddly, I was wondering this very thing today. Here's what I came up with. I created an anonymous subclass of ApplicationController. In this anonymous subclass, I exposed the protected methods that I wanted to test as public methods. Then I tested them directly.
describe ApplicationController do
controller do
def after_sign_in_path_for(resource)
super resource
end
end
before (:each) do
#user = FactoryGirl.create(:user)
end
describe "After sigin-in" do
it "redirects to the /jobs page" do
controller.after_sign_in_path_for(#user).should == jobs_path
end
end
end
On a similar note - if you want to test the redirect after sign-up, you have two options.
First, you can follow a pattern similar to above and very directly test the method in RegistrationsController:
require 'spec_helper'
describe RegistrationsController do
controller(RegistrationsController) do
def after_sign_up_path_for(resource)
super resource
end
end
describe "After sign-up" do
it "redirects to the /organizations/new page" do
#user = FactoryGirl.build(:user)
controller.after_sign_up_path_for(#user).should == new_organization_path
end
end
end
Or, you can take a more integration-testing sort of approach and do the following:
require 'spec_helper'
describe RegistrationsController do
describe "After successfully completing the sign-up form" do
before do
#request.env["devise.mapping"] = Devise.mappings[:user]
end
it "redirects to the new organization page" do
post :create, :user => {"name" => "Test User", "email" => "test#example.com", "password" => "please"}
response.should redirect_to(new_organization_path)
end
end
end
For the newcomers, I would recommend doing this way:
RSpec.describe ApplicationController, type: :controller do
let(:user) { create :user }
describe "After sing-in" do
it "redirects to the /yourpath/ home page" do
expect(subject.after_sign_in_path_for(user)).to eq(yourpath_root_path)
end
end
end
I found this answer through Google recently and thought I would add my solution. I didn't like the accepted answer because it was testing the return value of a method on the application controller vs testing the desired behavior of the app.
I ended up just testing the call to create a new sessions as a request spec.
RSpec.describe "Sessions", type: :request do
it "redirects to the internal home page" do
user = FactoryBot.create(:user, password: 'password 123', password_confirmation: 'password 123')
post user_session_path, params: {user: {email: user.email, password: 'password 123'}}
expect(response).to redirect_to(internal_home_index_path)
end
end
(Rails 5, Devise 4, RSpec 3)
context "without previous page" do
before do
Factory.create(:user, email: "junior#example.com", password: "123456", password_confirmation: "123456")
request.env["devise.mapping"] = Devise.mappings[:user]
post :create, user: { email: "junior#example.com", password: "123456" }
end
end
it { response.should redirect_to(root_path) }
context "with previous page" do
before do
Factory.create(:user, email: "junior#example.com", password: "123456", password_confirmation: "123456")
request.env["devise.mapping"] = Devise.mappings[:user]
request.env['HTTP_REFERER'] = 'http://test.com/restaurants'
post :create, user: { email: "junior#example.com", password: "123456" }
end
it { response.should redirect_to("http://test.com/restaurants") }
end