mirror of
https://github.com/Freika/dawarich.git
synced 2026-01-10 17:21:38 -05:00
313 lines
9 KiB
Ruby
313 lines
9 KiB
Ruby
|
|
# frozen_string_literal: true
|
||
|
|
|
||
|
|
require 'rails_helper'
|
||
|
|
|
||
|
|
RSpec.describe 'Families', type: :request do
|
||
|
|
let(:user) { create(:user) }
|
||
|
|
let(:other_user) { create(:user) }
|
||
|
|
let(:family) { create(:family, creator: user) }
|
||
|
|
let!(:membership) { create(:family_membership, user: user, family: family, role: :owner) }
|
||
|
|
|
||
|
|
before { sign_in user }
|
||
|
|
|
||
|
|
describe 'GET /families' do
|
||
|
|
context 'when user is not in a family' do
|
||
|
|
let(:user_without_family) { create(:user) }
|
||
|
|
|
||
|
|
before { sign_in user_without_family }
|
||
|
|
|
||
|
|
it 'renders the index page' do
|
||
|
|
get '/families'
|
||
|
|
expect(response).to have_http_status(:ok)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
context 'when user is in a family' do
|
||
|
|
it 'redirects to family show page' do
|
||
|
|
get '/families'
|
||
|
|
expect(response).to redirect_to(family_path(family))
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
describe 'GET /families/:id' do
|
||
|
|
it 'shows the family page' do
|
||
|
|
get "/families/#{family.id}"
|
||
|
|
expect(response).to have_http_status(:ok)
|
||
|
|
end
|
||
|
|
|
||
|
|
context 'when user is not in the family' do
|
||
|
|
let(:outsider) { create(:user) }
|
||
|
|
|
||
|
|
before { sign_in outsider }
|
||
|
|
|
||
|
|
it 'redirects to families index' do
|
||
|
|
get "/families/#{family.id}"
|
||
|
|
expect(response).to redirect_to(families_path)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
describe 'GET /families/new' do
|
||
|
|
context 'when user is not in a family' do
|
||
|
|
let(:user_without_family) { create(:user) }
|
||
|
|
|
||
|
|
before { sign_in user_without_family }
|
||
|
|
|
||
|
|
it 'renders the new family form' do
|
||
|
|
get '/families/new'
|
||
|
|
expect(response).to have_http_status(:ok)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
context 'when user is already in a family' do
|
||
|
|
it 'redirects to family show page' do
|
||
|
|
get '/families/new'
|
||
|
|
expect(response).to redirect_to(family_path(family))
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
describe 'POST /families' do
|
||
|
|
let(:user_without_family) { create(:user) }
|
||
|
|
|
||
|
|
before { sign_in user_without_family }
|
||
|
|
|
||
|
|
context 'with valid attributes' do
|
||
|
|
let(:valid_attributes) { { family: { name: 'Test Family' } } }
|
||
|
|
|
||
|
|
it 'creates a new family' do
|
||
|
|
expect do
|
||
|
|
post '/families', params: valid_attributes
|
||
|
|
end.to change(Family, :count).by(1)
|
||
|
|
end
|
||
|
|
|
||
|
|
it 'creates a family membership for the user' do
|
||
|
|
expect do
|
||
|
|
post '/families', params: valid_attributes
|
||
|
|
end.to change(FamilyMembership, :count).by(1)
|
||
|
|
end
|
||
|
|
|
||
|
|
it 'redirects to the new family with success message' do
|
||
|
|
post '/families', params: valid_attributes
|
||
|
|
created_family = Family.last
|
||
|
|
expect(response).to redirect_to(family_path(created_family))
|
||
|
|
follow_redirect!
|
||
|
|
expect(response.body).to include('Family created successfully!')
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
context 'with invalid attributes' do
|
||
|
|
let(:invalid_attributes) { { family: { name: '' } } }
|
||
|
|
|
||
|
|
it 'does not create a family' do
|
||
|
|
expect do
|
||
|
|
post '/families', params: invalid_attributes
|
||
|
|
end.not_to change(Family, :count)
|
||
|
|
end
|
||
|
|
|
||
|
|
it 'renders the new template with errors' do
|
||
|
|
post '/families', params: invalid_attributes
|
||
|
|
expect(response).to have_http_status(:unprocessable_entity)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
describe 'GET /families/:id/edit' do
|
||
|
|
it 'shows the edit form' do
|
||
|
|
get "/families/#{family.id}/edit"
|
||
|
|
expect(response).to have_http_status(:ok)
|
||
|
|
end
|
||
|
|
|
||
|
|
context 'when user is not the owner' do
|
||
|
|
before { membership.update!(role: :member) }
|
||
|
|
|
||
|
|
it 'returns forbidden' do
|
||
|
|
get "/families/#{family.id}/edit"
|
||
|
|
expect(response).to have_http_status(:forbidden)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
describe 'PATCH /families/:id' do
|
||
|
|
let(:new_attributes) { { family: { name: 'Updated Family Name' } } }
|
||
|
|
|
||
|
|
context 'with valid attributes' do
|
||
|
|
it 'updates the family' do
|
||
|
|
patch "/families/#{family.id}", params: new_attributes
|
||
|
|
family.reload
|
||
|
|
expect(family.name).to eq('Updated Family Name')
|
||
|
|
expect(response).to redirect_to(family_path(family))
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
context 'with invalid attributes' do
|
||
|
|
let(:invalid_attributes) { { family: { name: '' } } }
|
||
|
|
|
||
|
|
it 'does not update the family' do
|
||
|
|
original_name = family.name
|
||
|
|
patch "/families/#{family.id}", params: invalid_attributes
|
||
|
|
family.reload
|
||
|
|
expect(family.name).to eq(original_name)
|
||
|
|
expect(response).to have_http_status(:unprocessable_entity)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
context 'when user is not the owner' do
|
||
|
|
before { membership.update!(role: :member) }
|
||
|
|
|
||
|
|
it 'returns forbidden' do
|
||
|
|
patch "/families/#{family.id}", params: new_attributes
|
||
|
|
expect(response).to have_http_status(:forbidden)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
describe 'DELETE /families/:id' do
|
||
|
|
context 'when family has only one member' do
|
||
|
|
it 'deletes the family' do
|
||
|
|
expect do
|
||
|
|
delete "/families/#{family.id}"
|
||
|
|
end.to change(Family, :count).by(-1)
|
||
|
|
expect(response).to redirect_to(families_path)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
context 'when family has multiple members' do
|
||
|
|
before do
|
||
|
|
create(:family_membership, user: other_user, family: family, role: :member)
|
||
|
|
end
|
||
|
|
|
||
|
|
it 'does not delete the family' do
|
||
|
|
expect do
|
||
|
|
delete "/families/#{family.id}"
|
||
|
|
end.not_to change(Family, :count)
|
||
|
|
expect(response).to redirect_to(family_path(family))
|
||
|
|
follow_redirect!
|
||
|
|
expect(response.body).to include('Cannot delete family with members')
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
context 'when user is not the owner' do
|
||
|
|
before { membership.update!(role: :member) }
|
||
|
|
|
||
|
|
it 'returns forbidden' do
|
||
|
|
delete "/families/#{family.id}"
|
||
|
|
expect(response).to have_http_status(:forbidden)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
describe 'DELETE /families/:id/leave' do
|
||
|
|
context 'when user is not the owner' do
|
||
|
|
before { membership.update!(role: :member) }
|
||
|
|
|
||
|
|
it 'allows user to leave the family' do
|
||
|
|
expect do
|
||
|
|
delete "/families/#{family.id}/leave"
|
||
|
|
end.to change { user.reload.family }.from(family).to(nil)
|
||
|
|
expect(response).to redirect_to(families_path)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
context 'when user is the owner with other members' do
|
||
|
|
before do
|
||
|
|
create(:family_membership, user: other_user, family: family, role: :member)
|
||
|
|
end
|
||
|
|
|
||
|
|
it 'prevents leaving and shows error message' do
|
||
|
|
expect do
|
||
|
|
delete "/families/#{family.id}/leave"
|
||
|
|
end.not_to(change { user.reload.family })
|
||
|
|
expect(response).to redirect_to(family_path(family))
|
||
|
|
follow_redirect!
|
||
|
|
expect(response.body).to include('cannot leave')
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
context 'when user is the only owner' do
|
||
|
|
it 'allows leaving and deletes the family' do
|
||
|
|
expect do
|
||
|
|
delete "/families/#{family.id}/leave"
|
||
|
|
end.to change(Family, :count).by(-1)
|
||
|
|
expect(response).to redirect_to(families_path)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
describe 'authorization for outsiders' do
|
||
|
|
let(:outsider) { create(:user) }
|
||
|
|
|
||
|
|
before { sign_in outsider }
|
||
|
|
|
||
|
|
it 'denies access to show when user is not in family' do
|
||
|
|
get "/families/#{family.id}"
|
||
|
|
expect(response).to redirect_to(families_path)
|
||
|
|
end
|
||
|
|
|
||
|
|
it 'denies access to edit when user is not in family' do
|
||
|
|
get "/families/#{family.id}/edit"
|
||
|
|
expect(response).to have_http_status(:forbidden)
|
||
|
|
end
|
||
|
|
|
||
|
|
it 'denies access to update when user is not in family' do
|
||
|
|
patch "/families/#{family.id}", params: { family: { name: 'Hacked' } }
|
||
|
|
expect(response).to have_http_status(:forbidden)
|
||
|
|
end
|
||
|
|
|
||
|
|
it 'denies access to destroy when user is not in family' do
|
||
|
|
delete "/families/#{family.id}"
|
||
|
|
expect(response).to have_http_status(:forbidden)
|
||
|
|
end
|
||
|
|
|
||
|
|
it 'denies access to leave when user is not in family' do
|
||
|
|
delete "/families/#{family.id}/leave"
|
||
|
|
expect(response).to have_http_status(:forbidden)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
describe 'authentication required' do
|
||
|
|
before { sign_out user }
|
||
|
|
|
||
|
|
it 'redirects to login for index' do
|
||
|
|
get '/families'
|
||
|
|
expect(response).to redirect_to(new_user_session_path)
|
||
|
|
end
|
||
|
|
|
||
|
|
it 'redirects to login for show' do
|
||
|
|
get "/families/#{family.id}"
|
||
|
|
expect(response).to redirect_to(new_user_session_path)
|
||
|
|
end
|
||
|
|
|
||
|
|
it 'redirects to login for new' do
|
||
|
|
get '/families/new'
|
||
|
|
expect(response).to redirect_to(new_user_session_path)
|
||
|
|
end
|
||
|
|
|
||
|
|
it 'redirects to login for create' do
|
||
|
|
post '/families', params: { family: { name: 'Test' } }
|
||
|
|
expect(response).to redirect_to(new_user_session_path)
|
||
|
|
end
|
||
|
|
|
||
|
|
it 'redirects to login for edit' do
|
||
|
|
get "/families/#{family.id}/edit"
|
||
|
|
expect(response).to redirect_to(new_user_session_path)
|
||
|
|
end
|
||
|
|
|
||
|
|
it 'redirects to login for update' do
|
||
|
|
patch "/families/#{family.id}", params: { family: { name: 'Test' } }
|
||
|
|
expect(response).to redirect_to(new_user_session_path)
|
||
|
|
end
|
||
|
|
|
||
|
|
it 'redirects to login for destroy' do
|
||
|
|
delete "/families/#{family.id}"
|
||
|
|
expect(response).to redirect_to(new_user_session_path)
|
||
|
|
end
|
||
|
|
|
||
|
|
it 'redirects to login for leave' do
|
||
|
|
delete "/families/#{family.id}/leave"
|
||
|
|
expect(response).to redirect_to(new_user_session_path)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|