- add transactional fixtures to rails_helper for test isolation - restructure crew errors to CrewErrors module for Zeitwerk - add rescue_from for CrewErrors::CrewError in api_controller - add model specs for Crew and CrewMembership (34 examples) - add controller specs for crews and memberships (28 examples) - add crew-related specs to User model (22 examples) - add factories for crews and crew_memberships
253 lines
7.2 KiB
Ruby
253 lines
7.2 KiB
Ruby
require 'rails_helper'
|
|
|
|
RSpec.describe 'Crews API', type: :request do
|
|
let(:user) { create(:user) }
|
|
let(:other_user) { create(:user) }
|
|
let(:access_token) do
|
|
Doorkeeper::AccessToken.create!(resource_owner_id: user.id, expires_in: 30.days, scopes: 'public')
|
|
end
|
|
let(:other_access_token) do
|
|
Doorkeeper::AccessToken.create!(resource_owner_id: other_user.id, expires_in: 30.days, scopes: 'public')
|
|
end
|
|
let(:headers) do
|
|
{ 'Authorization' => "Bearer #{access_token.token}", 'Content-Type' => 'application/json' }
|
|
end
|
|
let(:other_headers) do
|
|
{ 'Authorization' => "Bearer #{other_access_token.token}", 'Content-Type' => 'application/json' }
|
|
end
|
|
|
|
describe 'POST /api/v1/crews' do
|
|
let(:valid_params) do
|
|
{
|
|
crew: {
|
|
name: 'Test Crew',
|
|
gamertag: 'TEST',
|
|
granblue_crew_id: '12345678',
|
|
description: 'A test crew'
|
|
}
|
|
}
|
|
end
|
|
|
|
it 'creates a crew and makes user captain' do
|
|
post '/api/v1/crews', params: valid_params.to_json, headers: headers
|
|
|
|
expect(response).to have_http_status(:created)
|
|
json = JSON.parse(response.body)
|
|
expect(json['crew']['name']).to eq('Test Crew')
|
|
expect(json['crew']['gamertag']).to eq('TEST')
|
|
|
|
user.reload
|
|
expect(user.crew).to be_present
|
|
expect(user.crew_captain?).to be true
|
|
end
|
|
|
|
it 'returns error if user already in a crew' do
|
|
crew = create(:crew)
|
|
create(:crew_membership, :captain, crew: crew, user: user)
|
|
|
|
post '/api/v1/crews', params: valid_params.to_json, headers: headers
|
|
|
|
expect(response).to have_http_status(:unprocessable_entity)
|
|
json = JSON.parse(response.body)
|
|
expect(json['message']).to eq('You are already in a crew')
|
|
end
|
|
|
|
it 'returns unauthorized without authentication' do
|
|
post '/api/v1/crews', params: valid_params.to_json
|
|
|
|
expect(response).to have_http_status(:unauthorized)
|
|
end
|
|
|
|
it 'validates crew name presence' do
|
|
invalid_params = { crew: { name: '' } }
|
|
post '/api/v1/crews', params: invalid_params.to_json, headers: headers
|
|
|
|
expect(response).to have_http_status(:unprocessable_entity)
|
|
end
|
|
end
|
|
|
|
describe 'GET /api/v1/crew' do
|
|
let(:crew) { create(:crew) }
|
|
|
|
before do
|
|
create(:crew_membership, :captain, crew: crew, user: user)
|
|
end
|
|
|
|
it 'returns the current user crew' do
|
|
get '/api/v1/crew', headers: headers
|
|
|
|
expect(response).to have_http_status(:ok)
|
|
json = JSON.parse(response.body)
|
|
expect(json['crew']['name']).to eq(crew.name)
|
|
end
|
|
|
|
it 'returns 404 if user has no crew' do
|
|
user.active_crew_membership.retire!
|
|
|
|
get '/api/v1/crew', headers: headers
|
|
|
|
expect(response).to have_http_status(:not_found)
|
|
end
|
|
|
|
it 'returns unauthorized without authentication' do
|
|
get '/api/v1/crew'
|
|
|
|
expect(response).to have_http_status(:unauthorized)
|
|
end
|
|
end
|
|
|
|
describe 'PUT /api/v1/crew' do
|
|
let(:crew) { create(:crew) }
|
|
|
|
context 'as captain' do
|
|
before do
|
|
create(:crew_membership, :captain, crew: crew, user: user)
|
|
end
|
|
|
|
it 'updates the crew' do
|
|
put '/api/v1/crew', params: { crew: { name: 'New Name' } }.to_json, headers: headers
|
|
|
|
expect(response).to have_http_status(:ok)
|
|
json = JSON.parse(response.body)
|
|
expect(json['crew']['name']).to eq('New Name')
|
|
end
|
|
end
|
|
|
|
context 'as vice captain' do
|
|
before do
|
|
create(:crew_membership, :captain, crew: crew)
|
|
create(:crew_membership, :vice_captain, crew: crew, user: user)
|
|
end
|
|
|
|
it 'updates the crew' do
|
|
put '/api/v1/crew', params: { crew: { name: 'New Name' } }.to_json, headers: headers
|
|
|
|
expect(response).to have_http_status(:ok)
|
|
end
|
|
end
|
|
|
|
context 'as member' do
|
|
before do
|
|
create(:crew_membership, :captain, crew: crew)
|
|
create(:crew_membership, crew: crew, user: user)
|
|
end
|
|
|
|
it 'returns unauthorized' do
|
|
put '/api/v1/crew', params: { crew: { name: 'New Name' } }.to_json, headers: headers
|
|
|
|
expect(response).to have_http_status(:unauthorized)
|
|
end
|
|
end
|
|
end
|
|
|
|
describe 'GET /api/v1/crew/members' do
|
|
let(:crew) { create(:crew) }
|
|
let(:captain) { create(:user) }
|
|
let(:member) { create(:user) }
|
|
|
|
before do
|
|
create(:crew_membership, :captain, crew: crew, user: captain)
|
|
create(:crew_membership, crew: crew, user: user)
|
|
create(:crew_membership, crew: crew, user: member)
|
|
end
|
|
|
|
it 'returns all active members' do
|
|
get '/api/v1/crew/members', headers: headers
|
|
|
|
expect(response).to have_http_status(:ok)
|
|
json = JSON.parse(response.body)
|
|
expect(json['members'].length).to eq(3)
|
|
end
|
|
|
|
it 'does not include retired members' do
|
|
crew.crew_memberships.find_by(user: member).retire!
|
|
|
|
get '/api/v1/crew/members', headers: headers
|
|
|
|
expect(response).to have_http_status(:ok)
|
|
json = JSON.parse(response.body)
|
|
expect(json['members'].length).to eq(2)
|
|
end
|
|
end
|
|
|
|
describe 'POST /api/v1/crew/leave' do
|
|
let(:crew) { create(:crew) }
|
|
|
|
context 'as regular member' do
|
|
before do
|
|
create(:crew_membership, :captain, crew: crew)
|
|
create(:crew_membership, crew: crew, user: user)
|
|
end
|
|
|
|
it 'retires the membership' do
|
|
post '/api/v1/crew/leave', headers: headers
|
|
|
|
expect(response).to have_http_status(:no_content)
|
|
user.reload
|
|
expect(user.crew).to be_nil
|
|
end
|
|
end
|
|
|
|
context 'as captain' do
|
|
before do
|
|
create(:crew_membership, :captain, crew: crew, user: user)
|
|
end
|
|
|
|
it 'returns error' do
|
|
post '/api/v1/crew/leave', headers: headers
|
|
|
|
expect(response).to have_http_status(:unprocessable_entity)
|
|
json = JSON.parse(response.body)
|
|
expect(json['message']).to eq('Captain must transfer ownership before leaving')
|
|
end
|
|
end
|
|
|
|
context 'when not in crew' do
|
|
it 'returns error' do
|
|
post '/api/v1/crew/leave', headers: headers
|
|
|
|
expect(response).to have_http_status(:unprocessable_entity)
|
|
end
|
|
end
|
|
end
|
|
|
|
describe 'POST /api/v1/crews/:id/transfer_captain' do
|
|
let(:crew) { create(:crew) }
|
|
let(:vice_captain) { create(:user) }
|
|
|
|
before do
|
|
create(:crew_membership, :captain, crew: crew, user: user)
|
|
create(:crew_membership, :vice_captain, crew: crew, user: vice_captain)
|
|
end
|
|
|
|
it 'transfers captain role to another member' do
|
|
post "/api/v1/crews/#{crew.id}/transfer_captain",
|
|
params: { user_id: vice_captain.id }.to_json,
|
|
headers: headers
|
|
|
|
expect(response).to have_http_status(:ok)
|
|
user.reload
|
|
vice_captain.reload
|
|
expect(user.crew_role).to eq('vice_captain')
|
|
expect(vice_captain.crew_role).to eq('captain')
|
|
end
|
|
|
|
it 'returns error if target user is not in crew' do
|
|
post "/api/v1/crews/#{crew.id}/transfer_captain",
|
|
params: { user_id: other_user.id }.to_json,
|
|
headers: headers
|
|
|
|
expect(response).to have_http_status(:not_found)
|
|
end
|
|
|
|
it 'requires captain role' do
|
|
create(:crew_membership, crew: crew, user: other_user)
|
|
|
|
post "/api/v1/crews/#{crew.id}/transfer_captain",
|
|
params: { user_id: vice_captain.id }.to_json,
|
|
headers: other_headers
|
|
|
|
expect(response).to have_http_status(:unauthorized)
|
|
end
|
|
end
|
|
end
|