Skip to content

Instantly share code, notes, and snippets.

@morhekil
Last active August 29, 2015 14:02
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 morhekil/dafdbba006b4bcf6e485 to your computer and use it in GitHub Desktop.
Save morhekil/dafdbba006b4bcf6e485 to your computer and use it in GitHub Desktop.
Shared examples spec'ing JSON API of a RESTful model backed by Ohm (Redis), for RSpec 3
# Shared examples take a model class as parameters, and expect:
# 1. ``create_attrs`` and ``update_attrs`` to be available in the context.
# 2. ``user`` method to be available in the context, representing currently logged in user.
# 3. Factory to be defined for the model, and ``build`` method to be included into examples.
#
# EXAMPLE
# -------
#
# 1. factories.rb:
# FactoryGirl.define do
# factory :jaeger do
# id { SecureRandom::uuid }
# name { Faker::Name.name }
# year { Faker::Number.number(4) }
# end
# end
#
# 2. jaeger_spec.rb:
#
# # ... bootstrapping, API setup etc
# context 'Jaeger API' do
# let(:create_attrs) { { name: 'Striker Eureka', year: '2019' } }
# let(:update_attrs) { { name: 'Chrome Brutus', year: '2017' } }
#
# it_behaves_like 'a RESTful Ohm resource', Jaeger
# end
#
# This spec also assumes that all requests and responses are JSON data, with model name as the root key, e.g.:
# { jaeger: { name: 'Striker Eureka' } }
#
RSpec.shared_examples "a RESTful Ohm resource" do |model|
let(:path) { '/' + model.to_s.underscore.pluralize }
let(:class_str) { model.to_s.underscore }
let(:class_sym) { class_str.to_sym }
describe 'POST' do
subject(:create_resource) { post path, class_sym => create_attrs }
it 'creates new resource' do
expect { create_resource }.to change { model.all.size }.by(1)
end
describe 'created resource' do
let!(:new_resource) do
old_ids = model.all.ids
create_resource
id = (model.all.ids - old_ids).last
expect(id).to_not be_nil
model[id]
end
it 'returned in the response' do
expect(last_response.status).to eq 201
expect(
JSON.parse(last_response.body)[class_str]
).to represent_entity_of(new_resource)
end
it 'is assigned to the current user' do
expect(new_resource.user).to eq user
end
it 'is given a UUID' do
expect(new_resource.id).to_not be_nil
end
end
end
describe "#{model.to_s.underscore.pluralize}/:id" do
let(:resource) { build(class_sym, user: user).tap(&:save) }
describe 'GET' do
before { get "#{path}/#{resource.id}" }
it 'returns resource data' do
expect(last_response.status).to eq 200
expect(
JSON.parse(last_response.body)[class_str]
).to represent_entity_of(resource)
end
end
describe 'PUT' do
before { put "#{path}/#{resource.id}", class_sym => update_attrs }
it 'updates resource' do
expect(resource.load!.attributes).to include update_attrs
end
it 'returns updated resource data' do
expect(last_response.status).to eq 200
expect(
JSON.parse(last_response.body)[class_str]
).to represent_entity_of(resource.load!)
end
end
describe 'DELETE' do
before { delete "#{path}/#{resource.id}" }
it 'deletes resource' do
expect(model[resource.id]).to be_nil
end
it 'returns deleted resource data' do
expect(last_response.status).to eq 200
expect(
JSON.parse(last_response.body)[class_str]
).to represent_entity_of(resource)
end
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment