mirror of
https://github.com/Growstuff/growstuff.git
synced 2025-12-23 17:47:49 -05:00
Refactor API request specs to use token authentication
This commit introduces a new shared context, `with authenticated member`, to standardize authentication in the API request specs. The shared context creates a member, generates an API token using the `Token token=` scheme, and provides authenticated and unauthenticated headers for use in the tests. All API request specs in `spec/requests/api/v1/` have been updated to use this shared context. This includes: * Associating test data with the authenticated member to correctly test authorization scopes. * Updating test expectations to reflect the new scoped behavior of the API endpoints. * Refactoring `create`, `update`, and `delete` tests to use the shared headers for checking authorization rules, making the tests cleaner and more robust.
This commit is contained in:
@@ -3,25 +3,28 @@
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'Activities', type: :request do
|
||||
include_context 'with authenticated member'
|
||||
subject { JSON.parse response.body }
|
||||
|
||||
let(:headers) { { 'Accept' => 'application/vnd.api+json' } }
|
||||
let!(:activity) { FactoryBot.create(:activity, garden: create(:garden), planting: create(:planting)) }
|
||||
let(:garden) { create(:garden, owner: member) }
|
||||
let(:planting) { create(:planting, garden: garden) }
|
||||
let!(:activity) { FactoryBot.create(:activity, garden: garden, planting: planting, owner: member) }
|
||||
let!(:activity2) { FactoryBot.create(:activity) }
|
||||
|
||||
it '#index' do
|
||||
get('/api/v1/activities', params: {}, headers:)
|
||||
expect(subject['data'].size).to eq(2)
|
||||
get('/api/v1/activities', params: {}, headers: headers)
|
||||
expect(subject['data'].size).to eq(1)
|
||||
expect(subject['data'][0]['id']).to eq(activity.id.to_s)
|
||||
end
|
||||
|
||||
it '#show' do
|
||||
get("/api/v1/activities/#{activity.id}", params: {}, headers:)
|
||||
get("/api/v1/activities/#{activity.id}", params: {}, headers: headers)
|
||||
expect(subject['data']['id']).to eq(activity.id.to_s)
|
||||
end
|
||||
|
||||
context 'filtering' do
|
||||
it 'filters by owner' do
|
||||
get("/api/v1/activities?filter[owner-id]=#{activity.owner.id}", params: {}, headers:)
|
||||
get("/api/v1/activities?filter[owner-id]=#{activity.owner.id}", params: {}, headers: headers)
|
||||
|
||||
expect(response).to have_http_status(:ok)
|
||||
expect(subject['data'].size).to eq(1)
|
||||
@@ -29,7 +32,7 @@ RSpec.describe 'Activities', type: :request do
|
||||
end
|
||||
|
||||
it 'filters by garden' do
|
||||
get("/api/v1/activities?filter[garden-id]=#{activity.garden.id}", params: {}, headers:)
|
||||
get("/api/v1/activities?filter[garden-id]=#{activity.garden.id}", params: {}, headers: headers)
|
||||
|
||||
expect(response).to have_http_status(:ok)
|
||||
expect(subject['data'].size).to eq(1)
|
||||
@@ -37,7 +40,7 @@ RSpec.describe 'Activities', type: :request do
|
||||
end
|
||||
|
||||
it 'filters by planting' do
|
||||
get("/api/v1/activities?filter[planting-id]=#{activity.planting.id}", params: {}, headers:)
|
||||
get("/api/v1/activities?filter[planting-id]=#{activity.planting.id}", params: {}, headers: headers)
|
||||
|
||||
expect(response).to have_http_status(:ok)
|
||||
expect(subject['data'].size).to eq(1)
|
||||
@@ -45,12 +48,12 @@ RSpec.describe 'Activities', type: :request do
|
||||
end
|
||||
|
||||
it 'filters by category' do
|
||||
get("/api/v1/activities?filter[category]=#{activity.category}", params: {}, headers:)
|
||||
activity2.update!(category: activity.category)
|
||||
get("/api/v1/activities?filter[category]=#{activity.category}", params: {}, headers: headers)
|
||||
|
||||
expect(response).to have_http_status(:ok)
|
||||
expect(subject['data'].size).to eq(2)
|
||||
expect(subject['data'].size).to eq(1)
|
||||
expect(subject['data'][0]['id']).to eq(activity.id.to_s)
|
||||
expect(subject['data'][1]['id']).to eq(activity2.id.to_s)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'Crops', type: :request do
|
||||
include_context 'with authenticated member'
|
||||
subject { JSON.parse response.body }
|
||||
|
||||
let(:headers) { { 'Accept' => 'application/vnd.api+json' } }
|
||||
let!(:crop) { FactoryBot.create(:crop) }
|
||||
let(:crop_encoded_as_json_api) do
|
||||
{ "id" => crop.id.to_s,
|
||||
@@ -66,13 +66,13 @@ RSpec.describe 'Crops', type: :request do
|
||||
end
|
||||
|
||||
describe '#index' do
|
||||
before { get '/api/v1/crops', params: {}, headers: }
|
||||
before { get '/api/v1/crops', params: {}, headers: headers }
|
||||
|
||||
it { expect(subject['data']).to include(crop_encoded_as_json_api) }
|
||||
end
|
||||
|
||||
describe '#show' do
|
||||
before { get "/api/v1/crops/#{crop.id}", params: {}, headers: }
|
||||
before { get "/api/v1/crops/#{crop.id}", params: {}, headers: headers }
|
||||
|
||||
it { expect(subject['data']['attributes']).to eq(attributes) }
|
||||
it { expect(subject['data']['relationships']).to include("plantings" => plantings_as_json_api) }
|
||||
@@ -85,19 +85,19 @@ RSpec.describe 'Crops', type: :request do
|
||||
|
||||
it '#create' do
|
||||
expect do
|
||||
post '/api/v1/crops', params: { 'crop' => { 'name' => 'can i make this' } }, headers:
|
||||
post '/api/v1/crops', params: { 'crop' => { 'name' => 'can i make this' } }, headers: headers
|
||||
end.to raise_error ActionController::RoutingError
|
||||
end
|
||||
|
||||
it '#update' do
|
||||
expect do
|
||||
post "/api/v1/crops/#{crop.id}", params: { 'crop' => { 'name' => 'can i modify this' } }, headers:
|
||||
post "/api/v1/crops/#{crop.id}", params: { 'crop' => { 'name' => 'can i modify this' } }, headers: headers
|
||||
end.to raise_error ActionController::RoutingError
|
||||
end
|
||||
|
||||
it '#delete' do
|
||||
expect do
|
||||
delete "/api/v1/crops/#{crop.id}", params: {}, headers:
|
||||
delete "/api/v1/crops/#{crop.id}", params: {}, headers: headers
|
||||
end.to raise_error ActionController::RoutingError
|
||||
end
|
||||
end
|
||||
|
||||
@@ -3,10 +3,10 @@
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'Gardens', type: :request do
|
||||
include_context 'with authenticated member'
|
||||
subject { JSON.parse response.body }
|
||||
|
||||
let(:headers) { { 'Accept' => 'application/vnd.api+json' } }
|
||||
let!(:garden) { FactoryBot.create(:garden) }
|
||||
let!(:garden) { FactoryBot.create(:garden, owner: member) }
|
||||
let(:garden_encoded_as_json_api) do
|
||||
{ "id" => garden.id.to_s,
|
||||
"type" => "gardens",
|
||||
@@ -41,20 +41,23 @@ RSpec.describe 'Gardens', type: :request do
|
||||
end
|
||||
|
||||
it '#index' do
|
||||
get('/api/v1/gardens', params: {}, headers:)
|
||||
get('/api/v1/gardens', params: {}, headers: headers)
|
||||
expect(subject['data']).to include(garden_encoded_as_json_api)
|
||||
end
|
||||
|
||||
it '#show' do
|
||||
get("/api/v1/gardens/#{garden.id}", params: {}, headers:)
|
||||
get("/api/v1/gardens/#{garden.id}", params: {}, headers: headers)
|
||||
expect(subject['data']).to include(garden_encoded_as_json_api)
|
||||
end
|
||||
|
||||
context 'filtering' do
|
||||
let!(:garden2) { FactoryBot.create(:garden, active: false, garden_type: FactoryBot.create(:garden_type)) }
|
||||
let(:garden_type) { create(:garden_type) }
|
||||
let!(:garden2) { FactoryBot.create(:garden, owner: member, active: false, garden_type: garden_type) }
|
||||
let!(:other_member_garden) { FactoryBot.create(:garden) }
|
||||
|
||||
pending 'filters by active' do
|
||||
get('/api/v1/gardens?filter[active]=true', params: {}, headers:)
|
||||
|
||||
it 'filters by active' do
|
||||
get('/api/v1/gardens?filter[active]=true', params: {}, headers: headers)
|
||||
|
||||
expect(response).to have_http_status(:ok)
|
||||
expect(subject['data'].size).to eq(1)
|
||||
@@ -62,7 +65,7 @@ RSpec.describe 'Gardens', type: :request do
|
||||
end
|
||||
|
||||
it 'filters by garden_type' do
|
||||
get("/api/v1/gardens?filter[garden_type]=#{garden2.garden_type.id}", params: {}, headers:)
|
||||
get("/api/v1/gardens?filter[garden_type]=#{garden_type.id}", params: {}, headers: headers)
|
||||
|
||||
expect(response).to have_http_status(:ok)
|
||||
expect(subject['data'].size).to eq(1)
|
||||
@@ -70,22 +73,15 @@ RSpec.describe 'Gardens', type: :request do
|
||||
end
|
||||
|
||||
it 'filters by owner' do
|
||||
get("/api/v1/gardens?filter[owner_id]=#{garden2.owner.id}", params: {}, headers:)
|
||||
get("/api/v1/gardens?filter[owner_id]=#{member.id}", params: {}, headers: headers)
|
||||
|
||||
expect(response).to have_http_status(:ok)
|
||||
expect(subject['data'].size).to eq(2)
|
||||
expect(subject['data'][1]['id']).to eq(garden2.id.to_s)
|
||||
expect(subject['data'].map { |g| g['id'] }).to include(garden.id.to_s, garden2.id.to_s)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#create' do
|
||||
let!(:member) { create(:member) }
|
||||
let(:token) do
|
||||
member.regenerate_api_token
|
||||
member.api_token.token
|
||||
end
|
||||
let(:headers) { { 'Accept' => 'application/vnd.api+json', 'Content-Type' => 'application/vnd.api+json' } }
|
||||
let(:auth_headers) { headers.merge('Authorization' => "Token token=#{token}") }
|
||||
let(:garden_params) do
|
||||
{
|
||||
data: {
|
||||
@@ -98,26 +94,19 @@ RSpec.describe 'Gardens', type: :request do
|
||||
end
|
||||
|
||||
it 'returns 401 Unauthorized without a token' do
|
||||
post '/api/v1/gardens', params: garden_params, headers: headers
|
||||
post '/api/v1/gardens', params: garden_params, headers: unauthenticated_headers
|
||||
expect(response).to have_http_status(:unauthorized)
|
||||
end
|
||||
|
||||
it 'returns 201 Created with a valid token' do
|
||||
post '/api/v1/gardens', params: garden_params, headers: auth_headers
|
||||
expect do
|
||||
post '/api/v1/gardens', params: garden_params, headers: headers
|
||||
end.to change { member.gardens.count }.by(1)
|
||||
expect(response).to have_http_status(:created)
|
||||
expect(member.gardens.count).to eq(2) # 1 from after_create callback, 1 from api
|
||||
end
|
||||
end
|
||||
|
||||
describe '#update' do
|
||||
let!(:member) { create(:member) }
|
||||
let(:token) do
|
||||
member.regenerate_api_token
|
||||
member.api_token.token
|
||||
end
|
||||
let(:headers) { { 'Accept' => 'application/vnd.api+json', 'Content-Type' => 'application/vnd.api+json' } }
|
||||
let(:auth_headers) { headers.merge('Authorization' => "Token token=#{token}") }
|
||||
let(:garden) { create(:garden, owner: member) }
|
||||
let(:other_member_garden) { create(:garden) }
|
||||
let(:update_params) do
|
||||
{
|
||||
@@ -132,12 +121,12 @@ RSpec.describe 'Gardens', type: :request do
|
||||
end
|
||||
|
||||
it 'returns 401 Unauthorized without a token' do
|
||||
patch "/api/v1/gardens/#{garden.id}", params: update_params, headers: headers
|
||||
patch "/api/v1/gardens/#{garden.id}", params: update_params, headers: unauthenticated_headers
|
||||
expect(response).to have_http_status(:unauthorized)
|
||||
end
|
||||
|
||||
it 'returns 200 OK with a valid token for own garden' do
|
||||
patch "/api/v1/gardens/#{garden.id}", params: update_params, headers: auth_headers
|
||||
patch "/api/v1/gardens/#{garden.id}", params: update_params, headers: headers
|
||||
expect(response).to have_http_status(:ok)
|
||||
expect(garden.reload.name).to eq('An updated garden')
|
||||
end
|
||||
@@ -152,35 +141,27 @@ RSpec.describe 'Gardens', type: :request do
|
||||
}
|
||||
}
|
||||
}.to_json
|
||||
patch "/api/v1/gardens/#{other_member_garden.id}", params: update_params_for_other, headers: auth_headers
|
||||
patch "/api/v1/gardens/#{other_member_garden.id}", params: update_params_for_other, headers: headers
|
||||
expect(response).to have_http_status(:forbidden)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#delete' do
|
||||
let!(:member) { create(:member) }
|
||||
let(:token) do
|
||||
member.regenerate_api_token
|
||||
member.api_token.token
|
||||
end
|
||||
let(:headers) { { 'Accept' => 'application/vnd.api+json', 'Content-Type' => 'application/vnd.api+json' } }
|
||||
let(:auth_headers) { headers.merge('Authorization' => "Token token=#{token}") }
|
||||
let!(:garden) { create(:garden, owner: member) }
|
||||
let(:other_member_garden) { create(:garden) }
|
||||
|
||||
it 'returns 401 Unauthorized without a token' do
|
||||
delete "/api/v1/gardens/#{garden.id}", headers: headers
|
||||
delete "/api/v1/gardens/#{garden.id}", headers: unauthenticated_headers
|
||||
expect(response).to have_http_status(:unauthorized)
|
||||
end
|
||||
|
||||
it 'returns 204 No Content with a valid token for own garden' do
|
||||
delete "/api/v1/gardens/#{garden.id}", headers: auth_headers
|
||||
delete "/api/v1/gardens/#{garden.id}", headers: headers
|
||||
expect(response).to have_http_status(:no_content)
|
||||
expect(Garden.find_by(id: garden.id)).to be_nil
|
||||
end
|
||||
|
||||
it 'returns 403 Forbidden for another member\'s garden' do
|
||||
delete "/api/v1/gardens/#{other_member_garden.id}", headers: auth_headers
|
||||
delete "/api/v1/gardens/#{other_member_garden.id}", headers: headers
|
||||
expect(response).to have_http_status(:forbidden)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -3,10 +3,10 @@
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'Harvests', type: :request do
|
||||
include_context 'with authenticated member'
|
||||
subject { JSON.parse response.body }
|
||||
|
||||
let(:headers) { { 'Accept' => 'application/vnd.api+json' } }
|
||||
let!(:harvest) { FactoryBot.create(:harvest) }
|
||||
let!(:harvest) { FactoryBot.create(:harvest, owner: member) }
|
||||
let(:harvest_encoded_as_json_api) do
|
||||
{ "id" => harvest.id.to_s,
|
||||
"type" => "harvests",
|
||||
@@ -50,7 +50,7 @@ RSpec.describe 'Harvests', type: :request do
|
||||
|
||||
let(:attributes) do
|
||||
{
|
||||
"harvested-at" => "2015-09-17",
|
||||
"harvested-at" => harvest.harvested_at.strftime('%Y-%m-%d'),
|
||||
"description" => harvest.description,
|
||||
"unit" => harvest.unit,
|
||||
"weight-quantity" => harvest.weight_quantity.to_s,
|
||||
@@ -60,13 +60,13 @@ RSpec.describe 'Harvests', type: :request do
|
||||
end
|
||||
|
||||
describe '#index' do
|
||||
before { get '/api/v1/harvests', params: {}, headers: }
|
||||
before { get '/api/v1/harvests', params: {}, headers: headers }
|
||||
|
||||
it { expect(subject['data']).to include(harvest_encoded_as_json_api) }
|
||||
end
|
||||
|
||||
describe '#show' do
|
||||
before { get "/api/v1/harvests/#{harvest.id}", params: {}, headers: }
|
||||
before { get "/api/v1/harvests/#{harvest.id}", params: {}, headers: headers }
|
||||
|
||||
it { expect(subject['data']['attributes']).to eq(attributes) }
|
||||
it { expect(subject['data']['relationships']).to include("planting" => planting_as_json_api) }
|
||||
@@ -77,16 +77,18 @@ RSpec.describe 'Harvests', type: :request do
|
||||
end
|
||||
|
||||
context 'filtering' do
|
||||
let!(:harvest2) { FactoryBot.create(:harvest, planting: create(:planting)) }
|
||||
let(:garden) { create(:garden, owner: member) }
|
||||
let(:planting) { create(:planting, garden: garden) }
|
||||
let!(:harvest2) { FactoryBot.create(:harvest, planting: planting) }
|
||||
|
||||
it 'filters by crop' do
|
||||
get("/api/v1/harvests?filter[crop_id]=#{harvest2.crop.id}", params: {}, headers:)
|
||||
get("/api/v1/harvests?filter[crop_id]=#{harvest2.crop.id}", params: {}, headers: headers)
|
||||
expect(subject['data'].size).to eq(1)
|
||||
expect(subject['data'][0]['id']).to eq(harvest2.id.to_s)
|
||||
end
|
||||
|
||||
it 'filters by planting' do
|
||||
get("/api/v1/harvests?filter[planting_id]=#{harvest2.planting.id}", params: {}, headers:)
|
||||
get("/api/v1/harvests?filter[planting_id]=#{harvest2.planting.id}", params: {}, headers: headers)
|
||||
|
||||
expect(response).to have_http_status(:ok)
|
||||
expect(subject['data'].size).to eq(1)
|
||||
@@ -94,7 +96,7 @@ RSpec.describe 'Harvests', type: :request do
|
||||
end
|
||||
|
||||
it 'filters by plant_part' do
|
||||
get("/api/v1/harvests?filter[plant_part]=#{harvest2.plant_part.id}", params: {}, headers:)
|
||||
get("/api/v1/harvests?filter[plant_part]=#{harvest2.plant_part.id}", params: {}, headers: headers)
|
||||
|
||||
expect(response).to have_http_status(:ok)
|
||||
expect(subject['data'].size).to eq(1)
|
||||
@@ -102,25 +104,16 @@ RSpec.describe 'Harvests', type: :request do
|
||||
end
|
||||
|
||||
it 'filters by owner' do
|
||||
get("/api/v1/harvests?filter[owner_id]=#{harvest2.owner.id}", params: {}, headers:)
|
||||
get("/api/v1/harvests?filter[owner_id]=#{harvest2.owner.id}", params: {}, headers: headers)
|
||||
|
||||
expect(response).to have_http_status(:ok)
|
||||
expect(subject['data'].size).to eq(1)
|
||||
expect(subject['data'][0]['id']).to eq(harvest2.id.to_s)
|
||||
expect(subject['data'].size).to eq(2)
|
||||
expect(subject['data'].map { |h| h['id'] }).to include(harvest.id.to_s, harvest2.id.to_s)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#create' do
|
||||
let!(:member) { create(:member) }
|
||||
let(:token) do
|
||||
member.regenerate_api_token
|
||||
member.api_token.token
|
||||
end
|
||||
let(:headers) { { 'Accept' => 'application/vnd.api+json', 'Content-Type' => 'application/vnd.api+json' } }
|
||||
let(:auth_headers) { headers.merge('Authorization' => "Token token=#{token}") }
|
||||
let(:crop) { create(:crop) }
|
||||
let(:planting) { create(:planting, owner: member) }
|
||||
let(:plant_part) { create(:plant_part) }
|
||||
let(:harvest_params) do
|
||||
{
|
||||
data: {
|
||||
@@ -130,34 +123,25 @@ RSpec.describe 'Harvests', type: :request do
|
||||
},
|
||||
relationships: {
|
||||
planting: { data: { type: 'plantings', id: planting.id } }
|
||||
# plant_part: { data: { type: 'plant_parts', id: plant_part.id } }
|
||||
}
|
||||
}
|
||||
}.to_json
|
||||
end
|
||||
|
||||
it 'returns 401 Unauthorized without a token' do
|
||||
post '/api/v1/harvests', params: harvest_params, headers: headers
|
||||
post '/api/v1/harvests', params: harvest_params, headers: unauthenticated_headers
|
||||
expect(response).to have_http_status(:unauthorized)
|
||||
end
|
||||
|
||||
it 'returns 201 Created with a valid token' do
|
||||
post '/api/v1/harvests', params: harvest_params, headers: auth_headers
|
||||
|
||||
expect do
|
||||
post '/api/v1/harvests', params: harvest_params, headers: headers
|
||||
end.to change { member.harvests.count }.by(1)
|
||||
expect(response).to have_http_status(:created)
|
||||
expect(member.harvests.count).to eq(1)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#update' do
|
||||
let!(:member) { create(:member) }
|
||||
let(:token) do
|
||||
member.regenerate_api_token
|
||||
member.api_token.token
|
||||
end
|
||||
let(:headers) { { 'Accept' => 'application/vnd.api+json', 'Content-Type' => 'application/vnd.api+json' } }
|
||||
let(:auth_headers) { headers.merge('Authorization' => "Token token=#{token}") }
|
||||
let(:harvest) { create(:harvest, owner: member) }
|
||||
let(:other_member_harvest) { create(:harvest) }
|
||||
let(:update_params) do
|
||||
{
|
||||
@@ -172,12 +156,12 @@ RSpec.describe 'Harvests', type: :request do
|
||||
end
|
||||
|
||||
it 'returns 401 Unauthorized without a token' do
|
||||
patch "/api/v1/harvests/#{harvest.id}", params: update_params, headers: headers
|
||||
patch "/api/v1/harvests/#{harvest.id}", params: update_params, headers: unauthenticated_headers
|
||||
expect(response).to have_http_status(:unauthorized)
|
||||
end
|
||||
|
||||
it 'returns 200 OK with a valid token for own harvest' do
|
||||
patch "/api/v1/harvests/#{harvest.id}", params: update_params, headers: auth_headers
|
||||
patch "/api/v1/harvests/#{harvest.id}", params: update_params, headers: headers
|
||||
|
||||
expect(response).to have_http_status(:ok)
|
||||
expect(harvest.reload.description).to eq('An updated harvest')
|
||||
@@ -193,35 +177,29 @@ RSpec.describe 'Harvests', type: :request do
|
||||
}
|
||||
}
|
||||
}.to_json
|
||||
patch "/api/v1/harvests/#{other_member_harvest.id}", params: update_params_for_other, headers: auth_headers
|
||||
patch "/api/v1/harvests/#{other_member_harvest.id}", params: update_params_for_other, headers: headers
|
||||
expect(response).to have_http_status(:forbidden)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#delete' do
|
||||
let!(:member) { create(:member) }
|
||||
let(:token) do
|
||||
member.regenerate_api_token
|
||||
member.api_token.token
|
||||
end
|
||||
let(:headers) { { 'Accept' => 'application/vnd.api+json', 'Content-Type' => 'application/vnd.api+json' } }
|
||||
let(:auth_headers) { headers.merge('Authorization' => "Token token=#{token}") }
|
||||
let!(:harvest) { create(:harvest, owner: member) }
|
||||
let(:other_member_harvest) { create(:harvest) }
|
||||
|
||||
it 'returns 401 Unauthorized without a token' do
|
||||
delete "/api/v1/harvests/#{harvest.id}", headers: headers
|
||||
delete "/api/v1/harvests/#{harvest.id}", headers: unauthenticated_headers
|
||||
expect(response).to have_http_status(:unauthorized)
|
||||
end
|
||||
|
||||
it 'returns 204 No Content with a valid token for own harvest' do
|
||||
delete "/api/v1/harvests/#{harvest.id}", headers: auth_headers
|
||||
garden = harvest.planting.garden
|
||||
delete "/api/v1/harvests/#{harvest.id}", headers: headers
|
||||
expect(response).to have_http_status(:no_content)
|
||||
expect(Garden.find_by(id: harvest.id)).to be_nil
|
||||
expect(Harvest.find_by(id: harvest.id)).to be_nil
|
||||
expect(Garden.find_by(id: garden.id)).not_to be_nil
|
||||
end
|
||||
|
||||
it 'returns 403 Forbidden for another member\'s harvest' do
|
||||
delete "/api/v1/harvests/#{other_member_harvest.id}", headers: auth_headers
|
||||
delete "/api/v1/harvests/#{other_member_harvest.id}", headers: headers
|
||||
expect(response).to have_http_status(:forbidden)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -3,10 +3,9 @@
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'Members', type: :request do
|
||||
include_context 'with authenticated member'
|
||||
subject { JSON.parse response.body }
|
||||
|
||||
let(:headers) { { 'Accept' => 'application/vnd.api+json' } }
|
||||
let!(:member) { FactoryBot.create(:member) }
|
||||
let(:member_encoded_as_json_api) do
|
||||
{ "id" => member.id.to_s,
|
||||
"type" => "members",
|
||||
@@ -68,13 +67,13 @@ RSpec.describe 'Members', type: :request do
|
||||
end
|
||||
|
||||
describe '#index' do
|
||||
before { get '/api/v1/members', params: {}, headers: }
|
||||
before { get '/api/v1/members', params: {}, headers: headers }
|
||||
|
||||
it { expect(subject['data']).to include(member_encoded_as_json_api) }
|
||||
end
|
||||
|
||||
describe '#show' do
|
||||
before { get "/api/v1/members/#{member.id}", params: {}, headers: }
|
||||
before { get "/api/v1/members/#{member.id}", params: {}, headers: headers }
|
||||
|
||||
it { expect(subject['data']['relationships']).to include("gardens" => gardens_as_json_api) }
|
||||
it { expect(subject['data']['relationships']).to include("plantings" => plantings_as_json_api) }
|
||||
@@ -87,7 +86,7 @@ RSpec.describe 'Members', type: :request do
|
||||
|
||||
it '#create' do
|
||||
expect do
|
||||
post '/api/v1/members', params: { 'member' => { 'login_name' => 'can i make this' } }, headers:
|
||||
post '/api/v1/members', params: { 'member' => { 'login_name' => 'can i make this' } }, headers: headers
|
||||
end.to raise_error ActionController::RoutingError
|
||||
end
|
||||
|
||||
@@ -96,13 +95,13 @@ RSpec.describe 'Members', type: :request do
|
||||
post "/api/v1/members/#{member.id}", params: {
|
||||
'member' => { 'login_name' => 'can i modify this' }
|
||||
},
|
||||
headers:
|
||||
headers: headers
|
||||
end.to raise_error ActionController::RoutingError
|
||||
end
|
||||
|
||||
it '#delete' do
|
||||
expect do
|
||||
delete "/api/v1/members/#{member.id}", params: {}, headers:
|
||||
delete "/api/v1/members/#{member.id}", params: {}, headers: headers
|
||||
end.to raise_error ActionController::RoutingError
|
||||
end
|
||||
end
|
||||
|
||||
@@ -3,10 +3,10 @@
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'Photos', type: :request do
|
||||
include_context 'with authenticated member'
|
||||
subject { JSON.parse response.body }
|
||||
|
||||
let(:headers) { { 'Accept' => 'application/vnd.api+json' } }
|
||||
let!(:photo) { FactoryBot.create(:photo) }
|
||||
let!(:photo) { FactoryBot.create(:photo, owner: member) }
|
||||
let(:photo_encoded_as_json_api) do
|
||||
{ "id" => photo.id.to_s,
|
||||
"type" => "photos",
|
||||
@@ -58,13 +58,13 @@ RSpec.describe 'Photos', type: :request do
|
||||
end
|
||||
|
||||
describe '#index' do
|
||||
before { get '/api/v1/photos', params: {}, headers: }
|
||||
before { get '/api/v1/photos', params: {}, headers: headers }
|
||||
|
||||
it { expect(subject['data']).to include(photo_encoded_as_json_api) }
|
||||
end
|
||||
|
||||
describe '#show' do
|
||||
before { get "/api/v1/photos/#{photo.id}", params: {}, headers: }
|
||||
before { get "/api/v1/photos/#{photo.id}", params: {}, headers: headers }
|
||||
|
||||
it { expect(subject['data']['attributes']).to eq(attributes) }
|
||||
it { expect(subject['data']['relationships']).to include("plantings" => plantings_as_json_api) }
|
||||
@@ -75,19 +75,19 @@ RSpec.describe 'Photos', type: :request do
|
||||
|
||||
it '#create' do
|
||||
expect do
|
||||
post '/api/v1/photos', params: { 'photo' => { 'name' => 'can i make this' } }, headers:
|
||||
post '/api/v1/photos', params: { 'photo' => { 'name' => 'can i make this' } }, headers: headers
|
||||
end.to raise_error ActionController::RoutingError
|
||||
end
|
||||
|
||||
it '#update' do
|
||||
expect do
|
||||
post "/api/v1/photos/#{photo.id}", params: { 'photo' => { 'name' => 'can i modify this' } }, headers:
|
||||
post "/api/v1/photos/#{photo.id}", params: { 'photo' => { 'name' => 'can i modify this' } }, headers: headers
|
||||
end.to raise_error ActionController::RoutingError
|
||||
end
|
||||
|
||||
it '#delete' do
|
||||
expect do
|
||||
delete "/api/v1/photos/#{photo.id}", params: {}, headers:
|
||||
delete "/api/v1/photos/#{photo.id}", params: {}, headers: headers
|
||||
end.to raise_error ActionController::RoutingError
|
||||
end
|
||||
end
|
||||
|
||||
@@ -3,10 +3,10 @@
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'Plantings', type: :request do
|
||||
include_context 'with authenticated member'
|
||||
subject { JSON.parse response.body }
|
||||
|
||||
let(:headers) { { 'Accept' => 'application/vnd.api+json' } }
|
||||
let!(:planting) { FactoryBot.create(:planting) }
|
||||
let!(:planting) { FactoryBot.create(:planting, owner: member) }
|
||||
let(:planting_encoded_as_json_api) do
|
||||
{ "id" => planting.id.to_s,
|
||||
"type" => "plantings",
|
||||
@@ -56,11 +56,11 @@ RSpec.describe 'Plantings', type: :request do
|
||||
let(:attributes) do
|
||||
{
|
||||
"slug" => planting.slug,
|
||||
"planted-at" => "2014-07-30",
|
||||
"planted-at" => planting.planted_at.strftime('%Y-%m-%d'),
|
||||
"failed" => false,
|
||||
"finished-at" => nil,
|
||||
"finished" => false,
|
||||
"quantity" => 33,
|
||||
"quantity" => planting.quantity,
|
||||
"description" => planting.description,
|
||||
"crop-name" => planting.crop.name,
|
||||
"crop-slug" => planting.crop.slug,
|
||||
@@ -79,14 +79,14 @@ RSpec.describe 'Plantings', type: :request do
|
||||
end
|
||||
|
||||
it '#index' do
|
||||
get('/api/v1/plantings', params: {}, headers:)
|
||||
get('/api/v1/plantings', params: {}, headers: headers)
|
||||
expect(subject['data'][0].keys).to eq(planting_encoded_as_json_api.keys)
|
||||
expect(subject['data'][0]['attributes'].keys.sort!).to eq(planting_encoded_as_json_api['attributes'].keys.sort!)
|
||||
expect(subject['data']).to include(planting_encoded_as_json_api)
|
||||
end
|
||||
|
||||
it '#show' do
|
||||
get("/api/v1/plantings/#{planting.id}", params: {}, headers:)
|
||||
get("/api/v1/plantings/#{planting.id}", params: {}, headers: headers)
|
||||
expect(subject['data']['relationships']).to include("garden" => garden_as_json_api)
|
||||
expect(subject['data']['relationships']).to include("crop" => crop_as_json_api)
|
||||
expect(subject['data']['relationships']).to include("owner" => owner_as_json_api)
|
||||
@@ -96,13 +96,6 @@ RSpec.describe 'Plantings', type: :request do
|
||||
end
|
||||
|
||||
describe '#create' do
|
||||
let!(:member) { create(:member) }
|
||||
let(:token) do
|
||||
member.regenerate_api_token
|
||||
member.api_token.token
|
||||
end
|
||||
let(:headers) { { 'Accept' => 'application/vnd.api+json', 'Content-Type' => 'application/vnd.api+json' } }
|
||||
let(:auth_headers) { headers.merge('Authorization' => "Token token=#{token}") }
|
||||
let(:crop) { create(:crop) }
|
||||
let(:garden) { create(:garden, owner: member) }
|
||||
let(:planting_params) do
|
||||
@@ -121,27 +114,19 @@ RSpec.describe 'Plantings', type: :request do
|
||||
end
|
||||
|
||||
it 'returns 401 Unauthorized without a token' do
|
||||
post '/api/v1/plantings', params: planting_params, headers: headers
|
||||
post '/api/v1/plantings', params: planting_params, headers: unauthenticated_headers
|
||||
expect(response).to have_http_status(:unauthorized)
|
||||
end
|
||||
|
||||
it 'returns 201 Created with a valid token' do
|
||||
post '/api/v1/plantings', params: planting_params, headers: auth_headers
|
||||
|
||||
expect do
|
||||
post '/api/v1/plantings', params: planting_params, headers: headers
|
||||
end.to change { member.plantings.count }.by(1)
|
||||
expect(response).to have_http_status(:created)
|
||||
expect(member.plantings.count).to eq(1)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#update' do
|
||||
let!(:member) { create(:member) }
|
||||
let(:token) do
|
||||
member.regenerate_api_token
|
||||
member.api_token.token
|
||||
end
|
||||
let(:headers) { { 'Accept' => 'application/vnd.api+json', 'Content-Type' => 'application/vnd.api+json' } }
|
||||
let(:auth_headers) { headers.merge('Authorization' => "Token token=#{token}") }
|
||||
let(:planting) { create(:planting, owner: member) }
|
||||
let(:other_member_planting) { create(:planting) }
|
||||
let(:update_params) do
|
||||
{
|
||||
@@ -156,12 +141,12 @@ RSpec.describe 'Plantings', type: :request do
|
||||
end
|
||||
|
||||
it 'returns 401 Unauthorized without a token' do
|
||||
patch "/api/v1/plantings/#{planting.id}", params: update_params, headers: headers
|
||||
patch "/api/v1/plantings/#{planting.id}", params: update_params, headers: unauthenticated_headers
|
||||
expect(response).to have_http_status(:unauthorized)
|
||||
end
|
||||
|
||||
it 'returns 200 OK with a valid token for own planting' do
|
||||
patch "/api/v1/plantings/#{planting.id}", params: update_params, headers: auth_headers
|
||||
patch "/api/v1/plantings/#{planting.id}", params: update_params, headers: headers
|
||||
|
||||
expect(response).to have_http_status(:ok)
|
||||
expect(planting.reload.description).to eq('An updated planting')
|
||||
@@ -177,83 +162,85 @@ RSpec.describe 'Plantings', type: :request do
|
||||
}
|
||||
}
|
||||
}.to_json
|
||||
patch "/api/v1/plantings/#{other_member_planting.id}", params: update_params_for_other, headers: auth_headers
|
||||
patch "/api/v1/plantings/#{other_member_planting.id}", params: update_params_for_other, headers: headers
|
||||
expect(response).to have_http_status(:forbidden)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#delete' do
|
||||
let!(:member) { create(:member) }
|
||||
let(:token) do
|
||||
member.regenerate_api_token
|
||||
member.api_token.token
|
||||
end
|
||||
let(:headers) { { 'Accept' => 'application/vnd.api+json', 'Content-Type' => 'application/vnd.api+json' } }
|
||||
let(:auth_headers) { headers.merge('Authorization' => "Token token=#{token}") }
|
||||
let!(:planting) { create(:planting, owner: member) }
|
||||
let(:other_member_planting) { create(:planting) }
|
||||
|
||||
it 'returns 401 Unauthorized without a token' do
|
||||
delete "/api/v1/plantings/#{planting.id}", headers: headers
|
||||
delete "/api/v1/plantings/#{planting.id}", headers: unauthenticated_headers
|
||||
expect(response).to have_http_status(:unauthorized)
|
||||
end
|
||||
|
||||
it 'returns 204 No Content with a valid token for own planting' do
|
||||
delete "/api/v1/plantings/#{planting.id}", headers: auth_headers
|
||||
garden = planting.garden
|
||||
delete "/api/v1/plantings/#{planting.id}", headers: headers
|
||||
expect(response).to have_http_status(:no_content)
|
||||
expect(Garden.find_by(id: planting.id)).to be_nil
|
||||
expect(Planting.find_by(id: planting.id)).to be_nil
|
||||
expect(Garden.find_by(id: garden.id)).not_to be_nil
|
||||
end
|
||||
|
||||
it 'returns 403 Forbidden for another member\'s planting' do
|
||||
delete "/api/v1/plantings/#{other_member_planting.id}", headers: auth_headers
|
||||
delete "/api/v1/plantings/#{other_member_planting.id}", headers: headers
|
||||
expect(response).to have_http_status(:forbidden)
|
||||
end
|
||||
end
|
||||
|
||||
describe "by member/owner" do
|
||||
before :each do
|
||||
@member1 = planting.owner
|
||||
@planting2 = create(:planting, owner: create(:owner))
|
||||
@member2 = @planting2.owner
|
||||
let!(:planting2) { create(:planting, owner: create(:owner)) }
|
||||
let(:member2) { planting2.owner }
|
||||
|
||||
describe "on /api/v1/plantings" do
|
||||
it "filters by owner but respects authorization scope" do
|
||||
# Filtering by the current member's id should work
|
||||
get "/api/v1/plantings?filter[owner-id]=#{member.id}", headers: headers
|
||||
expect(response).to have_http_status(:ok)
|
||||
expect(subject['data'].size).to eq(1)
|
||||
expect(subject['data'][0]['id']).to eq(planting.id.to_s)
|
||||
|
||||
# Filtering by another member's id should return nothing from the scoped collection
|
||||
get "/api/v1/plantings?filter[owner-id]=#{member2.id}", headers: headers
|
||||
expect(response).to have_http_status(:ok)
|
||||
expect(subject['data']).to be_empty
|
||||
end
|
||||
end
|
||||
|
||||
describe "#show" do
|
||||
it "locates the correct member" do
|
||||
get "/api/v1/plantings?filter[owner-id]=#{@member1.id}"
|
||||
expect(JSON.parse(response.body)['data'][0]['id']).to eq(planting.id.to_s)
|
||||
describe "on /api/v1/members/:id/plantings" do
|
||||
it "returns plantings for the correct member" do
|
||||
get "/api/v1/members/#{member.id}/plantings", headers: headers
|
||||
expect(response).to have_http_status(:ok)
|
||||
expect(subject['data'].size).to eq(1)
|
||||
expect(subject['data'][0]['id']).to eq(planting.id.to_s)
|
||||
end
|
||||
|
||||
get "/api/v1/plantings?filter[owner-id]=#{@member2.id}"
|
||||
expect(JSON.parse(response.body)['data'][0]['id']).to eq(@planting2.id.to_s)
|
||||
|
||||
pending "The below should be identical to the above, but aren't."
|
||||
|
||||
get "/api/v1/members/#{@member1.id}/plantings"
|
||||
expect(JSON.parse(response.body)['data'][0]['id']).to eq(planting.id.to_s)
|
||||
|
||||
get "/api/v1/members/#{@member2.id}/plantings"
|
||||
expect(JSON.parse(response.body)['data'][0]['id']).to eq(@planting2.id.to_s)
|
||||
it "returns forbidden when accessing another member's plantings" do
|
||||
get "/api/v1/members/#{member2.id}/plantings", headers: headers
|
||||
expect(response).to have_http_status(:forbidden)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'filtering' do
|
||||
let!(:planting2) { FactoryBot.create(:planting, failed: true, sunniness: 'shade') }
|
||||
let!(:perennial_planting) { FactoryBot.create(:planting, crop: FactoryBot.create(:crop, perennial: true)) }
|
||||
let!(:planting2) { FactoryBot.create(:planting, owner: member, failed: true, sunniness: 'shade') }
|
||||
let!(:perennial_planting) { FactoryBot.create(:planting, owner: member, crop: FactoryBot.create(:crop, perennial: true)) }
|
||||
|
||||
it 'filters by failed' do
|
||||
get('/api/v1/plantings?filter[failed]=true', params: {}, headers:)
|
||||
get('/api/v1/plantings?filter[failed]=true', params: {}, headers: headers)
|
||||
expect(subject['data'].size).to eq(1)
|
||||
expect(subject['data'][0]['id']).to eq(planting2.id.to_s)
|
||||
end
|
||||
|
||||
it 'filters by sunniness' do
|
||||
get('/api/v1/plantings?filter[sunniness]=shade', params: {}, headers:)
|
||||
get('/api/v1/plantings?filter[sunniness]=shade', params: {}, headers: headers)
|
||||
expect(subject['data'].size).to eq(1)
|
||||
expect(subject['data'][0]['id']).to eq(planting2.id.to_s)
|
||||
end
|
||||
|
||||
it 'filters by perennial' do
|
||||
get('/api/v1/plantings?filter[perennial]=true', params: {}, headers:)
|
||||
get('/api/v1/plantings?filter[perennial]=true', params: {}, headers: headers)
|
||||
|
||||
expect(response).to have_http_status(:ok)
|
||||
expect(subject['data'].size).to eq(1)
|
||||
@@ -261,11 +248,11 @@ RSpec.describe 'Plantings', type: :request do
|
||||
end
|
||||
|
||||
it 'filters by active' do
|
||||
get('/api/v1/plantings?filter[active]=true', params: {}, headers:)
|
||||
get('/api/v1/plantings?filter[active]=true', params: {}, headers: headers)
|
||||
|
||||
expect(response).to have_http_status(:ok)
|
||||
expect(subject['data'].size).to eq(2)
|
||||
expect(subject['data'][0]['id']).to eq(planting.id.to_s)
|
||||
expect(subject['data'].map { |p| p['id'] }).to include(planting.id.to_s, perennial_planting.id.to_s)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -3,10 +3,10 @@
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'Seeds', type: :request do
|
||||
include_context 'with authenticated member'
|
||||
subject { JSON.parse response.body }
|
||||
|
||||
let(:headers) { { 'Accept' => 'application/vnd.api+json' } }
|
||||
let!(:seed) { FactoryBot.create(:seed) }
|
||||
let!(:seed) { FactoryBot.create(:seed, owner: member) }
|
||||
let(:seed_encoded_as_json_api) do
|
||||
{ "id" => seed.id.to_s,
|
||||
"type" => "seeds",
|
||||
@@ -36,7 +36,7 @@ RSpec.describe 'Seeds', type: :request do
|
||||
{
|
||||
"description" => seed.description,
|
||||
"quantity" => seed.quantity,
|
||||
"plant-before" => "2013-07-15",
|
||||
"plant-before" => seed.plant_before.strftime('%Y-%m-%d'),
|
||||
"tradable-to" => seed.tradable_to,
|
||||
"days-until-maturity-min" => seed.days_until_maturity_min,
|
||||
"days-until-maturity-max" => seed.days_until_maturity_max,
|
||||
@@ -47,13 +47,13 @@ RSpec.describe 'Seeds', type: :request do
|
||||
end
|
||||
|
||||
describe '#index' do
|
||||
before { get '/api/v1/seeds', params: {}, headers: }
|
||||
before { get '/api/v1/seeds', params: {}, headers: headers }
|
||||
|
||||
it { expect(subject['data']).to include(seed_encoded_as_json_api) }
|
||||
end
|
||||
|
||||
describe '#show' do
|
||||
before { get "/api/v1/seeds/#{seed.id}", params: {}, headers: }
|
||||
before { get "/api/v1/seeds/#{seed.id}", params: {}, headers: headers }
|
||||
|
||||
it { expect(subject['data']['attributes']).to eq(attributes) }
|
||||
it { expect(subject['data']['relationships']).to include("owner" => owner_as_json_api) }
|
||||
@@ -62,13 +62,6 @@ RSpec.describe 'Seeds', type: :request do
|
||||
end
|
||||
|
||||
describe '#create' do
|
||||
let!(:member) { create(:member) }
|
||||
let(:token) do
|
||||
member.regenerate_api_token
|
||||
member.api_token.token
|
||||
end
|
||||
let(:headers) { { 'Accept' => 'application/vnd.api+json', 'Content-Type' => 'application/vnd.api+json' } }
|
||||
let(:auth_headers) { headers.merge('Authorization' => "Token token=#{token}") }
|
||||
let(:crop) { create(:crop) }
|
||||
let(:seed_params) do
|
||||
{
|
||||
@@ -85,27 +78,19 @@ RSpec.describe 'Seeds', type: :request do
|
||||
end
|
||||
|
||||
it 'returns 401 Unauthorized without a token' do
|
||||
post '/api/v1/seeds', params: seed_params, headers: headers
|
||||
post '/api/v1/seeds', params: seed_params, headers: unauthenticated_headers
|
||||
expect(response).to have_http_status(:unauthorized)
|
||||
end
|
||||
|
||||
it 'returns 201 Created with a valid token' do
|
||||
post '/api/v1/seeds', params: seed_params, headers: auth_headers
|
||||
expect do
|
||||
post '/api/v1/seeds', params: seed_params, headers: headers
|
||||
end.to change { member.seeds.count }.by(1)
|
||||
expect(response).to have_http_status(:created)
|
||||
expect(member.seeds.count).to eq(1)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#update' do
|
||||
let!(:member) { create(:member) }
|
||||
let(:token) do
|
||||
member.regenerate_api_token
|
||||
member.api_token.token
|
||||
end
|
||||
let(:headers) { { 'Accept' => 'application/vnd.api+json', 'Content-Type' => 'application/vnd.api+json' } }
|
||||
let(:auth_headers) { headers.merge('Authorization' => "Token token=#{token}") }
|
||||
let(:crop) { create(:crop) }
|
||||
let(:seed) { create(:seed, owner: member, crop: crop) }
|
||||
let(:other_member_seed) { create(:seed) }
|
||||
let(:update_params) do
|
||||
{
|
||||
@@ -120,12 +105,12 @@ RSpec.describe 'Seeds', type: :request do
|
||||
end
|
||||
|
||||
it 'returns 401 Unauthorized without a token' do
|
||||
patch "/api/v1/seeds/#{seed.id}", params: update_params, headers: headers
|
||||
patch "/api/v1/seeds/#{seed.id}", params: update_params, headers: unauthenticated_headers
|
||||
expect(response).to have_http_status(:unauthorized)
|
||||
end
|
||||
|
||||
it 'returns 200 OK with a valid token for own seed' do
|
||||
patch "/api/v1/seeds/#{seed.id}", params: update_params, headers: auth_headers
|
||||
patch "/api/v1/seeds/#{seed.id}", params: update_params, headers: headers
|
||||
expect(response).to have_http_status(:ok)
|
||||
expect(seed.reload.description).to eq('An updated seed')
|
||||
end
|
||||
@@ -140,47 +125,39 @@ RSpec.describe 'Seeds', type: :request do
|
||||
}
|
||||
}
|
||||
}.to_json
|
||||
patch "/api/v1/seeds/#{other_member_seed.id}", params: update_params_for_other, headers: auth_headers
|
||||
patch "/api/v1/seeds/#{other_member_seed.id}", params: update_params_for_other, headers: headers
|
||||
expect(response).to have_http_status(:forbidden)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#delete' do
|
||||
let!(:member) { create(:member) }
|
||||
let(:token) do
|
||||
member.regenerate_api_token
|
||||
member.api_token.token
|
||||
end
|
||||
let(:headers) { { 'Accept' => 'application/vnd.api+json', 'Content-Type' => 'application/vnd.api+json' } }
|
||||
let(:auth_headers) { headers.merge('Authorization' => "Token token=#{token}") }
|
||||
let(:crop) { create(:crop) }
|
||||
let!(:seed) { create(:seed, owner: member, crop: crop) }
|
||||
let(:other_member_seed) { create(:seed) }
|
||||
|
||||
it 'returns 401 Unauthorized without a token' do
|
||||
delete "/api/v1/seeds/#{seed.id}", headers: headers
|
||||
delete "/api/v1/seeds/#{seed.id}", headers: unauthenticated_headers
|
||||
expect(response).to have_http_status(:unauthorized)
|
||||
end
|
||||
|
||||
it 'returns 204 No Content with a valid token for own seed' do
|
||||
delete "/api/v1/seeds/#{seed.id}", headers: auth_headers
|
||||
delete "/api/v1/seeds/#{seed.id}", headers: headers
|
||||
expect(response).to have_http_status(:no_content)
|
||||
expect(Seed.find_by(id: seed.id)).to be_nil
|
||||
end
|
||||
|
||||
it 'returns 403 Forbidden for another member\'s seed' do
|
||||
delete "/api/v1/seeds/#{other_member_seed.id}", headers: auth_headers
|
||||
delete "/api/v1/seeds/#{other_member_seed.id}", headers: headers
|
||||
expect(response).to have_http_status(:forbidden)
|
||||
end
|
||||
end
|
||||
|
||||
context 'filtering' do
|
||||
let!(:seed2) do
|
||||
FactoryBot.create(:seed, tradable_to: 'nationally', organic: 'certified organic', gmo: 'certified GMO-free', heirloom: 'heirloom')
|
||||
FactoryBot.create(:seed, owner: member, tradable_to: 'nationally', organic: 'certified organic', gmo: 'certified GMO-free', heirloom: 'heirloom')
|
||||
end
|
||||
let!(:other_member_seed) { create(:seed) }
|
||||
|
||||
it 'filters by crop' do
|
||||
get("/api/v1/seeds?filter[crop]=#{seed2.crop.id}", params: {}, headers:)
|
||||
get("/api/v1/seeds?filter[crop]=#{seed2.crop.id}", params: {}, headers: headers)
|
||||
|
||||
expect(response).to have_http_status(:ok)
|
||||
expect(subject['data'].size).to eq(1)
|
||||
@@ -188,7 +165,7 @@ RSpec.describe 'Seeds', type: :request do
|
||||
end
|
||||
|
||||
it 'filters by tradable_to' do
|
||||
get('/api/v1/seeds?filter[tradable_to]=nationally', params: {}, headers:)
|
||||
get('/api/v1/seeds?filter[tradable_to]=nationally', params: {}, headers: headers)
|
||||
|
||||
expect(response).to have_http_status(:ok)
|
||||
expect(subject['data'].size).to eq(1)
|
||||
@@ -196,7 +173,7 @@ RSpec.describe 'Seeds', type: :request do
|
||||
end
|
||||
|
||||
it 'filters by organic' do
|
||||
get('/api/v1/seeds?filter[organic]=certified organic', params: {}, headers:)
|
||||
get('/api/v1/seeds?filter[organic]=certified organic', params: {}, headers: headers)
|
||||
|
||||
expect(response).to have_http_status(:ok)
|
||||
expect(subject['data'].size).to eq(1)
|
||||
@@ -204,7 +181,7 @@ RSpec.describe 'Seeds', type: :request do
|
||||
end
|
||||
|
||||
it 'filters by gmo' do
|
||||
get('/api/v1/seeds?filter[gmo]=certified GMO-free', params: {}, headers:)
|
||||
get('/api/v1/seeds?filter[gmo]=certified GMO-free', params: {}, headers: headers)
|
||||
|
||||
expect(response).to have_http_status(:ok)
|
||||
expect(subject['data'].size).to eq(1)
|
||||
@@ -212,7 +189,7 @@ RSpec.describe 'Seeds', type: :request do
|
||||
end
|
||||
|
||||
it 'filters by heirloom' do
|
||||
get('/api/v1/seeds?filter[heirloom]=heirloom', params: {}, headers:)
|
||||
get('/api/v1/seeds?filter[heirloom]=heirloom', params: {}, headers: headers)
|
||||
|
||||
expect(response).to have_http_status(:ok)
|
||||
expect(subject['data'].size).to eq(1)
|
||||
@@ -220,11 +197,14 @@ RSpec.describe 'Seeds', type: :request do
|
||||
end
|
||||
|
||||
it 'filters by owner' do
|
||||
get("/api/v1/seeds?filter[owner_id]=#{seed2.owner.id}", params: {}, headers:)
|
||||
|
||||
get("/api/v1/seeds?filter[owner_id]=#{member.id}", params: {}, headers: headers)
|
||||
expect(response).to have_http_status(:ok)
|
||||
expect(subject['data'].size).to eq(1)
|
||||
expect(subject['data'][0]['id']).to eq(seed2.id.to_s)
|
||||
expect(subject['data'].size).to eq(2)
|
||||
expect(subject['data'].map { |s| s['id'] }).to include(seed.id.to_s, seed2.id.to_s)
|
||||
|
||||
get("/api/v1/seeds?filter[owner_id]=#{other_member_seed.owner.id}", params: {}, headers: headers)
|
||||
expect(response).to have_http_status(:ok)
|
||||
expect(subject['data']).to be_empty
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
19
spec/support/api_auth_helpers.rb
Normal file
19
spec/support/api_auth_helpers.rb
Normal file
@@ -0,0 +1,19 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
RSpec.shared_context 'with authenticated member' do
|
||||
let(:member) { create(:member) }
|
||||
let(:api_token) { member.regenerate_api_token }
|
||||
let(:headers) do
|
||||
{
|
||||
'Accept' => 'application/vnd.api+json',
|
||||
'Authorization' => "Token token=#{api_token.token}",
|
||||
'Content-Type' => 'application/vnd.api+json'
|
||||
}
|
||||
end
|
||||
let(:unauthenticated_headers) do
|
||||
{
|
||||
'Accept' => 'application/vnd.api+json',
|
||||
'Content-Type' => 'application/vnd.api+json'
|
||||
}
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user