hensei-api/spec/requests/api/v1/crew_memberships_spec.rb

179 lines
6.4 KiB
Ruby

require 'rails_helper'
RSpec.describe 'Api::V1::CrewMemberships', type: :request do
let(:user) { create(:user) }
let(:access_token) do
Doorkeeper::AccessToken.create!(resource_owner_id: user.id, expires_in: 30.days, scopes: 'public')
end
let(:auth_headers) { { 'Authorization' => "Bearer #{access_token.token}" } }
let(:crew) { create(:crew) }
let(:target_user) { create(:user) }
let!(:target_membership) { create(:crew_membership, crew: crew, user: target_user, role: :member) }
describe 'PUT /api/v1/crews/:crew_id/memberships/:id' do
context 'as captain' do
let!(:captain_membership) { create(:crew_membership, crew: crew, user: user, role: :captain) }
it 'updates member role' do
put "/api/v1/crews/#{crew.id}/memberships/#{target_membership.id}",
params: { membership: { role: 'vice_captain' } },
headers: auth_headers
expect(response).to have_http_status(:ok)
json = JSON.parse(response.body)
expect(json['membership']['role']).to eq('vice_captain')
end
end
context 'as vice captain' do
let!(:vc_membership) { create(:crew_membership, crew: crew, user: user, role: :vice_captain) }
it 'cannot change role but request succeeds' do
put "/api/v1/crews/#{crew.id}/memberships/#{target_membership.id}",
params: { membership: { role: 'vice_captain' } },
headers: auth_headers
# Vice captains can access update endpoint (for joined_at) but role param is ignored
expect(response).to have_http_status(:ok)
expect(target_membership.reload.role).to eq('member') # Role not changed
end
it 'can update joined_at' do
put "/api/v1/crews/#{crew.id}/memberships/#{target_membership.id}",
params: { membership: { joined_at: '2024-01-15' } },
headers: auth_headers
expect(response).to have_http_status(:ok)
json = JSON.parse(response.body)
expect(json['membership']['joined_at']).to include('2024-01-15')
end
end
end
describe 'DELETE /api/v1/crews/:crew_id/memberships/:id' do
context 'as captain' do
let!(:captain_membership) { create(:crew_membership, crew: crew, user: user, role: :captain) }
it 'removes a member' do
delete "/api/v1/crews/#{crew.id}/memberships/#{target_membership.id}",
headers: auth_headers
expect(response).to have_http_status(:no_content)
expect(target_membership.reload.retired).to be true
end
it 'cannot remove self (captain)' do
delete "/api/v1/crews/#{crew.id}/memberships/#{captain_membership.id}",
headers: auth_headers
expect(response).to have_http_status(:unprocessable_entity)
json = JSON.parse(response.body)
expect(json['code']).to eq('cannot_remove_captain')
end
end
context 'as vice captain' do
let!(:vc_membership) { create(:crew_membership, crew: crew, user: user, role: :vice_captain) }
it 'can remove regular members' do
delete "/api/v1/crews/#{crew.id}/memberships/#{target_membership.id}",
headers: auth_headers
expect(response).to have_http_status(:no_content)
end
end
context 'as regular member' do
let!(:membership) { create(:crew_membership, crew: crew, user: user, role: :member) }
it 'returns unauthorized' do
delete "/api/v1/crews/#{crew.id}/memberships/#{target_membership.id}",
headers: auth_headers
expect(response).to have_http_status(:unauthorized)
end
end
end
describe 'POST /api/v1/crews/:crew_id/memberships/:id/promote' do
context 'as captain' do
let!(:captain_membership) { create(:crew_membership, crew: crew, user: user, role: :captain) }
it 'promotes member to vice captain' do
post "/api/v1/crews/#{crew.id}/memberships/#{target_membership.id}/promote",
headers: auth_headers
expect(response).to have_http_status(:ok)
json = JSON.parse(response.body)
expect(json['membership']['role']).to eq('vice_captain')
end
it 'returns error when VC limit reached' do
3.times { create(:crew_membership, crew: crew, role: :vice_captain) }
post "/api/v1/crews/#{crew.id}/memberships/#{target_membership.id}/promote",
headers: auth_headers
expect(response).to have_http_status(:unprocessable_entity)
json = JSON.parse(response.body)
expect(json['code']).to eq('vice_captain_limit')
end
it 'cannot promote captain' do
post "/api/v1/crews/#{crew.id}/memberships/#{captain_membership.id}/promote",
headers: auth_headers
expect(response).to have_http_status(:unprocessable_entity)
end
end
context 'as vice captain' do
let!(:vc_membership) { create(:crew_membership, crew: crew, user: user, role: :vice_captain) }
it 'returns unauthorized' do
post "/api/v1/crews/#{crew.id}/memberships/#{target_membership.id}/promote",
headers: auth_headers
expect(response).to have_http_status(:unauthorized)
end
end
end
describe 'POST /api/v1/crews/:crew_id/memberships/:id/demote' do
let!(:vc_target) { create(:crew_membership, crew: crew, role: :vice_captain) }
context 'as captain' do
let!(:captain_membership) { create(:crew_membership, crew: crew, user: user, role: :captain) }
it 'demotes vice captain to member' do
post "/api/v1/crews/#{crew.id}/memberships/#{vc_target.id}/demote",
headers: auth_headers
expect(response).to have_http_status(:ok)
json = JSON.parse(response.body)
expect(json['membership']['role']).to eq('member')
end
it 'cannot demote captain' do
post "/api/v1/crews/#{crew.id}/memberships/#{captain_membership.id}/demote",
headers: auth_headers
expect(response).to have_http_status(:unprocessable_entity)
json = JSON.parse(response.body)
expect(json['code']).to eq('cannot_demote_captain')
end
end
context 'as vice captain' do
let!(:vc_membership) { create(:crew_membership, crew: crew, user: user, role: :vice_captain) }
it 'returns unauthorized' do
post "/api/v1/crews/#{crew.id}/memberships/#{vc_target.id}/demote",
headers: auth_headers
expect(response).to have_http_status(:unauthorized)
end
end
end
end