Skip to content

Instantly share code, notes, and snippets.

@vasilakisfil
Last active August 29, 2015 14:16
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save vasilakisfil/a463eee233a00772ba59 to your computer and use it in GitHub Desktop.
Save vasilakisfil/a463eee233a00772ba59 to your computer and use it in GitHub Desktop.
Rspec API Helper
#rspec/support/rspec_api_helper.rb
module RspecApiHelper
module ExampleMethods
def objectize_resources(json, root: root)
array = []
array_hash = HashWithIndifferentAccess.new(MultiJson.load(json))
if root
array_hash = array_hash[root]
end
array_hash.each do |resource|
array << object_hash(resource)
end
return array
end
def objectize_resource(json, root: root)
hash = HashWithIndifferentAccess.new(MultiJson.load(json))
if root
obj = object_hash(hash[root])
else
obj = object_hash(hash)
end
return obj
end
def object_hash(hash)
ObjectHash.new(hash)
end
class ObjectHash
attr_accessor :hash
def initialize(hash)
@hash = HashWithIndifferentAccess.new(hash)
end
def method_missing(name)
return hash[name] if hash.key? name
raise KeyError.new("Attribute not found: #{name}")
end
end
end
module ExampleGroupMethods
def it_returns_status(status)
it 'returns the correct status' do
expect(last_response.status).to eql(status)
end
end
def it_returns_attributes(resource:, model:, only: [], modifier: nil)
it "expects returned resource to have the following model's attributes" do
@api_resource = objectize_resource(last_response.body, root: resource)
@model = eval(model)
if @model.is_a? Hash
@model = object_hash(@model)
end
if only
only.each do |attribute|
if modifier
expect(@api_resource.send(attribute)).to(
eql(@model.send(attribute).send(modifier.to_sym))
)
else
expect(@api_resource.send(attribute)).to eql(@model.send(attribute))
end
end
end
end
end
alias_method :it_returns_db_model, :it_returns_attributes
alias_method :it_returns_more_attributes, :it_returns_attributes
def it_includes_in_headers(headers: {})
it 'returns the correct headers' do
headers.each do |header, value|
expect(last_response.headers[header.to_s]).to eq(eval(value))
end
end
end
def it_returns_the_resources(root:, number:)
it 'returns the correct number of data in the body' do
users = objectize_resources(last_response.body, root: root)
expect(users.length).to eql(number)
end
end
end
def self.included(receiver)
receiver.extend ExampleGroupMethods
receiver.send :include, ExampleMethods
end
end
RSpec.configure do |config|
config.include RspecApiHelper, type: :api #apply to all spec for apis folder
end
#rspec/apis/users_spec.rb
require 'rails_helper'
describe Api::V1::UsersController, type: :api do
context :index do
before do
create_and_sign_in_user
5.times{ FactoryGirl.create(:user) }
get api_v1_users_path, format: :json
end
it_returns_status(200)
it_returns_the_resources(root: 'users', number: 5+1)
end
context :create do
before do
@user = FactoryGirl.attributes_for(:user)
post api_v1_users_path, user: @user.as_json, format: :json
end
it_returns_status(201)
it_returns_attributes(resource: 'user', model: '@user', only: [
:email, :first_name, :last_name
])
it_returns_more_attributes(
resource: 'user',
model: 'User.last!',
only: [:updated_at, :created_at],
modifier: 'iso8601'
)
end
context :show do
before do
create_and_sign_in_user
@user = FactoryGirl.create(:user)
get api_v1_user_path(@user.id), format: :json
end
it_returns_status(200)
it_returns_attributes(resource: 'user', model: '@user', only: [
:email, :first_name, :last_name
])
it_returns_more_attributes(
resource: 'user',
model: '@user',
only: [:updated_at, :created_at],
modifier: 'iso8601'
)
end
context :update do
before do
create_and_sign_in_user
@user = FactoryGirl.create(:user)
@user.first_name = 'Another name'
put api_v1_user_path(@user.id), user: @user.as_json, format: :json
end
it_returns_status(200)
it_includes_in_headers(headers: {Location: 'api_v1_user_path(@user.id)'})
it_returns_attributes(resource: 'user', model: '@user', only: [
:email, :first_name, :last_name
])
it_returns_more_attributes(
resource: 'user',
model: '@user',
only: [:updated_at, :created_at],
modifier: 'iso8601'
)
end
context :delete do
context 'when the resource does NOT exist' do
before do
create_and_sign_in_user
@user = FactoryGirl.create(:user)
delete api_v1_user_path(rand(100..1000)), format: :json
end
it_returns_status(404)
end
context 'when the resource does exist' do
before do
create_and_sign_in_user
@user = FactoryGirl.create(:user)
delete api_v1_user_path(@user.id), format: :json
end
it_returns_status(204)
it 'actually deletes the resource' do
expect(User.find_by(id: @user.id)).to eql(nil)
end
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment