Skip to content

Commit 5334dbc

Browse files
committed
test: improve coverage
1 parent a61fad9 commit 5334dbc

6 files changed

Lines changed: 719 additions & 0 deletions

File tree

spec/models/inhouse_spec.rb

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
# frozen_string_literal: true
2+
3+
require 'rails_helper'
4+
5+
RSpec.describe Inhouse, type: :model do
6+
let(:organization) { create(:organization) }
7+
let(:coach_user) { create(:user, :coach, organization: organization) }
8+
9+
def build_inhouse(**attrs)
10+
Inhouse.new({
11+
organization: organization,
12+
created_by: coach_user,
13+
status: 'waiting'
14+
}.merge(attrs))
15+
end
16+
17+
def create_inhouse(**attrs)
18+
build_inhouse(**attrs).tap(&:save!)
19+
end
20+
21+
describe 'validations' do
22+
it 'is valid with status waiting' do
23+
expect(build_inhouse).to be_valid
24+
end
25+
26+
it 'rejects invalid status values' do
27+
expect { build_inhouse(status: 'invalid') }.to raise_error(ArgumentError)
28+
end
29+
30+
it 'rejects invalid status transitions on update' do
31+
inhouse = create_inhouse(status: 'waiting')
32+
inhouse.update!(status: 'done')
33+
inhouse.status = 'waiting'
34+
expect(inhouse).not_to be_valid
35+
expect(inhouse.errors[:status]).to be_present
36+
end
37+
38+
it 'allows valid transition from waiting to draft' do
39+
inhouse = create_inhouse(status: 'waiting')
40+
inhouse.status = 'draft'
41+
expect(inhouse).to be_valid
42+
end
43+
44+
it 'allows valid transition from waiting to in_progress' do
45+
inhouse = create_inhouse(status: 'waiting')
46+
inhouse.status = 'in_progress'
47+
expect(inhouse).to be_valid
48+
end
49+
50+
it 'prevents illegal transition from in_progress to draft' do
51+
inhouse = create_inhouse(status: 'waiting')
52+
inhouse.update!(status: 'draft')
53+
inhouse.update!(status: 'in_progress')
54+
inhouse.status = 'draft'
55+
expect(inhouse).not_to be_valid
56+
end
57+
end
58+
59+
describe 'scopes' do
60+
it '.active includes waiting, draft, and in_progress statuses' do
61+
waiting = create_inhouse(status: 'waiting')
62+
done_house = create_inhouse(status: 'waiting')
63+
done_house.update!(status: 'done')
64+
65+
expect(Inhouse.active).to include(waiting)
66+
expect(Inhouse.active).not_to include(done_house)
67+
end
68+
69+
it '.history includes only done inhousess' do
70+
waiting = create_inhouse(status: 'waiting')
71+
done_house = create_inhouse(status: 'waiting')
72+
done_house.update!(status: 'done')
73+
74+
expect(Inhouse.history).to include(done_house)
75+
expect(Inhouse.history).not_to include(waiting)
76+
end
77+
end
78+
79+
describe '#current_pick_team' do
80+
it 'returns nil when status is not draft' do
81+
expect(build_inhouse(status: 'waiting').current_pick_team).to be_nil
82+
end
83+
84+
it 'returns the correct team for pick number 0 (blue first)' do
85+
inhouse = create_inhouse(status: 'waiting')
86+
inhouse.update_columns(status: 'draft', draft_pick_number: 0)
87+
expect(inhouse.current_pick_team).to eq(Inhouse::PICK_ORDER[0])
88+
end
89+
90+
it 'returns nil when all picks are exhausted' do
91+
inhouse = create_inhouse(status: 'waiting')
92+
inhouse.update_columns(status: 'draft', draft_pick_number: Inhouse::PICK_ORDER.size)
93+
expect(inhouse.current_pick_team).to be_nil
94+
end
95+
end
96+
97+
describe '#draft_complete?' do
98+
it 'returns true when pick number equals PICK_ORDER size' do
99+
inhouse = build_inhouse(draft_pick_number: Inhouse::PICK_ORDER.size)
100+
expect(inhouse.draft_complete?).to be(true)
101+
end
102+
103+
it 'returns false when picks remain' do
104+
inhouse = build_inhouse(draft_pick_number: 3)
105+
expect(inhouse.draft_complete?).to be(false)
106+
end
107+
108+
it 'returns false when draft_pick_number is nil' do
109+
inhouse = build_inhouse(draft_pick_number: nil)
110+
expect(inhouse.draft_complete?).to be(false)
111+
end
112+
end
113+
end

spec/models/organization_spec.rb

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
# frozen_string_literal: true
2+
3+
require 'rails_helper'
4+
5+
RSpec.describe Organization, type: :model do
6+
subject { build(:organization) }
7+
8+
describe 'validations' do
9+
it { is_expected.to validate_presence_of(:name) }
10+
11+
it 'rejects invalid region' do
12+
org = build(:organization, region: 'INVALID')
13+
expect(org).not_to be_valid
14+
expect(org.errors[:region]).to be_present
15+
end
16+
17+
it 'accepts all valid regions' do
18+
Constants::REGIONS.each do |region|
19+
org = build(:organization, region: region)
20+
expect(org).to be_valid, "expected region #{region} to be valid"
21+
end
22+
end
23+
24+
it 'rejects invalid tier' do
25+
org = build(:organization, tier: 'invalid_tier')
26+
expect(org).not_to be_valid
27+
end
28+
29+
it 'accepts blank tier' do
30+
org = build(:organization, tier: nil)
31+
expect(org).to be_valid
32+
end
33+
end
34+
35+
describe 'associations' do
36+
it { is_expected.to have_many(:users).dependent(:destroy) }
37+
it { is_expected.to have_many(:players).dependent(:destroy) }
38+
it { is_expected.to have_many(:matches).dependent(:destroy) }
39+
it { is_expected.to have_many(:scrims).dependent(:destroy) }
40+
it { is_expected.to have_many(:competitive_matches).dependent(:destroy) }
41+
it { is_expected.to have_many(:messages).dependent(:destroy) }
42+
end
43+
44+
describe 'slug generation' do
45+
it 'generates a slug from name on create' do
46+
org = create(:organization, name: 'Test Team Alpha')
47+
expect(org.slug).to be_present
48+
end
49+
50+
it 'does not override a manually set slug' do
51+
org = create(:organization, name: 'My Org', slug: 'custom-slug')
52+
expect(org.slug).to eq('custom-slug')
53+
end
54+
55+
it 'generates a unique slug with counter when collision exists' do
56+
create(:organization, name: 'Same Name', slug: 'same-name')
57+
org2 = create(:organization, name: 'Same Name')
58+
expect(org2.slug).to match(/same-name-\d+/)
59+
end
60+
end
61+
62+
describe 'trial management' do
63+
let(:org) { create(:organization) }
64+
65+
it 'sets trial period for new organizations' do
66+
expect(org.subscription_status).to eq('trial')
67+
expect(org.trial_expires_at).to be_present
68+
end
69+
70+
describe '#on_trial?' do
71+
it 'returns true when trial is active' do
72+
expect(org.on_trial?).to be(true)
73+
end
74+
75+
it 'returns false when trial has expired' do
76+
org.update_columns(trial_expires_at: 1.day.ago)
77+
expect(org.on_trial?).to be(false)
78+
end
79+
end
80+
81+
describe '#trial_expired?' do
82+
it 'returns false for active trial' do
83+
expect(org.trial_expired?).to be(false)
84+
end
85+
86+
it 'returns true when trial has expired' do
87+
org.update_columns(trial_expires_at: 1.day.ago)
88+
expect(org.trial_expired?).to be(true)
89+
end
90+
end
91+
92+
describe '#trial_days_remaining' do
93+
it 'returns a positive integer for active trials' do
94+
expect(org.trial_days_remaining).to be > 0
95+
end
96+
97+
it 'returns 0 when not on trial' do
98+
org.update_columns(subscription_status: 'active')
99+
expect(org.trial_days_remaining).to eq(0)
100+
end
101+
end
102+
103+
describe '#has_active_access?' do
104+
it 'returns true when on active trial' do
105+
expect(org.has_active_access?).to be(true)
106+
end
107+
108+
it 'returns true with active subscription' do
109+
org.update_columns(subscription_status: 'active')
110+
expect(org.has_active_access?).to be(true)
111+
end
112+
113+
it 'returns false when subscription has expired' do
114+
org.update_columns(subscription_status: 'expired')
115+
expect(org.has_active_access?).to be(false)
116+
end
117+
end
118+
end
119+
end

spec/models/user_spec.rb

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
# frozen_string_literal: true
2+
3+
require 'rails_helper'
4+
5+
RSpec.describe User, type: :model do
6+
subject { build(:user) }
7+
8+
describe 'validations' do
9+
it { is_expected.to validate_presence_of(:email) }
10+
it { is_expected.to validate_presence_of(:full_name) }
11+
it { is_expected.to validate_presence_of(:role) }
12+
it { is_expected.to validate_inclusion_of(:role).in_array(Constants::User::ROLES) }
13+
it { is_expected.to validate_uniqueness_of(:email).case_insensitive }
14+
15+
it 'rejects invalid email format' do
16+
user = build(:user, email: 'not-an-email')
17+
expect(user).not_to be_valid
18+
expect(user.errors[:email]).to be_present
19+
end
20+
21+
it 'accepts valid email format' do
22+
user = build(:user, email: 'valid@example.com')
23+
expect(user).to be_valid
24+
end
25+
26+
it 'requires password to contain uppercase letter' do
27+
user = build(:user, password: 'alllowercase1', password_confirmation: 'alllowercase1')
28+
expect(user).not_to be_valid
29+
end
30+
31+
it 'accepts a strong password' do
32+
user = build(:user, password: 'StrongPass1!', password_confirmation: 'StrongPass1!')
33+
expect(user).to be_valid
34+
end
35+
36+
it 'requires minimum password length of 8' do
37+
user = build(:user, password: 'Ab1', password_confirmation: 'Ab1')
38+
expect(user).not_to be_valid
39+
end
40+
end
41+
42+
describe 'associations' do
43+
it { is_expected.to belong_to(:organization) }
44+
it { is_expected.to have_many(:notifications).dependent(:destroy) }
45+
it { is_expected.to have_many(:audit_logs).dependent(:destroy) }
46+
it { is_expected.to have_many(:password_reset_tokens).dependent(:destroy) }
47+
end
48+
49+
describe 'scopes' do
50+
let!(:organization) { create(:organization) }
51+
let!(:active_user) { create(:user, organization: organization, last_login_at: 1.hour.ago) }
52+
let!(:never_logged) { create(:user, organization: organization, last_login_at: nil) }
53+
54+
describe '.by_role' do
55+
it 'filters users by role' do
56+
owner = create(:user, :owner, organization: organization)
57+
expect(User.by_role('owner')).to include(owner)
58+
expect(User.by_role('owner')).not_to include(active_user)
59+
end
60+
end
61+
62+
describe '.active' do
63+
it 'includes users who have logged in' do
64+
expect(User.active).to include(active_user)
65+
end
66+
67+
it 'excludes users who never logged in' do
68+
expect(User.active).not_to include(never_logged)
69+
end
70+
end
71+
end
72+
73+
describe 'callbacks' do
74+
it 'downcases email before save' do
75+
user = create(:user, email: 'UPPER@EXAMPLE.COM')
76+
expect(user.reload.email).to eq('upper@example.com')
77+
end
78+
end
79+
80+
describe '#admin?' do
81+
it 'returns true for admin role' do
82+
expect(build(:user, :admin).admin?).to be(true)
83+
end
84+
85+
it 'returns false for coach role' do
86+
expect(build(:user, :coach).admin?).to be(false)
87+
end
88+
end
89+
90+
describe '#owner?' do
91+
it 'returns true for owner role' do
92+
expect(build(:user, :owner).owner?).to be(true)
93+
end
94+
95+
it 'returns false for admin role' do
96+
expect(build(:user, :admin).owner?).to be(false)
97+
end
98+
end
99+
100+
describe '#can_manage_players?' do
101+
it 'returns true for owner, admin, and coach' do
102+
%w[owner admin coach].each do |role|
103+
expect(build(:user, role: role).can_manage_players?).to be(true),
104+
"expected #{role} to manage players"
105+
end
106+
end
107+
108+
it 'returns false for analyst and viewer' do
109+
%w[analyst viewer].each do |role|
110+
expect(build(:user, role: role).can_manage_players?).to be(false),
111+
"expected #{role} not to manage players"
112+
end
113+
end
114+
end
115+
116+
describe '#can_view_analytics?' do
117+
it 'returns true for owner, admin, coach, and analyst' do
118+
%w[owner admin coach analyst].each do |role|
119+
expect(build(:user, role: role).can_view_analytics?).to be(true)
120+
end
121+
end
122+
123+
it 'returns false for viewer' do
124+
expect(build(:user, :viewer).can_view_analytics?).to be(false)
125+
end
126+
end
127+
128+
describe '#update_last_login!' do
129+
it 'sets last_login_at to the current time' do
130+
user = create(:user)
131+
expect { user.update_last_login! }.to change { user.reload.last_login_at }.from(nil)
132+
end
133+
end
134+
end

0 commit comments

Comments
 (0)