Skip to content

Instantly share code, notes, and snippets.

@vasilakisfil
Last active August 29, 2015 14:14
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/b0c9cdb267d9863399a7 to your computer and use it in GitHub Desktop.
Save vasilakisfil/b0c9cdb267d9863399a7 to your computer and use it in GitHub Desktop.
rspec API helpers
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
module RspecApi
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 << ObjectHash.new(resource)
end
return array
end
def objectize_resource(json, root: root)
hash = HashWithIndifferentAccess.new(MultiJson.load(json))
if root
obj = ObjectHash.new hash[root]
else
obj = ObjectHash.new hash
end
return obj
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(name:, check_only: [])
it "expects returned resource to have the following model's attributes" do
@api_resource = objectize_resource(last_response.body, root: name)
if instance_variable_get("@#{name}").is_a? Hash
@model = ObjectHash.new instance_variable_get("@#{name}")
else
@model = instance_variable_get("@#{name}")
end
if check_only
check_only.each do |attribute|
expect(@api_resource.send(attribute)).to eql(@model.send(attribute))
end
end
end
end
alias_method :it_returns_db_model, :it_returns_attributes
end
def self.included(receiver)
receiver.extend ExampleGroupMethods
receiver.send :include, ExampleMethods
end
end
describe Api::V1::CountiesController, type: :api do
include RspecApi
#it_behaves_like "ActiveModelAPI#index", {api_resource: 'Api::V1::County'}
context :index do
before do
#create_and_sign_in_user
@resources_count = 5 #rand(min..max)
5.times{ FactoryGirl.create(:county) }
get api_v1_counties_path, format: :json
end
it_returns_status(200)
it 'returns the correct number of data in the body' do
obj_array = objectize_resources(last_response.body, root: :counties)
expect(obj_array.count).to eql 5
end
end
context :create do
before do
create_and_sign_in_user
@county = FactoryGirl.attributes_for(:county)
post api_v1_counties_path, county: @county.as_json, format: :json
@county_last = County.last!
end
it_returns_status(201)
it_returns_attributes(name: :county, check_only: [:name])
end
context :show do
before do
create_and_sign_in_user
@county = FactoryGirl.create(:county)
get api_v1_county_path(@county.id), format: :json
end
it_returns_status(200)
it_returns_db_model(name: :county, check_only: [:name])
it 'returns date in iso8601' do
obj = objectize_resource(last_response.body, root: :county)
expect(obj.updated_at).eql? @county.updated_at.iso8601
end
end
end
#probably too much
RSpec.shared_examples "ActiveModelAPI#index" do |options|
before(:all) do
routes = Rails.application.routes.routes.to_a.select do |r|
r.defaults[:controller] == "api/v1/users"
end
resource_a = options[:api_resource].downcase.split('::')
path_prefix = options[:api_resource].downcase.split('::')[0..-2].join("_")
@resource = resource_a.last
resources = @resource.pluralize
if routes.detect{|r| r.defaults[:action] == "index"}
@index_route = path_prefix + "_#{resources}_path"
end
if routes.detect{|r| r.defaults[:action] == "create"}
@create_route = path_prefix + "_#{@resource}_path"
end
if routes.detect{|r| r.defaults[:action] == "show"}
@show_route = path_prefix + "_#{@resource}_path"
end
if routes.detect{|r| r.defaults[:action] == "update"}
@update_route = path_prefix + "_#{@resource}_path"
end
if routes.detect{|r| r.defaults[:action] == "destroy"}
@destroy_route = path_prefix + "_#{@resource}_path"
end
end
if @index_route
context :index do
include RspecApi
before do
#create_and_sign_in_user
@resources_count = 5 #rand(min..max)
binding.pry
5.times{ FactoryGirl.create(@resource.to_sym) }
get self.send(@index_route.to_sym), format: :json
end
it 'returns the correct status' do
expect(last_response.status).to eql(200)
end
it 'returns the correct number of data in the body' do
body = HashWithIndifferentAccess.new(MultiJson.load(last_response.body))
expect(body[@resource.to_sym].length).to eql(5)
end
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment