Add missing specs

This commit is contained in:
Eugene Burmakin 2025-11-20 00:04:37 +01:00
parent c99f6597f0
commit 50bfece971
2 changed files with 290 additions and 0 deletions

View file

@ -0,0 +1,196 @@
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe Taggable do
# Use Place as the test model since it includes Taggable
let(:user) { create(:user) }
let(:tag1) { create(:tag, user: user, name: 'Home') }
let(:tag2) { create(:tag, user: user, name: 'Work') }
let(:tag3) { create(:tag, user: user, name: 'Gym') }
describe 'associations' do
it { expect(Place.new).to have_many(:taggings).dependent(:destroy) }
it { expect(Place.new).to have_many(:tags).through(:taggings) }
end
describe 'scopes' do
let!(:place1) { create(:place, user: user) }
let!(:place2) { create(:place, user: user) }
let!(:place3) { create(:place, user: user) }
before do
place1.tags << [tag1, tag2]
place2.tags << tag1
# place3 has no tags
end
describe '.with_tags' do
it 'returns places with any of the specified tag IDs' do
results = Place.with_tags([tag1.id])
expect(results).to contain_exactly(place1, place2)
end
it 'returns places with multiple tag IDs' do
results = Place.with_tags([tag1.id, tag2.id])
expect(results).to contain_exactly(place1, place2)
end
it 'returns distinct results when place has multiple matching tags' do
results = Place.with_tags([tag1.id, tag2.id])
expect(results.count).to eq(2)
expect(results).to contain_exactly(place1, place2)
end
it 'returns empty when no places have the specified tags' do
results = Place.with_tags([tag3.id])
expect(results).to be_empty
end
it 'accepts a single tag ID' do
results = Place.with_tags(tag1.id)
expect(results).to contain_exactly(place1, place2)
end
end
describe '.without_tags' do
it 'returns only places without any tags' do
results = Place.without_tags
expect(results).to contain_exactly(place3)
end
it 'returns empty when all places have tags' do
place3.tags << tag3
results = Place.without_tags
expect(results).to be_empty
end
it 'returns all places when none have tags' do
place1.tags.clear
place2.tags.clear
results = Place.without_tags
expect(results).to contain_exactly(place1, place2, place3)
end
end
describe '.tagged_with' do
it 'returns places tagged with the specified tag name' do
results = Place.tagged_with('Home', user)
expect(results).to contain_exactly(place1, place2)
end
it 'returns distinct results' do
results = Place.tagged_with('Home', user)
expect(results.count).to eq(2)
end
it 'returns empty when no places have the tag name' do
results = Place.tagged_with('NonExistent', user)
expect(results).to be_empty
end
it 'filters by user' do
other_user = create(:user)
other_tag = create(:tag, user: other_user, name: 'Home')
other_place = create(:place, user: other_user)
other_place.tags << other_tag
results = Place.tagged_with('Home', user)
expect(results).to contain_exactly(place1, place2)
expect(results).not_to include(other_place)
end
end
end
describe 'instance methods' do
let(:place) { create(:place, user: user) }
describe '#add_tag' do
it 'adds a tag to the record' do
expect {
place.add_tag(tag1)
}.to change { place.tags.count }.by(1)
end
it 'does not add duplicate tags' do
place.add_tag(tag1)
expect {
place.add_tag(tag1)
}.not_to change { place.tags.count }
end
it 'adds the correct tag' do
place.add_tag(tag1)
expect(place.tags).to include(tag1)
end
it 'can add multiple different tags' do
place.add_tag(tag1)
place.add_tag(tag2)
expect(place.tags).to contain_exactly(tag1, tag2)
end
end
describe '#remove_tag' do
before do
place.tags << [tag1, tag2]
end
it 'removes a tag from the record' do
expect {
place.remove_tag(tag1)
}.to change { place.tags.count }.by(-1)
end
it 'removes the correct tag' do
place.remove_tag(tag1)
expect(place.tags).not_to include(tag1)
expect(place.tags).to include(tag2)
end
it 'does nothing when tag is not present' do
expect {
place.remove_tag(tag3)
}.not_to change { place.tags.count }
end
end
describe '#tag_names' do
it 'returns an empty array when no tags' do
expect(place.tag_names).to eq([])
end
it 'returns array of tag names' do
place.tags << [tag1, tag2]
expect(place.tag_names).to contain_exactly('Home', 'Work')
end
it 'returns tag names in database order' do
place.tags << tag2
place.tags << tag1
# Order depends on taggings created_at
expect(place.tag_names).to be_an(Array)
expect(place.tag_names.size).to eq(2)
end
end
describe '#tagged_with?' do
before do
place.tags << tag1
end
it 'returns true when tagged with the specified tag' do
expect(place.tagged_with?(tag1)).to be true
end
it 'returns false when not tagged with the specified tag' do
expect(place.tagged_with?(tag2)).to be false
end
it 'returns false when place has no tags' do
place.tags.clear
expect(place.tagged_with?(tag1)).to be false
end
end
end
end

View file

@ -18,6 +18,100 @@ RSpec.describe Place, type: :model do
it { is_expected.to define_enum_for(:source).with_values(%i[manual photon]) }
end
describe 'scopes' do
let(:user1) { create(:user) }
let(:user2) { create(:user) }
let!(:place1) { create(:place, user: user1, name: 'Zoo') }
let!(:place2) { create(:place, user: user1, name: 'Airport') }
let!(:place3) { create(:place, user: user2, name: 'Museum') }
describe '.for_user' do
it 'returns places for the specified user' do
expect(Place.for_user(user1)).to contain_exactly(place1, place2)
end
it 'does not return places for other users' do
expect(Place.for_user(user1)).not_to include(place3)
end
it 'returns empty when user has no places' do
new_user = create(:user)
expect(Place.for_user(new_user)).to be_empty
end
end
describe '.ordered' do
it 'orders places by name alphabetically' do
expect(Place.for_user(user1).ordered).to eq([place2, place1])
end
it 'handles case-insensitive ordering' do
place_lower = create(:place, user: user1, name: 'airport')
place_upper = create(:place, user: user1, name: 'BEACH')
ordered = Place.for_user(user1).ordered
# The ordered scope orders by name alphabetically (case-sensitive in most DBs)
expect(ordered.map(&:name)).to include('airport', 'BEACH')
end
end
end
describe 'Taggable concern integration' do
let(:user) { create(:user) }
let(:place) { create(:place, user: user) }
let(:tag1) { create(:tag, user: user, name: 'Restaurant') }
let(:tag2) { create(:tag, user: user, name: 'Favorite') }
it 'can add tags to a place' do
place.add_tag(tag1)
expect(place.tags).to include(tag1)
end
it 'can remove tags from a place' do
place.tags << tag1
place.remove_tag(tag1)
expect(place.tags).not_to include(tag1)
end
it 'returns tag names' do
place.tags << [tag1, tag2]
expect(place.tag_names).to contain_exactly('Restaurant', 'Favorite')
end
it 'checks if tagged with a specific tag' do
place.tags << tag1
expect(place.tagged_with?(tag1)).to be true
expect(place.tagged_with?(tag2)).to be false
end
describe 'scopes' do
let!(:tagged_place) { create(:place, user: user) }
let!(:untagged_place) { create(:place, user: user) }
before do
tagged_place.tags << tag1
end
it 'filters places with specific tags' do
results = Place.with_tags([tag1.id])
expect(results).to include(tagged_place)
expect(results).not_to include(untagged_place)
end
it 'filters places without tags' do
results = Place.without_tags
expect(results).to include(untagged_place)
expect(results).not_to include(tagged_place)
end
it 'filters places by tag name and user' do
results = Place.tagged_with('Restaurant', user)
expect(results).to include(tagged_place)
expect(results).not_to include(untagged_place)
end
end
end
describe 'methods' do
let(:place) { create(:place, :with_geodata) }