Shoulda matchers - Rspec - Test controllers Actions to Json Response - FastJSON - unit-testing

How to test using shoulda-matchers for these actions, to response JSON success 200, and fail 422
and how to test with normal RSpec: both cases if you can:
I think there is missing some information for shoulda matches on its repository.
if you can help thanks very much.
module V1
class MeasurementsController < ApplicationController
protect_from_forgery with: :null_session
before_action :set_measurement, only: %i[destroy]
def index
measurement = Measurement.all
render json: MeasurementSerializer.new(measurement).serialized_json
end
def create
measurement = Measurement.new(measurement_params)
if measurement.save
render json: MeasurementSerializer.new(measurement).serialized_json
else
render json: { error: measurement.errors.messages }, status: 422
end
end
def destroy
if #measurement.destroy
head :no_content
else
render json: { error: measurement.errors.messages }, status: 422
end
end
private
def set_measurement
#measurement = Measurement.find(params[:id])
end
def measurement_params
params.require(:measurement).permit(:time, :date, :sport_id)
end
end
end
end```

No need for shoulda-matchers
You can test with something like this:
require 'rails_helper'
describe V1::MeasurementsController do
describe '#index', type: request do
it 'respond with 200' do
get /your/endpoint
expect(response).to have_http_status(200)
end
end
end

what works for me
describe 'GET #index' do
before { get :index }
it { should respond_with(200) }
end

Related

DRY rspec test with routing

I spent several hours trying to make my rspec test work. And as a result I got not really DRY tests which I want optimize somehow.
They look like the following:
describe ExtApi::BaseController do
let!(:app) { create(:api_application) }
let!(:token) { app.token }
controller do
def resp
render json: {foo: 'bar'}
end
def error
raise StandardError 'baz'
end
end
describe '#authenticate' do
context 'when is successfull' do
it 'renders bar' do
routes.draw { get '/foo' => 'ext_api/base#resp' }
get :resp, access_token: token
expect ...
end
end
context 'when token is invalid' do
before do
app.destroy
end
it 'renders error' do
routes.draw { get '/foo' => 'ext_api/base#resp' }
get :resp, access_token: token
expect ...
end
it do
routes.draw { get '/foo' => 'ext_api/base#resp' }
get :resp, access_token: token
is_expected.to respond_with 401
end
end
context 'when token is not presented' do
it 'renders error' do
routes.draw { get '/foo' => 'ext_api/base#resp' }
get :resp
expect ...
end
it do
routes.draw { get '/foo' => 'ext_api/base#resp' }
get :resp
is_expected.to respond_with 401
end
end
end
I have to repeat routes.draw in each it block (and not in before) because otherwise, it crushes all the routing, and in all tests that run after these ones, I get RoutingError.
So, I would like to know if there is any way to do this better than I do?
(I use rails 4.2 and rspec 3.4)
If you split your each controller test into a different block, you can do like this.
RSpec.describe ExtApi::BaseController, type: :controller do
describe "GET resp" do
it 'renders bar' do
get :resp, access_token: token
# expect ...
end
end
end
reference: https://relishapp.com/rspec/rspec-rails/docs/controller-specs

Devise validation fails with can't be blank even if I send values properly

I am sending the request using postman, all the required fields are in place, however, I get the params required errors, like I send nothing when I actually do send the required params to the server.
I was reading this blog that says in order to get json reponse in devise I just need to add respond_to :json line in devise controllers, but it seems this is not enough.
I would've add more info to the question if I would know what exactly is needed.
routes:
namespace :api, defaults: { format: :json } do
devise_for :users, controllers: {
registrations: 'api/users/registrations',
sessions: 'api/users/sessions',
invitations: 'api/users/invitations'
}
end
controllers:
module Api
class Users::RegistrationsController < Devise::RegistrationsController
respond_to :json
layout false, only: :create
def create
build_resource(sign_up_params)
resource.save
yield resource if block_given?
if resource.persisted?
# valid resource
else
clean_up_passwords resource
set_minimum_password_length
render json: {user: resource.errors}
end
end
end
end
class ApplicationController < ActionController::Base
protect_from_forgery with: :null_session
before_action :configure_permitted_parameters, if: :devise_controller?
protected
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) << [:first_name, :last_name]
end
end
request:
with headers: Accept - application/json
Started POST "/api/users" for 127.0.0.1 at 2015-07-01 17:05:26 +0300
Processing by Api::Users::RegistrationsController#create as JSON
Parameters: {"user"=>{"email"=>"usermail#gmail.com", "password"=>"[FILTERED]", "first_name"=>"firstName", "last_name"=>"lastName"}}
(0.1ms) BEGIN
(0.1ms) ROLLBACK
Completed 200 OK in 17ms (Views: 0.2ms | ActiveRecord: 3.8ms)
response:
{"user":{"email":["can't be blank"],"password":["can't be blank"],"first_name":["can't be blank"],"last_name":["can't be blank"]}}

Testing with Rspec get errors , But testing with brower works fine

Hello friends I have something to confess first,my previous account was banned from asking questions,From now on, i will try to make the questions more clear and precise!
I'm working on Hartl's ruby on rails tutorials ,i have been stuck at chapter 9.2.2 Requiring the right user `"Listing 9.13 Testing that the edit and update actions require the right user" for a few days. I have done lots of research,i went back and forth of the chapters , it didn't work and it seems no one had the issue that i have now . Let me explain in details.
Errors:
Authentication authorization as wrong user submitting a GET request to the Users#edit action
Failure/Error: specify { expect(response.body).not_to match(full_title('Edit user')) }
TypeError:
wrong argument type nil (expected Regexp)
# ./spec/requests/authentication_pages_spec.rb:61:in `block (5 levels) in <top (required)>'
Finished in 1.77 seconds
64 examples, 1 failure
i have tested with the brower,it works perfectly,i tried to edit other users. the page was directed to the home page successfully!
Github: https://github.com/Snailseason2014/Sample
here are some related files:
spec/requests/authentication_pages_spec.rb
require 'spec_helper'
describe 'Authentication' do
subject { page }
describe 'signin page' do
before { visit signin_path }
it { should have_content('Sign in') }
it { should have_title('Sign in') }
end
describe 'signin' do
before { visit signin_path }
describe 'with invalid information' do
before { click_button 'Sign in' }
it { should have_title('Sign in') }
it { should have_selector('div.alert.alert-error', text: 'Invalid') }
describe 'after visiting another page' do
before { click_link 'Home' }
it { should_not have_selector('div.alert.alter-error') }
end
end
describe 'with valid information' do
let(:user) { FactoryGirl.create(:user) }
before { sign_in user }
it { should have_title(user.name) }
it { should have_link('Profile', href: user_path(user)) }
it { should have_link('Settings', href: edit_user_path(user)) }
it { should have_link('Sign out', href: signout_path) }
it { should_not have_link('Sign in', href: signin_path) }
describe 'followed by signout' do
before { click_link 'Sign out' }
it { should have_link('Sign in') }
end
end
end
describe 'authorization' do
describe 'for non-signed-in users' do
let(:user) { FactoryGirl.create(:user) }
describe 'in the Users controller' do
describe 'visiting the edit page' do
before { visit edit_user_path(user) }
it { should have_title('Sign in') }
end
describe 'submitting to the update action' do
before { patch user_path(user) }
specify { expect(response).to redirect_to(signin_path) }
end
end
end
describe 'as wrong user' do
let(:user) { FactoryGirl.create(:user) }
let(:wrong_user) { FactoryGirl.create(:user, email: 'wrong#example.com') }
before { sign_in user, no_capybara: true }
describe 'submitting a GET request to the Users#edit action' do
before { get edit_user_path(wrong_user) }
specify { expect(response.body).not_to match(full_title('Edit user')) }
specify { expect(response).to redirect_to(root_url) }
end
describe 'submitting a PATCH request to the Users#update action' do
before { patch user_path(wrong_user) }
specify { expect(response).to redirect_to(root_url) }
end
end
end
end
app/controllers/users_controller.rb
class UsersController < ApplicationController
before_action :signed_in_user, only: [:edit, :update]
before_action :correct_user, only: [:edit, :update]
def show
#user = User.find(params[:id])
end
def new
#user = User.new
end
def create
#user = User.new(user_params)
if #user.save
sign_in #user
flash[:success] = 'welcome'
redirect_to #user
else
render 'new'
end
end
def edit
# #user = User.find(params[:id])
end
def update
# #user = User.find(params[:id])
if #user.update_attributes(user_params)
flash[:success] = 'Profile updated'
redirect_to #user
else
render 'edit'
end
end
private
def user_params
params.require(:user).permit(:name, :email, :password, :password_confirmation)
end
# Before filters
def signed_in_user
redirect_to signin_url, notice: 'Please sign in.' unless signed_in?
end
def correct_user
#user = User.find(params[:id])
redirect_to(root_path) unless current_user?(#user)
end
end
It looks like you skipped some of the exercises, specifically the exercises in section 5.6, which would have prevented your error.
In any case, in chapter 5 the tutorial had you define a duplicate full_title() helper for the tests to use, which was to be put in the file:
spec/support/utilities.rb
The original full_title() helper was used by the views.
Looking at your spec/support/utilities.rb file, you have this:
def full_title(page_title)
base_title = 'Ruby on Rails Tutorial Sample App'
if page_title.empty?
base_title
else
"#{base_title} | #{page_title}"
end
Can you see what's wrong? It's obvious that you copy and pasted that code from the text of the tutorial, and you missed the last line which was: end, which is required to close the def you started on the first line. However, I cannot explain why you haven't been getting a SyntaxError when trying to run your tests, which prevents the tests from running at all when I try it.
In your spec:
expect(response.body).not_to match(full_title('Edit user'))
a match exepctation is expected to match some text against a regular expression eg:
expect("hello").to match(/ell/) # => true
expect("hello").to match(/blah/) # => false
full_title('Edit user') is not a regular expression... it's some content on the page. So it really isn't the right thing to use in an expect...match. You can turn any string into a regular expression by putting it inside // and using string-interpolation syntax eg:
a_string = 'some string'
a_regex = /#{a_string}/
so here you could use:
expect(response.body).not_to match(/#{full_title('Edit user')}/)
HOWEVER... the error message you get is indicative of something deeper... it says that you are passing a nil instead of a regular expression... which means that full_title('Edit user') is evaluating to nil instead of an actual string.
if you use my example above... the spec will likely still fail... so you have to figure out why full-title('Edit user') is returning nil and fix that first.

How can I return a 404 JSON format in Rails 4?

I am new to Ruby. I am writing a Restful API application using Rails 4.
How can I return a 404 JSON not found string when the record is not found?
I found a number of posts but no luck, only for Rails 3.
In my controller I can caught the exception
def show
country = Country.find(params[:id])
render :json => country.to_record
rescue Exception
render :json => "404"
end
But I want a generic one to capture all the not found resources.
Use rescue_from. See http://guides.rubyonrails.org/v2.3.11/action_controller_overview.html#rescue
In this instance use something like:
class ApplicationController < ActionController::Base
rescue_from ActiveRecord::RecordNotFound, :with => :record_not_found
private
def record_not_found(error)
render json: { error: error.message }, status: :not_found
end
end
Do:
def show
country = Country.find(params[:id])
render :json => country.to_record
rescue Exception
render :json => 404_json_text, :status => 404
end

How do I use a simple test spy in a controller test?

I'm trying to test that my controller simply calls a method on a service object. I thought a test spy would be perfect for this. What am I doing wrong? Thanks for any help!
Controller:
class PostsController < ApplicationController
def create
#post = Post.new(post_params)
if #post.save
ServiceObject.new(#post).call
redirect_to posts_path, success: "#{#post.title} was successfully created."
else
render action: :new
end
end
end
Service object:
class ServiceObject
def initialize(post)
#post = post
end
def call
puts "Service object was called!"
end
end
Controller test:
require 'spec_helper'
describe PostsController do
describe 'POST #create' do
it 'calls the service object' do
service_object = double(ServiceObject)
service_object.stub(:new).and_return(service_object)
service_object.stub(:call)
post :create, post: Fabricate.attributes_for(:post)
expect(service_object).to have_received(:call)
end
end
end
Error:
Failure/Error: expect(service_object).to have_received(:call)
(Double ServiceObject).call(any args)
expected: 1 time with any arguments
received: 0 times with any arguments
try this:
require 'spec_helper'
describe PostsController do
describe 'POST #create' do
let(:service_object) { double(:service_object) }
before do
ServiceObject.stub(:new).and_return(service_object)
service_object.stub(:call)
end
it 'calls the service object' do
post :create, post: Fabricate.attributes_for(:post)
expect(service_object).to have_received(:call)
end
end
end